@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.
- package/LICENSE +201 -0
- package/MARKS.md +45 -0
- package/dist/index.cjs +3899 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2424 -0
- package/dist/index.d.ts +2424 -0
- package/dist/index.js +3678 -0
- package/dist/index.js.map +1 -0
- package/package.json +107 -0
package/dist/index.d.cts
ADDED
|
@@ -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 };
|