~james/core

core/web/src/lib/components/ui/TextSwap.svelte -rw-r--r-- 833 bytes
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<script lang="ts">
	import { tick, untrack } from "svelte";

	interface Props {
		value: string;
		class?: string;
	}

	let { value, class: className }: Props = $props();

	let el: HTMLSpanElement | undefined = $state();
	let shown = $state(untrack(() => value));
	let phase = $state<"exit" | "enter" | undefined>();

	$effect(() => {
		const next = value;
		if (!el || next === shown) return;

		const dur = parseFloat(getComputedStyle(el).getPropertyValue("--text-swap-dur")) || 150;

		phase = "exit";
		const timer = setTimeout(() => {
			void (async () => {
				shown = next;
				phase = "enter";
				await tick();
				void el?.offsetHeight;
				phase = undefined;
			})();
		}, dur);

		return () => clearTimeout(timer);
	});
</script>

<span bind:this={el} class="text-swap {className ?? ''}" data-swap={phase}>{shown}</span>