mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-08 01:39:12 +00:00
63 lines
1.5 KiB
TypeScript
63 lines
1.5 KiB
TypeScript
import { createEffect, createMemo, createSignal, onCleanup, type ValidComponent } from "solid-js"
|
|
import { Dynamic } from "solid-js/web"
|
|
|
|
export const TextShimmer = <T extends ValidComponent = "span">(props: {
|
|
text: string
|
|
class?: string
|
|
as?: T
|
|
active?: boolean
|
|
offset?: number
|
|
}) => {
|
|
const text = createMemo(() => props.text ?? "")
|
|
const active = createMemo(() => props.active ?? true)
|
|
const offset = createMemo(() => props.offset ?? 0)
|
|
const [run, setRun] = createSignal(active())
|
|
const swap = 220
|
|
let timer: ReturnType<typeof setTimeout> | undefined
|
|
|
|
createEffect(() => {
|
|
if (timer) {
|
|
clearTimeout(timer)
|
|
timer = undefined
|
|
}
|
|
|
|
if (active()) {
|
|
setRun(true)
|
|
return
|
|
}
|
|
|
|
timer = setTimeout(() => {
|
|
timer = undefined
|
|
setRun(false)
|
|
}, swap)
|
|
})
|
|
|
|
onCleanup(() => {
|
|
if (!timer) return
|
|
clearTimeout(timer)
|
|
})
|
|
|
|
return (
|
|
<Dynamic
|
|
component={props.as ?? "span"}
|
|
data-component="text-shimmer"
|
|
data-active={active() ? "true" : "false"}
|
|
class={props.class}
|
|
aria-label={text()}
|
|
style={{
|
|
"--text-shimmer-swap": `${swap}ms`,
|
|
"--text-shimmer-index": `${offset()}`,
|
|
}}
|
|
>
|
|
<span data-slot="text-shimmer-char">
|
|
<span data-slot="text-shimmer-char-base" aria-hidden="true">
|
|
{text()}
|
|
</span>
|
|
<span data-slot="text-shimmer-char-shimmer" data-run={run() ? "true" : "false"} aria-hidden="true">
|
|
{text()}
|
|
</span>
|
|
</span>
|
|
</Dynamic>
|
|
)
|
|
}
|