@storybook/addon-ondevice-controls
Version:
Display storybook controls on your device.
43 lines (42 loc) • 2.19 kB
JavaScript
import { useState, useEffect, useCallback } from 'react';
import { UPDATE_STORY_ARGS, RESET_STORY_ARGS, STORY_ARGS_UPDATED, } from 'storybook/internal/core-events';
// Controls must work with the unmapped values, same as web: `story.args` holds
// the mapped values, so a mapped `select` can't match them back to its options.
const getControlArgs = (story) => story.unmappedArgs ?? story.args;
export const useArgs = (storyId, storyStore) => {
// Reading a story runs `prepareContext` (arg mapping, conditional filtering),
// so only do it when the args state needs (re)initializing, not every render.
const getStoryControlArgs = useCallback(() => {
const story = storyStore.fromId(storyId);
if (!story) {
throw new Error(`Unknown story: ${storyId}`);
}
return getControlArgs(story);
}, [storyId, storyStore]);
const [args, setArgs] = useState(getStoryControlArgs);
useEffect(() => {
// Sync the args up with the initial args of the story, since the story ID
// must have changed for this effect to run.
// eslint-disable-next-line react-hooks/set-state-in-effect
setArgs(getStoryControlArgs());
const cb = (changed) => {
if (changed.storyId === storyId) {
// The STORY_ARGS_UPDATED payload comes straight from the ArgsStore,
// which holds unmapped args — no need to re-read the story here.
setArgs(changed.args);
}
};
storyStore._channel.on(STORY_ARGS_UPDATED, cb);
return () => storyStore._channel.off(STORY_ARGS_UPDATED, cb);
// Exclude `getStoryControlArgs` from the dependencies; it only varies with
// `storyId`.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [storyId]);
const updateArgs = useCallback((newArgs) => {
storyStore._channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs: newArgs });
}, [storyId, storyStore]);
const resetArgs = useCallback((argNames) => {
storyStore._channel.emit(RESET_STORY_ARGS, { storyId, argNames });
}, [storyId, storyStore]);
return [args, updateArgs, resetArgs];
};