diff options
author | 2024-11-14 15:31:51 +0000 | |
---|---|---|
committer | 2024-11-14 23:31:51 +0800 | |
commit | 9fc2ab8cc848739a21bfa3f754e9bec4926dc034 (patch) | |
tree | a184ada6711296569a064c01defd2fa6a74f63c5 /packages/integrations/svelte/client.svelte.js | |
parent | bdc0890061533466da19660ff83a331a3136f6c4 (diff) | |
download | astro-9fc2ab8cc848739a21bfa3f754e9bec4926dc034.tar.gz astro-9fc2ab8cc848739a21bfa3f754e9bec4926dc034.tar.zst astro-9fc2ab8cc848739a21bfa3f754e9bec4926dc034.zip |
Update to svelte 5 (#12364)
Co-authored-by: bluwy <bjornlu.dev@gmail.com>
Diffstat (limited to 'packages/integrations/svelte/client.svelte.js')
-rw-r--r-- | packages/integrations/svelte/client.svelte.js | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/packages/integrations/svelte/client.svelte.js b/packages/integrations/svelte/client.svelte.js new file mode 100644 index 000000000..1bff1bf24 --- /dev/null +++ b/packages/integrations/svelte/client.svelte.js @@ -0,0 +1,79 @@ +import { createRawSnippet, hydrate, mount, unmount } from 'svelte'; + +/** @type {WrakMap<any, ReturnType<typeof createComponent>} */ +const existingApplications = new WeakMap(); + +export default (element) => { + return async (Component, props, slotted, { client }) => { + if (!element.hasAttribute('ssr')) return; + + let children = undefined; + let _$$slots = undefined; + let renderFns = {}; + + for (const [key, value] of Object.entries(slotted)) { + // Legacy slot support + _$$slots ??= {}; + if (key === 'default') { + _$$slots.default = true; + children = createRawSnippet(() => ({ + render: () => `<astro-slot>${value}</astro-slot>`, + })); + } else { + _$$slots[key] = createRawSnippet(() => ({ + render: () => `<astro-slot name="${key}">${value}</astro-slot>`, + })); + } + // @render support for Svelte ^5.0 + if (key === 'default') { + renderFns.children = createRawSnippet(() => ({ + render: () => `<astro-slot>${value}</astro-slot>`, + })); + } else { + renderFns[key] = createRawSnippet(() => ({ + render: () => `<astro-slot name="${key}">${value}</astro-slot>`, + })); + } + } + + const resolvedProps = { + ...props, + children, + $$slots: _$$slots, + ...renderFns, + }; + if (existingApplications.has(element)) { + existingApplications.get(element).setProps(resolvedProps); + } else { + const component = createComponent(Component, element, resolvedProps, client !== 'only'); + existingApplications.set(element, component); + element.addEventListener('astro:unmount', () => component.destroy(), { once: true }); + } + }; +}; + +/** + * @param {any} Component + * @param {HTMLElement} target + * @param {Record<string, any>} props + * @param {boolean} shouldHydrate + */ +function createComponent(Component, target, props, shouldHydrate) { + let propsState = $state(props); + const bootstrap = shouldHydrate ? hydrate : mount; + const component = bootstrap(Component, { target, props: propsState }); + return { + setProps(newProps) { + Object.assign(propsState, newProps); + // Remove props in `propsState` but not in `newProps` + for (const key in propsState) { + if (!(key in newProps)) { + delete propsState[key]; + } + } + }, + destroy() { + unmount(component); + }, + }; +} |