Skip to content

Commit

Permalink
[refactor] move EuiProvider decorator + globalTypes to separate file
Browse files Browse the repository at this point in the history
- cleaner, contain concerns in a single file
  • Loading branch information
cee-chen committed Sep 13, 2024
1 parent 7aedaa0 commit c388067
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 106 deletions.
122 changes: 122 additions & 0 deletions packages/eui/.storybook/decorator.tsx
Original file line number Diff line number Diff line change
@@ -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 <body>)
// so that loki correctly captures them for VRT screenshots
const [sibling, setPortalSibling] = useState<HTMLElement | null>(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 (
<EuiProvider componentDefaults={portalInsert} {...euiProviderProps}>
<div id="story-wrapper" ref={setPortalSibling} css={writingModeCss}>
{portalInsert && children}
</div>
</EuiProvider>
);
};

/**
* 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,
},
},
};
79 changes: 7 additions & 72 deletions packages/eui/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/// <reference types="@emotion/react/types/css-prop" />

import React, { useState, useMemo, FunctionComponent } from 'react';
import React from 'react';
import type { Preview } from '@storybook/react';
import { MINIMAL_VIEWPORTS } from '@storybook/addon-viewport';

Expand All @@ -28,57 +28,17 @@ Object.entries(typeToPathMap).forEach(async ([iconType, iconFileName]) => {
});
appendIconComponentCache(iconCache);

/*
* Theming
*/
import { EuiProvider, EuiProviderProps } from '../src/components/provider';
import { writingModeStyles } from './writing_mode.styles';

/**
* Ensure that any provider errors throw & warn us early
*/
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';

const EuiProviderDecorator: FunctionComponent<
EuiProviderProps<{}> & {
writingMode: 'ltr' | 'rtl' | 'vertical-lr' | 'vertical-rl' | 'sideways';
}
> = ({ children, writingMode, ...euiProviderProps }) => {
// Append portals into Storybook's root div (rather than <body>)
// so that loki correctly captures them for VRT screenshots
const [portalSibling, setPortalSibling] = useState<HTMLElement | null>(null);
const portalInsert = useMemo(() => {
if (portalSibling) {
return {
EuiPortal: {
insert: { sibling: portalSibling, position: 'after' as const },
},
};
}
}, [portalSibling]);

return (
<EuiProvider componentDefaults={portalInsert} {...euiProviderProps}>
<div
ref={setPortalSibling}
id="story-wrapper"
css={[writingModeStyles.writingMode, writingModeStyles[writingMode]]}
>
{portalInsert && children}
</div>
</EuiProvider>
);
};
import { EuiProviderDecorator, euiProviderDecoratorGlobals } from './decorator';

const preview: Preview = {
decorators: [
Expand All @@ -93,35 +53,7 @@ const preview: Preview = {
</EuiProviderDecorator>
),
],
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: {
Expand Down Expand Up @@ -158,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<CommonProps>(preview, [
'css',
'className',
Expand Down
34 changes: 0 additions & 34 deletions packages/eui/.storybook/writing_mode.styles.ts

This file was deleted.

0 comments on commit c388067

Please sign in to comment.