1 | import "core-js/modules/es.array.reduce.js";
|
2 | import React, { Component, Fragment, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
|
3 | import mergeWith from 'lodash/mergeWith';
|
4 | import { STORY_CHANGED, SHARED_STATE_CHANGED, SHARED_STATE_SET, SET_STORIES } from '@storybook/core-events';
|
5 | import { createContext } from './context';
|
6 | import Store from './store';
|
7 | import getInitialState from './initial-state';
|
8 | import { isGroup, isRoot, isStory } from './lib/stories';
|
9 | import * as provider from './modules/provider';
|
10 | import * as addons from './modules/addons';
|
11 | import * as channel from './modules/channel';
|
12 | import * as notifications from './modules/notifications';
|
13 | import * as settings from './modules/settings';
|
14 | import * as releaseNotes from './modules/release-notes';
|
15 | import * as stories from './modules/stories';
|
16 | import * as refs from './modules/refs';
|
17 | import * as layout from './modules/layout';
|
18 | import * as shortcuts from './modules/shortcuts';
|
19 | import * as url from './modules/url';
|
20 | import * as version from './modules/versions';
|
21 | import * as globals from './modules/globals';
|
22 | const {
|
23 | ActiveTabs
|
24 | } = layout;
|
25 | export { default as merge } from './lib/merge';
|
26 | export { ActiveTabs };
|
27 | const ManagerContext = createContext({
|
28 | api: undefined,
|
29 | state: getInitialState({})
|
30 | });
|
31 |
|
32 | export const combineParameters = (...parameterSets) => mergeWith({}, ...parameterSets, (objValue, srcValue) => {
|
33 |
|
34 | if (Array.isArray(srcValue)) return srcValue;
|
35 | return undefined;
|
36 | });
|
37 |
|
38 | class ManagerProvider extends Component {
|
39 | constructor(props) {
|
40 | super(props);
|
41 | this.api = {};
|
42 | this.modules = void 0;
|
43 |
|
44 | this.initModules = () => {
|
45 |
|
46 |
|
47 | this.modules.forEach(({
|
48 | init
|
49 | }) => {
|
50 | if (init) {
|
51 | init();
|
52 | }
|
53 | });
|
54 | };
|
55 |
|
56 | const {
|
57 | location,
|
58 | path,
|
59 | refId,
|
60 | viewMode = props.docsMode ? 'docs' : 'story',
|
61 | singleStory,
|
62 | storyId,
|
63 | docsMode,
|
64 | navigate
|
65 | } = props;
|
66 | const store = new Store({
|
67 | getState: () => this.state,
|
68 | setState: (stateChange, callback) => this.setState(stateChange, callback)
|
69 | });
|
70 | const routeData = {
|
71 | location,
|
72 | path,
|
73 | viewMode,
|
74 | singleStory,
|
75 | storyId,
|
76 | refId
|
77 | };
|
78 |
|
79 |
|
80 |
|
81 | const docsModeState = {
|
82 | layout: {
|
83 | showToolbar: false,
|
84 | showPanel: false
|
85 | },
|
86 | ui: {
|
87 | docsMode: true
|
88 | }
|
89 | };
|
90 | this.state = store.getInitialState(getInitialState(Object.assign({}, routeData, docsMode ? docsModeState : null)));
|
91 | const apiData = {
|
92 | navigate,
|
93 | store,
|
94 | provider: props.provider
|
95 | };
|
96 | this.modules = [provider, channel, addons, layout, notifications, settings, releaseNotes, shortcuts, stories, refs, globals, url, version].map(m => m.init(Object.assign({}, routeData, apiData, {
|
97 | state: this.state,
|
98 | fullAPI: this.api
|
99 | })));
|
100 |
|
101 | const state = getInitialState(this.state, ...this.modules.map(m => m.state));
|
102 |
|
103 | const api = Object.assign(this.api, {
|
104 | navigate
|
105 | }, ...this.modules.map(m => m.api));
|
106 | this.state = state;
|
107 | this.api = api;
|
108 | }
|
109 |
|
110 | static getDerivedStateFromProps(props, state) {
|
111 | if (state.path !== props.path) {
|
112 | return Object.assign({}, state, {
|
113 | location: props.location,
|
114 | path: props.path,
|
115 | refId: props.refId,
|
116 |
|
117 | viewMode: (props.docsMode && props.viewMode) === 'story' ? 'docs' : props.viewMode,
|
118 | storyId: props.storyId
|
119 | });
|
120 | }
|
121 |
|
122 | return null;
|
123 | }
|
124 |
|
125 | shouldComponentUpdate(nextProps, nextState) {
|
126 | const prevState = this.state;
|
127 | const prevProps = this.props;
|
128 |
|
129 | if (prevState !== nextState) {
|
130 | return true;
|
131 | }
|
132 |
|
133 | if (prevProps.path !== nextProps.path) {
|
134 | return true;
|
135 | }
|
136 |
|
137 | return false;
|
138 | }
|
139 |
|
140 | render() {
|
141 | const {
|
142 | children
|
143 | } = this.props;
|
144 | const value = {
|
145 | state: this.state,
|
146 | api: this.api
|
147 | };
|
148 | return React.createElement(EffectOnMount, {
|
149 | effect: this.initModules
|
150 | }, React.createElement(ManagerContext.Provider, {
|
151 | value: value
|
152 | }, React.createElement(ManagerConsumer, null, children)));
|
153 | }
|
154 |
|
155 | }
|
156 |
|
157 | ManagerProvider.displayName = "ManagerProvider";
|
158 | ManagerProvider.displayName = 'Manager';
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 | const EffectOnMount = ({
|
166 | children,
|
167 | effect
|
168 | }) => {
|
169 | React.useEffect(effect, []);
|
170 | return children;
|
171 | };
|
172 |
|
173 | const defaultFilter = c => c;
|
174 |
|
175 | function ManagerConsumer({
|
176 | // @ts-ignore
|
177 | filter = defaultFilter,
|
178 | children
|
179 | }) {
|
180 | const c = useContext(ManagerContext);
|
181 | const renderer = useRef(children);
|
182 | const filterer = useRef(filter);
|
183 |
|
184 | if (typeof renderer.current !== 'function') {
|
185 | return React.createElement(Fragment, null, renderer.current);
|
186 | }
|
187 |
|
188 | const data = filterer.current(c);
|
189 | const l = useMemo(() => {
|
190 | return [...Object.entries(data).reduce((acc, keyval) => acc.concat(keyval), [])];
|
191 | }, [c.state]);
|
192 | return useMemo(() => {
|
193 | const Child = renderer.current;
|
194 | return React.createElement(Child, data);
|
195 | }, l);
|
196 | }
|
197 |
|
198 | export function useStorybookState() {
|
199 | const {
|
200 | state
|
201 | } = useContext(ManagerContext);
|
202 | return state;
|
203 | }
|
204 | export function useStorybookApi() {
|
205 | const {
|
206 | api
|
207 | } = useContext(ManagerContext);
|
208 | return api;
|
209 | }
|
210 | export { ManagerConsumer as Consumer, ManagerProvider as Provider, isGroup, isRoot, isStory };
|
211 |
|
212 | function orDefault(fromStore, defaultState) {
|
213 | if (typeof fromStore === 'undefined') {
|
214 | return defaultState;
|
215 | }
|
216 |
|
217 | return fromStore;
|
218 | }
|
219 |
|
220 | export const useChannel = (eventMap, deps = []) => {
|
221 | const api = useStorybookApi();
|
222 | useEffect(() => {
|
223 | Object.entries(eventMap).forEach(([type, listener]) => api.on(type, listener));
|
224 | return () => {
|
225 | Object.entries(eventMap).forEach(([type, listener]) => api.off(type, listener));
|
226 | };
|
227 | }, deps);
|
228 | return api.emit;
|
229 | };
|
230 | export function useStoryPrepared(storyId) {
|
231 | const api = useStorybookApi();
|
232 | return api.isPrepared(storyId);
|
233 | }
|
234 | export function useParameter(parameterKey, defaultValue) {
|
235 | const api = useStorybookApi();
|
236 | const result = api.getCurrentParameter(parameterKey);
|
237 | return orDefault(result, defaultValue);
|
238 | }
|
239 |
|
240 | const addonStateCache = {};
|
241 |
|
242 | export function useSharedState(stateId, defaultState) {
|
243 | const api = useStorybookApi();
|
244 | const existingState = api.getAddonState(stateId);
|
245 | const state = orDefault(existingState, addonStateCache[stateId] ? addonStateCache[stateId] : defaultState);
|
246 |
|
247 | const setState = (s, options) => {
|
248 |
|
249 | if (addonStateCache[stateId]) {
|
250 | addonStateCache[stateId] = s;
|
251 | }
|
252 |
|
253 | api.setAddonState(stateId, s, options);
|
254 | };
|
255 |
|
256 | const allListeners = useMemo(() => {
|
257 | const stateChangeHandlers = {
|
258 | [`${SHARED_STATE_CHANGED}-client-${stateId}`]: s => setState(s),
|
259 | [`${SHARED_STATE_SET}-client-${stateId}`]: s => setState(s)
|
260 | };
|
261 | const stateInitializationHandlers = {
|
262 | [SET_STORIES]: () => {
|
263 | const currentState = api.getAddonState(stateId);
|
264 |
|
265 | if (currentState) {
|
266 | addonStateCache[stateId] = currentState;
|
267 | api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, currentState);
|
268 | } else if (addonStateCache[stateId]) {
|
269 |
|
270 | setState(addonStateCache[stateId]);
|
271 | api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, addonStateCache[stateId]);
|
272 | } else if (defaultState !== undefined) {
|
273 |
|
274 | setState(defaultState);
|
275 |
|
276 | addonStateCache[stateId] = defaultState;
|
277 | api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, defaultState);
|
278 | }
|
279 | },
|
280 | [STORY_CHANGED]: () => {
|
281 | const currentState = api.getAddonState(stateId);
|
282 |
|
283 | if (currentState !== undefined) {
|
284 | api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, currentState);
|
285 | }
|
286 | }
|
287 | };
|
288 | return Object.assign({}, stateChangeHandlers, stateInitializationHandlers);
|
289 | }, [stateId]);
|
290 | const emit = useChannel(allListeners);
|
291 | return [state, (newStateOrMerger, options) => {
|
292 | setState(newStateOrMerger, options);
|
293 | emit(`${SHARED_STATE_CHANGED}-manager-${stateId}`, newStateOrMerger);
|
294 | }];
|
295 | }
|
296 | export function useAddonState(addonId, defaultState) {
|
297 | return useSharedState(addonId, defaultState);
|
298 | }
|
299 | export function useArgs() {
|
300 | const {
|
301 | getCurrentStoryData,
|
302 | updateStoryArgs,
|
303 | resetStoryArgs
|
304 | } = useStorybookApi();
|
305 | const data = getCurrentStoryData();
|
306 | const args = isStory(data) ? data.args : {};
|
307 | const updateArgs = useCallback(newArgs => updateStoryArgs(data, newArgs), [data, updateStoryArgs]);
|
308 | const resetArgs = useCallback(argNames => resetStoryArgs(data, argNames), [data, resetStoryArgs]);
|
309 | return [args, updateArgs, resetArgs];
|
310 | }
|
311 | export function useGlobals() {
|
312 | const api = useStorybookApi();
|
313 | return [api.getGlobals(), api.updateGlobals];
|
314 | }
|
315 | export function useGlobalTypes() {
|
316 | return useStorybookApi().getGlobalTypes();
|
317 | }
|
318 |
|
319 | function useCurrentStory() {
|
320 | const {
|
321 | getCurrentStoryData
|
322 | } = useStorybookApi();
|
323 | return getCurrentStoryData();
|
324 | }
|
325 |
|
326 | export function useArgTypes() {
|
327 | var _useCurrentStory;
|
328 |
|
329 | return ((_useCurrentStory = useCurrentStory()) === null || _useCurrentStory === void 0 ? void 0 : _useCurrentStory.argTypes) || {};
|
330 | } |
\ | No newline at end of file |