// @ts-nocheck import { createEffect, onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { BasicTool } from "./basic-tool" import { animate } from "motion" export default { title: "UI/Shell Submessage Motion", id: "components-shell-submessage-motion", tags: ["autodocs"], parameters: { docs: { description: { component: `### Overview Interactive playground for animating the Shell tool subtitle ("submessage") in the timeline trigger row. ### Production component path - Trigger layout: \`packages/ui/src/components/basic-tool.tsx\` - Bash tool subtitle source: \`packages/ui/src/components/message-part.tsx\` (tool: \`bash\`, \`trigger.subtitle\`) ### What this playground tunes - Width reveal (spring-driven pixel width via \`useSpring\`) - Opacity fade - Blur settle`, }, }, }, } const btn = (accent?: boolean) => ({ padding: "6px 14px", "border-radius": "6px", border: "1px solid var(--color-divider, #333)", background: accent ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", color: "var(--color-text, #eee)", cursor: "pointer", "font-size": "13px", }) as const const sliderLabel = { "font-size": "11px", "font-family": "monospace", color: "var(--color-text-weak, #666)", "min-width": "84px", "flex-shrink": "0", "text-align": "right", } const sliderValue = { "font-family": "monospace", "font-size": "11px", color: "var(--color-text-weak, #aaa)", "min-width": "76px", } const shellCss = ` [data-component="shell-submessage-scene"] [data-component="tool-trigger"] [data-slot="basic-tool-tool-info-main"] { align-items: baseline; } [data-component="shell-submessage"] { min-width: 0; max-width: 100%; display: inline-flex; align-items: baseline; vertical-align: baseline; } [data-component="shell-submessage"] [data-slot="shell-submessage-width"] { min-width: 0; max-width: 100%; display: inline-flex; align-items: baseline; overflow: hidden; } [data-component="shell-submessage"] [data-slot="shell-submessage-value"] { display: inline-block; vertical-align: baseline; min-width: 0; line-height: inherit; white-space: nowrap; opacity: 0; filter: blur(var(--shell-sub-blur, 2px)); transition-property: opacity, filter; transition-duration: var(--shell-sub-fade-ms, 320ms); transition-timing-function: var(--shell-sub-fade-ease, cubic-bezier(0.22, 1, 0.36, 1)); } [data-component="shell-submessage"][data-visible] [data-slot="shell-submessage-value"] { opacity: 1; filter: blur(0px); } ` const ease = { smooth: "cubic-bezier(0.16, 1, 0.3, 1)", snappy: "cubic-bezier(0.22, 1, 0.36, 1)", standard: "cubic-bezier(0.2, 0.8, 0.2, 1)", linear: "linear", } function SpringSubmessage(props: { text: string; visible: boolean; visualDuration: number; bounce: number }) { let ref: HTMLSpanElement | undefined let widthRef: HTMLSpanElement | undefined createEffect(() => { if (!widthRef) return if (props.visible) { requestAnimationFrame(() => { ref?.setAttribute("data-visible", "") animate( widthRef!, { width: "auto" }, { type: "spring", visualDuration: props.visualDuration, bounce: props.bounce }, ) }) } else { ref?.removeAttribute("data-visible") animate( widthRef, { width: "0px" }, { type: "spring", visualDuration: props.visualDuration, bounce: props.bounce }, ) } }) return ( {props.text || "\u00A0"} ) } export const Playground = { render: () => { const [state, setState] = createStore({ text: "Prints five topic blocks between timed commands", show: true, visualDuration: 0.35, bounce: 0, fadeMs: 320, blur: 2, fadeEase: "snappy", auto: false, }) const text = () => state.text const show = () => state.show const visualDuration = () => state.visualDuration const bounce = () => state.bounce const fadeMs = () => state.fadeMs const blur = () => state.blur const fadeEase = () => state.fadeEase const auto = () => state.auto let replayTimer let autoTimer const replay = () => { setState("show", false) if (replayTimer) clearTimeout(replayTimer) replayTimer = setTimeout(() => { setState("show", true) }, 50) } const stopAuto = () => { if (autoTimer) clearInterval(autoTimer) autoTimer = undefined setState("auto", false) } const toggleAuto = () => { if (auto()) { stopAuto() return } setState("auto", true) autoTimer = setInterval(replay, 2200) } onCleanup(() => { if (replayTimer) clearTimeout(replayTimer) if (autoTimer) clearInterval(autoTimer) }) return (
Shell
} >
{"$ cat <<'TOPIC1'"}
subtitle setState("text", e.currentTarget.value)} style={{ width: "420px", "max-width": "100%", padding: "6px 8px", "border-radius": "6px", border: "1px solid var(--color-divider, #333)", background: "var(--color-fill-element, #222)", color: "var(--color-text, #eee)", }} />
visualDuration setState("visualDuration", Number(e.currentTarget.value))} /> {visualDuration().toFixed(2)}s
bounce setState("bounce", Number(e.currentTarget.value))} /> {bounce().toFixed(2)}
fade ease
fade setState("fadeMs", Number(e.currentTarget.value))} /> {fadeMs()}ms
blur setState("blur", Number(e.currentTarget.value))} /> {blur()}px
) }, }