-
-
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 #6601 from storybooks/add/addon-contexts/url-query…
…-param Add URL query param feature
- Loading branch information
Showing
26 changed files
with
276 additions
and
183 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 |
---|---|---|
@@ -1,7 +1,38 @@ | ||
import { withContexts } from './preview/frameworks/react'; | ||
export { withContexts }; | ||
export default withContexts; | ||
import { makeDecorator, StoryWrapper } from '@storybook/addons'; | ||
import { ContextsPreviewAPI } from './preview/ContextsPreviewAPI'; | ||
import { ID, PARAM } from './shared/constants'; | ||
import { AddonSetting, AnyFunctionReturns, ContextNode, PropsMap } from './shared/types'; | ||
|
||
console.error( | ||
`[addon-contexts] Deprecation warning: "import { withContexts } from 'addon-contexts'" has been deprecated. Please import from 'addon-contexts/react' instead.` | ||
); | ||
/** | ||
* This file serves a idiomatic facade of a Storybook decorator. | ||
* | ||
* Wrapper function get called whenever the Storybook rerender the view. This reflow logic is | ||
* framework agnostic; on the other hand, the framework specific bindings are the implementation | ||
* details hidden behind the passed `render` function. | ||
* | ||
* Here, we need a dedicated singleton as a state manager for preview (the addon API, in vanilla) | ||
* who is also knowing how to communicate with the Storybook manager (in React) via the Storybook | ||
* event system. | ||
* | ||
* @param {Render} render - framework specific bindings | ||
*/ | ||
export type Render<T> = (...args: [ContextNode[], PropsMap, AnyFunctionReturns<T>]) => T; | ||
type CreateAddonDecorator = <T>(render: Render<T>) => (contexts: AddonSetting[]) => unknown; | ||
|
||
export const createAddonDecorator: CreateAddonDecorator = render => { | ||
const wrapper: StoryWrapper = (getStory, context, settings: any) => { | ||
const { getContextNodes, getSelectionState, getPropsMap } = ContextsPreviewAPI(); | ||
const nodes = getContextNodes(settings); | ||
const state = getSelectionState(); | ||
const props = getPropsMap(nodes, state); | ||
return render(nodes, props, () => getStory(context)); | ||
}; | ||
|
||
return makeDecorator({ | ||
name: ID, | ||
parameterName: PARAM, | ||
skipIfNoParametersOrOptions: true, | ||
allowDeprecatedUsage: false, | ||
wrapper, | ||
}); | ||
}; |
This file was deleted.
Oops, something went wrong.
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, { useEffect, useState, useCallback } from 'react'; | ||
import { useChannel } from './libs/useChannel'; | ||
import { ToolBar } from './components/ToolBar'; | ||
import { deserialize, serialize } from '../shared/serializers'; | ||
import { PARAM, REBOOT_MANAGER, UPDATE_MANAGER, UPDATE_PREVIEW } from '../shared/constants'; | ||
import { FCNoChildren, ManagerAPI, SelectionState } from '../shared/types'; | ||
|
||
/** | ||
* A smart component for handling manager-preview interactions | ||
*/ | ||
type ContextsManager = FCNoChildren<{ | ||
api: ManagerAPI; | ||
}>; | ||
|
||
export const ContextsManager: ContextsManager = ({ api }) => { | ||
const [nodes, setNodes] = useState([]); | ||
const [state, setState] = useState<SelectionState>(deserialize(api.getQueryParam(PARAM))); | ||
const setSelected = useCallback( | ||
(nodeId, name) => setState(obj => ({ ...obj, [nodeId]: name })), | ||
[] | ||
); | ||
|
||
// from preview | ||
useChannel(UPDATE_MANAGER, newNodes => setNodes(newNodes), []); | ||
|
||
// to preview | ||
useEffect(() => api.emit(REBOOT_MANAGER), []); | ||
useEffect(() => api.emit(UPDATE_PREVIEW, state), [state]); | ||
useEffect(() => api.setQueryParams({ [PARAM]: serialize(state) }), [state]); | ||
|
||
return <ToolBar nodes={nodes} state={state || {}} setSelected={setSelected} />; | ||
}; |
2 changes: 1 addition & 1 deletion
2
addons/contexts/src/manager/ToolBar.tsx → ...ntexts/src/manager/components/ToolBar.tsx
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
2 changes: 1 addition & 1 deletion
2
addons/contexts/src/manager/ToolBarMenu.tsx → ...ts/src/manager/components/ToolBarMenu.tsx
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
4 changes: 2 additions & 2 deletions
4
...ntexts/src/manager/ToolBarMenuOptions.tsx → ...manager/components/ToolBarMenuOptions.tsx
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,81 @@ | ||
import addons from '@storybook/addons'; | ||
import { parse } from 'qs'; | ||
import { getContextNodes, getPropsMap, getRendererFrom, singleton } from './libs'; | ||
import { deserialize } from '../shared/serializers'; | ||
import { | ||
PARAM, | ||
REBOOT_MANAGER, | ||
UPDATE_PREVIEW, | ||
UPDATE_MANAGER, | ||
FORCE_RE_RENDER, | ||
SET_CURRENT_STORY, | ||
} from '../shared/constants'; | ||
import { ContextNode, PropsMap, SelectionState } from '../shared/types'; | ||
|
||
/** | ||
* A singleton for handling preview-manager and one-time-only side-effects | ||
*/ | ||
export const ContextsPreviewAPI = singleton(() => { | ||
const channel = addons.getChannel(); | ||
let contextsNodesMemo: ContextNode[] = null; | ||
let selectionState: SelectionState = {}; | ||
|
||
/** | ||
* URL query param can be used to predetermine the contexts a story should render, | ||
* which is useful for performing image snapshot testing or URL sharing. | ||
*/ | ||
if (window && window.location) { | ||
const contextQuery = parse(window.location.search)[PARAM]; | ||
if (contextQuery) { | ||
selectionState = deserialize(contextQuery); | ||
} | ||
} | ||
|
||
/** | ||
* (Vue specific) | ||
* Vue will inject getter/setters on the first rendering of the addon, | ||
* which is the reason why we have to keep an internal reference and use `Object.assign` to update it. | ||
*/ | ||
let reactivePropsMap = {}; | ||
const updateReactiveSystem = (propsMap: PropsMap) => | ||
/* tslint:disable:prefer-object-spread */ | ||
Object.assign(reactivePropsMap, propsMap); | ||
|
||
/** | ||
* Preview-manager communications. | ||
*/ | ||
// from manager | ||
channel.on(SET_CURRENT_STORY, () => (contextsNodesMemo = null)); | ||
channel.on(REBOOT_MANAGER, () => channel.emit(UPDATE_MANAGER, contextsNodesMemo)); | ||
channel.on(UPDATE_PREVIEW, state => { | ||
if (state) { | ||
selectionState = state; | ||
channel.emit(FORCE_RE_RENDER); | ||
} | ||
}); | ||
|
||
// to manager | ||
const getContextNodesWithSideEffects: typeof getContextNodes = (...arg) => { | ||
// we want to notify the manager only when the story changed since `parameter` can be changed | ||
if (contextsNodesMemo === null) { | ||
contextsNodesMemo = getContextNodes(...arg); | ||
channel.emit(UPDATE_MANAGER, contextsNodesMemo); | ||
} | ||
return contextsNodesMemo; | ||
}; | ||
|
||
/** | ||
* @Public | ||
* Exposed interfaces | ||
*/ | ||
return { | ||
// methods get called on Storybook event lifecycle | ||
getContextNodes: getContextNodesWithSideEffects, | ||
getSelectionState: () => selectionState, | ||
getPropsMap, | ||
|
||
// methods for processing framework specific bindings | ||
getRendererFrom, | ||
updateReactiveSystem, | ||
}; | ||
}); |
This file was deleted.
Oops, something went wrong.
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.