preview.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import 'focus-visible';
  2. import 'docs-ui/index.js';
  3. import {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, Theme} 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. 'Data Visualization',
  145. 'Alerts',
  146. 'Tags',
  147. 'Badges',
  148. 'Pills',
  149. 'Tooltips',
  150. 'Toast Indicators',
  151. 'Loading Indicators',
  152. 'Avatars',
  153. 'Context Data',
  154. 'Confirm',
  155. 'Well',
  156. ],
  157. 'Views',
  158. [
  159. 'Layout - Narrow',
  160. 'Layout - Thirds',
  161. 'Sidebar Section',
  162. 'Modals',
  163. 'Activity',
  164. 'Empty States',
  165. 'Not Available',
  166. 'Page Heading',
  167. 'Tabs',
  168. 'Breadcrumbs',
  169. 'Detailed Error',
  170. 'Onboarding Panel',
  171. ],
  172. 'Utilities',
  173. [
  174. 'Text',
  175. 'Copy',
  176. 'Clipboard',
  177. 'Highlight',
  178. 'Hidden Content',
  179. 'Lazy Load',
  180. 'Command Line',
  181. 'Get Dynamic Text',
  182. ],
  183. 'Features',
  184. 'Deprecated',
  185. ],
  186. },
  187. },
  188. });
  189. const commonTheme = {
  190. brandTitle: 'Sentry UI System',
  191. brandUrl: '#',
  192. fontBase: '"Rubik", sans-serif',
  193. };
  194. const getThemeColors = (theme: ExtendedTheme) => ({
  195. appBg: theme.bodyBackground,
  196. appContentBg: theme.background,
  197. appBorderColor: theme.innerBorder,
  198. textColor: theme.textColor,
  199. textInverseColor: theme.white,
  200. barTextColor: theme.subText,
  201. barSelectedColor: theme.active,
  202. barBg: theme.background,
  203. inputBg: theme.backgroundElevated,
  204. inputBorder: theme.border,
  205. inputTextColor: theme.textColor,
  206. });
  207. export const parameters: Parameters = {
  208. darkMode: {
  209. dark: {
  210. ...themes.dark,
  211. ...commonTheme,
  212. ...getThemeColors(darkTheme),
  213. },
  214. light: {
  215. ...themes.normal,
  216. ...commonTheme,
  217. ...getThemeColors(lightTheme),
  218. },
  219. },
  220. };
  221. // Configure Emotion to use our theme
  222. declare module '@emotion/react' {
  223. export interface Theme extends ExtendedTheme {}
  224. }