fbredius/storybook

View on GitHub
lib/ui/src/settings/index.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import { useStorybookApi, useStorybookState } from '@storybook/api';
import { IconButton, Icons, FlexBar, TabBar, TabButton, ScrollArea } from '@storybook/components';
import { Location, Route } from '@storybook/router';
import { styled } from '@storybook/theming';
import global from 'global';
import React, { FunctionComponent, SyntheticEvent, Fragment } from 'react';

import { AboutPage } from './about_page';
import { ReleaseNotesPage } from './release_notes_page';
import { ShortcutsPage } from './shortcuts_page';
import { matchesModifiers, matchesKeyCode } from '../keybinding';

const { document } = global;

const TabBarButton = React.memo<{
  changeTab: (tab: string) => void;
  id: string;
  title: string;
}>(({ changeTab, id, title }) => (
  <Location>
    {({ path }) => {
      const active = path.includes(`settings/${id}`);
      return (
        <TabButton
          id={`tabbutton-${id}`}
          className={['tabbutton'].concat(active ? ['tabbutton-active'] : []).join(' ')}
          type="button"
          key="id"
          active={active}
          onClick={() => changeTab(id)}
          role="tab"
        >
          {title}
        </TabButton>
      );
    }}
  </Location>
));

const Content = styled(ScrollArea)(
  {
    position: 'absolute',
    top: 40,
    left: 0,
    right: 0,
    bottom: 0,
    overflow: 'auto',
  },
  ({ theme }) => ({
    background: theme.background.content,
  })
);

const Pages: FunctionComponent<{
  onClose: () => void;
  enableShortcuts?: boolean;
  hasReleaseNotes?: boolean;
  changeTab: (tab: string) => void;
}> = ({ changeTab, onClose, enableShortcuts = true, hasReleaseNotes = false }) => {
  React.useEffect(() => {
    const handleEscape = (event: KeyboardEvent) => {
      if (!enableShortcuts || event.repeat) return;
      if (matchesModifiers(false, event) && matchesKeyCode('Escape', event)) {
        event.preventDefault();
        onClose();
      }
    };
    document.addEventListener('keydown', handleEscape);
    return () => document.removeEventListener('keydown', handleEscape);
  }, []);

  return (
    <Fragment>
      <FlexBar border>
        <TabBar role="tablist">
          <TabBarButton id="about" title="About" changeTab={changeTab} />
          {hasReleaseNotes && (
            <TabBarButton id="release-notes" title="Release notes" changeTab={changeTab} />
          )}
          <TabBarButton id="shortcuts" title="Keyboard shortcuts" changeTab={changeTab} />
        </TabBar>
        <IconButton
          onClick={(e: SyntheticEvent) => {
            e.preventDefault();
            return onClose();
          }}
          title="Close settings page"
        >
          <Icons icon="close" />
        </IconButton>
      </FlexBar>
      <Content vertical horizontal={false}>
        <Route path="about">
          <AboutPage key="about" />
        </Route>
        <Route path="release-notes">
          <ReleaseNotesPage key="release-notes" />
        </Route>
        <Route path="shortcuts">
          <ShortcutsPage key="shortcuts" />
        </Route>
      </Content>
    </Fragment>
  );
};

const SettingsPages: FunctionComponent = () => {
  const api = useStorybookApi();
  const state = useStorybookState();
  const changeTab = (tab: string) => api.changeSettingsTab(tab);

  return (
    <Pages
      hasReleaseNotes={!!api.releaseNotesVersion()}
      enableShortcuts={state.ui.enableShortcuts}
      changeTab={changeTab}
      onClose={api.closeSettings}
    />
  );
};

export { SettingsPages as default };