summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/tool-utils.ts
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-09 07:36:39 -0500
committerGitHub <[email protected]>2026-03-09 07:36:39 -0500
commitc71d1bde5e8dcc8be49c15697ad2e5d0f2607e5e (patch)
treea30482cedb38dc24cad70e24ad717817065620d6 /packages/ui/src/components/tool-utils.ts
parentf27ef595f65aa719be3f8d08665d683e95083ed3 (diff)
downloadopencode-c71d1bde5e8dcc8be49c15697ad2e5d0f2607e5e.tar.gz
opencode-c71d1bde5e8dcc8be49c15697ad2e5d0f2607e5e.zip
revert(app): "STUPID SEXY TIMELINE (#16420)" (#16745)
Diffstat (limited to 'packages/ui/src/components/tool-utils.ts')
-rw-r--r--packages/ui/src/components/tool-utils.ts336
1 files changed, 0 insertions, 336 deletions
diff --git a/packages/ui/src/components/tool-utils.ts b/packages/ui/src/components/tool-utils.ts
deleted file mode 100644
index 4d57c626e..000000000
--- a/packages/ui/src/components/tool-utils.ts
+++ /dev/null
@@ -1,336 +0,0 @@
-import type { ToolPart } from "@opencode-ai/sdk/v2"
-import { createEffect, createMemo, createSignal, on, onCleanup, onMount } from "solid-js"
-import { useReducedMotion } from "../hooks/use-reduced-motion"
-import {
- animate,
- type AnimationPlaybackControls,
- clearFadeStyles,
- clearMaskStyles,
- COLLAPSIBLE_SPRING,
- GROW_SPRING,
- WIPE_MASK,
-} from "./motion"
-
-export const TEXT_RENDER_THROTTLE_MS = 100
-
-export function createThrottledValue(getValue: () => string) {
- const [value, setValue] = createSignal(getValue())
- let timeout: ReturnType<typeof setTimeout> | undefined
- let last = 0
-
- createEffect(() => {
- const next = getValue()
- const now = Date.now()
-
- const remaining = TEXT_RENDER_THROTTLE_MS - (now - last)
- if (remaining <= 0) {
- if (timeout) {
- clearTimeout(timeout)
- timeout = undefined
- }
- last = now
- setValue(next)
- return
- }
- if (timeout) clearTimeout(timeout)
- timeout = setTimeout(() => {
- last = Date.now()
- setValue(next)
- timeout = undefined
- }, remaining)
- })
-
- onCleanup(() => {
- if (timeout) clearTimeout(timeout)
- })
-
- return value
-}
-
-export function busy(status: string | undefined) {
- return status === "pending" || status === "running"
-}
-
-export function hold(state: () => boolean, wait = 2000) {
- const [live, setLive] = createSignal(state())
- let timer: ReturnType<typeof setTimeout> | undefined
-
- createEffect(() => {
- if (state()) {
- if (timer) clearTimeout(timer)
- timer = undefined
- setLive(true)
- return
- }
-
- if (timer) clearTimeout(timer)
- timer = setTimeout(() => {
- timer = undefined
- setLive(false)
- }, wait)
- })
-
- onCleanup(() => {
- if (timer) clearTimeout(timer)
- })
-
- return live
-}
-
-export function updateScrollMask(el: HTMLElement, fade = 12) {
- const { scrollTop, scrollHeight, clientHeight } = el
- const overflow = scrollHeight - clientHeight
- if (overflow <= 1) {
- el.style.maskImage = ""
- el.style.webkitMaskImage = ""
- return
- }
- const top = scrollTop > 1
- const bottom = scrollTop < overflow - 1
- const mask =
- top && bottom
- ? `linear-gradient(to bottom, transparent 0, black ${fade}px, black calc(100% - ${fade}px), transparent 100%)`
- : top
- ? `linear-gradient(to bottom, transparent 0, black ${fade}px)`
- : bottom
- ? `linear-gradient(to bottom, black calc(100% - ${fade}px), transparent 100%)`
- : ""
- el.style.maskImage = mask
- el.style.webkitMaskImage = mask
-}
-
-export function useCollapsible(options: {
- content: () => HTMLElement | undefined
- body: () => HTMLElement | undefined
- open: () => boolean
- measure?: () => number
- onOpen?: () => void
-}) {
- const reduce = useReducedMotion()
- let heightAnim: AnimationPlaybackControls | undefined
- let fadeAnim: AnimationPlaybackControls | undefined
- let gen = 0
-
- createEffect(
- on(options.open, (isOpen) => {
- const content = options.content()
- const body = options.body()
- if (!content || !body) return
- heightAnim?.stop()
- fadeAnim?.stop()
- if (reduce()) {
- body.style.opacity = ""
- body.style.filter = ""
- if (isOpen) {
- content.style.display = ""
- content.style.height = "auto"
- options.onOpen?.()
- return
- }
- content.style.height = "0px"
- content.style.display = "none"
- return
- }
- const id = ++gen
- if (isOpen) {
- content.style.display = ""
- content.style.height = "0px"
- body.style.opacity = "0"
- body.style.filter = "blur(2px)"
- fadeAnim = animate(body, { opacity: [0, 1], filter: ["blur(2px)", "blur(0px)"] }, COLLAPSIBLE_SPRING)
- queueMicrotask(() => {
- if (gen !== id) return
- const c = options.content()
- if (!c) return
- const h = options.measure?.() ?? Math.ceil(body.getBoundingClientRect().height)
- heightAnim = animate(c, { height: ["0px", `${h}px`] }, COLLAPSIBLE_SPRING)
- heightAnim.finished.then(
- () => {
- if (gen !== id) return
- c.style.height = "auto"
- options.onOpen?.()
- },
- () => {},
- )
- })
- return
- }
-
- const h = content.getBoundingClientRect().height
- heightAnim = animate(content, { height: [`${h}px`, "0px"] }, COLLAPSIBLE_SPRING)
- fadeAnim = animate(body, { opacity: [1, 0], filter: ["blur(0px)", "blur(2px)"] }, COLLAPSIBLE_SPRING)
- heightAnim.finished.then(
- () => {
- if (gen !== id) return
- content.style.display = "none"
- },
- () => {},
- )
- }),
- )
-
- onCleanup(() => {
- ++gen
- heightAnim?.stop()
- fadeAnim?.stop()
- })
-}
-
-export function useContextToolPending(parts: () => ToolPart[], working?: () => boolean) {
- const anyRunning = createMemo(() => parts().some((part) => busy(part.state.status)))
- const [settled, setSettled] = createSignal(false)
- createEffect(() => {
- if (!anyRunning() && !working?.()) setSettled(true)
- })
- return createMemo(() => !settled() && (!!working?.() || anyRunning()))
-}
-
-export function useRowWipe(opts: {
- id: () => string
- text: () => string | undefined
- ref: () => HTMLElement | undefined
- seen: Set<string>
-}) {
- const reduce = useReducedMotion()
-
- createEffect(() => {
- const id = opts.id()
- const txt = opts.text()
- const el = opts.ref()
- if (!el) return
- if (!txt) {
- clearFadeStyles(el)
- clearMaskStyles(el)
- return
- }
- if (reduce() || typeof window === "undefined") {
- clearFadeStyles(el)
- clearMaskStyles(el)
- return
- }
- if (opts.seen.has(id)) {
- clearFadeStyles(el)
- clearMaskStyles(el)
- return
- }
- opts.seen.add(id)
-
- el.style.maskImage = WIPE_MASK
- el.style.webkitMaskImage = WIPE_MASK
- el.style.maskSize = "240% 100%"
- el.style.webkitMaskSize = "240% 100%"
- el.style.maskRepeat = "no-repeat"
- el.style.webkitMaskRepeat = "no-repeat"
- el.style.maskPosition = "100% 0%"
- el.style.webkitMaskPosition = "100% 0%"
- el.style.opacity = "0"
- el.style.filter = "blur(2px)"
- el.style.transform = "translateX(-0.06em)"
-
- let done = false
- const clear = () => {
- if (done) return
- done = true
- clearFadeStyles(el)
- clearMaskStyles(el)
- }
- if (typeof requestAnimationFrame !== "function") {
- clear()
- return
- }
- let anim: AnimationPlaybackControls | undefined
- let frame: number | undefined = requestAnimationFrame(() => {
- frame = undefined
- const node = opts.ref()
- if (!node) return
- anim = animate(
- node,
- {
- opacity: [0, 1],
- filter: ["blur(2px)", "blur(0px)"],
- transform: ["translateX(-0.06em)", "translateX(0)"],
- maskPosition: "0% 0%",
- },
- GROW_SPRING,
- )
-
- anim.finished.catch(() => {}).finally(clear)
- })
-
- onCleanup(() => {
- if (frame !== undefined) {
- cancelAnimationFrame(frame)
- clear()
- }
- })
- })
-}
-
-export function useToolFade(
- ref: () => HTMLElement | undefined,
- options?: { delay?: number; wipe?: boolean; animate?: boolean },
-) {
- let anim: AnimationPlaybackControls | undefined
- let frame: number | undefined
- const delay = options?.delay ?? 0
- const wipe = options?.wipe ?? false
- const active = options?.animate !== false
- const reduce = useReducedMotion()
-
- onMount(() => {
- if (!active) return
-
- const el = ref()
- if (!el || typeof window === "undefined") return
- if (reduce()) return
-
- const mask =
- wipe &&
- typeof CSS !== "undefined" &&
- (CSS.supports("mask-image", "linear-gradient(to right, black, transparent)") ||
- CSS.supports("-webkit-mask-image", "linear-gradient(to right, black, transparent)"))
-
- el.style.opacity = "0"
- el.style.filter = wipe ? "blur(3px)" : "blur(2px)"
- el.style.transform = wipe ? "translateX(-0.06em)" : "translateY(0.04em)"
-
- if (mask) {
- el.style.maskImage = WIPE_MASK
- el.style.webkitMaskImage = WIPE_MASK
- el.style.maskSize = "240% 100%"
- el.style.webkitMaskSize = "240% 100%"
- el.style.maskRepeat = "no-repeat"
- el.style.webkitMaskRepeat = "no-repeat"
- el.style.maskPosition = "100% 0%"
- el.style.webkitMaskPosition = "100% 0%"
- }
-
- frame = requestAnimationFrame(() => {
- frame = undefined
- const node = ref()
- if (!node) return
-
- anim = wipe
- ? mask
- ? animate(
- node,
- { opacity: 1, filter: "blur(0px)", transform: "translateX(0)", maskPosition: "0% 0%" },
- { ...GROW_SPRING, delay },
- )
- : animate(node, { opacity: 1, filter: "blur(0px)", transform: "translateX(0)" }, { ...GROW_SPRING, delay })
- : animate(node, { opacity: 1, filter: "blur(0px)", transform: "translateY(0)" }, { ...GROW_SPRING, delay })
-
- anim?.finished.then(() => {
- const value = ref()
- if (!value) return
- clearFadeStyles(value)
- if (mask) clearMaskStyles(value)
- })
- })
- })
-
- onCleanup(() => {
- if (frame !== undefined) cancelAnimationFrame(frame)
- anim?.stop()
- })
-}