Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion code/renderers/svelte/src/components/PreviewRender.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@
});
</script>

<DecoratorHandler {Component} {props} />
<svelte:boundary>
{#snippet pending()}
<div id="sb-pending-async-component-notice">Pending async component...</div>
{/snippet}
<DecoratorHandler {Component} {props} />
</svelte:boundary>
4 changes: 3 additions & 1 deletion code/renderers/svelte/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const componentsByDomElement = new Map<
{ mountedComponent: ReturnType<(typeof svelte)['mount']>; props: RenderContext }
>();

export function renderToCanvas(
export async function renderToCanvas(
{
storyFn,
title,
Expand Down Expand Up @@ -80,6 +80,7 @@ export function renderToCanvas(
target: canvasElement,
props,
});
await svelte.tick();
componentsByDomElement.set(canvasElement, { mountedComponent, props });
} else {
// We need to mutate the existing props for Svelte reactivity to work, we can't just re-assign them
Expand All @@ -90,6 +91,7 @@ export function renderToCanvas(
title,
showError,
});
await svelte.tick();
}

showMain();
Expand Down
24 changes: 24 additions & 0 deletions code/renderers/svelte/template/stories/AsyncComponent.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script>
let shown = $state(false);
let { onEffect } = $props();
/*
TODO: Replace this with the comment below once async components have been released in Svelte.
https://github.com/sveltejs/svelte/discussions/15845
await new Promise((resolve) => {
setTimeout(() => {
onEffect?.();
shown = true;
resolve();
}, 100);
});
*/
$effect(() => {
onEffect?.();
shown = true;
});
</script>
{#if shown}
<div data-testid="after-effect">This element is shown after the component's effect runs</div>
{/if}
13 changes: 13 additions & 0 deletions code/renderers/svelte/template/stories/SyncComponent.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
let shown = $state(false);
let { onEffect } = $props();
$effect(() => {
onEffect?.();
shown = true;
});
</script>
{#if shown}
<div data-testid="after-effect">This element is shown after the component's effect runs</div>
{/if}
51 changes: 51 additions & 0 deletions code/renderers/svelte/template/stories/settled.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { StoryObj } from '@storybook/svelte';

import { expect, fn, waitFor } from 'storybook/test';

import AsyncComponent from './AsyncComponent.svelte';
import SyncComponent from './SyncComponent.svelte';

export default {
title: 'stories/renderers/svelte/settled',
};

export const Sync: StoryObj<typeof SyncComponent> = {
render: (args) => ({
Component: SyncComponent,
props: args,
}),
args: {
onEffect: fn(),
},
play: async ({ canvas, args }) => {
await expect(args.onEffect).toHaveBeenCalledOnce();
await expect(canvas.getByTestId('after-effect')).toBeInTheDocument();
},
};

/*
TODO: Enable this story once async components have been released in Svelte.
https://github.com/sveltejs/svelte/discussions/15845
export const Async: StoryObj<typeof AsyncComponent> = {
render: (args) => ({
Component: AsyncComponent,
props: args,
}),
args: {
onEffect: fn(),
},
play: async ({ canvas, args }) => {
await expect(args.onEffect).not.toHaveBeenCalled();
await expect(canvas.getElementById('sb-pending-async-component-notice')).toBeInTheDocument();
// TODO: Ideally we should be able to call await svelte.settled() here instead of waitFor, but currently there's a bug making it never resolve
// await svelte.settled();
await waitFor(() => {
expect(args.onEffect).toHaveBeenCalledOnce();
expect(canvas.getByTestId('after-effect')).toBeInTheDocument();
});
},
};
*/
Loading