preview.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import { useLayoutEffect } from 'react';
  2. import type { Decorator, Preview } from '@storybook/react-vite';
  3. import { ConfigProvider } from 'antd';
  4. import i18next from 'i18next';
  5. import { initReactI18next } from 'react-i18next';
  6. import { buildAntdThemeConfig } from '@/hooks/useTheme';
  7. import enUS from '../../internal/web/translation/en-US.json';
  8. if (!i18next.isInitialized) {
  9. void i18next.use(initReactI18next).init({
  10. lng: 'en-US',
  11. fallbackLng: 'en-US',
  12. resources: { 'en-US': { translation: enUS } },
  13. interpolation: { escapeValue: false, prefix: '{', suffix: '}' },
  14. returnNull: false,
  15. });
  16. }
  17. export const withTheme: Decorator = (Story, context) => {
  18. const dark = context.globals.theme === 'dark';
  19. useLayoutEffect(() => {
  20. document.body.classList.remove('dark', 'light');
  21. document.body.classList.add(dark ? 'dark' : 'light');
  22. document.documentElement.style.colorScheme = dark ? 'dark' : 'light';
  23. document.documentElement.removeAttribute('data-theme');
  24. }, [dark]);
  25. return (
  26. // The click wave outlives its story and re-renders from a ResizeObserver
  27. // inside the next story's act(), tripping React's act-environment warning.
  28. <ConfigProvider theme={buildAntdThemeConfig(dark, false)} wave={{ disabled: true }}>
  29. <div style={{ padding: 24, minWidth: 320 }}>
  30. <Story />
  31. </div>
  32. </ConfigProvider>
  33. );
  34. };
  35. const preview: Preview = {
  36. decorators: [withTheme],
  37. globalTypes: {
  38. theme: {
  39. description: 'Ant Design theme',
  40. defaultValue: 'light',
  41. toolbar: {
  42. title: 'Theme',
  43. icon: 'circlehollow',
  44. items: [
  45. { value: 'light', title: 'Light' },
  46. { value: 'dark', title: 'Dark' },
  47. ],
  48. dynamicTitle: true,
  49. },
  50. },
  51. },
  52. parameters: {
  53. controls: {
  54. expanded: true,
  55. sort: 'requiredFirst',
  56. matchers: {
  57. color: /(background|color)$/i,
  58. date: /Date$/i,
  59. },
  60. },
  61. a11y: {
  62. test: 'error',
  63. },
  64. },
  65. };
  66. export default preview;