@platned/ui 0.1.4 → 0.5.1

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/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react from 'react';
2
- import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes } from 'react';
2
+ import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, HTMLAttributes, LabelHTMLAttributes, TextareaHTMLAttributes, ReactElement, RefObject, AnchorHTMLAttributes, TdHTMLAttributes, ThHTMLAttributes, Key } from 'react';
3
+ import { ClassValue } from 'clsx';
3
4
 
4
5
  type ButtonVariant = 'primary' | 'neutral' | 'subtle' | 'danger' | 'danger-subtle';
5
6
  type ButtonSize = 'lg' | 'md' | 'sm';
@@ -8,8 +9,20 @@ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
8
9
  size?: ButtonSize;
9
10
  leadingIcon?: ReactNode;
10
11
  trailingIcon?: ReactNode;
12
+ /**
13
+ * Render the single child element instead of a `<button>` — e.g. a router `Link`, so a
14
+ * navigation action can look like a button without nesting an anchor inside one.
15
+ */
16
+ asChild?: boolean;
17
+ /**
18
+ * Swaps the leading icon for a spinner and disables the button. `aria-busy` is set so
19
+ * assistive tech reports the pending state rather than only the disabled one.
20
+ */
21
+ loading?: boolean;
22
+ /** Announced while `loading`. Defaults to the button's own content. */
23
+ loadingLabel?: string;
11
24
  }
12
- declare function Button({ variant, size, leadingIcon, trailingIcon, children, className, ...props }: ButtonProps): react.JSX.Element;
25
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
13
26
 
14
27
  type IconButtonVariant = 'primary' | 'neutral' | 'subtle';
15
28
  interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
@@ -17,8 +30,11 @@ interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
17
30
  size?: ButtonSize;
18
31
  /** Required for accessibility — no visible text label */
19
32
  'aria-label': string;
33
+ /** Render the single child element instead of a `<button>` — e.g. a router `Link`. */
34
+ asChild?: boolean;
35
+ children?: ReactNode;
20
36
  }
21
- declare function IconButton({ variant, size, children, className, ...props }: IconButtonProps): react.JSX.Element;
37
+ declare const IconButton: react.ForwardRefExoticComponent<IconButtonProps & react.RefAttributes<HTMLButtonElement>>;
22
38
 
23
39
  type ButtonGroupVariant = 'primary' | 'neutral' | 'filter';
24
40
  type ButtonGroupAlign = 'justify' | 'start' | 'end' | 'center' | 'stack';
@@ -81,140 +97,429 @@ interface AvatarBlockProps {
81
97
  }
82
98
  declare function AvatarBlock({ children, title, description, className }: AvatarBlockProps): react.JSX.Element;
83
99
 
84
- interface NavItemProps {
85
- icon?: ReactNode;
86
- label: string;
87
- isActive?: boolean;
88
- /** Red indicator dot at top-right corner (e.g. unread count) */
89
- indicator?: boolean;
90
- /** Collapsed mode — icon only, label hidden */
91
- collapsed?: boolean;
92
- className?: string;
93
- }
94
- declare function NavItem({ icon, label, isActive, indicator, collapsed, className, }: NavItemProps): react.JSX.Element;
95
-
96
100
  type InputSize = 'lg' | 'md' | 'sm';
97
101
  interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
98
102
  label?: string;
99
103
  description?: string;
100
- /** Red border + message shown below the input */
104
+ /** Red border + message shown below the input. Also sets `aria-invalid`. */
101
105
  error?: string;
102
106
  /** Neutral helper text shown below the input (hidden when error is set) */
103
107
  hint?: string;
104
108
  size?: InputSize;
105
109
  leadingIcon?: ReactNode;
106
110
  trailingIcon?: ReactNode;
111
+ /** Interactive trailing slot (e.g. a show/hide password button) — unlike
112
+ * `trailingIcon` it receives pointer events. */
113
+ trailingAction?: ReactNode;
107
114
  }
108
115
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
116
+ /**
117
+ * The bare `<input>` with the field wiring applied and no label/message chrome — for
118
+ * `InputGroup` and any composition that supplies its own `Field`.
119
+ */
120
+ interface InputControlProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
121
+ size?: InputSize;
122
+ invalid?: boolean;
123
+ }
124
+ declare const InputControl: react.ForwardRefExoticComponent<InputControlProps & react.RefAttributes<HTMLInputElement>>;
125
+
126
+ /**
127
+ * The label / description / error / control wiring, in one place.
128
+ *
129
+ * This exists because of the single largest defect the 0.3.0 audit found. `Input`,
130
+ * `Textarea`, `Select` and `DatePicker` all accepted `label`, `description`, `error` and
131
+ * `hint`, rendered them, and then connected **none** of them:
132
+ *
133
+ * - `<label htmlFor={id}>` used the caller's `id` with no fallback. Omit `id` — the
134
+ * common case — and `htmlFor` was `undefined`, so the label pointed at nothing.
135
+ * Clicking it did nothing and assistive tech announced an unlabelled field.
136
+ * - `description`, `error` and `hint` were bare `<p>` elements with no `id`, and no
137
+ * control ever referenced them. A consumer could not fix this from outside either:
138
+ * passing `aria-describedby` had nothing to point at.
139
+ * - `error` drove the border colour and nothing else. No `aria-invalid`, no `role`, no
140
+ * live region — so an async validation failure was completely silent.
141
+ *
142
+ * For scale: `aria-describedby`, `aria-invalid` and `aria-required` appeared nowhere in
143
+ * `src/`, and `useId` was used exactly once in the whole library — in `Sparkline`, for an
144
+ * SVG gradient.
145
+ *
146
+ * `Field` generates the ids and hands them down through context, so a control only has to
147
+ * spread `useFieldControl()` onto its input element. It is also usable directly for
148
+ * controls the library does not wrap, which is why the parts are exported.
149
+ */
150
+ interface FieldContextValue {
151
+ controlId: string;
152
+ /**
153
+ * Id of the `FieldLabel`, for controls whose accessible name cannot come from a
154
+ * `<label for>` association. A `<button>` is named by its own contents, so the Select
155
+ * trigger has to point `aria-labelledby` at the label explicitly or it announces only
156
+ * the chosen value.
157
+ */
158
+ labelId: string;
159
+ descriptionId: string;
160
+ errorId: string;
161
+ hintId: string;
162
+ hasDescription: boolean;
163
+ hasError: boolean;
164
+ hasHint: boolean;
165
+ invalid: boolean;
166
+ required: boolean;
167
+ disabled: boolean;
168
+ size: InputSize;
169
+ }
170
+ declare function useFieldContext(): FieldContextValue | null;
171
+ /**
172
+ * Props for the control itself. Spread onto the `<input>`/`<select>`/`<textarea>`.
173
+ *
174
+ * `aria-describedby` deliberately lists description *and* message: a field can carry
175
+ * both persistent guidance and a transient error, and a screen reader should read both
176
+ * rather than have the error replace the instruction that explains the format.
177
+ */
178
+ declare function useFieldControl(): {
179
+ id: string | undefined;
180
+ 'aria-describedby': string | undefined;
181
+ 'aria-invalid': true | undefined;
182
+ 'aria-required': true | undefined;
183
+ disabled: boolean | undefined;
184
+ };
185
+ type FieldOrientation = 'vertical' | 'horizontal';
186
+ interface FieldProps extends HTMLAttributes<HTMLDivElement> {
187
+ children: ReactNode;
188
+ /** Supply to control the id yourself; otherwise one is generated. */
189
+ id?: string;
190
+ size?: InputSize;
191
+ invalid?: boolean;
192
+ required?: boolean;
193
+ disabled?: boolean;
194
+ /** `horizontal` puts the label beside the control — for switches and checkboxes. */
195
+ orientation?: FieldOrientation;
196
+ /** Set when a `FieldDescription` is rendered. Inferred by the wrapped controls. */
197
+ hasDescription?: boolean;
198
+ hasError?: boolean;
199
+ hasHint?: boolean;
200
+ }
201
+ declare function Field({ children, id, size, invalid, required, disabled, orientation, hasDescription, hasError, hasHint, className, ...rest }: FieldProps): react.JSX.Element;
202
+ interface FieldLabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
203
+ children: ReactNode;
204
+ }
205
+ declare function FieldLabel({ children, className, htmlFor, ...rest }: FieldLabelProps): react.JSX.Element;
206
+ interface FieldTextProps extends HTMLAttributes<HTMLParagraphElement> {
207
+ children: ReactNode;
208
+ }
209
+ /** Persistent guidance, shown above the control and announced with it. */
210
+ declare function FieldDescription({ children, className, ...rest }: FieldTextProps): react.JSX.Element;
211
+ /**
212
+ * Validation message. `role="alert"` because an error that appears after submit —
213
+ * asynchronously, without focus moving — is otherwise never announced at all.
214
+ */
215
+ declare function FieldError({ children, className, ...rest }: FieldTextProps): react.JSX.Element;
216
+ /** Neutral helper text. Suppressed while an error is showing, so the two never stack. */
217
+ declare function FieldHint({ children, className, ...rest }: FieldTextProps): react.JSX.Element;
218
+ interface FieldGroupProps extends HTMLAttributes<HTMLDivElement> {
219
+ children: ReactNode;
220
+ }
221
+ /** Stacks several `Field`s with consistent rhythm. */
222
+ declare function FieldGroup({ children, className, ...rest }: FieldGroupProps): react.JSX.Element;
223
+ interface FieldSetProps extends HTMLAttributes<HTMLFieldSetElement> {
224
+ children: ReactNode;
225
+ }
226
+ /**
227
+ * A real `<fieldset>`. Required for radio groups and checkbox groups: the group needs a
228
+ * name of its own, and only `<legend>` gives it one that is announced before each option.
229
+ */
230
+ declare function FieldSet({ children, className, ...rest }: FieldSetProps): react.JSX.Element;
231
+ interface FieldLegendProps extends HTMLAttributes<HTMLLegendElement> {
232
+ children: ReactNode;
233
+ /** `label` matches a field label's weight; `legend` is the larger section heading. */
234
+ variant?: 'legend' | 'label';
235
+ }
236
+ declare function FieldLegend({ children, variant, className, ...rest }: FieldLegendProps): react.JSX.Element;
237
+ interface FieldSeparatorProps extends HTMLAttributes<HTMLDivElement> {
238
+ }
239
+ declare function FieldSeparator({ className, ...rest }: FieldSeparatorProps): react.JSX.Element;
240
+
241
+ interface ControlSizeProviderProps {
242
+ size: InputSize;
243
+ children: ReactNode;
244
+ }
245
+ declare function ControlSizeProvider({ size, children }: ControlSizeProviderProps): react.JSX.Element;
246
+ /**
247
+ * Resolve a control's size: an explicit prop, else the enclosing container's default,
248
+ * else `md`.
249
+ *
250
+ * Call it unconditionally at the top of the component — it is a hook.
251
+ */
252
+ declare function useControlSize(explicit?: InputSize): InputSize;
109
253
 
110
254
  interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
111
255
  label?: string;
112
256
  description?: string;
257
+ /** Red border + message shown below the control. Also sets `aria-invalid`. */
113
258
  error?: string;
114
259
  hint?: string;
115
260
  size?: InputSize;
116
261
  }
117
262
  declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
263
+ interface TextareaControlProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
264
+ size?: InputSize;
265
+ invalid?: boolean;
266
+ }
267
+ /** The bare `<textarea>` with field wiring, for compositions that supply their own `Field`. */
268
+ declare const TextareaControl: react.ForwardRefExoticComponent<TextareaControlProps & react.RefAttributes<HTMLTextAreaElement>>;
118
269
 
119
270
  interface SelectOption {
120
271
  value: string;
121
272
  label: string;
273
+ disabled?: boolean;
274
+ }
275
+ interface SelectOptionGroup {
276
+ label: string;
277
+ options: SelectOption[];
278
+ }
279
+ interface SelectControlProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'defaultValue' | 'onChange' | 'children' | 'type'> {
280
+ /** Flat options, or groups which render as a labelled `role="group"`. */
281
+ options: (SelectOption | SelectOptionGroup)[];
282
+ value?: string | null;
283
+ defaultValue?: string | null;
284
+ onValueChange?: (value: string) => void;
285
+ /**
286
+ * Submits with a surrounding form, through a hidden input. Note that hidden inputs are
287
+ * exempt from constraint validation, so `required` no longer blocks submit — see the
288
+ * note on `Select`.
289
+ */
290
+ name?: string;
291
+ size?: InputSize;
292
+ invalid?: boolean;
293
+ placeholder?: string;
294
+ }
295
+ /**
296
+ * The bare trigger and its listbox, with field wiring and no label/message chrome — for
297
+ * `Select` and any composition that supplies its own `Field`.
298
+ */
299
+ declare const SelectControl: react.ForwardRefExoticComponent<SelectControlProps & react.RefAttributes<HTMLButtonElement>>;
300
+ interface SelectProps extends SelectControlProps {
301
+ label?: string;
302
+ description?: string;
303
+ /** Red border + message shown below the control. Also sets `aria-invalid`. */
304
+ error?: string;
305
+ hint?: string;
306
+ required?: boolean;
122
307
  }
123
- interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'size'> {
308
+ /**
309
+ * Single-select dropdown: a trigger and a portalled listbox.
310
+ *
311
+ * Through 0.4.0 this wrapped a native `<select>`, which was the right call for its keyboard
312
+ * contract and the wrong one for everything visual: the option popup is drawn by the OS and
313
+ * cannot be styled at all, so a Select never matched the `DropdownMenu` and `Combobox`
314
+ * panels sitting beside it on the same filter row. It is now the same panel as those, and
315
+ * the keyboard contract it used to inherit is implemented rather than borrowed — arrows,
316
+ * Home/End, typeahead, Escape, and Tab that leaves without committing.
317
+ *
318
+ * Two consequences of dropping the native element, neither papered over:
319
+ *
320
+ * - **No OS picker on mobile.** The wheel/sheet a native select opens is gone.
321
+ * - **`required` no longer blocks submit.** The value posts through a hidden input, and
322
+ * hidden inputs are exempt from constraint validation. `required` remains semantic and
323
+ * visual — `aria-required` on the control and the `*` on its label — which is already
324
+ * true of `Combobox`, `RadioGroup` and `MultiSelectCard`. In react-hook-form, register
325
+ * it with `Controller` rather than `register`.
326
+ *
327
+ * For a list long enough to need filtering, use `Combobox`.
328
+ */
329
+ declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLButtonElement>>;
330
+
331
+ interface DatePickerProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
124
332
  label?: string;
125
333
  description?: string;
334
+ /** Red border + message shown below the control. Also sets `aria-invalid`. */
126
335
  error?: string;
127
336
  hint?: string;
128
337
  size?: InputSize;
129
- options: SelectOption[];
130
- placeholder?: string;
131
338
  }
132
- declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLSelectElement>>;
339
+ /**
340
+ * A native `<input type="date">`.
341
+ *
342
+ * The `::-webkit-calendar-picker-indicator` styling below is Chromium-only — on Firefox
343
+ * and Safari the native affordance differs, so the drawn `LuCalendar` sits alongside
344
+ * whatever the platform renders rather than replacing it. That is a known limitation of
345
+ * this component, not a bug to paper over: for a real month grid, range selection, locale
346
+ * control or min/max navigation, use `Calendar` and `DateField` instead.
347
+ */
348
+ declare const DatePicker: react.ForwardRefExoticComponent<DatePickerProps & react.RefAttributes<HTMLInputElement>>;
133
349
 
134
350
  type StepStatus = 'complete' | 'active' | 'upcoming';
135
351
  interface StepItem {
136
352
  label: string;
137
353
  status: StepStatus;
138
354
  }
355
+ type StepperSize = 'sm' | 'md';
139
356
  interface StepperProps {
140
357
  steps: StepItem[];
358
+ /** Matches Figma's `Size` axis on the `Stepper` component set. */
359
+ size?: StepperSize;
360
+ /** Names the list. Defaults to `Progress`. Override for a non-English UI. */
361
+ label?: string;
141
362
  className?: string;
142
363
  }
143
- declare function Stepper({ steps, className }: StepperProps): react.JSX.Element;
364
+ declare function Stepper({ steps, size, label, className }: StepperProps): react.JSX.Element;
144
365
 
366
+ /** Matches Figma's `Size` axis on `Multiselect Card` (`Default | Small`). */
367
+ type MultiSelectCardSize = 'default' | 'sm';
145
368
  interface MultiSelectCardProps {
146
369
  icon: ReactNode;
147
370
  title: string;
148
371
  description?: string;
149
372
  selected: boolean;
150
373
  onToggle: () => void;
374
+ /**
375
+ * Figma has had this axis since 0.2.0; the 0.3.0 CHANGELOG recorded it as "left alone
376
+ * pending a design decision". `Default` and `Small` differ only in padding, icon box and
377
+ * type step, so there was nothing to decide.
378
+ */
379
+ size?: MultiSelectCardSize;
380
+ disabled?: boolean;
151
381
  className?: string;
152
382
  }
153
- declare function MultiSelectCard({ icon, title, description, selected, onToggle, className, }: MultiSelectCardProps): react.JSX.Element;
383
+ declare function MultiSelectCard({ icon, title, description, selected, onToggle, size, disabled, className, }: MultiSelectCardProps): react.JSX.Element;
154
384
 
155
- interface ColumnDef<T> {
156
- key: string;
157
- header: string;
158
- /** CSS width value — e.g. "320px", "10rem". When grow is true, acts as min-width. */
159
- width: string;
160
- /** When true the column fills remaining row width; width becomes a min-width floor. */
161
- grow?: boolean;
162
- render: (row: T) => ReactNode;
385
+ type SwitchSize = 'sm' | 'md';
386
+ interface SwitchProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'value' | 'type'> {
387
+ /** Controlled. Omit and pass `defaultChecked` for uncontrolled. */
388
+ checked?: boolean;
389
+ defaultChecked?: boolean;
390
+ onCheckedChange?: (checked: boolean) => void;
391
+ /** Visible text beside the switch. Doubles as the accessible name. */
392
+ label?: ReactNode;
393
+ /** Second line under the label. Matches Figma's `Supporting text` axis. */
394
+ description?: ReactNode;
395
+ /** Track size. `sm` is 36×20, `md` is 44×24. */
396
+ size?: SwitchSize;
163
397
  }
164
- declare function DataTable<T>({ columns, rows, getRowKey, className, onRowClick, }: {
165
- columns: ColumnDef<T>[];
166
- rows: T[];
167
- getRowKey: (row: T, index: number) => React.Key;
168
- className?: string;
169
- onRowClick?: (row: T) => void;
170
- }): react.JSX.Element;
171
- /** Primary bold text + optional muted subtitle — for lead entity/name cells */
172
- declare function TableCellLeadText({ primary, secondary, }: {
173
- primary: string;
174
- secondary?: string;
175
- }): react.JSX.Element;
176
- /** Plain text cell — muted (secondary) by default, pass muted=false for primary colour */
177
- declare function TableCellText({ children, muted, }: {
178
- children: ReactNode;
179
- muted?: boolean;
180
- }): react.JSX.Element;
181
- /** Small outlined chip — Supplier / Customer, entity type labels etc. */
182
- declare function TableCellBadge({ label }: {
183
- label: string;
184
- }): react.JSX.Element;
185
- /** Coloured pill with a leading dot — pass explicit colours for full design-system flexibility */
186
- declare function TableCellStatusPill({ label, dotColor, backgroundColor, textColor, }: {
187
- label: string;
188
- dotColor: string;
189
- backgroundColor: string;
190
- textColor: string;
191
- }): react.JSX.Element;
192
- /** Mini horizontal progress bar with a percentage label below */
193
- declare function TableCellProgress({ percent, barColor, }: {
194
- percent: number;
195
- barColor?: string;
196
- }): react.JSX.Element;
398
+ /**
399
+ * An on/off switch — a setting that takes effect immediately, with no save step.
400
+ *
401
+ * **Renamed from `Toggle` in 0.4.0.** It was always a switch: `role="switch"`,
402
+ * `aria-checked`, and the track/knob geometry taken from Figma. The name was blocking,
403
+ * because "Toggle" means something else in shadcn/ui and in most design systems — a
404
+ * pressed-state *button*, like a bold button in a text toolbar. That component now exists
405
+ * here under the name everyone expects, and the two are not interchangeable:
406
+ *
407
+ * - `Switch` — `role="switch"`, "on"/"off", applies immediately. A setting.
408
+ * - `Toggle` — `aria-pressed`, "pressed"/"not pressed". A button whose effect persists.
409
+ *
410
+ * Figma calls its set `Toggle` with a `Pressed` axis, but its geometry and `_Toggle base`
411
+ * match this component exactly, so Figma's `Toggle` **is** this switch. Figma has no
412
+ * pressed-button equivalent yet; that is a gap on the design side, recorded in the
413
+ * CHANGELOG rather than papered over here.
414
+ */
415
+ declare const Switch: react.ForwardRefExoticComponent<SwitchProps & react.RefAttributes<HTMLButtonElement>>;
197
416
 
198
- interface StatTileProps {
417
+ type ToggleSize = 'sm' | 'md' | 'lg';
418
+ type ToggleVariant = 'ghost' | 'outline';
419
+ interface ToggleProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'type'> {
420
+ /** Controlled pressed state. Omit and pass `defaultPressed` for uncontrolled. */
421
+ pressed?: boolean;
422
+ defaultPressed?: boolean;
423
+ onPressedChange?: (pressed: boolean) => void;
424
+ size?: ToggleSize;
425
+ variant?: ToggleVariant;
426
+ children?: ReactNode;
427
+ }
428
+ /**
429
+ * A button with a sticky pressed state — bold in a text toolbar, a map layer on/off, a
430
+ * filter that stays applied.
431
+ *
432
+ * **New in 0.4.0, and not what `Toggle` used to be.** Through 0.3.0 this name belonged to
433
+ * the on/off switch, which is now `Switch`. The two look similar and mean different things:
434
+ *
435
+ * - `Toggle` — `aria-pressed`. A *button*. "Bold is pressed."
436
+ * - `Switch` — `role="switch"` + `aria-checked`. A *setting*. "Notifications are on."
437
+ *
438
+ * `aria-pressed` rather than `aria-checked` is the whole distinction as far as assistive
439
+ * tech is concerned, and it is why this is not just `Switch` with different styling.
440
+ *
441
+ * An icon-only toggle needs `aria-label`, exactly as `IconButton` does — there is no visible
442
+ * text to name it.
443
+ */
444
+ declare const Toggle: react.ForwardRefExoticComponent<ToggleProps & react.RefAttributes<HTMLButtonElement>>;
445
+ type ToggleGroupType = 'single' | 'multiple';
446
+ interface ToggleGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
447
+ children: ReactNode;
448
+ /** `single` behaves like a radio group; `multiple` like a set of checkboxes. */
449
+ type?: ToggleGroupType;
450
+ value?: string | string[];
451
+ defaultValue?: string | string[];
452
+ onValueChange?: (value: string | string[]) => void;
453
+ /** Names the group. Required by the APG for a toolbar-style group. */
199
454
  label: string;
200
- value: string | number;
201
- dotColor?: string;
202
- className?: string;
455
+ disabled?: boolean;
456
+ orientation?: 'horizontal' | 'vertical';
457
+ }
458
+ /**
459
+ * A set of related toggles sharing one selection.
460
+ *
461
+ * `role="group"` with `aria-pressed` on each child, and a roving tabindex so the set is one
462
+ * tab stop with arrow keys inside — the same contract `SegmentedControl` was missing before
463
+ * 0.4.0.
464
+ *
465
+ * How this differs from the neighbours, since three components in this library now look
466
+ * similar: `SegmentedControl` is a `radiogroup` for choosing *one* of a small set of views,
467
+ * and always has exactly one selection. `ToggleGroup type="multiple"` allows none or many.
468
+ * `ToggleGroup type="single"` allows none or one — the deselectable case a radio group
469
+ * cannot express.
470
+ */
471
+ declare function ToggleGroup({ children, type, value: valueProp, defaultValue, onValueChange, label, disabled, orientation, className, ...rest }: ToggleGroupProps): react.JSX.Element;
472
+ interface ToggleGroupItemProps extends Omit<ToggleProps, 'pressed' | 'defaultPressed'> {
473
+ value: string;
203
474
  }
204
- declare function StatTile({ label, value, dotColor, className }: StatTileProps): react.JSX.Element;
475
+ /** A `Toggle` wired to its `ToggleGroup`, with the roving tabindex applied. */
476
+ declare const ToggleGroupItem: react.ForwardRefExoticComponent<ToggleGroupItemProps & react.RefAttributes<HTMLButtonElement>>;
205
477
 
206
- interface ToggleProps {
207
- checked: boolean;
208
- onChange: (checked: boolean) => void;
478
+ type InputOTPMode = 'numeric' | 'alphanumeric';
479
+ interface InputOTPProps {
480
+ /** Number of characters. Default `6`. */
481
+ length?: number;
482
+ value?: string;
483
+ defaultValue?: string;
484
+ onValueChange?: (value: string) => void;
485
+ /** Fired once the last slot is filled. */
486
+ onComplete?: (value: string) => void;
487
+ mode?: InputOTPMode;
488
+ /** Draws a gap after this many slots — `3` for a `123 456` code. */
489
+ groupAfter?: number;
490
+ /** Accessible name. Default `Verification code`. */
209
491
  label?: string;
210
492
  disabled?: boolean;
493
+ invalid?: boolean;
494
+ autoFocus?: boolean;
495
+ className?: string;
211
496
  }
212
- declare function Toggle({ checked, onChange, label, disabled }: ToggleProps): react.JSX.Element;
497
+ /**
498
+ * A one-time-code field — the boxed digits from a 2FA or email-verification flow.
499
+ *
500
+ * **One real input, N drawn boxes.** The obvious implementation is N separate `<input>`s,
501
+ * and it is the wrong one: it makes the code N tab stops, breaks paste (the browser puts all
502
+ * six characters in the first box), fights password managers and SMS autofill, and announces
503
+ * "edit text, blank" six times. Instead there is a single input holding the whole value —
504
+ * with `autocomplete="one-time-code"`, so iOS and Android offer the code from the incoming
505
+ * message — rendered transparently over the boxes, which are decorative.
506
+ *
507
+ * That means paste, autofill, undo, selection and screen readers all get the real value, and
508
+ * the caret position simply drives which box is highlighted.
509
+ */
510
+ declare const InputOTP: react.ForwardRefExoticComponent<InputOTPProps & react.RefAttributes<HTMLInputElement>>;
213
511
 
214
512
  interface FileDropZoneProps {
215
513
  className?: string;
514
+ /** Caption shown under "Upload file". Defaults to the generic document hint. */
515
+ description?: string;
516
+ accept?: string;
517
+ /** Files above this size are rejected before any upload starts. */
518
+ maxSizeBytes?: number;
519
+ onFileSelected?: (file: File) => void;
520
+ disabled?: boolean;
216
521
  }
217
- declare function FileDropZone({ className }: FileDropZoneProps): react.JSX.Element;
522
+ declare function FileDropZone({ className, description, accept, maxSizeBytes, onFileSelected, disabled, }: FileDropZoneProps): react.JSX.Element;
218
523
 
219
524
  declare function FormCard({ children, className, }: {
220
525
  children: ReactNode;
@@ -231,37 +536,46 @@ interface FormCardFooterProps {
231
536
  onContinue?: () => void;
232
537
  continueLabel?: string;
233
538
  backDisabled?: boolean;
539
+ continueDisabled?: boolean;
234
540
  }
235
- declare function FormCardFooter({ onSaveDraft, onBack, onContinue, continueLabel, backDisabled, }: FormCardFooterProps): react.JSX.Element;
236
-
237
- type DocumentStatus = 'uploaded' | 'under-review' | 'processing' | 'missing' | 'not-provided';
238
- interface DocumentRowProps {
239
- title: string;
240
- required: boolean;
241
- description: string;
242
- status: DocumentStatus;
243
- fileName?: string;
244
- fileSize?: string;
245
- fileType?: string;
246
- }
247
- declare function DocumentRow({ title, required, description, status, fileName, fileSize, fileType, }: DocumentRowProps): react.JSX.Element;
541
+ declare function FormCardFooter({ onSaveDraft, onBack, onContinue, continueLabel, backDisabled, continueDisabled, }: FormCardFooterProps): react.JSX.Element;
248
542
 
249
- interface ModalProps {
250
- isOpen: boolean;
251
- onClose: () => void;
252
- title: string;
253
- subtitle?: string;
254
- children: ReactNode;
255
- footer?: ReactNode;
256
- maxWidth?: string;
543
+ type BadgeColor = 'gray' | 'red' | 'yellow' | 'lime' | 'green' | 'teal' | 'blue' | 'pink' | 'slate';
544
+ type BadgeSize = 'sm' | 'lg';
545
+ type BadgeVariant = 'default' | 'subtle';
546
+ interface BadgeProps {
547
+ label: string;
548
+ color?: BadgeColor;
549
+ size?: BadgeSize;
550
+ variant?: BadgeVariant;
551
+ indicator?: boolean;
552
+ onClose?: () => void;
553
+ className?: string;
257
554
  }
258
- declare function Modal({ isOpen, onClose, title, subtitle, children, footer, maxWidth }: ModalProps): react.JSX.Element | null;
555
+ declare function Badge({ label, color, size, variant, indicator, onClose, className, }: BadgeProps): react.JSX.Element;
259
556
 
557
+ /**
558
+ * The nine-hue categorical palette from `badge.css`, which is what roles want: a role is a
559
+ * *category*, not a severity, so it must not borrow the semantic tones — a `danger`-coloured
560
+ * role badge would imply the role itself is a problem.
561
+ */
562
+ type RoleBadgeTone = 'slate' | 'blue' | 'green' | 'yellow' | 'red' | 'pink' | 'teal' | 'lime' | 'gray';
260
563
  interface RoleBadgeProps {
261
564
  role: string;
262
565
  size?: 'sm' | 'md';
566
+ /**
567
+ * Override the name-map lookup. Use this for roles the map does not know, in preference to
568
+ * `color` — it stays on the token layer and re-themes with the rest of the badge palette.
569
+ */
570
+ tone?: RoleBadgeTone;
571
+ /**
572
+ * @deprecated Bypasses the design tokens — pass `tone` instead. Raw 6-digit hex; text uses
573
+ * the hex and the background a 12% tint of it. Kept for role colours that genuinely come
574
+ * from API data rather than from the design system.
575
+ */
576
+ color?: string | null;
263
577
  }
264
- declare function RoleBadge({ role, size }: RoleBadgeProps): react.JSX.Element;
578
+ declare function RoleBadge({ role, size, tone, color }: RoleBadgeProps): react.JSX.Element;
265
579
 
266
580
  interface RoleOption {
267
581
  role: string;
@@ -272,29 +586,3027 @@ interface RoleComboBoxProps {
272
586
  value: string;
273
587
  onChange: (role: string) => void;
274
588
  options?: RoleOption[];
589
+ /** Accessible name. Defaults to `Role`. */
590
+ label?: string;
591
+ size?: InputSize;
592
+ disabled?: boolean;
593
+ className?: string;
594
+ }
595
+ /**
596
+ * Role picker.
597
+ *
598
+ * Rebuilt in 0.4.0 as a thin wrapper over `Combobox`, which is all it should ever have been.
599
+ * The version it replaces was the least correct component in the library and is worth
600
+ * recording, because every one of these was a category of bug rather than a detail:
601
+ *
602
+ * - `role="combobox"` sat on a `<div>` while the real `<input>` had no role and none of the
603
+ * state attributes. Under ARIA 1.2 the role belongs on the input.
604
+ * - The `role="listbox"` had no `id`, so `aria-controls` could not point at it, and there
605
+ * was no `aria-activedescendant` at all.
606
+ * - No arrow keys, no Home/End, no wrap. The **selected** option had no `tabIndex`, so it
607
+ * was mouse-only, while every *other* option was individually tabbable.
608
+ * - Escape worked on the trigger but not on the search input or the options, and closing
609
+ * never returned focus to the trigger.
610
+ * - The tick was a literal `✓` text node, announced as "check mark" mid-option.
611
+ * - It bypassed the token system entirely — `border-blue-500`, `bg-white`, `bg-blue-50`,
612
+ * `text-blue-600`, `text-sm` — and built its className with a template literal. Both are
613
+ * explicitly against the rules in CLAUDE.md, and the raw colours meant it would not theme.
614
+ *
615
+ * It stays a preset rather than becoming `Combobox` usage at every call site only because it
616
+ * renders a `RoleBadge` per option, which `renderOption` exists for.
617
+ */
618
+ declare function RoleComboBox({ value, onChange, options, label, size, disabled, className, }: RoleComboBoxProps): react.JSX.Element;
619
+
620
+ interface ComboboxOption<T = string> {
621
+ value: T;
622
+ label: string;
623
+ description?: string;
624
+ disabled?: boolean;
625
+ /** Optional group heading. Options sharing a group are rendered together. */
626
+ group?: string;
627
+ }
628
+ interface ComboboxProps<T extends string = string> {
629
+ options: ComboboxOption<T>[];
630
+ value?: T | null;
631
+ defaultValue?: T | null;
632
+ onValueChange?: (value: T | null) => void;
633
+ /** Accessible name. Required unless the combobox is inside a `Field` with a label. */
634
+ label?: string;
635
+ placeholder?: string;
636
+ size?: InputSize;
637
+ disabled?: boolean;
638
+ invalid?: boolean;
639
+ /** Allow clearing back to `null` by selecting the chosen option again. Default `true`. */
640
+ clearable?: boolean;
641
+ /** Override the filter. Default is a case-insensitive substring match on `label`. */
642
+ filter?: (option: ComboboxOption<T>, query: string) => boolean;
643
+ /** Shown when nothing matches. */
644
+ emptyMessage?: ReactNode;
645
+ /** Custom option rendering. Receives the option and whether it is selected. */
646
+ renderOption?: (option: ComboboxOption<T>, selected: boolean) => ReactNode;
647
+ className?: string;
648
+ }
649
+ /**
650
+ * Single-select combobox with a text filter — an autocomplete.
651
+ *
652
+ * Implements the ARIA 1.2 combobox pattern, which is specific about a few things that are
653
+ * easy to get wrong and were all wrong in the `RoleComboBox` this replaces:
654
+ *
655
+ * - **`role="combobox"` belongs on the text input**, not on a wrapping `<div>`. The div
656
+ * version means the state attributes sit on an element the user never focuses.
657
+ * - **`aria-activedescendant`, not focus, tracks the highlighted option.** Focus stays in
658
+ * the input the whole time — moving DOM focus into the list breaks typing. This is the
659
+ * one place a roving tabindex is the *wrong* answer, which is why this does not use
660
+ * `useRovingFocus`.
661
+ * - **`aria-controls` points at the listbox**, which therefore needs a stable id.
662
+ * - The listbox is portaled, so it is not clipped by a `Card` or a scrolling container.
663
+ *
664
+ * For a command palette — filter over *actions* rather than a value — use `Command`.
665
+ */
666
+ declare function Combobox<T extends string = string>({ options, value: valueProp, defaultValue, onValueChange, label, placeholder, size: sizeProp, disabled, invalid, clearable, filter, emptyMessage, renderOption, className, }: ComboboxProps<T>): react.JSX.Element;
667
+
668
+ interface CommandItem {
669
+ id: string;
670
+ label: string;
671
+ description?: string;
672
+ /** Group heading. Items sharing a group render together, in the order given. */
673
+ group?: string;
674
+ icon?: ReactNode;
675
+ /** Trailing hint — pass `<Kbd>` elements. */
676
+ shortcut?: ReactNode;
677
+ /** Extra words to match on that are not in the label — synonyms, the old name of a page. */
678
+ keywords?: string[];
679
+ disabled?: boolean;
680
+ onSelect: () => void;
681
+ }
682
+ interface CommandProps {
683
+ items: CommandItem[];
684
+ /** Accessible name. Default `Command palette`. */
685
+ label?: string;
686
+ placeholder?: string;
687
+ emptyMessage?: ReactNode;
688
+ /** Called after any item is chosen — usually closes the containing dialog. */
689
+ onAfterSelect?: () => void;
690
+ autoFocus?: boolean;
691
+ className?: string;
692
+ }
693
+ /**
694
+ * A ⌘K command palette — filter over *actions* and run one.
695
+ *
696
+ * The same ARIA combobox pattern as `Combobox`, and for the same reasons: `role="combobox"`
697
+ * on the input, focus never leaving it, and `aria-activedescendant` carrying the highlight.
698
+ * What differs is the intent, and it changes two behaviours:
699
+ *
700
+ * - Items are **commands, not values**. There is no selected state to display, no way to
701
+ * clear, and choosing one runs a callback rather than setting anything.
702
+ * - Matching includes `keywords`, so "logout" can find "Sign out" — a palette is useless if
703
+ * you have to already know the wording.
704
+ *
705
+ * This is the palette body only. Put it in a `Modal` for the usual ⌘K overlay; keeping the
706
+ * two separate means the palette can also be embedded in a page or a `Popover`, and the
707
+ * dialog semantics stay with the component that owns them.
708
+ *
709
+ * A live region reports the result count, because otherwise a screen reader user typing into
710
+ * the filter gets no feedback that the list changed underneath them.
711
+ */
712
+ declare function Command({ items, label, placeholder, emptyMessage, onAfterSelect, autoFocus, className, }: CommandProps): react.JSX.Element;
713
+
714
+ /**
715
+ * The six status tones from the Figma design system.
716
+ * Values live in `src/app/styles/tokens/status.css`; see that file for why they do
717
+ * not derive from the SDS semantic colour families.
718
+ */
719
+ type StatusTone = 'neutral' | 'info' | 'warning' | 'caution' | 'accent' | 'positive' | 'danger';
720
+ type StatusBadgeSize = 'sm' | 'md';
721
+ interface StatusBadgeProps {
722
+ label: string;
723
+ tone?: StatusTone;
724
+ size?: StatusBadgeSize;
725
+ /** Leading dot. On by default — the Figma status pills all carry one. */
726
+ dot?: boolean;
727
+ /**
728
+ * Leading glyph, replacing the dot — e.g. `<LuCheck className="size-3" />`.
729
+ * Use for states a colour alone under-states, like verified or rejected.
730
+ */
731
+ icon?: ReactNode;
732
+ className?: string;
733
+ }
734
+ /**
735
+ * The status pill.
736
+ *
737
+ * Replaces thirteen inline re-implementations of the same markup plus five
738
+ * competing hardcoded hex palettes. Generalises `TableCellStatusPill`, which had
739
+ * this exact markup but required callers to pass raw hex strings.
740
+ *
741
+ * Note this is NOT `StatusChip` — that one renders a label *and a count* and is a
742
+ * different component.
743
+ */
744
+ declare function StatusBadge({ label, tone, size, dot, icon, className, }: StatusBadgeProps): react.JSX.Element;
745
+
746
+ type StatusDotTone = 'brand' | 'positive' | 'warning' | 'danger' | 'neutral' | 'default';
747
+ interface StatusDotProps {
748
+ tone?: StatusDotTone;
749
+ /** @deprecated Bypasses the design tokens — pass `tone` instead. Raw hex color, overrides `tone` via inline style. Use when the exact source color doesn't match a design token. */
750
+ color?: string;
751
+ className?: string;
752
+ }
753
+ declare function StatusDot({ tone, color, className }: StatusDotProps): react.JSX.Element;
754
+
755
+ interface StatusChipProps {
756
+ label: string;
757
+ count: number | string;
758
+ tone?: StatusDotTone;
759
+ /** @deprecated Bypasses the design tokens — pass `tone` instead. Raw hex dot color, overrides `tone` via inline style. Use when the exact source color doesn't match a design token. */
760
+ dotColor?: string;
761
+ bg?: string;
762
+ className?: string;
763
+ }
764
+ declare function StatusChip({ label, count, tone, dotColor, bg, className }: StatusChipProps): react.JSX.Element;
765
+
766
+ interface CountBadgeProps {
767
+ count: number | string;
768
+ label?: string;
769
+ tone?: StatusDotTone;
770
+ className?: string;
771
+ }
772
+ declare function CountBadge({ count, label, tone, className }: CountBadgeProps): react.JSX.Element;
773
+
774
+ type TagPillTone = 'default' | 'brand' | 'positive' | 'warning' | 'danger';
775
+ interface TagPillProps {
776
+ label: string;
777
+ tone?: TagPillTone;
778
+ /** @deprecated Bypasses the design tokens — pass `tone` instead. Raw hex bg/text pair, overrides `tone` via inline style. Use when the exact source colors don't match design tokens. */
779
+ bg?: string;
780
+ color?: string;
781
+ className?: string;
782
+ }
783
+ declare function TagPill({ label, tone, bg, color, className }: TagPillProps): react.JSX.Element;
784
+
785
+ interface TrailChipProps {
786
+ label: string;
787
+ value: string;
788
+ tone?: StatusTone;
789
+ /**
790
+ * Data-driven dot colour, overriding `tone`. The investigations trail mirrors the
791
+ * severity accent of whichever tree node is selected, and those accents come from
792
+ * the row data rather than the status palette — this is the escape hatch Phase 10
793
+ * classifies as "genuinely data-driven colour", not a token bypass.
794
+ */
795
+ dotColor?: string;
796
+ className?: string;
797
+ }
798
+ /**
799
+ * Dot + small uppercase label + value, used for the drill-down breadcrumb trail on
800
+ * the investigations page.
801
+ *
802
+ * Promoted from `pages/investigations`, where the dot colour was passed as a raw hex.
803
+ */
804
+ declare function TrailChip({ label, value, tone, dotColor, className }: TrailChipProps): react.JSX.Element;
805
+
806
+ type UserAccountStatus = 'active' | 'pending' | 'deactivated';
807
+ interface UserStatusPillProps {
808
+ status: UserAccountStatus;
809
+ }
810
+ /** Account-status pill. A thin wrapper over `StatusBadge`. */
811
+ declare function UserStatusPill({ status }: UserStatusPillProps): react.JSX.Element;
812
+
813
+ /**
814
+ * States of a compliance check.
815
+ *
816
+ * Union of the two previously-divergent local unions:
817
+ * - `features/entity-detail` had passed | in_progress | pending | action_required
818
+ * - `features/reviewer-detail` had passed | in-progress | failed | pending | waived
819
+ *
820
+ * Note `in_progress` (underscore) is canonical — entity-detail's spelling, which is
821
+ * the one backed by the API. reviewer-detail used `in-progress` (hyphen) in mock data.
822
+ */
823
+ type CheckIndicatorStatus = 'passed' | 'in_progress' | 'action_required' | 'failed' | 'pending' | 'waived';
824
+ interface CheckIndicatorProps {
825
+ status: CheckIndicatorStatus;
826
+ /** Accessible label. Without one the indicator is decorative, which is correct when an adjacent text label already names the state. */
827
+ label?: string;
828
+ className?: string;
275
829
  }
276
- declare function RoleComboBox({ value, onChange, options }: RoleComboBoxProps): react.JSX.Element;
830
+ /**
831
+ * The 22px outlined circle used for compliance-check state in entity and reviewer
832
+ * detail. Ring and glyph share one colour; see the check tokens in
833
+ * `src/app/styles/tokens/status.css`.
834
+ */
835
+ declare function CheckIndicator({ status, label, className }: CheckIndicatorProps): react.JSX.Element;
277
836
 
278
- declare function Panel({ children, className }: {
837
+ type EntityIconBadgeSize = 'sm' | 'md';
838
+ type EntityIconBadgeTone = 'default' | 'brand' | 'positive' | 'warning' | 'danger' | 'neutral';
839
+ type EntityIconBadgeShape = 'square' | 'circle';
840
+ interface EntityIconBadgeProps {
841
+ size?: EntityIconBadgeSize;
842
+ tone?: EntityIconBadgeTone;
843
+ /**
844
+ * `square` is the rounded-rect used on entity rows. `circle` is the tinted glyph
845
+ * circle used in modal headers. A prop rather than a `className` override, so it
846
+ * does not depend on Tailwind's stylesheet emit order.
847
+ */
848
+ shape?: EntityIconBadgeShape;
849
+ /** @deprecated Bypasses the design tokens — pass `tone` instead. Raw hex background, overrides `tone` via inline style. Use when the exact source color doesn't match a design token. */
850
+ bg?: string;
851
+ iconColor?: string;
279
852
  children: ReactNode;
280
853
  className?: string;
281
- }): react.JSX.Element;
282
- declare function MetricCard({ label, value, tone }: {
854
+ }
855
+ declare function EntityIconBadge({ size, tone, shape, bg, iconColor, children, className }: EntityIconBadgeProps): react.JSX.Element;
856
+
857
+ type CheckControlSize = 'sm' | 'md';
858
+
859
+ type CheckboxSize = CheckControlSize;
860
+ interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type' | 'onChange' | 'checked'> {
861
+ /** Controlled. Omit and pass `defaultChecked` for uncontrolled. */
862
+ checked?: boolean;
863
+ defaultChecked?: boolean;
864
+ onCheckedChange?: (checked: boolean) => void;
865
+ label?: ReactNode;
866
+ /** Second line under the label. Matches Figma's `Supporting text` axis. */
867
+ description?: ReactNode;
868
+ /** Matches Figma's `Size` axis. Default `md`, which is 0.3.0's fixed 18px. */
869
+ size?: CheckboxSize;
870
+ indeterminate?: boolean;
871
+ invalid?: boolean;
872
+ className?: string;
873
+ }
874
+ /**
875
+ * Checkbox built on a real `<input type="checkbox">`.
876
+ *
877
+ * Widened in 0.4.0 to match Figma's `Checkbox` set, which has `Size: sm | md`,
878
+ * `Text` and `Supporting text` axes — none of which existed in code, where the control was
879
+ * a fixed 18px with an optional single-line label and no `id`, `name`, `value`, `required`
880
+ * or ref. It also had no uncontrolled mode: `checked` and `onChange` were both required, so
881
+ * the simplest possible use site needed a `useState` in the consumer.
882
+ *
883
+ * `onChange` became `onCheckedChange` and takes a boolean, matching the rest of 0.4.0.
884
+ * The native `onChange` event shape is still reachable — the ref is forwarded to the real
885
+ * input, so `react-hook-form`'s `register()` works.
886
+ */
887
+ declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
888
+
889
+ type RadioGroupOrientation = 'vertical' | 'horizontal';
890
+ interface RadioGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
891
+ children: ReactNode;
892
+ value?: string;
893
+ defaultValue?: string;
894
+ onValueChange?: (value: string) => void;
895
+ /** Shared `name` for the underlying inputs. Generated when omitted. */
896
+ name?: string;
897
+ /** Names the group. Prefer wrapping in `FieldSet` + `FieldLegend` for a visible label. */
898
+ label?: string;
899
+ size?: CheckControlSize;
900
+ orientation?: RadioGroupOrientation;
901
+ disabled?: boolean;
902
+ invalid?: boolean;
903
+ required?: boolean;
904
+ }
905
+ /**
906
+ * Radio group. Matches the `Type=Radio` half of Figma's `Checkbox` set, and shares its
907
+ * geometry through `CheckControl`.
908
+ *
909
+ * Built on real `<input type="radio">` elements sharing a `name`, which is what buys the
910
+ * whole keyboard contract for free: arrow keys move *and* select, only the checked radio is
911
+ * in the tab sequence, and the group is announced as "2 of 4". A `div`-based
912
+ * `role="radiogroup"` has to reimplement all of that, and the version of this pattern the
913
+ * library already had — `SegmentedControl` before 0.4.0 — shipped with none of it.
914
+ *
915
+ * `role="radiogroup"` is still set explicitly rather than relying on a `<fieldset>`, so the
916
+ * group works with or without a visible legend.
917
+ */
918
+ declare const RadioGroup: react.ForwardRefExoticComponent<RadioGroupProps & react.RefAttributes<HTMLDivElement>>;
919
+ interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type' | 'onChange' | 'checked'> {
920
+ value: string;
921
+ label?: ReactNode;
922
+ /** Second line under the label. Matches Figma's `Supporting text` axis. */
923
+ description?: ReactNode;
924
+ className?: string;
925
+ }
926
+ declare const Radio: react.ForwardRefExoticComponent<RadioProps & react.RefAttributes<HTMLInputElement>>;
927
+
928
+ interface SegmentedControlOption {
929
+ value: string;
283
930
  label: string;
284
- value: string | number;
285
- tone?: 'default' | 'signal' | 'ember' | 'moss';
286
- }): react.JSX.Element;
287
- declare function SeverityBadge({ severity }: {
288
- severity?: string | null;
289
- }): react.JSX.Element;
290
- declare function SentimentBadge({ sentiment }: {
291
- sentiment?: string | null;
292
- }): react.JSX.Element;
931
+ disabled?: boolean;
932
+ }
933
+ interface SegmentedControlProps {
934
+ options: SegmentedControlOption[];
935
+ /** Controlled selection. Omit and pass `defaultValue` for uncontrolled. */
936
+ value?: string;
937
+ defaultValue?: string;
938
+ onValueChange?: (value: string) => void;
939
+ /** Names the group. Required by the APG when the control has no visible label. */
940
+ label?: string;
941
+ className?: string;
942
+ }
943
+ /**
944
+ * Single-select segmented toggle.
945
+ *
946
+ * Through 0.3.0 this had **no ARIA whatsoever** — the selected segment was distinguished
947
+ * only by `bg-default shadow-panel`, so a screen reader user could not tell which of the
948
+ * segments was active. It is single-select, so `radiogroup`/`radio` is the correct pattern
949
+ * rather than a row of `aria-pressed` buttons: it announces "2 of 3" and lets the arrow
950
+ * keys move between options, which a toggle-button group does not.
951
+ *
952
+ * `onChange` was also optional, so `<SegmentedControl options value />` rendered a control
953
+ * that looked interactive and silently did nothing.
954
+ */
955
+ declare function SegmentedControl({ options, value: valueProp, defaultValue, onValueChange, label, className, }: SegmentedControlProps): react.JSX.Element;
293
956
 
294
- declare function SectionHeading({ eyebrow, title, detail }: {
295
- eyebrow: string;
296
- title: string;
297
- detail?: string;
298
- }): react.JSX.Element;
957
+ interface SliderProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size' | 'onChange' | 'value'> {
958
+ value?: number;
959
+ defaultValue?: number;
960
+ onValueChange?: (value: number) => void;
961
+ min?: number;
962
+ max?: number;
963
+ step?: number;
964
+ /** Matches Figma's `Label` / `Has Label`. */
965
+ label?: ReactNode;
966
+ /** Matches Figma's `Description` / `Has Description`. */
967
+ description?: ReactNode;
968
+ /** Show the current value at the right of the label row. */
969
+ showValue?: boolean;
970
+ /** Formats the displayed and announced value — percentages, currency, durations. */
971
+ formatValue?: (value: number) => string;
972
+ className?: string;
973
+ }
974
+ /**
975
+ * Range slider. Matches Figma's `Slider Field` (`State: Default | Disabled`, with label and
976
+ * description slots).
977
+ *
978
+ * A native `<input type="range">`, deliberately. It arrives with the entire APG slider
979
+ * contract already implemented — arrow keys, Page Up/Down, Home/End, the correct
980
+ * `aria-valuenow`/`valuemin`/`valuemax`, touch and pointer dragging, and RTL handling — and
981
+ * a `div`-based slider has to rebuild all of it. The track and thumb are styled through the
982
+ * vendor pseudo-elements instead, which is the one place raw `[&::-webkit-…]` selectors are
983
+ * the right tool.
984
+ *
985
+ * `formatValue` feeds `aria-valuetext`, because "70" announced on a price slider is
986
+ * meaningless where "£70" is not.
987
+ */
988
+ declare const Slider: react.ForwardRefExoticComponent<SliderProps & react.RefAttributes<HTMLInputElement>>;
989
+
990
+ interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
991
+ children: ReactNode;
992
+ size?: InputSize;
993
+ }
994
+ /**
995
+ * A standalone `<label>`.
996
+ *
997
+ * `FieldLabel` is the one to reach for inside a `Field` — it picks up the generated id,
998
+ * the size and the disabled state from context automatically. This is for the cases that
999
+ * are not a field: naming a `SegmentedControl`, a group of buttons, or any control the
1000
+ * library does not wrap. It still reads `Field` context when it happens to be inside one,
1001
+ * so it degrades to `FieldLabel` behaviour rather than silently losing the association.
1002
+ */
1003
+ declare const Label: react.ForwardRefExoticComponent<LabelProps & react.RefAttributes<HTMLLabelElement>>;
1004
+
1005
+ type CalendarMode = 'single' | 'range';
1006
+ interface DateRange {
1007
+ from: Date | null;
1008
+ to: Date | null;
1009
+ }
1010
+ interface CalendarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect'> {
1011
+ mode?: CalendarMode;
1012
+ /** Selected date in `single` mode. */
1013
+ value?: Date | null;
1014
+ /** Selected range in `range` mode. */
1015
+ range?: DateRange;
1016
+ onSelect?: (value: Date) => void;
1017
+ onRangeChange?: (range: DateRange) => void;
1018
+ /** Month shown on mount. Defaults to the selection's month, else today. */
1019
+ defaultMonth?: Date;
1020
+ min?: Date;
1021
+ max?: Date;
1022
+ /** Return `true` to disable a day. Combined with `min`/`max`. */
1023
+ isDateDisabled?: (date: Date) => boolean;
1024
+ /** 0 = Sunday, 1 = Monday. Default `1`. */
1025
+ weekStartsOn?: 0 | 1;
1026
+ /** BCP 47 tag for month, weekday and announced day names. Default: the browser's. */
1027
+ locale?: string;
1028
+ /** Names the grid. Default `Calendar`. */
1029
+ label?: string;
1030
+ }
1031
+ /**
1032
+ * Month grid. Matches Figma's `Calendar`, `Calendar Button`
1033
+ * (`State: Default | Hover | Active | Disabled | Range | Range Disabled | Hidden`),
1034
+ * `Calendar Select Group` and `Calendar Month/Year Field`.
1035
+ *
1036
+ * The code had no calendar at all — `DatePicker` was a bare `<input type="date">` with
1037
+ * Chromium-only indicator styling, so there was nothing to build a range picker on, no
1038
+ * locale control and no min/max navigation.
1039
+ *
1040
+ * The keyboard model is the APG date-grid pattern, and it is the whole reason this is not
1041
+ * just a table of buttons:
1042
+ *
1043
+ * - **One tab stop.** Tab enters the grid once and leaves it; arrows move within. A grid of
1044
+ * 42 individually tabbable buttons takes 42 presses to get past.
1045
+ * - **Arrows cross month boundaries.** Pressing Left on the 1st moves to the previous
1046
+ * month's last day and pages the view, rather than dead-ending.
1047
+ * - **PageUp/PageDown** move by month, **Home/End** to the start/end of the week.
1048
+ * - Each day's accessible name is the full date, not the number — "14" tells a screen
1049
+ * reader user nothing.
1050
+ */
1051
+ declare function Calendar({ mode, value, range, onSelect, onRangeChange, defaultMonth, min, max, isDateDisabled, weekStartsOn, locale, label, className, ...rest }: CalendarProps): react.JSX.Element;
1052
+
1053
+ type InputGroupAlign = 'inline-start' | 'inline-end' | 'block-start' | 'block-end';
1054
+ interface InputGroupProps extends HTMLAttributes<HTMLDivElement> {
1055
+ children: ReactNode;
1056
+ size?: InputSize;
1057
+ invalid?: boolean;
1058
+ disabled?: boolean;
1059
+ }
1060
+ /**
1061
+ * A bordered shell that holds an input alongside addons — a prefix, a unit suffix, a
1062
+ * search glyph, a clear button, a copy button.
1063
+ *
1064
+ * This generalises what `PasswordInput` did as a one-off. `Input` has `leadingIcon`,
1065
+ * `trailingIcon` and `trailingAction` props, which works for a single decoration but forces
1066
+ * absolute positioning and per-size padding maps to keep the text clear of it. Here the
1067
+ * addons are real flex siblings, so the input's text box simply ends where the addon
1068
+ * begins and nothing has to be measured.
1069
+ *
1070
+ * The border and focus ring live on the group, not the input — so focusing the input rings
1071
+ * the whole control, which is what a user perceives as "the field".
1072
+ */
1073
+ declare const InputGroup: react.ForwardRefExoticComponent<InputGroupProps & react.RefAttributes<HTMLDivElement>>;
1074
+ interface InputGroupInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
1075
+ }
1076
+ /**
1077
+ * The input inside an `InputGroup`. Carries no border, background or ring of its own —
1078
+ * the group owns all three.
1079
+ */
1080
+ declare const InputGroupInput: react.ForwardRefExoticComponent<InputGroupInputProps & react.RefAttributes<HTMLInputElement>>;
1081
+ interface InputGroupAddonProps extends HTMLAttributes<HTMLSpanElement> {
1082
+ children: ReactNode;
1083
+ align?: InputGroupAlign;
1084
+ /**
1085
+ * `true` when the addon is decoration — an icon, a unit. Decorative addons are
1086
+ * `aria-hidden` and ignore pointer events, so they never steal a click meant for the
1087
+ * text box. Default `true`; set `false` for an addon containing a control.
1088
+ */
1089
+ decorative?: boolean;
1090
+ }
1091
+ declare const InputGroupAddon: react.ForwardRefExoticComponent<InputGroupAddonProps & react.RefAttributes<HTMLSpanElement>>;
1092
+ interface InputGroupTextProps extends HTMLAttributes<HTMLSpanElement> {
1093
+ children: ReactNode;
1094
+ }
1095
+ /** Static text inside the shell — a currency symbol, a domain suffix, a unit. */
1096
+ declare const InputGroupText: react.ForwardRefExoticComponent<InputGroupTextProps & react.RefAttributes<HTMLSpanElement>>;
1097
+ interface SearchInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
1098
+ size?: InputSize;
1099
+ /** Renders a clear button once there is a value. */
1100
+ onClear?: () => void;
1101
+ /** Accessible name. Default `Search`. */
1102
+ label?: string;
1103
+ className?: string;
1104
+ }
1105
+ /**
1106
+ * Search field. Matches Figma's `Search` set — `Size: Large | Medium | Small`,
1107
+ * `State: Default | Disabled`, `Value Type: Filled | Placeholder`.
1108
+ *
1109
+ * `type="search"` rather than `type="text"`: it gets the platform's search affordances and
1110
+ * is announced as a search field. The clear button is a real button so it is keyboard
1111
+ * reachable, unlike the UA-provided cancel widget which is pointer-only in most browsers
1112
+ * and is therefore suppressed.
1113
+ */
1114
+ declare const SearchInput: react.ForwardRefExoticComponent<SearchInputProps & react.RefAttributes<HTMLInputElement>>;
1115
+
1116
+ type ModalSize = 'sm' | 'md' | 'lg' | 'xl';
1117
+ /**
1118
+ * Note `positive`, not `success` — every other tone union in the library
1119
+ * (`InlineAlertTone`, `TagPillTone`, `EntityIconBadgeTone`) and the token layer say
1120
+ * `positive`, and one vocabulary beats a familiar synonym.
1121
+ */
1122
+ type ModalTone = 'default' | 'info' | 'positive' | 'warning' | 'danger';
1123
+ type ModalFooterAlign = 'start' | 'between' | 'end';
1124
+ interface ModalProps {
1125
+ open: boolean;
1126
+ /** Fired with `false` on Escape, an outside press, or the close button. */
1127
+ onOpenChange: (open: boolean) => void;
1128
+ /**
1129
+ * Accessible name. Only needed when the dialog renders no `ModalTitle` — with one, the
1130
+ * name comes from the heading itself via `aria-labelledby`, so it cannot drift.
1131
+ */
1132
+ label?: string;
1133
+ children: ReactNode;
1134
+ size?: ModalSize;
1135
+ /**
1136
+ * `alertdialog` for a dialog that interrupts to confirm or warn — it makes assistive
1137
+ * tech announce the body immediately rather than waiting to be browsed. `ConfirmDialog`
1138
+ * passes it; plain content dialogs should stay `dialog`.
1139
+ */
1140
+ role?: 'dialog' | 'alertdialog';
1141
+ /** Renders the top-right close button. */
1142
+ showClose?: boolean;
1143
+ /** Applied to the panel. With `cn`, `className="sm:max-w-[560px]"` beats `size`. */
1144
+ className?: string;
1145
+ /** Call `preventDefault()` to keep the dialog open — e.g. unsaved input. */
1146
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
1147
+ /** Call `preventDefault()` to keep the dialog open. */
1148
+ onInteractOutside?: (event: PointerEvent) => void;
1149
+ /** Focus this on open instead of the first tabbable element. */
1150
+ initialFocus?: React.RefObject<HTMLElement | null>;
1151
+ }
1152
+ /**
1153
+ * A centred dialog above `sm`, a bottom sheet below it.
1154
+ *
1155
+ * Composed from `ModalHeader` / `ModalBody` / `ModalFooter`, mirroring the `Card`
1156
+ * parts — so a modal can take any layout a card can, including headerless. Tone lives
1157
+ * on `ModalHeader` (the part that draws the glyph); `ConfirmDialog` and
1158
+ * `NoteConfirmModal` accept `tone` at their top level and forward it.
1159
+ */
1160
+ declare function Modal(props: ModalProps): react.JSX.Element | null;
1161
+ interface ModalHeaderProps extends HTMLAttributes<HTMLDivElement> {
1162
+ children: ReactNode;
1163
+ /** Adds a tinted glyph circle. `default` renders none. */
1164
+ tone?: ModalTone;
1165
+ divider?: boolean;
1166
+ }
1167
+ declare function ModalHeader({ children, tone, divider, className, ...rest }: ModalHeaderProps): react.JSX.Element;
1168
+ interface ModalTitleProps extends HTMLAttributes<HTMLHeadingElement> {
1169
+ children: ReactNode;
1170
+ }
1171
+ declare function ModalTitle({ children, className, id, ...rest }: ModalTitleProps): react.JSX.Element;
1172
+ interface ModalDescriptionProps extends HTMLAttributes<HTMLParagraphElement> {
1173
+ children: ReactNode;
1174
+ }
1175
+ declare function ModalDescription({ children, className, id, ...rest }: ModalDescriptionProps): react.JSX.Element;
1176
+ interface ModalBodyProps extends HTMLAttributes<HTMLDivElement> {
1177
+ children: ReactNode;
1178
+ }
1179
+ /** Must not carry its own `overflow` — the panel is the scroll container. */
1180
+ declare function ModalBody({ children, className, ...rest }: ModalBodyProps): react.JSX.Element;
1181
+ interface ModalFooterProps extends HTMLAttributes<HTMLDivElement> {
1182
+ children: ReactNode;
1183
+ align?: ModalFooterAlign;
1184
+ divider?: boolean;
1185
+ }
1186
+ declare function ModalFooter({ children, align, divider, className, ...rest }: ModalFooterProps): react.JSX.Element;
1187
+
1188
+ type FloatingSide = 'top' | 'right' | 'bottom' | 'left';
1189
+ type FloatingAlign = 'start' | 'center' | 'end';
1190
+
1191
+ interface TooltipProps {
1192
+ /**
1193
+ * The trigger. Must be a single focusable element — a tooltip that can only be reached
1194
+ * with a pointer is invisible to keyboard and touch users, so this deliberately does not
1195
+ * wrap its child in a span to make it hoverable.
1196
+ */
1197
+ children: ReactElement;
1198
+ /** Bold first line. Matches Figma's `Title` property. */
1199
+ title?: ReactNode;
1200
+ /** Supporting line. Matches Figma's `Body` / `Has Body`. */
1201
+ body?: ReactNode;
1202
+ side?: FloatingSide;
1203
+ align?: FloatingAlign;
1204
+ /** Delay before opening, in ms. Default `150`. */
1205
+ openDelay?: number;
1206
+ /** Delay before closing, in ms. Default `0`. */
1207
+ closeDelay?: number;
1208
+ open?: boolean;
1209
+ defaultOpen?: boolean;
1210
+ onOpenChange?: (open: boolean) => void;
1211
+ /**
1212
+ * `describedby` — the trigger keeps its own name and the tooltip adds detail. This is
1213
+ * almost always what you want. `labelledby` makes the tooltip *be* the trigger's name,
1214
+ * for an icon-only button with no other text. Default `describedby`.
1215
+ *
1216
+ * Deliberately not called `as`: everywhere else in this library `as` chooses the rendered
1217
+ * element, and reusing it for something else here would be a trap (it also makes
1218
+ * `jsx-a11y`'s polymorphic-component checking treat the value as a tag name).
1219
+ */
1220
+ association?: 'describedby' | 'labelledby';
1221
+ className?: string;
1222
+ }
1223
+ /**
1224
+ * Tooltip. Matches Figma's `Tooltip` set — `Placement: Top | Left | Right | Bottom`, with
1225
+ * a title and an optional body.
1226
+ *
1227
+ * Things this gets right that a naive tooltip does not:
1228
+ *
1229
+ * - **Keyboard and touch reachable.** Opens on `focus` as well as hover, and closes on
1230
+ * Escape. A hover-only tooltip is inaccessible to half the people using it.
1231
+ * - **Referenced, not floating text.** The panel is wired to the trigger with
1232
+ * `aria-describedby` (or `aria-labelledby`), so it is announced *with* the control
1233
+ * rather than being an orphan region a screen reader may never reach.
1234
+ * - **`role="tooltip"` and no interactive content.** A tooltip cannot be hovered into or
1235
+ * focused, so anything interactive inside it is unreachable — use `Popover` for that.
1236
+ * - Not modal: no focus trap, no scroll lock, no inert background.
1237
+ */
1238
+ declare function Tooltip({ children, title, body, side, align, openDelay, closeDelay, open: openProp, defaultOpen, onOpenChange, association, className, }: TooltipProps): react.JSX.Element | null;
1239
+
1240
+ interface PopoverProps {
1241
+ children: ReactNode;
1242
+ open?: boolean;
1243
+ defaultOpen?: boolean;
1244
+ onOpenChange?: (open: boolean) => void;
1245
+ /**
1246
+ * Trap focus, lock scroll and mark the rest of the page inert. Default `false`.
1247
+ *
1248
+ * A popover is normally non-modal: the page behind stays usable, and Tab moves out of the
1249
+ * panel and on through the document. Set `modal` when the panel is a small form whose
1250
+ * background must not be touched until it is dismissed.
1251
+ */
1252
+ modal?: boolean;
1253
+ }
1254
+ /**
1255
+ * A floating panel anchored to a trigger, for **interactive** content.
1256
+ *
1257
+ * The distinction from `Tooltip` is not visual and it matters: a tooltip cannot be hovered
1258
+ * into or focused, so anything interactive inside one is unreachable. If the panel holds a
1259
+ * link, a button or a field, it has to be a popover — which means a real trigger with
1260
+ * `aria-expanded`/`aria-controls`, focus moving into the panel on open, and focus returning
1261
+ * to the trigger on close. All of that is here; none of it is in `Tooltip`, by design.
1262
+ */
1263
+ declare function Popover({ children, open: openProp, defaultOpen, onOpenChange, modal, }: PopoverProps): react.JSX.Element;
1264
+ interface PopoverTriggerProps extends HTMLAttributes<HTMLElement> {
1265
+ children: ReactNode;
1266
+ asChild?: boolean;
1267
+ }
1268
+ declare function PopoverTrigger({ children, asChild, className, ...rest }: PopoverTriggerProps): react.JSX.Element;
1269
+ interface PopoverContentProps extends HTMLAttributes<HTMLDivElement> {
1270
+ children: ReactNode;
1271
+ side?: FloatingSide;
1272
+ align?: FloatingAlign;
1273
+ sideOffset?: number;
1274
+ /** Accessible name for the panel. Falls back to being labelled by the trigger. */
1275
+ label?: string;
1276
+ }
1277
+ declare function PopoverContent({ children, side, align, sideOffset, label, className, ...rest }: PopoverContentProps): react.JSX.Element | null;
1278
+
1279
+ interface HoverCardProps {
1280
+ /** The trigger. Must be a single focusable element — normally a link. */
1281
+ children: ReactElement;
1282
+ /** Panel content. May contain links and text; see the note on interactivity below. */
1283
+ content: ReactNode;
1284
+ side?: FloatingSide;
1285
+ align?: FloatingAlign;
1286
+ /** Delay before opening, in ms. Default `400`. */
1287
+ openDelay?: number;
1288
+ /** Delay before closing, in ms. Default `200`. */
1289
+ closeDelay?: number;
1290
+ open?: boolean;
1291
+ defaultOpen?: boolean;
1292
+ onOpenChange?: (open: boolean) => void;
1293
+ className?: string;
1294
+ }
1295
+ /**
1296
+ * A preview panel that appears on hover — a user card on an @mention, a page preview on a
1297
+ * link.
1298
+ *
1299
+ * Sits between `Tooltip` and `Popover`, and the difference is about intent rather than
1300
+ * looks:
1301
+ *
1302
+ * - `Tooltip` is a short label. It cannot be entered, so it must hold no controls.
1303
+ * - `HoverCard` is supplementary content that *can* be entered — the panel stays open while
1304
+ * the pointer is inside it, so a link in the preview is reachable. It is opened by hover
1305
+ * and focus, never by click.
1306
+ * - `Popover` is opened deliberately by click and is the only one of the three appropriate
1307
+ * for content the user must act on.
1308
+ *
1309
+ * **It is supplementary by contract.** Hover has no touch equivalent, so anything only
1310
+ * reachable here is unreachable on a phone. The panel is `aria-labelledby` the trigger and
1311
+ * exposed as a group; the trigger keeps its own name and destination.
1312
+ *
1313
+ * The close delay is what makes the panel usable: without it, moving the pointer from the
1314
+ * trigger to the panel crosses a gap and dismisses the thing you were reaching for.
1315
+ */
1316
+ declare function HoverCard({ children, content, side, align, openDelay, closeDelay, open: openProp, defaultOpen, onOpenChange, className, }: HoverCardProps): react.JSX.Element | null;
1317
+
1318
+ type OverlayItemTone = 'default' | 'danger';
1319
+
1320
+ type MenuItemTone = OverlayItemTone;
1321
+ interface MenuItemProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect'> {
1322
+ children: ReactNode;
1323
+ onSelect?: () => void;
1324
+ tone?: MenuItemTone;
1325
+ disabled?: boolean;
1326
+ /** Leading glyph. Marked decorative automatically. Matches Figma's `Icon` / `Has Icon`. */
1327
+ icon?: ReactNode;
1328
+ /** Second line. Matches Figma's `Description` / `Has Description`. */
1329
+ description?: ReactNode;
1330
+ /** Trailing shortcut hint. Matches Figma's `Shortcut` / `Has Shortcut`. */
1331
+ shortcut?: ReactNode;
1332
+ /** Typeahead match text, when `children` is not a plain string. */
1333
+ textValue?: string;
1334
+ }
1335
+ declare function MenuItem({ children, onSelect, tone, disabled, icon, description, shortcut, textValue, className, ...rest }: MenuItemProps): react.JSX.Element;
1336
+ interface MenuCheckboxItemProps extends Omit<MenuItemProps, 'onSelect' | 'icon'> {
1337
+ checked: boolean;
1338
+ onCheckedChange?: (checked: boolean) => void;
1339
+ }
1340
+ declare function MenuCheckboxItem({ children, checked, onCheckedChange, disabled, tone, shortcut, textValue, className, ...rest }: MenuCheckboxItemProps): react.JSX.Element;
1341
+ interface MenuRadioGroupProps {
1342
+ children: ReactNode;
1343
+ value?: string;
1344
+ onValueChange?: (value: string) => void;
1345
+ }
1346
+ declare function MenuRadioGroup({ children, value, onValueChange }: MenuRadioGroupProps): react.JSX.Element;
1347
+ interface MenuRadioItemProps extends Omit<MenuItemProps, 'onSelect' | 'icon'> {
1348
+ value: string;
1349
+ }
1350
+ declare function MenuRadioItem({ children, value, disabled, tone, textValue, className, ...rest }: MenuRadioItemProps): react.JSX.Element;
1351
+ interface MenuGroupProps extends HTMLAttributes<HTMLDivElement> {
1352
+ children: ReactNode;
1353
+ /** Names the group. Rendered as a heading when set. */
1354
+ label?: string;
1355
+ }
1356
+ declare function MenuGroup({ children, label, className, ...rest }: MenuGroupProps): react.JSX.Element;
1357
+ interface MenuLabelProps extends HTMLAttributes<HTMLDivElement> {
1358
+ children: ReactNode;
1359
+ }
1360
+ /** A non-interactive heading inside the menu. Matches Figma's `Menu Heading`. */
1361
+ declare function MenuLabel({ children, className, ...rest }: MenuLabelProps): react.JSX.Element;
1362
+ interface MenuSeparatorProps extends HTMLAttributes<HTMLDivElement> {
1363
+ }
1364
+ /** Matches Figma's `Menu Separator`. Was a bare unlabelled `div` before 0.4.0. */
1365
+ declare function MenuSeparator({ className, ...rest }: MenuSeparatorProps): react.JSX.Element;
1366
+ interface MenuShortcutProps extends HTMLAttributes<HTMLSpanElement> {
1367
+ children: ReactNode;
1368
+ }
1369
+ /** Trailing keyboard hint, for use outside an item's `shortcut` prop. */
1370
+ declare function MenuShortcut({ children, className, ...rest }: MenuShortcutProps): react.JSX.Element;
1371
+
1372
+ interface ContextMenuProps {
1373
+ children: ReactNode;
1374
+ open?: boolean;
1375
+ defaultOpen?: boolean;
1376
+ onOpenChange?: (open: boolean) => void;
1377
+ }
1378
+ /**
1379
+ * Right-click menu.
1380
+ *
1381
+ * Shares every item and the whole keyboard contract with `DropdownMenu` via `menu-core`;
1382
+ * the only difference is how it opens — at the pointer, with no trigger element to anchor
1383
+ * to, so it is positioned from coordinates rather than by Floating UI's reference/floating
1384
+ * pair.
1385
+ *
1386
+ * **A context menu must never be the only way to reach an action.** `contextmenu` fires on
1387
+ * right-click and on the Windows Menu / Shift+F10 keys, but not on touch, and plenty of
1388
+ * users never right-click at all. `ContextMenuTrigger` therefore also opens on Shift+F10 and
1389
+ * the ContextMenu key, and anything in here should have a visible equivalent elsewhere —
1390
+ * usually a `DropdownMenu` on the same row.
1391
+ */
1392
+ declare function ContextMenu({ children, open: openProp, defaultOpen, onOpenChange, }: ContextMenuProps): react.JSX.Element;
1393
+ interface ContextMenuTriggerProps extends HTMLAttributes<HTMLDivElement> {
1394
+ children: ReactNode;
1395
+ disabled?: boolean;
1396
+ }
1397
+ declare function ContextMenuTrigger({ children, disabled, className, ...rest }: ContextMenuTriggerProps): react.JSX.Element;
1398
+ interface ContextMenuContentProps extends HTMLAttributes<HTMLDivElement> {
1399
+ children: ReactNode;
1400
+ /** Minimum gap from the viewport edge, in px. Default `8`. */
1401
+ collisionPadding?: number;
1402
+ }
1403
+ declare function ContextMenuContent({ children, collisionPadding, className, ...rest }: ContextMenuContentProps): react.JSX.Element | null;
1404
+
1405
+ interface MenubarProps extends HTMLAttributes<HTMLDivElement> {
1406
+ children: ReactNode;
1407
+ /** Names the menubar. Required by the APG. */
1408
+ label: string;
1409
+ }
1410
+ /**
1411
+ * An application menu bar — a horizontal row of menus, as in a desktop app.
1412
+ *
1413
+ * Two things distinguish it from a row of `DropdownMenu`s, and both are in the APG:
1414
+ *
1415
+ * - **The bar is one tab stop.** Left/Right move between the top-level menus; Tab leaves the
1416
+ * bar entirely. A row of independent dropdowns is N tab stops.
1417
+ * - **Only one menu is open at a time**, and once any is open, moving along the bar switches
1418
+ * directly to the next menu rather than closing and reopening.
1419
+ *
1420
+ * Items and the vertical keyboard contract come from `menu-core`, shared with
1421
+ * `DropdownMenu` and `ContextMenu`.
1422
+ */
1423
+ declare function Menubar({ children, label, className, ...rest }: MenubarProps): react.JSX.Element;
1424
+ interface MenubarMenuProps {
1425
+ children: ReactNode;
1426
+ /** Identifies this menu within the bar. */
1427
+ value: string;
1428
+ }
1429
+ /** One menu in the bar. Wraps a `MenubarTrigger` and a `MenubarContent`. */
1430
+ declare function MenubarMenu({ children, value }: MenubarMenuProps): react.JSX.Element;
1431
+ interface MenubarTriggerProps extends HTMLAttributes<HTMLButtonElement> {
1432
+ children: ReactNode;
1433
+ }
1434
+ declare function MenubarTrigger({ children, className, ...rest }: MenubarTriggerProps): react.JSX.Element;
1435
+ interface MenubarContentProps extends HTMLAttributes<HTMLDivElement> {
1436
+ children: ReactNode;
1437
+ }
1438
+ declare function MenubarContent({ children, className, ...rest }: MenubarContentProps): react.JSX.Element | null;
1439
+
1440
+ type DrawerSide = 'right' | 'left';
1441
+ interface DrawerProps {
1442
+ open: boolean;
1443
+ /** Fired with `false` on Escape, an outside press, or the close button. */
1444
+ onOpenChange: (open: boolean) => void;
1445
+ /** Header content (left side). The copies this replaces differ only here — a status badge +
1446
+ * title in one, an avatar + title + category in another — so it is a slot, not props. */
1447
+ header: ReactNode;
1448
+ children: ReactNode;
1449
+ footer?: ReactNode;
1450
+ /** `between` when the footer has a left-aligned secondary action. */
1451
+ footerAlign?: 'end' | 'between';
1452
+ /** Panel width. Defaults to the `w-[440px] max-w-[90vw]` shared by every existing drawer. */
1453
+ width?: string;
1454
+ /** Which edge the panel slides in from. Default `right`. */
1455
+ side?: DrawerSide;
1456
+ /**
1457
+ * Accessible name for the dialog. **Required** as of 0.4.0.
1458
+ *
1459
+ * It was optional through 0.3.0 while `Modal.label` was required, which meant the
1460
+ * public API allowed a `role="dialog" aria-modal="true"` element with no accessible
1461
+ * name at all — a screen reader announced "dialog" and nothing else. Unlike `Modal`
1462
+ * there is no `DrawerTitle` part to infer a name from, because `header` is a free
1463
+ * slot, so the string is the only place it can come from.
1464
+ */
1465
+ label: string;
1466
+ className?: string;
1467
+ /** Call `preventDefault()` to keep the drawer open — e.g. unsaved input. */
1468
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
1469
+ /** Call `preventDefault()` to keep the drawer open. */
1470
+ onInteractOutside?: (event: PointerEvent) => void;
1471
+ /** Focus this on open instead of the first tabbable element. */
1472
+ initialFocus?: RefObject<HTMLElement | null>;
1473
+ }
1474
+ /**
1475
+ * Side panel. Handles Esc, traps Tab focus, locks background scroll, marks the rest of
1476
+ * the page inert, and restores focus to the trigger on close.
1477
+ */
1478
+ declare function Drawer(props: DrawerProps): react.JSX.Element | null;
1479
+
1480
+ interface ConfirmDialogProps {
1481
+ open: boolean;
1482
+ title: string;
1483
+ subtitle?: string;
1484
+ /**
1485
+ * Adds a tinted glyph to the header. Defaults to `default` (no glyph) so existing
1486
+ * call sites look unchanged; opt in per dialog rather than deriving it from
1487
+ * `confirmVariant`, which would silently restyle every destructive confirm.
1488
+ */
1489
+ tone?: ModalTone;
1490
+ size?: ModalSize;
1491
+ confirmLabel?: string;
1492
+ cancelLabel?: string;
1493
+ confirmVariant?: 'primary' | 'danger';
1494
+ /** Disables the confirm button and swaps its label — the double-submit guard. */
1495
+ isConfirming?: boolean;
1496
+ /** Label shown on the confirm button while `isConfirming`. */
1497
+ confirmingLabel?: string;
1498
+ /** Optional body — a warning callout, a consequences list, or a failed-attempt error. */
1499
+ children?: ReactNode;
1500
+ className?: string;
1501
+ onConfirm: () => void;
1502
+ /** Fired with `false` on cancel, Escape, or an outside press. */
1503
+ onOpenChange: (open: boolean) => void;
1504
+ }
1505
+ /**
1506
+ * The in-app replacement for `window.confirm`: a title, an optional body, and a
1507
+ * cancel/confirm pair.
1508
+ *
1509
+ * Kept as a preset rather than folded into `Modal` because it carries *behaviour*, not
1510
+ * just layout — the `isConfirming` guard that disables the button and swaps its label
1511
+ * is the thing call sites get wrong when they hand-roll a confirm. For any other
1512
+ * shape, compose `Modal` and its parts directly.
1513
+ */
1514
+ declare function ConfirmDialog({ open, title, subtitle, tone, size, confirmLabel, cancelLabel, confirmVariant, isConfirming, confirmingLabel, children, className, onConfirm, onOpenChange, }: ConfirmDialogProps): react.JSX.Element;
1515
+
1516
+ interface NoteConfirmModalProps {
1517
+ open: boolean;
1518
+ title: string;
1519
+ subtitle?: string;
1520
+ tone?: ModalTone;
1521
+ size?: ModalSize;
1522
+ confirmLabel: string;
1523
+ cancelLabel?: string;
1524
+ confirmVariant?: 'primary' | 'danger';
1525
+ /** Block confirmation until the note has content. */
1526
+ requireNote?: boolean;
1527
+ notePlaceholder?: string;
1528
+ submittingLabel?: string;
1529
+ isSubmitting?: boolean;
1530
+ className?: string;
1531
+ /** Fired with `false` on cancel, Escape, or an outside press. */
1532
+ onOpenChange: (open: boolean) => void;
1533
+ onConfirm: (note: string) => void;
1534
+ /**
1535
+ * Asked before an Escape or outside press throws away a note that has content.
1536
+ * Return `false` to keep the dialog open. Defaults to `window.confirm`.
1537
+ */
1538
+ onDiscardNote?: (note: string) => boolean;
1539
+ }
1540
+ /**
1541
+ * Confirm dialog that collects a free-text note — approvals, rejections, information
1542
+ * requests. The note is trimmed before it reaches `onConfirm`.
1543
+ *
1544
+ * Kept as a preset because it owns state, and a composition cannot.
1545
+ */
1546
+ declare function NoteConfirmModal({ open, ...rest }: NoteConfirmModalProps): react.JSX.Element | null;
1547
+
1548
+ /**
1549
+ * Overflow / row-actions menu, rebuilt in 0.4.0.
1550
+ *
1551
+ * The previous version declared `role="menu"` and `role="menuitem"` and implemented none of
1552
+ * the WAI-ARIA menu contract. Announcing a pattern you do not implement is worse than
1553
+ * announcing nothing, because a screen reader tells the user which keys should work. Fixed:
1554
+ * arrow keys, Home/End and typeahead; a roving tabindex (every item used to be a natively
1555
+ * tabbable `<button>`, so Tab walked all of them); focus moving into the menu on open and
1556
+ * back to the trigger on close; a portal, so the panel is no longer clipped by `Card`'s
1557
+ * `overflow-hidden` or `DataTable`'s `overflow-x-auto` — both named in its own doc comment
1558
+ * as the reason it exists; collision handling instead of a static `left`/`right`; correct
1559
+ * ARIA ownership; and `open`/`onOpenChange`, where open state used to be unreachable.
1560
+ *
1561
+ * The items and keyboard model now live in `menu-core`, shared with `ContextMenu` and
1562
+ * `Menubar`.
1563
+ *
1564
+ * Not implemented: submenus. Doing them properly needs hover intent and a safe-travel
1565
+ * polygon between trigger and panel, and a half-built version is worse than none — nest a
1566
+ * second `DropdownMenu` in the meantime.
1567
+ */
1568
+ interface DropdownMenuProps {
1569
+ children: ReactNode;
1570
+ /** Controlled open state. Omit for uncontrolled. */
1571
+ open?: boolean;
1572
+ defaultOpen?: boolean;
1573
+ onOpenChange?: (open: boolean) => void;
1574
+ }
1575
+ declare function DropdownMenu({ children, open: openProp, defaultOpen, onOpenChange, }: DropdownMenuProps): react.JSX.Element;
1576
+ interface DropdownMenuTriggerProps extends HTMLAttributes<HTMLElement> {
1577
+ children?: ReactNode;
1578
+ /** Render the child element instead of the default overflow button. */
1579
+ asChild?: boolean;
1580
+ /** Accessible name for the default `⋯` button. Ignored when `asChild` is set. */
1581
+ label?: string;
1582
+ }
1583
+ declare function DropdownMenuTrigger({ children, asChild, label, ...rest }: DropdownMenuTriggerProps): react.JSX.Element;
1584
+ interface DropdownMenuContentProps extends HTMLAttributes<HTMLDivElement> {
1585
+ children: ReactNode;
1586
+ side?: FloatingSide;
1587
+ align?: FloatingAlign;
1588
+ sideOffset?: number;
1589
+ }
1590
+ declare function DropdownMenuContent({ children, side, align, sideOffset, className, ...rest }: DropdownMenuContentProps): react.JSX.Element | null;
1591
+
1592
+ interface PortalProps {
1593
+ children: ReactNode;
1594
+ /**
1595
+ * Where to mount. Defaults to `document.body`.
1596
+ *
1597
+ * Pass a container when the app renders inside a shadow root or a scoped theme
1598
+ * wrapper — the portal must stay inside whatever element the design tokens are
1599
+ * declared on, or every `var(--color-*)` resolves to nothing.
1600
+ */
1601
+ container?: HTMLElement | null;
1602
+ }
1603
+ /**
1604
+ * Renders `children` outside the parent DOM hierarchy.
1605
+ *
1606
+ * Until 0.4.0 this library never called `createPortal` — `Modal`, `Drawer`,
1607
+ * `DropdownMenu`, `RoleComboBox` and the sidebar menu all rendered inline. Two concrete
1608
+ * failures came out of that:
1609
+ *
1610
+ * - `DropdownMenu` was positioned `absolute` inside a `relative` wrapper, so it was
1611
+ * clipped by `Card`'s `overflow-hidden` and by `DataTable`'s `overflow-x-auto` — the
1612
+ * two places its own doc comment said it was for.
1613
+ * - `position: fixed` resolves against the nearest ancestor with `transform`, `filter`,
1614
+ * `backdrop-filter`, `perspective`, `will-change` or `contain`, so a `Modal` opened
1615
+ * from inside any transformed ancestor was positioned against that ancestor rather
1616
+ * than the viewport, and `z-50` was scoped to a stacking context it did not control.
1617
+ *
1618
+ * Mounting is deferred to an effect so the server render and the first client render
1619
+ * agree — reaching for `document` during render breaks SSR and hydration.
1620
+ */
1621
+ declare function Portal({ children, container }: PortalProps): react.ReactPortal | null;
1622
+
1623
+ /** The one scrim for every overlay primitive.
1624
+ *
1625
+ * Modal and Drawer both reference this constant, so there is a single place to change
1626
+ * the dimming behind a dialog. Backed by `--color-background-utilities-overlay`. */
1627
+ declare const OVERLAY_SCRIM = "bg-overlay";
1628
+ interface UseOverlayDismissOptions {
1629
+ /** Called when the overlay should close. */
1630
+ onDismiss: () => void;
1631
+ /** The panel element — not the scrim. */
1632
+ panelRef: RefObject<HTMLElement | null>;
1633
+ /** Set `false` to suspend every behaviour without unmounting. Default `true`. */
1634
+ active?: boolean;
1635
+ /** Default `true`. */
1636
+ closeOnEscape?: boolean;
1637
+ /** Default `true`. */
1638
+ closeOnOutsidePress?: boolean;
1639
+ /** Keep Tab inside the panel. Default `true`. Turn off for non-modal surfaces. */
1640
+ trapFocus?: boolean;
1641
+ /** Default `true`. */
1642
+ lockScroll?: boolean;
1643
+ /** Mark sibling content `inert`. Default `true`. */
1644
+ inertBackground?: boolean;
1645
+ /**
1646
+ * Move focus into the panel on mount. Default `true`.
1647
+ *
1648
+ * Set `false` when the overlay manages its own entry point — a menu with a roving
1649
+ * tabindex exposes exactly one focusable item at a time, so a generic
1650
+ * "focus the first tabbable element" scan would fight it.
1651
+ */
1652
+ autoFocus?: boolean;
1653
+ /** Focus this instead of the first tabbable element. */
1654
+ initialFocus?: RefObject<HTMLElement | null>;
1655
+ /**
1656
+ * Restore focus here instead of wherever it was when the overlay opened.
1657
+ *
1658
+ * Passing the ref at all takes over the restore: a `current` of `null` means "leave
1659
+ * focus alone", not "fall back to the previously focused element". `Menubar` depends on
1660
+ * that — while it is switching from one menu to a sibling, focus already belongs to the
1661
+ * sibling and pulling it back to the closing menu's trigger reopens the menu.
1662
+ */
1663
+ returnFocus?: RefObject<HTMLElement | null>;
1664
+ /** Call `preventDefault()` to veto the close — e.g. a form with unsaved input. */
1665
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
1666
+ /** Call `preventDefault()` to veto the close. */
1667
+ onInteractOutside?: (event: PointerEvent) => void;
1668
+ }
1669
+ /** Esc-to-close, a Tab focus trap, scroll lock, an inert background, and focus restore
1670
+ * for a mounted overlay. Pass the ref of the panel element (not the scrim).
1671
+ *
1672
+ * Rewritten in 0.4.0. The previous version handled Esc, Tab and focus restore, and had
1673
+ * the following defects — each is now covered by a test:
1674
+ *
1675
+ * - **One Escape closed every open overlay.** Each overlay put its own listener on
1676
+ * `document` and called `stopPropagation`, which stops propagation to other *nodes*,
1677
+ * not to sibling listeners on the same node. Dismissal is now gated on `isTopmost`
1678
+ * from the shared layer stack.
1679
+ * - **A text-selection drag dismissed the dialog.** Outside-press used `click`, whose
1680
+ * target for a drag is the nearest common ancestor — the scrim. Now `pointerdown`.
1681
+ * - **Forward Tab could walk out of the panel.** The trap only compared against the
1682
+ * last tabbable element; once focus was outside by any other route, Tab roamed the
1683
+ * background freely. A `focusin` guard now pulls focus back.
1684
+ * - **Fixed-position elements were excluded from the trap.** The visibility filter was
1685
+ * `offsetParent !== null`, which is `null` for `position: fixed`. Element collection
1686
+ * is delegated to `tabbable`, which also honours real tab order (a positive
1687
+ * `tabindex` reorders the sequence, so DOM order was the wrong answer), `inert`,
1688
+ * `[aria-disabled]`, `contenteditable`, `<summary>`, media with controls, and
1689
+ * descendants of a disabled `<fieldset>`.
1690
+ * - **Initial focus was a silent no-op for a content-only dialog.** It fell back to
1691
+ * focusing the panel, which does nothing without `tabIndex="-1"`. The hook now sets
1692
+ * that itself, and retries once content arrives asynchronously.
1693
+ * - **Focus restore could land on a detached node**, resetting focus to `<body>`.
1694
+ * Now checked with `isConnected`.
1695
+ * - No opt-out existed for either dismissal route. Both are now vetoable.
1696
+ */
1697
+ declare function useOverlayDismiss({ onDismiss, panelRef, active, closeOnEscape, closeOnOutsidePress, trapFocus, lockScroll, inertBackground, autoFocus, initialFocus, returnFocus, onEscapeKeyDown, onInteractOutside, }: UseOverlayDismissOptions): void;
1698
+
1699
+ /**
1700
+ * `clsx` + `tailwind-merge`, taught this system's type scale.
1701
+ *
1702
+ * Use this instead of bare `clsx` in any component whose `className` prop is meant to
1703
+ * *override* a base utility — the composable `Card*` and `Modal*` parts, and anything
1704
+ * else built to be reshaped by its caller.
1705
+ *
1706
+ * Why it is necessary: `clsx` only concatenates. When two conflicting Tailwind
1707
+ * utilities both end up in the attribute, the winner is decided by *stylesheet order*,
1708
+ * not attribute order. Tailwind emits `flex-row` before `flex-col` and `gap-3` before
1709
+ * `gap-4`, so under plain `clsx`:
1710
+ *
1711
+ * <CardBody className="flex-row gap-3" /> // base is 'flex flex-col gap-4 p-4'
1712
+ *
1713
+ * silently stays a column with a 4-unit gap. `twMerge` drops the losing class instead,
1714
+ * so the caller's intent wins.
1715
+ *
1716
+ * Everywhere else in the library `className` is purely additive, and plain `clsx`
1717
+ * remains correct — and cheaper. Do not sweep it out of those files.
1718
+ */
1719
+ declare function cn(...inputs: ClassValue[]): string;
1720
+
1721
+ type CardSize = 'sm' | 'md' | 'lg';
1722
+ type CardRadius = 'lg' | 'xl' | '2xl';
1723
+ type CardTone = 'default' | 'brand' | 'positive' | 'warning' | 'danger';
1724
+ type CardFooterAlign = 'start' | 'between' | 'end';
1725
+ interface CardProps extends HTMLAttributes<HTMLDivElement> {
1726
+ children: ReactNode;
1727
+ /** `2xl` suits detail pages, `xl` section panels, `lg` dense or nested cards. */
1728
+ radius?: CardRadius;
1729
+ /**
1730
+ * Surface tint. This is a prop rather than a `className` because a tone has to
1731
+ * un-set the base `border-default bg-default` pair, not add to it.
1732
+ */
1733
+ tone?: CardTone;
1734
+ }
1735
+ /**
1736
+ * The card shell. Composed from `CardHeader`, `CardBody` and `CardFooter` — or from
1737
+ * nothing at all, if you want content to bleed to the edges (drop `CardBody` and put
1738
+ * a `DataTable` straight inside).
1739
+ *
1740
+ * Replaces `SectionCard` and the two monolithic cards that shipped beside it,
1741
+ * `AlertCard` and `BenchmarkCard`. Both of those are now documented compositions; see
1742
+ * the Cards page. The vocabulary follows shadcn/ui so it is already familiar, with
1743
+ * `CardBody` in place of its `CardContent`.
1744
+ */
1745
+ declare function Card({ children, radius, tone, className, ...rest }: CardProps): react.JSX.Element;
1746
+ interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {
1747
+ children: ReactNode;
1748
+ size?: CardSize;
1749
+ /** Bottom rule separating the header from the body. */
1750
+ divider?: boolean;
1751
+ }
1752
+ /**
1753
+ * Header row. Holds `CardTitle`, `CardDescription` and an optional `CardAction`.
1754
+ *
1755
+ * The `has-[…]` selector switches to a two-column grid only when a `CardAction` is
1756
+ * present, which is what lets title, description and action share a header with no
1757
+ * wrapper div and no stray gap when the action is absent.
1758
+ */
1759
+ declare function CardHeader({ children, size, divider, className, ...rest }: CardHeaderProps): react.JSX.Element;
1760
+ interface CardTitleProps extends HTMLAttributes<HTMLElement> {
1761
+ children: ReactNode;
1762
+ size?: CardSize;
1763
+ /** Heading level. Defaults to `p`; use h2/h3 where the page has a real hierarchy. */
1764
+ as?: 'h2' | 'h3' | 'h4' | 'p';
1765
+ }
1766
+ declare function CardTitle({ children, size, as: Tag, className, ...rest }: CardTitleProps): react.JSX.Element;
1767
+ interface CardDescriptionProps extends HTMLAttributes<HTMLParagraphElement> {
1768
+ children: ReactNode;
1769
+ /** Overrides the size inherited from the enclosing `CardHeader`. */
1770
+ size?: CardSize;
1771
+ }
1772
+ declare function CardDescription({ children, size, className, ...rest }: CardDescriptionProps): react.JSX.Element;
1773
+ interface CardActionProps extends HTMLAttributes<HTMLDivElement> {
1774
+ children: ReactNode;
1775
+ }
1776
+ /** Right-hand slot in a `CardHeader` — a button, a count, a status badge, a menu. */
1777
+ declare function CardAction({ children, className, ...rest }: CardActionProps): react.JSX.Element;
1778
+ interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {
1779
+ children: ReactNode;
1780
+ size?: CardSize;
1781
+ }
1782
+ /**
1783
+ * The content region. A vertical stack by default.
1784
+ *
1785
+ * Because this file uses `cn`, `className` genuinely overrides the base — so
1786
+ * `className="flex-row items-center"` gives you a row, and
1787
+ * `className="grid grid-cols-3"` a grid. That is what makes the `AlertCard` and
1788
+ * `BenchmarkCard` rebuilds possible without a `layout` prop.
1789
+ */
1790
+ declare function CardBody({ children, size, className, ...rest }: CardBodyProps): react.JSX.Element;
1791
+ interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {
1792
+ children: ReactNode;
1793
+ size?: CardSize;
1794
+ divider?: boolean;
1795
+ align?: CardFooterAlign;
1796
+ }
1797
+ /** Action row at the foot of a card. Mirrors `ModalFooter` and `Drawer`'s footer. */
1798
+ declare function CardFooter({ children, size, divider, align, className, ...rest }: CardFooterProps): react.JSX.Element;
1799
+
1800
+ type AccordionType = 'single' | 'multiple';
1801
+ interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
1802
+ children: ReactNode;
1803
+ /** `single` closes the open item when another opens. Default `single`. */
1804
+ type?: AccordionType;
1805
+ /** Open item value(s) — a string for `single`, an array for `multiple`. */
1806
+ value?: string | string[];
1807
+ defaultValue?: string | string[];
1808
+ onValueChange?: (value: string | string[]) => void;
1809
+ /** Allow closing the open item in `single` mode. Default `true`. */
1810
+ collapsible?: boolean;
1811
+ /**
1812
+ * Heading level for each item's trigger. Default `3`.
1813
+ *
1814
+ * Each trigger is wrapped in a real heading, per the APG, so the accordion appears in
1815
+ * the document outline and a screen reader can jump between sections by heading. The
1816
+ * right level depends on what surrounds it, which only the caller knows.
1817
+ */
1818
+ headingLevel?: 2 | 3 | 4;
1819
+ }
1820
+ /**
1821
+ * Accordion. Matches Figma's `Accordion` / `Accordion Item` (`State: Closed | Open`).
1822
+ *
1823
+ * Width is deliberately not set — Figma's own note on `Accordion Item` says the 640px in
1824
+ * the component set is a container artefact and the parent should own width, so this is
1825
+ * `w-full` and nothing more.
1826
+ */
1827
+ declare function Accordion({ children, type, value: valueProp, defaultValue, onValueChange, collapsible, headingLevel, className, ...rest }: AccordionProps): react.JSX.Element;
1828
+ interface AccordionItemProps extends HTMLAttributes<HTMLDivElement> {
1829
+ children: ReactNode;
1830
+ value: string;
1831
+ disabled?: boolean;
1832
+ }
1833
+ declare function AccordionItem({ children, value, disabled, className, ...rest }: AccordionItemProps): react.JSX.Element;
1834
+ interface AccordionTriggerProps extends HTMLAttributes<HTMLButtonElement> {
1835
+ children: ReactNode;
1836
+ /** Hide the chevron — for a trigger that supplies its own affordance. */
1837
+ hideIndicator?: boolean;
1838
+ }
1839
+ declare function AccordionTrigger({ children, hideIndicator, className, ...rest }: AccordionTriggerProps): react.JSX.Element;
1840
+ interface AccordionContentProps extends HTMLAttributes<HTMLDivElement> {
1841
+ children: ReactNode;
1842
+ }
1843
+ declare function AccordionContent({ children, className, ...rest }: AccordionContentProps): react.JSX.Element | null;
1844
+
1845
+ interface CollapsibleProps extends HTMLAttributes<HTMLDivElement> {
1846
+ children: ReactNode;
1847
+ open?: boolean;
1848
+ defaultOpen?: boolean;
1849
+ onOpenChange?: (open: boolean) => void;
1850
+ disabled?: boolean;
1851
+ }
1852
+ /**
1853
+ * A show/hide region with a trigger. The single-item primitive behind `Accordion`.
1854
+ *
1855
+ * The whole point is the wiring, which is easy to get wrong by hand: the trigger needs
1856
+ * `aria-expanded` and `aria-controls`, the panel needs an id and a matching
1857
+ * `aria-labelledby`, and the panel must be genuinely removed from the accessibility tree
1858
+ * when closed — `height: 0` with `overflow: hidden` leaves its content focusable and
1859
+ * announceable, so a keyboard user tabs into a collapsed section.
1860
+ */
1861
+ declare function Collapsible({ children, open: openProp, defaultOpen, onOpenChange, disabled, className, ...rest }: CollapsibleProps): react.JSX.Element;
1862
+ interface CollapsibleTriggerProps extends HTMLAttributes<HTMLButtonElement> {
1863
+ children?: ReactNode;
1864
+ asChild?: boolean;
1865
+ }
1866
+ declare function CollapsibleTrigger({ children, asChild, className, ...rest }: CollapsibleTriggerProps): react.JSX.Element;
1867
+ interface CollapsibleContentProps extends HTMLAttributes<HTMLDivElement> {
1868
+ children: ReactNode;
1869
+ /**
1870
+ * Keep the content mounted while closed, hidden with `hidden`. Default `false`.
1871
+ *
1872
+ * `hidden` — not `height: 0` — is what keeps hidden content out of the tab sequence and
1873
+ * the accessibility tree, so this stays safe. Use it to preserve form state or scroll
1874
+ * position across collapses.
1875
+ */
1876
+ keepMounted?: boolean;
1877
+ }
1878
+ declare function CollapsibleContent({ children, keepMounted, className, ...rest }: CollapsibleContentProps): react.JSX.Element | null;
1879
+
1880
+ interface AspectRatioProps extends HTMLAttributes<HTMLDivElement> {
1881
+ children: ReactNode;
1882
+ /** Width ÷ height. `16 / 9` for video, `1` for a square, `4 / 3` for a photo. Default `1`. */
1883
+ ratio?: number;
1884
+ }
1885
+ /**
1886
+ * Holds a fixed width-to-height ratio for its content.
1887
+ *
1888
+ * Uses the CSS `aspect-ratio` property rather than the old padding-top percentage hack, so
1889
+ * the child is a normal in-flow element instead of being absolutely positioned inside a
1890
+ * zero-height box. The ratio is an inline style because it is a per-instance numeric value —
1891
+ * a Tailwind class cannot express `16 / 9` without an arbitrary-value escape at every call
1892
+ * site.
1893
+ */
1894
+ declare const AspectRatio: react.ForwardRefExoticComponent<AspectRatioProps & react.RefAttributes<HTMLDivElement>>;
1895
+
1896
+ /**
1897
+ * Styled native scrollbars, for the components that must own their own overflow and so
1898
+ * cannot delegate to `ScrollArea`.
1899
+ *
1900
+ * Two kinds qualify. A table wrapper, a tab strip or a stepper, where inserting another
1901
+ * element would break the layout or the `<table>` element relationship; and a floating panel
1902
+ * that is already its own scroll container. Both hold focusable children, so a keyboard user
1903
+ * can already reach and scroll them — which is the one thing `ScrollArea` adds beyond these
1904
+ * classes, and the one thing they do not need.
1905
+ *
1906
+ * Prefer `ScrollArea` for a scrolling *region* of content. Reach for this only when a wrapper
1907
+ * element is not an option, and say why at the call site.
1908
+ *
1909
+ * A plain string module rather than an export from `scroll-area.tsx`: `menu-styles.ts` needs
1910
+ * it, and importing a component module from a style module would pull the component into the
1911
+ * bundle graph for the sake of a class list.
1912
+ */
1913
+ declare const SCROLLBAR_CLASSES: string;
1914
+
1915
+ type ScrollAreaAxis = 'vertical' | 'horizontal' | 'both';
1916
+ interface ScrollAreaProps extends HTMLAttributes<HTMLDivElement> {
1917
+ children: ReactNode;
1918
+ axis?: ScrollAreaAxis;
1919
+ /**
1920
+ * Accessible name for the scrollable region. Strongly recommended — a scroll container
1921
+ * that becomes focusable (see below) needs to announce what it is.
1922
+ */
1923
+ label?: string;
1924
+ }
1925
+
1926
+ /**
1927
+ * A scrollable region with styled scrollbars.
1928
+ *
1929
+ * **Native scrolling, deliberately.** shadcn/Radix replaces the scrollbar with a rendered
1930
+ * one, which looks tidier and costs real accessibility: an overlay scrollbar has to
1931
+ * reimplement keyboard scrolling, momentum, trackpad and pen behaviour, and the OS
1932
+ * "click the track to page" convention — and it drops out entirely if the JS fails. Styling
1933
+ * `::-webkit-scrollbar` plus `scrollbar-width`/`scrollbar-color` gets most of the look with
1934
+ * none of that risk, and degrades to a normal scrollbar where unsupported.
1935
+ *
1936
+ * The one thing this *does* add is the piece browsers get wrong: a scroll container is not
1937
+ * keyboard focusable by default in Chrome or Safari, so a keyboard-only user cannot scroll
1938
+ * an overflowing `<div>` at all unless something inside it is focusable. This measures its
1939
+ * own content and sets `tabIndex={0}` only while it actually overflows, so the region is
1940
+ * scrollable with the arrow keys without adding a pointless tab stop when it does not.
1941
+ */
1942
+ declare const ScrollArea: react.ForwardRefExoticComponent<ScrollAreaProps & react.RefAttributes<HTMLDivElement>>;
1943
+
1944
+ interface CarouselProps extends HTMLAttributes<HTMLDivElement> {
1945
+ children: ReactNode;
1946
+ /** Names the carousel region. Required — a nameless region is not navigable. */
1947
+ label: string;
1948
+ index?: number;
1949
+ defaultIndex?: number;
1950
+ onIndexChange?: (index: number) => void;
1951
+ /** Number of slides. Needed up front for the controls; `CarouselSlide` count is checked against it. */
1952
+ count: number;
1953
+ loop?: boolean;
1954
+ /** Advance every N ms. Omit for a manual carousel. */
1955
+ autoplayInterval?: number;
1956
+ }
1957
+ /**
1958
+ * A slide carousel.
1959
+ *
1960
+ * Carousels are one of the most reliably inaccessible patterns on the web, so the parts that
1961
+ * look like polish here are the requirements:
1962
+ *
1963
+ * - **`aria-roledescription="carousel"`** on a named region, so it is announced as a carousel
1964
+ * rather than as an anonymous group of divs.
1965
+ * - **Slides are `role="group"` with `aria-roledescription="slide"` and an
1966
+ * "N of M" label** — position is otherwise invisible to anyone not seeing the dots.
1967
+ * - **Off-screen slides are `hidden`**, not merely translated out of view. A slide moved with
1968
+ * `transform` keeps its links in the tab order, so keyboard users tab into content they
1969
+ * cannot see. This is the single most common carousel bug.
1970
+ * - **Autoplay stops on hover, on focus, and permanently once the user takes control**, and
1971
+ * there is a visible pause button whenever autoplay is on — required by WCAG 2.2.2 for any
1972
+ * motion lasting more than five seconds.
1973
+ * - **`prefers-reduced-motion` disables autoplay entirely**, rather than just shortening the
1974
+ * transition.
1975
+ */
1976
+ declare function Carousel({ children, label, index: indexProp, defaultIndex, onIndexChange, count, loop, autoplayInterval, className, ...rest }: CarouselProps): react.JSX.Element;
1977
+ interface CarouselViewportProps extends HTMLAttributes<HTMLDivElement> {
1978
+ children: ReactNode;
1979
+ }
1980
+ declare function CarouselViewport({ children, className, ...rest }: CarouselViewportProps): react.JSX.Element;
1981
+ interface CarouselSlideProps extends HTMLAttributes<HTMLDivElement> {
1982
+ children: ReactNode;
1983
+ }
1984
+ declare function CarouselSlide({ children, className, ...rest }: CarouselSlideProps): react.JSX.Element;
1985
+ interface CarouselControlsProps extends HTMLAttributes<HTMLDivElement> {
1986
+ /** Show the dot indicators. Default `true`. */
1987
+ showDots?: boolean;
1988
+ }
1989
+ declare function CarouselControls({ showDots, className, ...rest }: CarouselControlsProps): react.JSX.Element;
1990
+
1991
+ type ResizableDirection = 'horizontal' | 'vertical';
1992
+ interface ResizableProps extends HTMLAttributes<HTMLDivElement> {
1993
+ children: ReactNode;
1994
+ direction?: ResizableDirection;
1995
+ /** First pane's size as a percentage. Controlled. */
1996
+ size?: number;
1997
+ defaultSize?: number;
1998
+ onSizeChange?: (size: number) => void;
1999
+ /** Percentage bounds. Defaults `10` and `90`. */
2000
+ min?: number;
2001
+ max?: number;
2002
+ }
2003
+ /**
2004
+ * Two resizable panes with a draggable divider.
2005
+ *
2006
+ * This is the APG **window splitter** pattern, and the handle is the whole component as far
2007
+ * as accessibility goes. A `<div>` with pointer listeners — the usual implementation — is
2008
+ * completely unusable without a mouse. `ResizableHandle` is therefore a real focusable
2009
+ * control with:
2010
+ *
2011
+ * - `role="separator"` plus `aria-valuenow`/`valuemin`/`valuemax`, so the current split is
2012
+ * announced as a percentage rather than being invisible;
2013
+ * - `tabIndex={0}` and arrow keys to move it in 1% steps, Shift+arrow in 10%, Home/End to
2014
+ * the bounds, and Enter to collapse and restore;
2015
+ * - `aria-controls` pointing at the pane it resizes.
2016
+ *
2017
+ * Sizes are percentages, not pixels, so the split survives a container resize — a pixel
2018
+ * split silently becomes wrong the moment the window changes.
2019
+ */
2020
+ declare function Resizable({ children, direction, size: sizeProp, defaultSize, onSizeChange, min, max, className, ...rest }: ResizableProps): react.JSX.Element;
2021
+ interface ResizablePanelProps extends HTMLAttributes<HTMLDivElement> {
2022
+ children: ReactNode;
2023
+ /** `first` is the pane the handle sizes; `second` fills the remainder. */
2024
+ which: 'first' | 'second';
2025
+ }
2026
+ declare function ResizablePanel({ children, which, className, ...rest }: ResizablePanelProps): react.JSX.Element;
2027
+ interface ResizableHandleProps extends HTMLAttributes<HTMLDivElement> {
2028
+ /** Names the splitter. Default `Resize panels`. */
2029
+ label?: string;
2030
+ /** Show the grip dots. Default `true`. */
2031
+ withGrip?: boolean;
2032
+ }
2033
+ declare function ResizableHandle({ label, withGrip, className, ...rest }: ResizableHandleProps): react.JSX.Element;
2034
+
2035
+ /**
2036
+ * Two genuinely different heading contexts, which the source markup distinguished:
2037
+ *
2038
+ * `page` 24px title / 14px subtitle — an in-body page heading (settings, users,
2039
+ * alerts), i.e. the old `text-2xl` + `mt-1 text-body-sm` block.
2040
+ * `toolbar` 20px title / 13px subtitle — inside a `PageToolbar`, where the bar is
2041
+ * only 72px tall. Flattening these into one size would have grown ten
2042
+ * toolbar titles by 4px.
2043
+ * `section` 18px — a panel or card heading.
2044
+ */
2045
+ type PageHeadingSize = 'page' | 'toolbar' | 'section';
2046
+ interface PageHeadingProps {
2047
+ title: ReactNode;
2048
+ subtitle?: ReactNode;
2049
+ size?: PageHeadingSize;
2050
+ /** Heading level. Defaults to `h1` for page/toolbar and `h2` for section. */
2051
+ as?: 'h1' | 'h2' | 'h3';
2052
+ /** Right-aligned action cluster. When set, the heading becomes a flex row. */
2053
+ actions?: ReactNode;
2054
+ /** Clamp a long title to one line — needed when the title is user data, e.g. an article headline. */
2055
+ truncateTitle?: boolean;
2056
+ className?: string;
2057
+ }
2058
+ /**
2059
+ * Page or section title with an optional subtitle underneath.
2060
+ *
2061
+ * Replaces nine copies of the `<h1>` + `<p className="mt-1 …">` block, plus the
2062
+ * heading halves of `SettingsTabs` and `my-account/tabs`.
2063
+ *
2064
+ * Emitting a real heading element matters: `reviewer-detail`,
2065
+ * `settings-audit-log`'s table area and `widget-gallery` render their titles as
2066
+ * `<p>`/`<div>` today, so `getByRole('heading')` finds nothing there — an
2067
+ * accessibility gap the e2e specs currently work around.
2068
+ */
2069
+ declare function PageHeading({ title, subtitle, size, as, actions, truncateTitle, className, }: PageHeadingProps): react.JSX.Element;
2070
+
2071
+ type PageToolbarSize = 'sm' | 'md';
2072
+ interface PageToolbarProps {
2073
+ children: ReactNode;
2074
+ /** Allow the row to wrap when the action cluster is wide (entity-detail has seven buttons). */
2075
+ wrap?: boolean;
2076
+ /**
2077
+ * The bar's **own** height and padding. `sm` suits a secondary bar under the main toolbar.
2078
+ *
2079
+ * Not to be confused with `FilterBar.size`, which sets the density of the controls
2080
+ * *inside* the row. Same literals, different subject: a bar sizes itself, a row of
2081
+ * controls sizes its children. `PageToolbar` passes nothing down.
2082
+ */
2083
+ size?: PageToolbarSize;
2084
+ className?: string;
2085
+ }
2086
+ /**
2087
+ * The sticky top bar on a full-bleed detail or list screen: title block on the
2088
+ * left, actions on the right.
2089
+ *
2090
+ * Replaces ten copies of this class string. Three of those copies used the
2091
+ * responsive `px-4 py-4 md:px-7` and seven used a fixed `px-7 py-4`; the responsive
2092
+ * variant is adopted here, which is a deliberate improvement below `md` where the
2093
+ * fixed 28px padding was cramped.
2094
+ */
2095
+ declare function PageToolbar({ children, wrap, size, className }: PageToolbarProps): react.JSX.Element;
2096
+
2097
+ type FilterBarSize = 'sm' | 'md';
2098
+ interface FilterBarProps {
2099
+ children: ReactNode;
2100
+ /** Right-aligned slot for a result count or a secondary action. */
2101
+ trailing?: ReactNode;
2102
+ /**
2103
+ * Row density. Sets the gap between controls **and** the default `size` of the controls
2104
+ * inside — an Input, Select, Combobox, DatePicker or Button that is not given its own
2105
+ * `size` inherits this one. Pass `size` on a child to opt it out.
2106
+ *
2107
+ * `sm` is for a filter row inside a card or drawer: 8px gaps and 24px controls.
2108
+ */
2109
+ size?: FilterBarSize;
2110
+ className?: string;
2111
+ }
2112
+ /**
2113
+ * Row of search inputs and filter selects above a table.
2114
+ *
2115
+ * Replaces nine copies of `flex flex-wrap items-center gap-3`.
2116
+ *
2117
+ * Through 0.4.0 `size` set only the gap, so every caller had to repeat it on each control
2118
+ * and the page documenting this component got it wrong: its `size="sm"` example put a 24px
2119
+ * Input beside a 36px Select. A container with a size prop should mean it, so the size now
2120
+ * reaches the controls through `ControlSizeProvider`.
2121
+ */
2122
+ declare function FilterBar({ children, trailing, size, className }: FilterBarProps): react.JSX.Element;
2123
+
2124
+ type TabsVariant = 'underline' | 'pill';
2125
+ type TabsSize = 'sm' | 'md';
2126
+ type TabsOrientation = 'horizontal' | 'vertical';
2127
+ /**
2128
+ * `automatic` selects as focus moves, which is the APG default and right when panels are
2129
+ * cheap. `manual` requires Enter/Space — use it when switching tab triggers a fetch, so
2130
+ * arrowing across five tabs does not fire five requests.
2131
+ */
2132
+ type TabsActivation = 'automatic' | 'manual';
2133
+ interface TabItem<K extends string = string> {
2134
+ key: K;
2135
+ label: string;
2136
+ /** Renders a count chip after the label. */
2137
+ count?: number;
2138
+ disabled?: boolean;
2139
+ }
2140
+ interface TabsProps<K extends string = string> {
2141
+ items: TabItem<K>[];
2142
+ /** Controlled selection. Omit and pass `defaultValue` for uncontrolled. */
2143
+ value?: K;
2144
+ defaultValue?: K;
2145
+ onValueChange?: (key: K) => void;
2146
+ /**
2147
+ * `underline` is the detail-page form (entity detail, reviewer detail, role detail).
2148
+ * `pill` is the filter-style form used by the reviewer queue.
2149
+ */
2150
+ variant?: TabsVariant;
2151
+ /** `md` is the page-level strip; `sm` suits a tab strip inside a card or drawer. */
2152
+ size?: TabsSize;
2153
+ orientation?: TabsOrientation;
2154
+ activation?: TabsActivation;
2155
+ /**
2156
+ * Shared prefix for the generated tab and panel ids. Pass the same value to `TabsPanel`
2157
+ * to wire `aria-controls` / `aria-labelledby`. Generated when omitted.
2158
+ */
2159
+ idPrefix?: string;
2160
+ /** Names the tab strip. Required by the APG when there is more than one on a page. */
2161
+ label?: string;
2162
+ className?: string;
2163
+ }
2164
+ declare const tabId: (prefix: string, key: string) => string;
2165
+ declare const tabPanelId: (prefix: string, key: string) => string;
2166
+ /**
2167
+ * Tab strip.
2168
+ *
2169
+ * Reworked in 0.4.0. It previously carried `role="tablist"`, `role="tab"` and
2170
+ * `aria-selected` with **no `onKeyDown` at all** — no Arrow keys, no Home/End, no roving
2171
+ * tabindex, no `aria-controls`, and no `role="tabpanel"` counterpart anywhere in the
2172
+ * library. That combination is worse than shipping no ARIA: a screen reader announces
2173
+ * "tab 3 of 5", the user presses the arrow keys it implies, and nothing happens. Every
2174
+ * tab was also individually tabbable, so Tab walked the strip instead of leaving it.
2175
+ *
2176
+ * The `underline` active colour is `background-brand` (#0C2D58), which is what Figma
2177
+ * specifies.
2178
+ */
2179
+ declare function Tabs<K extends string = string>({ items, value: valueProp, defaultValue, onValueChange, variant, size, orientation, activation, idPrefix, label, className, }: TabsProps<K>): react.JSX.Element;
2180
+ interface TabsPanelProps extends HTMLAttributes<HTMLDivElement> {
2181
+ /** The `key` of the tab this panel belongs to. */
2182
+ tabKey: string;
2183
+ /** Must match the `idPrefix` given to `Tabs`. */
2184
+ idPrefix: string;
2185
+ /** Whether this panel's tab is the selected one. */
2186
+ active: boolean;
2187
+ children: ReactNode;
2188
+ /**
2189
+ * Keep the panel mounted while hidden. Default `false`. Mounting all panels preserves
2190
+ * scroll position and form state across tab switches at the cost of rendering them all.
2191
+ */
2192
+ keepMounted?: boolean;
2193
+ }
2194
+ /**
2195
+ * The `role="tabpanel"` half of the pattern, which the library had no equivalent of —
2196
+ * so `aria-controls` on a tab pointed at nothing and there was no labelled region for a
2197
+ * screen reader to move into.
2198
+ *
2199
+ * `tabIndex={0}` is deliberate and required: when a panel contains no focusable element,
2200
+ * it must be reachable itself, otherwise Tab from the selected tab skips the content
2201
+ * entirely.
2202
+ */
2203
+ declare function TabsPanel({ tabKey, idPrefix, active, children, keepMounted, className, ...rest }: TabsPanelProps): react.JSX.Element | null;
2204
+
2205
+ type NavItemSize = 'sm' | 'md';
2206
+ type NavItemVariant = 'card' | 'plain';
2207
+ interface NavItemProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
2208
+ /**
2209
+ * Leading glyph. Optional, but when `collapsed` it is the only thing left to look at, so
2210
+ * a row without one falls back to a monogram taken from the label.
2211
+ */
2212
+ icon?: ReactNode;
2213
+ label: string;
2214
+ /**
2215
+ * The row you are on — the current route. Paints the brand fill and, under `asChild`, sets
2216
+ * `aria-current="page"`; it also reflects to `data-state="active"`.
2217
+ *
2218
+ * Not the same thing as focus, though Figma's `MenuButton` names this variant
2219
+ * `state=focussed`. That is a misnomer to fix on the design side: keyboard focus is the
2220
+ * ring below, it is transient and can land on any row, and if it painted the brand fill
2221
+ * too there would be no way to see which row is the current one while tabbing past it.
2222
+ */
2223
+ isActive?: boolean;
2224
+ /** Red indicator dot at top-right corner (e.g. unread count) */
2225
+ indicator?: boolean;
2226
+ /** Collapsed mode — label is visually hidden but stays in the accessibility tree. */
2227
+ collapsed?: boolean;
2228
+ /** Row height. `sm` suits a dense secondary nav or a nested group. */
2229
+ size?: NavItemSize;
2230
+ /**
2231
+ * Row weight.
2232
+ *
2233
+ * `card` gives every inactive row its own border and surface — right for a short primary
2234
+ * rail of eight or ten destinations, where each row is a target in its own right.
2235
+ * `plain` drops both, so an inactive row is just text: right for a long grouped nav,
2236
+ * where thirty bordered pills read as thirty cards rather than a list.
2237
+ *
2238
+ * A variant decides what a row looks like **at rest, and nothing else**. Hover and the
2239
+ * current-row fill are one vocabulary shared by both — see `STATE`. Through 0.5.0 each
2240
+ * variant defined its own, and `plain`'s was invisible against the rail it was written for.
2241
+ */
2242
+ variant?: NavItemVariant;
2243
+ /**
2244
+ * Render the single child element as the row, so the row itself is the link or button.
2245
+ *
2246
+ * `NavItem` is presentational by default — a `<span>` with hover styling. That is fine
2247
+ * inside a router `NavLink`, which is how `src/sidebar/` uses it, but on its own it is a
2248
+ * nav row that looks interactive and cannot be focused or activated. `asChild` is the
2249
+ * fix for anyone using it outside that wrapper:
2250
+ *
2251
+ * <NavItem asChild icon={<LuHouse />} label="Home">
2252
+ * <NavLink to="/" />
2253
+ * </NavItem>
2254
+ */
2255
+ asChild?: boolean;
2256
+ children?: ReactNode;
2257
+ className?: string;
2258
+ }
2259
+ declare function NavItem({ icon, label, isActive, indicator, collapsed, size, variant, asChild, children, className, ...rest }: NavItemProps): react.JSX.Element;
2260
+
2261
+ type EyebrowLabelVariant = 'uppercase' | 'plain';
2262
+ interface EyebrowLabelProps {
2263
+ children: ReactNode;
2264
+ /**
2265
+ * `uppercase` is the dominant form (nine of twelve source copies).
2266
+ * `plain` covers the entity-detail / reviewer-detail variant, whose label text is
2267
+ * already capitalised in the source string.
2268
+ */
2269
+ variant?: EyebrowLabelVariant;
2270
+ className?: string;
2271
+ }
2272
+ /**
2273
+ * Small semibold label above a group of fields.
2274
+ *
2275
+ * Replaces twelve copies across three variants:
2276
+ * `mb-2 text-body-tiny font-semibold uppercase tracking-wide …` (×9)
2277
+ * `text-[11px] font-semibold … tracking-wide` (×5, entity/reviewer detail)
2278
+ * `text-body-tiny font-semibold uppercase tracking-wider` (×2, entity onboarding)
2279
+ *
2280
+ * `text-body-tiny` is 11px, so the `text-[11px]` variant collapses into it exactly.
2281
+ * The `tracking-wider` copies become `tracking-wide` — a 0.0125em difference at 11px,
2282
+ * i.e. sub-pixel.
2283
+ */
2284
+ declare function EyebrowLabel({ children, variant, className }: EyebrowLabelProps): react.JSX.Element;
2285
+
2286
+ type SeparatorOrientation = 'horizontal' | 'vertical';
2287
+ interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {
2288
+ orientation?: SeparatorOrientation;
2289
+ /**
2290
+ * `true` when the rule is purely visual, which is the common case. A decorative
2291
+ * separator is `role="none"` and stays out of the accessibility tree; a semantic one
2292
+ * is `role="separator"` and announces a break between groups.
2293
+ */
2294
+ decorative?: boolean;
2295
+ }
2296
+ /**
2297
+ * A hairline rule. Matches Figma's `Menu Separator`, generalised to both orientations.
2298
+ *
2299
+ * Drawn as a filled element rather than a border, because a 1px border on a flex child
2300
+ * collapses to nothing at some zoom levels while a `1px` height does not — which is why
2301
+ * the preset carries a `divider` background token separate from `border-default`.
2302
+ */
2303
+ declare const Separator: react.ForwardRefExoticComponent<SeparatorProps & react.RefAttributes<HTMLDivElement>>;
2304
+
2305
+ type KbdSize = 'sm' | 'md';
2306
+ interface KbdProps extends HTMLAttributes<HTMLElement> {
2307
+ children: ReactNode;
2308
+ size?: KbdSize;
2309
+ }
2310
+ /**
2311
+ * A keyboard key. Matches Figma's `Menu Shortcut`.
2312
+ *
2313
+ * Renders a real `<kbd>` so assistive tech announces it as key input rather than as a
2314
+ * stray glyph — `⌘K` read as plain text is "place of interest sign K".
2315
+ *
2316
+ * Pass one key per element and let the caller supply the joiner, so a shortcut reads as
2317
+ * separate keys instead of one run-together string:
2318
+ *
2319
+ * <Kbd>⌘</Kbd><Kbd>K</Kbd>
2320
+ */
2321
+ declare const Kbd: react.ForwardRefExoticComponent<KbdProps & react.RefAttributes<HTMLElement>>;
2322
+
2323
+ interface BreadcrumbProps extends HTMLAttributes<HTMLElement> {
2324
+ children: ReactNode;
2325
+ /** Names the landmark. Default `Breadcrumb`. */
2326
+ label?: string;
2327
+ }
2328
+ /**
2329
+ * Breadcrumb trail.
2330
+ *
2331
+ * A `<nav>` wrapping an ordered list, which is the whole semantic point: the order *is* the
2332
+ * hierarchy, so `<ol>` says something `<div>` cannot, and the landmark lets a screen reader
2333
+ * user jump to the trail without walking the header.
2334
+ *
2335
+ * The separators are `aria-hidden` and generated by the list, not passed in — a chevron
2336
+ * announced between every crumb is noise, and the `/` characters people usually hand-type
2337
+ * get read out one by one.
2338
+ */
2339
+ declare const Breadcrumb: react.ForwardRefExoticComponent<BreadcrumbProps & react.RefAttributes<HTMLElement>>;
2340
+ interface BreadcrumbItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
2341
+ children: ReactNode;
2342
+ /**
2343
+ * The page you are on. Renders as plain text with `aria-current="page"` rather than a
2344
+ * link — a link to the current page is a dead control, and the APG says the last crumb
2345
+ * should not be one.
2346
+ */
2347
+ current?: boolean;
2348
+ /** Render a router `Link` instead of an `<a>`. */
2349
+ asChild?: boolean;
2350
+ /** Suppress the leading separator. Set automatically on the first item you render. */
2351
+ first?: boolean;
2352
+ }
2353
+ declare const BreadcrumbItem: react.ForwardRefExoticComponent<BreadcrumbItemProps & react.RefAttributes<HTMLAnchorElement>>;
2354
+ interface BreadcrumbEllipsisProps extends HTMLAttributes<HTMLSpanElement> {
2355
+ }
2356
+ /**
2357
+ * Stands in for collapsed middle crumbs on a deep trail.
2358
+ *
2359
+ * A `<span>`, not a button: it is a truncation marker, and making it a disabled control
2360
+ * puts an unusable stop in the tab order. If the hidden crumbs need to be reachable, wrap
2361
+ * this in a `DropdownMenuTrigger` and list them.
2362
+ */
2363
+ declare const BreadcrumbEllipsis: react.ForwardRefExoticComponent<BreadcrumbEllipsisProps & react.RefAttributes<HTMLSpanElement>>;
2364
+
2365
+ type PaginationType = 'default' | 'dots';
2366
+ interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {
2367
+ /** 1-based. */
2368
+ page: number;
2369
+ /** Total number of pages. Values below 1 render nothing. */
2370
+ pageCount: number;
2371
+ onPageChange: (page: number) => void;
2372
+ /** Matches Figma's `Type` axis. `dots` is the compact carousel form. */
2373
+ type?: PaginationType;
2374
+ /** How many numbered pages to show either side of the current one. Default `1`. */
2375
+ siblingCount?: number;
2376
+ /** Names the nav landmark. Default `Pagination`. */
2377
+ label?: string;
2378
+ }
2379
+ declare const GAP = "\u2026";
2380
+ /**
2381
+ * Builds the visible page list with ellipses.
2382
+ *
2383
+ * Always returns first and last, the current page, and `siblingCount` either side. The
2384
+ * window is widened rather than allowed to shrink near the ends, so the control does not
2385
+ * change width as the user pages through — a row of buttons that reflows under the cursor
2386
+ * is how you mis-click.
2387
+ */
2388
+ declare function paginationRange(page: number, pageCount: number, siblingCount?: number): (number | typeof GAP)[];
2389
+ /**
2390
+ * Pagination. Matches Figma's `Pagination` (`Type: Default | Dots`), `Pagination Page`
2391
+ * (`State: Default | Hover | Current | Current Hover`), `Pagination Next` / `Previous`
2392
+ * (`Default | Hover | Disabled`) and `Pagination dots` (`Active | Inactive`).
2393
+ *
2394
+ * `DataTable` had no pager at all, so every consumer built one. Notes on the semantics:
2395
+ *
2396
+ * - A `<nav>` landmark with a name, so it is reachable by landmark navigation.
2397
+ * - `aria-current="page"` on the active page. It is the only non-visual signal of which
2398
+ * page you are on; the filled background is not announced.
2399
+ * - Each page button is named "Page 3", not "3" — a bare number read out of context tells
2400
+ * a screen reader user nothing about what activating it does.
2401
+ * - The ellipsis is inert text, not a disabled button, so it is skipped rather than
2402
+ * announced as an unavailable control.
2403
+ */
2404
+ declare const Pagination: react.ForwardRefExoticComponent<PaginationProps & react.RefAttributes<HTMLElement>>;
2405
+
2406
+ type NavigationMenuOrientation = 'horizontal' | 'vertical';
2407
+ type NavigationMenuVariant = 'pill' | 'link';
2408
+ interface NavigationMenuProps extends HTMLAttributes<HTMLElement> {
2409
+ children: ReactNode;
2410
+ orientation?: NavigationMenuOrientation;
2411
+ /** Names the nav landmark. Required when a page has more than one `<nav>`. */
2412
+ label: string;
2413
+ }
2414
+ /**
2415
+ * A navigation landmark wrapping a list of links. Matches Figma's `Navigation Pill List`
2416
+ * and `Navigation Button List`.
2417
+ *
2418
+ * Why the `<nav>` + `<ul>` + `<li>` nesting rather than a flat row of anchors: the list is
2419
+ * what makes a screen reader announce "list, 5 items" and lets the user jump the whole
2420
+ * block. A bare row of links is announced one at a time with no sense of how many there
2421
+ * are or where the set ends. The `label` is required for the same reason — an unnamed
2422
+ * landmark in a page with a sidebar *and* a top bar is not navigable.
2423
+ */
2424
+ declare const NavigationMenu: react.ForwardRefExoticComponent<NavigationMenuProps & react.RefAttributes<HTMLElement>>;
2425
+ interface NavigationMenuItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
2426
+ children: ReactNode;
2427
+ /** Matches Figma's `State: Active`. Sets `aria-current="page"`. */
2428
+ active?: boolean;
2429
+ variant?: NavigationMenuVariant;
2430
+ /** Render a router `Link` instead of an `<a>`. */
2431
+ asChild?: boolean;
2432
+ /** Leading glyph. Marked decorative automatically. */
2433
+ icon?: ReactNode;
2434
+ }
2435
+ /**
2436
+ * A single navigation link. Matches Figma's `Navigation Pill` and `Navigation Button`
2437
+ * (`State: Default | Active | Hover`).
2438
+ *
2439
+ * `aria-current="page"` is the point: the filled pill is not announced, so without it a
2440
+ * screen reader user cannot tell which page they are on.
2441
+ */
2442
+ declare const NavigationMenuItem: react.ForwardRefExoticComponent<NavigationMenuItemProps & react.RefAttributes<HTMLAnchorElement>>;
2443
+
2444
+ /**
2445
+ * The type ramp as components, mirroring Figma's `Text*` primitives one-for-one:
2446
+ * `Text`, `Text Strong`, `Text Emphasis`, `Text Small`, `Text Code`, `Text Link`,
2447
+ * `Text Heading`, `Text Subheading`, `Text Subtitle`, `Text Title Page`,
2448
+ * `Text Title Hero`, `Text List`, `Text List Item`, `Text Link List`.
2449
+ *
2450
+ * These existed in Figma with settled styles and had no code counterpart, so every
2451
+ * consumer reached for a raw `text-body-sm text-default` triplet and the ramp drifted.
2452
+ * Each component pins the size/weight/colour combination and nothing else, so layout
2453
+ * stays the caller's job.
2454
+ *
2455
+ * All of them take `asChild`, because the right element is contextual — a `Heading` is an
2456
+ * `<h2>` on a page and an `<h3>` inside a card, and only the caller knows the outline.
2457
+ */
2458
+ type BaseProps = HTMLAttributes<HTMLElement> & {
2459
+ children?: ReactNode;
2460
+ asChild?: boolean;
2461
+ };
2462
+ type TextProps = BaseProps;
2463
+ /** `Text` — the default body paragraph. */
2464
+ declare const Text: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2465
+ children?: ReactNode;
2466
+ asChild?: boolean;
2467
+ } & react.RefAttributes<HTMLElement>>;
2468
+ /** `Text Small` — secondary body copy. */
2469
+ declare const TextSmall: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2470
+ children?: ReactNode;
2471
+ asChild?: boolean;
2472
+ } & react.RefAttributes<HTMLElement>>;
2473
+ /** `Text Tiny` — the smallest readable step; captions and table meta. */
2474
+ declare const TextTiny: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2475
+ children?: ReactNode;
2476
+ asChild?: boolean;
2477
+ } & react.RefAttributes<HTMLElement>>;
2478
+ /** `Text Strong` — emphasis by weight, in a real `<strong>`. */
2479
+ declare const TextStrong: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2480
+ children?: ReactNode;
2481
+ asChild?: boolean;
2482
+ } & react.RefAttributes<HTMLElement>>;
2483
+ /** `Text Emphasis` — emphasis by slant, in a real `<em>`. */
2484
+ declare const TextEmphasis: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2485
+ children?: ReactNode;
2486
+ asChild?: boolean;
2487
+ } & react.RefAttributes<HTMLElement>>;
2488
+ /** `Text Code` — inline monospace. */
2489
+ declare const TextCode: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2490
+ children?: ReactNode;
2491
+ asChild?: boolean;
2492
+ } & react.RefAttributes<HTMLElement>>;
2493
+ /** `Text Title Hero` — the largest step, one per page at most. */
2494
+ declare const TitleHero: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2495
+ children?: ReactNode;
2496
+ asChild?: boolean;
2497
+ } & react.RefAttributes<HTMLElement>>;
2498
+ /** `Text Title Page` — page title. */
2499
+ declare const TitlePage: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2500
+ children?: ReactNode;
2501
+ asChild?: boolean;
2502
+ } & react.RefAttributes<HTMLElement>>;
2503
+ /** `Text Subtitle` — a lead paragraph under a title; regular weight by design. */
2504
+ declare const Subtitle: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2505
+ children?: ReactNode;
2506
+ asChild?: boolean;
2507
+ } & react.RefAttributes<HTMLElement>>;
2508
+ /** `Text Heading` — section heading. */
2509
+ declare const Heading: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2510
+ children?: ReactNode;
2511
+ asChild?: boolean;
2512
+ } & react.RefAttributes<HTMLElement>>;
2513
+ /** `Text Subheading` — subsection heading; regular weight, matching Figma. */
2514
+ declare const Subheading: react.ForwardRefExoticComponent<HTMLAttributes<HTMLElement> & {
2515
+ children?: ReactNode;
2516
+ asChild?: boolean;
2517
+ } & react.RefAttributes<HTMLElement>>;
2518
+ interface TextLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
2519
+ children?: ReactNode;
2520
+ asChild?: boolean;
2521
+ }
2522
+ /**
2523
+ * `Text Link`. Underlined rather than colour-only: colour alone is not a sufficient
2524
+ * distinction for a link inside a run of text (WCAG 1.4.1).
2525
+ */
2526
+ declare const TextLink: react.ForwardRefExoticComponent<TextLinkProps & react.RefAttributes<HTMLAnchorElement>>;
2527
+ type TextListVariant = 'bulleted' | 'numbered' | 'plain';
2528
+ type TextListDensity = 'default' | 'compact';
2529
+ interface TextListProps extends HTMLAttributes<HTMLElement> {
2530
+ children?: ReactNode;
2531
+ variant?: TextListVariant;
2532
+ /** Matches Figma's `Density` axis on `Text List` / `Text Link List`. */
2533
+ density?: TextListDensity;
2534
+ }
2535
+ /** `Text List` — a real `<ul>`/`<ol>`, so item count is announced. */
2536
+ declare const TextList: react.ForwardRefExoticComponent<TextListProps & react.RefAttributes<HTMLElement>>;
2537
+ type TextListItemProps = HTMLAttributes<HTMLLIElement> & {
2538
+ children?: ReactNode;
2539
+ };
2540
+ /** `Text List Item`. */
2541
+ declare const TextListItem: react.ForwardRefExoticComponent<HTMLAttributes<HTMLLIElement> & {
2542
+ children?: ReactNode;
2543
+ } & react.RefAttributes<HTMLLIElement>>;
2544
+
2545
+ type WidgetTitleSize = 'sm' | 'md' | 'lg';
2546
+ interface WidgetTitleProps {
2547
+ children: ReactNode;
2548
+ size?: WidgetTitleSize;
2549
+ className?: string;
2550
+ }
2551
+ declare function WidgetTitle({ children, size, className }: WidgetTitleProps): react.JSX.Element;
2552
+
2553
+ type WidgetHeaderEyebrowVariant = 'uppercase' | 'plain';
2554
+ interface WidgetHeaderProps {
2555
+ eyebrow?: string;
2556
+ eyebrowVariant?: WidgetHeaderEyebrowVariant;
2557
+ title: string;
2558
+ titleSize?: WidgetTitleSize;
2559
+ subtitle?: string;
2560
+ badge?: ReactNode;
2561
+ action?: ReactNode;
2562
+ className?: string;
2563
+ }
2564
+ declare function WidgetHeader({ eyebrow, eyebrowVariant, title, titleSize, subtitle, badge, action, className, }: WidgetHeaderProps): react.JSX.Element;
2565
+
2566
+ interface WidgetFooterProps {
2567
+ caption?: string;
2568
+ subcaption?: string;
2569
+ action?: ReactNode;
2570
+ className?: string;
2571
+ }
2572
+ declare function WidgetFooter({ caption, subcaption, action, className }: WidgetFooterProps): react.JSX.Element;
2573
+
2574
+ interface StatTileProps {
2575
+ label: string;
2576
+ value: string | number;
2577
+ /** Status tone for the leading dot. Prefer this over `dotColor`. */
2578
+ tone?: StatusTone;
2579
+ /**
2580
+ * @deprecated Pass `tone` instead. A raw colour here bypasses the token layer,
2581
+ * which is how competing status palettes drift apart.
2582
+ */
2583
+ dotColor?: string;
2584
+ className?: string;
2585
+ }
2586
+ declare function StatTile({ label, value, tone, dotColor, className }: StatTileProps): react.JSX.Element;
2587
+
2588
+ type StatNumberSize = 'sm' | 'md' | 'lg';
2589
+ type StatNumberWeight = 'medium' | 'bold';
2590
+ interface StatNumberProps {
2591
+ value: string | number;
2592
+ unit?: string;
2593
+ size?: StatNumberSize;
2594
+ weight?: StatNumberWeight;
2595
+ /** @deprecated Bypasses the design tokens — pass `tone` instead. Raw hex color, overrides the default text color via inline style. Use when the exact source color doesn't match a design token. */
2596
+ color?: string;
2597
+ className?: string;
2598
+ }
2599
+ declare function StatNumber({ value, unit, size, weight, color, className }: StatNumberProps): react.JSX.Element;
2600
+
2601
+ type ScoreValueSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
2602
+ type ScoreValueWeight = 'normal' | 'semibold' | 'bold';
2603
+ type ScoreTone = 'brand' | 'positive' | 'warning' | 'danger' | 'neutral' | 'default';
2604
+ type ScoreValueTone = ScoreTone | 'auto';
2605
+ /**
2606
+ * The four tones the automatic ramp can produce.
2607
+ *
2608
+ * Narrower than `ScoreTone` on purpose: a ramp position is always one of these, so the
2609
+ * result is directly assignable to `ProgressBarTone` too — which is what lets a caller
2610
+ * tone a bar and its score from one `getScoreTone` call.
2611
+ */
2612
+ type ScoreRampTone = 'positive' | 'neutral' | 'warning' | 'danger';
2613
+ /** Which end of the scale is the bad end. */
2614
+ type ScoreDirection = 'higher-is-worse' | 'higher-is-better';
2615
+ interface ScoreThresholds {
2616
+ /** At or above this, the score is `danger`. */
2617
+ danger: number;
2618
+ /** At or above this, `warning`. */
2619
+ warning: number;
2620
+ /** At or above this, `neutral`. Below it, `positive`. */
2621
+ neutral: number;
2622
+ }
2623
+ /**
2624
+ * Default ramp, on a 0–100 scale read as "higher is worse" — the risk case.
2625
+ *
2626
+ * 0.2.0's ramp had only four stops and resolved 65–79 to `brand` (the blue brand
2627
+ * colour), which left `warning` and `positive` unreachable without passing `tone`
2628
+ * by hand. This is a real five-stop ramp.
2629
+ */
2630
+ declare const DEFAULT_SCORE_THRESHOLDS: ScoreThresholds;
2631
+ /**
2632
+ * Resolve a numeric score to a tone.
2633
+ *
2634
+ * Was `getRiskTone` in 0.2.0, with the thresholds and the direction both hardcoded.
2635
+ */
2636
+ declare function getScoreTone(score: number, { direction, thresholds, }?: {
2637
+ direction?: ScoreDirection;
2638
+ thresholds?: ScoreThresholds;
2639
+ }): ScoreRampTone;
2640
+ interface ScoreValueProps {
2641
+ value: string | number;
2642
+ /** Trailing caption — `/100`, `High`, `of target`. */
2643
+ label?: string;
2644
+ size?: ScoreValueSize;
2645
+ weight?: ScoreValueWeight;
2646
+ /** `auto` derives the tone from `value` via {@link getScoreTone}. */
2647
+ tone?: ScoreValueTone;
2648
+ direction?: ScoreDirection;
2649
+ thresholds?: ScoreThresholds;
2650
+ className?: string;
2651
+ }
2652
+ /**
2653
+ * A scored number with an optional caption and a tone that can track its value.
2654
+ *
2655
+ * Was `RiskScore`. Nothing about it was ever risk-specific except the name and the
2656
+ * direction of its ramp, so both are now parameters: use it for a risk score, a
2657
+ * compliance score, a match confidence, a utilisation percentage.
2658
+ *
2659
+ * Not to be confused with `StatNumber`, which is the *large display* number with a
2660
+ * unit (32–48px, for tiles and widget headlines). `ScoreValue` is the inline one with
2661
+ * a label and a tone ramp.
2662
+ */
2663
+ declare function ScoreValue({ value, label, size, weight, tone, direction, thresholds, className, }: ScoreValueProps): react.JSX.Element;
2664
+
2665
+ type TileGridColumns = 2 | 3 | 4 | 5 | 6;
2666
+ /**
2667
+ * Responsive column counts. Every source copy started two-up on mobile and stepped
2668
+ * to its full count at one breakpoint.
2669
+ *
2670
+ * The twelve source grids disagreed on which: seven used `lg:`, three used `md:`.
2671
+ * Standardising on `lg:` matches eight of them byte-for-byte and is the safer choice
2672
+ * — five tiles at `md` (768px) was cramped. `alerts`, `settings-users` and
2673
+ * `settings-organization` therefore stay two-up slightly longer on tablets than
2674
+ * before; that is the one deliberate layout change here.
2675
+ *
2676
+ * Six keeps its intermediate `sm:grid-cols-3` step, matching entities-listing —
2677
+ * without it, six tiles would stack 2×3 on tablet instead of 3×2.
2678
+ */
2679
+ type TileGridBreakpoint = 'sm' | 'md' | 'lg';
2680
+ interface TileGridProps {
2681
+ children: ReactNode;
2682
+ columns?: TileGridColumns;
2683
+ /**
2684
+ * Breakpoint at which the grid reaches its full column count. `lg` is the default
2685
+ * and correct for a full-width page. Narrow contexts — a stat row inside a panel,
2686
+ * as on the article detail page — legitimately need `sm`.
2687
+ */
2688
+ at?: TileGridBreakpoint;
2689
+ className?: string;
2690
+ }
2691
+ /**
2692
+ * A responsive grid of equal-width tiles.
2693
+ *
2694
+ * Was `StatTileGrid`, which read as a `StatTile`-specific component. It has never been
2695
+ * coupled to one: no context, no cloning, no constraint on `children`. It takes any
2696
+ * nodes — `StatTile`s, `Card`s, chart tiles — and only owns the column counts and the
2697
+ * `gap-3`. The rename says so.
2698
+ */
2699
+ declare function TileGrid({ children, columns, at, className, }: TileGridProps): react.JSX.Element;
2700
+
2701
+ /**
2702
+ * Chart colour.
2703
+ *
2704
+ * SVG paints via the `stroke` / `fill` *attributes*, which cannot take a Tailwind
2705
+ * class — so charts resolve a `tone` to a CSS variable reference instead of a utility.
2706
+ * That keeps them on the token layer; 0.2.0's charts defaulted to raw hex (`#0c2d58`,
2707
+ * `rgba(140,155,176,0.5)`) and drifted from it.
2708
+ *
2709
+ * Every chart still accepts an explicit `color` string for genuinely data-driven
2710
+ * colour — a series whose colour comes from the data, not from semantics.
2711
+ */
2712
+ type ChartTone = 'brand' | 'info' | 'positive' | 'warning' | 'danger' | 'neutral';
2713
+ declare const CHART_TONE: Record<ChartTone, string>;
2714
+ /** The muted track/rest colour behind a highlighted series. */
2715
+ declare const CHART_TRACK = "var(--color-background-default-tertiary)";
2716
+ /**
2717
+ * Ordered sequence for multi-series charts, so two donuts in the same product never
2718
+ * assign different colours to the same first category. Semantic tones come first
2719
+ * because a chart with two or three series is usually still saying something.
2720
+ */
2721
+ declare const CHART_SEQUENCE: ChartTone[];
2722
+ /** Resolve an explicit colour, else a tone, else the sequence position. */
2723
+ declare function resolveChartColor(color: string | undefined, tone: ChartTone | undefined, index?: number): string;
2724
+
2725
+ type BarChartOrientation = 'vertical' | 'horizontal';
2726
+ type BarChartSize = 'sm' | 'md' | 'lg';
2727
+ interface BarChartSeries {
2728
+ label: string;
2729
+ /** One value per category. */
2730
+ values: number[];
2731
+ tone?: ChartTone;
2732
+ color?: string;
2733
+ }
2734
+ interface BarChartProps {
2735
+ /** Category names — the axis labels. */
2736
+ categories: string[];
2737
+ series: BarChartSeries[];
2738
+ orientation?: BarChartOrientation;
2739
+ /** Stack series on top of each other instead of placing them side by side. */
2740
+ stacked?: boolean;
2741
+ size?: BarChartSize;
2742
+ /** Overall length of the value axis, in px. */
2743
+ length?: number;
2744
+ /** Show the category labels along the axis. */
2745
+ showLabels?: boolean;
2746
+ /** Print each bar's value at the end of the bar. Horizontal orientation only. */
2747
+ showValues?: boolean;
2748
+ radius?: number;
2749
+ label?: string;
2750
+ className?: string;
2751
+ }
2752
+ /**
2753
+ * Grouped or stacked bars, in either orientation.
2754
+ *
2755
+ * Horizontal is the orientation the library was missing and the one that actually suits
2756
+ * category data, because long category names get a full line of width rather than being
2757
+ * rotated or truncated under a vertical bar.
2758
+ *
2759
+ * Deliberately axis-light: one baseline, no gridlines, no ticks. For anything needing
2760
+ * real axes or interaction, this is the wrong component.
2761
+ */
2762
+ declare function BarChart({ categories, series, orientation, stacked, size, length, showLabels, showValues, radius, label, className, }: BarChartProps): react.JSX.Element | null;
2763
+
2764
+ type DonutChartSize = 'sm' | 'md' | 'lg';
2765
+ interface DonutSegment {
2766
+ label: string;
2767
+ value: number;
2768
+ /** Token-backed colour. Falls back to the segment's position in the chart sequence. */
2769
+ tone?: ChartTone;
2770
+ /** Explicit colour, for data-driven series. */
2771
+ color?: string;
2772
+ }
2773
+ interface DonutChartProps {
2774
+ segments: DonutSegment[];
2775
+ size?: DonutChartSize;
2776
+ /** Ring thickness in px. Overrides the `size` preset. */
2777
+ thickness?: number;
2778
+ /** Large text at the centre — a total, a percentage. */
2779
+ centerValue?: ReactNode;
2780
+ /** Caption beneath `centerValue`. */
2781
+ centerLabel?: ReactNode;
2782
+ /** Gap between segments, in degrees. */
2783
+ gap?: number;
2784
+ /** Accessible description. */
2785
+ label?: string;
2786
+ className?: string;
2787
+ }
2788
+ /**
2789
+ * A proportional ring.
2790
+ *
2791
+ * Drawn with `stroke-dasharray` on circles rather than arc paths: one element per
2792
+ * segment, no trigonometry, and the segments stay crisp at any thickness.
2793
+ */
2794
+ declare function DonutChart({ segments, size, thickness, centerValue, centerLabel, gap, label, className, }: DonutChartProps): react.JSX.Element;
2795
+
2796
+ type RadialGaugeSize = 'sm' | 'md' | 'lg';
2797
+ interface RadialGaugeProps {
2798
+ value: number;
2799
+ /** Top of the scale. */
2800
+ max?: number;
2801
+ size?: RadialGaugeSize;
2802
+ tone?: ChartTone;
2803
+ color?: string;
2804
+ /** Ring thickness in px. Overrides the `size` preset. */
2805
+ thickness?: number;
2806
+ /**
2807
+ * Sweep in degrees. 360 is a full ring; 270 leaves a gap at the bottom, which reads
2808
+ * more like a dial than a pie.
2809
+ */
2810
+ sweep?: number;
2811
+ /** Centre content. Defaults to the value; pass `null` for an empty ring. */
2812
+ children?: ReactNode;
2813
+ /** Caption beneath the centre value. */
2814
+ centerLabel?: ReactNode;
2815
+ label?: string;
2816
+ className?: string;
2817
+ }
2818
+ /**
2819
+ * A single-value arc — a score ring, a utilisation dial, a completion meter.
2820
+ *
2821
+ * The shape the library had no form for: `ProgressBar` covers linear progress and
2822
+ * `DonutChart` compares parts of a whole, but neither draws "one number against its
2823
+ * ceiling" in a round frame.
2824
+ */
2825
+ declare function RadialGauge({ value, max, size, tone, color, thickness, sweep, children, centerLabel, label, className, }: RadialGaugeProps): react.JSX.Element;
2826
+
2827
+ type SparklineVariant = 'line' | 'area';
2828
+ type SparklineSize = 'sm' | 'md' | 'lg';
2829
+ interface SparklineProps {
2830
+ data: number[];
2831
+ variant?: SparklineVariant;
2832
+ /** Token-backed colour. Ignored when `color` is set. */
2833
+ tone?: ChartTone;
2834
+ /** Explicit colour, for series whose colour comes from the data. */
2835
+ color?: string;
2836
+ size?: SparklineSize;
2837
+ /** Overrides the `size` preset. */
2838
+ width?: number;
2839
+ height?: number;
2840
+ strokeWidth?: number;
2841
+ /** Dot on the final point — useful when the line is the "current value". */
2842
+ showEndDot?: boolean;
2843
+ /**
2844
+ * Stretch to fill the container instead of drawing at a fixed pixel size.
2845
+ *
2846
+ * The `size` preset still sets the viewBox, so it decides the sampling density; the SVG then
2847
+ * scales to the box it is given. Stroke width is held constant with `non-scaling-stroke`,
2848
+ * without which a non-uniform stretch would thin the line on one axis and thicken it on the
2849
+ * other.
2850
+ */
2851
+ fill?: boolean;
2852
+ /** Accessible description. Omit to keep the chart decorative. */
2853
+ label?: string;
2854
+ className?: string;
2855
+ }
2856
+ /**
2857
+ * A compact trend line, with no axes and no interaction.
2858
+ *
2859
+ * `variant="area"` adds the gradient fill beneath the line that 0.2.0 had no way to
2860
+ * draw, which is what makes a sparkline readable at `lg` where a bare 1.5px stroke
2861
+ * looks thin.
2862
+ */
2863
+ declare function Sparkline({ data, variant, tone, color, size, width, height, strokeWidth, showEndDot, fill: stretch, label, className, }: SparklineProps): react.JSX.Element | null;
2864
+
2865
+ type MiniBarChartSize = 'sm' | 'md' | 'lg';
2866
+ type MiniBarChartOrientation = 'vertical' | 'horizontal';
2867
+ interface MiniBarChartProps {
2868
+ bars: number[];
2869
+ /** Colour of the highlighted bars. */
2870
+ tone?: ChartTone;
2871
+ color?: string;
2872
+ /** Colour of the un-highlighted bars. Defaults to the muted track token. */
2873
+ restColor?: string;
2874
+ /**
2875
+ * Which bars are highlighted. A number or list of indices; negatives count from the
2876
+ * end, so `-1` is the last bar. Pass `[]` to highlight none.
2877
+ *
2878
+ * Replaces 0.2.0's `highlightLastBar` boolean, which could only ever mean `-1`.
2879
+ */
2880
+ highlight?: number | number[];
2881
+ size?: MiniBarChartSize;
2882
+ /** Overrides the `size` preset. */
2883
+ width?: number;
2884
+ height?: number;
2885
+ gap?: number;
2886
+ orientation?: MiniBarChartOrientation;
2887
+ radius?: number;
2888
+ /**
2889
+ * Stretch to fill the container instead of drawing at a fixed pixel size.
2890
+ *
2891
+ * The `size` preset still sets the viewBox, so it decides the bar-to-gap proportions; the
2892
+ * SVG then scales to whatever box it is given. Without this a widget body could only hold a
2893
+ * chart at a hardcoded width, which stops being the right width as soon as the widget
2894
+ * reflows.
2895
+ */
2896
+ fill?: boolean;
2897
+ label?: string;
2898
+ className?: string;
2899
+ }
2900
+ /** A compact bar series with no axes — a distribution or a per-period count. */
2901
+ declare function MiniBarChart({ bars, tone, color, restColor, highlight, size, width, height, gap, orientation, radius, fill: stretch, label, className, }: MiniBarChartProps): react.JSX.Element | null;
2902
+
2903
+ type LegendDotSize = 'sm' | 'md';
2904
+ /** `line` is the swatch for a line series; `dot` and `square` for areas and bars. */
2905
+ type LegendDotShape = 'dot' | 'square' | 'line';
2906
+ interface LegendDotProps {
2907
+ /** Token-backed colour. Ignored when `color` is set. */
2908
+ tone?: ChartTone;
2909
+ /** Explicit colour, for data-driven series. */
2910
+ color?: string;
2911
+ size?: LegendDotSize;
2912
+ shape?: LegendDotShape;
2913
+ className?: string;
2914
+ }
2915
+ /** The colour swatch beside a series name. */
2916
+ declare function LegendDot({ tone, color, size, shape, className }: LegendDotProps): react.JSX.Element;
2917
+
2918
+ type ChartLegendOrientation = 'vertical' | 'horizontal';
2919
+ interface ChartLegendItem {
2920
+ label: string;
2921
+ /** Trailing value. Omit for a legend that only names the series. */
2922
+ count?: number | string;
2923
+ /** Token-backed colour. Falls back to the item's position in the chart sequence. */
2924
+ tone?: ChartTone;
2925
+ /** Explicit colour, for data-driven series. */
2926
+ color?: string;
2927
+ }
2928
+ interface ChartLegendProps {
2929
+ items: ChartLegendItem[];
2930
+ /**
2931
+ * `vertical` spreads each row to fill its container, so the counts align in a column
2932
+ * beside a donut. `horizontal` wraps inline, for a legend under a bar chart.
2933
+ */
2934
+ orientation?: ChartLegendOrientation;
2935
+ size?: LegendDotSize;
2936
+ shape?: LegendDotShape;
2937
+ className?: string;
2938
+ }
2939
+ /** Series names, swatches and optional values. */
2940
+ declare function ChartLegend({ items, orientation, size, shape, className, }: ChartLegendProps): react.JSX.Element;
2941
+
2942
+ type TrendLabelWeight = 'semibold' | 'bold';
2943
+ type TrendLabelSize = 'sm' | 'md' | 'lg';
2944
+ /**
2945
+ * Which direction is the good one.
2946
+ *
2947
+ * A delta component cannot infer this: +4% on-time delivery is good, +4% unit cost is
2948
+ * not. 0.2.0 had no such prop, so the only way to render a "rising is bad" delta was to
2949
+ * pass a raw hex — which is exactly what the deleted `BenchmarkCard` did, inverting its
2950
+ * own `positiveColor` default to red to compensate.
2951
+ */
2952
+ type TrendDirection = 'up-is-good' | 'up-is-bad';
2953
+ interface TrendLabelProps {
2954
+ value: number;
2955
+ suffix?: string;
2956
+ size?: TrendLabelSize;
2957
+ weight?: TrendLabelWeight;
2958
+ direction?: TrendDirection;
2959
+ /** Trend arrow. On by default — the docs described one long before there was one. */
2960
+ showArrow?: boolean;
2961
+ /** Explicit colour, for the rare data-driven case. Overrides the direction logic. */
2962
+ color?: string;
2963
+ className?: string;
2964
+ }
2965
+ /** A signed delta with a direction arrow, toned by whether the movement is good news. */
2966
+ declare function TrendLabel({ value, suffix, size, weight, direction, showArrow, color, className, }: TrendLabelProps): react.JSX.Element;
2967
+
2968
+ type ListRowDensity = 'default' | 'compact';
2969
+ type ListRowDivider = 'none' | 'top' | 'bottom';
2970
+ interface ListRowProps {
2971
+ /** Left of the title, on the title line — an icon badge, avatar, checkbox, file chip. */
2972
+ leading?: ReactNode;
2973
+ title?: ReactNode;
2974
+ /** Inline after the title — a Required/Optional chip, a count, a tag. */
2975
+ titleMeta?: ReactNode;
2976
+ /** Muted line under the title. */
2977
+ description?: ReactNode;
2978
+ /** Right end of the title line — a `StatusBadge`, a score, a timestamp. */
2979
+ meta?: ReactNode;
2980
+ /** Right-hand column spanning the whole row, vertically centred — actions, a `Toggle`. */
2981
+ trailing?: ReactNode;
2982
+ /** Full-width block below the title line — a `FileRow`, a `FileDropZone`, an alert, a nested list. */
2983
+ footer?: ReactNode;
2984
+ density?: ListRowDensity;
2985
+ divider?: ListRowDivider;
2986
+ /** Render an `<li>` instead of a `<div>` — use inside a `<ul>`/`<ol>`. */
2987
+ as?: 'div' | 'li';
2988
+ onClick?: () => void;
2989
+ /**
2990
+ * Accessible name for a clickable row. Strongly recommended whenever `onClick` is set:
2991
+ * without it the name is the concatenation of every slot's text.
2992
+ */
2993
+ 'aria-label'?: string;
2994
+ className?: string;
2995
+ }
2996
+ /**
2997
+ * The generic list row: six slots and no opinion about what goes in them.
2998
+ *
2999
+ * Replaces `DocumentRow` and `DocumentChecklistRow`, which baked one product's
3000
+ * document-upload flow — its status vocabulary, its five raw-hex pills and its
3001
+ * unicode-glyph labels — into the library. Every feature of those rows is reachable by
3002
+ * composing this with `FileRow`, `FileDropZone` and `StatusBadge`; see the docs.
3003
+ */
3004
+ declare function ListRow({ leading, title, titleMeta, description, meta, trailing, footer, density, divider, as: Tag, onClick, 'aria-label': ariaLabel, className, }: ListRowProps): react.JSX.Element;
3005
+
3006
+ interface FileRowProps {
3007
+ name: string;
3008
+ /** Muted second line — size, upload date, uploader. */
3009
+ detail?: ReactNode;
3010
+ /** Leading chip showing the file extension, e.g. `"PDF"`. Ignored when `leading` is set. */
3011
+ fileType?: string;
3012
+ /** Custom leading node — overrides `fileType`. */
3013
+ leading?: ReactNode;
3014
+ /** The canonical action. Renders a text link before `actions`. */
3015
+ onDownload?: () => void;
3016
+ downloadLabel?: string;
3017
+ /** Everything else on the right — `Button`s, a `DropdownMenu`. */
3018
+ actions?: ReactNode;
3019
+ className?: string;
3020
+ }
3021
+ /**
3022
+ * One attached file: name, optional detail line, and actions.
3023
+ *
3024
+ * This strip was hardcoded inline inside both `DocumentRow` and
3025
+ * `DocumentChecklistRow`. Nothing about it is document-specific — it is the same row
3026
+ * for a generated export, an invoice or an evidence attachment.
3027
+ */
3028
+ declare function FileRow({ name, detail, fileType, leading, onDownload, downloadLabel, actions, className, }: FileRowProps): react.JSX.Element;
3029
+
3030
+ type ScoredRowAlign = 'center' | 'end';
3031
+ /** 8 / 12 / 20 / 48px — the four gaps the source mockups actually used. */
3032
+ type ScoredRowGap = 'sm' | 'md' | 'lg' | 'xl';
3033
+ interface ScoredRowProps {
3034
+ /** Leading visual — an `EntityIconBadge`, an `Avatar`, a rank number, or nothing. */
3035
+ leading?: ReactNode;
3036
+ title: ReactNode;
3037
+ subtitle?: ReactNode;
3038
+ /** Fixed-width column between the title block and the meter. */
3039
+ aside?: ReactNode;
3040
+ /** The bar. Put a `<ProgressBar>` here — the row does not choose one for you. */
3041
+ meter?: ReactNode;
3042
+ /** Right-hand value — a `<ScoreValue>`, a `<TrendLabel>`, a `<Badge>`, a button. */
3043
+ trailing?: ReactNode;
3044
+ /** CSS width values. Omit one and that slot flexes instead. */
3045
+ titleWidth?: string;
3046
+ asideWidth?: string;
3047
+ meterWidth?: string;
3048
+ trailingWidth?: string;
3049
+ gap?: ScoredRowGap;
3050
+ /** Gap between `leading` and the title block. Defaults to `gap`. */
3051
+ leadingGap?: ScoredRowGap;
3052
+ align?: ScoredRowAlign;
3053
+ className?: string;
3054
+ }
3055
+ /**
3056
+ * A row with a title block, an optional bar and a right-hand value.
3057
+ *
3058
+ * Was `EntityRow`. The rename is the smaller half of the change: the old component
3059
+ * hardcoded `RiskScore`, `WidgetProgressBar`, `TrendLabel` and `getRiskTone`, which
3060
+ * locked it to one scoring domain and forced 32 props — including four raw
3061
+ * `CSSProperties` escape hatches and a magic `nameWidth = '133px'` — to make it fit
3062
+ * anything else. The score and the bar are now slots, so the caller decides.
3063
+ */
3064
+ declare function ScoredRow({ leading, title, subtitle, aside, meter, trailing, titleWidth, asideWidth, meterWidth, trailingWidth, gap, leadingGap, align, className, }: ScoredRowProps): react.JSX.Element;
3065
+
3066
+ type ProgressBarTone = 'brand' | 'positive' | 'warning' | 'danger' | 'neutral';
3067
+ type ProgressBarSize = 'xs' | 'sm' | 'md' | 'lg';
3068
+ interface ProgressBarProps {
3069
+ /** 0–100. Values outside the range are clamped. */
3070
+ value: number;
3071
+ tone?: ProgressBarTone;
3072
+ size?: ProgressBarSize;
3073
+ /** Caption above the bar. Also becomes the accessible name. */
3074
+ label?: string;
3075
+ /** Show the percentage at the right of the label row. */
3076
+ showValue?: boolean;
3077
+ /** CSS radius override, e.g. `'1px'` for a square-ended bar. Defaults to fully round. */
3078
+ radius?: string;
3079
+ /** Accessible name when there is no visible `label`. */
3080
+ 'aria-label'?: string;
3081
+ /**
3082
+ * Applied to the track. This is how you set a fixed width — `className="w-16"`.
3083
+ * It genuinely overrides the base `w-full` because this file uses `cn`.
3084
+ */
3085
+ className?: string;
3086
+ }
3087
+ /**
3088
+ * A horizontal progress / proportion bar.
3089
+ *
3090
+ * Was `WidgetProgressBar` in 0.2.0, which fixed the height at 6px and lived under
3091
+ * `widgets/` despite being a general-purpose primitive — so `TableCellProgress`
3092
+ * hand-rolled a second copy rather than reuse it. It also had no ARIA at all.
3093
+ */
3094
+ declare function ProgressBar({ value, tone, size, label, showValue, radius, 'aria-label': ariaLabel, className, }: ProgressBarProps): react.JSX.Element;
3095
+
3096
+ interface NumberedListItem {
3097
+ title: string;
3098
+ /** Second line under the title — a region, a category, an id. */
3099
+ subtitle?: string;
3100
+ score: number;
3101
+ /** Bar and value colour for this row. `auto` derives it from `score`. */
3102
+ tone?: ProgressBarTone | 'auto';
3103
+ }
3104
+ type NumberedListGap = 'sm' | 'md';
3105
+ interface NumberedListProps {
3106
+ items: NumberedListItem[];
3107
+ /** Which end of the scale is bad, for rows resolving `tone` automatically. */
3108
+ direction?: ScoreDirection;
3109
+ scoreSize?: ScoreValueSize;
3110
+ scoreWeight?: ScoreValueWeight;
3111
+ /** First ordinal. Set it to continue a list across a page boundary. */
3112
+ startAt?: number;
3113
+ gap?: NumberedListGap;
3114
+ className?: string;
3115
+ }
3116
+ /**
3117
+ * A ranked leaderboard: ordinal, title, score, and a full-width bar under each row.
3118
+ *
3119
+ * Was `RankedRow`, which was one row and made the caller supply both the `<ol>` and every
3120
+ * `rank` by hand — so a filtered or re-sorted list silently kept stale numbers. Owning the
3121
+ * list means the ordinal is derived from position and cannot disagree with the order on
3122
+ * screen. It also puts it at the same granularity as `StepsList`, its neighbour.
3123
+ *
3124
+ * It still hardcodes `ProgressBar` and `ScoreValue`, and that is the point: a leaderboard
3125
+ * row *is* those three things. Where the pieces need to vary, reach for `ScoredRow`, whose
3126
+ * slots take arbitrary content.
3127
+ */
3128
+ declare function NumberedList({ items, direction, scoreSize, scoreWeight, startAt, gap, className, }: NumberedListProps): react.JSX.Element;
3129
+
3130
+ interface IconTextRowProps {
3131
+ icon: ReactNode;
3132
+ title: string;
3133
+ detail: string;
3134
+ className?: string;
3135
+ }
3136
+ /**
3137
+ * A circular icon badge, a title, and one line of detail.
3138
+ *
3139
+ * Feature lists, empty-state explanations, onboarding intros, "what happens next"
3140
+ * steps. Was `FeatureRow`, which named it after the one screen it was extracted from.
3141
+ */
3142
+ declare function IconTextRow({ icon, title, detail, className }: IconTextRowProps): react.JSX.Element;
3143
+
3144
+ type ChecklistRowState = 'done' | 'active' | 'pending';
3145
+ interface ChecklistRowProps {
3146
+ label: string;
3147
+ state: ChecklistRowState;
3148
+ className?: string;
3149
+ }
3150
+ /**
3151
+ * One step in a progress checklist: a done tick, a spinning active ring, or an empty
3152
+ * pending ring.
3153
+ *
3154
+ * Shared by the event-onboarding "building your dashboard" screen and the
3155
+ * intelligence page's processing checklist. Both drove the same three states; only
3156
+ * the onboarding copy had the animated ring, which is the better treatment and is
3157
+ * adopted for both.
3158
+ *
3159
+ * Renders an `<li>` — callers must wrap it in a list, which is what both sources did.
3160
+ */
3161
+ declare function ChecklistRow({ label, state, className }: ChecklistRowProps): react.JSX.Element;
3162
+
3163
+ interface StepsListProps {
3164
+ steps: ReactNode[];
3165
+ className?: string;
3166
+ }
3167
+ /**
3168
+ * Ordered list of instructions with small filled number bullets.
3169
+ *
3170
+ * Was `NumberedStepsList`. Renamed in 0.5.0 because `NumberedList` — the ranked
3171
+ * leaderboard — also numbers its rows, and two components whose names both led with
3172
+ * "Numbered" gave no hint which was which. The distinction is what the numbers *mean*:
3173
+ * here they are sequence ("do this, then this"), there they are rank.
3174
+ *
3175
+ * The bullet was `bg-[#e7edfb] text-[#1d4ed8]` — a pale blue pair that is not in the
3176
+ * token set. It now uses the brand-tertiary background and brand text, which is the
3177
+ * documented treatment for a subtle brand-tinted chip.
3178
+ */
3179
+ declare function StepsList({ steps, className }: StepsListProps): react.JSX.Element;
3180
+
3181
+ type DetailItemLayout = 'stacked' | 'inline';
3182
+ type DetailItemSpan = 1 | 2 | 'full';
3183
+ interface DetailItemProps {
3184
+ label: string;
3185
+ value: ReactNode;
3186
+ /** Optional second line under the value. */
3187
+ detail?: ReactNode;
3188
+ /**
3189
+ * `stacked` puts the label above the value (detail pages, review summaries).
3190
+ * `inline` puts a fixed-width label beside it (drawer detail rows).
3191
+ */
3192
+ layout?: DetailItemLayout;
3193
+ /**
3194
+ * Columns to occupy inside a `DetailGrid`. `full` spans the row — for a long value
3195
+ * such as an alias list or a legal name that would otherwise truncate.
3196
+ */
3197
+ span?: DetailItemSpan;
3198
+ /**
3199
+ * Label column width for the `inline` layout. A `min-w`/`max-w` pair rather than a
3200
+ * fixed `w-`, so a long label wraps instead of colliding with the value.
3201
+ */
3202
+ labelWidth?: string;
3203
+ className?: string;
3204
+ }
3205
+ /**
3206
+ * A label/value pair.
3207
+ *
3208
+ * Was `MetaField` — an internal codename that said nothing about the shape. Consolidates
3209
+ * the same pair from six places: an entity-detail overview grid, a reviewer-detail metric
3210
+ * column, three `DetailRow` copies in drawers, and `ReviewMeta` in two onboarding wizards.
3211
+ *
3212
+ * An empty value renders an em dash, which is what every source copy did by hand. Note
3213
+ * that the check is for `null`/`undefined`/`''` only — `0` and `false` are real values and
3214
+ * render as themselves.
3215
+ */
3216
+ declare function DetailItem({ label, value, detail, layout, span, labelWidth, className, }: DetailItemProps): react.JSX.Element;
3217
+ type DetailGridColumns = 2 | 3 | 4 | 'auto';
3218
+ interface DetailGridProps {
3219
+ children: ReactNode;
3220
+ columns?: DetailGridColumns;
3221
+ className?: string;
3222
+ }
3223
+ /**
3224
+ * Wrapper for a set of `DetailItem`s.
3225
+ *
3226
+ * A real grid, not the `flex flex-wrap` it was as `MetaFieldGrid`. Under flex-wrap every
3227
+ * item had to carry its own width (`sm:w-[262px]` was the documented idiom) and whatever
3228
+ * space was left over at the end of a row stayed empty — so a three-item row in a wide
3229
+ * card had a ragged gap on the right. `1fr` tracks divide the row exactly, and an item
3230
+ * that genuinely needs more room asks for it with `span` instead of a magic width.
3231
+ */
3232
+ declare function DetailGrid({ children, columns, className }: DetailGridProps): react.JSX.Element;
3233
+
3234
+ type CheckedGroupListColumns = 1 | 2 | 3;
3235
+ /** One labelled group of ticked items. */
3236
+ interface CheckedGroup {
3237
+ label: string;
3238
+ items: string[];
3239
+ }
3240
+ interface CheckedGroupListProps {
3241
+ groups: CheckedGroup[];
3242
+ columns?: CheckedGroupListColumns;
3243
+ /** Leading glyph for every item. Defaults to a check; pass `null` for none. */
3244
+ icon?: ReactNode | null;
3245
+ emptyLabel?: string;
3246
+ className?: string;
3247
+ }
3248
+ /**
3249
+ * A read-only, grouped list of ticked items in a balanced multi-column flow.
3250
+ *
3251
+ * Was `PermissionGrid` — RBAC-specific naming for a generic shape, and not a grid
3252
+ * either: groups pack tightly down each column rather than aligning to shared row
3253
+ * heights, so a tall group beside a short one leaves no ragged gap.
3254
+ * `break-inside-avoid` keeps each group whole within a column.
3255
+ *
3256
+ * Granted permissions, included plan features, completed requirements, matched
3257
+ * criteria — anything that is "these labels, grouped, all ticked".
3258
+ */
3259
+ declare function CheckedGroupList({ groups, columns, icon, emptyLabel, className, }: CheckedGroupListProps): react.JSX.Element;
3260
+
3261
+ type TableDensity = 'default' | 'compact';
3262
+ type TableSortDirection = 'ascending' | 'descending';
3263
+ /**
3264
+ * The composable table primitive, matching Figma's `Table` and `Table cell`.
3265
+ *
3266
+ * `DataTable` is the config-driven form — you give it `columns` and `rows` and it renders
3267
+ * everything. It is the right tool most of the time, and it is not going away. But it
3268
+ * cannot express a grouped header, a footer row, a colspan, or a cell layout outside its
3269
+ * `render` signature, so anything unusual meant abandoning it for a hand-rolled `<table>`
3270
+ * with none of the semantics. These parts are that escape hatch with the semantics kept.
3271
+ *
3272
+ * Figma's `Table cell` has a 32-value `Style` axis (lead checkbox, lead avatar, badges
3273
+ * multiple, trend positive/negative, action icons, star ratings, payment method…). Those
3274
+ * are *compositions*, not variants of one component — each is an existing library
3275
+ * component dropped into a cell — so they are expressed here as `TableCell` plus whatever
3276
+ * goes inside it, rather than 32 props.
3277
+ */
3278
+ interface TableProps extends HTMLAttributes<HTMLTableElement> {
3279
+ /** Names the table. Required unless you render a `TableCaption`. */
3280
+ label?: string;
3281
+ density?: TableDensity;
3282
+ /** Equal-width columns driven by `<colgroup>`, matching `DataTable`. Default `false`. */
3283
+ fixed?: boolean;
3284
+ }
3285
+ declare const Table: react.ForwardRefExoticComponent<TableProps & react.RefAttributes<HTMLTableElement>>;
3286
+ interface TableCaptionProps extends HTMLAttributes<HTMLTableCaptionElement> {
3287
+ }
3288
+ /**
3289
+ * A visible table title that also names the table. Prefer this over `label` when the
3290
+ * heading is on screen anyway — `DataTable` could not be named at all before 0.4.0.
3291
+ */
3292
+ declare const TableCaption: react.ForwardRefExoticComponent<TableCaptionProps & react.RefAttributes<HTMLTableCaptionElement>>;
3293
+ declare const TableHeader: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableSectionElement> & react.RefAttributes<HTMLTableSectionElement>>;
3294
+ declare const TableBody: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableSectionElement> & react.RefAttributes<HTMLTableSectionElement>>;
3295
+ declare const TableFooter: react.ForwardRefExoticComponent<HTMLAttributes<HTMLTableSectionElement> & react.RefAttributes<HTMLTableSectionElement>>;
3296
+ interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {
3297
+ selected?: boolean;
3298
+ }
3299
+ declare const TableRow: react.ForwardRefExoticComponent<TableRowProps & react.RefAttributes<HTMLTableRowElement>>;
3300
+ interface TableHeadProps extends ThHTMLAttributes<HTMLTableCellElement> {
3301
+ /**
3302
+ * Makes the header a sort control. `false` means sortable but not currently sorted.
3303
+ *
3304
+ * `aria-sort` goes on the `<th>` and must be present on exactly one column at a time —
3305
+ * it is the only non-visual signal of sort state, and `DataTable` had none.
3306
+ */
3307
+ sort?: TableSortDirection | false;
3308
+ onSort?: () => void;
3309
+ align?: 'left' | 'center' | 'right';
3310
+ /** Keeps the header visible while the body scrolls. */
3311
+ sticky?: boolean;
3312
+ }
3313
+ declare const TableHead: react.ForwardRefExoticComponent<TableHeadProps & react.RefAttributes<HTMLTableCellElement>>;
3314
+ interface TableCellProps extends TdHTMLAttributes<HTMLTableCellElement> {
3315
+ align?: 'left' | 'center' | 'right';
3316
+ /** Vertical rhythm. Matches `DataTable`'s `density`. */
3317
+ density?: TableDensity;
3318
+ /** Makes this the row's header cell — `scope="row"`, for a table with row headers. */
3319
+ header?: boolean;
3320
+ }
3321
+ declare const TableCell: react.ForwardRefExoticComponent<TableCellProps & react.RefAttributes<HTMLTableCellElement>>;
3322
+
3323
+ interface ColumnDef<T> {
3324
+ key: string;
3325
+ header: string;
3326
+ /**
3327
+ * CSS width value — e.g. `"320px"`, `"10rem"`. When `grow` is true this becomes the
3328
+ * column's floor: it counts toward the table's min-width, below which the wrapper
3329
+ * scrolls sideways rather than crushing the columns.
3330
+ */
3331
+ width: string;
3332
+ /**
3333
+ * When true the column absorbs the remaining table width.
3334
+ *
3335
+ * With no `grow` column, `table-fixed` distributes surplus width proportionally
3336
+ * across every column — the old flex layout left it blank on the right instead. Mark
3337
+ * whichever column should soak it up.
3338
+ */
3339
+ grow?: boolean;
3340
+ render: (row: T) => ReactNode;
3341
+ }
3342
+ type DataTableDensity = 'default' | 'compact';
3343
+ type DataTableAlign = 'center' | 'top';
3344
+ interface DataTableProps<T> {
3345
+ columns: ColumnDef<T>[];
3346
+ rows: T[];
3347
+ getRowKey: (row: T, index: number) => Key;
3348
+ /** Row and header padding. `compact` also steps the header and cell type down. */
3349
+ density?: DataTableDensity;
3350
+ /** Vertical alignment of every body cell. Use `top` for multi-line or ragged cells. */
3351
+ align?: DataTableAlign;
3352
+ onRowClick?: (row: T) => void;
3353
+ /** Rendered as one full-width row when `rows` is empty. Omit to render nothing. */
3354
+ emptyLabel?: string;
3355
+ className?: string;
3356
+ }
3357
+ /**
3358
+ * A real `<table>` with `table-fixed` and a `<colgroup>`.
3359
+ *
3360
+ * 0.2.0 laid each row out as its own flex container sized `w-max`, so a `grow` column
3361
+ * sized itself per row and one long cell shunted that row's remaining columns out of
3362
+ * line with its neighbours. `table-fixed` resolves column widths once for the whole
3363
+ * table, which is the property the consuming app hand-rolled a separate audit table
3364
+ * to get.
3365
+ */
3366
+ declare function DataTable<T>({ columns, rows, getRowKey, density, align, onRowClick, emptyLabel, className, }: DataTableProps<T>): react.JSX.Element;
3367
+ /**
3368
+ * Cell type scale.
3369
+ *
3370
+ * Named `size`, not `density`, and deliberately *not* inherited from the table: the two
3371
+ * real compact tables disagree about the mapping — the audit table wants default
3372
+ * padding with small cell text — so inheritance could not express it anyway, and it
3373
+ * would make these render one size inside a table and another outside one.
3374
+ */
3375
+ type TableCellSize = 'sm' | 'md';
3376
+ interface TableCellLeadTextProps {
3377
+ primary: string;
3378
+ secondary?: string;
3379
+ size?: TableCellSize;
3380
+ className?: string;
3381
+ }
3382
+ /** Primary text plus an optional muted subtitle — for lead entity/name cells. */
3383
+ declare function TableCellLeadText({ primary, secondary, size, className }: TableCellLeadTextProps): react.JSX.Element;
3384
+ interface TableCellTextProps {
3385
+ children: ReactNode;
3386
+ /** Muted (secondary) by default; pass false for the primary colour. */
3387
+ muted?: boolean;
3388
+ size?: TableCellSize;
3389
+ /** Ellipsise instead of wrapping, so every row keeps the same height. */
3390
+ truncate?: boolean;
3391
+ className?: string;
3392
+ }
3393
+ /** Plain text cell. */
3394
+ declare function TableCellText({ children, muted, size, truncate, className, }: TableCellTextProps): react.JSX.Element;
3395
+ interface TableCellBadgeProps {
3396
+ label: string;
3397
+ className?: string;
3398
+ }
3399
+ /** Small outlined chip — entity type labels, categories. */
3400
+ declare function TableCellBadge({ label, className }: TableCellBadgeProps): react.JSX.Element;
3401
+ interface TableCellProgressProps {
3402
+ percent: number;
3403
+ /**
3404
+ * Bar colour. `brand` is 0.2.0's default and byte-identical to it — `bg-brand`
3405
+ * resolves to the same `--prim-brand-900` the old raw-hex default hardcoded.
3406
+ */
3407
+ tone?: ProgressBarTone;
3408
+ size?: TableCellSize;
3409
+ className?: string;
3410
+ }
3411
+ /** Mini progress bar with a percentage label below. */
3412
+ declare function TableCellProgress({ percent, tone, size, className, }: TableCellProgressProps): react.JSX.Element;
3413
+
3414
+ type InlineAlertTone = 'info' | 'warning' | 'danger' | 'positive';
3415
+ interface InlineAlertProps {
3416
+ tone: InlineAlertTone;
3417
+ children: ReactNode;
3418
+ /** Overrides the per-tone default glyph. Pass `null` for no icon. */
3419
+ icon?: ReactNode | null;
3420
+ className?: string;
3421
+ }
3422
+ /** Banner for inline messaging — form errors, destructive-action warnings, success confirmations.
3423
+ *
3424
+ * Replaces four byte-identical raw-`amber-*` callouts, five competing error-text styles and a
3425
+ * standalone `Banner` component. `danger` renders as `role="alert"`; the rest as `role="status"`. */
3426
+ declare function InlineAlert({ tone, children, icon, className }: InlineAlertProps): react.JSX.Element;
3427
+
3428
+ type EmptyStateVariant = 'empty' | 'loading' | 'error';
3429
+ type EmptyStateSize = 'sm' | 'md' | 'lg';
3430
+ interface EmptyStateProps {
3431
+ message: string;
3432
+ /** `error` is the only variant that changes colour; `loading` exists for intent. */
3433
+ variant?: EmptyStateVariant;
3434
+ size?: EmptyStateSize;
3435
+ icon?: ReactNode;
3436
+ /** A primary action, e.g. "Add your first source". */
3437
+ action?: ReactNode;
3438
+ className?: string;
3439
+ }
3440
+ /**
3441
+ * Centred placeholder for an empty list, a loading list, or a failed fetch.
3442
+ *
3443
+ * Replaces eighteen copies of `py-8 text-center text-body-sm
3444
+ * text-default-secondary` plus four divergent variants. Loading and empty were
3445
+ * always the same markup in this codebase, so they are one component with a
3446
+ * `variant` rather than two near-identical ones.
3447
+ *
3448
+ * `aria-live` is set for the loading and error variants so a screen reader announces
3449
+ * the state change instead of silently swapping list content.
3450
+ */
3451
+ declare function EmptyState({ message, variant, size, icon, action, className, }: EmptyStateProps): react.JSX.Element;
3452
+
3453
+ type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg';
3454
+ interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
3455
+ size?: SpinnerSize;
3456
+ /**
3457
+ * Accessible name. When omitted the spinner is marked decorative — correct when it sits
3458
+ * inside a control that already announces the pending state (`Button loading` sets
3459
+ * `aria-busy`), and wrong when the spinner is the only thing on screen.
3460
+ */
3461
+ label?: string;
3462
+ }
3463
+ /**
3464
+ * Indeterminate loading indicator. `ProgressBar` is the determinate counterpart.
3465
+ *
3466
+ * The spin is a border-based ring rather than an SVG so it inherits `currentColor` and
3467
+ * needs no fill/stroke plumbing — it works on any button variant unchanged. The animation
3468
+ * is suppressed under `prefers-reduced-motion` by the preset's base rule, which leaves a
3469
+ * static ring; that is why the transparent segment is a full quarter and still legible
3470
+ * when frozen.
3471
+ */
3472
+ declare const Spinner: react.ForwardRefExoticComponent<SpinnerProps & react.RefAttributes<HTMLSpanElement>>;
3473
+
3474
+ type SkeletonShape = 'line' | 'block' | 'circle';
3475
+ interface SkeletonProps extends HTMLAttributes<HTMLDivElement> {
3476
+ shape?: SkeletonShape;
3477
+ /** Number of stacked lines. Only meaningful for `line`. */
3478
+ lines?: number;
3479
+ }
3480
+ /**
3481
+ * Loading placeholder.
3482
+ *
3483
+ * `aria-hidden` and no role: a skeleton is a picture of content that does not exist yet,
3484
+ * so announcing it produces a burst of meaningless nodes. The *region* it sits in should
3485
+ * carry the loading state — `EmptyState variant="loading"` or `aria-busy` on the
3486
+ * container — which is a decision only the caller can make.
3487
+ *
3488
+ * The pulse is suppressed by the preset's `prefers-reduced-motion` rule, leaving a plain
3489
+ * tinted block.
3490
+ */
3491
+ declare const Skeleton: react.ForwardRefExoticComponent<SkeletonProps & react.RefAttributes<HTMLDivElement>>;
3492
+
3493
+ type BannerVariant = 'message' | 'alert';
3494
+ interface BannerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
3495
+ /** Bold first line. Matches Figma's `Title`. */
3496
+ title: ReactNode;
3497
+ /** Supporting copy. Matches Figma's `Body`. */
3498
+ children?: ReactNode;
3499
+ /**
3500
+ * Matches Figma's `Variant` axis. `message` is informational; `alert` is urgent and is
3501
+ * announced immediately.
3502
+ */
3503
+ variant?: BannerVariant;
3504
+ tone?: InlineAlertTone;
3505
+ /** Replaces the tone glyph. Pass `null` to suppress it. Matches `Icon` / `Has Icon`. */
3506
+ icon?: ReactNode | null;
3507
+ /** Trailing action slot. Matches `Has Button`. */
3508
+ action?: ReactNode;
3509
+ /** Renders a dismiss button. Matches `Dismissible`. */
3510
+ onDismiss?: () => void;
3511
+ }
3512
+ /**
3513
+ * A page- or section-level banner with a title, body, optional action and optional dismiss.
3514
+ *
3515
+ * This is Figma's `Notification` set (`Variant: Message | Alert`, with `Title`, `Body`,
3516
+ * `Has Icon`, `Has Button` and `Dismissible`). Worth being precise about the name: its
3517
+ * Figma keywords are "message, alert, feedback, callout, banner" — it is a *persistent,
3518
+ * in-flow* notice, **not** a toast. A toast is transient, stacked, and announced from a
3519
+ * live region that already exists; that is `Toast`, and it is a different component.
3520
+ *
3521
+ * `InlineAlert` remains the compact single-line form for use inside a form or a card.
3522
+ * `Banner` is the one with a heading and an action.
3523
+ *
3524
+ * `variant` drives the announcement, not just the styling: `alert` is `role="alert"`
3525
+ * (interrupts), `message` is `role="status"` (waits its turn).
3526
+ */
3527
+ declare const Banner: react.ForwardRefExoticComponent<BannerProps & react.RefAttributes<HTMLDivElement>>;
3528
+
3529
+ type ToastTone = InlineAlertTone;
3530
+ type ToasterPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
3531
+ interface ToastOptions {
3532
+ title: ReactNode;
3533
+ description?: ReactNode;
3534
+ tone?: ToastTone;
3535
+ /** Milliseconds before auto-dismiss. `0` keeps it until dismissed. Default `5000`. */
3536
+ duration?: number;
3537
+ action?: ReactNode;
3538
+ }
3539
+ interface ToastRecord extends ToastOptions {
3540
+ id: string;
3541
+ }
3542
+ interface ToastContextValue {
3543
+ toast: (options: ToastOptions) => string;
3544
+ dismiss: (id: string) => void;
3545
+ dismissAll: () => void;
3546
+ }
3547
+ /**
3548
+ * Queue a toast. Must be called under a `<Toaster>`.
3549
+ *
3550
+ * Returns the toast's id so a long-running action can dismiss its own "Saving…" toast when
3551
+ * it finishes.
3552
+ */
3553
+ declare function useToast(): ToastContextValue;
3554
+ interface ToasterProps {
3555
+ children: ReactNode;
3556
+ position?: ToasterPosition;
3557
+ /** Maximum simultaneous toasts. Oldest are dropped first. Default `4`. */
3558
+ max?: number;
3559
+ /** Default auto-dismiss for toasts that do not set their own. Default `5000`. */
3560
+ duration?: number;
3561
+ }
3562
+ /**
3563
+ * Provider plus the region toasts render into. Mount once, near the app root.
3564
+ *
3565
+ * The library had no toast and — more importantly — **no persistent live region at all**,
3566
+ * so nothing could announce an event that happened away from focus. The distinction that
3567
+ * matters here: a live region must already exist in the DOM before content is put into it.
3568
+ * A region that mounts at the same moment as its message is frequently not announced,
3569
+ * which is why the wrapper below renders unconditionally and only its children come and go.
3570
+ *
3571
+ * `aria-live="polite"` on the container, and `role="alert"` on individual `danger` toasts
3572
+ * so a failure interrupts rather than queueing behind a success message.
3573
+ */
3574
+ declare function Toaster({ children, position, max, duration, }: ToasterProps): react.JSX.Element;
3575
+
3576
+ type PasswordInputProps = Omit<InputProps, 'type' | 'trailingIcon' | 'trailingAction'>;
3577
+ /** Password field with a show/hide visibility toggle. */
3578
+ declare const PasswordInput: react.ForwardRefExoticComponent<PasswordInputProps & react.RefAttributes<HTMLInputElement>>;
3579
+
3580
+ interface AIChatBarProps {
3581
+ placeholder?: string;
3582
+ className?: string;
3583
+ }
3584
+ declare function AIChatBar({ placeholder, className, }: AIChatBarProps): react.JSX.Element;
3585
+
3586
+ interface AISuggestionChipProps {
3587
+ prompt: string;
3588
+ onClick?: () => void;
3589
+ className?: string;
3590
+ }
3591
+ declare function AISuggestionChip({ prompt, onClick, className }: AISuggestionChipProps): react.JSX.Element;
3592
+
3593
+ interface QuickAction {
3594
+ label: string;
3595
+ value: string;
3596
+ }
3597
+ interface QuickActionsBarProps {
3598
+ actions: QuickAction[];
3599
+ active?: string;
3600
+ onSelect?: (value: string) => void;
3601
+ className?: string;
3602
+ }
3603
+ declare function QuickActionsBar({ actions, active, onSelect, className }: QuickActionsBarProps): react.JSX.Element;
3604
+
3605
+ /** Soft aurora atmosphere used by the public-facing screens (auth, event
3606
+ * onboarding) — mirrors AuroraBackground in pages/intelligence. Blobs are
3607
+ * corner-anchored so the effect scales from phones to kiosk displays.
3608
+ * Render inside a `relative overflow-hidden` container; content goes on top
3609
+ * with `relative`. */
3610
+ declare function AuroraBackdrop(): react.JSX.Element;
299
3611
 
300
- export { Avatar, AvatarBlock, type AvatarBlockProps, AvatarGroup, type AvatarGroupProps, type AvatarGroupSpacing, type AvatarImageProps, type AvatarInitialProps, type AvatarProps, type AvatarShape, type AvatarSize, Button, ButtonGroup, type ButtonGroupAlign, type ButtonGroupItem, type ButtonGroupProps, type ButtonGroupVariant, type ButtonProps, type ButtonSize, type ButtonVariant, type ColumnDef, DataTable, DocumentRow, type DocumentRowProps, type DocumentStatus, FileDropZone, type FileDropZoneProps, FormCard, FormCardFooter, type FormCardFooterProps, FormCardHeader, type FormCardHeaderProps, IconButton, type IconButtonProps, type IconButtonVariant, Input, type InputProps, type InputSize, MetricCard, Modal, type ModalProps, MultiSelectCard, type MultiSelectCardProps, NavItem, type NavItemProps, Panel, ROLE_COMBO_OPTIONS, RoleBadge, type RoleBadgeProps, RoleComboBox, type RoleComboBoxProps, type RoleOption, SectionHeading, Select, type SelectOption, type SelectProps, SentimentBadge, SeverityBadge, StatTile, type StatTileProps, type StepItem, type StepStatus, Stepper, type StepperProps, TableCellBadge, TableCellLeadText, TableCellProgress, TableCellStatusPill, TableCellText, Textarea, type TextareaProps, Toggle, type ToggleProps };
3612
+ export { AIChatBar, type AIChatBarProps, AISuggestionChip, type AISuggestionChipProps, Accordion, AccordionContent, type AccordionContentProps, AccordionItem, type AccordionItemProps, type AccordionProps, AccordionTrigger, type AccordionTriggerProps, type AccordionType, AspectRatio, type AspectRatioProps, AuroraBackdrop, Avatar, AvatarBlock, type AvatarBlockProps, AvatarGroup, type AvatarGroupProps, type AvatarGroupSpacing, type AvatarImageProps, type AvatarInitialProps, type AvatarProps, type AvatarShape, type AvatarSize, Badge, type BadgeColor, type BadgeProps, type BadgeSize, type BadgeVariant, Banner, type BannerProps, type BannerVariant, BarChart, type BarChartOrientation, type BarChartProps, type BarChartSeries, type BarChartSize, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEllipsisProps, BreadcrumbItem, type BreadcrumbItemProps, type BreadcrumbProps, Button, ButtonGroup, type ButtonGroupAlign, type ButtonGroupItem, type ButtonGroupProps, type ButtonGroupVariant, type ButtonProps, type ButtonSize, type ButtonVariant, CHART_SEQUENCE, CHART_TONE, CHART_TRACK, Calendar, type CalendarMode, type CalendarProps, Card, CardAction, type CardActionProps, CardBody, type CardBodyProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterAlign, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, type CardRadius, type CardSize, CardTitle, type CardTitleProps, type CardTone, Carousel, CarouselControls, type CarouselControlsProps, type CarouselProps, CarouselSlide, type CarouselSlideProps, CarouselViewport, type CarouselViewportProps, ChartLegend, type ChartLegendItem, type ChartLegendOrientation, type ChartLegendProps, type ChartTone, CheckIndicator, type CheckIndicatorProps, type CheckIndicatorStatus, Checkbox, type CheckboxProps, type CheckboxSize, type CheckedGroup, CheckedGroupList, type CheckedGroupListColumns, type CheckedGroupListProps, ChecklistRow, type ChecklistRowProps, type ChecklistRowState, Collapsible, CollapsibleContent, type CollapsibleContentProps, type CollapsibleProps, CollapsibleTrigger, type CollapsibleTriggerProps, type ColumnDef, Combobox, type ComboboxOption, type ComboboxProps, Command, type CommandItem, type CommandProps, ConfirmDialog, type ConfirmDialogProps, ContextMenu, MenuCheckboxItem as ContextMenuCheckboxItem, ContextMenuContent, type ContextMenuContentProps, MenuGroup as ContextMenuGroup, MenuItem as ContextMenuItem, MenuLabel as ContextMenuLabel, type ContextMenuProps, MenuRadioGroup as ContextMenuRadioGroup, MenuRadioItem as ContextMenuRadioItem, MenuSeparator as ContextMenuSeparator, MenuShortcut as ContextMenuShortcut, ContextMenuTrigger, type ContextMenuTriggerProps, ControlSizeProvider, type ControlSizeProviderProps, CountBadge, type CountBadgeProps, DEFAULT_SCORE_THRESHOLDS, DataTable, type DataTableAlign, type DataTableDensity, type DataTableProps, DatePicker, type DatePickerProps, type DateRange, DetailGrid, type DetailGridColumns, type DetailGridProps, DetailItem, type DetailItemLayout, type DetailItemProps, type DetailItemSpan, DonutChart, type DonutChartProps, type DonutChartSize, type DonutSegment, Drawer, type DrawerProps, DropdownMenu, MenuCheckboxItem as DropdownMenuCheckboxItem, type MenuCheckboxItemProps as DropdownMenuCheckboxItemProps, DropdownMenuContent, type DropdownMenuContentProps, MenuGroup as DropdownMenuGroup, type MenuGroupProps as DropdownMenuGroupProps, MenuItem as DropdownMenuItem, type MenuItemProps as DropdownMenuItemProps, type MenuItemTone as DropdownMenuItemTone, MenuLabel as DropdownMenuLabel, type MenuLabelProps as DropdownMenuLabelProps, type DropdownMenuProps, MenuRadioGroup as DropdownMenuRadioGroup, type MenuRadioGroupProps as DropdownMenuRadioGroupProps, MenuRadioItem as DropdownMenuRadioItem, type MenuRadioItemProps as DropdownMenuRadioItemProps, MenuSeparator as DropdownMenuSeparator, type MenuSeparatorProps as DropdownMenuSeparatorProps, MenuShortcut as DropdownMenuShortcut, type MenuShortcutProps as DropdownMenuShortcutProps, DropdownMenuTrigger, type DropdownMenuTriggerProps, EmptyState, type EmptyStateProps, type EmptyStateSize, type EmptyStateVariant, EntityIconBadge, type EntityIconBadgeProps, type EntityIconBadgeSize, type EntityIconBadgeTone, EyebrowLabel, type EyebrowLabelProps, type EyebrowLabelVariant, Field, type FieldContextValue, FieldDescription, FieldError, FieldGroup, type FieldGroupProps, FieldHint, FieldLabel, type FieldLabelProps, FieldLegend, type FieldLegendProps, type FieldOrientation, type FieldProps, FieldSeparator, type FieldSeparatorProps, FieldSet, type FieldSetProps, type FieldTextProps, FileDropZone, type FileDropZoneProps, FileRow, type FileRowProps, FilterBar, type FilterBarProps, type FilterBarSize, FormCard, FormCardFooter, type FormCardFooterProps, FormCardHeader, type FormCardHeaderProps, Heading, HoverCard, type HoverCardProps, IconButton, type IconButtonProps, type IconButtonVariant, IconTextRow, type IconTextRowProps, InlineAlert, type InlineAlertProps, type InlineAlertTone, Input, InputControl, type InputControlProps, InputGroup, InputGroupAddon, type InputGroupAddonProps, type InputGroupAlign, InputGroupInput, type InputGroupInputProps, type InputGroupProps, InputGroupText, type InputGroupTextProps, InputOTP, type InputOTPMode, type InputOTPProps, type InputProps, type InputSize, Kbd, type KbdProps, type KbdSize, Label, type LabelProps, LegendDot, type LegendDotProps, type LegendDotShape, type LegendDotSize, ListRow, type ListRowDensity, type ListRowDivider, type ListRowProps, Menubar, MenuCheckboxItem as MenubarCheckboxItem, MenubarContent, type MenubarContentProps, MenuGroup as MenubarGroup, MenuItem as MenubarItem, MenuLabel as MenubarLabel, MenubarMenu, type MenubarMenuProps, type MenubarProps, MenuRadioGroup as MenubarRadioGroup, MenuRadioItem as MenubarRadioItem, MenuSeparator as MenubarSeparator, MenuShortcut as MenubarShortcut, MenubarTrigger, type MenubarTriggerProps, MiniBarChart, type MiniBarChartOrientation, type MiniBarChartProps, type MiniBarChartSize, Modal, ModalBody, type ModalBodyProps, ModalDescription, type ModalDescriptionProps, ModalFooter, type ModalFooterAlign, type ModalFooterProps, ModalHeader, type ModalHeaderProps, type ModalProps, type ModalSize, ModalTitle, type ModalTitleProps, type ModalTone, MultiSelectCard, type MultiSelectCardProps, type MultiSelectCardSize, NavItem, type NavItemProps, type NavItemSize, type NavItemVariant, NavigationMenu, NavigationMenuItem, type NavigationMenuItemProps, type NavigationMenuOrientation, type NavigationMenuProps, type NavigationMenuVariant, NoteConfirmModal, type NoteConfirmModalProps, NumberedList, type NumberedListGap, type NumberedListItem, type NumberedListProps, OVERLAY_SCRIM, PageHeading, type PageHeadingProps, type PageHeadingSize, PageToolbar, type PageToolbarProps, type PageToolbarSize, Pagination, type PaginationProps, type PaginationType, PasswordInput, type PasswordInputProps, Popover, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger, type PopoverTriggerProps, Portal, type PortalProps, ProgressBar, type ProgressBarProps, type ProgressBarSize, type ProgressBarTone, type QuickAction, QuickActionsBar, type QuickActionsBarProps, ROLE_COMBO_OPTIONS, RadialGauge, type RadialGaugeProps, type RadialGaugeSize, Radio, RadioGroup, type RadioGroupOrientation, type RadioGroupProps, type RadioProps, Resizable, type ResizableDirection, ResizableHandle, type ResizableHandleProps, ResizablePanel, type ResizablePanelProps, type ResizableProps, RoleBadge, type RoleBadgeProps, type RoleBadgeTone, RoleComboBox, type RoleComboBoxProps, type RoleOption, SCROLLBAR_CLASSES, type ScoreDirection, type ScoreRampTone, type ScoreThresholds, type ScoreTone, ScoreValue, type ScoreValueProps, type ScoreValueSize, type ScoreValueTone, type ScoreValueWeight, ScoredRow, type ScoredRowAlign, type ScoredRowGap, type ScoredRowProps, ScrollArea, type ScrollAreaAxis, type ScrollAreaProps, SearchInput, type SearchInputProps, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectControl, type SelectControlProps, type SelectOption, type SelectOptionGroup, type SelectProps, Separator, type SeparatorOrientation, type SeparatorProps, Skeleton, type SkeletonProps, type SkeletonShape, Slider, type SliderProps, Sparkline, type SparklineProps, type SparklineSize, type SparklineVariant, Spinner, type SpinnerProps, type SpinnerSize, StatNumber, type StatNumberProps, type StatNumberSize, type StatNumberWeight, StatTile, type StatTileProps, StatusBadge, type StatusBadgeProps, type StatusBadgeSize, StatusChip, type StatusChipProps, StatusDot, type StatusDotProps, type StatusDotTone, type StatusTone, type StepItem, type StepStatus, Stepper, type StepperProps, type StepperSize, StepsList, type StepsListProps, Subheading, Subtitle, Switch, type SwitchProps, type SwitchSize, type TabItem, Table, TableBody, TableCaption, type TableCaptionProps, TableCell, TableCellBadge, type TableCellBadgeProps, TableCellLeadText, type TableCellLeadTextProps, TableCellProgress, type TableCellProgressProps, type TableCellProps, type TableCellSize, TableCellText, type TableCellTextProps, type TableDensity, TableFooter, TableHead, type TableHeadProps, TableHeader, type TableProps, TableRow, type TableRowProps, type TableSortDirection, Tabs, type TabsActivation, type TabsOrientation, TabsPanel, type TabsPanelProps, type TabsProps, type TabsSize, type TabsVariant, TagPill, type TagPillProps, type TagPillTone, Text, TextCode, TextEmphasis, TextLink, type TextLinkProps, TextList, type TextListDensity, TextListItem, type TextListItemProps, type TextListProps, type TextListVariant, type TextProps, TextSmall, TextStrong, TextTiny, Textarea, TextareaControl, type TextareaControlProps, type TextareaProps, TileGrid, type TileGridBreakpoint, type TileGridColumns, type TileGridProps, TitleHero, TitlePage, type ToastOptions, type ToastRecord, type ToastTone, Toaster, type ToasterPosition, type ToasterProps, Toggle, ToggleGroup, ToggleGroupItem, type ToggleGroupItemProps, type ToggleGroupProps, type ToggleGroupType, type ToggleProps, type ToggleSize, type ToggleVariant, Tooltip, type TooltipProps, TrailChip, type TrailChipProps, type TrendDirection, TrendLabel, type TrendLabelProps, type TrendLabelSize, type TrendLabelWeight, type UserAccountStatus, UserStatusPill, type UserStatusPillProps, WidgetFooter, type WidgetFooterProps, WidgetHeader, type WidgetHeaderEyebrowVariant, type WidgetHeaderProps, WidgetTitle, type WidgetTitleProps, type WidgetTitleSize, cn, getScoreTone, paginationRange, resolveChartColor, tabId, tabPanelId, useControlSize, useFieldContext, useFieldControl, useOverlayDismiss, useToast };