summaryrefslogtreecommitdiff
path: root/packages/integrations/svelte/client.svelte.js
diff options
context:
space:
mode:
authorGravatar Jacob Jenkins <jacob_jenkins@live.com> 2024-11-14 15:31:51 +0000
committerGravatar GitHub <noreply@github.com> 2024-11-14 23:31:51 +0800
commit9fc2ab8cc848739a21bfa3f754e9bec4926dc034 (patch)
treea184ada6711296569a064c01defd2fa6a74f63c5 /packages/integrations/svelte/client.svelte.js
parentbdc0890061533466da19660ff83a331a3136f6c4 (diff)
downloadastro-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.js79
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);
+ },
+ };
+}