@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/README.md +116 -16
- package/dist/index.cjs +8911 -799
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3427 -115
- package/dist/index.d.ts +3427 -115
- package/dist/index.js +8847 -783
- package/dist/index.js.map +1 -1
- package/dist/sidebar.cjs +1372 -263
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.d.cts +125 -7
- package/dist/sidebar.d.ts +125 -7
- package/dist/sidebar.js +1402 -262
- package/dist/sidebar.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +33 -8
- package/tailwind-preset.cjs +349 -0
- package/tailwind-preset.js +0 -124
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, TextareaHTMLAttributes,
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
282
|
-
declare function
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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 };
|