diff --git a/packages/eui/.storybook/decorator.tsx b/packages/eui/.storybook/decorator.tsx new file mode 100644 index 00000000000..10e265a13de --- /dev/null +++ b/packages/eui/.storybook/decorator.tsx @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { useState, useMemo, FunctionComponent } from 'react'; +import { css } from '@emotion/react'; +import type { Preview } from '@storybook/react'; + +import { EuiThemeColorMode } from '../src/services'; +import { EuiProvider, EuiProviderProps } from '../src/components/provider'; + +/** + * Primary EuiProvider decorator to wrap around all stories + * @see https://storybook.js.org/docs/writing-stories/decorators + */ +export const EuiProviderDecorator: FunctionComponent< + EuiProviderProps<{}> & { + writingMode: WritingModes; + } +> = ({ children, writingMode, ...euiProviderProps }) => { + // Append portals into Storybook's root div (rather than ) + // so that loki correctly captures them for VRT screenshots + const [sibling, setPortalSibling] = useState(null); + const portalInsert = useMemo(() => { + if (sibling) { + return { + EuiPortal: { insert: { sibling, position: 'after' as const } }, + }; + } + }, [sibling]); + + // Set CSS writing mode/direction on story-wrapper + const writingModeCss = useMemo( + () => [{ label: 'writingMode' }, writingModeStyles[writingMode]], + [writingMode] + ); + + return ( + +
+ {portalInsert && children} +
+
+ ); +}; + +/** + * Styles used for testing CSS logical properties + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_writing_modes + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties + */ +const writingModeStyles = { + ltr: css` + direction: ltr; + `, + rtl: css` + direction: rtl; + `, + 'vertical-lr': css` + writing-mode: vertical-lr; + `, + 'vertical-rl': css` + writing-mode: vertical-rl; + `, + // Sideways RL is the same as vertical RL + sideways: css` + writing-mode: sideways-lr; + `, +}; +type WritingModes = keyof typeof writingModeStyles; + +/** + * Storybook toolbar types - define these separately so that we can ensure + * their values match ones that EuiProviderDecorator expects + */ +type ToolbarDisplay = { title: string; icon: string }; + +const storybookToolbarColorModes: Array< + ToolbarDisplay & { value: EuiThemeColorMode } +> = [ + { value: 'light', title: 'Light mode', icon: 'circlehollow' }, + { value: 'dark', title: 'Dark mode', icon: 'circle' }, +]; + +const storybookToolbarWritingModes: Array< + ToolbarDisplay & { value: WritingModes } +> = [ + { value: 'ltr', title: 'LTR', icon: 'arrowleft' }, + { value: 'rtl', title: 'RTL', icon: 'arrowright' }, + { value: 'vertical-lr', title: 'Vertical LTR', icon: 'arrowup' }, + { value: 'vertical-rl', title: 'Vertical RTL', icon: 'arrowdown' }, + { value: 'sideways', title: 'Sideways LTR', icon: 'collapse' }, +]; + +/** + * Export Storybook toolbar globals/context that affect our EuiProvider decorator + * @see https://storybook.js.org/docs/essentials/toolbars-and-globals + */ +export const euiProviderDecoratorGlobals: Preview['globalTypes'] = { + colorMode: { + description: 'Color mode for EuiProvider theme', + defaultValue: 'light', + toolbar: { + title: 'Color mode', + items: storybookToolbarColorModes, + dynamicTitle: true, + }, + }, + writingMode: { + description: 'Writing mode for testing logical property directions', + defaultValue: 'ltr', + toolbar: { + title: 'Writing mode', + items: storybookToolbarWritingModes, + dynamicTitle: true, + }, + }, +}; diff --git a/packages/eui/.storybook/preview.tsx b/packages/eui/.storybook/preview.tsx index b103c083dd0..c34435f5032 100644 --- a/packages/eui/.storybook/preview.tsx +++ b/packages/eui/.storybook/preview.tsx @@ -10,7 +10,6 @@ import React from 'react'; import type { Preview } from '@storybook/react'; -import { useState, useMemo } from '@storybook/preview-api'; import { MINIMAL_VIEWPORTS } from '@storybook/addon-viewport'; /* @@ -29,12 +28,6 @@ Object.entries(typeToPathMap).forEach(async ([iconType, iconFileName]) => { }); appendIconComponentCache(iconCache); -/* - * Theming - */ -import { EuiProvider } from '../src/components/provider'; -import { writingModeStyles } from './writing_mode.styles'; - /** * Ensure that any provider errors throw & warn us early */ @@ -42,82 +35,25 @@ import { setEuiDevProviderWarning } from '../src/services'; setEuiDevProviderWarning('error'); /** - * Prop controls + * Custom global decorators */ - -import type { CommonProps } from '../src/components/common'; - import { customJsxDecorator } from './addons/code-snippet/decorators/jsx_decorator'; -import { hideStorybookControls } from './utils'; +import { EuiProviderDecorator, euiProviderDecoratorGlobals } from './decorator'; const preview: Preview = { decorators: [ customJsxDecorator, - (Story, context) => { - const [portalSibling, setPortalSibling] = useState( - null - ); - const portalInsert = useMemo(() => { - if (portalSibling) { - return { - EuiPortal: { - insert: { sibling: portalSibling, position: 'after' as const }, - }, - }; - } - }, [portalSibling]); - - return ( - -
*/ - id="story-wrapper" - css={[ - writingModeStyles.writingMode, - // @ts-ignore - we're manually ensuring `writingMode` globals match our Emotion style keys - writingModeStyles[context.globals.writingMode], - ]} - > - {portalInsert && } -
-
- ); - }, + (Story, context) => ( + + + + ), ], - globalTypes: { - colorMode: { - description: 'Color mode for EuiProvider theme', - defaultValue: 'light', - toolbar: { - title: 'Color mode', - items: [ - { value: 'light', title: 'Light mode', icon: 'circlehollow' }, - { value: 'dark', title: 'Dark mode', icon: 'circle' }, - ], - dynamicTitle: true, - }, - }, - writingMode: { - description: 'Writing mode for testing logical property directions', - defaultValue: 'ltr', - toolbar: { - title: 'Writing mode', - items: [ - { value: 'ltr', title: 'LTR', icon: 'arrowleft' }, - { value: 'rtl', title: 'RTL', icon: 'arrowright' }, - { value: 'vertical-lr', title: 'Vertical LTR', icon: 'arrowup' }, - { value: 'vertical-rl', title: 'Vertical RTL', icon: 'arrowdown' }, - { value: 'sideways', title: 'Sideways LTR', icon: 'collapse' }, - ], - dynamicTitle: true, - }, - }, - }, + globalTypes: { ...euiProviderDecoratorGlobals }, parameters: { backgrounds: { disable: true }, // Use colorMode instead options: { @@ -154,10 +90,13 @@ const preview: Preview = { }, }, }; + // Due to CommonProps, these props appear on almost every Story, but generally // aren't super useful to test - let's disable them by default and (if needed) // individual stories can re-enable them, e.g. by passing // `argTypes: { 'data-test-subj': { table: { disable: false } } }` +import type { CommonProps } from '../src/components/common'; +import { hideStorybookControls } from './utils'; hideStorybookControls(preview, [ 'css', 'className', diff --git a/packages/eui/.storybook/writing_mode.styles.ts b/packages/eui/.storybook/writing_mode.styles.ts deleted file mode 100644 index 9eb94d2793a..00000000000 --- a/packages/eui/.storybook/writing_mode.styles.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { css } from '@emotion/react'; - -/** - * Used for testing CSS logical properties - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_writing_modes - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties - */ -export const writingModeStyles = { - writingMode: css``, - ltr: css` - direction: ltr; - `, - rtl: css` - direction: rtl; - `, - 'vertical-lr': css` - writing-mode: vertical-lr; - `, - 'vertical-rl': css` - writing-mode: vertical-rl; - `, - // Sideways RL is the same as vertical RL - sideways: css` - writing-mode: sideways-lr; - `, -};