From 058f3c22a2eff3b5e266f8d63e760b2d298cd4e7 Mon Sep 17 00:00:00 2001 From: Andrew Lisowski Date: Sat, 9 Mar 2019 10:25:15 -0800 Subject: [PATCH 1/5] switch to hooks --- package.json | 3 --- src/Tool.tsx | 57 ++++++++++++++++++++-------------------------------- 2 files changed, 22 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index d2faa0df..edbf7854 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 80d426da..6ca28c63 100644 --- a/src/Tool.tsx +++ b/src/Tool.tsx @@ -14,20 +14,11 @@ interface DarkModeProps { }; } -interface DarkModeState { - isDark: boolean; -} - -export default class DarkMode extends React.Component< - DarkModeProps, - DarkModeState -> { - state = { - isDark: false - }; +export const DarkModeHooks: React.FunctionComponent = props => { + const [isDark, setDark] = React.useState(false); - setDarkMode = (isDark: boolean) => { - const { parameters } = this.props.api.getCurrentStoryData(); + function setDarkMode() { + const { parameters } = props.api.getCurrentStoryData(); let darkTheme = themes.dark; let lightTheme = themes.light; @@ -37,30 +28,26 @@ export default class DarkMode extends React.Component< lightTheme = parameters.darkMode.light || lightTheme; } - this.props.api.setOptions({ + props.api.setOptions({ isDark, theme: isDark ? darkTheme : lightTheme }); - this.setState({ - isDark - }); - }; - - render() { - const { isDark } = this.state; - - return ( - this.setDarkMode(!this.state.isDark)} - > - {isDark ? : } - - ); + setDark(!isDark); } -} + + return ( + + {isDark ? : } + + ); +}; + +export default DarkModeHooks; From 8d9d466ff4f376354a6be217a925a830ed1bcd51 Mon Sep 17 00:00:00 2001 From: Andrew Lisowski Date: Wed, 13 Mar 2019 12:21:52 -0700 Subject: [PATCH 2/5] use localstorage --- src/Tool.tsx | 107 ++++++++++++++++++++++++++++++++++++++++---------- tsconfig.json | 2 +- 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/Tool.tsx b/src/Tool.tsx index 6ca28c63..9727d37b 100644 --- a/src/Tool.tsx +++ b/src/Tool.tsx @@ -1,41 +1,108 @@ import * as React from 'react'; -import { themes } from '@storybook/theming'; +import { themes, ThemeVars } from '@storybook/theming'; import { IconButton } from '@storybook/components'; 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: { - setOptions(options: any): void; - on(event: string, callback: (data: any) => void): void; - off(event: string, callback: (data: any) => void): void; - getCurrentStoryData(): any; - }; + api: StorybookAPI; } -export const DarkModeHooks: React.FunctionComponent = props => { - const [isDark, setDark] = React.useState(false); +interface DarkModeStore { + current: 'dark' | 'light'; + dark: ThemeVars; + light: ThemeVars; +} - function setDarkMode() { - const { parameters } = props.api.getCurrentStoryData(); +let defaultStore: DarkModeStore = { + current: 'light', + dark: themes.dark, + light: themes.light +}; - let darkTheme = themes.dark; - let lightTheme = themes.light; +const update = (newStore: any) => { + window.localStorage.setItem('sb-addon-themes-3', JSON.stringify(newStore)); +}; + +const store = (themes: { dark?: any; light?: any } = {}): DarkModeStore => { + if (window.localStorage.getItem('sb-addon-themes-3')) { + return JSON.parse(window.localStorage.getItem( + 'sb-addon-themes-3' + ) as string); + } - if (parameters && parameters.darkMode) { - darkTheme = parameters.darkMode.dark || darkTheme; - lightTheme = parameters.darkMode.light || lightTheme; - } + defaultStore = { ...defaultStore, ...themes }; + return defaultStore; +}; - props.api.setOptions({ - isDark, - theme: isDark ? darkTheme : lightTheme +function setTheme({ + api, + toggle, + themes +}: { + api: StorybookAPI; + toggle?: boolean; + themes?: { dark?: ThemeVars; light?: ThemeVars }; +}) { + const currentStore = store(themes); + let { current } = currentStore; + + if (toggle) { + current = currentStore.current === 'dark' ? 'light' : 'dark'; + update({ + ...currentStore, + current }); + } + + api.setOptions({ theme: currentStore[current] }); + return current; +} + +export const DarkModeHooks: React.FunctionComponent = props => { + const [isDark, setDark] = React.useState(false); + + function setDarkMode() { + setTheme({ api: props.api, toggle: true }); setDark(!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 current = setTheme({ + api: props.api, + themes: { + light: lightTheme, + dark: darkTheme + } + }); + + setDark(current === 'dark'); + }); + }, []); + return ( Date: Wed, 13 Mar 2019 12:25:24 -0700 Subject: [PATCH 3/5] get rid of some anys --- src/Tool.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tool.tsx b/src/Tool.tsx index 00e2a6c7..7794f15b 100644 --- a/src/Tool.tsx +++ b/src/Tool.tsx @@ -32,11 +32,11 @@ let defaultStore: DarkModeStore = { light: themes.light }; -const update = (newStore: any) => { +const update = (newStore: DarkModeStore) => { window.localStorage.setItem('sb-addon-themes-3', JSON.stringify(newStore)); }; -const store = (themes: { dark?: any; light?: any } = {}): DarkModeStore => { +const store = (themes: Partial = {}): DarkModeStore => { if (window.localStorage.getItem('sb-addon-themes-3')) { return JSON.parse(window.localStorage.getItem( 'sb-addon-themes-3' From bcd5576f3c838cb1b3c1f5de531c7415d2723167 Mon Sep 17 00:00:00 2001 From: Andrew Lisowski Date: Wed, 13 Mar 2019 12:37:12 -0700 Subject: [PATCH 4/5] simplify --- src/Tool.tsx | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/src/Tool.tsx b/src/Tool.tsx index 7794f15b..8eb1b439 100644 --- a/src/Tool.tsx +++ b/src/Tool.tsx @@ -47,36 +47,19 @@ const store = (themes: Partial = {}): DarkModeStore => { return defaultStore; }; -function setTheme({ - api, - toggle, - themes -}: { - api: StorybookAPI; - toggle?: boolean; - themes?: { dark?: ThemeVars; light?: ThemeVars }; -}) { - const currentStore = store(themes); - let { current } = currentStore; - - if (toggle) { - current = currentStore.current === 'dark' ? 'light' : 'dark'; +export const DarkMode: React.FunctionComponent = props => { + const [isDark, setDark] = React.useState(false); + + function setDarkMode() { + const currentStore = store(); + const current = currentStore.current === 'dark' ? 'light' : 'dark'; + update({ ...currentStore, current }); - } - api.setOptions({ theme: currentStore[current] }); - - return current; -} - -export const DarkModeHooks: React.FunctionComponent = props => { - const [isDark, setDark] = React.useState(false); - - function setDarkMode() { - setTheme({ api: props.api, toggle: true }); + props.api.setOptions({ theme: currentStore[current] }); setDark(!isDark); props.channel.emit('DARK_MODE', !isDark); } @@ -95,14 +78,13 @@ export const DarkModeHooks: React.FunctionComponent = props => { lightTheme = parameters.darkMode.light || lightTheme; } - const current = setTheme({ - api: props.api, - themes: { - light: lightTheme, - dark: darkTheme - } + 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'); }); @@ -122,4 +104,4 @@ export const DarkModeHooks: React.FunctionComponent = props => { ); }; -export default DarkModeHooks; +export default DarkMode; From 60b8086221089c5c0fe2c15af841100d5e272833 Mon Sep 17 00:00:00 2001 From: Andrew Lisowski Date: Wed, 13 Mar 2019 12:41:29 -0700 Subject: [PATCH 5/5] allow user to change options --- src/Tool.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Tool.tsx b/src/Tool.tsx index 8eb1b439..7494cc36 100644 --- a/src/Tool.tsx +++ b/src/Tool.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; 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'; @@ -38,9 +39,21 @@ const update = (newStore: DarkModeStore) => { const store = (themes: Partial = {}): DarkModeStore => { if (window.localStorage.getItem('sb-addon-themes-3')) { - return JSON.parse(window.localStorage.getItem( + const stored = JSON.parse(window.localStorage.getItem( 'sb-addon-themes-3' - ) as string); + ) as string) as DarkModeStore; + + if (themes) { + if (themes.dark && !equal(stored.dark, themes.dark)) { + stored.dark = themes.dark; + } + + if (themes.light && !equal(stored.light, themes.light)) { + stored.light = themes.light; + } + } + + return stored; } defaultStore = { ...defaultStore, ...themes };