diff --git a/code/lib/store/template/stories/rendering.stories.ts b/code/lib/store/template/stories/rendering.stories.ts index 131e3f7a7de3..d79f1a3fb0cc 100644 --- a/code/lib/store/template/stories/rendering.stories.ts +++ b/code/lib/store/template/stories/rendering.stories.ts @@ -31,13 +31,9 @@ export const ChangeArgs = { await expect(button).toHaveFocus(); // Vue3: https://github.com/storybookjs/storybook/issues/13913 - // Svelte: https://github.com/storybookjs/storybook/issues/19205 // Web-components: https://github.com/storybookjs/storybook/issues/19415 // Preact: https://github.com/storybookjs/storybook/issues/19504 - if ( - ['vue3', 'svelte', 'web-components', 'html', 'preact'].includes(globalThis.storybookRenderer) - ) - return; + if (['vue3', 'web-components', 'html', 'preact'].includes(globalThis.storybookRenderer)) return; // When we change the args to the button, it should not rerender await channel.emit('updateStoryArgs', { storyId: id, updatedArgs: { label: 'New Text' } }); diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts index f5f671c99d14..39c45a7c554f 100644 --- a/code/renderers/svelte/src/render.ts +++ b/code/renderers/svelte/src/render.ts @@ -1,5 +1,3 @@ -import global from 'global'; - import type { Store_RenderContext, ArgsStoryFn } from '@storybook/types'; import type { SvelteComponentTyped } from 'svelte'; // eslint-disable-next-line import/no-extraneous-dependencies @@ -7,40 +5,66 @@ import PreviewRender from '@storybook/svelte/templates/PreviewRender.svelte'; import type { SvelteFramework } from './types'; -const { document } = global; - -let previousComponent: SvelteComponentTyped | null = null; +const componentsByDomElement = new Map(); -function cleanUpPreviousStory() { - if (!previousComponent) { +function teardown(domElement: Element) { + if (!componentsByDomElement.has(domElement)) { return; } - previousComponent.$destroy(); - previousComponent = null; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know it exists because we just checked + componentsByDomElement.get(domElement)!.$destroy(); + + // eslint-disable-next-line no-param-reassign -- this is on purpose + domElement.innerHTML = ''; + componentsByDomElement.delete(domElement); } export function renderToDOM( - { storyFn, kind, name, showMain, showError, storyContext }: Store_RenderContext, + { + storyFn, + kind, + name, + showMain, + showError, + storyContext, + forceRemount, + }: Store_RenderContext, domElement: Element ) { - cleanUpPreviousStory(); - - const target = domElement || document.getElementById('storybook-root'); + const existingComponent = componentsByDomElement.get(domElement); - target.innerHTML = ''; + if (forceRemount) { + teardown(domElement); + } - previousComponent = new PreviewRender({ - target, - props: { + if (!existingComponent || forceRemount) { + const createdComponent = new PreviewRender({ + target: domElement, + props: { + storyFn, + storyContext, + name, + kind, + showError, + }, + }) as SvelteComponentTyped; + componentsByDomElement.set(domElement, createdComponent); + } else { + existingComponent.$set({ storyFn, storyContext, name, kind, showError, - }, - }); + }); + } showMain(); + + // teardown the component when the story changes + return () => { + teardown(domElement); + }; } export const render: ArgsStoryFn = (args, context) => { diff --git a/code/renderers/svelte/template/cli/Button.svelte b/code/renderers/svelte/template/cli/Button.svelte index 01704b7c0a52..5a19ed6d6814 100644 --- a/code/renderers/svelte/template/cli/Button.svelte +++ b/code/renderers/svelte/template/cli/Button.svelte @@ -9,7 +9,7 @@ /** * What background color to use */ - export let backgroundColor; + export let backgroundColor = undefined; /** * How large should the button be? */ @@ -19,9 +19,9 @@ */ export let label = ''; - let mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + $: mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; - let style = backgroundColor ? `background-color: ${backgroundColor}` : ''; + $: style = backgroundColor ? `background-color: ${backgroundColor}` : ''; const dispatch = createEventDispatcher(); diff --git a/code/renderers/svelte/template/components/Button.svelte b/code/renderers/svelte/template/components/Button.svelte index 9f4f69357087..4b80e84b8132 100644 --- a/code/renderers/svelte/template/components/Button.svelte +++ b/code/renderers/svelte/template/components/Button.svelte @@ -21,9 +21,9 @@ */ export let label = ''; - let mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + $: mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; - let style = backgroundColor ? `background-color: ${backgroundColor}` : ''; + $: style = backgroundColor ? `background-color: ${backgroundColor}` : ''; const dispatch = createEventDispatcher(); diff --git a/code/renderers/svelte/templates/PreviewRender.svelte b/code/renderers/svelte/templates/PreviewRender.svelte index bfdab9a223d1..6ad197bea0f0 100644 --- a/code/renderers/svelte/templates/PreviewRender.svelte +++ b/code/renderers/svelte/templates/PreviewRender.svelte @@ -8,7 +8,7 @@ export let showError; export let storyContext; - const { + let { /** @type {SvelteComponent} */ Component, /** @type {any} */ @@ -19,11 +19,16 @@ WrapperData = {}, } = storyFn(); - const eventsFromArgTypes = Object.fromEntries(Object.entries(storyContext.argTypes) + // reactive, re-render on storyFn change + $: ({ Component, props = {}, on, Wrapper, WrapperData = {} } = storyFn()); + + const eventsFromArgTypes = Object.fromEntries( + Object.entries(storyContext.argTypes) .filter(([k, v]) => v.action && props[k] != null) - .map(([k, v]) => [v.action, props[k]])); + .map(([k, v]) => [v.action, props[k]]) + ); - const events = {...eventsFromArgTypes, ...on}; + const events = { ...eventsFromArgTypes, ...on }; if (!Component) { showError({ @@ -36,9 +41,11 @@ }); } + \ No newline at end of file + {props} + on={events} +/> diff --git a/code/renderers/svelte/templates/SlotDecorator.svelte b/code/renderers/svelte/templates/SlotDecorator.svelte index bd51e06f4271..6b0d06337001 100644 --- a/code/renderers/svelte/templates/SlotDecorator.svelte +++ b/code/renderers/svelte/templates/SlotDecorator.svelte @@ -21,10 +21,11 @@ }); } + {#if decorator} - + {:else} - -{/if} \ No newline at end of file + +{/if} diff --git a/code/workspace.json b/code/workspace.json index bbd44b617358..a5a0e8b7e18f 100644 --- a/code/workspace.json +++ b/code/workspace.json @@ -181,11 +181,6 @@ "root": "lib/core-server", "type": "library" }, - "@storybook/core-vite": { - "implicitDependencies": [], - "root": "lib/core-vite", - "type": "library" - }, "@storybook/core-webpack": { "implicitDependencies": [], "root": "lib/core-webpack", diff --git a/docs/snippets/svelte/button-implementation.js.mdx b/docs/snippets/svelte/button-implementation.js.mdx index cfb8af862de8..94bf7dd75946 100644 --- a/docs/snippets/svelte/button-implementation.js.mdx +++ b/docs/snippets/svelte/button-implementation.js.mdx @@ -11,7 +11,7 @@ /** * What background color to use */ - export let backgroundColor; + export let backgroundColor = undefined; /** * How large should the button be? */ @@ -34,4 +34,4 @@ -``` \ No newline at end of file +```