-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10015 from storybookjs/feature/global-args
Core: Add global args feature
- Loading branch information
Showing
18 changed files
with
534 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
export default { | ||
title: 'addons/useGlobalArgs', | ||
}; | ||
|
||
export const PassedToStory = ({ globalArgs }) => { | ||
return ( | ||
<div> | ||
<h3>Global args:</h3> | ||
<pre>{JSON.stringify(globalArgs)}</pre> | ||
</div> | ||
); | ||
}; | ||
|
||
PassedToStory.propTypes = { | ||
globalArgs: PropTypes.shape({}).isRequired, | ||
}; | ||
|
||
export const SecondStory = ({ globalArgs }) => { | ||
return ( | ||
<div> | ||
<h3>Global args (2):</h3> | ||
<pre>{JSON.stringify(globalArgs)}</pre> | ||
</div> | ||
); | ||
}; | ||
|
||
SecondStory.propTypes = { | ||
globalArgs: PropTypes.shape({}).isRequired, | ||
}; |
68 changes: 68 additions & 0 deletions
68
examples/official-storybook/stories/core/globalArgs.stories.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React, { useState } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { useGlobalArgs } from '@storybook/client-api'; | ||
|
||
// eslint-disable-next-line react/prop-types | ||
const ArgUpdater = ({ args, updateArgs }) => { | ||
const [argsInput, updateArgsInput] = useState(JSON.stringify(args)); | ||
|
||
return ( | ||
<div> | ||
<h3>Hooks args:</h3> | ||
<pre>{JSON.stringify(args)}</pre> | ||
<form | ||
onSubmit={e => { | ||
e.preventDefault(); | ||
updateArgs(JSON.parse(argsInput)); | ||
}} | ||
> | ||
<textarea value={argsInput} onChange={e => updateArgsInput(e.target.value)} /> | ||
<br /> | ||
<button type="submit">Change</button> | ||
</form> | ||
</div> | ||
); | ||
}; | ||
|
||
export default { | ||
title: 'Core/Global Args', | ||
decorators: [ | ||
story => { | ||
const [globalArgs, updateGlobalArgs] = useGlobalArgs(); | ||
|
||
return ( | ||
<> | ||
{story()} | ||
<ArgUpdater args={globalArgs} updateArgs={updateGlobalArgs} /> | ||
</> | ||
); | ||
}, | ||
], | ||
}; | ||
|
||
export const PassedToStory = ({ globalArgs }) => { | ||
return ( | ||
<div> | ||
<h3>Global args:</h3> | ||
<pre>{JSON.stringify(globalArgs)}</pre> | ||
</div> | ||
); | ||
}; | ||
|
||
PassedToStory.propTypes = { | ||
globalArgs: PropTypes.shape({}).isRequired, | ||
}; | ||
|
||
export const SecondStory = ({ globalArgs }) => { | ||
return ( | ||
<div> | ||
<h3>Global args (2):</h3> | ||
<pre>{JSON.stringify(globalArgs)}</pre> | ||
</div> | ||
); | ||
}; | ||
|
||
SecondStory.propTypes = { | ||
globalArgs: PropTypes.shape({}).isRequired, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { UPDATE_GLOBAL_ARGS, GLOBAL_ARGS_UPDATED } from '@storybook/core-events'; | ||
import { Args, Module, API } from '../index'; | ||
|
||
export interface SubState { | ||
globalArgs: Args; | ||
} | ||
|
||
export interface SubAPI { | ||
updateGlobalArgs: (newGlobalArgs: Args) => void; | ||
} | ||
|
||
const initGlobalArgsApi = ({ store }: Module) => { | ||
let fullApi: API; | ||
const updateGlobalArgs = (newGlobalArgs: Args) => { | ||
if (!fullApi) throw new Error('Cannot set global args until api has been initialized'); | ||
|
||
fullApi.emit(UPDATE_GLOBAL_ARGS, newGlobalArgs); | ||
}; | ||
|
||
const api: SubAPI = { | ||
updateGlobalArgs, | ||
}; | ||
|
||
const state: SubState = { | ||
// Currently global args always start empty. TODO -- should this be set on the channel at init time? | ||
globalArgs: {}, | ||
}; | ||
|
||
const init = ({ api: inputApi }: { api: API }) => { | ||
fullApi = inputApi; | ||
fullApi.on(GLOBAL_ARGS_UPDATED, (globalArgs: Args) => store.setState({ globalArgs })); | ||
}; | ||
|
||
return { | ||
api, | ||
state, | ||
init, | ||
}; | ||
}; | ||
|
||
export default initGlobalArgsApi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import EventEmitter from 'event-emitter'; | ||
import { UPDATE_GLOBAL_ARGS, GLOBAL_ARGS_UPDATED } from '@storybook/core-events'; | ||
|
||
import { Module, API } from '../index'; | ||
import initGlobalArgs from '../modules/globalArgs'; | ||
|
||
function createMockStore() { | ||
let state = {}; | ||
return { | ||
getState: jest.fn().mockImplementation(() => state), | ||
setState: jest.fn().mockImplementation(s => { | ||
state = { ...state, ...s }; | ||
}), | ||
}; | ||
} | ||
|
||
function createMockModule() { | ||
// This mock module doesn't have all the fields but we don't use them all in this sub-module | ||
return ({ store: createMockStore() } as unknown) as Module; | ||
} | ||
|
||
describe('stories API', () => { | ||
it('sets a sensible initialState', () => { | ||
const { state } = initGlobalArgs(createMockModule()); | ||
|
||
expect(state).toEqual({ | ||
globalArgs: {}, | ||
}); | ||
}); | ||
|
||
it('updates the state when the preview emits GLOBAL_ARGS_UPDATED', () => { | ||
const mod = createMockModule(); | ||
const { state, init } = initGlobalArgs(mod); | ||
mod.store.setState(state); | ||
|
||
const api = new EventEmitter() as API; | ||
init({ api }); | ||
|
||
api.emit(GLOBAL_ARGS_UPDATED, { a: 'b' }); | ||
expect(mod.store.getState()).toEqual({ globalArgs: { a: 'b' } }); | ||
|
||
api.emit(GLOBAL_ARGS_UPDATED, { a: 'c' }); | ||
expect(mod.store.getState()).toEqual({ globalArgs: { a: 'c' } }); | ||
|
||
// SHOULD NOT merge global args | ||
api.emit(GLOBAL_ARGS_UPDATED, { d: 'e' }); | ||
expect(mod.store.getState()).toEqual({ globalArgs: { d: 'e' } }); | ||
}); | ||
|
||
it('emits UPDATE_GLOBAL_ARGS when updateGlobalArgs is called', () => { | ||
const { init, api } = initGlobalArgs({} as Module); | ||
|
||
const fullApi = ({ emit: jest.fn(), on: jest.fn() } as unknown) as API; | ||
init({ api: fullApi }); | ||
|
||
api.updateGlobalArgs({ a: 'b' }); | ||
expect(fullApi.emit).toHaveBeenCalledWith(UPDATE_GLOBAL_ARGS, { a: 'b' }); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.