From 6f165e23deae6d3a812af2b0aaf1557d94251a15 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Fri, 8 May 2026 15:36:28 +1000 Subject: [PATCH] perf(ui): defer tool status width measurement (#26282) --- .../ui/src/components/tool-status-title.tsx | 132 +++++++++--------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/packages/ui/src/components/tool-status-title.tsx b/packages/ui/src/components/tool-status-title.tsx index 412d92e3db..5c46593f71 100644 --- a/packages/ui/src/components/tool-status-title.tsx +++ b/packages/ui/src/components/tool-status-title.tsx @@ -1,4 +1,4 @@ -import { Show, createEffect, createMemo, on, onCleanup, onMount } from "solid-js" +import { Show, createEffect, createMemo, on, onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { TextShimmer } from "./text-shimmer" @@ -15,10 +15,8 @@ function common(active: string, done: string) { } function contentWidth(el: HTMLSpanElement | undefined) { - if (!el) return 0 - const range = document.createRange() - range.selectNodeContents(el) - return Math.ceil(range.getBoundingClientRect().width) + if (!el) return + return `${Math.ceil(el.getBoundingClientRect().width)}px` } export function ToolStatusTitle(props: { @@ -37,99 +35,99 @@ export function ToolStatusTitle(props: { const doneTail = createMemo(() => (suffix() ? split().done : props.doneText)) const [state, setState] = createStore({ - width: "auto", - ready: false, + active: props.active, + animating: false, + width: undefined as string | undefined, }) const width = () => state.width - const ready = () => state.ready + const active = () => state.active + const animating = () => state.animating let activeRef: HTMLSpanElement | undefined let doneRef: HTMLSpanElement | undefined + let widthRef: HTMLSpanElement | undefined let frame: number | undefined - let readyFrame: number | undefined - - const measure = () => { - const target = props.active ? activeRef : doneRef - const px = contentWidth(target) - if (px > 0) setState("width", `${px}px`) - } - - const schedule = () => { - if (typeof requestAnimationFrame !== "function") { - measure() - return - } - if (frame !== undefined) cancelAnimationFrame(frame) - frame = requestAnimationFrame(() => { - frame = undefined - measure() - }) - } + let finishTimer: ReturnType | undefined const finish = () => { - if (typeof requestAnimationFrame !== "function") { - setState("ready", true) + if (frame !== undefined) cancelAnimationFrame(frame) + if (finishTimer !== undefined) clearTimeout(finishTimer) + frame = undefined + finishTimer = undefined + setState("animating", false) + setState("width", undefined) + } + + const animate = () => { + const first = contentWidth(widthRef) + finish() + setState("animating", true) + setState("active", props.active) + const last = contentWidth(props.active ? activeRef : doneRef) + if (!first || !last) { + finish() return } - if (readyFrame !== undefined) cancelAnimationFrame(readyFrame) - readyFrame = requestAnimationFrame(() => { - readyFrame = undefined - setState("ready", true) + + setState("width", first) + if (first === last) { + finishTimer = setTimeout(finish, 600) + return + } + + frame = requestAnimationFrame(() => { + frame = undefined + setState("width", last) + finishTimer = setTimeout(finish, 600) }) } - createEffect(on([() => props.active, activeTail, doneTail, suffix], () => schedule())) - - onMount(() => { - measure() - const fonts = typeof document !== "undefined" ? document.fonts : undefined - if (!fonts) { - finish() - return - } - void fonts.ready.finally(() => { - measure() - finish() - }) - }) + createEffect(on([() => props.active, activeTail, doneTail], () => animate(), { defer: true })) onCleanup(() => { - if (frame !== undefined) cancelAnimationFrame(frame) - if (readyFrame !== undefined) cancelAnimationFrame(readyFrame) + finish() }) return ( - - - - - - + + + + + + + + + + + } > - + - - - - - - - + + + + + + + + + + +