/** * Svelte action to mount a Svelte component into a DOM element */ import type { ComponentType, Snippet } from 'svelte'; import { mount, unmount } from 'svelte'; export function mountComponent( node: HTMLElement, component: ComponentType, props: Record ) { let instance: any = null; // Mount the component if (component && typeof component === 'function') { try { // Clear the node first to ensure clean mounting node.innerHTML = ''; // Try using Svelte 5's mount function first try { instance = mount(component, { target: node, props }); } catch (e) { // Fallback to Svelte 4 compatibility API console.debug('[mountComponent] Svelte 5 mount failed, trying compatibility API:', e); instance = new (component as any)({ target: node, props, hydrate: false, intro: false }); } // Verify the component was mounted if (!instance) { console.warn('[mountComponent] Component instance not created', { component, props }); } else { // Force a tick to ensure effects run setTimeout(() => { // Effects should have run by now }, 0); } } catch (e) { console.error('[mountComponent] Failed to mount component:', e, { component, props, node }); } } else { console.warn('[mountComponent] Invalid component provided', { component, props }); } return { update(newProps: Record) { if (instance) { // Try Svelte 5 update first if (typeof instance.$set === 'function') { try { instance.$set(newProps); } catch (e) { console.error('[mountComponent] Failed to update component:', e); } } } }, destroy() { if (instance) { // Try Svelte 5 unmount first try { if (typeof unmount === 'function') { unmount(instance); } else if (typeof instance.$destroy === 'function') { instance.$destroy(); } } catch (e) { console.error('[mountComponent] Failed to destroy component:', e); } } instance = null; } }; }