grommet/grommet

View on GitHub
storybook/preview.js

Summary

Maintainability
A
2 hrs
Test Coverage
import React, { useState, useEffect } from 'react';
import Root from 'react-shadow';
import { StyleSheetManager } from 'styled-components';
import { hpe } from 'grommet-theme-hpe';
import isChromatic from 'chromatic/isChromatic';
import { Grommet, grommet, hacktoberfest2022, Box, Text } from '../src/js';

const CUSTOM_THEMED = 'Custom Themed';
const THEMES = {
  hpe,
  grommet,
  hacktoberfest2022,
  base: {},
};

export const decorators = [
  (Story, context) => {
    const [rootRef, setRootRef] = useState(null);
    const [state, setState] = useState('grommet');
    const [root, setRoot] = useState('document');
    const full = context.allArgs?.full || 'min';
    const dir = context.allArgs?.dir;
    const options = context.allArgs?.options;

    useEffect(() => {
      setState(context.globals.theme);
    }, [context.globals.theme]);
    useEffect(() => {
      setRoot(context.globals.root);
    }, [context.globals.root]);

    /**
     * This demonstrates that custom themed stories are driven off the "base"
     * theme. Custom themed stories will live under a "CustomThemed" directory.
     */
    if (context.kind.split('/')[2] === CUSTOM_THEMED && state !== 'base') {
      // if we are running the story in chromatic we want the chromatic snapshot
      // to be taken in the base theme for custom theme stories
      if (isChromatic()) {
        return (
          <Grommet theme={THEMES.base}>
            <Story state={THEMES.base} />
          </Grommet>
        );
      }
      return (
        <Box align="center" pad="large">
          <Text size="large">
            {`Custom themed stories are only displayed in the
                "base" theme mode. To enable, select "base" from the
                Theme menu above.`}
          </Text>
          <div hidden>
            <Story state={THEMES[state]} />
          </div>
        </Box>
      );
    }

    if (root === 'shadow') {
      return (
        // eslint-disable-next-line react/jsx-pascal-case
        <Root.div ref={setRootRef}>
          {rootRef && (
            <StyleSheetManager target={rootRef.shadowRoot}>
              <Grommet
                theme={THEMES[state]}
                full={full}
                dir={dir}
                options={options}
                containerTarget={rootRef.shadowRoot}
              >
                <Story state={THEMES[state]} />
              </Grommet>
            </StyleSheetManager>
          )}
        </Root.div>
      );
    }

    return (
      <Grommet theme={THEMES[state]} full={full} dir={dir} options={options}>
        <Story state={THEMES[state]} />
      </Grommet>
    );
  },
];

export const parameters = {
  layout: 'fullscreen',
  options: {
    storySort: (first, second) => {
      /**
       * The story sort algorithm will only ever compare two stories
       * a single time. This means that every story will only ever be either
       * the "first" parameter OR the "second" parameter, but not both.
       * So, the checks for custom themed stories need to happen on both inputs
       * of this function.
       *
       * A return value of 1 results in sorting the "first" story AFTER the
       * "second" story.
       *
       * A return value of 0 results in sorting the "first" story BEFORE the
       * secondary story.
       */
      const isFirstCustom = first[1].kind.split('/')[2] === CUSTOM_THEMED;
      const isSecondCustom = second[1].kind.split('/')[2] === CUSTOM_THEMED;
      if (isFirstCustom) return 1;
      if (isSecondCustom) return 0;
      return first[1].kind === second[1].kind
        ? 0
        : first[1].id.localeCompare(second[1].id, undefined, { numeric: true });
    },
  },
};

export const globalTypes = {
  theme: {
    defaultValue: 'grommet',
    toolbar: {
      title: 'Theme',
      items: [
        { title: 'base', value: 'base' },
        { title: 'grommet', value: 'grommet' },
        { title: 'hpe', value: 'hpe' },
        { title: 'hacktoberfest2022', value: 'hacktoberfest2022' },
      ],
    },
  },
  root: {
    defaultValue: 'document',
    toolbar: {
      title: 'Root',
      items: ['document', 'shadow'],
    },
  },
};