import React, { Component, Fragment } from 'react';
import memoize from 'memoizerific';
import { API } from '@storybook/api';
import { SET_STORIES } from '@storybook/core-events';
import { Icons, IconButton, WithTooltip, TooltipLinkList } from '@storybook/components';
import { CHANGE, DECORATOR, THEME } from '../constants';
import { Theme, ThemeSelectorItem } from '../models';
import { getConfigFromApi, getSelectedTheme, getSelectedThemeName } from '../shared';
import { ColorIcon } from './ColorIcon';
import { ThemeStory } from './ThemeStory';
const iframeId = 'storybook-preview-iframe';
const createThemeSelectorItem = memoize(1000)(
(
id: string,
title: string,
color: string,
hasSwatch: boolean,
change: (arg: { selected: string; expanded: boolean }) => void,
active: boolean,
): ThemeSelectorItem => ({
id,
title,
onClick: () => {
change({ selected: id, expanded: false });
},
value: id,
right: hasSwatch ? : undefined,
active,
})
);
const getDisplayableState = memoize(10)(
(props: ThemeToolProps, state: ThemeToolState, change) => {
const { clearable, list, target, default: defaultTheme } = getConfigFromApi(props.api);
const selectedThemeName = getSelectedThemeName(list, defaultTheme, state.selected);
let availableThemeSelectorItems: ThemeSelectorItem[] = [];
let selectedTheme: Theme;
if (selectedThemeName !== 'none' && clearable) {
availableThemeSelectorItems.push(
createThemeSelectorItem('none', 'Clear theme', 'transparent', null, change, false)
);
}
if (list.length) {
availableThemeSelectorItems = [
...availableThemeSelectorItems,
...list.map(({ color, name }) =>
createThemeSelectorItem(name, name, color, true, change, name === selectedThemeName)
),
];
selectedTheme = getSelectedTheme(list, selectedThemeName);
}
return {
items: availableThemeSelectorItems,
selectedTheme,
themes: list,
target,
};
}
);
interface ThemeToolProps {
api: API;
}
interface ThemeToolState {
decorator: boolean,
selected: string;
expanded: boolean;
}
export class ThemeSelector extends Component {
state: ThemeToolState = {
decorator: false,
selected: null,
expanded: false,
};
private setStories = () => this.setState({ selected: null });
private setTheme = (theme: string) => this.setState({ selected: theme });
private setDecorator = () => this.setState({ decorator: true });
componentDidMount() {
const { api } = this.props;
api.on(SET_STORIES, this.setStories);
api.on(THEME, this.setTheme);
api.on(DECORATOR, this.setDecorator);
}
componentWillUnmount() {
const { api } = this.props;
api.off(SET_STORIES, this.setStories);
api.off(THEME, this.setTheme);
api.off(DECORATOR, this.setDecorator);
}
change = (args: { selected: string; expanded: boolean }) => {
const { selected } = args;
const { api } = this.props;
const { list, onChange } = getConfigFromApi(api);
this.setState(args);
api.emit(CHANGE, selected);
if (typeof onChange === 'function') {
const selectedTheme = getSelectedTheme(list, selected);
onChange(selectedTheme);
}
};
render() {
const { decorator, expanded } = this.state;
const { items, selectedTheme, target, themes } = getDisplayableState(
this.props,
this.state,
this.change
);
return items.length ? (
{!decorator && (
)}
this.setState({ expanded: newVisibility })
}
tooltip={}
closeOnClick
>
) : null;
}
}