How can I use a story in another story without copy & pasting it? #109
Replies: 3 comments 2 replies
-
I have been able to get a version of this working, but it looks a little odd. I'll try to point out the key pieces. Wondering if there is a better way. :) import { html, TemplateResult } from 'lit';
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
import './example-component';
const configuration = {
title: 'Example/Example',
component: 'example-component',
argTypes: {
exampleSlot: {
name: 'slot="example"',
description: '...',
table: {
category: 'Slots',
},
control: { type: 'text' },
},
},
args: {
exampleSlot: `
<div slot="example">hello world</div>
`,
},
};
export default configuration;
const Template = (customArguments = {}): TemplateResult => {
const args = {
...configuration.args,
...customArguments,
};
return html`
<example-component>
${unsafeHTML(args.exampleSlot ?? '')}
</example-component>
`;
};
export const ExampleStory = (customArguments = {}) => Template(customArguments);
export const ExampleStoryWithCustomArguments = () => Template({
exampleSlot: `
<div slot="example">something different</div>
`,
}); import { html } from 'lit';
import { Meta, Canvas, Story } from '@storybook/addon-docs/blocks';
import { ExampleStory } from '../../../components/example-component/example-component.stories';
<Meta title="Page Demos/Demo Page" />
<Canvas>
<Story name="Demo page">
html`
${ExampleStory()}
${ExampleStory({exampleSlot: `<div slot="example">customized here</div>`})}
`
</Story>
</Canvas> DetailsA story needs to be a function. The So, I made a wrapper that was simpler? and more explicit. export const ExampleStory = (customArguments = {}) => Template(customArguments); This takes an optional object of arguments which are combined in the template. This allows us to call the story from another story and get the a copy of that story since it's all contained in one function. In the story, this does the combining. const Template = (customArguments = {}): TemplateResult => {
const args = {
...configuration.args,
...customArguments,
};
// ...
} It's the same for all stories and supports autocomplete. Instead of exporting the configuration straight up, I found I needed to save it to a variable and then use export default configuration; This let me access the object in the Summary
You can remove defaults by setting them to { exampleSlot: null } Issues / ChallengesStorybook sometimes claims that controls are not configured for the stories, but the controls are shown and they work. If they don't right away, you may need to restart storybook. |
Beta Was this translation helpful? Give feedback.
-
I ran into an issue with this pattern. export const ExampleStory = (customArguments = {}) => Template(customArguments);
export const ExampleStoryWithCustomArguments = () => Template({
exampleSlot: `
<div slot="example">something different</div>
`,
}); 3 things we'd like to have working:
Essentially, the first case works as expected. The second, doesn't. This is what I was able to get working, but it is clunky. I'm not sure how much of an issue that is though because we have yet to find a use case for loading a non-default story in another story. We usually load the default and pass in the customizations. const ExampleStoryWithCustomArguments = ExampleStory.bind({});
ExampleStoryWithCustomArguments.args = {
exampleSlot: `
<div slot="example">something different</div>
`,
}
export { ExampleStoryWithCustomArguments }; Then call it in another story with ${ExampleStoryWithCustomArguments(ExampleStoryWithCustomArguments.args)} I tried a few others solutions. export const ExampleStoryWithCustomArguments = (customArguments = {}) => Template({
...customArguments,
exampleSlot: `
<div slot="example">something different</div>
`,
}); This works except that you cannot override the example slot. You can override any arguments that are defaults. This is a little confusing in the Storybook UI. This is mitigated by the fact that you can still use the story that uses all the defaults to mess around. I think what is happening here is that Storybook always passes in the combined defaults + control changes as the argument to the story function. At that point, we don't really know which is used and we only want to set our per-story default if it hasn't been changed by controls. Choose first
|
Beta Was this translation helpful? Give feedback.
-
A little more digging this is what I was able to come up with.
import { html, TemplateResult } from 'lit';
import './outline-example';
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
const configuration = {
title: 'Content/Example',
component: 'outline-example',
// This is important so that the controls show up consistently.
argTypes: {
mySlot: {
description: 'My slot.',
control: { type: 'text' },
},
},
// These values are used if the story is loaded from another story without any arguments.
args: {
mySlot: `<div slot="my-slot">Hello World</div>`,
},
};
export default configuration;
// If the story is called from another story without any arguments, the default arguments are loaded from the configuration object.
const Template = (args = configuration.args): TemplateResult => {
// If the story is called with only some arguments defined, include all the other defaults too so you only need to specify overrides.
args = {
...configuration.args,
...args,
};
return html`
<outline-example>
${unsafeHTML(args.mySlot ?? '')}
</outline-example>
`;
};
export const MyStory = Template.bind({});
export const MyStoryWithOverrides = Template.bind({});
MyStoryWithOverrides.args = {
mySlot: `<div slot="my-slot">Overridden Slot</div>`,
}; You can call this from another story with: Use all defaults. ${MyStory()} Override value. ${MyStory({ mySlot: `` })} Call story with values defined on the story and not the defaults: ${MyStoryWithOverrides(MyStoryWithOverrides.args)} This more or less follows the pattern in https://storybook.js.org/docs/react/writing-stories/args. I think the use case for non-default stories is there, but not sure how to tackle this. I think Storybook is using I feel like the approach listed above is pretty close to the Storybook documentation, which I like. I was a little confused about exports and passing arguments before. wrapping |
Beta Was this translation helpful? Give feedback.
-
We have a use case for building demo pages out of existing components / stories. It would be nice not to have to copy & paste.
This is possible in Storybook, but no documentation exists for web components.
See https://storybook.js.org/docs/react/workflows/stories-for-multiple-components.
Beta Was this translation helpful? Give feedback.
All reactions