import * as React from "react" /** * When Leo greets, measured from the arrival starting. * * Not at mount, which is where the greeting used to fire and where it could not * be seen. Two reasons, and both of them are about what else is happening in * that first frame. The gesture is a ~420ms keyframe on SVG transforms driven * from JavaScript, so at mount it competes with the page's own first layout and * the frames that carry it are the frames most likely to be dropped. And the * launcher arrives icon-only with its wash still 150ms out, so a greeting there * lands before there is anything to greet from: the star had finished moving * before the chip started opening, which reads as the star not animating at all. * * This puts the flick inside the opening beat instead * (`--ask-leo-label-open-*` in `globals.css`: 140ms in, 380ms long), so the star * and the box move together and the label's ink and shimmer follow it. */ const GREETING_DELAY_MS = 160 /** * How long the greeting is held — the gesture plus its sparkle stagger, with a * frame in hand. * * Released rather than left on for the rest of the arrival, because the state it * drives (`LeoIcon`'s `invited`) is a one-shot: while it stays set, a hover is * not a state change, so Leo would ignore the pointer for as long as the * arrival claims to be running. */ const GREETING_HOLD_MS = 600 /** * True for the stretch of an arrival where Leo should be mid-gesture. * * `active` is the arrival itself (`useOneShotIntro`). This delays the greeting * into it and then lets go, so the caller can hand the result straight to * `LeoIcon`'s `motionActive` beside its own hover state. */ export function useStagedGreeting(active: boolean): boolean { const [greeting, setGreeting] = React.useState(false) React.useEffect(() => { if (!active) return let release = 0 const start = window.setTimeout(() => { setGreeting(true) release = window.setTimeout(() => setGreeting(false), GREETING_HOLD_MS) }, GREETING_DELAY_MS) return () => { window.clearTimeout(start) window.clearTimeout(release) } }, [active]) return greeting }