Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: Story children no longer forwards args & storyContext & add new props - asChild and template #228

Open
wants to merge 15 commits into
base: next
Choose a base branch
from
Open
18 changes: 9 additions & 9 deletions ERRORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@ It must be a valid **object expression** with the same structure as [the Default

### `SB_SVELTE_CSF_PARSER_EXTRACT_SVELTE_0007`

A `<Story>` component received an invalid `children` prop. If set, the `children` prop must be a reference to a [snippet](https://svelte-5-preview.vercel.app/docs/snippets) defined in the root scope file. Eg.:
A `<Story>` component received an invalid `template` prop. If set, the `template` prop must be a reference to a [snippet](https://svelte-5-preview.vercel.app/docs/snippets) defined in the root scope file. Eg.:

```svelte
{#snippet template()}
<span>🚀</span>
{/snippet}

<Story name="Rocket" children={template} />
<Story name="Rocket" {template} />
```

This error indicates that the `children` prop was passed, but it was not correctly referencing a snippet.
This error indicates that the `template` prop was passed, but it was not correctly referencing a snippet.

### `SB_SVELTE_CSF_PARSER_EXTRACT_SVELTE_0008`

Expand Down Expand Up @@ -141,47 +141,47 @@ The import of `defineMeta` from this addon could not be found while parsing the

If you get this error, please open a bug report with detailed reproduction steps including the code that caused the error.

https://github.com/storybookjs/addon-svelte-csf/issues/new
<https://github.com/storybookjs/addon-svelte-csf/issues/new>

### `SB_SVELTE_CSF_PARSER_EXTRACT_COMPILED_0002`

A variable declaration with the `defineMeta` call could not be found while parsing the _compiled_ code.

If you get this error, please open a bug report with detailed reproduction steps including the code that caused the error.

https://github.com/storybookjs/addon-svelte-csf/issues/new
<https://github.com/storybookjs/addon-svelte-csf/issues/new>

### `SB_SVELTE_CSF_PARSER_EXTRACT_COMPILED_0003`

A default export could not be found while parsing the _compiled_ code. The Svelte compiler should automatically default export a component, but this couldn't be found for some reason.

If you get this error, please open a bug report with detailed reproduction steps including the code that caused the error.

https://github.com/storybookjs/addon-svelte-csf/issues/new
<https://github.com/storybookjs/addon-svelte-csf/issues/new>

### `SB_SVELTE_CSF_PARSER_EXTRACT_COMPILED_0004`

A `Story` identifier could not be found while parsing the _compiled_ code.

If you get this error, please open a bug report with detailed reproduction steps including the code that caused the error.

https://github.com/storybookjs/addon-svelte-csf/issues/new
<https://github.com/storybookjs/addon-svelte-csf/issues/new>

### `SB_SVELTE_CSF_PARSER_EXTRACT_COMPILED_0005`

A main function component could not be found while parsing the _compiled_ code.

If you get this error, please open a bug report with detailed reproduction steps including the code that caused the error.

https://github.com/storybookjs/addon-svelte-csf/issues/new
<https://github.com/storybookjs/addon-svelte-csf/issues/new>

### `SB_SVELTE_CSF_PARSER_EXTRACT_COMPILED_0006`

A Story-component's props could not be extracted as an object expression from the _compiled_ code.

If you get this error, please open a bug report with detailed reproduction steps including the code that caused the error.

https://github.com/storybookjs/addon-svelte-csf/issues/new
<https://github.com/storybookjs/addon-svelte-csf/issues/new>

## `PARSER_ANALYSE_DEFINE_META`

Expand Down
13 changes: 7 additions & 6 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ After:

```svelte
<Story name="Default">
{#snippet children(args)}
{#snippet template(args)}
<Button {...args} />
{/snippet}
</Story>
Expand All @@ -172,7 +172,7 @@ Difference:
```diff
- <Story name="Default" let:args>
+ <Story name="Default">
+ {#snippet children(args)}
+ {#snippet template(args)}
<Button {...args} />
+ {/snippet}
</Story>
Expand All @@ -195,22 +195,22 @@ After:

```svelte
<Story name="Context">
{#snippet children(_args, context)}
{#snippet template(_args, context)}
<div>StoryContext.name = {context.name}</div>
<div>StoryContext.id = {context.id}</div>
{/snippet}
</Story>
```

> [!NOTE]
> Snippet `children` second argument `context` is optional.
> Snippet `template` second argument `context` is optional.

Difference:

```diff
- <Story name="Context" let:context>
+ <Story name="Context">
+ {#snippet children(_args, context)}
+ {#snippet template(_args, context)}
<div>StoryContext.name = {context.name}</div>
<div>StoryContext.id = {context.id}</div>
+ {/snippet}
Expand All @@ -227,7 +227,8 @@ We have **new ways of setting a template** for our `<Story>` components:
1. [Static template](./README.md#static-template)
1. [Default template](./README.md#default-template)

It’s also no longer required to define a template. Stories without templates will just render the component with args becoming props.
> [!IMPORTANT]:
> **It’s also no longer required to define a template.** Stories without templates will just render the component with args becoming props.

---

Expand Down
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,19 @@ If you need more customization of the story, like composing components or defini

#### Inline snippet

If you need composition/snippets but also want a dynamic story that reacts to args or the story context, you can define a `children` snippet in the `Story` component:
If you need composition/snippets but also want a dynamic story that reacts to args or the story context, you can define a `template` snippet in the `Story` component:

```svelte
<Story name="Simple Children" args={{ simpleChild: true }}>
{#snippet children(args)}
<Story name="Simple Template" args={{ simpleChild: true }}>
{#snippet template(args)}
<MyComponent {...args}>Component with args</MyComponent>
{/snippet}
</Story>
```

#### Shared snippet

Often your stories are very similar and their only differences are args or play-functions. In this case it can be cumbersome to define the same `children` snippet over and over again. You can share snippets by defining them at the top-level and passing them as props to `Story`:
Often your stories are very similar and their only differences are args or play-functions. In this case it can be cumbersome to define the same `template` snippet over and over again. You can share snippets by defining them at the top-level and passing them as props to `Story`:

```svelte
{#snippet template(args)}
Expand All @@ -142,23 +142,23 @@ Often your stories are very similar and their only differences are args or play-
</MyComponent>
{/snippet}

<Story name="Simple Children" args={{ simpleChild: true }} children={template} />
<Story name="Simple Template" args={{ simpleChild: true }} {template} />

<Story name="Complex Children" args={{ simpleChild: false }} children={template} />
<Story name="Complex Template" args={{ simpleChild: false }} {template} />
```

You can also use this pattern to define multiple templates and share the different templates among different stories.

#### Default snippet

If you only need a single template that you want to share, it can be tedious to include `children={template}` in each `Story` component. Like in th example below:
If you only need a single template that you want to share, it can be tedious to include `{template}` in each `Story` component. Like in th example below:

```svelte
<Story name="Primary" args={{ variant: 'primary' }} children={template} />
<Story name="Secondary" args={{ variant: 'secondary' }} children={template} />
<Story name="Tertiary" args={{ variant: 'tertiary' }} children={template} />
<Story name="Primary" args={{ variant: 'primary' }} {template} />
<Story name="Secondary" args={{ variant: 'secondary' }} {template} />
<Story name="Tertiary" args={{ variant: 'tertiary' }} {template} />
<!-- ... more ... -->
<Story name="Denary" args={{ variant: 'denary' }} children={template} />
<Story name="Denary" args={{ variant: 'denary' }} {template} />
```

In this case you can use the `setTemplate()` helper function that sets a default template for all stories. In regular CSF terms, this is the equivalent of defining a meta-level `render`-function versus story-level `render`-functions:
Expand Down Expand Up @@ -215,11 +215,11 @@ At least one of the `name` or `exportName` props must be passed to the `Story` c

#### Accessing Story context

If for some reason you need to access the [Story context](https://storybook.js.org/docs/writing-stories/decorators#context-for-mocking) _(e.g. for mocking)_ while rendering the story, then `<Story />`'s attribute `children` snippet provides an optional second argument.
If for some reason you need to access the [Story context](https://storybook.js.org/docs/writing-stories/decorators#context-for-mocking) _(e.g. for mocking)_ while rendering the story, then `<Story />`'s attribute `template` snippet provides an optional second argument.

```svelte
<Story name="Default">
{#snippet children(args, context)}
{#snippet template(args, context)}
<!-- 👆 use the optional second argument to access Story context -->
<MyComponent {...args}>
{/snippet}
Expand Down
18 changes: 16 additions & 2 deletions examples/Button.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@
<!-- This is _tiny_ 🤏 -->
<Story name="Small" args={{ size: 'small' }} />

<Story name="Long content">
<Button onclick={onclickFn}>The very long content</Button>
<Story name="Long content">The very long content</Story>

<Story name="Custom template">
{#snippet template(args, context)}
<Button {...args}>🩷 Storybook</Button>
<Button {...args}>🧡 Svelte</Button>
{/snippet}
</Story>

<!--
Input values from the controls tab will **not** be passed down to story.
Neither the `args` from meta.
-->
<Story name="Static story" parameters={{ controls: { disable: true } }} asChild>
<h1>This is a static story</h1>
<Button>Static button</Button>
</Story>
20 changes: 10 additions & 10 deletions examples/Templating.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@
</Story>

<!--
Pass a `children` snippet to the story to make it dynamic and react to Storybook's `args` changes.
Pass a `template` snippet to the story to make it dynamic and react to Storybook's `args` changes.
The snippet takes two arguments, `args` and `context`.

Example:

```svelte
<Story name="Dynamic story">
{#snippet children(args)}
{#snippet template(args)}
<SomeComponent {...args}>
Dynamic template
</SomeComponent>
Expand All @@ -72,8 +72,8 @@
```
-->
<Story
name="Children snippet"
args={{ text: 'This story uses a children snippet' }}
name="Template snippet"
args={{ text: 'This story uses a template snippet' }}
play={async (context) => {
const { args, canvasElement } = context;
const canvas = within(canvasElement);
Expand All @@ -84,8 +84,8 @@
expect(p).toBeInTheDocument();
}}
>
{#snippet children(args)}
<h2 data-testid="heading">Children snippet</h2>
{#snippet template(args)}
<h2 data-testid="heading">Template snippet</h2>
<p>{args?.text}</p>
{/snippet}
</Story>
Expand All @@ -97,7 +97,7 @@

<!--
If you want to share the template between multiple stories,
you can define the snippet at the root and pass it in as the `children` **prop** to the `<Story>` component.
you can define the snippet at the root and pass it in as the `template` **prop** to the `<Story>` component.

Example:

Expand All @@ -108,14 +108,14 @@
</SomeComponent>
{/snippet}

<Story name="Explicit snippet" children={template} />
<Story name="Explicit snippet" {template} />
```
-->
<Story
name="Shared template"
children={sharedTemplate}
template={sharedTemplate}
args={{
text: 'This story uses a shared snippet, which is explicitly set as the `children` prop to the <Story> component',
text: 'This story uses a shared snippet, which is explicitly set as the `template` prop to the <Story> component',
}}
play={async (context) => {
const { args, canvasElement } = context;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@
"chromatic": "^11.16.1",
"concurrently": "^8.2.2",
"eslint": "^7.32.0",
"eslint-plugin-storybook": "^0.8.0",
"jsdom": "^24.1.0",
"eslint-plugin-storybook": "^0.11.0",
"happy-dom": "^15.11.0",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.5",
"rimraf": "^5.0.7",
Expand Down
Loading