svelte.txt (2243B)
1 # Svelte 2 3 ## Attachment factories 4 5 A useful pattern is for a function, such as tooltip in this example, to return 6 an attachment: 7 8 <script lang="ts"> 9 import tippy from 'tippy.js'; 10 import type { Attachment } from 'svelte/attachments'; 11 12 let content = $state('Hello!'); 13 14 function tooltip(content: string): Attachment { 15 return (element) => { 16 const tooltip = tippy(element, { content }); 17 return tooltip.destroy; 18 }; 19 } 20 </script> 21 22 <input bind:value={content} /> 23 24 <button {@attach tooltip(content)}> 25 Hover me 26 </button> 27 28 ## Interesting syntax here (root.svelte by rich harris): 29 30 <script lang="ts"> 31 import { afterNavigate } from '$app/navigation'; 32 import type { Page } from '@sveltejs/kit'; 33 import type { RenderNode } from '../types.js'; 34 35 interface Props { 36 page: Page; 37 tree: RenderNode; 38 components: any[]; 39 resetters: Array<(() => void) | undefined>; 40 form?: any; 41 error?: App.Error; 42 } 43 44 const { page, components, resetters, tree, form, error }: Props = $props(); 45 46 let mounted = $state(false); 47 let navigated = $state(false); 48 let title = $state(''); 49 50 afterNavigate(() => { 51 if (mounted) { 52 navigated = true; 53 title = document.title || 'untitled page'; 54 } else { 55 mounted = true; 56 } 57 }); 58 </script> 59 60 {#snippet node(n: RenderNode, depth: number)} 61 {const Component = $derived(n.component)} 62 {const Error = $derived(n.error)} 63 {const data = $derived(n.data)} 64 65 <svelte:boundary onerror={(_, reset) => (resetters[depth] = reset)}> 66 {#if n.child} 67 <!-- svelte-ignore binding_property_non_reactive --> 68 <Component bind:this={components[depth]} {data} {form} params={page.params}> 69 {@render node(n.child, depth + 1)} 70 </Component> 71 {:else} 72 <!-- svelte-ignore binding_property_non_reactive --> 73 <Component bind:this={components[depth]} {data} {form} params={page.params} {error} /> 74 {/if} 75 76 {#snippet failed(error)} 77 <Error {error} /> 78 {/snippet} 79 </svelte:boundary> 80 {/snippet} 81 82 {@render node(tree, 0)} 83 84 {#if mounted} 85 <div 86 id="svelte-announcer" 87 aria-live="assertive" 88 aria-atomic="true" 89 style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px" 90 > 91 {#if navigated} 92 {title} 93 {/if} 94 </div> 95 {/if}