mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-03 05:04:51 +08:00
dont remount Svelte components on control change, make template stories reactive
This commit is contained in:
parent
2e017abaa2
commit
12dcacc5d3
@ -1,3 +1,4 @@
|
||||
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
|
||||
@ -5,38 +6,77 @@ import PreviewRender from '@storybook/svelte/templates/PreviewRender.svelte';
|
||||
|
||||
import type { SvelteFramework } from './types';
|
||||
|
||||
const componentsByDomElementId = new Map<string, SvelteComponentTyped>();
|
||||
const componentsByDomElementKey = new Map<string, SvelteComponentTyped>();
|
||||
|
||||
function cleanupExistingComponent(domElementKey: string) {
|
||||
if (!componentsByDomElementId.has(domElementKey)) {
|
||||
const STORYBOOK_ROOT_ID = 'storybook-root';
|
||||
|
||||
function teardown(domElementKey: string) {
|
||||
if (!componentsByDomElementKey.has(domElementKey)) {
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know it exists because we just checked
|
||||
componentsByDomElementId.get(domElementKey)!.$destroy();
|
||||
componentsByDomElementId.delete(domElementKey);
|
||||
componentsByDomElementKey.get(domElementKey)!.$destroy();
|
||||
|
||||
// in docs mode, the element we render to is a child of the element with the story id
|
||||
// TODO: this feels brittle. If we ever change the structure in the <Story /> component, this will break
|
||||
const rootElement =
|
||||
domElementKey === STORYBOOK_ROOT_ID
|
||||
? global.document.getElementById(domElementKey)
|
||||
: global.document.getElementById(domElementKey).children[0];
|
||||
rootElement.innerHTML = '';
|
||||
componentsByDomElementKey.delete(domElementKey);
|
||||
}
|
||||
|
||||
export function renderToDOM(
|
||||
{ storyFn, kind, name, showMain, showError, storyContext }: Store_RenderContext<SvelteFramework>,
|
||||
{
|
||||
storyFn,
|
||||
kind,
|
||||
name,
|
||||
id,
|
||||
showMain,
|
||||
showError,
|
||||
storyContext,
|
||||
forceRemount,
|
||||
}: Store_RenderContext<SvelteFramework>,
|
||||
domElement: Element
|
||||
) {
|
||||
// in docs mode we're rendering multiple stories to the DOM, so we need to key by the story id
|
||||
const domElementKey = storyContext.viewMode === 'docs' ? storyContext.id : 'storybook-root';
|
||||
cleanupExistingComponent(domElementKey);
|
||||
const domElementKey = storyContext.viewMode === 'docs' ? id : STORYBOOK_ROOT_ID;
|
||||
|
||||
const renderedComponent = new PreviewRender({
|
||||
target: domElement,
|
||||
props: {
|
||||
const existingComponent = componentsByDomElementKey.get(domElementKey);
|
||||
|
||||
if (forceRemount) {
|
||||
teardown(domElementKey);
|
||||
}
|
||||
|
||||
if (!existingComponent || forceRemount) {
|
||||
const createdComponent = new PreviewRender({
|
||||
target: domElement,
|
||||
props: {
|
||||
storyFn,
|
||||
storyContext,
|
||||
name,
|
||||
kind,
|
||||
showError,
|
||||
},
|
||||
}) as SvelteComponentTyped;
|
||||
componentsByDomElementKey.set(domElementKey, createdComponent);
|
||||
} else {
|
||||
existingComponent.$set({
|
||||
storyFn,
|
||||
storyContext,
|
||||
name,
|
||||
kind,
|
||||
showError,
|
||||
},
|
||||
});
|
||||
componentsByDomElementId.set(domElementKey, renderedComponent);
|
||||
});
|
||||
}
|
||||
|
||||
showMain();
|
||||
|
||||
// teardown the component when the story changes
|
||||
return () => {
|
||||
teardown(domElementKey);
|
||||
};
|
||||
}
|
||||
|
||||
export const render: ArgsStoryFn<SvelteFramework> = (args, context) => {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -8,7 +8,14 @@
|
||||
export let showError;
|
||||
export let storyContext;
|
||||
|
||||
const {
|
||||
let Component;
|
||||
let props = {};
|
||||
let on;
|
||||
let Wrapper;
|
||||
let WrapperData = {};
|
||||
|
||||
// reactive, re-render on storyFn change
|
||||
$: ({
|
||||
/** @type {SvelteComponent} */
|
||||
Component,
|
||||
/** @type {any} */
|
||||
@ -17,13 +24,15 @@
|
||||
on,
|
||||
Wrapper,
|
||||
WrapperData = {},
|
||||
} = storyFn();
|
||||
} = storyFn());
|
||||
|
||||
const eventsFromArgTypes = Object.fromEntries(Object.entries(storyContext.argTypes)
|
||||
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 +45,11 @@
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<SlotDecorator
|
||||
decorator={Wrapper}
|
||||
decoratorProps={WrapperData}
|
||||
component={Component}
|
||||
props={props}
|
||||
on={events}/>
|
||||
{props}
|
||||
on={events}
|
||||
/>
|
||||
|
@ -21,10 +21,11 @@
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if decorator}
|
||||
<svelte:component this={decorator} {...decoratorProps} bind:this={decoratorInstance}>
|
||||
<svelte:component this={component} {...props} bind:this={instance}/>
|
||||
<svelte:component this={component} {...props} bind:this={instance} />
|
||||
</svelte:component>
|
||||
{:else}
|
||||
<svelte:component this={component} {...props} bind:this={instance}/>
|
||||
{/if}
|
||||
<svelte:component this={component} {...props} bind:this={instance} />
|
||||
{/if}
|
||||
|
Loading…
x
Reference in New Issue
Block a user