Files
2024-02-15 17:01:50 +00:00

191 lines
5.9 KiB
TypeScript

import {Fragment, useState} from 'react';
import range from 'lodash/range';
import JSXNode from 'sentry/components/stories/jsxNode';
import Matrix from 'sentry/components/stories/matrix';
import SideBySide from 'sentry/components/stories/sideBySide';
import SizingWindow from 'sentry/components/stories/sizingWindow';
import type {TabListProps, TabsProps} from 'sentry/components/tabs';
import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
import storyBook from 'sentry/stories/storyBook';
export default storyBook(Tabs, story => {
const TABS = [
{key: 'one', label: 'One', content: 'This is the first Panel.'},
{key: 'two', label: 'Two', content: 'This is the second panel'},
{key: 'three', label: 'Three', content: 'This is the third panel'},
];
story('Default', () => (
<Fragment>
<p>
You should be using all of <JSXNode name="Tabs" />, <JSXNode name="TabList" />,{' '}
<JSXNode name="TabList.Item" />, <JSXNode name="TabPanels" /> and
<JSXNode name="TabPanels.Item" /> components.
</p>
<p>
This will give you all kinds of accessibility and state tracking out of the box.
But you will have to render all tab content, including hooks, upfront.
</p>
<SizingWindow>
<Tabs>
<TabList>
{TABS.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
<TabPanels>
{TABS.map(tab => (
<TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
))}
</TabPanels>
</Tabs>
</SizingWindow>
</Fragment>
));
story('Items Overflow', () => {
const tabs = range(65, 75).map(i => ({
key: 'i' + i,
label: String.fromCharCode(i, i, i, i),
content: String.fromCharCode(i, i, i, i),
}));
return (
<Fragment>
<p>When there are many items, they will overflow into a dropdown menu.</p>
<SizingWindow display="block" style={{height: '210px', width: '400px'}}>
<Tabs defaultValue="two">
<TabList>
{tabs.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
</Tabs>
</SizingWindow>
</Fragment>
);
});
story('Default Value', () => (
<Fragment>
<p>
Set <JSXNode name="Tabs" props={{defaultValue: String}} />
</p>
<SizingWindow>
<Tabs defaultValue="two">
<TabList>
{TABS.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
<TabPanels>
{TABS.map(tab => (
<TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
))}
</TabPanels>
</Tabs>
</SizingWindow>
</Fragment>
));
story('Controlled Value', () => {
const [selected, setSelected] = useState('two');
return (
<Fragment>
<p>
If you want to control the state of the tabs from outside, you can call{' '}
<var>{'useState()'}</var> and set{' '}
<JSXNode name="Tabs" props={{value: String, onChange: Function}} /> manually.
</p>
<p>
This is useful if you want to detect button clicks and do something different.{' '}
The <JSXNode name="Tabs" /> context wrapper is not required in this case.
</p>
<p>selected={selected}</p>
<SizingWindow>
<Tabs value={selected} onChange={setSelected}>
<TabList>
{TABS.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
<TabPanels>
{TABS.map(tab => (
<TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
))}
</TabPanels>
</Tabs>
</SizingWindow>
</Fragment>
);
});
story('Rendering', () => (
<Matrix<TabsProps<string> & TabListProps>
render={props => (
<Tabs orientation={props.orientation}>
<TabList hideBorder={props.hideBorder}>
{TABS.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
<TabPanels>
{TABS.map(tab => (
<TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
))}
</TabPanels>
</Tabs>
)}
propMatrix={{
orientation: ['horizontal', 'vertical'],
hideBorder: [false, true],
}}
selectedProps={['orientation', 'hideBorder']}
/>
));
story('Disabled', () => (
<SideBySide>
<div>
<p>
Use <JSXNode name="Tabs" props={{disabled: true}} /> to disable everything.
</p>
<SizingWindow>
<Tabs disabled>
<TabList>
{TABS.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
<TabPanels>
{TABS.map(tab => (
<TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
))}
</TabPanels>
</Tabs>
</SizingWindow>
</div>
<div>
<p>
Use <JSXNode name="TabList" props={{disabledKeys: Array}} /> to disable
individual <JSXNode name="TabList.Item" /> children.
</p>
<SizingWindow>
<Tabs>
<TabList disabledKeys={['two']}>
{TABS.map(tab => (
<TabList.Item key={tab.key}>{tab.label}</TabList.Item>
))}
</TabList>
<TabPanels>
{TABS.map(tab => (
<TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
))}
</TabPanels>
</Tabs>
</SizingWindow>
</div>
</SideBySide>
));
});