@ceebee/ui 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/dist/client.d.ts +932 -0
- package/dist/client.js +2104 -0
- package/dist/index.d.ts +417 -0
- package/dist/index.js +486 -0
- package/dist/skins/astra.css +30 -0
- package/dist/styles.css +2498 -0
- package/package.json +68 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, TextareaHTMLAttributes, ReactElement } from 'react';
|
|
3
|
+
import * as _base_ui_react from '@base-ui/react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Every string the library says out loud. They are here rather than inline because a component
|
|
7
|
+
* that hard-codes "Previous slide" is an English component, and this library is used to build
|
|
8
|
+
* products that are not in English.
|
|
9
|
+
*/
|
|
10
|
+
interface Labels {
|
|
11
|
+
dismiss: string;
|
|
12
|
+
close: string;
|
|
13
|
+
clear: string;
|
|
14
|
+
open: string;
|
|
15
|
+
previousSlide: string;
|
|
16
|
+
nextSlide: string;
|
|
17
|
+
/** Given the 1-based slide number. */
|
|
18
|
+
goToSlide: (index: number) => string;
|
|
19
|
+
previousPage: string;
|
|
20
|
+
nextPage: string;
|
|
21
|
+
page: (index: number) => string;
|
|
22
|
+
/** Given the range shown and the total, e.g. "1–20 of 137". */
|
|
23
|
+
pageSummary: (from: number, to: number, total: number) => string;
|
|
24
|
+
chooseDate: string;
|
|
25
|
+
chooseTime: string;
|
|
26
|
+
previousMonth: string;
|
|
27
|
+
nextMonth: string;
|
|
28
|
+
chooseFiles: string;
|
|
29
|
+
chooseFile: string;
|
|
30
|
+
dropFilesHere: string;
|
|
31
|
+
dropFileHere: string;
|
|
32
|
+
removeFile: (name: string) => string;
|
|
33
|
+
increase: string;
|
|
34
|
+
decrease: string;
|
|
35
|
+
expandNavigation: string;
|
|
36
|
+
collapseNavigation: string;
|
|
37
|
+
/** Tour buttons. A Tour's own `labels` prop still wins over these. */
|
|
38
|
+
back: string;
|
|
39
|
+
next: string;
|
|
40
|
+
done: string;
|
|
41
|
+
skip: string;
|
|
42
|
+
/** Coachmark and Checklist progress, e.g. "2 of 5". */
|
|
43
|
+
progress: (current: number, total: number) => string;
|
|
44
|
+
}
|
|
45
|
+
declare const DEFAULT_LABELS: Labels;
|
|
46
|
+
interface LabelsProviderProps {
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
/** Only the strings you are replacing; the rest fall back to English. */
|
|
49
|
+
labels: Partial<Labels>;
|
|
50
|
+
}
|
|
51
|
+
declare function LabelsProvider({ children, labels }: LabelsProviderProps): react.JSX.Element;
|
|
52
|
+
declare function useLabels(): Labels;
|
|
53
|
+
|
|
54
|
+
type SpringPreset = 'snappy' | 'soft' | 'bouncy';
|
|
55
|
+
type DurationToken = 'instant' | 'fast' | 'base' | 'slow' | 'deliberate';
|
|
56
|
+
interface MotionSettings {
|
|
57
|
+
/** False when the app disabled motion or the user asked for reduced motion. */
|
|
58
|
+
enabled: boolean;
|
|
59
|
+
/** Multiplier on every duration. 0 is equivalent to disabled. */
|
|
60
|
+
scale: number;
|
|
61
|
+
}
|
|
62
|
+
interface MotionProviderProps {
|
|
63
|
+
children: ReactNode;
|
|
64
|
+
/** App-level off switch — for a settings toggle, or for tests. */
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
scale?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The one place animation is scaled or switched off, and the seam that honours
|
|
70
|
+
* `prefers-reduced-motion` (ADR 0004). Reduced motion means transforms drop and opacity
|
|
71
|
+
* stays; it never means a state change happens invisibly.
|
|
72
|
+
*/
|
|
73
|
+
declare function MotionProvider({ children, enabled, scale }: MotionProviderProps): react.JSX.Element;
|
|
74
|
+
interface MotionHelpers extends MotionSettings {
|
|
75
|
+
/** Seconds for a duration token, already scaled. 0 when motion is off. */
|
|
76
|
+
duration: (token: DurationToken) => number;
|
|
77
|
+
/** A Motion transition for a spring preset, collapsing to an instant one when off. */
|
|
78
|
+
spring: (preset?: SpringPreset) => Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
declare function useMotionSettings(): MotionHelpers;
|
|
81
|
+
|
|
82
|
+
type ThemeChoice = 'light' | 'dark' | 'system';
|
|
83
|
+
interface ThemeState {
|
|
84
|
+
choice: ThemeChoice;
|
|
85
|
+
setChoice: (choice: ThemeChoice) => void;
|
|
86
|
+
/** What is actually rendering right now, once `system` is resolved. */
|
|
87
|
+
resolved: 'light' | 'dark';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Colour itself comes from CSS, not from here (ADR 0002) — this only flips `data-theme`
|
|
91
|
+
* on the document root, so the first paint is already correct without a blocking script
|
|
92
|
+
* for anyone who never overrides the system setting.
|
|
93
|
+
*/
|
|
94
|
+
declare function ThemeProvider({ children, defaultChoice, persist, }: {
|
|
95
|
+
children: ReactNode;
|
|
96
|
+
defaultChoice?: ThemeChoice;
|
|
97
|
+
persist?: boolean;
|
|
98
|
+
}): react.JSX.Element;
|
|
99
|
+
declare function useTheme(): ThemeState;
|
|
100
|
+
|
|
101
|
+
type Tone = 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'danger';
|
|
102
|
+
type Size = 'sm' | 'md' | 'lg';
|
|
103
|
+
|
|
104
|
+
/** Motion redefines the drag and animation event handlers, so the DOM versions are dropped
|
|
105
|
+
* rather than silently conflicting. A button that needs HTML5 drag is not this component. */
|
|
106
|
+
type NativeButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color' | 'onDrag' | 'onDragStart' | 'onDragEnd' | 'onAnimationStart' | 'onAnimationEnd' | 'onAnimationIteration'>;
|
|
107
|
+
interface ButtonProps extends NativeButtonProps {
|
|
108
|
+
variant?: 'solid' | 'soft' | 'outline' | 'ghost';
|
|
109
|
+
tone?: Tone;
|
|
110
|
+
size?: Size;
|
|
111
|
+
/** Shown instead of the label, with the button held at its current width. */
|
|
112
|
+
loading?: boolean;
|
|
113
|
+
iconStart?: ReactNode;
|
|
114
|
+
iconEnd?: ReactNode;
|
|
115
|
+
/** Opts this button out of press feedback without touching the provider. */
|
|
116
|
+
motion?: boolean;
|
|
117
|
+
}
|
|
118
|
+
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
119
|
+
|
|
120
|
+
interface FieldWiring {
|
|
121
|
+
controlId: string;
|
|
122
|
+
describedBy: string | undefined;
|
|
123
|
+
invalid: boolean;
|
|
124
|
+
required: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** Inputs read their id and aria wiring from here; standalone use returns null. */
|
|
127
|
+
declare function useFieldWiring(): FieldWiring | null;
|
|
128
|
+
interface FieldProps {
|
|
129
|
+
label: ReactNode;
|
|
130
|
+
hint?: ReactNode;
|
|
131
|
+
/** A string renders the message; `true` marks invalid without one. */
|
|
132
|
+
error?: ReactNode | boolean;
|
|
133
|
+
required?: boolean;
|
|
134
|
+
/** Hides the label visually while keeping it for screen readers. */
|
|
135
|
+
labelHidden?: boolean;
|
|
136
|
+
className?: string;
|
|
137
|
+
children: ReactNode;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Label, hint, error, and the `aria-describedby` / `aria-invalid` links between them —
|
|
141
|
+
* the part that is most often silently wrong. The library owns this and refuses to own
|
|
142
|
+
* form state or validation (ADR 0011).
|
|
143
|
+
*/
|
|
144
|
+
declare function Field({ label, hint, error, required, labelHidden, className, children }: FieldProps): react.JSX.Element;
|
|
145
|
+
|
|
146
|
+
interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
147
|
+
size?: Size;
|
|
148
|
+
/** Marks invalid when used outside a Field; inside one, the Field decides. */
|
|
149
|
+
invalid?: boolean;
|
|
150
|
+
}
|
|
151
|
+
declare const TextInput: react.ForwardRefExoticComponent<TextInputProps & react.RefAttributes<HTMLInputElement>>;
|
|
152
|
+
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
153
|
+
invalid?: boolean;
|
|
154
|
+
}
|
|
155
|
+
declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
|
|
156
|
+
|
|
157
|
+
interface SelectOption<T extends string = string> {
|
|
158
|
+
value: T;
|
|
159
|
+
label: ReactNode;
|
|
160
|
+
disabled?: boolean;
|
|
161
|
+
}
|
|
162
|
+
interface SelectProps<T extends string = string> {
|
|
163
|
+
items: Array<SelectOption<T>>;
|
|
164
|
+
value?: T | null;
|
|
165
|
+
defaultValue?: T | null;
|
|
166
|
+
onValueChange?: (value: T) => void;
|
|
167
|
+
placeholder?: string;
|
|
168
|
+
size?: Size;
|
|
169
|
+
disabled?: boolean;
|
|
170
|
+
invalid?: boolean;
|
|
171
|
+
name?: string;
|
|
172
|
+
id?: string;
|
|
173
|
+
className?: string;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Listbox behaviour — typeahead, roving focus, scroll containment, form association —
|
|
177
|
+
* is Base UI's (ADR 0003). This adds the brand and the Field wiring.
|
|
178
|
+
*/
|
|
179
|
+
declare function Select<T extends string = string>({ items, value, defaultValue, onValueChange, placeholder, size, disabled, invalid, name, id, className, }: SelectProps<T>): react.JSX.Element;
|
|
180
|
+
|
|
181
|
+
interface CheckboxProps {
|
|
182
|
+
label: ReactNode;
|
|
183
|
+
checked?: boolean;
|
|
184
|
+
defaultChecked?: boolean;
|
|
185
|
+
indeterminate?: boolean;
|
|
186
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
187
|
+
disabled?: boolean;
|
|
188
|
+
name?: string;
|
|
189
|
+
value?: string;
|
|
190
|
+
/** Secondary line under the label — the place for "why would I tick this". */
|
|
191
|
+
description?: ReactNode;
|
|
192
|
+
className?: string;
|
|
193
|
+
}
|
|
194
|
+
/** The control and its label are one component: a checkbox whose label is not wired is a bug. */
|
|
195
|
+
declare function Checkbox({ label, checked, defaultChecked, indeterminate, onCheckedChange, disabled, name, value, description, className, }: CheckboxProps): react.JSX.Element;
|
|
196
|
+
interface RadioOption<T extends string = string> {
|
|
197
|
+
value: T;
|
|
198
|
+
label: ReactNode;
|
|
199
|
+
description?: ReactNode;
|
|
200
|
+
disabled?: boolean;
|
|
201
|
+
}
|
|
202
|
+
interface RadioGroupProps<T extends string = string> {
|
|
203
|
+
options: Array<RadioOption<T>>;
|
|
204
|
+
value?: T;
|
|
205
|
+
defaultValue?: T;
|
|
206
|
+
onValueChange?: (value: T) => void;
|
|
207
|
+
name?: string;
|
|
208
|
+
/** Names the group for assistive technology when it is not inside a Field. */
|
|
209
|
+
label?: string;
|
|
210
|
+
direction?: 'column' | 'row';
|
|
211
|
+
disabled?: boolean;
|
|
212
|
+
className?: string;
|
|
213
|
+
}
|
|
214
|
+
declare function RadioGroup<T extends string = string>({ options, value, defaultValue, onValueChange, name, label, direction, disabled, className, }: RadioGroupProps<T>): react.JSX.Element;
|
|
215
|
+
interface SwitchProps {
|
|
216
|
+
label: ReactNode;
|
|
217
|
+
checked?: boolean;
|
|
218
|
+
defaultChecked?: boolean;
|
|
219
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
220
|
+
disabled?: boolean;
|
|
221
|
+
name?: string;
|
|
222
|
+
description?: ReactNode;
|
|
223
|
+
/** Label on the left, control on the right — the settings-row arrangement. */
|
|
224
|
+
justified?: boolean;
|
|
225
|
+
className?: string;
|
|
226
|
+
}
|
|
227
|
+
/** A Switch applies immediately. If a change needs saving, that is a Checkbox in a form. */
|
|
228
|
+
declare function Switch({ label, checked, defaultChecked, onCheckedChange, disabled, name, description, justified, className, }: SwitchProps): react.JSX.Element;
|
|
229
|
+
|
|
230
|
+
interface ComboboxOption {
|
|
231
|
+
value: string;
|
|
232
|
+
label: string;
|
|
233
|
+
description?: ReactNode;
|
|
234
|
+
}
|
|
235
|
+
interface ComboboxProps {
|
|
236
|
+
items: ComboboxOption[];
|
|
237
|
+
value?: string | null;
|
|
238
|
+
defaultValue?: string | null;
|
|
239
|
+
onValueChange?: (value: string | null) => void;
|
|
240
|
+
placeholder?: string;
|
|
241
|
+
/** Shown when the query matches nothing. */
|
|
242
|
+
emptyMessage?: ReactNode;
|
|
243
|
+
size?: Size;
|
|
244
|
+
disabled?: boolean;
|
|
245
|
+
invalid?: boolean;
|
|
246
|
+
name?: string;
|
|
247
|
+
className?: string;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* A Select you can type into. Reach for it past roughly a dozen options — below that, scanning a
|
|
251
|
+
* list is faster than typing, and Select is the simpler component.
|
|
252
|
+
*/
|
|
253
|
+
declare function Combobox({ items, value, defaultValue, onValueChange, placeholder, emptyMessage, size, disabled, invalid, name, className, }: ComboboxProps): react.JSX.Element;
|
|
254
|
+
|
|
255
|
+
interface DateInputProps {
|
|
256
|
+
value?: Date | null;
|
|
257
|
+
defaultValue?: Date | null;
|
|
258
|
+
onValueChange?: (value: Date | null) => void;
|
|
259
|
+
min?: Date;
|
|
260
|
+
max?: Date;
|
|
261
|
+
/** How the chosen date reads in the field. Defaults to the viewer's locale, medium length. */
|
|
262
|
+
format?: (date: Date) => string;
|
|
263
|
+
weekStartsOn?: 0 | 1;
|
|
264
|
+
size?: Size;
|
|
265
|
+
disabled?: boolean;
|
|
266
|
+
invalid?: boolean;
|
|
267
|
+
placeholder?: string;
|
|
268
|
+
className?: string;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Typing and picking, both. Typing is what fast people do and what a date of birth needs; the
|
|
272
|
+
* calendar is for "the second Tuesday" questions a text field cannot answer.
|
|
273
|
+
*/
|
|
274
|
+
declare function DateInput({ value, defaultValue, onValueChange, min, max, format, weekStartsOn, size, disabled, invalid, placeholder, className, }: DateInputProps): react.JSX.Element;
|
|
275
|
+
|
|
276
|
+
/** Date arithmetic for the picker. Pure, and dealing only in local calendar days. */
|
|
277
|
+
interface DayCell {
|
|
278
|
+
date: Date;
|
|
279
|
+
/** False for the leading and trailing days that belong to the neighbouring months. */
|
|
280
|
+
inMonth: boolean;
|
|
281
|
+
}
|
|
282
|
+
declare function isSameDay(a: Date | null, b: Date | null): boolean;
|
|
283
|
+
declare function startOfDay(date: Date): Date;
|
|
284
|
+
/**
|
|
285
|
+
* Six weeks of cells, always. A fixed grid height means the popover does not resize when a
|
|
286
|
+
* month happens to span five weeks instead of six.
|
|
287
|
+
*/
|
|
288
|
+
declare function monthMatrix(year: number, month: number, weekStartsOn?: 0 | 1): DayCell[][];
|
|
289
|
+
/**
|
|
290
|
+
* Reads what a person typed. ISO first, then day-first with `/`, `-`, or `.` — day-first because
|
|
291
|
+
* that is what most of the world writes, and an ambiguous `03/04` has to pick a side.
|
|
292
|
+
*/
|
|
293
|
+
declare function parseDateInput(input: string): Date | null;
|
|
294
|
+
declare function formatISO(date: Date | null): string;
|
|
295
|
+
declare function isOutOfRange(date: Date, min?: Date, max?: Date): boolean;
|
|
296
|
+
|
|
297
|
+
/** Time-of-day parsing and formatting. Pure, like the date maths next to it. */
|
|
298
|
+
interface TimeValue {
|
|
299
|
+
hours: number;
|
|
300
|
+
minutes: number;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Reads what a person typed: `9`, `9:30`, `0930`, `9.30`, `9 pm`, `21:05`. Returns null rather
|
|
304
|
+
* than guessing when the result would not be a real time.
|
|
305
|
+
*/
|
|
306
|
+
declare function parseTime(input: string): TimeValue | null;
|
|
307
|
+
declare function formatTime({ hours, minutes }: TimeValue): string;
|
|
308
|
+
declare function timeToMinutes({ hours, minutes }: TimeValue): number;
|
|
309
|
+
/** Every selectable time between two bounds, at `step` minutes. Bounds are inclusive. */
|
|
310
|
+
declare function timeOptions(step: number, min?: TimeValue, max?: TimeValue): TimeValue[];
|
|
311
|
+
declare function isTimeOutOfRange(value: TimeValue, min?: TimeValue, max?: TimeValue): boolean;
|
|
312
|
+
|
|
313
|
+
interface TimeInputProps {
|
|
314
|
+
value?: TimeValue | null;
|
|
315
|
+
defaultValue?: TimeValue | null;
|
|
316
|
+
onValueChange?: (value: TimeValue | null) => void;
|
|
317
|
+
min?: TimeValue;
|
|
318
|
+
max?: TimeValue;
|
|
319
|
+
/** Minutes between the offered times. Typing is never restricted to them. */
|
|
320
|
+
step?: number;
|
|
321
|
+
size?: Size;
|
|
322
|
+
disabled?: boolean;
|
|
323
|
+
invalid?: boolean;
|
|
324
|
+
placeholder?: string;
|
|
325
|
+
className?: string;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* The DateInput's sibling. Typing accepts what people actually type — `9`, `0930`, `9:30`,
|
|
329
|
+
* `9pm` — and the list is a convenience on top, never the only way to answer.
|
|
330
|
+
*/
|
|
331
|
+
declare function TimeInput({ value, defaultValue, onValueChange, min, max, step, size, disabled, invalid, placeholder, className, }: TimeInputProps): react.JSX.Element;
|
|
332
|
+
|
|
333
|
+
/** File acceptance rules, kept pure: what gets rejected and why is worth asserting. */
|
|
334
|
+
interface FileRules {
|
|
335
|
+
/** Extensions or MIME types, e.g. ['.pdf', 'image/*']. */
|
|
336
|
+
accept?: string[];
|
|
337
|
+
/** Bytes. */
|
|
338
|
+
maxSize?: number;
|
|
339
|
+
maxFiles?: number;
|
|
340
|
+
multiple?: boolean;
|
|
341
|
+
}
|
|
342
|
+
interface Rejection {
|
|
343
|
+
file: File;
|
|
344
|
+
reason: string;
|
|
345
|
+
}
|
|
346
|
+
declare function matchesAccept(file: File, accept: string[] | undefined): boolean;
|
|
347
|
+
/**
|
|
348
|
+
* Splits an incoming batch against the rules and what is already held. Every rejection carries
|
|
349
|
+
* a reason, because a file that disappears without explanation reads as a broken uploader.
|
|
350
|
+
*/
|
|
351
|
+
declare function partitionFiles(incoming: File[], existing: File[], rules: FileRules): {
|
|
352
|
+
accepted: File[];
|
|
353
|
+
rejected: Rejection[];
|
|
354
|
+
};
|
|
355
|
+
/** The " — PDF up to 5 MB" tail under the drop zone. Empty when there is nothing to say. */
|
|
356
|
+
declare function describeAccept(rules: FileRules): string;
|
|
357
|
+
|
|
358
|
+
interface FileDropProps extends FileRules {
|
|
359
|
+
onFilesChange: (files: File[]) => void;
|
|
360
|
+
files?: File[];
|
|
361
|
+
/** Rejections are surfaced rather than swallowed — a file that vanishes silently reads as a bug. */
|
|
362
|
+
onReject?: (rejections: Array<{
|
|
363
|
+
file: File;
|
|
364
|
+
reason: string;
|
|
365
|
+
}>) => void;
|
|
366
|
+
disabled?: boolean;
|
|
367
|
+
children?: ReactNode;
|
|
368
|
+
className?: string;
|
|
369
|
+
}
|
|
370
|
+
declare function FileDrop({ onFilesChange, files, onReject, accept, maxSize, maxFiles, multiple, disabled, children, className, }: FileDropProps): react.JSX.Element;
|
|
371
|
+
|
|
372
|
+
/** Numeric input arithmetic, kept pure so the awkward cases are asserted, not hoped for. */
|
|
373
|
+
interface NumberBounds {
|
|
374
|
+
min?: number;
|
|
375
|
+
max?: number;
|
|
376
|
+
step?: number;
|
|
377
|
+
}
|
|
378
|
+
/** Parses what a person typed. Accepts a comma decimal separator; returns null for nonsense. */
|
|
379
|
+
declare function parseNumber(input: string): number | null;
|
|
380
|
+
declare function clamp(value: number, { min, max }: NumberBounds): number;
|
|
381
|
+
/**
|
|
382
|
+
* Steps by `step` and clamps. Floating point is rounded back to the step's own precision,
|
|
383
|
+
* because 0.1 + 0.2 must read as 0.3 in an input a person is looking at.
|
|
384
|
+
*/
|
|
385
|
+
declare function stepBy(value: number | null, direction: 1 | -1, bounds: NumberBounds): number;
|
|
386
|
+
declare function decimalPlaces(step: number): number;
|
|
387
|
+
/** Whether stepping in this direction would do anything — drives the disabled state. */
|
|
388
|
+
declare function canStep(value: number | null, direction: 1 | -1, bounds: NumberBounds): boolean;
|
|
389
|
+
|
|
390
|
+
interface NumberInputProps extends NumberBounds {
|
|
391
|
+
value?: number | null;
|
|
392
|
+
defaultValue?: number | null;
|
|
393
|
+
onValueChange?: (value: number | null) => void;
|
|
394
|
+
size?: Size;
|
|
395
|
+
disabled?: boolean;
|
|
396
|
+
invalid?: boolean;
|
|
397
|
+
name?: string;
|
|
398
|
+
placeholder?: string;
|
|
399
|
+
/** Shown inside the control, e.g. 'kg', 'IDR'. Decorative — keep the unit in the label too. */
|
|
400
|
+
suffix?: string;
|
|
401
|
+
className?: string;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* A text input that speaks numbers, not `<input type="number">`: that one scrolls its value
|
|
405
|
+
* away under the wheel, accepts 'e' and '+', and formats inconsistently across locales.
|
|
406
|
+
*/
|
|
407
|
+
declare function NumberInput({ value, defaultValue, onValueChange, min, max, step, size, disabled, invalid, name, placeholder, suffix, className, }: NumberInputProps): react.JSX.Element;
|
|
408
|
+
|
|
409
|
+
interface DialogProps {
|
|
410
|
+
open?: boolean;
|
|
411
|
+
defaultOpen?: boolean;
|
|
412
|
+
onOpenChange?: (open: boolean) => void;
|
|
413
|
+
title: ReactNode;
|
|
414
|
+
description?: ReactNode;
|
|
415
|
+
children?: ReactNode;
|
|
416
|
+
footer?: ReactNode;
|
|
417
|
+
size?: 'sm' | 'md' | 'lg';
|
|
418
|
+
/** Slides from the edge instead of scaling in the centre. */
|
|
419
|
+
placement?: 'center' | 'end';
|
|
420
|
+
/** The element that opens it. Omit for a fully controlled dialog. */
|
|
421
|
+
trigger?: ReactNode;
|
|
422
|
+
className?: string;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Focus trapping, scroll locking, dismissal, and the `aria-labelledby` wiring are Base UI's
|
|
426
|
+
* (ADR 0003). Enter and exit are CSS transitions driven by Base UI's own state attributes,
|
|
427
|
+
* because Base UI owns this element's mount lifecycle — motion is used where we own it.
|
|
428
|
+
*/
|
|
429
|
+
declare function Dialog({ open, defaultOpen, onOpenChange, title, description, children, footer, size, placement, trigger, className, }: DialogProps): react.JSX.Element;
|
|
430
|
+
declare const DialogClose: react.ForwardRefExoticComponent<Omit<_base_ui_react.AlertDialogCloseProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
431
|
+
|
|
432
|
+
/** Command matching and ranking. Pure — search that ranks badly is a bug you can only see in a test. */
|
|
433
|
+
interface Command {
|
|
434
|
+
id: string;
|
|
435
|
+
label: string;
|
|
436
|
+
/** Extra words that should find this command, e.g. ['logout', 'exit'] for "Sign out". */
|
|
437
|
+
keywords?: string[];
|
|
438
|
+
group?: string;
|
|
439
|
+
shortcut?: string;
|
|
440
|
+
}
|
|
441
|
+
interface RankedCommand<T extends Command = Command> {
|
|
442
|
+
command: T;
|
|
443
|
+
score: number;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Ranks by how the query matched, not by string distance:
|
|
447
|
+
* an exact label wins, then a label prefix, then a word start, then anything containing it,
|
|
448
|
+
* then a keyword hit. Ties keep the order the caller supplied, so a curated list stays curated.
|
|
449
|
+
*/
|
|
450
|
+
declare function rankCommand(command: Command, query: string): number;
|
|
451
|
+
declare function filterCommands<T extends Command>(commands: T[], query: string): T[];
|
|
452
|
+
/** Groups in first-seen order, so a ranked list does not shuffle its own headings. */
|
|
453
|
+
declare function groupCommands<T extends Command>(commands: T[]): Array<{
|
|
454
|
+
group: string | undefined;
|
|
455
|
+
items: T[];
|
|
456
|
+
}>;
|
|
457
|
+
|
|
458
|
+
interface PaletteCommand extends Command {
|
|
459
|
+
icon?: ReactNode;
|
|
460
|
+
onRun: () => void;
|
|
461
|
+
}
|
|
462
|
+
interface CommandPaletteProps {
|
|
463
|
+
open: boolean;
|
|
464
|
+
onOpenChange: (open: boolean) => void;
|
|
465
|
+
commands: PaletteCommand[];
|
|
466
|
+
placeholder?: string;
|
|
467
|
+
emptyMessage?: ReactNode;
|
|
468
|
+
className?: string;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Search over actions. The list is the app's — the palette ranks, renders, and runs, and knows
|
|
472
|
+
* nothing about what a command does.
|
|
473
|
+
*/
|
|
474
|
+
declare function CommandPalette({ open, onOpenChange, commands, placeholder, emptyMessage, className, }: CommandPaletteProps): react.JSX.Element;
|
|
475
|
+
|
|
476
|
+
interface ChecklistTask {
|
|
477
|
+
id: string;
|
|
478
|
+
label: ReactNode;
|
|
479
|
+
description?: ReactNode;
|
|
480
|
+
done?: boolean;
|
|
481
|
+
onSelect?: () => void;
|
|
482
|
+
}
|
|
483
|
+
interface ChecklistProps {
|
|
484
|
+
title?: ReactNode;
|
|
485
|
+
tasks: ChecklistTask[];
|
|
486
|
+
/** Rendered once every task is done — the reason the checklist can go away. */
|
|
487
|
+
completeSlot?: ReactNode;
|
|
488
|
+
className?: string;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Getting-started tasks with progress. Which tasks are done is the app's knowledge, passed in —
|
|
492
|
+
* the library does not track anyone's account state, the same rule the Seen Store follows
|
|
493
|
+
* (ADR 0006).
|
|
494
|
+
*/
|
|
495
|
+
declare function Checklist({ title, tasks, completeSlot, className }: ChecklistProps): react.JSX.Element;
|
|
496
|
+
|
|
497
|
+
type Side = 'top' | 'right' | 'bottom' | 'left';
|
|
498
|
+
type Align = 'start' | 'center' | 'end';
|
|
499
|
+
interface PopoverProps {
|
|
500
|
+
trigger: ReactElement;
|
|
501
|
+
children: ReactNode;
|
|
502
|
+
side?: Side;
|
|
503
|
+
align?: Align;
|
|
504
|
+
/** Distance from the anchor, in px. Keep it at the token step unless the arrow needs room. */
|
|
505
|
+
sideOffset?: number;
|
|
506
|
+
showArrow?: boolean;
|
|
507
|
+
open?: boolean;
|
|
508
|
+
onOpenChange?: (open: boolean) => void;
|
|
509
|
+
className?: string;
|
|
510
|
+
}
|
|
511
|
+
/** Positioning, dismissal, and focus return come from Base UI; this adds the surface (ADR 0003). */
|
|
512
|
+
declare function Popover({ trigger, children, side, align, sideOffset, showArrow, open, onOpenChange, className, }: PopoverProps): react.JSX.Element;
|
|
513
|
+
interface TooltipProps {
|
|
514
|
+
children: ReactElement;
|
|
515
|
+
/** Plain text. A tooltip that needs markup is a Popover — screen readers read this as a label. */
|
|
516
|
+
label: string;
|
|
517
|
+
side?: Side;
|
|
518
|
+
delay?: number;
|
|
519
|
+
}
|
|
520
|
+
declare function Tooltip({ children, label, side, delay }: TooltipProps): react.JSX.Element;
|
|
521
|
+
|
|
522
|
+
interface AlertProps {
|
|
523
|
+
title?: ReactNode;
|
|
524
|
+
children?: ReactNode;
|
|
525
|
+
tone?: Tone;
|
|
526
|
+
/** Replaces the tone's default icon. Pass null to drop it. */
|
|
527
|
+
icon?: ReactNode | null;
|
|
528
|
+
actions?: ReactNode;
|
|
529
|
+
onDismiss?: () => void;
|
|
530
|
+
className?: string;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* `danger` and `warning` announce themselves through `role="alert"`; the quieter tones do not,
|
|
534
|
+
* because a success note that interrupts a screen reader mid-sentence is not helpful.
|
|
535
|
+
*/
|
|
536
|
+
declare function Alert({ title, children, tone, icon, actions, onDismiss, className }: AlertProps): react.JSX.Element;
|
|
537
|
+
|
|
538
|
+
type ToastPosition = 'bottom-end' | 'bottom-center' | 'bottom-start' | 'top-end' | 'top-center' | 'top-start';
|
|
539
|
+
interface ToastProviderProps {
|
|
540
|
+
children: ReactNode;
|
|
541
|
+
/** Milliseconds before a toast leaves on its own. Errors ignore it and stay. */
|
|
542
|
+
timeout?: number;
|
|
543
|
+
limit?: number;
|
|
544
|
+
/** Where the stack lives. Logical, so `end` follows the writing direction. */
|
|
545
|
+
position?: ToastPosition;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Wrap the app once. The viewport is rendered here rather than left to the caller, because a
|
|
549
|
+
* provider without a viewport fails silently: the toast is created and nothing appears.
|
|
550
|
+
*/
|
|
551
|
+
declare function ToastProvider({ children, timeout, limit, position, }: ToastProviderProps): react.JSX.Element;
|
|
552
|
+
interface ToastOptions {
|
|
553
|
+
title?: string;
|
|
554
|
+
description?: string;
|
|
555
|
+
tone?: Extract<Tone, 'info' | 'success' | 'warning' | 'danger'>;
|
|
556
|
+
timeout?: number;
|
|
557
|
+
action?: {
|
|
558
|
+
label: string;
|
|
559
|
+
onClick: () => void;
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
/** Called inside a ToastProvider. Returns the manager, with our vocabulary in front of it. */
|
|
563
|
+
declare function useToast(): {
|
|
564
|
+
show: ({ title, description, tone, timeout, action }: ToastOptions) => string;
|
|
565
|
+
close: (id?: string) => void;
|
|
566
|
+
promise: <Value, T extends any = any>(promise: Promise<Value>, options: _base_ui_react.ToastManagerPromiseOptions<Value, T>) => Promise<Value>;
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
interface TabItem {
|
|
570
|
+
value: string;
|
|
571
|
+
label: ReactNode;
|
|
572
|
+
/** Count or status shown after the label, e.g. a Badge. */
|
|
573
|
+
adornment?: ReactNode;
|
|
574
|
+
disabled?: boolean;
|
|
575
|
+
content: ReactNode;
|
|
576
|
+
}
|
|
577
|
+
interface TabsProps {
|
|
578
|
+
items: TabItem[];
|
|
579
|
+
value?: string;
|
|
580
|
+
defaultValue?: string;
|
|
581
|
+
onValueChange?: (value: string) => void;
|
|
582
|
+
variant?: 'underline' | 'pill';
|
|
583
|
+
className?: string;
|
|
584
|
+
}
|
|
585
|
+
/** Roving focus, panel association, and the moving indicator are Base UI's (ADR 0003). */
|
|
586
|
+
declare function Tabs({ items, value, defaultValue, onValueChange, variant, className }: TabsProps): react.JSX.Element;
|
|
587
|
+
|
|
588
|
+
interface MenuItem {
|
|
589
|
+
/** Omit everything but `separator` to draw a divider. */
|
|
590
|
+
separator?: boolean;
|
|
591
|
+
label?: ReactNode;
|
|
592
|
+
icon?: ReactNode;
|
|
593
|
+
shortcut?: string;
|
|
594
|
+
tone?: Extract<Tone, 'neutral' | 'danger'>;
|
|
595
|
+
disabled?: boolean;
|
|
596
|
+
checked?: boolean;
|
|
597
|
+
onSelect?: () => void;
|
|
598
|
+
}
|
|
599
|
+
interface DropdownMenuProps {
|
|
600
|
+
trigger: ReactElement;
|
|
601
|
+
items: MenuItem[];
|
|
602
|
+
align?: 'start' | 'center' | 'end';
|
|
603
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
604
|
+
className?: string;
|
|
605
|
+
}
|
|
606
|
+
/** Typeahead, roving focus, and dismissal are Base UI's; the surface and the rhythm are ours. */
|
|
607
|
+
declare function DropdownMenu({ trigger, items, align, side, className }: DropdownMenuProps): react.JSX.Element;
|
|
608
|
+
|
|
609
|
+
interface NavItem {
|
|
610
|
+
label: ReactNode;
|
|
611
|
+
icon?: ReactNode;
|
|
612
|
+
href?: string;
|
|
613
|
+
onClick?: () => void;
|
|
614
|
+
active?: boolean;
|
|
615
|
+
/** A count or status shown at the end of the row. */
|
|
616
|
+
adornment?: ReactNode;
|
|
617
|
+
/** One level of children. A parent with children is a disclosure, not a destination. */
|
|
618
|
+
items?: NavItem[];
|
|
619
|
+
}
|
|
620
|
+
interface NavSection {
|
|
621
|
+
title?: ReactNode;
|
|
622
|
+
items: NavItem[];
|
|
623
|
+
}
|
|
624
|
+
interface SidebarProps {
|
|
625
|
+
sections: NavSection[];
|
|
626
|
+
/** Brand block at the top — a Logo, usually. */
|
|
627
|
+
header?: ReactNode;
|
|
628
|
+
footer?: ReactNode;
|
|
629
|
+
collapsed?: boolean;
|
|
630
|
+
onCollapsedChange?: (collapsed: boolean) => void;
|
|
631
|
+
className?: string;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* The shell's navigation. Collapsed, it keeps the icons and hides the labels — the labels stay in
|
|
635
|
+
* the accessible name, and hovering or focusing a rail item opens a flyout carrying that label and
|
|
636
|
+
* any children, so a collapsed rail stays readable instead of becoming a column of guesses.
|
|
637
|
+
*/
|
|
638
|
+
declare function Sidebar({ sections, header, footer, collapsed, onCollapsedChange, className }: SidebarProps): react.JSX.Element;
|
|
639
|
+
interface TopBarProps {
|
|
640
|
+
/** Page title, or a Breadcrumbs trail. */
|
|
641
|
+
title?: ReactNode;
|
|
642
|
+
subtitle?: ReactNode;
|
|
643
|
+
/** Search, filters — anything that belongs in the middle. */
|
|
644
|
+
center?: ReactNode;
|
|
645
|
+
actions?: ReactNode;
|
|
646
|
+
sticky?: boolean;
|
|
647
|
+
className?: string;
|
|
648
|
+
}
|
|
649
|
+
declare function TopBar({ title, subtitle, center, actions, sticky, className }: TopBarProps): react.JSX.Element;
|
|
650
|
+
|
|
651
|
+
/** Sorting and pagination arithmetic, kept pure so the off-by-ones are asserted (ADR 0012). */
|
|
652
|
+
type SortDirection = 'asc' | 'desc';
|
|
653
|
+
interface SortState {
|
|
654
|
+
column: string;
|
|
655
|
+
direction: SortDirection;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* What clicking a header does. Sorting a new column starts ascending; clicking the sorted
|
|
659
|
+
* column flips it; clicking a descending column clears the sort — three states, because
|
|
660
|
+
* "back to the order the server gave me" is a state people look for.
|
|
661
|
+
*/
|
|
662
|
+
declare function nextSort(current: SortState | null, column: string): SortState | null;
|
|
663
|
+
declare function ariaSortFor(current: SortState | null, column: string): 'ascending' | 'descending' | 'none';
|
|
664
|
+
interface PageRange {
|
|
665
|
+
/** Page numbers to render; `null` is an ellipsis. */
|
|
666
|
+
items: Array<number | null>;
|
|
667
|
+
totalPages: number;
|
|
668
|
+
/** 1-based index of the first and last row on this page, for "1–20 of 137". */
|
|
669
|
+
from: number;
|
|
670
|
+
to: number;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* The page list, with ellipses. `siblings` is how many pages flank the current one; first and
|
|
674
|
+
* last are always shown, because jumping to the end is the second most common thing people do.
|
|
675
|
+
*/
|
|
676
|
+
declare function pageRange(page: number, pageSize: number, total: number, siblings?: number): PageRange;
|
|
677
|
+
|
|
678
|
+
interface Column<Row> {
|
|
679
|
+
key: string;
|
|
680
|
+
header: ReactNode;
|
|
681
|
+
/** Cell content. Given the row, so a column can render a Badge or an Avatar. */
|
|
682
|
+
cell: (row: Row) => ReactNode;
|
|
683
|
+
align?: 'start' | 'end';
|
|
684
|
+
width?: string;
|
|
685
|
+
sortable?: boolean;
|
|
686
|
+
/** Hides the column below 720px — for the ones a phone can live without. */
|
|
687
|
+
secondary?: boolean;
|
|
688
|
+
/** Clips overflowing text with an ellipsis instead of widening the column. */
|
|
689
|
+
truncate?: boolean;
|
|
690
|
+
}
|
|
691
|
+
interface DataTableProps<Row> {
|
|
692
|
+
columns: Array<Column<Row>>;
|
|
693
|
+
rows: Row[];
|
|
694
|
+
rowKey: (row: Row) => string;
|
|
695
|
+
/** Accessible name for the table. */
|
|
696
|
+
label: string;
|
|
697
|
+
sort?: SortState | null;
|
|
698
|
+
onSortChange?: (sort: SortState | null) => void;
|
|
699
|
+
onRowClick?: (row: Row) => void;
|
|
700
|
+
/** Rendered in place of the body when there are no rows — an EmptyState, usually. */
|
|
701
|
+
empty?: ReactNode;
|
|
702
|
+
className?: string;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* A table, not a grid: no virtualisation, no column resizing, no editing. It renders rows and
|
|
706
|
+
* sorts by a column, and anything past that is a product feature rather than a design system one.
|
|
707
|
+
*/
|
|
708
|
+
declare function DataTable<Row>({ columns, rows, rowKey, label, sort, onSortChange, onRowClick, empty, className, }: DataTableProps<Row>): react.JSX.Element;
|
|
709
|
+
declare namespace DataTable {
|
|
710
|
+
var Skeleton: typeof DataTableSkeleton;
|
|
711
|
+
}
|
|
712
|
+
interface DataTableSkeletonProps {
|
|
713
|
+
columns: number;
|
|
714
|
+
rows?: number;
|
|
715
|
+
className?: string;
|
|
716
|
+
}
|
|
717
|
+
/** Same row height and column count as the real table, so the page does not jump (ADR 0009). */
|
|
718
|
+
declare function DataTableSkeleton({ columns, rows, className }: DataTableSkeletonProps): react.JSX.Element;
|
|
719
|
+
|
|
720
|
+
interface PaginationProps {
|
|
721
|
+
page: number;
|
|
722
|
+
pageSize: number;
|
|
723
|
+
total: number;
|
|
724
|
+
onPageChange: (page: number) => void;
|
|
725
|
+
/** Shows "1–20 of 137" beside the controls. */
|
|
726
|
+
showSummary?: boolean;
|
|
727
|
+
siblings?: number;
|
|
728
|
+
className?: string;
|
|
729
|
+
}
|
|
730
|
+
declare function Pagination({ page, pageSize, total, onPageChange, showSummary, siblings, className, }: PaginationProps): react.JSX.Element;
|
|
731
|
+
|
|
732
|
+
interface ImageProps {
|
|
733
|
+
src: string;
|
|
734
|
+
/** Empty string is allowed, and means "decorative" — but it has to be said out loud. */
|
|
735
|
+
alt: string;
|
|
736
|
+
/** Width / height, e.g. 16 / 9. Reserves the space so nothing below it jumps. */
|
|
737
|
+
aspectRatio?: number;
|
|
738
|
+
/** A tiny data URI, blurred up while the real image loads. */
|
|
739
|
+
blurDataUrl?: string;
|
|
740
|
+
/** Flat colour to sit behind the image when there is no blur placeholder. */
|
|
741
|
+
background?: string;
|
|
742
|
+
fit?: 'cover' | 'contain';
|
|
743
|
+
radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
|
744
|
+
loading?: 'lazy' | 'eager';
|
|
745
|
+
className?: string;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* An `<img>` that reserves its space and fades in. It is not a Next.js Image and does not want to
|
|
749
|
+
* be: no resizing service, no loader — those belong to the framework the app already chose.
|
|
750
|
+
*/
|
|
751
|
+
declare function Image({ src, alt, aspectRatio, blurDataUrl, background, fit, radius, loading, className, }: ImageProps): react.JSX.Element;
|
|
752
|
+
|
|
753
|
+
interface CarouselProps {
|
|
754
|
+
children: ReactNode;
|
|
755
|
+
/** Accessible name — a carousel with no name is an unlabelled region to a screen reader. */
|
|
756
|
+
label: string;
|
|
757
|
+
/** Slide width as a CSS length or fraction of the viewport, e.g. '18rem' or '50%'. */
|
|
758
|
+
slideWidth?: string;
|
|
759
|
+
gap?: 2 | 3 | 4 | 5;
|
|
760
|
+
loop?: boolean;
|
|
761
|
+
align?: 'start' | 'center';
|
|
762
|
+
/** Milliseconds between advances. Omit for a carousel that only moves when asked. */
|
|
763
|
+
autoplay?: number;
|
|
764
|
+
showArrows?: boolean;
|
|
765
|
+
showDots?: boolean;
|
|
766
|
+
className?: string;
|
|
767
|
+
}
|
|
768
|
+
declare function CarouselRoot({ children, label, slideWidth, gap, loop, align, autoplay, showArrows, showDots, className, }: CarouselProps): react.JSX.Element;
|
|
769
|
+
interface CarouselSlideProps {
|
|
770
|
+
children: ReactNode;
|
|
771
|
+
className?: string;
|
|
772
|
+
}
|
|
773
|
+
declare function CarouselSlide({ children, className }: CarouselSlideProps): react.JSX.Element;
|
|
774
|
+
interface CarouselSkeletonProps {
|
|
775
|
+
slides?: number;
|
|
776
|
+
slideWidth?: string;
|
|
777
|
+
slideHeight?: string;
|
|
778
|
+
gap?: 2 | 3 | 4 | 5;
|
|
779
|
+
}
|
|
780
|
+
/** Same track geometry as the real carousel, so slides do not resize on load (ADR 0009). */
|
|
781
|
+
declare function CarouselSkeleton({ slides, slideWidth, slideHeight, gap, }: CarouselSkeletonProps): react.JSX.Element;
|
|
782
|
+
declare const Carousel: typeof CarouselRoot & {
|
|
783
|
+
Slide: typeof CarouselSlide;
|
|
784
|
+
Skeleton: typeof CarouselSkeleton;
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
/** Inputs that decide whether a carousel may advance on its own. */
|
|
788
|
+
interface AutoplayConditions {
|
|
789
|
+
/** The caller asked for autoplay at all. */
|
|
790
|
+
requested: boolean;
|
|
791
|
+
pointerInside: boolean;
|
|
792
|
+
/** Focus is somewhere inside the carousel — keyboard users must not lose their place. */
|
|
793
|
+
focusInside: boolean;
|
|
794
|
+
documentHidden: boolean;
|
|
795
|
+
reducedMotion: boolean;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Autoplay stops for four separate reasons, and every one of them is a bug when missed:
|
|
799
|
+
* a hovered carousel that keeps moving, a focused one that steals the slide out from under
|
|
800
|
+
* a keyboard user, a background tab burning frames, and motion nobody asked for.
|
|
801
|
+
*/
|
|
802
|
+
declare function shouldAutoplay(conditions: AutoplayConditions): boolean;
|
|
803
|
+
|
|
804
|
+
interface CoachmarkProps {
|
|
805
|
+
open: boolean;
|
|
806
|
+
/** The element being pointed at. Already resolved — a Tour does the resolving. */
|
|
807
|
+
anchor: Element | null;
|
|
808
|
+
title: ReactNode;
|
|
809
|
+
children?: ReactNode;
|
|
810
|
+
side?: Side;
|
|
811
|
+
align?: Align;
|
|
812
|
+
/** Dims the page and cuts a hole around the anchor. A number sets the hole's padding in px. */
|
|
813
|
+
spotlight?: boolean | number;
|
|
814
|
+
/** e.g. `{ current: 2, total: 5 }` — rendered as "2 of 5" and announced. */
|
|
815
|
+
progress?: {
|
|
816
|
+
current: number;
|
|
817
|
+
total: number;
|
|
818
|
+
};
|
|
819
|
+
actions?: ReactNode;
|
|
820
|
+
onDismiss?: () => void;
|
|
821
|
+
className?: string;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* One anchored bubble pointing at one element. It knows nothing about sequence and nothing
|
|
825
|
+
* about who has seen it — those are Tour and the Seen Store (ADR 0006).
|
|
826
|
+
*/
|
|
827
|
+
declare function Coachmark({ open, anchor, title, children, side, align, spotlight, progress, actions, onDismiss, className, }: CoachmarkProps): react.JSX.Element;
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* How a Tour asks whether someone has already been through it.
|
|
831
|
+
*
|
|
832
|
+
* The library ships this interface and no implementation on purpose (ADR 0006): a library that
|
|
833
|
+
* reaches for localStorage has decided what a user is and where their state lives, and that is
|
|
834
|
+
* the assumption that makes an onboarding library impossible to remove later.
|
|
835
|
+
*
|
|
836
|
+
* A localStorage adapter is four lines; a server-backed one is a fetch. Both are yours.
|
|
837
|
+
*/
|
|
838
|
+
interface SeenStore {
|
|
839
|
+
/** Whether this tour has been completed or skipped before. May be async. */
|
|
840
|
+
has: (tourId: string) => boolean | Promise<boolean>;
|
|
841
|
+
/** Records that it has now. Called once, when the tour finishes or is skipped. */
|
|
842
|
+
mark: (tourId: string) => void | Promise<void>;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** Tour sequencing, kept pure so every edge is assertable (ADR 0012). */
|
|
846
|
+
type TourStatus = 'idle' | 'running' | 'finished' | 'skipped';
|
|
847
|
+
interface TourState {
|
|
848
|
+
index: number;
|
|
849
|
+
status: TourStatus;
|
|
850
|
+
}
|
|
851
|
+
type TourAction = {
|
|
852
|
+
type: 'start';
|
|
853
|
+
} | {
|
|
854
|
+
type: 'next';
|
|
855
|
+
} | {
|
|
856
|
+
type: 'prev';
|
|
857
|
+
} | {
|
|
858
|
+
type: 'goto';
|
|
859
|
+
index: number;
|
|
860
|
+
} | {
|
|
861
|
+
type: 'skip';
|
|
862
|
+
} | {
|
|
863
|
+
type: 'finish';
|
|
864
|
+
};
|
|
865
|
+
declare const initialTourState: TourState;
|
|
866
|
+
/**
|
|
867
|
+
* `stepCount` is passed in rather than held in state because steps are props: a tour whose
|
|
868
|
+
* steps change while it runs must not point past the end of the new list.
|
|
869
|
+
*/
|
|
870
|
+
declare function tourReducer(state: TourState, action: TourAction, stepCount: number): TourState;
|
|
871
|
+
/** A tour that ended, either way. Both outcomes mark the Seen Store. */
|
|
872
|
+
declare function hasEnded(status: TourStatus): boolean;
|
|
873
|
+
type StepTarget = string | Element | {
|
|
874
|
+
current: Element | null;
|
|
875
|
+
} | (() => Element | null) | null;
|
|
876
|
+
/**
|
|
877
|
+
* Resolves a step's target. Returns null rather than throwing when the element is not mounted
|
|
878
|
+
* yet — the Tour retries, because a target that appears one frame late is normal, not an error.
|
|
879
|
+
*/
|
|
880
|
+
declare function resolveTarget(target: StepTarget, root: ParentNode): Element | null;
|
|
881
|
+
|
|
882
|
+
interface TourStep {
|
|
883
|
+
target: StepTarget;
|
|
884
|
+
title: ReactNode;
|
|
885
|
+
content?: ReactNode;
|
|
886
|
+
side?: Side;
|
|
887
|
+
align?: Align;
|
|
888
|
+
spotlight?: boolean | number;
|
|
889
|
+
}
|
|
890
|
+
interface TourProps {
|
|
891
|
+
/** Stable id — this is what the Seen Store remembers. */
|
|
892
|
+
id: string;
|
|
893
|
+
steps: TourStep[];
|
|
894
|
+
/** Starts the tour when it turns true. */
|
|
895
|
+
open?: boolean;
|
|
896
|
+
onOpenChange?: (open: boolean) => void;
|
|
897
|
+
/** Injected by the app; without one the tour runs every time it is opened (ADR 0006). */
|
|
898
|
+
seenStore?: SeenStore;
|
|
899
|
+
onFinish?: () => void;
|
|
900
|
+
onSkip?: () => void;
|
|
901
|
+
labels?: Partial<Record<'back' | 'next' | 'done' | 'skip', string>>;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Sequences Coachmarks. It owns order and nothing else: memory is the Seen Store's, the bubble
|
|
905
|
+
* is the Coachmark's, and the steps belong to the caller.
|
|
906
|
+
*/
|
|
907
|
+
declare function Tour({ id, steps, open, onOpenChange, seenStore, onFinish, onSkip, labels }: TourProps): react.JSX.Element | null;
|
|
908
|
+
|
|
909
|
+
interface RevealProps {
|
|
910
|
+
children: ReactNode;
|
|
911
|
+
/** Direction the content travels from. Under reduced motion it only fades. */
|
|
912
|
+
from?: 'below' | 'above' | 'left' | 'right' | 'none';
|
|
913
|
+
distance?: number;
|
|
914
|
+
delay?: number;
|
|
915
|
+
spring?: SpringPreset;
|
|
916
|
+
/** Waits until the element scrolls into view instead of animating on mount. */
|
|
917
|
+
onView?: boolean;
|
|
918
|
+
className?: string;
|
|
919
|
+
}
|
|
920
|
+
declare function Reveal({ children, from, distance, delay, spring, onView, className, }: RevealProps): react.JSX.Element;
|
|
921
|
+
interface StaggerProps {
|
|
922
|
+
children: ReactNode;
|
|
923
|
+
/** Seconds between children. Collapses to zero under reduced motion. */
|
|
924
|
+
step?: number;
|
|
925
|
+
from?: RevealProps['from'];
|
|
926
|
+
onView?: boolean;
|
|
927
|
+
className?: string;
|
|
928
|
+
}
|
|
929
|
+
/** Wraps each child in a Reveal with an increasing delay — the list arrives, it does not pop. */
|
|
930
|
+
declare function Stagger({ children, step, from, onView, className }: StaggerProps): react.JSX.Element;
|
|
931
|
+
|
|
932
|
+
export { Alert, type AlertProps, type Align, type AutoplayConditions, Button, type ButtonProps, Carousel, type CarouselProps, type CarouselSkeletonProps, type CarouselSlideProps, Checkbox, type CheckboxProps, Checklist, type ChecklistProps, type ChecklistTask, Coachmark, type CoachmarkProps, type Column, Combobox, type ComboboxOption, type ComboboxProps, type Command, CommandPalette, type CommandPaletteProps, DEFAULT_LABELS, DataTable, type DataTableProps, type DataTableSkeletonProps, DateInput, type DateInputProps, type DayCell, Dialog, DialogClose, type DialogProps, DropdownMenu, type DropdownMenuProps, type DurationToken, Field, type FieldProps, FileDrop, type FileDropProps, type FileRules, Image, type ImageProps, type Labels, LabelsProvider, type LabelsProviderProps, type MenuItem, type MotionHelpers, MotionProvider, type MotionProviderProps, type MotionSettings, type NavItem, type NavSection, type NumberBounds, NumberInput, type NumberInputProps, type PageRange, Pagination, type PaginationProps, type PaletteCommand, Popover, type PopoverProps, RadioGroup, type RadioGroupProps, type RadioOption, type RankedCommand, type Rejection, Reveal, type RevealProps, type SeenStore, Select, type SelectOption, type SelectProps, type Side, Sidebar, type SidebarProps, type SortDirection, type SortState, type SpringPreset, Stagger, type StaggerProps, type StepTarget, Switch, type SwitchProps, type TabItem, Tabs, type TabsProps, TextInput, type TextInputProps, Textarea, type TextareaProps, type ThemeChoice, ThemeProvider, TimeInput, type TimeInputProps, type TimeValue, type ToastOptions, type ToastPosition, ToastProvider, type ToastProviderProps, Tooltip, type TooltipProps, TopBar, type TopBarProps, Tour, type TourAction, type TourProps, type TourState, type TourStatus, type TourStep, ariaSortFor, canStep, clamp, decimalPlaces, describeAccept, filterCommands, formatISO, formatTime, groupCommands, hasEnded, initialTourState, isOutOfRange, isSameDay, isTimeOutOfRange, matchesAccept, monthMatrix, nextSort, pageRange, parseDateInput, parseNumber, parseTime, partitionFiles, rankCommand, resolveTarget, shouldAutoplay, startOfDay, stepBy, timeOptions, timeToMinutes, tourReducer, useFieldWiring, useLabels, useMotionSettings, useTheme, useToast };
|