{"version":3,"sources":["../src/status.tsx"],"sourcesContent":["// In-app status primitives (interaction_standards R-IX-2/R-IX-3; the status half\n// of the standards' delivery vehicle, R3-613).\n//\n// `Status` is the live region: mount it ONCE per surface and change its content —\n// a content change inside a mounted `role=\"status\"` region announces without\n// stealing focus (WCAG 4.1.3). `Busy` is R-IX-2's write face as a component: the\n// pending control keeps its box and names what is happening, carrying `aria-busy`.\n//\n// TRUST BOUNDARY (same rule as `./loading` and `./dialog`): presentational only,\n// NO capability, NO host round-trip, no reserved landmark or host wordmark.\n//\n// TIMING: no constant is minted here. The flash floor below is LOADING_TIMINGS'\n// spinThresholdMs — §9-2's token clause, one timing language for both modules.\nimport { useEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport { LOADING_TIMINGS } from './loading';\n\n/** Props for {@link Status}. */\nexport interface StatusProps {\n  /** The current message. Change THIS to announce; do not mount/unmount the\n   *  region per message — a region that mounts with content announces nothing. */\n  children: ReactNode;\n  /** Assertive live regions interrupt — polite never does. Opt in only for\n   *  outcomes the user must hear immediately; the default is polite. */\n  assertive?: boolean;\n  className?: string;\n  style?: CSSProperties;\n}\n\n/**\n * A polite live region (WCAG 4.1.3): content changes inside a mounted region\n * are announced without moving focus. Mount it once per surface; announce by\n * changing `children`.\n */\nexport function Status({ children, assertive = false, className, style }: StatusProps): ReactNode {\n  return (\n    <div role=\"status\" aria-live={assertive ? 'assertive' : 'polite'} className={className} style={style}>\n      {children}\n    </div>\n  );\n}\n\n/** Props for {@link Busy}. */\nexport interface BusyProps {\n  /** What is happening, named (\"Saving…\", \"Connecting…\") — the R-IX-2 label. */\n  label: string;\n  /** The flash floor: below this wait, nothing shows (LOADING_UX_SPEC §3.3 /\n   *  UI_AS_APPS_SPEC §6.2 — a fast wait never flashes a busy state). Defaults to\n   *  the platform floor; pass `0` to show immediately. */\n  floorMs?: number;\n  className?: string;\n  style?: CSSProperties;\n}\n\n/**\n * The named busy state as a component: the box renders from the first frame\n * (R-IX-2 — the control is never removed and the surface is never replaced by\n * a spinner), `aria-busy` throughout, and the caller's label appears once the\n * flash floor has passed — below it, nothing shows rather than a flash.\n *\n * Render it IN PLACE of the control's resting label while the request is in\n * flight, with the control itself disabled by the caller:\n * `<button disabled>{busy ? <Busy label=\"Saving…\" /> : \"Save\"}</button>`.\n */\nexport function Busy({ label, floorMs = LOADING_TIMINGS.spinThresholdMs, className, style }: BusyProps): ReactNode {\n  const [show, setShow] = useState(floorMs <= 0);\n  useEffect(() => {\n    if (floorMs <= 0) {\n      setShow(true);\n      return;\n    }\n    const t = setTimeout(() => setShow(true), floorMs);\n    return () => clearTimeout(t);\n  }, [floorMs, label]);\n\n  return (\n    <span aria-busy=\"true\" className={className} style={style}>\n      {show ? label : ''}\n    </span>\n  );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCI;AAtBJ,mBAAwE;AACxE,qBAAgC;AAmBzB,SAAS,OAAO,EAAE,UAAU,YAAY,OAAO,WAAW,MAAM,GAA2B;AAChG,SACE,4CAAC,SAAI,MAAK,UAAS,aAAW,YAAY,cAAc,UAAU,WAAsB,OACrF,UACH;AAEJ;AAwBO,SAAS,KAAK,EAAE,OAAO,UAAU,+BAAgB,iBAAiB,WAAW,MAAM,GAAyB;AACjH,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,WAAW,CAAC;AAC7C,8BAAU,MAAM;AACd,QAAI,WAAW,GAAG;AAChB,cAAQ,IAAI;AACZ;AAAA,IACF;AACA,UAAM,IAAI,WAAW,MAAM,QAAQ,IAAI,GAAG,OAAO;AACjD,WAAO,MAAM,aAAa,CAAC;AAAA,EAC7B,GAAG,CAAC,SAAS,KAAK,CAAC;AAEnB,SACE,4CAAC,UAAK,aAAU,QAAO,WAAsB,OAC1C,iBAAO,QAAQ,IAClB;AAEJ;","names":[]}