preview.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import 'focus-visible';
  2. import 'docs-ui/index.js';
  3. import {Theme, ThemeProvider} from '@emotion/react';
  4. import {DocsContainer, Meta} from '@storybook/addon-docs';
  5. import {addDecorator, addParameters, DecoratorFn, Parameters} from '@storybook/react';
  6. import {themes} from '@storybook/theming';
  7. import Code from 'docs-ui/components/code';
  8. import ColorChip from 'docs-ui/components/colorChip';
  9. import DocsLinks from 'docs-ui/components/docsLinks';
  10. import DoDont from 'docs-ui/components/doDont';
  11. import Sample from 'docs-ui/components/sample';
  12. import TableOfContents from 'docs-ui/components/tableOfContents';
  13. import {useDarkMode} from 'storybook-dark-mode';
  14. import GlobalStyles from 'sentry/styles/global';
  15. import {darkTheme, lightTheme} from 'sentry/utils/theme';
  16. import {DocsGlobalStyles, StoryGlobalStyles} from './globalStyles';
  17. type ExtendedTheme = Theme & {
  18. /**
  19. * [For Storybook only, do not use inside the app.]
  20. *
  21. * Substitute for the "background" property in Storybook components
  22. * (anything inside docs-ui), since Storybook overrides "background" with
  23. * its own object value.
  24. */
  25. docsBackground?: string;
  26. };
  27. // Theme decorator for stories
  28. const WithThemeStory: DecoratorFn = (Story, context) => {
  29. const isDark = useDarkMode();
  30. const currentTheme = isDark ? darkTheme : lightTheme;
  31. // Set @storybook/addon-backgrounds current color based on theme
  32. if (context.globals.theme) {
  33. context.globals.backgrounds = {value: currentTheme.bodyBackground};
  34. }
  35. return (
  36. <ThemeProvider theme={currentTheme}>
  37. <GlobalStyles isDark={isDark} theme={currentTheme} />
  38. <StoryGlobalStyles theme={currentTheme} />
  39. <Story {...context} />
  40. </ThemeProvider>
  41. );
  42. };
  43. addDecorator(WithThemeStory);
  44. // Theme decorator for MDX Docs
  45. const WithThemeDocs: DecoratorFn = ({children, context}) => {
  46. const isDark = useDarkMode();
  47. const currentTheme: ExtendedTheme = isDark ? darkTheme : lightTheme;
  48. currentTheme.docsBackground = currentTheme.background;
  49. // Set @storybook/addon-backgrounds current color based on theme
  50. if (context.globals.theme) {
  51. context.globals.backgrounds = {value: currentTheme.bodyBackground};
  52. }
  53. const {hideToc} = context.parameters;
  54. return (
  55. <ThemeProvider theme={currentTheme}>
  56. <GlobalStyles isDark={isDark} theme={currentTheme} />
  57. <DocsGlobalStyles theme={currentTheme} />
  58. <DocsContainer context={context}>{children}</DocsContainer>
  59. <TableOfContents hidden={!!hideToc} />
  60. </ThemeProvider>
  61. );
  62. };
  63. // Option defaults:
  64. addParameters({
  65. docs: {
  66. container: WithThemeDocs,
  67. components: {Meta, code: Code, ColorChip, DocsLinks, DoDont, Sample},
  68. },
  69. options: {
  70. /**
  71. * show story component as full screen
  72. * @type {Boolean}
  73. */
  74. isFullscreen: false,
  75. /**
  76. * display panel that shows a list of stories
  77. * @type {Boolean}
  78. */
  79. showNav: true,
  80. /**
  81. * display panel that shows addon configurations
  82. * @type {Boolean}
  83. */
  84. showPanel: true,
  85. /**
  86. * where to show the addon panel
  87. * @type {('bottom'|'right')}
  88. */
  89. panelPosition: 'bottom',
  90. /**
  91. * regex for finding the hierarchy separator
  92. * @example:
  93. * null - turn off hierarchy
  94. * /\// - split by `/`
  95. * /\./ - split by `.`
  96. * /\/|\./ - split by `/` or `.`
  97. * @type {Regex}
  98. */
  99. hierarchySeparator: /\/|\./,
  100. /**
  101. * regex for finding the hierarchy root separator
  102. * @example:
  103. * null - turn off multiple hierarchy roots
  104. * /\|/ - split by `|`
  105. * @type {Regex}
  106. */
  107. hierarchyRootSeparator: /\|/,
  108. /**
  109. * sidebar tree animat
  110. * ions
  111. * @type {Boolean}
  112. */
  113. sidebarAnimations: true,
  114. /**
  115. * enable/disable shortcuts
  116. * @type {Boolean}
  117. */
  118. enableShortcuts: true,
  119. /**
  120. * show/hide tool bar
  121. * @type {Boolean}
  122. */
  123. showToolbar: true,
  124. /**
  125. * function to sort stories in the tree view
  126. * common use is alphabetical `(a, b) => a[1].id.localeCompare(b[1].id)`
  127. * if left undefined, then the order in which the stories are imported will
  128. * be the order they display
  129. * @type {Function}
  130. */
  131. storySort: {
  132. order: [
  133. 'Getting Started',
  134. 'Changelog',
  135. 'Core',
  136. ['Overview', 'Colors', 'Typography'],
  137. 'Assets',
  138. ['Icons', 'Logo', 'Platforms'],
  139. 'Components',
  140. [
  141. 'Buttons',
  142. 'Tables',
  143. 'Forms',
  144. 'Segmented Control',
  145. 'Data Visualization',
  146. 'Alerts',
  147. 'Tags',
  148. 'Badges',
  149. 'Pills',
  150. 'Tooltips',
  151. 'Toast Indicators',
  152. 'Loading Indicators',
  153. 'Avatars',
  154. 'Context Data',
  155. 'Confirm',
  156. 'Well',
  157. ],
  158. 'Views',
  159. [
  160. 'Layout - Narrow',
  161. 'Layout - Thirds',
  162. 'Sidebar Section',
  163. 'Modals',
  164. 'Activity',
  165. 'Empty States',
  166. 'Not Available',
  167. 'Page Heading',
  168. 'Tabs',
  169. 'Breadcrumbs',
  170. 'Detailed Error',
  171. 'Onboarding Panel',
  172. ],
  173. 'Utilities',
  174. [
  175. 'Text',
  176. 'Copy',
  177. 'Clipboard',
  178. 'Highlight',
  179. 'Hidden Content',
  180. 'Lazy Load',
  181. 'Command Line',
  182. 'Get Dynamic Text',
  183. ],
  184. 'Features',
  185. 'Deprecated',
  186. ],
  187. },
  188. },
  189. });
  190. const commonTheme = {
  191. brandTitle: 'Sentry UI System',
  192. brandUrl: '#',
  193. fontBase: '"Rubik", sans-serif',
  194. };
  195. const getThemeColors = (theme: ExtendedTheme) => ({
  196. appBg: theme.bodyBackground,
  197. appContentBg: theme.background,
  198. appBorderColor: theme.innerBorder,
  199. textColor: theme.textColor,
  200. textInverseColor: theme.white,
  201. barTextColor: theme.subText,
  202. barSelectedColor: theme.active,
  203. barBg: theme.background,
  204. inputBg: theme.backgroundElevated,
  205. inputBorder: theme.border,
  206. inputTextColor: theme.textColor,
  207. });
  208. export const parameters: Parameters = {
  209. darkMode: {
  210. dark: {
  211. ...themes.dark,
  212. ...commonTheme,
  213. ...getThemeColors(darkTheme),
  214. },
  215. light: {
  216. ...themes.normal,
  217. ...commonTheme,
  218. ...getThemeColors(lightTheme),
  219. },
  220. },
  221. };
  222. // Configure Emotion to use our theme
  223. declare module '@emotion/react' {
  224. export interface Theme extends ExtendedTheme {}
  225. }