UNPKG

@wix/design-system

Version:

@wix/design-system

606 lines (567 loc) 18.1 kB
## Feature Examples ### Size - description: <p>Control tabs size with <code>size</code> prop:</p><li>Use <code>small</code> in dense layouts, like narrow panels.</li><li>Use <code>medium</code> (default) in all other layouts, like below <code><Page.Header/></code>.</li> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(2); return ( <StorybookComponents.Stack flexDirection="column"> <Tabs size="small" activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Small' }, { id: 2, title: 'Small' }, ]} /> <Tabs size="medium" activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Medium' }, { id: 2, title: 'Medium' }, ]} /> </StorybookComponents.Stack> ); }; ``` ### Min width - description: <p>By default, tabs fill in the entire width of their parent container and have a minimum width of 628 px.</p><p></p><p>Set custom min width of tabs using the <code>minWidth</code> prop.</p> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(2); return ( <StorybookComponents.Stack flexDirection="column"> <Tabs activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Default' }, { id: 2, title: 'Default' }, ]} /> <Box> <Tabs minWidth="360px" activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Min width' }, { id: 2, title: 'Min width' }, ]} /> </Box> </StorybookComponents.Stack> ); }; ``` ### Type - description: <p>Control how tabs are positioned with <code>type</code> prop:</p><li>By default, each tab grows with its title. Side paddings are inside tabs.</li><li><code>compact</code> - each tab grows with its title. Side paddings are outside tabs.</li><li><code>compactSide</code> - each tab grows with its title. Side paddings are outside tabs. The first and the last tab has no left and right paddings respectively.</li><li><code>uniformSide</code> - each tab grows to the size defined in <code>width</code> prop. If tab content is longer than the <code>width</code>, it gets truncated by ellipsis. Side paddings are inside tabs.</li><li><code>uniformFull</code> - all tabs grow equally to fill in the whole container. Side paddings are inside tabs.</li> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(1); return ( <StorybookComponents.Stack flexDirection="column"> <Box direction="vertical" gap="1"> <Text secondary weight="normal"> Default </Text> <Tabs items={[ { id: 1, title: 'Tab' }, { id: 2, title: 'Tab' }, { id: 3, title: 'Tab' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> </Box> <Box direction="vertical" gap="1"> <Text secondary weight="normal"> Compact </Text> <Tabs type="compact" items={[ { id: 1, title: 'Tab' }, { id: 2, title: 'Tab' }, { id: 3, title: 'Tab' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> </Box> <Box direction="vertical" gap="1"> <Text secondary weight="normal"> Compact side </Text> <Tabs type="compactSide" items={[ { id: 1, title: 'Tab' }, { id: 2, title: 'Tab' }, { id: 3, title: 'Tab' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> </Box> <Box direction="vertical" gap="1"> <Text secondary weight="normal"> Uniform side </Text> <Tabs type="uniformSide" width={120} items={[ { id: 1, title: 'Tab' }, { id: 2, title: 'Tab' }, { id: 3, title: 'Tab' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> </Box> <Box direction="vertical" gap="1"> <Text secondary weight="normal"> Uniform full </Text> <Tabs type="uniformFull" items={[ { id: 1, title: 'Tab' }, { id: 2, title: 'Tab' }, { id: 3, title: 'Tab' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> </Box> </StorybookComponents.Stack> ); }; ``` ### Alignment - description: <p>Control text alignment inside tabs with <code>alignment</code> prop. It supports 3 options:</p><li>Use <code>start</code> (default) to align tab titles to to the left.</li><li>Use <code>center</code> to align them to the middle.</li><li>Use <code>end</code> to align them to the right.</li> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(1); return ( <StorybookComponents.Stack flexDirection="column"> <Tabs alignment="start" type="uniformFull" items={[ { id: 1, title: 'Start' }, { id: 2, title: 'Start' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> <Tabs alignment="center" type="uniformFull" items={[ { id: 1, title: 'Center' }, { id: 2, title: 'Center' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> <Tabs alignment="end" type="uniformFull" items={[ { id: 1, title: 'End' }, { id: 2, title: 'End' }, ]} activeId={activeId} onClick={(value) => setActiveId(value.id)} /> </StorybookComponents.Stack> ); }; ``` ### Bottom divider - description: <p>Control if the default bottom divider is shown with <code>hasDivider</code> prop.</p> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(1); return ( <StorybookComponents.Stack flexDirection="column"> <Tabs activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Default' }, { id: 2, title: 'Default' }, ]} /> <Tabs hasDivider={false} activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'No divider' }, { id: 2, title: 'No divider' }, ]} /> </StorybookComponents.Stack> ); }; ``` ### Side content - description: <p>Add any component to the end of tabs with <code>sideContent</code> prop.</p><p></p><p>For example, use it to store a filter or form actions like Save and Cancel.</p> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(1); return ( <Tabs activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Tab' }, { id: 2, title: 'Tab' }, ]} sideContent=<StorybookComponents.Placeholder> Side content </StorybookComponents.Placeholder> /> ); }; ``` ## Common Use Case Examples ### In a page - description: <p>Use tabs to divide all page contents into shorter, digestible parts.</p><p></p><p>Divide content in a way that allows users completing their task under each tab independently.</p> - example: ```jsx () => { const [activeId, setActiveId] = React.useState(1); const tabContent = { 1: ( <Card> <Card.Header title="General (RSVP event)" subtitle={ <Box gap="1"> <Text skin="standard" secondary> Guests register by submitting yes & no responses. </Text> <TextButton underline="always">Learn More</TextButton> </Box> } /> <Card.Divider /> <Card.Content> <Layout> <Cell span={8}> <Layout> <Cell> <FormField label="Event name"> <Input value="90s Rock Concert" /> </FormField> </Cell> <Cell> <FormField label="Short teaser (optional)"> <InputArea placeholder="Add a few words under the name of the event to inspire guests, e.g., An unforgettable show!" resizable rows={3} /> </FormField> </Cell> </Layout> </Cell> <Cell span={4}> <FormField label="Event cover"> <ImageViewer width="100%" height="168px" /> </FormField> </Cell> </Layout> </Card.Content> </Card> ), 2: ( <Card> <MarketingLayout title="Customize your own automated emails" description="Design customized emails and set the automated triggers. Remember to disable the relevant default email above if you're creating your own branded emails." actions={ <Button size="small" priority="secondary"> Create Automations </Button> } image={ <Box width="100%" align="right"> <Image width="120px" src="PromotionalPromoteMarketingHomeEmail.svg" transparent /> </Box> } /> </Card> ), 3: ( <EmptyState theme={'page-no-border'} title="Start inviting guests" subtitle="Once guests RSVP to your event, you’ll see their info here. To get started, send an invite." > {<TextButton prefixIcon={<Icons.Add />}>Create Invitation</TextButton>} </EmptyState> ), }; return ( <Page> <Page.Header breadcrumbs={ <Breadcrumbs activeId="2" items={[ { id: '1', value: 'Events' }, { id: '2', value: '90s Rock Concert' }, ]} onClick={() => {}} /> } showBackButton onBackClicked={() => {}} title="90s Rock Concert" actionsBar=<Box gap="2" height="60px"> <Button priority="secondary">Cancel</Button> <Button>Save</Button> </Box> /> <Page.Content> <Layout> <Cell> <Tabs activeId={activeId} onClick={(value) => setActiveId(value.id)} items={[ { id: 1, title: 'Event details' }, { id: 2, title: 'Emails' }, { id: 3, title: 'Guest list' }, ]} /> </Cell> <Cell>{tabContent[activeId]}</Cell> </Layout> </Page.Content> </Page> ); }; ``` ### In a panel - description: <p>Let users switch between parts of content in the same context of a <code><SidePanel/></code>.</p><p></p><p>Select to show either panel divider or a default tabs’ divider to separate panel header from its main content.</p> - example: ```jsx () => { const [selectedSidebar, setSelectedSidebar] = React.useState(0); const [activeTab, setActiveTab] = React.useState(0); const [toggleImage, setToggleImage] = React.useState(true); const [togglePosts, setTogglePosts] = React.useState(false); const [toggleCommenting, setToggleCommenting] = React.useState(false); const [descriptionValue, setDescriptionValue] = React.useState(''); const [authorTags, setAuthorTags] = React.useState([]); const [publishDate, setPublishDate] = React.useState(); const [author, setAuthor] = React.useState(); const items = [ { id: 0, label: 'Settings', icon: <Icons.Settings />, }, { id: 1, label: 'Categories', icon: <Icons.Category />, }, { id: 2, label: 'Tags', icon: <Icons.Tag />, }, ]; const authorOptions = [ listItemSelectBuilder({ id: 0, prefix: <Avatar size="size18" />, title: 'Doe John', label: 'Doe John', }), listItemSelectBuilder({ id: 1, prefix: <Avatar size="size18" />, title: 'John Doe', label: 'John Doe', }), listItemActionBuilder({ title: 'New Author', prefixIcon: <Icons.Add />, }), ]; const handleSelectTag = (tag, previousTags, setTags) => setTags([...previousTags, { id: tag.id, label: tag.value }]); const handleRemoveTag = (tag, previousTags, setTags) => setTags(previousTags.filter((currTag) => currTag.id !== tag)); const renderSettingsPanel = () => ( <SidePanel width="300px" onCloseButtonClick={() => {}}> <SidePanel.Header title="Post Settings" showDivider={false}> <Tabs items={[ { id: 0, title: 'General' }, { id: 1, title: 'Advanced' }, ]} activeId={activeTab} type="uniformSide" width="114px" onClick={(value) => setActiveTab(value.id)} /> </SidePanel.Header> <SidePanel.Content> {activeTab === 0 && ( <Box direction="vertical" gap="24px"> <FormField label="Display cover image" labelPlacement="left"> <ToggleSwitch width="100%" checked={toggleImage} onChange={() => setToggleImage(!toggleImage)} /> </FormField> {toggleImage && ( <Cell> <Box height="120px"> <AddItem theme="image" tooltipContent="Add Item" /> </Box> </Cell> )} <FormField label="Publish date"> <DatePicker width="100%" placeholderText="Publish Now" popoverProps={{ appendTo: 'scrollParent' }} autoFocus={false} value={publishDate} onChange={(date) => setPublishDate(date)} /> </FormField> <FormField label="Author"> <AutoComplete placeholder="Select Author" options={authorOptions} selectedId={author} popoverProps={{ appendTo: 'window' }} value={author} onSelect={(option) => setAuthor(option.label)} onChange={(event) => setAuthor(event.target.value)} /> </FormField> <FormField label="Set as featured post" labelPlacement="left"> <ToggleSwitch width="100%" checked={togglePosts} onChange={() => setTogglePosts(!togglePosts)} /> </FormField> </Box> )} {activeTab === 1 && ( <Box direction="vertical" gap="24px"> <FormField label="Description"> <InputArea placeholder="Add a description..." value={descriptionValue} onChange={(e) => setDescriptionValue(e.target.value)} maxLength={140} hasCounter /> </FormField> <FormField label="Related post"> <MultiSelect tags={authorTags} options={[ { id: '1', value: 'British authors' }, { id: '2', value: 'French authors' }, ]} customSuffix={ <Box> <TextButton prefixIcon={<Icons.Add />}> Add Posts </TextButton> </Box> } onSelect={(tag) => handleSelectTag(tag, authorTags, setAuthorTags) } onRemoveTag={(tag) => handleRemoveTag(tag, authorTags, setAuthorTags) } /> </FormField> <FormField label="Enable commenting" labelPlacement="left"> <ToggleSwitch width="100%" checked={toggleCommenting} onChange={() => setToggleCommenting(!toggleCommenting)} /> </FormField> </Box> )} </SidePanel.Content> </SidePanel> ); return ( <Layout gap={0}> <Cell> <ComposerHeader backButtonValue="Back"> <ComposerHeader.Actions justifyContent="flex-end"> <ToggleButton labelValue="Undo"> <Icons.Undo /> </ToggleButton> <ToggleButton labelValue="Redo"> <Icons.Redo /> </ToggleButton> </ComposerHeader.Actions> <ComposerHeader.MainActions> <Button skin="inverted">Preview</Button> <Button>Publish</Button> </ComposerHeader.MainActions> </ComposerHeader> </Cell> <Cell> <Box direction="vertical"> <Box gap="0" height="600px"> <ComposerSidebar labelPlacement="bottom" items={items} selectedId={0} /> {selectedSidebar === 0 && renderSettingsPanel()} <Box backgroundColor="D70" width="100%"> <Box width="100%" padding={4}> <StorybookComponents.Placeholder> <Box verticalAlign="middle" align="center" height="100%"> <Text>Composer content area</Text> </Box> </StorybookComponents.Placeholder> </Box> </Box> </Box> </Box> </Cell> </Layout> ); }; ```