mirror of
https://github.com/withastro/astro.git
synced 2025-01-20 22:12:38 -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">
|
<script lang="ts">
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
export let prefix = "";
|
||||||
|
|
||||||
function add() {
|
function add() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -11,9 +12,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="counter">
|
<div class="counter">
|
||||||
<button on:click={subtract}>-</button>
|
<button on:click={subtract} class="decrement">-</button>
|
||||||
<pre>{count}</pre>
|
<pre>{prefix}{count}</pre>
|
||||||
<button on:click={add}>+</button>
|
<button on:click={add} class="increment">+</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="message">
|
<div class="message">
|
||||||
<slot />
|
<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');
|
const pageTitle = page.locator('.page');
|
||||||
await expect(pageTitle).toHaveText('Island 2');
|
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
|
// Go to page 1
|
||||||
await page.goto(astro.resolveUrl('/island-solid-one'));
|
await page.goto(astro.resolveUrl('/island-solid-one'));
|
||||||
let cnt = page.locator('.counter pre');
|
let cnt = page.locator('.counter pre');
|
||||||
|
@ -569,6 +569,24 @@ test.describe('View Transitions', () => {
|
||||||
await expect(cnt).toHaveText('A1');
|
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 }) => {
|
test('Vue Islands can persist using transition:persist', async ({ page, astro }) => {
|
||||||
// Go to page 1
|
// Go to page 1
|
||||||
await page.goto(astro.resolveUrl('/island-vue-one'));
|
await page.goto(astro.resolveUrl('/island-vue-one'));
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { createRawSnippet, hydrate, mount, unmount } from 'svelte';
|
import { createRawSnippet, hydrate, mount, unmount } from 'svelte';
|
||||||
|
|
||||||
|
const existingApplications = new WeakMap();
|
||||||
|
|
||||||
export default (element) => {
|
export default (element) => {
|
||||||
return async (Component, props, slotted, { client }) => {
|
return async (Component, props, slotted, { client }) => {
|
||||||
if (!element.hasAttribute('ssr')) return;
|
if (!element.hasAttribute('ssr')) return;
|
||||||
|
@ -21,15 +23,23 @@ export default (element) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const bootstrap = client !== 'only' ? hydrate : mount;
|
const bootstrap = client !== 'only' ? hydrate : mount;
|
||||||
|
if (existingApplications.has(element)) {
|
||||||
const component = bootstrap(Component, {
|
existingApplications.get(element).$set({
|
||||||
target: element,
|
|
||||||
props: {
|
|
||||||
...props,
|
...props,
|
||||||
children,
|
children,
|
||||||
$$slots,
|
$$slots,
|
||||||
},
|
});
|
||||||
});
|
} else {
|
||||||
|
const component = bootstrap(Component, {
|
||||||
|
target: element,
|
||||||
|
props: {
|
||||||
|
...props,
|
||||||
|
children,
|
||||||
|
$$slots,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
existingApplications.set(element, component);
|
||||||
|
}
|
||||||
|
|
||||||
element.addEventListener('astro:unmount', () => unmount(component), { once: true });
|
element.addEventListener('astro:unmount', () => unmount(component), { once: true });
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,8 @@ const noop = () => {};
|
||||||
let originalConsoleWarning;
|
let originalConsoleWarning;
|
||||||
let consoleFilterRefs = 0;
|
let consoleFilterRefs = 0;
|
||||||
|
|
||||||
|
const existingApplications = new WeakMap();
|
||||||
|
|
||||||
export default (element) => {
|
export default (element) => {
|
||||||
return (Component, props, slotted, { client }) => {
|
return (Component, props, slotted, { client }) => {
|
||||||
if (!element.hasAttribute('ssr')) return;
|
if (!element.hasAttribute('ssr')) return;
|
||||||
|
@ -14,18 +16,23 @@ export default (element) => {
|
||||||
try {
|
try {
|
||||||
if (import.meta.env.DEV) useConsoleFilter();
|
if (import.meta.env.DEV) useConsoleFilter();
|
||||||
|
|
||||||
const component = new Component({
|
if (existingApplications.has(element)) {
|
||||||
target: element,
|
existingApplications.get(element).$set({ ...props, $$slots: slots, $$scope: { ctx: [] } });
|
||||||
props: {
|
} else {
|
||||||
...props,
|
const component = new Component({
|
||||||
$$slots: slots,
|
target: element,
|
||||||
$$scope: { ctx: [] },
|
props: {
|
||||||
},
|
...props,
|
||||||
hydrate: client !== 'only',
|
$$slots: slots,
|
||||||
$$inline: true,
|
$$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 {
|
} finally {
|
||||||
if (import.meta.env.DEV) finishUsingConsoleFilter();
|
if (import.meta.env.DEV) finishUsingConsoleFilter();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue