index.stories.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import {Fragment, useState} from 'react';
  2. import range from 'lodash/range';
  3. import JSXNode from 'sentry/components/stories/jsxNode';
  4. import Matrix from 'sentry/components/stories/matrix';
  5. import SideBySide from 'sentry/components/stories/sideBySide';
  6. import SizingWindow from 'sentry/components/stories/sizingWindow';
  7. import type {TabListProps, TabsProps} from 'sentry/components/tabs';
  8. import {TabList, TabPanels, Tabs} from 'sentry/components/tabs';
  9. import storyBook from 'sentry/stories/storyBook';
  10. export default storyBook(Tabs, story => {
  11. const TABS = [
  12. {key: 'one', label: 'One', content: 'This is the first Panel.'},
  13. {key: 'two', label: 'Two', content: 'This is the second panel'},
  14. {key: 'three', label: 'Three', content: 'This is the third panel'},
  15. ];
  16. story('Default', () => (
  17. <Fragment>
  18. <p>
  19. You should be using all of <JSXNode name="Tabs" />, <JSXNode name="TabList" />,{' '}
  20. <JSXNode name="TabList.Item" />, <JSXNode name="TabPanels" /> and
  21. <JSXNode name="TabPanels.Item" /> components.
  22. </p>
  23. <p>
  24. This will give you all kinds of accessibility and state tracking out of the box.
  25. But you will have to render all tab content, including hooks, upfront.
  26. </p>
  27. <SizingWindow>
  28. <Tabs>
  29. <TabList>
  30. {TABS.map(tab => (
  31. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  32. ))}
  33. </TabList>
  34. <TabPanels>
  35. {TABS.map(tab => (
  36. <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
  37. ))}
  38. </TabPanels>
  39. </Tabs>
  40. </SizingWindow>
  41. </Fragment>
  42. ));
  43. story('Items Overflow', () => {
  44. const tabs = range(65, 75).map(i => ({
  45. key: 'i' + i,
  46. label: String.fromCharCode(i, i, i, i),
  47. content: String.fromCharCode(i, i, i, i),
  48. }));
  49. return (
  50. <Fragment>
  51. <p>When there are many items, they will overflow into a dropdown menu.</p>
  52. <SizingWindow display="block" style={{height: '210px', width: '400px'}}>
  53. <Tabs defaultValue="two">
  54. <TabList>
  55. {tabs.map(tab => (
  56. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  57. ))}
  58. </TabList>
  59. </Tabs>
  60. </SizingWindow>
  61. </Fragment>
  62. );
  63. });
  64. story('Default Value', () => (
  65. <Fragment>
  66. <p>
  67. Set <JSXNode name="Tabs" props={{defaultValue: String}} />
  68. </p>
  69. <SizingWindow>
  70. <Tabs defaultValue="two">
  71. <TabList>
  72. {TABS.map(tab => (
  73. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  74. ))}
  75. </TabList>
  76. <TabPanels>
  77. {TABS.map(tab => (
  78. <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
  79. ))}
  80. </TabPanels>
  81. </Tabs>
  82. </SizingWindow>
  83. </Fragment>
  84. ));
  85. story('Controlled Value', () => {
  86. const [selected, setSelected] = useState('two');
  87. return (
  88. <Fragment>
  89. <p>
  90. If you want to control the state of the tabs from outside, you can call{' '}
  91. <var>{'useState()'}</var> and set{' '}
  92. <JSXNode name="Tabs" props={{value: String, onChange: Function}} /> manually.
  93. </p>
  94. <p>
  95. This is useful if you want to detect button clicks and do something different.{' '}
  96. The <JSXNode name="Tabs" /> context wrapper is not required in this case.
  97. </p>
  98. <p>selected={selected}</p>
  99. <SizingWindow>
  100. <Tabs value={selected} onChange={setSelected}>
  101. <TabList>
  102. {TABS.map(tab => (
  103. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  104. ))}
  105. </TabList>
  106. <TabPanels>
  107. {TABS.map(tab => (
  108. <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
  109. ))}
  110. </TabPanels>
  111. </Tabs>
  112. </SizingWindow>
  113. </Fragment>
  114. );
  115. });
  116. story('Rendering', () => (
  117. <Matrix<TabsProps<string> & TabListProps>
  118. render={props => (
  119. <Tabs orientation={props.orientation}>
  120. <TabList hideBorder={props.hideBorder}>
  121. {TABS.map(tab => (
  122. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  123. ))}
  124. </TabList>
  125. <TabPanels>
  126. {TABS.map(tab => (
  127. <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
  128. ))}
  129. </TabPanels>
  130. </Tabs>
  131. )}
  132. propMatrix={{
  133. orientation: ['horizontal', 'vertical'],
  134. hideBorder: [false, true],
  135. }}
  136. selectedProps={['orientation', 'hideBorder']}
  137. />
  138. ));
  139. story('Disabled', () => (
  140. <SideBySide>
  141. <div>
  142. <p>
  143. Use <JSXNode name="Tabs" props={{disabled: true}} /> to disable everything.
  144. </p>
  145. <SizingWindow>
  146. <Tabs disabled>
  147. <TabList>
  148. {TABS.map(tab => (
  149. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  150. ))}
  151. </TabList>
  152. <TabPanels>
  153. {TABS.map(tab => (
  154. <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
  155. ))}
  156. </TabPanels>
  157. </Tabs>
  158. </SizingWindow>
  159. </div>
  160. <div>
  161. <p>
  162. Use <JSXNode name="TabList" props={{disabledKeys: Array}} /> to disable
  163. individual <JSXNode name="TabList.Item" /> children.
  164. </p>
  165. <SizingWindow>
  166. <Tabs>
  167. <TabList disabledKeys={['two']}>
  168. {TABS.map(tab => (
  169. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  170. ))}
  171. </TabList>
  172. <TabPanels>
  173. {TABS.map(tab => (
  174. <TabPanels.Item key={tab.key}>{tab.content}</TabPanels.Item>
  175. ))}
  176. </TabPanels>
  177. </Tabs>
  178. </SizingWindow>
  179. </div>
  180. </SideBySide>
  181. ));
  182. });