Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Svelte
at icy/tmrrpn
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475<script lang="ts"> import { untrack } from "svelte"; import { File, type FileOptions } from "@pierre/diffs"; import { clearPierreRender, pierreFileOptions } from "./pierre";
interface Props { // used for the header and to infer the highlighting language name: string; contents: string; // pierre's native overflow: wrap keeps highlighting instead of scrolling wrap?: boolean; // server-prerendered shadow dom, only set for the initial ssr prerenderedHTML?: string; // forwarded to pierre, fires after every (async-safe) render pass onPostRender?: FileOptions<undefined>["onPostRender"]; }
let { name, contents, wrap = false, prerenderedHTML, onPostRender }: Props = $props();
let element: HTMLElement | undefined = $state();
let instance: File | undefined;
// same manual updates as PierreDiff, this effect owns the instance, // a contents swap re-renders in place instead of a shadow dom teardown $effect(() => { const host = element; if (!host) return; // scroll and wrap lay out differently enough in grid to re-hydrate on // toggle, and the toggle is rare const options: FileOptions<undefined> = { ...pierreFileOptions(wrap), onPostRender };
// sveltekit re-runs the load on hydration, the prop never reaches the // client. pierre marks its ssr output with data-dehydrated. a wrap toggle // lands here with the previous render: drop it, keep pierre's style nodes const dehydrated = host.shadowRoot?.querySelector("[data-dehydrated]") != null; if (prerenderedHTML === undefined && !dehydrated) clearPierreRender(host); const created = new File(options, undefined, true); // untracked, the render effect below owns updates created.hydrate({ file: untrack(() => ({ name, contents })), fileContainer: host, prerenderedHTML }); instance = created;
return () => { created.cleanUp(); instance = undefined; }; });
// hydrate paints the initial file, this pass covers later name/contents // changes let firstRender = true; $effect(() => { const file = { name, contents }; if (firstRender) { firstRender = false; return; } instance?.render({ file, forceRender: true }); });</script>
<diffs-container bind:this={element} class="diffs-container"> {#if prerenderedHTML} <!-- eslint-disable-next-line svelte/no-at-html-tags -- pierre's own renderer output, token text is escaped by its hast builder --> <template shadowrootmode="open">{@html prerenderedHTML}</template> {/if}</diffs-container>