index.stories.tsx 5.8 KB

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