2026-05-31 13:54:31 +02:00

73 lines
1.6 KiB
Svelte

<script lang='ts'>
import type { KeyedTokensInfo, MagicMoveRenderOptions } from 'shiki-magic-move/types'
import { MagicMoveRenderer } from 'shiki-magic-move/renderer'
interface ShikiMagicMoveRendererProps {
class?: string
animate?: boolean
tokens: KeyedTokensInfo
previous?: KeyedTokensInfo
options?: MagicMoveRenderOptions
onStart?: () => void
onEnd?: () => void
}
const {
animate = true,
tokens,
previous,
options,
onStart,
onEnd,
...props
}: ShikiMagicMoveRendererProps = $props()
let container: HTMLPreElement
let renderer: MagicMoveRenderer
let isMounted = $state(false)
$effect(() => {
if (!container)
return
container.innerHTML = ''
isMounted = true
renderer = new MagicMoveRenderer(container)
})
$effect(() => {
async function render() {
if (!renderer)
return
Object.assign(renderer.options, options)
if (animate) {
if (previous)
renderer.replace(previous)
onStart?.()
await renderer.render(tokens)
onEnd?.()
}
else {
renderer.replace(tokens)
}
}
render()
})
</script>
<pre bind:this={container} class='shiki-magic-move-container {props?.class}' {...props}>
<!-- render initial tokens for SSR -->
{#if !isMounted}
{#each tokens.tokens as token (token.key)}
{#if token.content === '\n'}
<br />
{/if}
<span
class='shiki-magic-move-item'
style:color={token.color}
style={token.htmlStyle}>
{token.content}
</span>
{/each}
{/if}
</pre>