@qball-inc/react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2424 @@
1
+ import * as react from 'react';
2
+ import { PropsWithChildren, CSSProperties, ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, ReactElement, ChangeEvent, ComponentPropsWithoutRef, HTMLAttributes, DependencyList, SVGProps } from 'react';
3
+ import * as Dialog from '@radix-ui/react-dialog';
4
+ import { ToasterProps } from 'sonner';
5
+ export { ToasterProps } from 'sonner';
6
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
7
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
8
+ import { RowData, ColumnDef, Row, RowSelectionState, OnChangeFn, ColumnMeta } from '@tanstack/react-table';
9
+ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
10
+
11
+ interface SurfaceProps extends PropsWithChildren {
12
+ /** Inline style overrides merged after the token-driven base. */
13
+ style?: CSSProperties;
14
+ }
15
+ /**
16
+ * Smoke primitive that proves the build harness end-to-end: the JSX transform,
17
+ * the DOM lib, the dual ESM/CJS emit, the `.d.ts` output, and the consumer
18
+ * import path (RB-3). It is styled ONLY via `@qball-inc/tokens` CSS custom
19
+ * properties — no hardcoded hex, no box-shadow, no pill radius (DESIGN.md FR4).
20
+ * The custom properties resolve at runtime from the consumer's token CSS import.
21
+ */
22
+ declare function Surface({ children, style }: SurfaceProps): react.JSX.Element;
23
+
24
+ /**
25
+ * Button — token-driven, framework-agnostic at the CSS layer.
26
+ *
27
+ * Styling is delivered entirely by the published `@qball-inc/tokens` CSS: this
28
+ * component only composes the shipped semantic class names (`.btn`, `.btn--*`)
29
+ * shown in the `preview/buttons*.html` oracle cards. There is NO component CSS,
30
+ * no hardcoded hex, no box-shadow, no Tailwind, and no shadcn runtime — the
31
+ * `.btn` rules (radius `--radius-sm`, border-only focus, the sanctioned loading
32
+ * spinner) live in `colors_and_type.css` and resolve from the consumer's token
33
+ * CSS import. DESIGN.md conformance is therefore inherited, not re-authored.
34
+ *
35
+ * `icon` and `loading` are layered MODIFIERS (per the oracle: `btn btn--secondary
36
+ * btn--icon`, `btn btn--primary btn--loading`), not standalone color variants.
37
+ */
38
+ type ButtonVariant = "primary" | "secondary" | "tertiary" | "ghost" | "destructive";
39
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
40
+ /**
41
+ * Color treatment. Default `primary`. The `destructive` variant signals a
42
+ * dangerous action with color — always pair it with a text label (or, for an
43
+ * icon-only destructive control, an `aria-label`) so the meaning is not
44
+ * carried by color alone (DESIGN.md finance-color-plus-cue).
45
+ */
46
+ variant?: ButtonVariant;
47
+ /** Icon-only square treatment (`.btn--icon`). Pair with `variant` for color; provide an `aria-label`. */
48
+ icon?: boolean;
49
+ /** Loading state (`.btn--loading`): hides the label, shows the spinner, sets `aria-busy`, and blocks interaction. */
50
+ loading?: boolean;
51
+ /**
52
+ * Render the single child element instead of a `<button>` (Radix Slot). The
53
+ * `.btn` classes merge onto the child, so `<Button asChild><a href="…">…</a></Button>`
54
+ * renders an `<a>` with identical styling. Note: the forwarded `ref` is typed
55
+ * as `HTMLButtonElement` for the default case; under `asChild` it resolves to
56
+ * the child's element type at runtime (e.g. `HTMLAnchorElement`).
57
+ */
58
+ asChild?: boolean;
59
+ children?: ReactNode;
60
+ }
61
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
62
+
63
+ /**
64
+ * Input — token-driven text/numeric input.
65
+ *
66
+ * Composes the shipped `.input` class from `@qball-inc/tokens`
67
+ * (`components.css`), matching the `preview/form-input.html` and
68
+ * `preview/form-controls.html` oracle cards. Border-only sage focus, error
69
+ * border, and tabular numerics all live in the published token CSS — this
70
+ * component authors no CSS and contains no hex.
71
+ *
72
+ * `numeric` opts into finance-grade tabular figures (`.num`) and an
73
+ * `inputMode="decimal"` keypad, following the oracle's `class="input num"
74
+ * inputmode="decimal"` cell rather than a native `type="number"` (which loses
75
+ * `inputMode` control and adds spinner chrome).
76
+ */
77
+ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
78
+ /** Numeric variant: tabular figures (`.num`) + decimal keypad for finance contexts. */
79
+ numeric?: boolean;
80
+ }
81
+ declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
82
+
83
+ /**
84
+ * Field — label + control + helper/error composition wrapper.
85
+ *
86
+ * Renders the shipped `.field` structure from `@qball-inc/tokens`
87
+ * (`components.css`), matching the `preview/form-controls.html` oracle: a
88
+ * `.field__label` associated to the control via `htmlFor`/`id`, optional
89
+ * `.field__help`, and a `.field__error` with `role="alert"`. When `errorText`
90
+ * is present it sets `aria-invalid` on the child control (which in turn applies
91
+ * the `.input--error` border) and points `aria-describedby` at the messages.
92
+ * No component CSS, no hex.
93
+ */
94
+ type FieldControl = ReactElement<{
95
+ id?: string;
96
+ "aria-invalid"?: InputHTMLAttributes<HTMLInputElement>["aria-invalid"];
97
+ "aria-describedby"?: string | undefined;
98
+ }>;
99
+ interface FieldProps {
100
+ /** Visible label text, associated to the control. */
101
+ label: string;
102
+ /** Optional helper text shown below the control (`aria-describedby`). */
103
+ helpText?: string;
104
+ /** Optional error text; when set, marks the control invalid and renders a `role="alert"` message. */
105
+ errorText?: string;
106
+ /** Render a required marker (`*`) after the label. */
107
+ required?: boolean;
108
+ /** The control element (typically an `Input`); receives `id`, `aria-invalid`, and `aria-describedby`. */
109
+ children: FieldControl;
110
+ }
111
+ declare function Field({ label, helpText, errorText, required, children }: FieldProps): react.JSX.Element;
112
+
113
+ /**
114
+ * Select — custom dropdown (no native `<select>`).
115
+ *
116
+ * Radix `@radix-ui/react-select` provides the behavior (keyboard navigation,
117
+ * focus management, typeahead, portalled panel — AC-2) while the visual surface
118
+ * is the shipped `@qball-inc/tokens` CSS: the trigger applies `.select` (whose
119
+ * chevron is a CSS background-image, so no icon dep is needed), and the panel +
120
+ * items apply `.menu` / `.menu__item` / `.menu__check` — matching the
121
+ * `preview/select.html` oracle. This is the same "Radix for behavior, shipped
122
+ * classes for style" pattern as Button's `asChild` Slot. No component CSS, no hex.
123
+ *
124
+ * NOTE (visual conformance / token-package concern): Radix exposes item highlight
125
+ * via `data-highlighted` and selection via `data-state`, whereas the shipped
126
+ * `.menu__item` tint keys on `:hover` + `[aria-selected]`. The selected item's
127
+ * check (`.menu__check`, via Radix `ItemIndicator`) always renders; refining the
128
+ * keyboard-highlight tint to `[data-highlighted]` is a tokens-package edit (a
129
+ * separate WP / semver event), not a React-component change here.
130
+ */
131
+ interface SelectProps {
132
+ /** Controlled selected value. */
133
+ value?: string;
134
+ /** Uncontrolled initial value. */
135
+ defaultValue?: string;
136
+ /** Fired with the newly selected value. */
137
+ onValueChange?: (value: string) => void;
138
+ /** Shown on the trigger when no value is selected. */
139
+ placeholder?: string;
140
+ /** Disables the trigger (applies the shipped `.select:disabled` styling). */
141
+ disabled?: boolean;
142
+ /** Accessible name for the trigger when there is no associated `<label>`. */
143
+ "aria-label"?: string;
144
+ /** `SelectItem` children. */
145
+ children?: ReactNode;
146
+ /** className merged onto the `.select` trigger. */
147
+ className?: string;
148
+ }
149
+ declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLButtonElement>>;
150
+ interface SelectItemProps {
151
+ /** The value selected when this item is chosen. */
152
+ value: string;
153
+ /** Disables this option. */
154
+ disabled?: boolean;
155
+ /** The visible option label. */
156
+ children?: ReactNode;
157
+ /** className merged onto the `.menu__item` element. */
158
+ className?: string;
159
+ }
160
+ declare const SelectItem: react.ForwardRefExoticComponent<SelectItemProps & react.RefAttributes<HTMLDivElement>>;
161
+
162
+ /**
163
+ * Switch — token-driven on/off toggle.
164
+ *
165
+ * Composes the shipped `.switch` structure from `@qball-inc/tokens`
166
+ * (`components.css`), matching the `preview/toggle.html` oracle: a `<label class="switch">`
167
+ * wrapping a visually-hidden native `<input type="checkbox">` and a `.switch__ui`
168
+ * track. The brand-native SQUARED knob (4px / `var(--radius-sm)` — explicitly NOT
169
+ * a 9999px pill, FR4) and the sage on-state live entirely in the published token
170
+ * CSS, driven by the `.switch input:checked + .switch__ui` sibling selector. This
171
+ * component authors no CSS and contains no hex.
172
+ *
173
+ * This is deliberately NOT a Radix Switch wrapper: Radix renders a
174
+ * `<button role="switch" data-state>` with no native `:checked` input, so the
175
+ * shipped sibling-selector CSS would never fire. The native checkbox is
176
+ * keyboard-accessible for free; `role="switch"` upgrades the exposed semantics so
177
+ * assistive tech announces on/off rather than checked/unchecked.
178
+ */
179
+ interface SwitchProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "role" | "children" | "onChange"> {
180
+ /** Controlled on/off state. Omit (with `defaultChecked`) for an uncontrolled switch. */
181
+ checked?: boolean;
182
+ /** Fired with the new boolean state whenever the user toggles. */
183
+ onCheckedChange?: (checked: boolean) => void;
184
+ /** Native change handler; fired alongside `onCheckedChange`. */
185
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
186
+ /** Optional visible label rendered beside the track (the oracle pattern). */
187
+ children?: ReactNode;
188
+ /** className applied to the outer `<label>` (`.switch`), not the hidden input. */
189
+ className?: string;
190
+ }
191
+ declare const Switch: react.ForwardRefExoticComponent<SwitchProps & react.RefAttributes<HTMLInputElement>>;
192
+
193
+ interface SegmentedProps {
194
+ /** Controlled selected value. */
195
+ value?: string;
196
+ /** Uncontrolled initial value; ensures one item starts pressed. */
197
+ defaultValue?: string;
198
+ /** Fired with the newly selected value (never with empty — no full-deselect). */
199
+ onValueChange?: (value: string) => void;
200
+ /** Accessible group label (the control has no visible heading). */
201
+ "aria-label"?: string;
202
+ /** `SegmentedItem` children. */
203
+ children?: ReactNode;
204
+ /** className applied to the `.segmented` group container. */
205
+ className?: string;
206
+ }
207
+ declare function Segmented({ value, defaultValue, onValueChange, children, className, "aria-label": ariaLabel, }: SegmentedProps): react.JSX.Element;
208
+ interface SegmentedItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "value" | "type" | "aria-pressed"> {
209
+ /** The value this segment selects. */
210
+ value: string;
211
+ children?: ReactNode;
212
+ }
213
+ declare const SegmentedItem: react.ForwardRefExoticComponent<SegmentedItemProps & react.RefAttributes<HTMLButtonElement>>;
214
+
215
+ /**
216
+ * SecretInput — masked BYO-key / secret entry with reveal, set, rotate, remove.
217
+ *
218
+ * A token-driven className wrapper over the shipped `@qball-inc/tokens` surface
219
+ * (`components.css` / `colors_and_type.css`), matching the
220
+ * `preview/secret-input.html` oracle card: a `.field` composition wrapping an
221
+ * `.input-wrap` (the `.input num` masked field + an `.input-wrap__affix` reveal
222
+ * toggle) and a `.btn` action row. There is NO behavioral library and NO
223
+ * component CSS — masking is the native `<input type="password">`, the reveal
224
+ * toggle flips `type` to `text`, and every visual comes from the shipped token
225
+ * classes. The two inline styles are structural-only (`display:flex` row +
226
+ * `gap`/`color` from `var(--*)` tokens), mirroring the oracle's own
227
+ * `style="color:var(--data-down)"` Delete affordance — no hex, no shadow.
228
+ *
229
+ * Security posture (BINDING): the raw secret lives ONLY as the controlled
230
+ * input's value — it is never duplicated into another node, attribute, or text,
231
+ * and is never passed to `console.*`. The masked state relies on the native
232
+ * password mask; the reveal toggle is the only path to plaintext, and only
233
+ * while held in view. The leak gate in `SecretInput.test.tsx` asserts the
234
+ * secret is confined to that single input's value and is absent from every
235
+ * other attribute, all text content, web storage, cookies, and `console.*`.
236
+ *
237
+ * State model:
238
+ * - `isSet={false}` (unset): editable input + a single "Set" affordance.
239
+ * - `isSet` (set): masked read-only value + "Rotate" + "Remove". "Rotate" opens
240
+ * an in-place edit (Update / Cancel) without round-tripping the stored secret.
241
+ */
242
+ interface SecretInputProps {
243
+ /** Current input value (controlled). In the masked set-state this is what the consumer chooses to display. */
244
+ value: string;
245
+ /** Fired with the new string on each edit (the value, not the DOM event). */
246
+ onChange: (value: string) => void;
247
+ /** Commit handler — fired with the current value when the user confirms (Set / Update / Enter). */
248
+ onSet: (value: string) => void;
249
+ /** Clear/remove handler — fired when the user removes a stored secret; resets to the unset state. */
250
+ onRemove: () => void;
251
+ /** Visible label, associated to the input via `htmlFor`/`id`. */
252
+ label: string;
253
+ /** Whether a secret is currently stored. `false` → unset/entry; `true` → masked display with rotate/remove. */
254
+ isSet?: boolean;
255
+ /** Disable the whole control. */
256
+ disabled?: boolean;
257
+ /** Placeholder shown in the unset/entry state. */
258
+ placeholder?: string;
259
+ /** Form field name; pairs with `autocomplete="new-password"` to suppress credential autofill. */
260
+ name?: string;
261
+ /** Optional helper text below the field (`aria-describedby`). */
262
+ helpText?: string;
263
+ /** Render a required marker (`*`) after the label. */
264
+ required?: boolean;
265
+ /** Label for the commit button in the unset state. Default `"Set"`. */
266
+ setLabel?: string;
267
+ /** Label for the commit button while rotating an existing secret. Default `"Update"`. */
268
+ updateLabel?: string;
269
+ /** Label for the rotate affordance in the set state. Default `"Rotate"`. */
270
+ rotateLabel?: string;
271
+ /** Label for the remove affordance in the set state. Default `"Remove"`. */
272
+ removeLabel?: string;
273
+ /** Label for the cancel affordance while rotating. Default `"Cancel"`. */
274
+ cancelLabel?: string;
275
+ /** `aria-label` for the reveal toggle when masked. Default `"Show secret"`. */
276
+ showSecretLabel?: string;
277
+ /** `aria-label` for the reveal toggle when revealed. Default `"Hide secret"`. */
278
+ hideSecretLabel?: string;
279
+ }
280
+ declare const SecretInput: react.ForwardRefExoticComponent<SecretInputProps & react.RefAttributes<HTMLInputElement>>;
281
+
282
+ /**
283
+ * Search — command-palette search/autocomplete built on `cmdk`.
284
+ *
285
+ * cmdk supplies the headless behavior (built-in fuzzy filtering, roving
286
+ * keyboard navigation, combobox/listbox ARIA), and the visuals come entirely
287
+ * from the shipped `@qball-inc/tokens` classes: the input is painted with
288
+ * `.input`, the results panel with `.menu`, and each result with `.menu__item`
289
+ * (the same dropdown surface `Select` paints). cmdk is additive — it ships no
290
+ * conflicting CSS, so applying the token classes on top is sufficient and no
291
+ * component CSS is authored (the loading/empty rows use structural padding +
292
+ * the `--text-muted` token only, mirroring the oracle's inline-token style).
293
+ *
294
+ * Filtering is cmdk's built-in matcher over each item's `label`; selecting a
295
+ * result (click or Enter) fires `onSelect` with the full item object.
296
+ */
297
+ interface SearchItem {
298
+ /** Stable identity; used as the React key. */
299
+ id: string;
300
+ /** Visible text; also the value cmdk filters against. */
301
+ label: string;
302
+ /** Optional group heading the item is bucketed under. */
303
+ group?: string;
304
+ }
305
+ interface SearchProps {
306
+ /** The selectable items. */
307
+ items: SearchItem[];
308
+ /** Fired with the selected item when a result is chosen (click or Enter). */
309
+ onSelect: (item: SearchItem) => void;
310
+ /** Placeholder for the search input. */
311
+ placeholder?: string;
312
+ /** Text shown when the query matches no items. Default `"No results found."`. */
313
+ emptyText?: string;
314
+ /** Show a loading row instead of (or alongside) results. */
315
+ isLoading?: boolean;
316
+ /** Disable the input and all results. */
317
+ disabled?: boolean;
318
+ /** Accessible label for the search input + command region. Default `"Search"`. */
319
+ label?: string;
320
+ }
321
+ declare function Search({ items, onSelect, placeholder, emptyText, isLoading, disabled, label, }: SearchProps): react.JSX.Element;
322
+
323
+ /** Modal root — owns the open state. Thin alias of Radix `Dialog.Root`. */
324
+ declare const Modal: react.FC<Dialog.DialogProps>;
325
+ /** Opens the modal; wrap a custom trigger element with `asChild`. Alias of `Dialog.Trigger`. */
326
+ declare const ModalTrigger: react.ForwardRefExoticComponent<Dialog.DialogTriggerProps & react.RefAttributes<HTMLButtonElement>>;
327
+ interface ModalContentProps extends ComponentPropsWithoutRef<typeof Dialog.Content> {
328
+ /** Close when Escape is pressed. Default `true`; set `false` to suppress (AC-6). */
329
+ closeOnEscape?: boolean;
330
+ /** Close when the scrim/overlay is clicked. Default `true`; set `false` to suppress (AC-6). */
331
+ closeOnOverlayClick?: boolean;
332
+ }
333
+ /**
334
+ * The portalled dialog surface: a `.scrim` overlay + the `.modal` content panel,
335
+ * fixed-centered. Must contain a `ModalTitle`. Escape / overlay-click close by
336
+ * default; pass `closeOnEscape={false}` / `closeOnOverlayClick={false}` to suppress.
337
+ */
338
+ declare const ModalContent: react.ForwardRefExoticComponent<ModalContentProps & react.RefAttributes<HTMLDivElement>>;
339
+ /** Dialog title (`.modal__title`). Required inside `ModalContent` for accessibility. */
340
+ declare const ModalTitle: react.ForwardRefExoticComponent<Omit<Dialog.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>, "ref"> & react.RefAttributes<HTMLHeadingElement>>;
341
+ /** Dialog description / subtitle (`.modal__sub`). */
342
+ declare const ModalDescription: react.ForwardRefExoticComponent<Omit<Dialog.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>, "ref"> & react.RefAttributes<HTMLParagraphElement>>;
343
+ /**
344
+ * Closes the modal. Defaults to the `.modal__x` icon button (for the head);
345
+ * pass `asChild` to style any element (e.g. a `.btn` Cancel in the footer).
346
+ */
347
+ declare const ModalClose: react.ForwardRefExoticComponent<Omit<Dialog.DialogCloseProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
348
+ interface AlertModalProps {
349
+ /** Controlled open state. */
350
+ open?: boolean;
351
+ /** Uncontrolled initial open state. */
352
+ defaultOpen?: boolean;
353
+ /** Fired when the open state changes. */
354
+ onOpenChange?: (open: boolean) => void;
355
+ /** Optional trigger element (wrapped with `asChild`). Omit when controlling `open` externally. */
356
+ trigger?: ReactNode;
357
+ /** Confirmation title (required for accessibility). */
358
+ title: ReactNode;
359
+ /** Supporting copy explaining the consequence. */
360
+ description?: ReactNode;
361
+ /** Optional extra body content between the description and the action row. */
362
+ children?: ReactNode;
363
+ /** Label for the confirm action. Default `"Confirm"`. */
364
+ confirmLabel?: string;
365
+ /** Label for the cancel action. Default `"Cancel"`. */
366
+ cancelLabel?: string;
367
+ /** Fired when the confirm action is chosen (the dialog then closes). */
368
+ onConfirm?: () => void;
369
+ /** Style the confirm button as destructive + show the warn badge. Default `true`. */
370
+ destructive?: boolean;
371
+ /** Accessible name for the dialog surface. */
372
+ "aria-label"?: string;
373
+ /** Structural style overrides merged onto the content panel (e.g. `maxWidth`). */
374
+ style?: CSSProperties;
375
+ }
376
+ /**
377
+ * AlertModal — a destructive/blocking confirmation built on Radix `AlertDialog`
378
+ * (Escape + overlay-click are intentionally NOT close-on-outside by Radix design;
379
+ * the user must choose Cancel or Confirm). Matches the `preview/modal.html`
380
+ * confirm-modal oracle: a warn badge + title + description and a ghost Cancel /
381
+ * destructive Confirm action row.
382
+ */
383
+ declare function AlertModal({ open, defaultOpen, onOpenChange, trigger, title, description, children, confirmLabel, cancelLabel, onConfirm, destructive, "aria-label": ariaLabel, style, }: AlertModalProps): react.JSX.Element;
384
+
385
+ interface ToastOptions {
386
+ /** Secondary body line under the title (`.toast__msg`). */
387
+ description?: ReactNode;
388
+ /** Auto-dismiss duration in ms. Default 4000. Pass `Infinity` to require manual dismiss. */
389
+ duration?: number;
390
+ /** Accessible label for the close button. Default `"Dismiss"`. */
391
+ dismissLabel?: string;
392
+ }
393
+ /**
394
+ * Imperative toast API. Each variant maps to a shipped `.toast--*` accent stripe
395
+ * + matching icon. Returns the toast id (pass to `toast.dismiss(id)`).
396
+ */
397
+ declare const toast: {
398
+ info: (title: ReactNode, options?: ToastOptions) => string | number;
399
+ success: (title: ReactNode, options?: ToastOptions) => string | number;
400
+ warning: (title: ReactNode, options?: ToastOptions) => string | number;
401
+ error: (title: ReactNode, options?: ToastOptions) => string | number;
402
+ /** Dismiss a specific toast by id, or all toasts when called with no id. */
403
+ dismiss: (id?: string | number) => string | number;
404
+ };
405
+ /**
406
+ * Toast provider. Render once at the app root. Defaults to `top-center` (FR /
407
+ * AC-7) and `unstyled` toasts so the shipped `.toast` classes own all visuals;
408
+ * any `ToasterProps` may be overridden (e.g. `visibleToasts`, `expand`). Keep
409
+ * `unstyled` on — overriding it to `false` re-enables Sonner's default card
410
+ * chrome and breaks the token styling.
411
+ */
412
+ declare function Toaster({ position, toastOptions, ...rest }: ToasterProps): react.JSX.Element;
413
+
414
+ /**
415
+ * Callout — inline banner / message surface, painted with the shipped
416
+ * `@qball-inc/tokens` `.callout` classes from the `preview/banner.html` oracle.
417
+ *
418
+ * This is a purely presentational component (no behavioral library): a tinted
419
+ * semantic surface with an accent edge, a leading icon (the redundant non-color
420
+ * cue — finance-color-plus-cue, FR4), an optional title, and a `children` body
421
+ * slot. Every visual comes from the token CSS — `.callout` / `.callout--{warn,
422
+ * error,neutral}` / `.callout__{icon,body,title,msg,x}`; there is no component
423
+ * CSS, no hardcoded color, no box-shadow.
424
+ *
425
+ * Callout is the DESIGNATED HOST for app-level disclaimers (the persistent v1
426
+ * "not financial advice" notice, rate-limit / degraded-data warnings). The
427
+ * `children` slot accepts rich inline content (text, links, inline elements) so
428
+ * a disclaimer can carry a "read more" link. The `neutral` variant is the home
429
+ * for non-urgent informational disclaimers.
430
+ *
431
+ * Variant → shipped class (note the abbreviated `warn`): `info` is the base
432
+ * `.callout` (no modifier), `warning` → `.callout--warn`, `error` →
433
+ * `.callout--error`, `neutral` → `.callout--neutral`.
434
+ */
435
+ type CalloutVariant = "info" | "warning" | "error" | "neutral";
436
+ interface CalloutProps {
437
+ /** Semantic treatment. Default `info` (the base `.callout`). */
438
+ variant?: CalloutVariant;
439
+ /** Optional bold lead line (`.callout__title`). */
440
+ title?: ReactNode;
441
+ /** Body content (`.callout__msg`) — rich inline content allowed (links, etc.). */
442
+ children?: ReactNode;
443
+ /** Render a dismiss (`.callout__x`) button. Default `false` (disclaimers are persistent). */
444
+ dismissible?: boolean;
445
+ /** Fired when the dismiss button is clicked. */
446
+ onDismiss?: () => void;
447
+ /** Accessible label for the dismiss button. Default `"Dismiss"`. */
448
+ dismissLabel?: string;
449
+ /** Render the leading semantic icon. Default `true`. */
450
+ icon?: boolean;
451
+ /** className merged onto the `.callout` root. */
452
+ className?: string;
453
+ }
454
+ declare function Callout({ variant, title, children, dismissible, onDismiss, dismissLabel, icon, className, }: CalloutProps): react.JSX.Element;
455
+
456
+ /**
457
+ * Skeleton — content placeholder, painted with the shipped `@qball-inc/tokens`
458
+ * `.skel` classes from the `preview/loading.html` oracle.
459
+ *
460
+ * A purely presentational shimmer placeholder for content that is still loading.
461
+ * Every visual comes from the token CSS — `.skel` + `.skel--{text,line,title,
462
+ * block,circle}`; there is no component CSS, no hardcoded color, no box-shadow.
463
+ *
464
+ * Reduced-motion is handled by the token CSS, not here: the shipped
465
+ * `@media (prefers-reduced-motion: reduce)` rule stops `.skel` shimmer entirely
466
+ * (falls back to a static `--bg-surface` tint), satisfying FR4/NFR5. The
467
+ * component only applies the class; the conformance is inherited.
468
+ *
469
+ * Skeletons are decorative, so the element is `aria-hidden` — announce the
470
+ * loading state on the surrounding region (e.g. `aria-busy` on the list) rather
471
+ * than on each placeholder. Prefer a skeleton over a {@link Spinner} for content
472
+ * that has a known shape (mirror the real layout so it doesn't jump on load).
473
+ */
474
+ type SkeletonShape = "text" | "line" | "title" | "block" | "circle";
475
+ interface SkeletonProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
476
+ /**
477
+ * Placeholder shape (the shipped `.skel--*` set). Default `line`. The AC's
478
+ * "rect" is `block` (full-height fill); `circle` is for avatars/icons.
479
+ */
480
+ shape?: SkeletonShape;
481
+ /** Convenience width (e.g. `"46%"`, `120`). Merged onto `style`; overrides `style.width`. */
482
+ width?: string | number;
483
+ /** Convenience height (e.g. `32`). Merged onto `style`; overrides `style.height`. */
484
+ height?: string | number;
485
+ }
486
+ declare function Skeleton({ shape, width, height, className, style, ...rest }: SkeletonProps): react.JSX.Element;
487
+
488
+ /**
489
+ * Spinner — the ONE sanctioned loading spinner for the library, painted with the
490
+ * shipped `@qball-inc/tokens` `.spinner` classes from the `preview/loading.html`
491
+ * oracle.
492
+ *
493
+ * There is exactly one spinner concept in `@qball-inc/react`. This component is
494
+ * it; no other component file may introduce an alternative rotating-SVG / loading
495
+ * pattern. The {@link Button} `loading` prop paints the SAME sanctioned loop via
496
+ * the shipped `.btn--loading` class (it does not compose this component), so a
497
+ * loading button needs no `<Spinner>`. For an inline wait next to text, or a
498
+ * spinner alongside button-like content, use `size="sm"` (the `.load-inline`
499
+ * pattern in the oracle). Every visual comes from the token CSS — `.spinner` +
500
+ * `.spinner--{sm,lg}`; there is no component CSS, no hardcoded color.
501
+ *
502
+ * Reduced-motion is handled by the token CSS, not here: the shipped
503
+ * `@media (prefers-reduced-motion: reduce)` rule stops `.spinner` rotation
504
+ * entirely (static ring, no spin), satisfying FR4/NFR5.
505
+ *
506
+ * Use a spinner only for true indeterminate waits (a submit in flight, an SSE
507
+ * reconnect). For content with a known shape, prefer a {@link Skeleton}.
508
+ */
509
+ type SpinnerSize = "sm" | "md" | "lg";
510
+ interface SpinnerProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
511
+ /**
512
+ * Size. Default `md` — the base `.spinner` (18px). `sm` (13px, `.spinner--sm`)
513
+ * is the inline / inside-a-button size; `lg` (28px, `.spinner--lg`) is for
514
+ * full-panel waits. (There is no `--md` modifier — `md` is the base class.)
515
+ */
516
+ size?: SpinnerSize;
517
+ /** Accessible label announced to assistive tech. Default `"Loading"`. */
518
+ label?: string;
519
+ }
520
+ declare function Spinner({ size, label, className, ...rest }: SpinnerProps): react.JSX.Element;
521
+
522
+ /**
523
+ * StateFig — empty- and error-state figures, painted with the shipped
524
+ * `@qball-inc/tokens` `.state-fig` classes from the `preview/states.html` oracle.
525
+ *
526
+ * A centered figure: an icon chip, a headline, an optional supporting line, and
527
+ * an actions row. Every visual comes from the token CSS — `.state-fig` +
528
+ * `.state-fig__{icon,title,msg,actions}` + the `--error` modifier; there is no
529
+ * component CSS, no hardcoded color, no box-shadow.
530
+ *
531
+ * Two named exports share the anatomy:
532
+ * - {@link EmptyStateFig} — the base `.state-fig` (neutral). For "nothing here
533
+ * yet" / "no results". The consumer supplies the CTA via `action`.
534
+ * - {@link ErrorStateFig} — `.state-fig--error` (red icon chip). For a genuine
535
+ * failure. A `retry` callback is MANDATORY and renders the primary Retry CTA;
536
+ * an optional `onDismiss` renders a secondary Dismiss CTA.
537
+ *
538
+ * The icon is a consumer-provided React node (e.g. a `lucide-react` icon) so the
539
+ * figure stays token-only and icon-swappable. There is no default icon. The
540
+ * title renders as a `<p class="state-fig__title">` (consistent with the sibling
541
+ * `Callout`) rather than a fixed heading level, so it never disturbs the
542
+ * consumer's document outline.
543
+ */
544
+ interface StateFigBaseProps {
545
+ /** Icon node rendered in the `.state-fig__icon` chip (e.g. a lucide-react icon). Optional. */
546
+ icon?: ReactNode;
547
+ /** Headline (`.state-fig__title`). */
548
+ title: ReactNode;
549
+ /** Optional supporting line (`.state-fig__msg`). */
550
+ body?: ReactNode;
551
+ /** className merged onto the `.state-fig` root. */
552
+ className?: string;
553
+ }
554
+ interface EmptyStateFigProps extends StateFigBaseProps {
555
+ /** CTA slot rendered in `.state-fig__actions` (e.g. a `<Button>` or a link). Optional. */
556
+ action?: ReactNode;
557
+ }
558
+ interface ErrorStateFigProps extends StateFigBaseProps {
559
+ /** REQUIRED. Fired when the Retry CTA is activated. */
560
+ retry: () => void;
561
+ /** Label for the Retry CTA. Default `"Retry"`. */
562
+ retryLabel?: string;
563
+ /** Optional. When provided, renders a secondary Dismiss CTA. */
564
+ onDismiss?: () => void;
565
+ /** Label for the Dismiss CTA. Default `"Dismiss"`. */
566
+ dismissLabel?: string;
567
+ }
568
+ declare function EmptyStateFig({ icon, title, body, action, className }: EmptyStateFigProps): react.JSX.Element;
569
+ declare function ErrorStateFig({ icon, title, body, retry, retryLabel, onDismiss, dismissLabel, className, }: ErrorStateFigProps): react.JSX.Element;
570
+
571
+ /**
572
+ * Stat — a single metric tile, painted with the shipped `@qball-inc/tokens`
573
+ * `.stat` classes from the `preview/stats-meters.html` oracle.
574
+ *
575
+ * A label, the main figure (Berkeley Mono tabular display font via `.stat__value`),
576
+ * an optional unit, an optional delta with a finance-direction treatment, and
577
+ * optional foot/sparkline slots. Every visual comes from the token CSS — `.stat`
578
+ * + `.stat__{label,row,value,unit,delta,foot,spark}` + the `--up/--down/--flat`
579
+ * delta modifiers; there is no component CSS, no hardcoded color, no box-shadow.
580
+ *
581
+ * Two binding rules from DESIGN.md (FR4):
582
+ * - **Missing value renders '—'.** When `value` is `null` or `undefined` the figure
583
+ * renders '—' (U+2014 EM DASH) — NEVER '0', an empty string, or any other
584
+ * placeholder. A stat with no data must read as "no data", not "zero".
585
+ * - **Finance color is always paired with a non-color cue.** The delta direction
586
+ * drives both the `.stat__delta--{up,down,flat}` color AND a leading ▲/▼/—
587
+ * glyph, so color is never the sole signal (RB-8). Matches the oracle's
588
+ * '▲ +8.4%' / '▼ −4.7%' / '— flat'.
589
+ */
590
+ type StatDirection = "up" | "down" | "flat";
591
+ interface StatProps {
592
+ /** Eyebrow label (`.stat__label`). Optional. */
593
+ label?: ReactNode;
594
+ /**
595
+ * The main figure (`.stat__value`). `null`/`undefined` renders '—' (EM DASH),
596
+ * never '0'. Numbers render as-is; pre-format (thousands separators, etc.) upstream.
597
+ */
598
+ value: number | string | null | undefined;
599
+ /** Optional unit suffix (`.stat__unit`, e.g. '%'). */
600
+ unit?: ReactNode;
601
+ /**
602
+ * Delta direction. Drives the `.stat__delta--*` finance color AND the ▲/▼/—
603
+ * non-color cue (FR4). Omit for a stat with no change indicator.
604
+ */
605
+ direction?: StatDirection;
606
+ /** Delta text shown after the directional cue (e.g. '+8.4%'). Rendered only when `direction` is set. */
607
+ delta?: ReactNode;
608
+ /** Footnote (`.stat__foot`). Optional. */
609
+ foot?: ReactNode;
610
+ /** Inline sparkline slot (`.stat__spark`). Optional (e.g. a future <Sparkline>). */
611
+ spark?: ReactNode;
612
+ /** className merged onto the `.stat` root. */
613
+ className?: string;
614
+ }
615
+ declare function Stat({ label, value, unit, direction, delta, foot, spark, className }: StatProps): react.JSX.Element;
616
+
617
+ /**
618
+ * Meter — a horizontal usage / progress bar, painted with the shipped
619
+ * `@qball-inc/tokens` `.meter` classes from the `preview/stats-meters.html` oracle.
620
+ *
621
+ * A head row (label + readout) over a track/fill bar. Every visual comes from the
622
+ * token CSS — `.meter` + `.meter__{head,label,val,track,fill}` + the `--warn`
623
+ * (gold) / `--over` (red) threshold modifiers; there is no component CSS, no
624
+ * hardcoded color, no box-shadow. The `.meter__track` 999px pill is the sanctioned
625
+ * track carve-out — it lives in `components.css`, not here, so the component never
626
+ * trips the ≤12px radius deny-rule (FR4).
627
+ *
628
+ * `value`/`max` drive the fill width (clamped 0–100%); `variant` selects the
629
+ * threshold treatment. The track carries `role="meter"` + `aria-valuenow/min/max`.
630
+ */
631
+ type MeterVariant = "normal" | "warn" | "over";
632
+ interface MeterProps {
633
+ /** Current value (numerator). */
634
+ value: number;
635
+ /** Maximum (denominator). Default `100`. */
636
+ max?: number;
637
+ /** Eyebrow label (`.meter__label`). Optional. */
638
+ label?: ReactNode;
639
+ /** Readout text (`.meter__val`). Default `"{value} / {max}"`. */
640
+ readout?: ReactNode;
641
+ /** Threshold treatment: `warn` (gold fill) / `over` (red fill). Default `normal` (base `.meter`). */
642
+ variant?: MeterVariant;
643
+ /** Accessible name for the meter when `label` is not a plain string. */
644
+ ariaLabel?: string;
645
+ /** className merged onto the `.meter` root. */
646
+ className?: string;
647
+ }
648
+ declare function Meter({ value, max, label, readout, variant, ariaLabel, className, }: MeterProps): react.JSX.Element;
649
+
650
+ /**
651
+ * Badge — a small status / finance pill, painted with the shipped
652
+ * `@qball-inc/tokens` `.badge` classes (`components.css`) as shown in the
653
+ * `preview/colors-data.html` oracle (and in context in `preview/data-table.html`
654
+ * / the app-chrome previews).
655
+ *
656
+ * NOTE — this is the `.badge` finance/status pill, NOT the editorial `.tag`
657
+ * (`preview/tags.html`, `colors_and_type.css`): those are two distinct shipped
658
+ * components (SD1 finding D-09). Badge targets `.badge`, never `.tag`.
659
+ *
660
+ * Every visual comes from the token CSS — `.badge` + the `--*` variant modifiers
661
+ * + the optional `.badge__dot`; there is no component CSS, no hardcoded color, no
662
+ * box-shadow.
663
+ *
664
+ * Variants split into two families:
665
+ * - **Semantic**: `neutral` (base `.badge`), `info`, `success`, `warning`, `error`.
666
+ * - **Finance**: `up`, `down`, `flat`.
667
+ *
668
+ * Variant → shipped class (note the abbreviated `warn`, mirroring `Callout`):
669
+ * `neutral` is the base `.badge` (no modifier); `warning` → `.badge--warn`;
670
+ * `info`/`up`/`down` map to their existing classes; `success` → `.badge--success`,
671
+ * `error` → `.badge--error`, and `flat` → `.badge--flat` are shipped additions
672
+ * to `components.css` (success = gain green, error = loss red, flat = neutral stone).
673
+ *
674
+ * **Finance variants pair color with a non-color cue (FR4 / RB-8).** `up`/`down`/
675
+ * `flat` render a leading ▲/▼/— glyph so the finance color is never the sole
676
+ * signal. Semantic variants carry their meaning in the label text.
677
+ */
678
+ type BadgeVariant = "neutral" | "info" | "success" | "warning" | "error" | "up" | "down" | "flat";
679
+ interface BadgeProps {
680
+ /** Semantic or finance treatment. Default `neutral` (base `.badge`). */
681
+ variant?: BadgeVariant;
682
+ /** Badge content. */
683
+ children?: ReactNode;
684
+ /** Render a leading status dot (`.badge__dot`). Default `false`. */
685
+ dot?: boolean;
686
+ /** className merged onto the `.badge` root. */
687
+ className?: string;
688
+ }
689
+ declare function Badge({ variant, children, dot, className }: BadgeProps): react.JSX.Element;
690
+
691
+ /**
692
+ * Card — a surface container, painted with the shipped `@qball-inc/tokens`
693
+ * `.card` class (`colors_and_type.css`) from the `preview/card-featured.html`
694
+ * and `preview/borders.html` oracles.
695
+ *
696
+ * The base `.card` is a static content surface: `var(--bg-surface)` background, a
697
+ * 0.5px `var(--border-default)` hairline border (intentional sub-pixel — renders
698
+ * as a hairline on retina; do NOT round up to 1px), `var(--radius-md)` (8px ≤12px)
699
+ * radius, and `var(--space-md)` padding. There is **no box-shadow** anywhere — the
700
+ * lift comes from the border weight + tonal surface step (DESIGN.md No-Shadows).
701
+ *
702
+ * Two optional states (the `.card--interactive` / `.card--selected`
703
+ * additions to `colors_and_type.css`):
704
+ * - `interactive` — a selectable card; the border lifts to sage
705
+ * (`var(--color-signal)`) on hover, with a pointer cursor.
706
+ * - `selected` — applies the selected-surface treatment (sage border + faint sage
707
+ * tint).
708
+ *
709
+ * All other `<div>` attributes (e.g. `onClick`, `role`, `tabIndex`, `aria-*`) pass
710
+ * through, so a consumer can make an interactive card fully keyboard-accessible.
711
+ */
712
+ interface CardProps extends HTMLAttributes<HTMLDivElement> {
713
+ /** Card content. */
714
+ children?: ReactNode;
715
+ /** Selectable card: sage border on hover + pointer cursor. Default `false` (static content card). */
716
+ interactive?: boolean;
717
+ /** Apply the selected-surface treatment (`.card--selected`). Default `false`. */
718
+ selected?: boolean;
719
+ }
720
+ declare function Card({ children, interactive, selected, className, ...rest }: CardProps): react.JSX.Element;
721
+
722
+ /**
723
+ * Divider — a horizontal separator, painted with the shipped `@qball-inc/tokens`
724
+ * `hr, .rule` style (`colors_and_type.css`) from the `preview/borders.html` oracle.
725
+ *
726
+ * Renders a native `<hr>` (implicit `role="separator"`, horizontal orientation)
727
+ * carrying the `.rule` class: a 1px `var(--border-top)` hairline via
728
+ * `var(--border-default)`, no box-shadow, no hardcoded hex (FR4). The `<hr>`
729
+ * element is the correct semantics for a thematic break and is announced as a
730
+ * separator by assistive tech.
731
+ *
732
+ * Horizontal only in v1 (the borders.html oracle ships horizontal dividers); a
733
+ * vertical variant is deferred (no shipped vertical-rule substrate).
734
+ */
735
+ interface DividerProps extends HTMLAttributes<HTMLHRElement> {
736
+ /** className merged onto the `.rule` separator. */
737
+ className?: string;
738
+ }
739
+ declare function Divider({ className, ...rest }: DividerProps): react.JSX.Element;
740
+
741
+ /**
742
+ * Tabs — accessible tabbed section switcher built on Radix `Tabs`, painted with
743
+ * the shipped `@qball-inc/tokens` classes (`.tabs`, `.tab-list`, `.tab`,
744
+ * `.tab-panel`) from the `preview/tabs.html` oracle.
745
+ *
746
+ * Radix supplies the behavior — roving-tabindex keyboard nav (Arrow / Home / End),
747
+ * the `role="tablist" / "tab" / "tabpanel"` wiring, and `aria-selected` on the
748
+ * active trigger — while the visual surface is the token CSS. This is the same
749
+ * "Radix for behavior, shipped classes for style" pattern as `Modal` / `Select`.
750
+ * There is NO component CSS and NO hardcoded color.
751
+ *
752
+ * The active tab's sage label + underline is driven by the shipped
753
+ * `.tab[aria-selected="true"]` rule, so selection MUST be expressed via
754
+ * `aria-selected` — which Radix's `Trigger` does. Keyboard focus uses the
755
+ * library's shared sage `:focus-visible` ring (also shipped in `components.css`).
756
+ *
757
+ * Distinct from `Segmented` (a compact boxed inline toggle): Tabs are an
758
+ * underline list for switching larger content regions.
759
+ *
760
+ * Composition (matches the oracle):
761
+ * <Tabs defaultValue="overview">
762
+ * <TabsList aria-label="Position detail">
763
+ * <TabsTrigger value="overview">Overview</TabsTrigger>
764
+ * <TabsTrigger value="holdings">Holdings</TabsTrigger>
765
+ * </TabsList>
766
+ * <TabsContent value="overview">…</TabsContent>
767
+ * <TabsContent value="holdings">…</TabsContent>
768
+ * </Tabs>
769
+ */
770
+ type TabsProps = ComponentPropsWithoutRef<typeof TabsPrimitive.Root>;
771
+ type TabsListProps = ComponentPropsWithoutRef<typeof TabsPrimitive.List>;
772
+ type TabsTriggerProps = ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>;
773
+ type TabsContentProps = ComponentPropsWithoutRef<typeof TabsPrimitive.Content>;
774
+ /** Tabs root — owns the active-tab state (`value` / `defaultValue` / `onValueChange`). */
775
+ declare const Tabs: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
776
+ /** The `role="tablist"` row of triggers (`.tab-list`). */
777
+ declare const TabsList: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
778
+ /**
779
+ * A single tab trigger (`.tab`). The active trigger shows the sage label +
780
+ * underline via `.tab[aria-selected="true"]`; `disabled` dims it.
781
+ */
782
+ declare const TabsTrigger: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
783
+ /** The panel shown for the active tab (`.tab-panel`). */
784
+ declare const TabsContent: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
785
+
786
+ /**
787
+ * Sparkline — a tiny inline trend chart, drawn as a pure hand-authored SVG
788
+ * `<polyline>` over the shipped `@qball-inc/tokens` `.sparkline` wrapper, matching
789
+ * the `preview/stats-meters.html` oracle (and the in-context sparks in the
790
+ * app-chrome previews).
791
+ *
792
+ * **No chart library (BINDING).** The geometry is computed inline (min/max
793
+ * normalization to a viewport + linear interpolation between points). Recharts,
794
+ * D3, Victory, Chart.js, etc. are NOT imported — and although `d3` is an optional
795
+ * peerDependency of `@qball-inc/react` (for the Candlestick), the
796
+ * Sparkline must NOT pull it in: it is a lightweight atom.
797
+ *
798
+ * **Color comes from `direction`, never from the data (BINDING, FR4 / RB-8).** The
799
+ * stroke color is applied via the shipped `.trend-{up,down,flat}` helper class
800
+ * (which sets `color: var(--data-{up,down,flat})`) with `stroke="currentColor"`,
801
+ * so there is no hardcoded hex and no inline color. The `direction` prop is the
802
+ * single source of truth — the color is deliberately NOT computed from `data[0]`
803
+ * vs `data[last]`, which could contradict an explicit prop on stale/out-of-order
804
+ * data. `direction` IS the directional cue the finance-color-plus-cue rule
805
+ * requires (a parent embedding the spark should still pair it with a label/arrow).
806
+ *
807
+ * **Degenerate data renders safely.** Empty data, a single point, or an
808
+ * all-identical (genuinely flat) series cannot form a trend line, so the geometry
809
+ * collapses to a horizontal line at the vertical midpoint — a valid SVG, never a
810
+ * throw. The color still follows `direction` (pass `direction="flat"` for a flat
811
+ * series). There is no `box-shadow` anywhere (FR4).
812
+ */
813
+ type SparklineDirection = "up" | "down" | "flat";
814
+ interface SparklineProps {
815
+ /** The series to plot. Empty / single-point / all-identical renders a flat midline. */
816
+ data: number[];
817
+ /**
818
+ * Trend direction — the SOLE source of the stroke color (`.trend-{up,down,flat}`
819
+ * → `var(--data-{up,down,flat})`). Never computed from `data` (BINDING FR4).
820
+ */
821
+ direction: SparklineDirection;
822
+ /** Accessible name for the `role="img"` SVG (required — an unlabeled graphic is an a11y violation). */
823
+ ariaLabel: string;
824
+ /** Optional caption shown under the spark (`.sparkline__cap`, e.g. "NVDA · 30d"). */
825
+ caption?: ReactNode;
826
+ /** SVG viewport width in user units. Default 64 (a compact inline size; override for a larger context — the oracle uses 90–150). */
827
+ width?: number;
828
+ /** SVG viewport height in user units. Default 20 (override to ~30 for the oracle's standalone spark). */
829
+ height?: number;
830
+ /** className merged onto the `.sparkline` wrapper. */
831
+ className?: string;
832
+ }
833
+ declare function Sparkline({ data, direction, ariaLabel, caption, width, height, className, }: SparklineProps): react.JSX.Element;
834
+
835
+ /**
836
+ * Tooltip — a hover/focus hint built on Radix `@radix-ui/react-tooltip`, painted
837
+ * with the shipped `@qball-inc/tokens` inverted-bubble visual from the
838
+ * `preview/tooltip-avatar.html` oracle. Same "Radix for behavior, shipped classes
839
+ * for style" pattern as `Modal` / `Select`.
840
+ *
841
+ * **Portaled to `<body>` (BINDING, RB-5).** `TooltipContent` renders inside a Radix
842
+ * `Portal`, so the bubble escapes any transformed / `backdrop-filter` ancestor —
843
+ * notably the floating `.dock`, which uses `transform: translateX(-50%)` and would
844
+ * otherwise clip or mis-place a parent-anchored tooltip. This is the same
845
+ * portal-to-body guarantee applied to `GroundingFlag`.
846
+ *
847
+ * **Why `.tip-pop`, not `.tip__pop`.** The shipped `.tip__pop` is a parent-anchored
848
+ * pure-CSS hover popover (`position:absolute` relative to `.tip`), which cannot be
849
+ * positioned once the node is portaled to `<body>` — Radix's popper owns placement.
850
+ * So the content carries the position-agnostic `.tip-pop` token class (an
851
+ * owner-approved additive variant): the SAME inverted-bubble look (`background: var(--text-primary)`,
852
+ * `radius-sm`, caret) MINUS the positioning. The lift is the brand no-shadow
853
+ * treatment — there is NO `box-shadow` (FR4). The caret is Radix's `Arrow`,
854
+ * token-filled via `.tip-pop__arrow`.
855
+ *
856
+ * Composition (wrap the tree once in `TooltipProvider`):
857
+ * <TooltipProvider>
858
+ * <Tooltip>
859
+ * <TooltipTrigger asChild><button>…</button></TooltipTrigger>
860
+ * <TooltipContent>Delayed ~15 min on the hobby tier.</TooltipContent>
861
+ * </Tooltip>
862
+ * </TooltipProvider>
863
+ */
864
+ /** Wraps the tree (typically once at app root); owns the shared `delayDuration`. Alias of Radix `Tooltip.Provider`. */
865
+ declare const TooltipProvider: react.FC<TooltipPrimitive.TooltipProviderProps>;
866
+ /** A single tooltip; owns its open state. Alias of Radix `Tooltip.Root`. */
867
+ declare const Tooltip: react.FC<TooltipPrimitive.TooltipProps>;
868
+ /** The element the tooltip describes; wrap a custom element with `asChild`. Alias of Radix `Tooltip.Trigger`. */
869
+ declare const TooltipTrigger: react.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & react.RefAttributes<HTMLButtonElement>>;
870
+ type TooltipContentProps = ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>;
871
+ /**
872
+ * The portaled tooltip bubble (`.tip-pop`) + caret (`.tip-pop__arrow`). Defaults
873
+ * `sideOffset` to 8 (matching the shipped `.tip__pop` gap). Placement, flip, and
874
+ * collision handling are Radix's; the visual is the shipped token CSS.
875
+ */
876
+ declare const TooltipContent: react.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
877
+
878
+ /**
879
+ * Avatar — a user/entity glyph, painted with the shipped `@qball-inc/tokens`
880
+ * `.avatar` family from the `preview/tooltip-avatar.html` oracle. Two display
881
+ * modes: an `<img>` (with graceful fallback to initials when it fails to load),
882
+ * or token-tiled initials derived from `name`. Every visual comes from the token
883
+ * CSS / token-valued custom properties — no hardcoded hex, no `box-shadow`.
884
+ *
885
+ * - **Size**: `sm` (`.avatar--sm`), `md` (the base `.avatar`, no modifier), `lg`
886
+ * (`.avatar--lg`), `xl` (`.avatar--xl`). md = base mirrors the Spinner size model.
887
+ * - **Initials color is deterministic**: the same `name` always maps to the same
888
+ * token-backed tile (a `charCodeAt`-sum hash into a small palette of `var(--*)`
889
+ * background/foreground pairs). No hardcoded color.
890
+ * - **Status dot** (`online`/`offline`/`busy`/`away`): a presence indicator, NOT a
891
+ * finance signal — so the dot shape itself is the cue and no paired arrow is
892
+ * required (this carve-out is intentional, distinct from the finance-color-plus-
893
+ * cue rule). `online` is the base `.avatar__status` (gain green); the other three
894
+ * map to `--data-flat` / `--data-down` / `--data-warn`. Omitted ⇒ no dot.
895
+ */
896
+ type AvatarSize = "sm" | "md" | "lg" | "xl";
897
+ type AvatarStatus = "online" | "offline" | "busy" | "away";
898
+ interface AvatarProps {
899
+ /** Image source. When set (and the image loads), renders an `<img>`; otherwise falls back to initials. */
900
+ src?: string;
901
+ /** Alt text for the image. Falls back to `name` then empty (decorative). */
902
+ alt?: string;
903
+ /** Display name — drives the initials AND the deterministic tile color; also the image-fallback content. */
904
+ name?: string;
905
+ /** Size variant. Default `md` (the base `.avatar`). */
906
+ size?: AvatarSize;
907
+ /** Presence status dot. Omitted ⇒ no dot. */
908
+ status?: AvatarStatus;
909
+ /** Round (circular) avatar (`.avatar--round`). Default `false` (squared, `--radius-sm`). */
910
+ round?: boolean;
911
+ /** className merged onto the `.avatar` root. */
912
+ className?: string;
913
+ }
914
+ declare function Avatar({ src, alt, name, size, status, round, className, }: AvatarProps): react.JSX.Element;
915
+ interface AvatarGroupProps {
916
+ /** The `Avatar` instances to stack. */
917
+ children: ReactNode;
918
+ /** Cap the visible avatars; the remainder collapse into a `+N` overflow tile. */
919
+ max?: number;
920
+ /** Round the overflow tile to match round group members. Default `false`. */
921
+ round?: boolean;
922
+ /** className merged onto the `.avatar-group` root. */
923
+ className?: string;
924
+ }
925
+ /**
926
+ * AvatarGroup — overlapping stack of `Avatar`s (`.avatar-group`, negative-margin
927
+ * overlap from the token CSS). With `max`, the overflow collapses into a single
928
+ * token-tinted `+N` tile (info blue, matching the oracle).
929
+ */
930
+ declare function AvatarGroup({ children, max, round, className }: AvatarGroupProps): react.JSX.Element;
931
+
932
+ /**
933
+ * DataTable — a compact, finance-aware data table, painted with the shipped
934
+ * `@qball-inc/tokens` `.dt` classes from the `preview/data-table.html` oracle and
935
+ * built on **TanStack Table** (`@tanstack/react-table`) as the headless core.
936
+ *
937
+ * The visual surface is entirely the token CSS — `.dt` + `.dt thead th`,
938
+ * `.dt td.num`, `.dt .up/.down/.flat`, the `:hover` tint, the `[aria-selected]`
939
+ * sage selection, and `.dt__remove` actions — so there is no component CSS, no
940
+ * hardcoded color, no box-shadow. The component only wires the headless row model
941
+ * to that surface and composes the state figures.
942
+ *
943
+ * Headless-only for v1: it renders the core row model (no built-in sorting or
944
+ * filtering UI — the oracle shows none). Consumers drive sorting/selection via
945
+ * TanStack's APIs through the pass-through props.
946
+ *
947
+ * Three binding rules from DESIGN.md (FR4) carried by this surface:
948
+ * - **Finance color is always paired with a non-color cue.** A column marked
949
+ * `meta.finance` renders the `.num .up/.down/.flat` color AND a leading `+`/`−`
950
+ * sign (mirroring the oracle's `+1.24%` / `−2.34%`), so color is never the sole
951
+ * signal (RB-8). The cue is the sign, not an arrow — matching `data-table.html`.
952
+ * - **One Skeleton, one StateFig.** Loading composes {@link Skeleton}; empty/error
953
+ * compose {@link EmptyStateFig} / {@link ErrorStateFig} — never re-implemented.
954
+ * - **Reduced-motion is inherited**, not overridden: the only animation is the
955
+ * Skeleton shimmer, whose `prefers-reduced-motion` rule lives in the token CSS.
956
+ */
957
+ declare module "@tanstack/react-table" {
958
+ interface ColumnMeta<TData extends RowData, TValue> {
959
+ /** Right-aligned tabular `.num` cell (display font + tabular-nums). */
960
+ numeric?: boolean;
961
+ /**
962
+ * Directional finance cell: pairs the `--data-up/down/flat` color (`.up/.down/.flat`)
963
+ * with a leading `+`/`−` sign cue (FR4). Implies {@link numeric}. The column's
964
+ * accessor value MUST be a number; non-numbers fall back to the default cell.
965
+ */
966
+ finance?: boolean;
967
+ /**
968
+ * Formats a finance cell's number into its display string. The result must keep
969
+ * the directional sign as the non-color cue. Default: signed 2-decimal percent
970
+ * (`+1.24%` / `−2.34%`), matching the oracle's `sign()`.
971
+ */
972
+ financeFormat?: (value: number) => string;
973
+ /**
974
+ * Mobile card-list label. At <=640px (container width) the table
975
+ * reflows to stacked cards and each cell surfaces its column header inline via
976
+ * `td::before { content: attr(data-label) }`. CSS cannot read thead text, so the
977
+ * label is sourced from a `data-label` attribute the component sets: the column's
978
+ * `header` when it is a plain string, else this `meta.label`. A column with a
979
+ * non-string (ReactNode) header and NO `meta.label` renders an empty mobile label.
980
+ */
981
+ label?: string;
982
+ }
983
+ }
984
+ /** Public alias for a DataTable column's `meta` shape (the augmented ColumnMeta). */
985
+ type DataTableColumnMeta = ColumnMeta<unknown, unknown>;
986
+ interface DataTableProps<TData> {
987
+ /** TanStack column definitions. Mark numeric/finance columns via `meta`. */
988
+ columns: ColumnDef<TData, unknown>[];
989
+ /** Row data. An empty array (with `loading=false`, no `error`) renders the empty figure. */
990
+ data: TData[];
991
+ /** When true, the header renders but each body cell shows a {@link Skeleton}. Wins over error/empty. */
992
+ loading?: boolean;
993
+ /** Number of skeleton rows rendered while `loading`. Default `4`. */
994
+ skeletonRowCount?: number;
995
+ /** When set (and `loading=false`), renders {@link ErrorStateFig} in the body. */
996
+ error?: string | Error;
997
+ /** Title for the error figure. Default `"Couldn't load data"`. */
998
+ errorTitle?: ReactNode;
999
+ /**
1000
+ * Wired to the error figure's Retry CTA. If omitted, the Retry button still
1001
+ * renders but does nothing — provide it whenever an `error` is possible.
1002
+ */
1003
+ onRetry?: () => void;
1004
+ /** Headline for the empty figure (overrides the default). */
1005
+ emptyMessage?: ReactNode;
1006
+ /**
1007
+ * Optional trailing actions cell per row (e.g. a `.dt__remove` button),
1008
+ * right-aligned. Adds a synthetic column with the reserved id `__actions` — do
1009
+ * not define a column with that id.
1010
+ */
1011
+ actions?: (row: TData) => ReactNode;
1012
+ /** Pin the hover-reveal actions visible (default: reveal on row hover). */
1013
+ actionsAlwaysVisible?: boolean;
1014
+ /** Enable TanStack row selection; selected rows get `aria-selected="true"` (sage tint). */
1015
+ enableRowSelection?: boolean | ((row: Row<TData>) => boolean);
1016
+ /**
1017
+ * Controlled row-selection state. For controlled mode pass BOTH `rowSelection`
1018
+ * AND `onRowSelectionChange`; passing only one freezes selection (TanStack's
1019
+ * controlled-state contract). Omit both to let TanStack manage selection
1020
+ * internally (uncontrolled).
1021
+ */
1022
+ rowSelection?: RowSelectionState;
1023
+ /** Controlled row-selection change handler. Pair with `rowSelection`. */
1024
+ onRowSelectionChange?: OnChangeFn<RowSelectionState>;
1025
+ /** Stable row id (TanStack `getRowId`). Defaults to the row index. */
1026
+ getRowId?: (originalRow: TData, index: number) => string;
1027
+ /** className merged onto the `.dt` table root. */
1028
+ className?: string;
1029
+ }
1030
+ declare function DataTable<TData>({ columns, data, loading, skeletonRowCount, error, errorTitle, onRetry, emptyMessage, actions, actionsAlwaysVisible, enableRowSelection, rowSelection, onRowSelectionChange, getRowId, className, }: DataTableProps<TData>): react.JSX.Element;
1031
+
1032
+ /**
1033
+ * Candlestick — a finance OHLC candlestick chart drawn with **D3** as a React
1034
+ * "island", matching the `preview/chart-candlestick-color.html` (color) and
1035
+ * `preview/chart-candlestick-chrome.html` (compact vs. detail chrome) oracles.
1036
+ *
1037
+ * **D3 owns the SVG subtree; React never reconciles its children (BINDING, RB-4).**
1038
+ * All drawing happens inside a single `useEffect` keyed on
1039
+ * `[data, range, theme, width, height, interactive, showGrid, showAxis]`. The
1040
+ * effect's cleanup nulls every registered listener (`.on(type, null)`),
1041
+ * interrupts any running transition, and clears the SVG (`selectAll('*').remove()`)
1042
+ * so no D3 selection, event handler, or timer survives an unmount or a re-key —
1043
+ * the no-leaked-listeners obligation. The only React-owned node is the HTML OHLC
1044
+ * tooltip rendered OUTSIDE the `<svg>`.
1045
+ *
1046
+ * **No charting library but D3 (BINDING).** Recharts/Victory/Chart.js are NOT
1047
+ * imported. `d3` is an OPTIONAL peerDependency of `@qball-inc/react` (it is large,
1048
+ * ~580 KB, and consumers that already ship D3 must not double-bundle it). A
1049
+ * consumer that renders `Candlestick` must install `d3` themselves; the optional
1050
+ * meta only suppresses the install warning — it does not make the chart work
1051
+ * without D3.
1052
+ *
1053
+ * **Color comes from tokens, never hardcoded hex (BINDING, FR4 / RB-8).** Up
1054
+ * candles (close ≥ open) carry the shipped `.trend-up` class, down candles
1055
+ * `.trend-down` (both set `color: var(--data-{up,down})`); the wick + body draw
1056
+ * with `currentColor`, so the candle color is the token, theme-aware via the
1057
+ * ambient `[data-theme]` cascade — exactly the Sparkline mechanism. Axes, grid,
1058
+ * crosshair, and the SVG frame are styled inline with `var(--token)` references
1059
+ * (`--text-muted`, `--border-default`, `--bg-surface`, …), so there is no
1060
+ * hardcoded color anywhere and no component CSS is added to `@qball-inc/tokens`.
1061
+ *
1062
+ * **Color is never the sole finance signal (FR4).** The OHLC tooltip pairs the
1063
+ * up/down color with a directional `▲`/`▼` arrow and a signed change value, so the
1064
+ * direction reads without relying on color perception.
1065
+ *
1066
+ * **Controlled `range`; `theme` is a redraw signal.** `range` is a controlled prop
1067
+ * — the range toggle calls `onRangeChange(next)` and the parent re-passes `range`
1068
+ * (the component never mutates a passed `range`). The `theme` prop does not carry
1069
+ * the palette (the tokens do, via `[data-theme]`); it is a dependency of the draw
1070
+ * effect so a host theme flip re-keys the redraw (AC-6/AC-8) and no stale
1071
+ * JS-derived value survives.
1072
+ *
1073
+ * **Degenerate data renders safely.** Empty or single-point data draws an empty,
1074
+ * valid `<svg>` (axes/candles are skipped) rather than throwing.
1075
+ */
1076
+ /** A discrete time range the chart can be toggled between. */
1077
+ type CandlestickRange = "1D" | "5D" | "1M" | "3M" | "1Y";
1078
+ /** One OHLCV bar. Price fields are in the instrument's quote currency. */
1079
+ interface CandlestickDatum {
1080
+ /** Bar timestamp — a `Date` or any `Date`-parseable string (e.g. ISO 8601). */
1081
+ date: Date | string;
1082
+ /** Opening price. @unit quote currency (e.g. USD) */
1083
+ open: number;
1084
+ /** Session high. @unit quote currency (e.g. USD) */
1085
+ high: number;
1086
+ /** Session low. @unit quote currency (e.g. USD) */
1087
+ low: number;
1088
+ /** Closing price. @unit quote currency (e.g. USD) */
1089
+ close: number;
1090
+ /** Traded volume (optional; not plotted in v1). @unit shares */
1091
+ volume?: number;
1092
+ }
1093
+ interface CandlestickProps {
1094
+ /** The OHLC series, oldest-first. Empty / single-point renders a safe empty chart. */
1095
+ data: CandlestickDatum[];
1096
+ /** The selected range (controlled). The toggle calls `onRangeChange`; the parent re-passes this. */
1097
+ range?: CandlestickRange;
1098
+ /** Which range toggles to render. Default: all five. Pass `[]` to hide the toggle row. */
1099
+ ranges?: CandlestickRange[];
1100
+ /** Called when a range toggle is pressed, with the selected range. */
1101
+ onRangeChange?: (range: CandlestickRange) => void;
1102
+ /**
1103
+ * Redraw signal. The tokens own the palette (via `[data-theme]`); this prop is a
1104
+ * draw-effect dependency so a host theme flip re-keys the redraw. Optional.
1105
+ */
1106
+ theme?: "light" | "dark";
1107
+ /** Explicit SVG viewport width (user units). Omit to fill the container via `ResizeObserver`. */
1108
+ width?: number;
1109
+ /** SVG viewport height (user units). Default 300. */
1110
+ height?: number;
1111
+ /** Crosshair + OHLC tooltip on pointer. Default `true`. `false` = the compact, static card view. */
1112
+ interactive?: boolean;
1113
+ /** Draw the dashed horizontal grid. Default: follows `interactive`. */
1114
+ showGrid?: boolean;
1115
+ /** Draw the price + date axes. Default `true`. `false` = bare candles (inline preview). */
1116
+ showAxis?: boolean;
1117
+ /** Accessible name for the chart's `role="img"` SVG. Default `"Candlestick chart"`. */
1118
+ ariaLabel?: string;
1119
+ /** Called after every (re)draw completes — useful for redraw assertions / screenshot timing. */
1120
+ onDraw?: () => void;
1121
+ /** className merged onto the `.candlestick` figure wrapper. */
1122
+ className?: string;
1123
+ }
1124
+ declare function Candlestick({ data, range, ranges, onRangeChange, theme, width: widthProp, height: heightProp, interactive, showGrid, showAxis, ariaLabel, onDraw, className, }: CandlestickProps): react.JSX.Element;
1125
+
1126
+ /**
1127
+ * AppBar — the application top bar.
1128
+ *
1129
+ * Painted with the shipped `@qball-inc/tokens` classes `.appbar` / `.appbar__brand` /
1130
+ * `.appnav` / `.appbar__spacer` / `.appbar__right` (matching the
1131
+ * `preview/app-chrome-traditional.html` oracle). All content is injected via slots
1132
+ * (`brand`, `nav`, `actions`) — no hardcoded brand assets or nav items.
1133
+ *
1134
+ * Hybrid chrome (owner decision, S83) — defaults to a plain in-flow bar; opts into the
1135
+ * Stocky prototype's glass-floating + hide-on-scroll behavior:
1136
+ * - `floating` — glass overlay (position:absolute top:0, z-index, backdrop-filter
1137
+ * blur + translucent bg, transition). Mirrors
1138
+ * docs/stocky-app/prototype/dashboard.css `.appbar`. The host shell
1139
+ * should be `position: relative; overflow: hidden`. The shipped
1140
+ * `.appbar` bottom hairline persists in float mode (the prototype
1141
+ * keeps it too).
1142
+ * - `hidden` — applies the hide transform (`translateY(-130%)` + fade). Use with
1143
+ * `floating`. Drives the same `.appbar--hidden` look as the prototype.
1144
+ * - `hideOnScroll` — opt-in self-managed behavior reproducing the prototype: hide WHILE
1145
+ * scrolling (either direction), spring back 220ms after scroll STOPS.
1146
+ * Implies `floating`. `scrollContainer` selects the scroll source
1147
+ * (default `window`; the prototype scrolls an inner `.main` pane).
1148
+ * The listener is cleaned up on unmount (no leak).
1149
+ *
1150
+ * Glass + hide styles are applied as inline structural styles (no hex, no box-shadow) —
1151
+ * DESIGN_DENY clean; `backdrop-filter` here is the sanctioned chrome-glass use.
1152
+ */
1153
+ interface NotificationBellProps extends ComponentPropsWithoutRef<"button"> {
1154
+ /**
1155
+ * Unread count. Renders the `.badge-count` overlay when `>= 1`; omits it when `0` or
1156
+ * `undefined`. The live value is produced by NotificationCenter; this is the
1157
+ * passive data surface.
1158
+ */
1159
+ unreadCount?: number;
1160
+ /** Custom bell icon node; defaults to the shipped outline bell SVG. */
1161
+ children?: ReactNode;
1162
+ }
1163
+ /**
1164
+ * The bell icon button + unread-count badge, for the AppBar `actions` cluster. A `.iconbtn`
1165
+ * hosting the bell SVG; the `unreadCount` prop drives the overlaid `.badge-count` span.
1166
+ */
1167
+ declare const NotificationBell: react.ForwardRefExoticComponent<NotificationBellProps & react.RefAttributes<HTMLButtonElement>>;
1168
+ interface AppBarProps extends Omit<ComponentPropsWithoutRef<"header">, "hidden"> {
1169
+ /** Brand slot (logo / wordmark) — rendered in `.appbar__brand`. */
1170
+ brand?: ReactNode;
1171
+ /** Primary navigation slot — wrapped in `<nav className="appnav">`. */
1172
+ nav?: ReactNode;
1173
+ /** Right-cluster slot (search, NotificationBell, ThemeToggle, UserMenu) — `.appbar__right`. */
1174
+ actions?: ReactNode;
1175
+ /** Render as a glass floating overlay (position:absolute, z-index, backdrop blur). */
1176
+ floating?: boolean;
1177
+ /** Apply the hide transform (`translateY(-130%)` + fade). Use with `floating`. */
1178
+ hidden?: boolean;
1179
+ /** Self-manage hide-while-scrolling + 220ms spring-back (implies `floating`). */
1180
+ hideOnScroll?: boolean;
1181
+ /** Scroll source for `hideOnScroll`. Default `window`. */
1182
+ scrollContainer?: HTMLElement | Window | null;
1183
+ }
1184
+ declare const AppBar: react.ForwardRefExoticComponent<AppBarProps & react.RefAttributes<HTMLElement>>;
1185
+
1186
+ /**
1187
+ * UserMenu — the app-bar user action menu, built on Radix `DropdownMenu`.
1188
+ *
1189
+ * Radix supplies the behavior (keyboard navigation — Arrow Up/Down cycle items,
1190
+ * Enter activates, Escape closes, focus returns to the trigger — plus the portalled
1191
+ * panel and focus management) while the visual surface is the shipped `@qball-inc/tokens`
1192
+ * classes: the trigger applies `.usermenu` (whose hover/open tint keys on the
1193
+ * `aria-expanded` Radix sets), and the panel + parts apply `.dropdown` / `.dropdown__head`
1194
+ * / `.dropdown__sec` / `.dropdown__row` / `.dropdown__rule` — matching the
1195
+ * `preview/app-chrome-traditional.html` oracle. Same "Radix for behavior, shipped classes
1196
+ * for style" pattern as Select. No component CSS, no hex.
1197
+ *
1198
+ * The dropdown lift is the brand's no-shadow treatment: the shipped `.dropdown` is a
1199
+ * heavier `1px solid var(--border-strong)` panel — there is NO `box-shadow` (FR4 / RB-8).
1200
+ *
1201
+ * Composition (matches the oracle):
1202
+ * <UserMenu>
1203
+ * <UserMenuTrigger><span className="wm"><span className="avatar">AK</span> Ashay</span></UserMenuTrigger>
1204
+ * <UserMenuContent>
1205
+ * <UserMenuHeader avatar={<span className="avatar avatar--lg">AK</span>} name="Ashay Kubal" email="ashay@…" />
1206
+ * <UserMenuGroup>
1207
+ * <UserMenuItem icon={<SettingsIcon />} onSelect={…}>Settings</UserMenuItem>
1208
+ * <UserMenuItem icon={<KeyIcon />} onSelect={…}>API key</UserMenuItem>
1209
+ * </UserMenuGroup>
1210
+ * <UserMenuSeparator />
1211
+ * <UserMenuGroup>
1212
+ * <UserMenuItem danger icon={<SignOutIcon />} onSelect={…}>Sign out</UserMenuItem>
1213
+ * </UserMenuGroup>
1214
+ * </UserMenuContent>
1215
+ * </UserMenu>
1216
+ */
1217
+ /** Menu root — owns the open state. Thin alias of Radix `DropdownMenu.Root`. */
1218
+ declare const UserMenu: react.FC<DropdownMenu.DropdownMenuProps>;
1219
+ interface UserMenuTriggerProps extends ComponentPropsWithoutRef<typeof DropdownMenu.Trigger> {
1220
+ /** Use a custom element as the trigger (no extra `.usermenu` wrapper DOM). */
1221
+ asChild?: boolean;
1222
+ }
1223
+ /**
1224
+ * The menu trigger. By default renders a `.usermenu` button hosting the avatar/name
1225
+ * slot; pass `asChild` to make a custom element the trigger instead.
1226
+ */
1227
+ declare const UserMenuTrigger: react.ForwardRefExoticComponent<UserMenuTriggerProps & react.RefAttributes<HTMLButtonElement>>;
1228
+ interface UserMenuContentProps extends ComponentPropsWithoutRef<typeof DropdownMenu.Content> {
1229
+ /** Distance from the trigger, in px. Default `6`. */
1230
+ sideOffset?: number;
1231
+ }
1232
+ /** The portalled `.dropdown` panel. Defaults to right-aligned under the trigger. */
1233
+ declare const UserMenuContent: react.ForwardRefExoticComponent<UserMenuContentProps & react.RefAttributes<HTMLDivElement>>;
1234
+ interface UserMenuHeaderProps {
1235
+ /** Avatar node (e.g. `<span className="avatar avatar--lg">AK</span>`). */
1236
+ avatar?: ReactNode;
1237
+ /** Display name. */
1238
+ name: ReactNode;
1239
+ /** Secondary line, typically the email. */
1240
+ email?: ReactNode;
1241
+ }
1242
+ /**
1243
+ * Non-interactive identity header (`.dropdown__head`). Radix `Label` (skipped by nav).
1244
+ * Render as a DIRECT child of `UserMenuContent` — NOT inside a `UserMenuGroup` — matching
1245
+ * the oracle's `.dropdown__head` placement at the top of the `.dropdown` panel.
1246
+ */
1247
+ declare function UserMenuHeader({ avatar, name, email }: UserMenuHeaderProps): react.JSX.Element;
1248
+ type UserMenuGroupProps = ComponentPropsWithoutRef<typeof DropdownMenu.Group>;
1249
+ /** A padded item group (`.dropdown__sec`). Wrap rows so they inset off the panel edge. */
1250
+ declare const UserMenuGroup: react.ForwardRefExoticComponent<Omit<DropdownMenu.DropdownMenuGroupProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1251
+ interface UserMenuItemProps extends ComponentPropsWithoutRef<typeof DropdownMenu.Item> {
1252
+ /** Tint the row as destructive (`.dropdown__row--danger`, e.g. Sign out). */
1253
+ danger?: boolean;
1254
+ /** Leading icon node (rendered before the label). */
1255
+ icon?: ReactNode;
1256
+ }
1257
+ /** A menu row (`.dropdown__row`). Enter / click fire `onSelect`; Radix handles focus. */
1258
+ declare const UserMenuItem: react.ForwardRefExoticComponent<UserMenuItemProps & react.RefAttributes<HTMLDivElement>>;
1259
+ type UserMenuSeparatorProps = ComponentPropsWithoutRef<typeof DropdownMenu.Separator>;
1260
+ /** A hairline divider between groups (`.dropdown__rule`). */
1261
+ declare const UserMenuSeparator: react.ForwardRefExoticComponent<Omit<DropdownMenu.DropdownMenuSeparatorProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1262
+
1263
+ /**
1264
+ * ThemeToggle — the single global light/dark switch.
1265
+ *
1266
+ * Painted with the shipped `@qball-inc/tokens` classes `.iconbtn` + `.theme-toggle`
1267
+ * (matching the `preview/app-chrome-traditional.html` oracle). BOTH the sun and the
1268
+ * moon are inline SVG icons wrapped in `.ic-sun` / `.ic-moon`; the shipped CSS swaps
1269
+ * which one shows based on `html[data-theme]` (components.css:637-640) — so there is
1270
+ * no icon library dependency and no React state needed for the icon swap.
1271
+ *
1272
+ * BINDING global-theme contract: a click flips `data-theme` on `document.documentElement`
1273
+ * (`<html>`) — never a subtree element, a React context, or a CSS class. The `data-theme`
1274
+ * attribute on `<html>` is the mechanism every preview card + the gallery use for theming
1275
+ * (gallery.html:155). The current theme is read from the same attribute, defaulting to
1276
+ * `"light"` when absent.
1277
+ *
1278
+ * Inline SVG only — no hardcoded color (the icons stroke with `currentColor`), no
1279
+ * `box-shadow`. DESIGN_DENY (RB-8 layer (a)) clean.
1280
+ */
1281
+ type Theme = "light" | "dark";
1282
+ interface ThemeToggleProps extends Omit<ComponentPropsWithoutRef<"button">, "onChange"> {
1283
+ /** Fired with the new theme AFTER the toggle writes `data-theme` to `<html>`. */
1284
+ onThemeChange?: (theme: Theme) => void;
1285
+ }
1286
+ declare const ThemeToggle: react.ForwardRefExoticComponent<ThemeToggleProps & react.RefAttributes<HTMLButtonElement>>;
1287
+
1288
+ /**
1289
+ * Scrim — the canonical library-wide scroll-lock primitive + dim backdrop.
1290
+ *
1291
+ * Painted with the shipped `.scrim` class (components.css:273-277): a full-viewport
1292
+ * `position: fixed; inset: 0` layer dimmed with `var(--color-scrim)`. The shipped
1293
+ * `.scrim` is DELIBERATELY flat — no `backdrop-filter` blur (the brand dims with a
1294
+ * flat tone), so this is a pure className wrapper with no inline color and no shadow.
1295
+ *
1296
+ * Scrim OWNS scroll-lock: while `open` is true it sets `document.body` `overflow:hidden`,
1297
+ * capturing the prior value, and restores that exact prior value when `open` becomes
1298
+ * false OR when the component unmounts (no leaked lock).
1299
+ *
1300
+ * NOTE: Radix overlays (Modal/Dialog) keep their OWN robust scroll-lock
1301
+ * (react-remove-scroll). This Scrim is the scroll-lock owner for NON-Radix / custom
1302
+ * overlays; the Modal's overlay already shares this same `.scrim` class for the visual
1303
+ * backdrop.
1304
+ */
1305
+ interface ScrimProps extends ComponentPropsWithoutRef<"div"> {
1306
+ /** When true, render the dim backdrop AND lock `document.body` scroll. */
1307
+ open: boolean;
1308
+ }
1309
+ declare const Scrim: react.ForwardRefExoticComponent<ScrimProps & react.RefAttributes<HTMLDivElement>>;
1310
+
1311
+ /** A discrete command surfaced in the dock's Search popover (and reused for Add suggestions). */
1312
+ interface CommandAction {
1313
+ /** Stable identity. */
1314
+ id: string;
1315
+ /** Human label; the Search filter matches a case-insensitive substring of this. */
1316
+ label: string;
1317
+ /** Optional leading icon node. */
1318
+ icon?: ReactNode;
1319
+ /** Invoked when the row is chosen (click / Enter); the dock closes afterward. */
1320
+ onSelect: () => void;
1321
+ }
1322
+ interface CommandDockProps extends Omit<ComponentPropsWithoutRef<"div">, "hidden"> {
1323
+ /** The filterable command list shown in the Search popover. */
1324
+ actions?: CommandAction[];
1325
+ /** Search input placeholder. */
1326
+ searchPlaceholder?: string;
1327
+ /** Message shown in the Search popover when the filter matches nothing. */
1328
+ noResultsLabel?: string;
1329
+ /** Enable the AI composer. When `false` (default) the composer is disabled with a BYO-key message. */
1330
+ aiEnabled?: boolean;
1331
+ /** Called with the trimmed prompt when the AI composer is submitted; clears the input. */
1332
+ onAiSubmit?: (prompt: string) => void;
1333
+ /** AI composer placeholder. */
1334
+ aiPlaceholder?: string;
1335
+ /** BYO-key gate message shown when `aiEnabled` is false. */
1336
+ aiDisabledLabel?: string;
1337
+ /** Suggestions shown in the Add popover (filtered by the add input, case-insensitive). */
1338
+ addSuggestions?: CommandAction[];
1339
+ /** Add input placeholder. */
1340
+ addPlaceholder?: string;
1341
+ /** Notified as the user types in the Add input. */
1342
+ onAddQueryChange?: (query: string) => void;
1343
+ /** Self-manage hide-while-scrolling + 220ms idle spring-back (mirrors AppBar). */
1344
+ hideOnScroll?: boolean;
1345
+ /** Scroll source for `hideOnScroll`. Default `window`. */
1346
+ scrollContainer?: HTMLElement | Window | null;
1347
+ /** Manually apply the `.dock--hidden` hide transform. */
1348
+ hidden?: boolean;
1349
+ }
1350
+ declare const CommandDock: react.ForwardRefExoticComponent<CommandDockProps & react.RefAttributes<HTMLDivElement>>;
1351
+
1352
+ /**
1353
+ * NotificationCenter — the app-bar bell dropdown, built on Radix `Popover`.
1354
+ *
1355
+ * The shipped `NotificationBell` is the Popover trigger; the panel paints the shipped
1356
+ * `.dropdown` / `.notif` token classes (matching `preview/app-chrome-island.html`). ZERO token-CSS
1357
+ * change. Radix supplies the behavior (portal to `<body>`, focus management, Escape/outside-click).
1358
+ *
1359
+ * Per-item visual treatment is SEMANTIC (owner sign-off, S84): each item's `kind`
1360
+ * (`up` | `down` | `warn` | `info`) drives the shipped `.notif__mark--*` left mark — finance/status
1361
+ * meaning, NOT a source-identity tag. Unread items are the sage-tinted `.notif__item--unread` row;
1362
+ * clicking an unread row marks it read (`onMarkRead(id)`). The unread count is derived from `items`
1363
+ * here (no shared store) and drives the bell's `.badge-count` badge — empty `items` → count 0 → no
1364
+ * badge contract.
1365
+ */
1366
+ /** Semantic meaning of a notification — drives the shipped `.notif__mark--*` left mark. */
1367
+ type NotificationKind = "up" | "down" | "warn" | "info";
1368
+ interface NotificationItemData {
1369
+ /** Stable identity (passed to `onMarkRead`). */
1370
+ id: string;
1371
+ /** Semantic meaning → `.notif__mark--{kind}`. Omit for a neutral mark. */
1372
+ kind?: NotificationKind;
1373
+ /** Primary message (rich nodes allowed, e.g. a bold ticker + `.notif__num`). */
1374
+ title: ReactNode;
1375
+ /** Optional secondary detail, rendered after the title. */
1376
+ body?: ReactNode;
1377
+ /** Display timestamp (e.g. "2 min ago"). */
1378
+ timestamp: ReactNode;
1379
+ /** Read state. Unread renders the `.notif__item--unread` tint + the mark-read affordance. */
1380
+ read: boolean;
1381
+ /** Invoked with the item id when an unread row is marked read (click / Enter / Space). */
1382
+ onMarkRead: (id: string) => void;
1383
+ }
1384
+ interface NotificationCenterProps {
1385
+ /** The notifications to show. Unread count (drives the bell badge) is derived from this. */
1386
+ items: NotificationItemData[];
1387
+ /** Panel head title. Default "Notifications". */
1388
+ title?: string;
1389
+ /** When provided, a "Mark all read" head action renders and calls this. */
1390
+ onMarkAllRead?: () => void;
1391
+ /** "Mark all read" label. */
1392
+ markAllLabel?: string;
1393
+ /** Empty-state message when `items` is empty. Default "No notifications". */
1394
+ emptyLabel?: string;
1395
+ /** When provided, a footer "View all" link renders pointing here. */
1396
+ viewAllHref?: string;
1397
+ /** Footer link label. */
1398
+ viewAllLabel?: string;
1399
+ /** Bell trigger aria-label. Defaults to NotificationBell's "Notifications". */
1400
+ bellLabel?: string;
1401
+ /** Popover alignment relative to the bell. Default "end". */
1402
+ align?: "start" | "center" | "end";
1403
+ /** Popover distance from the bell, in px. Default 6. */
1404
+ sideOffset?: number;
1405
+ }
1406
+ declare function NotificationCenter({ items, title, onMarkAllRead, markAllLabel, emptyLabel, viewAllHref, viewAllLabel, bellLabel, align, sideOffset, }: NotificationCenterProps): react.JSX.Element;
1407
+
1408
+ /**
1409
+ * Terminal — the Stocky AI conversation transcript, painted with the shipped
1410
+ * `@qball-inc/tokens` `.term*` classes from the `preview/conversation-terminal.html`
1411
+ * oracle. A scrollable, growable transcript of `you ›` / `stocky ›` turns with
1412
+ * token-only styling (no component CSS, no hardcoded color, no box-shadow).
1413
+ *
1414
+ * Behaviour this surface owns: auto-scroll to the newest content on append, the
1415
+ * blinking streaming cursor at the end of the in-progress assistant turn, a
1416
+ * persistent (non-dismissible) AI disclaimer rendered via the shipped `Callout`
1417
+ * (the DESIGNATED disclaimer host — owner decision S86, in place of the oracle's
1418
+ * inline footer), and an error row that visually distinguishes a transient
1419
+ * `Retrying…` frame (warning) from a fatal `Try again` frame (error).
1420
+ *
1421
+ * Streaming state comes from the `useStreaming` hook (`messages` / `streaming` /
1422
+ * `error`), but `Terminal` is a pure display surface — it accepts that state as
1423
+ * props. Grounding annotations (`[source]` / `[unverified]`) are OUT of scope:
1424
+ * Grounding annotations are composed in afterward via `GroundingFlag`.
1425
+ */
1426
+ /** Speaker for a transcript turn. */
1427
+ type TerminalRole = "user" | "assistant";
1428
+ /**
1429
+ * A single streamed token. The streaming hook accumulates these into the
1430
+ * in-progress assistant message; `Terminal` flattens them to display text.
1431
+ */
1432
+ interface StreamToken {
1433
+ /** The text fragment carried by this token. */
1434
+ text: string;
1435
+ }
1436
+ /** One transcript turn. `content` is a plain string or an accumulating token list. */
1437
+ interface TerminalMessage {
1438
+ /** Optional stable identity used as the React key; falls back to the index. */
1439
+ id?: string | number;
1440
+ role: TerminalRole;
1441
+ content: string | StreamToken[];
1442
+ }
1443
+ /**
1444
+ * A provider error surfaced into the transcript. Discriminated on `kind` so a
1445
+ * retryable frame is never confused with a string sentinel
1446
+ * (the `discriminated {kind}` pattern over a `string | "literal"` union).
1447
+ */
1448
+ interface StreamError {
1449
+ kind: "error";
1450
+ /** Retryable → a transient `Retrying…` indicator; fatal → a `Try again` action. */
1451
+ retryable: boolean;
1452
+ message: string;
1453
+ }
1454
+ interface TerminalProps {
1455
+ /** The transcript, oldest first. */
1456
+ messages: TerminalMessage[];
1457
+ /** While true, the last assistant turn shows the blinking streaming cursor. */
1458
+ streaming?: boolean;
1459
+ /** A provider error to surface as an error row (`null` / omitted = none). */
1460
+ error?: StreamError | null;
1461
+ /** Fired by the fatal-error row's `Try again` action. */
1462
+ onRetry?: () => void;
1463
+ /** Composer slot rendered in the terminal footer (e.g. a `<Composer/>`). */
1464
+ composer?: ReactNode;
1465
+ /** The persistent AI disclaimer. Defaults to the standard "not advice" notice. */
1466
+ disclaimer?: ReactNode;
1467
+ /** Header title (`.term__title`). Default `"stocky"`. */
1468
+ title?: ReactNode;
1469
+ /** Max height of the scrollable transcript body (a number is treated as px). */
1470
+ maxHeight?: number | string;
1471
+ /** className merged onto the `.term` root. */
1472
+ className?: string;
1473
+ }
1474
+ declare function Terminal({ messages, streaming, error, onRetry, composer, disclaimer, title, maxHeight, className, }: TerminalProps): react.JSX.Element;
1475
+
1476
+ /**
1477
+ * Composer — the terminal's multiline input + inline send control, painted with
1478
+ * the shipped `.term__composer` / `.term__prompt` / `.term__input` classes from
1479
+ * the `preview/conversation-terminal.html` oracle. Standalone so it can sit in a
1480
+ * `Terminal` footer (via the `composer` slot) or on its own.
1481
+ *
1482
+ * Send fires on Enter (without Shift) or a click of the inline `.iconbtn` send
1483
+ * arrow; the textarea then clears and its auto-grown height resets. The BYO-key
1484
+ * gate (`keyProvided={false}`) disables the input + send and shows an "Add your
1485
+ * key" prompt — `onSend` is never invoked while gated. The Composer does NOT
1486
+ * render the key-entry flow (that is `SecretInput`); it only reflects
1487
+ * the `keyProvided` boolean and exposes the disabled visual state.
1488
+ */
1489
+ interface ComposerProps {
1490
+ /** Fired with the trimmed text on Enter (no Shift) or a send-click. */
1491
+ onSend: (text: string) => void;
1492
+ /** BYO-key gate. When `false`, the input + send are disabled and a prompt shows. Default `true`. */
1493
+ keyProvided?: boolean;
1494
+ /** Placeholder for the textarea. */
1495
+ placeholder?: string;
1496
+ /** The `.term__prompt` label. Default `"you ›"`. */
1497
+ prompt?: ReactNode;
1498
+ /** The gated-state prompt (must read as "add your key"). Default `"Add your key to start chatting."`. */
1499
+ keyPrompt?: ReactNode;
1500
+ /** Accessible label for the send button + the textarea. Defaults `"Send"` / `"Message"`. */
1501
+ sendLabel?: string;
1502
+ inputLabel?: string;
1503
+ /** className merged onto the `.term__composer` root. */
1504
+ className?: string;
1505
+ }
1506
+ declare function Composer({ onSend, keyProvided, placeholder, prompt, keyPrompt, sendLabel, inputLabel, className, }: ComposerProps): react.JSX.Element;
1507
+
1508
+ /**
1509
+ * Streaming — the SSE token-by-token consumption layer behind the `Terminal`.
1510
+ *
1511
+ * Three pieces:
1512
+ * - `parseStreamFrame` — a pure SSE-frame parser (`data:` / `event: error` /
1513
+ * `[DONE]`) → a discriminated {@link StreamEvent}. Provider error frames map
1514
+ * to `{ type: "error"; retryable; message }`, never a thrown exception.
1515
+ * - `streamFromResponse` — adapts a real `fetch` SSE `Response` body into an
1516
+ * `AsyncIterable<StreamEvent>` (wire framing on `\n\n`).
1517
+ * - `useStreaming` — the React hook: owns the transcript, appends each token to
1518
+ * the in-progress assistant turn (re-rendering per token), surfaces retryable
1519
+ * vs fatal errors, and clears the streaming flag on close (which removes the
1520
+ * Terminal's cursor).
1521
+ *
1522
+ * The error shape is discriminated on `kind` (`StreamError`) / `type`
1523
+ * (`StreamEvent`) rather than a `string | "ERROR"` union, so a retryable frame
1524
+ * can never be confused with a sentinel string.
1525
+ */
1526
+ /** A parsed event from the SSE stream. */
1527
+ type StreamEvent = {
1528
+ type: "token";
1529
+ text: string;
1530
+ } | {
1531
+ type: "error";
1532
+ retryable: boolean;
1533
+ message: string;
1534
+ } | {
1535
+ type: "done";
1536
+ };
1537
+ /**
1538
+ * Parse a single SSE frame (the text between `\n\n` separators) into a
1539
+ * `StreamEvent`, or `null` if the frame carries no `data:` line. An
1540
+ * `event: error` frame whose `data:` is a JSON `{ retryable, message }` becomes
1541
+ * a discriminated error event; a `data: [DONE]` sentinel becomes a done event;
1542
+ * anything else is a token whose text is the raw `data:` payload.
1543
+ */
1544
+ declare function parseStreamFrame(frame: string): StreamEvent | null;
1545
+ /**
1546
+ * Adapt a `fetch` SSE `Response` into an `AsyncIterable<StreamEvent>`. Reads the
1547
+ * body reader, decodes incrementally, and splits on the `\n\n` SSE frame
1548
+ * boundary, yielding one `StreamEvent` per non-empty frame.
1549
+ */
1550
+ declare function streamFromResponse(response: Response): AsyncIterable<StreamEvent>;
1551
+ /** The state + actions returned by {@link useStreaming}. */
1552
+ interface UseStreamingResult {
1553
+ /** The transcript, oldest first. */
1554
+ messages: TerminalMessage[];
1555
+ /** True while a stream is in flight (drives the Terminal cursor). */
1556
+ streaming: boolean;
1557
+ /** The current provider error, or `null`. Retryable → transient; fatal → terminal. */
1558
+ error: StreamError | null;
1559
+ /** Append a user turn (e.g. from the Composer's `onSend`). */
1560
+ send: (text: string) => void;
1561
+ /** Consume a parsed event stream, accumulating tokens into a fresh assistant turn. */
1562
+ start: (events: AsyncIterable<StreamEvent>) => Promise<void>;
1563
+ /** Clear the current error (e.g. before a retry). */
1564
+ reset: () => void;
1565
+ }
1566
+ /**
1567
+ * Token-by-token streaming state machine. One stream at a time: `start` opens a
1568
+ * fresh assistant turn and accumulates tokens into it, re-rendering per token. A
1569
+ * retryable error sets a transient indicator but keeps the stream open (the next
1570
+ * token clears it); a fatal error terminates the stream and leaves the error for
1571
+ * a `Try again` retry. The streaming flag always clears when the iterable ends.
1572
+ */
1573
+ declare function useStreaming(initial?: TerminalMessage[]): UseStreamingResult;
1574
+
1575
+ /**
1576
+ * GroundingFlag — the inline `[source]` / `[unverified]` grounding annotation for
1577
+ * AI answers, painted with the shipped `@qball-inc/tokens` grounding surface
1578
+ * (`.ground-wave` wave-shimmer + the `.gtip*` explainer bubble) from the
1579
+ * `preview/conversation-terminal.html` + `preview/briefing.html` oracles.
1580
+ *
1581
+ * **Standalone marker, NOT a value wrapper (oracle semantics).** The flag is the
1582
+ * small shimmering `[source]`/`[unverified]` label itself; the flagged value
1583
+ * (a price, a percent) lives in the surrounding prose — e.g. `NVDA leads [source]
1584
+ * at +8.4%`. `children`, when supplied, OVERRIDES the label glyph; it is not a
1585
+ * wrapped value.
1586
+ *
1587
+ * **Shimmer + reduced-motion are shipped CSS, not JS.** The wave-shimmer is the
1588
+ * shipped `.ground-wave` + `.ground-wave--{source|unverified}` keyframe; a
1589
+ * `@media (prefers-reduced-motion: reduce)` block in the same stylesheet swaps the
1590
+ * animation for a static `var(--wave-base)` fill. The component applies BOTH
1591
+ * classes (the modifier supplies `--wave-base`/`--wave-hi`); there is no
1592
+ * `matchMedia` in here.
1593
+ *
1594
+ * **Portaled to `<body>` (BINDING, RB-5).** The explainer bubble composes
1595
+ * `@radix-ui/react-tooltip` directly, so it portals to `<body>` and Radix's popper
1596
+ * keeps it on-screen (collision-clamped) — the same portal-to-body guarantee as the
1597
+ * sibling `Tooltip`. We do NOT reuse the shipped `TooltipContent` wrapper:
1598
+ * it force-joins `.tip-pop` (the DARK inverted bubble), whereas grounding uses the
1599
+ * deliberately LIGHT guardrail bubble. The position-agnostic `.gtip-pop` token class
1600
+ * carries that light look minus the parent-anchored `.gtip` positioning (Radix owns
1601
+ * placement); `.gtip__k`/`.gtip__src`/`.gtip--{cited,unverified}` descendants compose
1602
+ * in unchanged.
1603
+ *
1604
+ * Self-contained: bundles its own `TooltipProvider`, so it drops into any tree
1605
+ * (Terminal message content, a DigestCard narrated number) without app-root setup.
1606
+ *
1607
+ * <p>NVDA leads <GroundingFlag variant="source" explainer="Live last-sale quote.">
1608
+ * <span className="gtip__src">Nasdaq · 3:42pm ET</span>
1609
+ * </GroundingFlag> at +8.4%.</p>
1610
+ */
1611
+ type GroundingVariant = "source" | "unverified";
1612
+ interface GroundingFlagProps {
1613
+ /** `'source'` renders the cited `[source]` flag; `'unverified'` renders `[unverified]`. */
1614
+ variant: GroundingVariant;
1615
+ /**
1616
+ * The explainer body shown in the hover/focus bubble. Caller-supplied — this
1617
+ * component owns the portal/clamp/shimmer, not the copy. A `.gtip__k` kicker
1618
+ * (`Source` / `Unverified`) is rendered automatically above it.
1619
+ */
1620
+ explainer: ReactNode;
1621
+ /** Optional override for the shimmer label glyph; defaults to `[source]` / `[unverified]`. */
1622
+ children?: ReactNode;
1623
+ /** Pin the explainer open (uncontrolled initial state) — useful for docs/specimens. */
1624
+ defaultOpen?: boolean;
1625
+ }
1626
+ declare function GroundingFlag({ variant, explainer, children, defaultOpen }: GroundingFlagProps): react.JSX.Element;
1627
+
1628
+ /**
1629
+ * MarkdownRenderer — renders streamed assistant text (the Terminal's bot turns)
1630
+ * as sanitized, token-styled markdown. Scoped to assistant prose; NOT
1631
+ * a general-purpose HTML renderer (the element allowlist is the hard boundary).
1632
+ *
1633
+ * **Token styling is inherited, not declared (compose the shipped surface).** The
1634
+ * renderer emits BARE semantic elements (`<h1>`-`<h4>`, `<p>`, `<blockquote>`,
1635
+ * `<code>`, `<pre><code>`, `<a>`, `<em>`, `<strong>`, lists, `<hr>`). The shipped
1636
+ * `@qball-inc/tokens` `colors_and_type.css` already styles every one of those bare
1637
+ * elements token-backed (`h1,.h1` … `blockquote,.pullquote` … `pre,.codeblock` …
1638
+ * `a,.link`), exactly as the `preview/code-block.html` + `preview/pull-quote.html`
1639
+ * oracles do. So this component ships ZERO prose CSS, zero hardcoded hex, zero font
1640
+ * strings — the styling rides the global stylesheet the consumer already imports.
1641
+ * Anchors carry `.link` so the shared sage `:focus-visible` ring applies to prose
1642
+ * links (the ring was extended to `.link:focus-visible` in this WP).
1643
+ *
1644
+ * **Safe-rendering strategy (BINDING, AC-3/AC-4).** No `dangerouslySetInnerHTML`,
1645
+ * ever. Three layers, default-deny:
1646
+ * 1. No `rehype-raw` + `skipHtml` → raw HTML in the source (`<script>`,
1647
+ * `<img onerror>`, `<iframe>`, `<style>`, `<svg onload>`) is never turned into
1648
+ * live DOM; it is stripped, not escaped-and-shown.
1649
+ * 2. `allowedElements` (the {@link ALLOWED_ELEMENTS} allowlist) → only the scoped
1650
+ * prose set can render; anything else is dropped (`unwrapDisallowed` keeps the
1651
+ * inner text so content is never silently lost).
1652
+ * 3. `urlTransform` → react-markdown's own hardened `defaultUrlTransform`, applied
1653
+ * at the prop AND re-applied defensively inside the anchor override. It tests the
1654
+ * ENTIRE pre-colon slice against a safe-scheme set, so only http/https/mailto/
1655
+ * irc/xmpp and scheme-less (relative/fragment/protocol-relative) URLs survive;
1656
+ * `javascript:`/`data:`/`vbscript:` — and control-char or zero-width-prefixed
1657
+ * scheme tricks a hand-rolled regex would miss — collapse to an empty href.
1658
+ * The dual-assert XSS suite (AC-9) verifies each payload BOTH does not execute
1659
+ * (`window.__xss` stays undefined) AND does not appear as a DOM element.
1660
+ *
1661
+ * **Streaming cursor is the shipped `.term__cursor` (compose, don't re-invent).**
1662
+ * When `streaming`, a `.term__cursor` block is appended after the content — the
1663
+ * same class the Terminal renders for an in-flight bot turn. Its blink keyframe and
1664
+ * the `@media (prefers-reduced-motion: reduce) { animation: none }` static fallback
1665
+ * (NFR5) are shipped CSS, so there is no `matchMedia` here and no new cursor rule.
1666
+ * (When this renderer is later wired INTO the Terminal in place of its plain-text
1667
+ * flatten, the Terminal's own cursor is de-duplicated against this one — a future
1668
+ * WP; out of scope here.)
1669
+ */
1670
+ /** The hard scope boundary: only these elements may render. Everything else drops. */
1671
+ declare const ALLOWED_ELEMENTS: readonly ["h1", "h2", "h3", "h4", "p", "code", "pre", "blockquote", "a", "em", "strong", "ol", "ul", "li", "hr"];
1672
+ interface MarkdownRendererProps {
1673
+ /** The markdown source to render (a streamed assistant turn's accumulated text). */
1674
+ content: string;
1675
+ /** While true, append the shipped `.term__cursor` after the content. Default false. */
1676
+ streaming?: boolean;
1677
+ /** className merged onto the wrapper. */
1678
+ className?: string;
1679
+ }
1680
+ declare function MarkdownRenderer({ content, streaming, className }: MarkdownRendererProps): react.JSX.Element;
1681
+
1682
+ /**
1683
+ * ToolUseIndicator — the compact, inline lifecycle chip for a skill / tool call
1684
+ * inside the AI terminal transcript (the `Terminal`). It names the
1685
+ * specific skill (`news-research`, `sec-filings-lookup`, …) and reports the state
1686
+ * of its run, so a multi-second tool call never reads as a hang.
1687
+ *
1688
+ * Built to the **owner-signed-off** design spec
1689
+ * (`docs/tool-use-indicator-design.md`) + `preview/tool-use-indicator.html`. It is a
1690
+ * transient, status-bearing chip — it reports state, it is NOT a control.
1691
+ *
1692
+ * **All visuals come from the shipped `@qball-inc/tokens` `.tuf*` classes** (added in
1693
+ * Built from the signed-off design — the Terminal/GroundingFlag token-CSS-port
1694
+ * precedent). `data-state` drives the per-state color + tint; the color flows to the
1695
+ * leading glyph + verb via `currentColor`. There is no component CSS and no hardcoded
1696
+ * color (FR4 / DESIGN_DENY-clean — flat tonal tints, no elevation).
1697
+ *
1698
+ * **Glyph = the primary non-color cue (FR4).** Each state carries a distinct leading
1699
+ * glyph — an inline SVG (Lucide geometry, stroke 1.5, 16px; matching the ThemeToggle /
1700
+ * StateFig inline-SVG precedent, NOT a `lucide-react` import) — except `running`, which
1701
+ * reuses the shipped `.spinner` (the one sanctioned loop) or, in `streaming` mode, the
1702
+ * shipped `.term__cursor` blink. `partial` (caution gold) ALWAYS pairs its color with
1703
+ * the glyph AND the literal verb word, so color never carries the meaning alone.
1704
+ *
1705
+ * **Reduced-motion is shipped CSS, not JS.** The `.spinner`, `.term__cursor`, and `.tuf`
1706
+ * appear/cross-fade all stop under `@media (prefers-reduced-motion: reduce)` in the token
1707
+ * stylesheet; the state stays fully legible from the static glyph + color + label. There
1708
+ * is no `matchMedia` in here (the Skeleton / GroundingFlag contract).
1709
+ *
1710
+ * `idle` renders nothing — the chip is absent/collapsed (the approved "absent or
1711
+ * collapsed" latitude); no looping idle animation.
1712
+ *
1713
+ * <ToolUseIndicator state="running" skill="news-research" meta="3.1s" />
1714
+ * <ToolUseIndicator state="partial" skill="news-research" meta="rate-limited" />
1715
+ * <ToolUseIndicator state="running" streaming>analyzing filings</ToolUseIndicator>
1716
+ */
1717
+ type ToolUseState = "idle" | "pending" | "running" | "success" | "error" | "partial";
1718
+ interface ToolUseIndicatorProps {
1719
+ /** Lifecycle state. `idle` renders nothing (the chip is absent/collapsed). */
1720
+ state: ToolUseState;
1721
+ /** The skill / tool id, e.g. `"news-research"`. Rendered before the state verb. */
1722
+ skill?: string;
1723
+ /**
1724
+ * Override the state verb (the default per state: queued / running / done /
1725
+ * failed / partial). Ignored when `children` supplies a free-form label. For
1726
+ * `state="partial"`, keep a caution word ("partial" / "rate-limited") so the
1727
+ * FR4 non-color cue survives — the glyph is always present, but the word
1728
+ * reinforces it; never suppress the text cue entirely.
1729
+ */
1730
+ verb?: string;
1731
+ /** Optional trailing meta — elapsed time, result count, or `"rate-limited"`. */
1732
+ meta?: ReactNode;
1733
+ /**
1734
+ * `running` only: render the streaming text-cursor (the shipped `.term__cursor`)
1735
+ * after the label instead of the leading `.spinner` glyph — for the
1736
+ * SSE-token-streaming variant.
1737
+ */
1738
+ streaming?: boolean;
1739
+ /**
1740
+ * Free-form label override (e.g. `"analyzing filings"`). When supplied, it
1741
+ * replaces the constructed `{skill} · {verb}` label. `null`/`undefined` both
1742
+ * fall through to the constructed label, so a conditional `children` never
1743
+ * yields an empty chip.
1744
+ */
1745
+ children?: ReactNode;
1746
+ /** Merged onto the `.tuf` root. */
1747
+ className?: string;
1748
+ }
1749
+ declare function ToolUseIndicator({ state, skill, verb, meta, streaming, children, className, }: ToolUseIndicatorProps): react.JSX.Element | null;
1750
+
1751
+ /**
1752
+ * DigestCard — the LLM market-briefing / digest card, painted with the shipped
1753
+ * `@qball-inc/tokens` `.digest` family from the `preview/briefing.html` oracle.
1754
+ *
1755
+ * A briefing is a self-contained `<article>` with an eyebrow period, a headline,
1756
+ * a prose body, and a footer (timestamp + actions). Four states, controlled by
1757
+ * `state`:
1758
+ * - `unread` — `.digest--unread` (sage left-border) + a visible sage `.digest__dot`.
1759
+ * - `read` — `.digest--read` (dimmed); NO dot.
1760
+ * - `loading` — composes the shipped {@link Skeleton} placeholders in the digest layout.
1761
+ * - `empty` — composes the shipped {@link EmptyStateFig} ("no briefings yet").
1762
+ *
1763
+ * **Pure className wrapper (S70 D-08).** Every visual comes from the shipped
1764
+ * `.digest*` token CSS — there is no component CSS and no hardcoded color (FR4 /
1765
+ * DESIGN_DENY-clean — flat tonal tints, no elevation). The sage accent (dot +
1766
+ * border) is delivered by the `.digest__dot`
1767
+ * / `.digest--unread` classes (which resolve `var(--color-signal)`, the sage
1768
+ * token), so the component inlines no color of its own.
1769
+ *
1770
+ * **The sage dot is the non-color cue (FR4).** It is rendered ONLY in the `unread`
1771
+ * state — its DOM presence/absence (not its color) signals unread vs read, so the
1772
+ * status survives a monochrome rendering. (The oracle hides the read dot via CSS,
1773
+ * but jsdom can't observe external CSS, so we render it conditionally instead.)
1774
+ *
1775
+ * **Grounding is composed by the caller, not owned here.** A narrated number in the
1776
+ * body is annotated by dropping a {@link GroundingFlag} marker inline in `children`,
1777
+ * NEXT TO the value (the oracle: `NVDA leads [source] at +8.4%`). DigestCard is the
1778
+ * host; it does not wrap values itself.
1779
+ *
1780
+ * <DigestCard state="unread" period="Morning briefing · 30 May"
1781
+ * title="Your watchlist is up 1.8% pre-open" time="Generated 7:02am ET">
1782
+ * <b>NVDA</b> leads{" "}
1783
+ * <GroundingFlag variant="source" explainer="Live last-sale quote.">
1784
+ * <span className="gtip__src">Nasdaq · 3:42pm ET</span>
1785
+ * </GroundingFlag>{" "}
1786
+ * at <b>+8.4%</b> on the week.
1787
+ * </DigestCard>
1788
+ */
1789
+ type DigestState = "unread" | "read" | "loading" | "empty";
1790
+ interface DigestCardProps {
1791
+ /** Display state. */
1792
+ state: DigestState;
1793
+ /** Eyebrow line, e.g. `"Morning briefing · 30 May"` (`.digest__period`). unread/read. */
1794
+ period?: ReactNode;
1795
+ /** Headline (`.digest__title`). unread/read. */
1796
+ title?: ReactNode;
1797
+ /** Body prose (`.digest__body`). Compose `<GroundingFlag>` markers inline. unread/read. */
1798
+ children?: ReactNode;
1799
+ /** Footer timestamp (`.digest__time`). unread/read. */
1800
+ time?: ReactNode;
1801
+ /** Footer actions slot (`.digest__actions`) — e.g. ghost icon buttons. unread/read. */
1802
+ actions?: ReactNode;
1803
+ /** `empty` state: icon node for the EmptyStateFig (e.g. an inline SVG). */
1804
+ emptyIcon?: ReactNode;
1805
+ /** `empty` state: headline. Default `"No briefings yet"`. */
1806
+ emptyTitle?: ReactNode;
1807
+ /** `empty` state: supporting line. */
1808
+ emptyBody?: ReactNode;
1809
+ /** `empty` state: optional CTA (e.g. a `<Button>`). */
1810
+ emptyAction?: ReactNode;
1811
+ /** Merged onto the `.digest` root. */
1812
+ className?: string;
1813
+ }
1814
+ declare function DigestCard({ state, period, title, children, time, actions, emptyIcon, emptyTitle, emptyBody, emptyAction, className, }: DigestCardProps): react.JSX.Element;
1815
+
1816
+ /**
1817
+ * Props shared by the canvas background primitives. Standard `<canvas>` attributes
1818
+ * (`className`, `style`, `id`, …) are spread onto the element so a consumer can
1819
+ * size and position it (the backgrounds fill their parent via CSS). The `ref` is
1820
+ * owned by the primitive (it drives the animation) and the canvas is always
1821
+ * `aria-hidden` — these decorative surfaces carry no semantic content.
1822
+ */
1823
+ type BackgroundProps = ComponentPropsWithoutRef<"canvas">;
1824
+
1825
+ /**
1826
+ * `GridBg` — a slowly pulsing dot matrix in the signal (sage) token color, faded
1827
+ * toward the top-left so an overlaid headline stays readable. A decorative,
1828
+ * `aria-hidden` `<canvas>` background.
1829
+ *
1830
+ * Token-driven (reads `--color-signal` at paint time; draws nothing if the token
1831
+ * stylesheet is absent). Honors `prefers-reduced-motion` via {@link useCanvas2D} —
1832
+ * one static frame, no animation loop. Brand rule: signal color only, very slow,
1833
+ * no spring.
1834
+ */
1835
+ declare function GridBg(props: BackgroundProps): react.JSX.Element;
1836
+
1837
+ /**
1838
+ * `AsciiBg` — slow falling streams of mono characters: bright amber (highlight) at
1839
+ * each column head fading to sage (signal) down the tail. A decorative,
1840
+ * `aria-hidden` `<canvas>` background.
1841
+ *
1842
+ * Token-driven (reads `--color-signal`, `--color-highlight`, and `--font-display`
1843
+ * at paint time; draws nothing if the color tokens are absent). The glyph font is
1844
+ * the design-system display font (`--font-display`), falling back to the public
1845
+ * Fira Code default — never the private commercial display face. Honors
1846
+ * `prefers-reduced-motion` via {@link useCanvas2D} (one static frame, no loop).
1847
+ */
1848
+ declare function AsciiBg(props: BackgroundProps): react.JSX.Element;
1849
+
1850
+ /**
1851
+ * `GlyphsBg` — brand glyphs drifting slowly like a constellation, mostly in the
1852
+ * signal (sage) token color with roughly one in six in amber (highlight), each
1853
+ * breathing in opacity. A decorative, `aria-hidden` `<canvas>` background.
1854
+ *
1855
+ * Token-driven (reads `--color-signal`, `--color-highlight`, and `--font-display`
1856
+ * at paint time; draws nothing if the color tokens are absent). The glyph font is
1857
+ * the design-system display font (`--font-display`), falling back to the public
1858
+ * Fira Code default — never the private commercial display face. Honors
1859
+ * `prefers-reduced-motion` via {@link useCanvas2D} (one static frame, no loop).
1860
+ */
1861
+ declare function GlyphsBg(props: BackgroundProps): react.JSX.Element;
1862
+
1863
+ /**
1864
+ * The per-frame context handed to a {@link CanvasDraw} callback. Sizes are in CSS
1865
+ * pixels (the draw callback works in CSS-pixel space; the hook has already applied
1866
+ * the device-pixel-ratio transform to the context).
1867
+ */
1868
+ interface CanvasFrame {
1869
+ /** Seconds elapsed since the animation started. */
1870
+ t: number;
1871
+ /** CSS-pixel width of the canvas (from `getBoundingClientRect`). */
1872
+ w: number;
1873
+ /** CSS-pixel height of the canvas. */
1874
+ h: number;
1875
+ /**
1876
+ * `true` when the user prefers reduced motion. The hook draws a single static
1877
+ * frame in that case (see the hook docs); a draw callback should additionally
1878
+ * zero any time-derived motion so the one frame it paints is still.
1879
+ */
1880
+ reduceMotion: boolean;
1881
+ }
1882
+ /** A draw callback: paints one frame onto a 2D context. */
1883
+ type CanvasDraw = (ctx: CanvasRenderingContext2D, frame: CanvasFrame) => void;
1884
+ /**
1885
+ * `useCanvas2D` — a DPR-aware (capped at 2×), `ResizeObserver`-refit driver for an
1886
+ * animated `<canvas>`. Returns a ref to attach to a `<canvas>` element.
1887
+ *
1888
+ * **SSR/static-safe.** Every canvas / `window` / `ResizeObserver` access lives
1889
+ * inside the effect, so the host component renders an inert `<canvas>` on the
1890
+ * server and only begins drawing after hydration. If the 2D context is
1891
+ * unavailable (server, jsdom without a canvas mock, or a browser without canvas),
1892
+ * the hook no-ops — the `<canvas>` still renders, nothing throws.
1893
+ *
1894
+ * **Honors `prefers-reduced-motion` as a TRUE short-circuit.** When reduced motion
1895
+ * is requested the hook paints exactly one static frame and starts **no** animation
1896
+ * loop (`requestAnimationFrame` is never called). A later resize repaints that one
1897
+ * frame so the canvas is never left blank. This differs from the original port,
1898
+ * which kept the rAF loop spinning on a frozen frame.
1899
+ *
1900
+ * **No leaked work (RB-4).** The effect cleanup flips the running flag, cancels any
1901
+ * pending frame, and disconnects the `ResizeObserver`, so no loop, frame, or
1902
+ * observer survives an unmount or a dependency change.
1903
+ *
1904
+ * @param draw Per-frame paint callback. Read theme/colors/state fresh inside it.
1905
+ * @param deps Dependencies that re-key the effect (default `[]`). The draw closure
1906
+ * reads its inputs fresh each frame, so most backgrounds pass none.
1907
+ */
1908
+ declare function useCanvas2D(draw: CanvasDraw, deps?: DependencyList): react.RefObject<HTMLCanvasElement>;
1909
+
1910
+ /**
1911
+ * Shared prop surface for every icon in the system — the per-icon named exports
1912
+ * (`<TrendingUp />`) and the dynamic registry (`<Icon name="trending-up" />`).
1913
+ *
1914
+ * Icons are **currentColor-only**: they never read a token. The placement wrapper
1915
+ * owns color (e.g. `.iconbtn { color: var(--text-muted) }`), and a consumer
1916
+ * recolors by setting `color` on any ancestor and resizes via `size`.
1917
+ *
1918
+ * `children` is omitted — an icon's geometry is baked at codegen time; it is not a
1919
+ * slot. (The generated component supplies its paths to the shared `IconBase`.)
1920
+ */
1921
+ interface IconProps extends Omit<SVGProps<SVGSVGElement>, "ref" | "children"> {
1922
+ /** Render size in px → `width` and `height` on the fixed 24 viewBox. Default 24. */
1923
+ size?: number;
1924
+ /** Stroke width. Default 1.5 (the DS idiom; a few heavier marks use 1.6). */
1925
+ strokeWidth?: number;
1926
+ /** className merged after the base `ic` class. */
1927
+ className?: string;
1928
+ /**
1929
+ * Accessible label. When present (or an `aria-label` is passed), the icon flips
1930
+ * from decorative (`aria-hidden`) to `role="img"` + a linked `<title>`. Omit for
1931
+ * decorative icons sitting next to text that already carries the meaning.
1932
+ */
1933
+ title?: string;
1934
+ }
1935
+
1936
+ /** `chevron-up` — generated from lucide-react@1.17.0 (ISC). */
1937
+ declare function ChevronUp(props: IconProps): react.JSX.Element;
1938
+
1939
+ /** `chevron-down` — generated from lucide-react@1.17.0 (ISC). */
1940
+ declare function ChevronDown(props: IconProps): react.JSX.Element;
1941
+
1942
+ /** `chevron-left` — generated from lucide-react@1.17.0 (ISC). */
1943
+ declare function ChevronLeft(props: IconProps): react.JSX.Element;
1944
+
1945
+ /** `chevron-right` — generated from lucide-react@1.17.0 (ISC). */
1946
+ declare function ChevronRight(props: IconProps): react.JSX.Element;
1947
+
1948
+ /** `arrow-up` — generated from lucide-react@1.17.0 (ISC). */
1949
+ declare function ArrowUp(props: IconProps): react.JSX.Element;
1950
+
1951
+ /** `arrow-down` — generated from lucide-react@1.17.0 (ISC). */
1952
+ declare function ArrowDown(props: IconProps): react.JSX.Element;
1953
+
1954
+ /** `arrow-left` — generated from lucide-react@1.17.0 (ISC). */
1955
+ declare function ArrowLeft(props: IconProps): react.JSX.Element;
1956
+
1957
+ /** `arrow-right` — generated from lucide-react@1.17.0 (ISC). */
1958
+ declare function ArrowRight(props: IconProps): react.JSX.Element;
1959
+
1960
+ /** `arrow-up-right` — generated from lucide-react@1.17.0 (ISC). */
1961
+ declare function ArrowUpRight(props: IconProps): react.JSX.Element;
1962
+
1963
+ /** `arrow-up-left` — generated from lucide-react@1.17.0 (ISC). */
1964
+ declare function ArrowUpLeft(props: IconProps): react.JSX.Element;
1965
+
1966
+ /** `arrow-down-right` — generated from lucide-react@1.17.0 (ISC). */
1967
+ declare function ArrowDownRight(props: IconProps): react.JSX.Element;
1968
+
1969
+ /** `arrow-down-left` — generated from lucide-react@1.17.0 (ISC). */
1970
+ declare function ArrowDownLeft(props: IconProps): react.JSX.Element;
1971
+
1972
+ /** `external-link` — generated from lucide-react@1.17.0 (ISC). */
1973
+ declare function ExternalLink(props: IconProps): react.JSX.Element;
1974
+
1975
+ /** `menu` — generated from lucide-react@1.17.0 (ISC). */
1976
+ declare function Menu(props: IconProps): react.JSX.Element;
1977
+
1978
+ /** `x` — generated from lucide-react@1.17.0 (ISC). */
1979
+ declare function X(props: IconProps): react.JSX.Element;
1980
+
1981
+ /** `search` — generated from lucide-react@1.17.0 (ISC). */
1982
+ declare function SearchIcon(props: IconProps): react.JSX.Element;
1983
+
1984
+ /** `plus` — generated from lucide-react@1.17.0 (ISC). */
1985
+ declare function Plus(props: IconProps): react.JSX.Element;
1986
+
1987
+ /** `minus` — generated from lucide-react@1.17.0 (ISC). */
1988
+ declare function Minus(props: IconProps): react.JSX.Element;
1989
+
1990
+ /** `square-pen` — generated from lucide-react@1.17.0 (ISC). */
1991
+ declare function SquarePen(props: IconProps): react.JSX.Element;
1992
+
1993
+ /** `trash-2` — generated from lucide-react@1.17.0 (ISC). */
1994
+ declare function Trash2(props: IconProps): react.JSX.Element;
1995
+
1996
+ /** `download` — generated from lucide-react@1.17.0 (ISC). */
1997
+ declare function Download(props: IconProps): react.JSX.Element;
1998
+
1999
+ /** `upload` — generated from lucide-react@1.17.0 (ISC). */
2000
+ declare function Upload(props: IconProps): react.JSX.Element;
2001
+
2002
+ /** `copy` — generated from lucide-react@1.17.0 (ISC). */
2003
+ declare function Copy(props: IconProps): react.JSX.Element;
2004
+
2005
+ /** `share-2` — generated from lucide-react@1.17.0 (ISC). */
2006
+ declare function Share2(props: IconProps): react.JSX.Element;
2007
+
2008
+ /** `funnel` — generated from lucide-react@1.17.0 (ISC). */
2009
+ declare function Funnel(props: IconProps): react.JSX.Element;
2010
+
2011
+ /** `arrow-up-down` — generated from lucide-react@1.17.0 (ISC). */
2012
+ declare function ArrowUpDown(props: IconProps): react.JSX.Element;
2013
+
2014
+ /** `settings` — generated from lucide-react@1.17.0 (ISC). */
2015
+ declare function Settings(props: IconProps): react.JSX.Element;
2016
+
2017
+ /** `refresh-cw` — generated from lucide-react@1.17.0 (ISC). */
2018
+ declare function RefreshCw(props: IconProps): react.JSX.Element;
2019
+
2020
+ /** `check` — generated from lucide-react@1.17.0 (ISC). */
2021
+ declare function Check(props: IconProps): react.JSX.Element;
2022
+
2023
+ /** `send` — generated from lucide-react@1.17.0 (ISC). */
2024
+ declare function Send(props: IconProps): react.JSX.Element;
2025
+
2026
+ /** `eye` — generated from lucide-react@1.17.0 (ISC). */
2027
+ declare function Eye(props: IconProps): react.JSX.Element;
2028
+
2029
+ /** `eye-off` — generated from lucide-react@1.17.0 (ISC). */
2030
+ declare function EyeOff(props: IconProps): react.JSX.Element;
2031
+
2032
+ /** `bell` — generated from lucide-react@1.17.0 (ISC). */
2033
+ declare function Bell(props: IconProps): react.JSX.Element;
2034
+
2035
+ /** `bell-off` — generated from lucide-react@1.17.0 (ISC). */
2036
+ declare function BellOff(props: IconProps): react.JSX.Element;
2037
+
2038
+ /** `ellipsis` — generated from lucide-react@1.17.0 (ISC). */
2039
+ declare function Ellipsis(props: IconProps): react.JSX.Element;
2040
+
2041
+ /** `ellipsis-vertical` — generated from lucide-react@1.17.0 (ISC). */
2042
+ declare function EllipsisVertical(props: IconProps): react.JSX.Element;
2043
+
2044
+ /** `save` — generated from lucide-react@1.17.0 (ISC). */
2045
+ declare function Save(props: IconProps): react.JSX.Element;
2046
+
2047
+ /** `info` — generated from lucide-react@1.17.0 (ISC). */
2048
+ declare function Info(props: IconProps): react.JSX.Element;
2049
+
2050
+ /** `triangle-alert` — generated from lucide-react@1.17.0 (ISC). */
2051
+ declare function TriangleAlert(props: IconProps): react.JSX.Element;
2052
+
2053
+ /** `circle-x` — generated from lucide-react@1.17.0 (ISC). */
2054
+ declare function CircleX(props: IconProps): react.JSX.Element;
2055
+
2056
+ /** `circle-check` — generated from lucide-react@1.17.0 (ISC). */
2057
+ declare function CircleCheck(props: IconProps): react.JSX.Element;
2058
+
2059
+ /** `circle-check-big` — generated from lucide-react@1.17.0 (ISC). */
2060
+ declare function CircleCheckBig(props: IconProps): react.JSX.Element;
2061
+
2062
+ /** `clock` — generated from lucide-react@1.17.0 (ISC). */
2063
+ declare function Clock(props: IconProps): react.JSX.Element;
2064
+
2065
+ /** `loader` — generated from lucide-react@1.17.0 (ISC). */
2066
+ declare function Loader(props: IconProps): react.JSX.Element;
2067
+
2068
+ /** `sun` — generated from lucide-react@1.17.0 (ISC). */
2069
+ declare function Sun(props: IconProps): react.JSX.Element;
2070
+
2071
+ /** `moon` — generated from lucide-react@1.17.0 (ISC). */
2072
+ declare function Moon(props: IconProps): react.JSX.Element;
2073
+
2074
+ /** `lock` — generated from lucide-react@1.17.0 (ISC). */
2075
+ declare function Lock(props: IconProps): react.JSX.Element;
2076
+
2077
+ /** `lock-open` — generated from lucide-react@1.17.0 (ISC). */
2078
+ declare function LockOpen(props: IconProps): react.JSX.Element;
2079
+
2080
+ /** `circle-question-mark` — generated from lucide-react@1.17.0 (ISC). */
2081
+ declare function CircleQuestionMark(props: IconProps): react.JSX.Element;
2082
+
2083
+ /** `ban` — generated from lucide-react@1.17.0 (ISC). */
2084
+ declare function Ban(props: IconProps): react.JSX.Element;
2085
+
2086
+ /** `check-check` — generated from lucide-react@1.17.0 (ISC). */
2087
+ declare function CheckCheck(props: IconProps): react.JSX.Element;
2088
+
2089
+ /** `octagon-alert` — generated from lucide-react@1.17.0 (ISC). */
2090
+ declare function OctagonAlert(props: IconProps): react.JSX.Element;
2091
+
2092
+ /** `play` — generated from lucide-react@1.17.0 (ISC). */
2093
+ declare function Play(props: IconProps): react.JSX.Element;
2094
+
2095
+ /** `pause` — generated from lucide-react@1.17.0 (ISC). */
2096
+ declare function Pause(props: IconProps): react.JSX.Element;
2097
+
2098
+ /** `square` — generated from lucide-react@1.17.0 (ISC). */
2099
+ declare function Square(props: IconProps): react.JSX.Element;
2100
+
2101
+ /** `globe` — generated from lucide-react@1.17.0 (ISC). */
2102
+ declare function Globe(props: IconProps): react.JSX.Element;
2103
+
2104
+ /** `image` — generated from lucide-react@1.17.0 (ISC). */
2105
+ declare function Image(props: IconProps): react.JSX.Element;
2106
+
2107
+ /** `file` — generated from lucide-react@1.17.0 (ISC). */
2108
+ declare function File(props: IconProps): react.JSX.Element;
2109
+
2110
+ /** `link` — generated from lucide-react@1.17.0 (ISC). */
2111
+ declare function Link(props: IconProps): react.JSX.Element;
2112
+
2113
+ /** `package` — generated from lucide-react@1.17.0 (ISC). */
2114
+ declare function Package(props: IconProps): react.JSX.Element;
2115
+
2116
+ /** `rocket` — generated from lucide-react@1.17.0 (ISC). */
2117
+ declare function Rocket(props: IconProps): react.JSX.Element;
2118
+
2119
+ /** `grid-3x3` — generated from lucide-react@1.17.0 (ISC). */
2120
+ declare function Grid3x3(props: IconProps): react.JSX.Element;
2121
+
2122
+ /** `notebook-pen` — generated from lucide-react@1.17.0 (ISC). */
2123
+ declare function NotebookPen(props: IconProps): react.JSX.Element;
2124
+
2125
+ /** `code-xml` — generated from lucide-react@1.17.0 (ISC). */
2126
+ declare function CodeXml(props: IconProps): react.JSX.Element;
2127
+
2128
+ /** `trending-up` — generated from lucide-react@1.17.0 (ISC). */
2129
+ declare function TrendingUp(props: IconProps): react.JSX.Element;
2130
+
2131
+ /** `trending-down` — generated from lucide-react@1.17.0 (ISC). */
2132
+ declare function TrendingDown(props: IconProps): react.JSX.Element;
2133
+
2134
+ /** `chart-line` — generated from lucide-react@1.17.0 (ISC). */
2135
+ declare function ChartLine(props: IconProps): react.JSX.Element;
2136
+
2137
+ /** `chart-column` — generated from lucide-react@1.17.0 (ISC). */
2138
+ declare function ChartColumn(props: IconProps): react.JSX.Element;
2139
+
2140
+ /** `chart-candlestick` — generated from lucide-react@1.17.0 (ISC). */
2141
+ declare function ChartCandlestick(props: IconProps): react.JSX.Element;
2142
+
2143
+ /** `chart-pie` — generated from lucide-react@1.17.0 (ISC). */
2144
+ declare function ChartPie(props: IconProps): react.JSX.Element;
2145
+
2146
+ /** `wallet` — generated from lucide-react@1.17.0 (ISC). */
2147
+ declare function Wallet(props: IconProps): react.JSX.Element;
2148
+
2149
+ /** `briefcase` — generated from lucide-react@1.17.0 (ISC). */
2150
+ declare function Briefcase(props: IconProps): react.JSX.Element;
2151
+
2152
+ /** `calendar` — generated from lucide-react@1.17.0 (ISC). */
2153
+ declare function Calendar(props: IconProps): react.JSX.Element;
2154
+
2155
+ /** `bookmark` — generated from lucide-react@1.17.0 (ISC). */
2156
+ declare function Bookmark(props: IconProps): react.JSX.Element;
2157
+
2158
+ /** `percent` — generated from lucide-react@1.17.0 (ISC). */
2159
+ declare function Percent(props: IconProps): react.JSX.Element;
2160
+
2161
+ /** `dollar-sign` — generated from lucide-react@1.17.0 (ISC). */
2162
+ declare function DollarSign(props: IconProps): react.JSX.Element;
2163
+
2164
+ /** `activity` — generated from lucide-react@1.17.0 (ISC). */
2165
+ declare function Activity(props: IconProps): react.JSX.Element;
2166
+
2167
+ /** `target` — generated from lucide-react@1.17.0 (ISC). */
2168
+ declare function Target(props: IconProps): react.JSX.Element;
2169
+
2170
+ /** `scale` — generated from lucide-react@1.17.0 (ISC). */
2171
+ declare function Scale(props: IconProps): react.JSX.Element;
2172
+
2173
+ /** `banknote` — generated from lucide-react@1.17.0 (ISC). */
2174
+ declare function Banknote(props: IconProps): react.JSX.Element;
2175
+
2176
+ /** `ai-sparkle` — generated from lucide-react@1.17.0 (ISC). */
2177
+ declare function AiSparkle(props: IconProps): react.JSX.Element;
2178
+
2179
+ /** `bot` — generated from lucide-react@1.17.0 (ISC). */
2180
+ declare function Bot(props: IconProps): react.JSX.Element;
2181
+
2182
+ /** `bot-message-square` — generated from lucide-react@1.17.0 (ISC). */
2183
+ declare function BotMessageSquare(props: IconProps): react.JSX.Element;
2184
+
2185
+ /** `cpu` — generated from lucide-react@1.17.0 (ISC). */
2186
+ declare function Cpu(props: IconProps): react.JSX.Element;
2187
+
2188
+ /**
2189
+ * `agent-stocky` — original DS art: the Stocky CRT-bot mascot rendered STATIC. A
2190
+ * faithful 0.75-scale of the signed-off preview design (the preview drew it at the
2191
+ * mascot's native 32-viewBox; the icon system is a fixed 24-viewBox), in the stroke
2192
+ * idiom (antenna + screen + eyes + legs, no animation). A distinct, tree-shakeable
2193
+ * icon; the animated `StockyIcon` in `CommandDock` stays unmigrated (§10).
2194
+ * currentColor-only.
2195
+ */
2196
+ declare function AgentStocky(props: IconProps): react.JSX.Element;
2197
+
2198
+ /**
2199
+ * `agent-orb` — original DS art (signed-off preview design): a core node radiating
2200
+ * concentric signal arcs, in the 24-viewBox stroke idiom. No third-party source / IP.
2201
+ * currentColor-only.
2202
+ */
2203
+ declare function AgentOrb(props: IconProps): react.JSX.Element;
2204
+
2205
+ /**
2206
+ * `agent-droid` — original DS art (signed-off preview design): a domed droid head
2207
+ * with a single antenna and a visor band, in the 24-viewBox stroke idiom. No
2208
+ * third-party source / IP. currentColor-only.
2209
+ */
2210
+ declare function AgentDroid(props: IconProps): react.JSX.Element;
2211
+
2212
+ /**
2213
+ * `agent-hex` — original DS art (signed-off preview design): a hexagonal agent badge
2214
+ * with a two-eye face, in the 24-viewBox stroke idiom. No third-party source / IP.
2215
+ * currentColor-only.
2216
+ */
2217
+ declare function AgentHex(props: IconProps): react.JSX.Element;
2218
+
2219
+ /** `github` — the GitHub mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2220
+ declare function GitHub(props: IconProps): react.JSX.Element;
2221
+
2222
+ /** `npm` — the npm mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2223
+ declare function NPM(props: IconProps): react.JSX.Element;
2224
+
2225
+ /** `figma` — the Figma mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2226
+ declare function Figma(props: IconProps): react.JSX.Element;
2227
+
2228
+ /** `notion` — the Notion mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2229
+ declare function Notion(props: IconProps): react.JSX.Element;
2230
+
2231
+ /** `vercel` — the Vercel mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2232
+ declare function Vercel(props: IconProps): react.JSX.Element;
2233
+
2234
+ /** `chromestore` — the Chrome Web Store mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2235
+ declare function ChromeWebStore(props: IconProps): react.JSX.Element;
2236
+
2237
+ /**
2238
+ * `vscode` — a VSCodium stand-in (the real VS Code mark is trademark-withheld from
2239
+ * CC0 sets, §12); swap in an official asset if one is provided. Nominative use only
2240
+ * — VS Code / VSCodium are trademarks of their owners (see MARKS.md).
2241
+ */
2242
+ declare function VSCode(props: IconProps): react.JSX.Element;
2243
+
2244
+ /** `linear` — the Linear mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2245
+ declare function Linear(props: IconProps): react.JSX.Element;
2246
+
2247
+ /**
2248
+ * `linkedin` — the LinkedIn mark (in-repo stroke glyph carried from the consumer;
2249
+ * Lucide removed brand icons, so it is NOT in lucide@1.17.0, §12). Stroke idiom —
2250
+ * a minor, owner-accepted inconsistency vs the filled brand marks. Nominative use
2251
+ * only — a trademark of its owner (see MARKS.md).
2252
+ */
2253
+ declare function LinkedIn(props: IconProps): react.JSX.Element;
2254
+
2255
+ /** `x-twitter` — the X mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2256
+ declare function XTwitter(props: IconProps): react.JSX.Element;
2257
+
2258
+ /** `youtube` — the YouTube mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2259
+ declare function YouTube(props: IconProps): react.JSX.Element;
2260
+
2261
+ /** `google` — the Google mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2262
+ declare function Google(props: IconProps): react.JSX.Element;
2263
+
2264
+ /** `reddit` — the Reddit mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2265
+ declare function Reddit(props: IconProps): react.JSX.Element;
2266
+
2267
+ /**
2268
+ * `openai` — the OpenAI mark (owner-supplied asset; not in CC0 sets, §12). The
2269
+ * source `#000000` fill is normalized to `currentColor` via the filled IconBase.
2270
+ * Nominative use only — a trademark of its owner (see MARKS.md).
2271
+ */
2272
+ declare function OpenAI(props: IconProps): react.JSX.Element;
2273
+
2274
+ /** `anthropic` — the Anthropic mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2275
+ declare function Anthropic(props: IconProps): react.JSX.Element;
2276
+
2277
+ /** `claude` — the Claude mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2278
+ declare function Claude(props: IconProps): react.JSX.Element;
2279
+
2280
+ /** `gemini` — the Google Gemini mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2281
+ declare function Gemini(props: IconProps): react.JSX.Element;
2282
+
2283
+ /** `deepseek` — the DeepSeek mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2284
+ declare function DeepSeek(props: IconProps): react.JSX.Element;
2285
+
2286
+ /** `moonshot` — the Moonshot AI mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2287
+ declare function Moonshot(props: IconProps): react.JSX.Element;
2288
+
2289
+ /**
2290
+ * `glm` — the GLM / Zhipu mark (owner-supplied asset; not in CC0 sets, §12). Already
2291
+ * `currentColor`; the multi-path mark uses an even-odd fill rule. Nominative use only
2292
+ * — a trademark of its owner (see MARKS.md).
2293
+ */
2294
+ declare function GLM(props: IconProps): react.JSX.Element;
2295
+
2296
+ /** `mistral` — the Mistral AI mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2297
+ declare function Mistral(props: IconProps): react.JSX.Element;
2298
+
2299
+ /** `perplexity` — the Perplexity mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2300
+ declare function Perplexity(props: IconProps): react.JSX.Element;
2301
+
2302
+ /** `huggingface` — the Hugging Face mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2303
+ declare function HuggingFace(props: IconProps): react.JSX.Element;
2304
+
2305
+ /** `ollama` — the Ollama mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2306
+ declare function Ollama(props: IconProps): react.JSX.Element;
2307
+
2308
+ /** `qwen` — the QWen mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2309
+ declare function Qwen(props: IconProps): react.JSX.Element;
2310
+
2311
+ /** `meta` — the Meta mark, generated from simple-icons@16.24.0 (CC0-1.0). Nominative use only (§12, MARKS.md). */
2312
+ declare function Meta(props: IconProps): react.JSX.Element;
2313
+
2314
+ /** Every shipped icon name (canonical + aliases). A 1.0 stability contract. */
2315
+ type IconName = "chevron-up" | "chevron-down" | "chevron-left" | "chevron-right" | "arrow-up" | "arrow-down" | "arrow-left" | "arrow-right" | "arrow-up-right" | "arrow-up-left" | "arrow-down-right" | "arrow-down-left" | "external-link" | "menu" | "x" | "search" | "plus" | "minus" | "square-pen" | "trash-2" | "download" | "upload" | "copy" | "share-2" | "funnel" | "filter" | "arrow-up-down" | "settings" | "refresh-cw" | "check" | "send" | "eye" | "eye-off" | "bell" | "bell-off" | "ellipsis" | "ellipsis-vertical" | "save" | "info" | "triangle-alert" | "circle-x" | "circle-check" | "circle-check-big" | "clock" | "loader" | "sun" | "moon" | "lock" | "lock-open" | "circle-question-mark" | "circle-help" | "ban" | "check-check" | "octagon-alert" | "play" | "pause" | "square" | "globe" | "image" | "file" | "link" | "package" | "rocket" | "grid-3x3" | "notebook-pen" | "code-xml" | "trending-up" | "trending-down" | "chart-line" | "chart-column" | "chart-candlestick" | "chart-pie" | "wallet" | "briefcase" | "calendar" | "bookmark" | "percent" | "dollar-sign" | "activity" | "target" | "scale" | "banknote" | "ai-sparkle" | "bot" | "bot-message-square" | "cpu" | "agent-stocky" | "agent-orb" | "agent-droid" | "agent-hex";
2316
+ /** Runtime list of every IconName — the contract surface for dynamic name use. */
2317
+ declare const ICON_NAMES: readonly ["chevron-up", "chevron-down", "chevron-left", "chevron-right", "arrow-up", "arrow-down", "arrow-left", "arrow-right", "arrow-up-right", "arrow-up-left", "arrow-down-right", "arrow-down-left", "external-link", "menu", "x", "search", "plus", "minus", "square-pen", "trash-2", "download", "upload", "copy", "share-2", "funnel", "filter", "arrow-up-down", "settings", "refresh-cw", "check", "send", "eye", "eye-off", "bell", "bell-off", "ellipsis", "ellipsis-vertical", "save", "info", "triangle-alert", "circle-x", "circle-check", "circle-check-big", "clock", "loader", "sun", "moon", "lock", "lock-open", "circle-question-mark", "circle-help", "ban", "check-check", "octagon-alert", "play", "pause", "square", "globe", "image", "file", "link", "package", "rocket", "grid-3x3", "notebook-pen", "code-xml", "trending-up", "trending-down", "chart-line", "chart-column", "chart-candlestick", "chart-pie", "wallet", "briefcase", "calendar", "bookmark", "percent", "dollar-sign", "activity", "target", "scale", "banknote", "ai-sparkle", "bot", "bot-message-square", "cpu", "agent-stocky", "agent-orb", "agent-droid", "agent-hex"];
2318
+ /** Every shipped brand-mark name. Distinct from IconName (logos are not icons, AC-4). */
2319
+ type BrandIconName = "github" | "npm" | "figma" | "notion" | "vercel" | "chromestore" | "vscode" | "linear" | "linkedin" | "x-twitter" | "youtube" | "google" | "reddit" | "openai" | "anthropic" | "claude" | "gemini" | "deepseek" | "moonshot" | "glm" | "mistral" | "perplexity" | "huggingface" | "ollama" | "qwen" | "meta";
2320
+ /** Runtime list of every BrandIconName. */
2321
+ declare const BRAND_ICON_NAMES: readonly ["github", "npm", "figma", "notion", "vercel", "chromestore", "vscode", "linear", "linkedin", "x-twitter", "youtube", "google", "reddit", "openai", "anthropic", "claude", "gemini", "deepseek", "moonshot", "glm", "mistral", "perplexity", "huggingface", "ollama", "qwen", "meta"];
2322
+
2323
+ interface IconComponentProps extends IconProps {
2324
+ /** Icon name from the generated set — a canonical id or a recorded alias. */
2325
+ name: IconName;
2326
+ }
2327
+ /**
2328
+ * Dynamic, data-driven icon: `<Icon name="trending-up" />`. Use this when the icon
2329
+ * is chosen at runtime. For static use, prefer the per-icon named export
2330
+ * (`<TrendingUp />`) — it tree-shakes, whereas this registry intentionally retains
2331
+ * the whole set (importing `Icon` pulls every icon).
2332
+ */
2333
+ declare function Icon({ name, ...props }: IconComponentProps): react.JSX.Element | null;
2334
+
2335
+ /**
2336
+ * MediaSlot — an art-directed, sized, shaped container that displays
2337
+ * heterogeneous media (static image / animated GIF / self-hosted video / an
2338
+ * embedded remote video) with one unifying contract: shape mask, object-fit,
2339
+ * object-position, aspect-ratio (CLS reserve), lazy-load, poster, placeholder,
2340
+ * and a11y. Painted with the shipped `@qball-inc/tokens` `.media-slot` family
2341
+ * from the `preview/media-slot.html` oracle — every visual comes from the token
2342
+ * CSS / token-valued custom properties (no hardcoded hex, no `box-shadow`).
2343
+ *
2344
+ * **Pure React, SSR/static-safe by construction** (research Option A):
2345
+ * renders native `<img>`/`<video>`/`<iframe>`; NO `window`/`document`/
2346
+ * `customElements` access at module-eval OR render. The only client-side work —
2347
+ * the embed facade's click→swap and the reduced-motion probe — lives in an event
2348
+ * handler / effect, so it never runs during SSR.
2349
+ *
2350
+ * **Discriminated `type` → 4 render paths:**
2351
+ * - `image`/`gif` → `<img>` (gif animates natively in the UA).
2352
+ * - `video` → `<video poster preload="none">`, **default muted, NO autoplay**,
2353
+ * native `controls`. gif-as-video = `autoPlay loop muted` (adds `playsInline`;
2354
+ * autoplay is suppressed under `prefers-reduced-motion`).
2355
+ * - `embed` → a **facade**: the provider's real thumbnail + a real `<button>` play
2356
+ * overlay on the shipped dark `--color-scrim`; the real `<iframe>` is swapped in
2357
+ * only on click — **no network until click** (consumer owns CSP/consent). The
2358
+ * facade resets when `src`/`provider` changes, so a reused instance never
2359
+ * auto-loads a new embed.
2360
+ *
2361
+ * The DISPLAY primitive only. Upload / drag-drop / reframe-crop / persistence /
2362
+ * oEmbed resolution are the deferred authoring layer; `adapter` is a
2363
+ * reserved, no-op seam that declares that future API for forward-compatibility.
2364
+ */
2365
+ type MediaSlotType = "image" | "gif" | "video" | "embed";
2366
+ type MediaSlotShape = "rect" | "rounded" | "circle" | "pill";
2367
+ type MediaSlotFit = "cover" | "contain" | "fill";
2368
+ /**
2369
+ * RESERVED no-op seam for the authoring layer (read/persist adapters).
2370
+ * Declared in 1.0 so 1.1 can ship the authoring behavior backward-compatibly;
2371
+ * MediaSlot ignores it entirely at 1.0 (zero persistence behavior).
2372
+ */
2373
+ interface MediaSlotAdapter {
2374
+ read?: (...args: never[]) => unknown;
2375
+ write?: (...args: never[]) => unknown;
2376
+ }
2377
+ interface MediaSlotProps {
2378
+ /** Image/GIF/video URL, or an embed URL. Absent ⇒ the empty-state placeholder. */
2379
+ src?: string;
2380
+ /** Discriminated render path. */
2381
+ type: MediaSlotType;
2382
+ /** Frame shape. Default `rounded`. Ignored when `mask` is set. */
2383
+ shape?: MediaSlotShape;
2384
+ /** Corner radius (px) for `shape="rounded"`. Defaults to the `--radius-md` token. */
2385
+ radius?: number;
2386
+ /** A CSS `clip-path` that overrides `shape`. */
2387
+ mask?: string;
2388
+ /** `object-fit` of the inner media. Default `cover`. */
2389
+ fit?: MediaSlotFit;
2390
+ /** `object-position` of the inner media. Default `50% 50%`. */
2391
+ position?: string;
2392
+ /** CSS `aspect-ratio` (e.g. `"16 / 9"`). Reserves the box → no CLS. Circle defaults to `1 / 1`. */
2393
+ aspectRatio?: string;
2394
+ /** `loading="lazy"` on `<img>` / `preload="none"` on `<video>`. Default `true`. */
2395
+ lazy?: boolean;
2396
+ /** `<video>` poster frame (`type="video"`). */
2397
+ poster?: string;
2398
+ /** Empty-state UI when `src` is absent. Defaults to a token-styled glyph placeholder. */
2399
+ placeholder?: ReactNode;
2400
+ /** Native `controls`. Default `true` (auto-`false` for a gif-as-video loop). */
2401
+ controls?: boolean;
2402
+ /** Autoplay. Default `false`. Suppressed under `prefers-reduced-motion`. */
2403
+ autoPlay?: boolean;
2404
+ /** Muted. Default `true`. */
2405
+ muted?: boolean;
2406
+ /** Loop. Default `false`. `autoPlay + loop + muted` = gif-as-video. */
2407
+ loop?: boolean;
2408
+ /** Provider override/fallback when URL inference can't determine it. Recognized
2409
+ * values: `"youtube"`, `"vimeo"`; any other value treats `src` as the embed URL. */
2410
+ provider?: string;
2411
+ /** Explicit facade thumbnail when the provider has no derivable thumb URL (e.g. Vimeo). */
2412
+ thumbnail?: string;
2413
+ /** Required for informative media; `alt=""` (the default) marks it decorative. */
2414
+ alt?: string;
2415
+ /** Optional in-frame type chip (e.g. "gif"). Rendered only when provided. */
2416
+ badge?: ReactNode;
2417
+ /** Merged onto the `.media-slot` root. The consumer owns WIDTH/layout here. */
2418
+ className?: string;
2419
+ /** RESERVED no-op in 1.0 (authoring seam). */
2420
+ adapter?: MediaSlotAdapter;
2421
+ }
2422
+ declare function MediaSlot({ src, type, shape, radius, mask, fit, position, aspectRatio, lazy, poster, placeholder, controls, autoPlay, muted, loop, provider, thumbnail, alt, badge, className, }: MediaSlotProps): react.JSX.Element;
2423
+
2424
+ export { ALLOWED_ELEMENTS, Activity, AgentDroid, AgentHex, AgentOrb, AgentStocky, AiSparkle, AlertModal, type AlertModalProps, Anthropic, AppBar, type AppBarProps, ArrowDown, ArrowDownLeft, ArrowDownRight, ArrowLeft, ArrowRight, ArrowUp, ArrowUpDown, ArrowUpLeft, ArrowUpRight, AsciiBg, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize, type AvatarStatus, BRAND_ICON_NAMES, type BackgroundProps, Badge, type BadgeProps, type BadgeVariant, Ban, Banknote, Bell, BellOff, Bookmark, Bot, BotMessageSquare, type BrandIconName, Briefcase, Button, type ButtonProps, type ButtonVariant, Calendar, Callout, type CalloutProps, type CalloutVariant, Candlestick, type CandlestickDatum, type CandlestickProps, type CandlestickRange, type CanvasDraw, type CanvasFrame, Card, type CardProps, ChartCandlestick, ChartColumn, ChartLine, ChartPie, Check, CheckCheck, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChromeWebStore, CircleCheck, CircleCheckBig, CircleQuestionMark as CircleHelp, CircleQuestionMark, CircleX, Claude, Clock, CodeXml, type CommandAction, CommandDock, type CommandDockProps, Composer, type ComposerProps, Copy, Cpu, DataTable, type DataTableColumnMeta, type DataTableProps, DeepSeek, DigestCard, type DigestCardProps, type DigestState, Divider, type DividerProps, DollarSign, Download, Ellipsis, EllipsisVertical, EmptyStateFig, type EmptyStateFigProps, ErrorStateFig, type ErrorStateFigProps, ExternalLink, Eye, EyeOff, Field, type FieldProps, Figma, File, Funnel as Filter, Funnel, GLM, Gemini, GitHub, Globe, GlyphsBg, Google, Grid3x3, GridBg, GroundingFlag, type GroundingFlagProps, type GroundingVariant, HuggingFace, ICON_NAMES, Icon, type IconName, type IconProps, Image, Info, Input, type InputProps, Linear, Link, LinkedIn, Loader, Lock, LockOpen, MarkdownRenderer, type MarkdownRendererProps, MediaSlot, type MediaSlotAdapter, type MediaSlotFit, type MediaSlotProps, type MediaSlotShape, type MediaSlotType, Menu, Meta, Meter, type MeterProps, type MeterVariant, Minus, Mistral, Modal, ModalClose, ModalContent, type ModalContentProps, ModalDescription, ModalTitle, ModalTrigger, Moon, Moonshot, NPM, NotebookPen, NotificationBell, type NotificationBellProps, NotificationCenter, type NotificationCenterProps, type NotificationItemData, type NotificationKind, Notion, OctagonAlert, Ollama, OpenAI, Package, Pause, Percent, Perplexity, Play, Plus, Qwen, Reddit, RefreshCw, Rocket, Save, Scale, Scrim, type ScrimProps, Search, SearchIcon, type SearchItem, type SearchProps, SecretInput, type SecretInputProps, Segmented, SegmentedItem, type SegmentedItemProps, type SegmentedProps, Select, SelectItem, type SelectItemProps, type SelectProps, Send, Settings, Share2, Skeleton, type SkeletonProps, type SkeletonShape, Sparkline, type SparklineDirection, type SparklineProps, Spinner, type SpinnerProps, type SpinnerSize, Square, SquarePen, Stat, type StatDirection, type StatProps, type StreamError, type StreamEvent, type StreamToken, Sun, Surface, type SurfaceProps, Switch, type SwitchProps, Tabs, TabsContent, type TabsContentProps, TabsList, type TabsListProps, type TabsProps, TabsTrigger, type TabsTriggerProps, Target, Terminal, type TerminalMessage, type TerminalProps, type TerminalRole, type Theme, ThemeToggle, type ThemeToggleProps, type ToastOptions, Toaster, ToolUseIndicator, type ToolUseIndicatorProps, type ToolUseState, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, Trash2, TrendingDown, TrendingUp, TriangleAlert, Upload, type UseStreamingResult, UserMenu, UserMenuContent, type UserMenuContentProps, UserMenuGroup, type UserMenuGroupProps, UserMenuHeader, type UserMenuHeaderProps, UserMenuItem, type UserMenuItemProps, UserMenuSeparator, type UserMenuSeparatorProps, UserMenuTrigger, type UserMenuTriggerProps, VSCode, Vercel, Wallet, X, XTwitter, YouTube, parseStreamFrame, streamFromResponse, toast, useCanvas2D, useStreaming };