diff --git a/package.json b/package.json index bce2edda..80180f38 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,6 @@ "build": "tsc", "release": "auto shipit" }, - "peerDependencies": { - "react": "*" - }, "devDependencies": { "@types/react": "^16.8.6", "@typescript-eslint/eslint-plugin": "^1.4.2", diff --git a/src/Tool.tsx b/src/Tool.tsx index 239b6233..7494cc36 100644 --- a/src/Tool.tsx +++ b/src/Tool.tsx @@ -1,71 +1,120 @@ import * as React from 'react'; -import { themes } from '@storybook/theming'; +import { themes, ThemeVars } from '@storybook/theming'; import { IconButton } from '@storybook/components'; +import equal from 'fast-deep-equal'; import Sun from './icons/Sun'; import Moon from './icons/Moon'; +interface StorybookAPI { + getChannel(): { on(event: string, cb: () => void): void }; + setOptions(options: any): void; + on(event: string, callback: (data: any) => void): void; + off(event: string, callback: (data: any) => void): void; + getCurrentStoryData(): any; +} + interface DarkModeProps { + api: StorybookAPI; channel: { emit(event: string, value: any): void; }; - api: { - setOptions(options: any): void; - on(event: string, callback: (data: any) => void): void; - off(event: string, callback: (data: any) => void): void; - getCurrentStoryData(): any; - }; } -interface DarkModeState { - isDark: boolean; +interface DarkModeStore { + current: 'dark' | 'light'; + dark: ThemeVars; + light: ThemeVars; } -export default class DarkMode extends React.Component< - DarkModeProps, - DarkModeState - > { - state = { - isDark: false - }; +let defaultStore: DarkModeStore = { + current: 'light', + dark: themes.dark, + light: themes.light +}; + +const update = (newStore: DarkModeStore) => { + window.localStorage.setItem('sb-addon-themes-3', JSON.stringify(newStore)); +}; - setDarkMode = (isDark: boolean) => { - const { parameters } = this.props.api.getCurrentStoryData(); +const store = (themes: Partial = {}): DarkModeStore => { + if (window.localStorage.getItem('sb-addon-themes-3')) { + const stored = JSON.parse(window.localStorage.getItem( + 'sb-addon-themes-3' + ) as string) as DarkModeStore; - let darkTheme = themes.dark; - let lightTheme = themes.light; + if (themes) { + if (themes.dark && !equal(stored.dark, themes.dark)) { + stored.dark = themes.dark; + } - if (parameters && parameters.darkMode) { - darkTheme = parameters.darkMode.dark || darkTheme; - lightTheme = parameters.darkMode.light || lightTheme; + if (themes.light && !equal(stored.light, themes.light)) { + stored.light = themes.light; + } } - this.props.api.setOptions({ - isDark, - theme: isDark ? darkTheme : lightTheme - }); + return stored; + } + + defaultStore = { ...defaultStore, ...themes }; + return defaultStore; +}; + +export const DarkMode: React.FunctionComponent = props => { + const [isDark, setDark] = React.useState(false); - this.setState({ - isDark - }, () => { - this.props.channel.emit('DARK_MODE', isDark); + function setDarkMode() { + const currentStore = store(); + const current = currentStore.current === 'dark' ? 'light' : 'dark'; + + update({ + ...currentStore, + current }); - }; - render() { - const { isDark } = this.state; - - return ( - this.setDarkMode(!this.state.isDark)} - > - {isDark ? : } - - ); + props.api.setOptions({ theme: currentStore[current] }); + setDark(!isDark); + props.channel.emit('DARK_MODE', !isDark); } -} + + React.useEffect(() => { + const channel = props.api.getChannel(); + + channel.on('storiesConfigured', () => { + const { parameters } = props.api.getCurrentStoryData(); + + let darkTheme = themes.dark; + let lightTheme = themes.light; + + if (parameters && parameters.darkMode) { + darkTheme = parameters.darkMode.dark || darkTheme; + lightTheme = parameters.darkMode.light || lightTheme; + } + + const currentStore = store({ + light: lightTheme, + dark: darkTheme + }); + const { current } = currentStore; + + props.api.setOptions({ theme: currentStore[current] }); + setDark(current === 'dark'); + props.channel.emit('DARK_MODE', current === 'dark'); + }); + }, []); + + return ( + + {isDark ? : } + + ); +}; + +export default DarkMode; diff --git a/tsconfig.json b/tsconfig.json index eabcf323..87e9440d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "declaration": true, - "lib": ["es2017"], + "lib": ["es2017", "dom"], "jsx": "react", "moduleResolution": "node", // "allowSyntheticDefaultImports": true,