diff --git a/app/react-native-server/src/client/manager/provider.js b/app/react-native-server/src/client/manager/provider.js index 688ed6f7e833..4d54264b5de3 100644 --- a/app/react-native-server/src/client/manager/provider.js +++ b/app/react-native-server/src/client/manager/provider.js @@ -46,6 +46,10 @@ export default class ReactProvider extends Provider { return addons.getElements(type); } + getConfig() { + return this.addons.getConfig(); + } + renderPreview() { return ( diff --git a/examples/dev-kits/addons.js b/examples/dev-kits/addons.js index 67087bd7bb9b..eb60732417bb 100644 --- a/examples/dev-kits/addons.js +++ b/examples/dev-kits/addons.js @@ -1,2 +1,9 @@ import '@storybook/addon-roundtrip/register'; import '@storybook/addon-parameter/register'; + +import { addons } from '@storybook/addons'; +import { themes } from '@storybook/theming'; + +addons.setConfig({ + theme: themes.dark, +}); diff --git a/lib/addons/src/index.ts b/lib/addons/src/index.ts index 06f3ef859171..e5861058c88e 100644 --- a/lib/addons/src/index.ts +++ b/lib/addons/src/index.ts @@ -39,6 +39,10 @@ interface Elements { [key: string]: Collection; } +interface Config { + [key: string]: any; +} + export class AddonStore { constructor() { this.promise = new Promise(res => { @@ -50,6 +54,8 @@ export class AddonStore { private elements: Elements = {}; + private config: Config = {}; + private channel: Channel | undefined; private promise: any; @@ -96,6 +102,12 @@ export class AddonStore { collection[name] = { id: name, ...addon }; }; + setConfig = (value: Config) => { + Object.assign(this.config, value); + }; + + getConfig = () => this.config; + register = (name: string, registerCallback: (api: API) => void): void => { if (this.loaders[name]) { logger.warn(`${name} was loaded twice, this could have bad side-effects`); diff --git a/lib/api/src/modules/layout.ts b/lib/api/src/modules/layout.ts index 7aa99602b3b6..33d19635158f 100644 --- a/lib/api/src/modules/layout.ts +++ b/lib/api/src/modules/layout.ts @@ -8,6 +8,7 @@ import { themes, ThemeVars } from '@storybook/theming'; import merge from '../lib/merge'; import { State } from '../index'; import Store from '../store'; +import { Provider } from '../init-provider-api'; export type PanelPositions = 'bottom' | 'right'; @@ -153,7 +154,7 @@ export const focusableUIElements = { }; let hasSetOptions = false; -export default function({ store }: { store: Store }) { +export default function({ store, provider }: { store: Store; provider: Provider }) { const api = { toggleFullscreen(toggled?: boolean) { return store.setState((state: State) => { @@ -248,6 +249,15 @@ export default function({ store }: { store: Store }) { } }, + getInitialOptions() { + const { theme } = provider.getConfig(); + + return { + ...initial, + theme: theme || initial.theme, + }; + }, + setOptions: (options: any) => { // The very first time the user sets their options, we don't consider what is in the store. // At this point in time, what is in the store is what we *persisted*. We did that in order @@ -255,7 +265,9 @@ export default function({ store }: { store: Store }) { // However, we don't want to have a memory about these things, otherwise we see bugs like the // user setting a name for their storybook, persisting it, then never being able to unset it // without clearing localstorage. See https://github.com/storybookjs/storybook/issues/5857 - const { layout, ui, selectedPanel, theme } = hasSetOptions ? store.getState() : initial; + const { layout, ui, selectedPanel, theme } = hasSetOptions + ? store.getState() + : api.getInitialOptions(); if (options) { const updatedLayout = { @@ -301,5 +313,5 @@ export default function({ store }: { store: Store }) { const persisted = pick(store.getState(), 'layout', 'ui', 'selectedPanel', 'theme'); - return { api, state: merge(initial, persisted) }; + return { api, state: merge(api.getInitialOptions(), persisted) }; } diff --git a/lib/api/src/tests/layout.test.js b/lib/api/src/tests/layout.test.js index b0109304db71..dbf644d9a53d 100644 --- a/lib/api/src/tests/layout.test.js +++ b/lib/api/src/tests/layout.test.js @@ -33,7 +33,7 @@ describe('layout API', () => { getState: () => currentState, setState: jest.fn(), }; - layoutApi = initLayout({ store }).api; + layoutApi = initLayout({ store, provider: { getConfig: jest.fn(() => ({})) } }).api; }); it('should not change selectedPanel if it is undefined in the options', () => { diff --git a/lib/core/src/client/manager/provider.js b/lib/core/src/client/manager/provider.js index 8ebdf8dee184..d40e0b1a7bf9 100644 --- a/lib/core/src/client/manager/provider.js +++ b/lib/core/src/client/manager/provider.js @@ -20,6 +20,10 @@ export default class ReactProvider extends Provider { return this.addons.getElements(type); } + getConfig() { + return this.addons.getConfig(); + } + handleAPI(api) { this.addons.loadAddons(api); } diff --git a/lib/ui/src/app.stories.js b/lib/ui/src/app.stories.js index c18c4ed37ebb..db6eb8e57c28 100644 --- a/lib/ui/src/app.stories.js +++ b/lib/ui/src/app.stories.js @@ -28,6 +28,10 @@ class FakeProvider extends Provider { handleAPI(api) { addons.loadAddons(api); } + + getConfig() { + return {}; + } } storiesOf('UI|Layout/App', module) diff --git a/lib/ui/src/provider.js b/lib/ui/src/provider.js index 6114e44d0d09..e9df2c7cc116 100644 --- a/lib/ui/src/provider.js +++ b/lib/ui/src/provider.js @@ -6,4 +6,8 @@ export default class Provider { handleAPI() { throw new Error('Provider.handleAPI() is not implemented!'); } + + getConfig() { + throw new Error('Provider.getConfig() is not implemented!'); + } }