mirror of
https://github.com/withastro/astro.git
synced 2025-01-06 22:10:10 -05:00
Fix Svelte view transition state persistence (#12006)
Co-authored-by: Martin Trapp <94928215+martrapp@users.noreply.github.com>
This commit is contained in:
parent
daca9951f4
commit
a582cb6124
7 changed files with 85 additions and 22 deletions
5
.changeset/warm-birds-cheer.md
Normal file
5
.changeset/warm-birds-cheer.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/svelte': patch
|
||||
---
|
||||
|
||||
Fix Svelte component view transition state persistence
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
let count = 0;
|
||||
export let prefix = "";
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
|
@ -11,9 +12,9 @@
|
|||
</script>
|
||||
|
||||
<div class="counter">
|
||||
<button on:click={subtract}>-</button>
|
||||
<pre>{count}</pre>
|
||||
<button on:click={add}>+</button>
|
||||
<button on:click={subtract} class="decrement">-</button>
|
||||
<pre>{prefix}{count}</pre>
|
||||
<button on:click={add} class="increment">+</button>
|
||||
</div>
|
||||
<div class="message">
|
||||
<slot />
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
import Counter from '../components/SvelteCounter.svelte';
|
||||
import Layout from '../components/Layout.astro';
|
||||
export const prerender = false;
|
||||
|
||||
---
|
||||
<Layout>
|
||||
<p id="island-one">Page 1</p>
|
||||
<a id="click-two" href="/island-svelte-two">go to 2</a>
|
||||
<Counter prefix="A" client:load transition:persist transition:name="counter"/>
|
||||
</Layout>
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
import Counter from '../components/SvelteCounter.svelte';
|
||||
import Layout from '../components/Layout.astro';
|
||||
export const prerender = false;
|
||||
|
||||
---
|
||||
<Layout>
|
||||
<p id="island-two">Page 2</p>
|
||||
<a id="click-one" href="/island-svelte-one">go to 1</a>
|
||||
<Counter prefix="B" client:load transition:persist transition:name="counter"/>
|
||||
</Layout>
|
|
@ -543,8 +543,8 @@ test.describe('View Transitions', () => {
|
|||
const pageTitle = page.locator('.page');
|
||||
await expect(pageTitle).toHaveText('Island 2');
|
||||
});
|
||||
|
||||
test('Solid Islands can persist using transition:persist', async ({ page, astro }) => {
|
||||
|
||||
test('Solid Islands can persist using transition:persist', async ({ page, astro }) => {
|
||||
// Go to page 1
|
||||
await page.goto(astro.resolveUrl('/island-solid-one'));
|
||||
let cnt = page.locator('.counter pre');
|
||||
|
@ -569,6 +569,24 @@ test.describe('View Transitions', () => {
|
|||
await expect(cnt).toHaveText('A1');
|
||||
});
|
||||
|
||||
test('Svelte Islands can persist using transition:persist', async ({ page, astro }) => {
|
||||
// Go to page 1
|
||||
await page.goto(astro.resolveUrl('/island-svelte-one'));
|
||||
let cnt = page.locator('.counter pre');
|
||||
await expect(cnt).toHaveText('A0');
|
||||
|
||||
await page.click('.increment');
|
||||
await expect(cnt).toHaveText('A1');
|
||||
|
||||
// Navigate to page 2
|
||||
await page.click('#click-two');
|
||||
let p = page.locator('#island-two');
|
||||
await expect(p).toBeVisible();
|
||||
cnt = page.locator('.counter pre');
|
||||
// Count should remain, but the prefix should be updated
|
||||
await expect(cnt).toHaveText('B1');
|
||||
});
|
||||
|
||||
test('Vue Islands can persist using transition:persist', async ({ page, astro }) => {
|
||||
// Go to page 1
|
||||
await page.goto(astro.resolveUrl('/island-vue-one'));
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { createRawSnippet, hydrate, mount, unmount } from 'svelte';
|
||||
|
||||
const existingApplications = new WeakMap();
|
||||
|
||||
export default (element) => {
|
||||
return async (Component, props, slotted, { client }) => {
|
||||
if (!element.hasAttribute('ssr')) return;
|
||||
|
@ -21,15 +23,23 @@ export default (element) => {
|
|||
}
|
||||
|
||||
const bootstrap = client !== 'only' ? hydrate : mount;
|
||||
|
||||
const component = bootstrap(Component, {
|
||||
target: element,
|
||||
props: {
|
||||
if (existingApplications.has(element)) {
|
||||
existingApplications.get(element).$set({
|
||||
...props,
|
||||
children,
|
||||
$$slots,
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const component = bootstrap(Component, {
|
||||
target: element,
|
||||
props: {
|
||||
...props,
|
||||
children,
|
||||
$$slots,
|
||||
},
|
||||
});
|
||||
existingApplications.set(element, component);
|
||||
}
|
||||
|
||||
element.addEventListener('astro:unmount', () => unmount(component), { once: true });
|
||||
};
|
||||
|
|
|
@ -3,6 +3,8 @@ const noop = () => {};
|
|||
let originalConsoleWarning;
|
||||
let consoleFilterRefs = 0;
|
||||
|
||||
const existingApplications = new WeakMap();
|
||||
|
||||
export default (element) => {
|
||||
return (Component, props, slotted, { client }) => {
|
||||
if (!element.hasAttribute('ssr')) return;
|
||||
|
@ -14,18 +16,23 @@ export default (element) => {
|
|||
try {
|
||||
if (import.meta.env.DEV) useConsoleFilter();
|
||||
|
||||
const component = new Component({
|
||||
target: element,
|
||||
props: {
|
||||
...props,
|
||||
$$slots: slots,
|
||||
$$scope: { ctx: [] },
|
||||
},
|
||||
hydrate: client !== 'only',
|
||||
$$inline: true,
|
||||
});
|
||||
if (existingApplications.has(element)) {
|
||||
existingApplications.get(element).$set({ ...props, $$slots: slots, $$scope: { ctx: [] } });
|
||||
} else {
|
||||
const component = new Component({
|
||||
target: element,
|
||||
props: {
|
||||
...props,
|
||||
$$slots: slots,
|
||||
$$scope: { ctx: [] },
|
||||
},
|
||||
hydrate: client !== 'only',
|
||||
$$inline: true,
|
||||
});
|
||||
existingApplications.set(element, component);
|
||||
|
||||
element.addEventListener('astro:unmount', () => component.$destroy(), { once: true });
|
||||
element.addEventListener('astro:unmount', () => component.$destroy(), { once: true });
|
||||
}
|
||||
} finally {
|
||||
if (import.meta.env.DEV) finishUsingConsoleFilter();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue