@molecule/app-ui-react 1.3.1 → 1.3.3

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 CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-10-03T14:45:44.646Z
6
+ Generated: 2026-10-16T00:37:43.433Z
7
7
  -->
8
8
 
9
9
  # @molecule/app-ui-react
@@ -66,331 +66,385 @@ npm install -D @types/react @types/react-dom
66
66
 
67
67
  ### Interfaces
68
68
 
69
- #### `AccordionItem`
69
+ #### `CSSProperties`
70
70
 
71
- A single item in an Accordion component.
71
+ Framework-agnostic CSS properties.
72
+ Mirrors React.CSSProperties but without React dependency.
72
73
 
73
74
  ```typescript
74
- interface AccordionItem<T = string> {
75
- /**
76
- * Item value/id.
77
- */
78
- value: T
79
- /**
80
- * Item header/trigger.
81
- */
82
- header: Children
83
- /**
84
- * Item content.
85
- */
86
- content: Children
87
- /**
88
- * Whether the item is disabled.
89
- */
90
- disabled?: boolean
75
+ interface CSSProperties {
76
+ [key: string]: string | number | undefined
91
77
  }
92
78
  ```
93
79
 
94
- #### `AccordionProps`
80
+ #### `BaseProps`
95
81
 
96
- Props for the Accordion component.
82
+ Base props shared by all components.
97
83
 
98
84
  ```typescript
99
- interface AccordionProps<T = string> extends BaseProps {
85
+ interface BaseProps {
100
86
  /**
101
- * Accordion items.
87
+ * Additional CSS class name(s).
102
88
  */
103
- items: AccordionItem<T>[]
89
+ className?: string
104
90
  /**
105
- * Expanded item(s).
91
+ * Inline styles.
106
92
  */
107
- value?: T | T[]
93
+ style?: CSSProperties
108
94
  /**
109
- * Default expanded item(s).
95
+ * Test ID for automated testing.
110
96
  */
111
- defaultValue?: T | T[]
97
+ testId?: string
112
98
  /**
113
- * Change handler.
99
+ * Automation ID for AI agents and E2E tests. Maps to the `data-mol-id`
100
+ * HTML attribute. Use `molId()` from `./automation.js` to generate
101
+ * semantic IDs. (Tooling only — screen readers do not expose `data-*`
102
+ * attributes; accessible names come from labels/`aria-*`.)
114
103
  */
115
- onChange?: (value: T | T[]) => void
104
+ automationId?: string
116
105
  /**
117
- * Whether multiple items can be expanded.
106
+ * Whether the component is disabled.
118
107
  */
119
- multiple?: boolean
108
+ disabled?: boolean
109
+ }
110
+ ```
111
+
112
+ #### `HTMLElementProps`
113
+
114
+ Base props for HTML elements.
115
+ Framework bindings should extend this with framework-specific attributes.
116
+
117
+ ```typescript
118
+ interface HTMLElementProps extends BaseProps {
119
+ id?: string
120
+ title?: string
121
+ tabIndex?: number
122
+ role?: string
123
+ 'aria-label'?: string
124
+ 'aria-labelledby'?: string
125
+ 'aria-describedby'?: string
126
+ 'aria-hidden'?: boolean
127
+ 'aria-disabled'?: boolean
128
+ 'aria-expanded'?: boolean
129
+ 'aria-selected'?: boolean
130
+ 'aria-checked'?: boolean | 'mixed'
131
+ 'aria-pressed'?: boolean | 'mixed'
132
+ 'aria-invalid'?: boolean
133
+ 'aria-required'?: boolean
134
+ 'aria-readonly'?: boolean
135
+ 'aria-busy'?: boolean
136
+ 'aria-live'?: 'off' | 'polite' | 'assertive'
137
+ onClick?: MouseEventHandler
138
+ onDoubleClick?: MouseEventHandler
139
+ onMouseEnter?: MouseEventHandler
140
+ onMouseLeave?: MouseEventHandler
141
+ onFocus?: FocusEventHandler
142
+ onBlur?: FocusEventHandler
143
+ onKeyDown?: KeyboardEventHandler
144
+ onKeyUp?: KeyboardEventHandler
145
+ onKeyPress?: KeyboardEventHandler
146
+ }
147
+ ```
148
+
149
+ #### `InputElementProps`
150
+
151
+ Base props for input elements.
152
+
153
+ ```typescript
154
+ interface InputElementProps extends HTMLElementProps {
155
+ name?: string
156
+ value?: string | number | readonly string[]
157
+ defaultValue?: string | number | readonly string[]
158
+ placeholder?: string
159
+ required?: boolean
160
+ readOnly?: boolean
161
+ autoFocus?: boolean
162
+ autoComplete?: string
163
+ maxLength?: number
164
+ minLength?: number
165
+ pattern?: string
166
+ onChange?: ChangeEventHandler
167
+ onInput?: FormEventHandler
168
+ }
169
+ ```
170
+
171
+ #### `ButtonElementProps`
172
+
173
+ Base props for button elements.
174
+
175
+ ```typescript
176
+ interface ButtonElementProps extends HTMLElementProps {
120
177
  /**
121
- * Whether items can be collapsed.
178
+ * Defaults to `'button'` in every framework binding, so a button never submits a
179
+ * form by accident. A form's primary action must set `type="submit"`: Enter then
180
+ * submits the form, and tests that select `button[type="submit"]` find it.
122
181
  */
123
- collapsible?: boolean
182
+ type?: 'button' | 'submit' | 'reset'
183
+ name?: string
184
+ value?: string
185
+ form?: string
124
186
  }
125
187
  ```
126
188
 
127
- #### `AlertProps`
189
+ #### `TextareaElementProps`
128
190
 
129
- Props for the Alert component.
191
+ Base props for textarea elements.
130
192
 
131
193
  ```typescript
132
- interface AlertProps extends HTMLElementProps {
194
+ interface TextareaElementProps extends HTMLElementProps {
195
+ name?: string
196
+ value?: string
197
+ defaultValue?: string
198
+ placeholder?: string
199
+ required?: boolean
200
+ readOnly?: boolean
201
+ autoFocus?: boolean
202
+ rows?: number
203
+ cols?: number
204
+ maxLength?: number
205
+ minLength?: number
206
+ wrap?: 'hard' | 'soft' | 'off'
207
+ onChange?: ChangeEventHandler
208
+ onInput?: FormEventHandler
209
+ }
210
+ ```
211
+
212
+ #### `SelectElementProps`
213
+
214
+ Base props for select elements.
215
+
216
+ ```typescript
217
+ interface SelectElementProps extends HTMLElementProps {
218
+ name?: string
219
+ required?: boolean
220
+ autoFocus?: boolean
221
+ multiple?: boolean
222
+ onChange?: ChangeEventHandler
223
+ }
224
+ ```
225
+
226
+ #### `FormElementProps`
227
+
228
+ Base props for form elements.
229
+
230
+ ```typescript
231
+ interface FormElementProps extends HTMLElementProps {
232
+ action?: string
233
+ method?: 'get' | 'post'
234
+ encType?: string
235
+ target?: string
236
+ noValidate?: boolean
237
+ autoComplete?: 'on' | 'off'
238
+ onSubmit?: FormEventHandler
239
+ onReset?: FormEventHandler
240
+ }
241
+ ```
242
+
243
+ #### `ButtonProps`
244
+
245
+ Props for the Button component.
246
+
247
+ ```typescript
248
+ interface ButtonProps extends ButtonElementProps {
133
249
  /**
134
- * Alert content.
250
+ * Button content.
135
251
  */
136
252
  children?: Children
137
253
  /**
138
- * Alert title.
254
+ * Visual variant.
139
255
  */
140
- title?: string
256
+ variant?: ButtonVariant
141
257
  /**
142
- * Alert status/type.
258
+ * Color scheme.
143
259
  */
144
- status?: ColorVariant
260
+ color?: ColorVariant
145
261
  /**
146
- * Alert variant.
262
+ * Button size.
147
263
  */
148
- variant?: 'solid' | 'subtle' | 'outline' | 'left-accent'
264
+ size?: ButtonSize
149
265
  /**
150
- * Whether the alert is dismissible.
266
+ * Whether the button is in a loading state.
151
267
  */
152
- dismissible?: boolean
268
+ loading?: boolean
153
269
  /**
154
- * Called when dismissed.
270
+ * Loading text to display.
155
271
  */
156
- onDismiss?: () => void
272
+ loadingText?: string
157
273
  /**
158
- * Icon to display.
274
+ * Whether the button takes full width.
159
275
  */
160
- icon?: Children
276
+ fullWidth?: boolean
161
277
  /**
162
- * Accessible label for the dismiss button.
163
- * @default 'Dismiss'
278
+ * Icon to display before the label.
164
279
  */
165
- dismissLabel?: string
280
+ leftIcon?: Children
281
+ /**
282
+ * Icon to display after the label.
283
+ */
284
+ rightIcon?: Children
166
285
  }
167
286
  ```
168
287
 
169
- #### `AuthGuardProps`
170
-
171
- Props for {@link AuthGuard}.
288
+ #### `InputProps`
172
289
 
173
- All props are optional — the default behavior (loading tag → redirect
174
- to `/login` → `<Outlet />`) matches the bare-bones guard apps were
175
- shipping locally. The props let apps customize per-call without
176
- forking the component.
290
+ Props for the Input component (text field, email, password, etc.).
177
291
 
178
292
  ```typescript
179
- interface AuthGuardProps {
180
- /**
181
- * Element rendered while `useAuth().state.initialized` is `false`.
182
- * Overrides the default `<div data-mol-id="auth-guard-loading">…</div>`
183
- * loading tag — pass a full-page spinner or any other UI you want
184
- * during the auth bootstrap window.
185
- */
186
- loadingFallback?: ReactNode
293
+ interface InputProps extends InputElementProps {
187
294
  /**
188
- * i18n key used for the default loading-tag text. Defaults to
189
- * `'common.loading'`. Ignored when `loadingFallback` is set.
295
+ * Input type.
190
296
  */
191
- loadingKey?: string
297
+ type?: InputType
192
298
  /**
193
- * Fallback text if the i18n key is missing. Defaults to `'Loading...'`
194
- * (the project-canonical ASCII glyph — Phase C of the locale
195
- * canonicalization plan). Ignored when `loadingFallback` is set.
299
+ * Input size.
196
300
  */
197
- loadingDefault?: string
301
+ size?: Size
198
302
  /**
199
- * Path to redirect to when the user is not authenticated. Defaults to
200
- * `'/login'`. The current `useLocation()` is preserved as `state.from`
201
- * for post-login restoration.
303
+ * Horizontal text alignment inside the input (see
304
+ * {@link InputClassOptions.align}). Defaults to the bond's own style.
202
305
  */
203
- loginPath?: string
306
+ align?: 'left' | 'center'
204
307
  /**
205
- * Callback invoked when `isAuthenticated` transitions to `true` (or is
206
- * already `true` on first render). Useful for one-shot per-app
207
- * bootstrap effects (e.g. seeding fixture data). The caller is
208
- * responsible for idempotency if the auth state can flip back and
209
- * forth — this fires on every transition.
308
+ * Label text.
210
309
  */
211
- onAuthenticated?: () => void
310
+ label?: string
212
311
  /**
213
- * Children to render when authenticated. Defaults to `<Outlet />`,
214
- * which is the React Router pattern this guard is designed for.
312
+ * Error message.
215
313
  */
216
- children?: ReactNode
217
- }
218
- ```
219
-
220
- #### `AvatarProps`
221
-
222
- Props for the Avatar component.
223
-
224
- ```typescript
225
- interface AvatarProps extends HTMLElementProps {
314
+ error?: string
226
315
  /**
227
- * Image source URL.
316
+ * Hint/help text.
228
317
  */
229
- src?: string
318
+ hint?: string
230
319
  /**
231
- * Alt text for the image.
320
+ * Element to display on the left.
232
321
  */
233
- alt?: string
322
+ leftElement?: Children
234
323
  /**
235
- * Name for fallback initials.
324
+ * Element to display on the right.
236
325
  */
237
- name?: string
326
+ rightElement?: Children
238
327
  /**
239
- * Avatar size.
328
+ * Whether to show a clear button.
240
329
  */
241
- size?: Size | number
330
+ clearable?: boolean
242
331
  /**
243
- * Whether the avatar is rounded.
332
+ * Called when the clear button is clicked.
244
333
  */
245
- rounded?: boolean
334
+ onClear?: () => void
246
335
  /**
247
- * Fallback element when no image.
336
+ * Accessible label for the clear button.
337
+ * @default 'Clear'
248
338
  */
249
- fallback?: Children
339
+ clearLabel?: string
250
340
  }
251
341
  ```
252
342
 
253
- #### `BadgeProps`
343
+ #### `TextareaProps`
254
344
 
255
- Props for the Badge component (status labels, counts, tags).
345
+ Props for the Textarea component.
256
346
 
257
347
  ```typescript
258
- interface BadgeProps extends HTMLElementProps {
348
+ interface TextareaProps extends TextareaElementProps {
259
349
  /**
260
- * Badge content.
350
+ * Text size tier (see {@link TextareaClassOptions.size}) — pass the same
351
+ * `size` as a neighboring Input for identical font sizes.
261
352
  */
262
- children?: Children
353
+ size?: Size
263
354
  /**
264
- * Badge color.
355
+ * Label text.
265
356
  */
266
- color?: ColorVariant
357
+ label?: string
267
358
  /**
268
- * Badge variant.
359
+ * Error message.
269
360
  */
270
- variant?: 'solid' | 'outline' | 'subtle'
361
+ error?: string
271
362
  /**
272
- * Badge size.
363
+ * Hint/help text.
273
364
  */
274
- size?: Size
365
+ hint?: string
275
366
  /**
276
- * Whether the badge is rounded.
367
+ * Whether the textarea auto-resizes.
277
368
  */
278
- rounded?: boolean
369
+ autoResize?: boolean
370
+ /**
371
+ * Minimum number of rows.
372
+ */
373
+ minRows?: number
374
+ /**
375
+ * Maximum number of rows.
376
+ */
377
+ maxRows?: number
279
378
  }
280
379
  ```
281
380
 
282
- #### `BaseProps`
381
+ #### `SelectOption`
283
382
 
284
- Base props shared by all components.
383
+ A single option in a Select dropdown.
285
384
 
286
385
  ```typescript
287
- interface BaseProps {
288
- /**
289
- * Additional CSS class name(s).
290
- */
291
- className?: string
386
+ interface SelectOption<T = string> {
292
387
  /**
293
- * Inline styles.
388
+ * Option value.
294
389
  */
295
- style?: CSSProperties
390
+ value: T
296
391
  /**
297
- * Test ID for automated testing.
392
+ * Display label.
298
393
  */
299
- testId?: string
394
+ label: string
300
395
  /**
301
- * Automation ID for AI agents and E2E tests. Maps to the `data-mol-id`
302
- * HTML attribute. Use `molId()` from `./automation.js` to generate
303
- * semantic IDs. (Tooling only — screen readers do not expose `data-*`
304
- * attributes; accessible names come from labels/`aria-*`.)
396
+ * Whether the option is disabled.
305
397
  */
306
- automationId?: string
398
+ disabled?: boolean
307
399
  /**
308
- * Whether the component is disabled.
400
+ * Option group (for grouped selects).
309
401
  */
310
- disabled?: boolean
311
- }
312
- ```
313
-
314
- #### `ButtonElementProps`
315
-
316
- Base props for button elements.
317
-
318
- ```typescript
319
- interface ButtonElementProps extends HTMLElementProps {
320
- type?: 'button' | 'submit' | 'reset'
321
- name?: string
322
- value?: string
323
- form?: string
402
+ group?: string
324
403
  }
325
404
  ```
326
405
 
327
- #### `ButtonProps`
406
+ #### `SelectProps`
328
407
 
329
- Props for the Button component.
408
+ Props for the Select dropdown component (single or multi-select).
330
409
 
331
410
  ```typescript
332
- interface ButtonProps extends ButtonElementProps {
333
- /**
334
- * Button content.
335
- */
336
- children?: Children
337
- /**
338
- * Visual variant.
339
- */
340
- variant?: ButtonVariant
341
- /**
342
- * Color scheme.
343
- */
344
- color?: ColorVariant
345
- /**
346
- * Button size.
347
- */
348
- size?: ButtonSize
411
+ interface SelectProps<T = string> extends SelectElementProps {
349
412
  /**
350
- * Whether the button is in a loading state.
413
+ * Select options.
351
414
  */
352
- loading?: boolean
415
+ options: SelectOption<T>[]
353
416
  /**
354
- * Loading text to display.
417
+ * Current value.
355
418
  */
356
- loadingText?: string
419
+ value?: T
357
420
  /**
358
- * Whether the button takes full width.
421
+ * Change handler (with typed value).
359
422
  */
360
- fullWidth?: boolean
423
+ onValueChange?: (value: T) => void
361
424
  /**
362
- * Icon to display before the label.
425
+ * Select size.
363
426
  */
364
- leftIcon?: Children
427
+ size?: Size
365
428
  /**
366
- * Icon to display after the label.
429
+ * Label text.
367
430
  */
368
- rightIcon?: Children
369
- }
370
- ```
371
-
372
- #### `CardProps`
373
-
374
- Props for the Card container component (elevated, outlined, or filled surface).
375
-
376
- ```typescript
377
- interface CardProps extends HTMLElementProps {
431
+ label?: string
378
432
  /**
379
- * Card content.
433
+ * Placeholder text.
380
434
  */
381
- children?: Children
435
+ placeholder?: string
382
436
  /**
383
- * Card variant.
437
+ * Error message.
384
438
  */
385
- variant?: 'elevated' | 'outlined' | 'filled'
439
+ error?: string
386
440
  /**
387
- * Whether the card is interactive (clickable).
441
+ * Hint/help text.
388
442
  */
389
- interactive?: boolean
443
+ hint?: string
390
444
  /**
391
- * Padding size.
445
+ * Whether to allow clearing the selection.
392
446
  */
393
- padding?: Size | 'none'
447
+ clearable?: boolean
394
448
  }
395
449
  ```
396
450
 
@@ -423,1027 +477,813 @@ interface CheckboxProps extends InputElementProps {
423
477
  }
424
478
  ```
425
479
 
426
- #### `ConfirmButtonProps`
480
+ #### `RadioOption`
427
481
 
428
- Props for {@link ConfirmButton}.
482
+ A single option in a RadioGroup.
429
483
 
430
484
  ```typescript
431
- interface ConfirmButtonProps extends Omit<
432
- ButtonProps,
433
- 'onClick' | 'children' | 'onConfirm' | keyof React.DOMAttributes<HTMLButtonElement>
434
- > {
485
+ interface RadioOption<T = string> {
435
486
  /**
436
- * Fired ONLY on the confirming (second) click — i.e. when the action
437
- * actually commits. Errors should be handled by the caller (render an
438
- * inline banner); while the returned promise is pending the button stays
439
- * in its confirming state and ignores further clicks.
487
+ * Option value.
440
488
  */
441
- onConfirm: () => void | Promise<void>
489
+ value: T
442
490
  /**
443
- * Visible label in the idle (armed-to-be-clicked) state.
491
+ * Display label.
444
492
  */
445
- label: React.ReactNode
493
+ label: Children
446
494
  /**
447
- * Visible label in the armed state — the "click again to confirm" step.
448
- * Defaults to a localized "Confirm?" via the i18n bond.
495
+ * Whether the option is disabled.
449
496
  */
450
- confirmLabel?: React.ReactNode
497
+ disabled?: boolean
498
+ }
499
+ ```
500
+
501
+ #### `RadioGroupProps`
502
+
503
+ Props for the RadioGroup component.
504
+
505
+ ```typescript
506
+ interface RadioGroupProps<T = string> extends BaseProps {
451
507
  /**
452
- * Visible label while {@link onConfirm} is pending. Defaults to a
453
- * localized "Working…".
508
+ * Radio options.
454
509
  */
455
- pendingLabel?: React.ReactNode
510
+ options: RadioOption<T>[]
456
511
  /**
457
- * Seconds before the armed state auto-disarms back to idle. Low-stakes
458
- * actions tolerate a long window; destructive ones should keep it short.
459
- * `0` disables auto-disarm (not recommended — a stray click then leaves
460
- * the button armed forever).
512
+ * Current value.
461
513
  */
462
- disarmSeconds?: number
514
+ value?: T
463
515
  /**
464
- * Disable the control entirely (idle and confirming states).
516
+ * Change handler.
465
517
  */
466
- disabled?: boolean
518
+ onChange?: (value: T) => void
467
519
  /**
468
- * data-mol-id for the button (all states share one element).
520
+ * Radio size.
469
521
  */
470
- testId?: string
471
- }
472
- ```
473
-
474
- #### `ConfirmDialogProps`
475
-
476
- Props for {@link ConfirmDialog}.
477
-
478
- ```typescript
479
- interface ConfirmDialogProps {
480
- /** Whether the dialog is open. */
481
- open: boolean
482
- /** Called when the dialog should close (escape, backdrop, cancel). */
483
- onClose: () => void
484
- /** Title. */
485
- title: ReactNode
486
- /** Body / warning text. */
487
- description: ReactNode
488
- /** Confirm-button label (e.g. "Delete"). */
489
- confirmLabel?: ReactNode
490
- /** Cancel-button label. */
491
- cancelLabel?: ReactNode
492
- /** Called when the user confirms. */
493
- onConfirm: () => void | Promise<void>
494
- /** Is the confirm action destructive? Defaults to true. */
495
- destructive?: boolean
496
- /** Extra body content between description and footer. */
497
- children?: ReactNode
498
- /** Disables both buttons. Set it yourself while your `onConfirm` promise is pending — the dialog does not track it and does not auto-close. */
499
- loading?: boolean
522
+ size?: Size
523
+ /**
524
+ * Group label.
525
+ */
526
+ label?: string
527
+ /**
528
+ * Shared `name` attribute for the group's radio inputs (used for native
529
+ * form submission). When omitted, a unique per-instance name is generated
530
+ * so separate groups never merge — the visible `label` is deliberately
531
+ * NOT used as the name, because two groups with the same label (e.g. two
532
+ * "Size" pickers) would otherwise form ONE native radio group and
533
+ * deselect each other.
534
+ */
535
+ name?: string
536
+ /**
537
+ * Layout direction.
538
+ */
539
+ direction?: 'horizontal' | 'vertical'
540
+ /**
541
+ * Error message.
542
+ */
543
+ error?: string
500
544
  }
501
545
  ```
502
546
 
503
- #### `ContainerProps`
547
+ #### `SwitchProps`
504
548
 
505
- Props for the Container layout component.
549
+ Props for the Switch/Toggle component.
506
550
 
507
551
  ```typescript
508
- interface ContainerProps extends HTMLElementProps {
552
+ interface SwitchProps extends InputElementProps {
509
553
  /**
510
- * Container content.
554
+ * Switch label.
511
555
  */
512
- children?: Children
556
+ label?: Children
513
557
  /**
514
- * Maximum width.
558
+ * Whether the switch is on.
515
559
  */
516
- maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | string
560
+ checked?: boolean
517
561
  /**
518
- * Whether to center the container.
562
+ * Switch size.
519
563
  */
520
- centered?: boolean
564
+ size?: Size
521
565
  /**
522
- * Horizontal padding.
566
+ * Color when on.
523
567
  */
524
- paddingX?: Size | string
525
- }
526
- ```
527
-
528
- #### `CSSProperties`
529
-
530
- Framework-agnostic CSS properties.
531
- Mirrors React.CSSProperties but without React dependency.
532
-
533
- ```typescript
534
- interface CSSProperties {
535
- [key: string]: string | number | undefined
568
+ color?: ColorVariant
536
569
  }
537
570
  ```
538
571
 
539
- #### `FlexProps`
572
+ #### `ModalProps`
540
573
 
541
- Flex container props.
574
+ Props for the Modal/Dialog component.
542
575
 
543
576
  ```typescript
544
- interface FlexProps extends HTMLElementProps {
577
+ interface ModalProps extends HTMLElementProps {
545
578
  /**
546
- * Flex content.
579
+ * Whether the modal is open.
547
580
  */
548
- children?: Children
581
+ open: boolean
549
582
  /**
550
- * Flex direction.
583
+ * Called when the modal should close.
551
584
  */
552
- direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
585
+ onClose: () => void
553
586
  /**
554
- * Justify content.
587
+ * Modal title.
555
588
  */
556
- justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'
589
+ title?: string
557
590
  /**
558
- * Align items.
591
+ * Modal content.
559
592
  */
560
- align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
593
+ children?: Children
561
594
  /**
562
- * Flex wrap.
595
+ * Modal size.
563
596
  */
564
- wrap?: 'wrap' | 'nowrap' | 'wrap-reverse'
597
+ size?: ModalSize
565
598
  /**
566
- * Gap between items.
599
+ * Whether to show a close button.
567
600
  */
568
- gap?: Size | string | number
569
- }
570
- ```
571
-
572
- #### `FormElementProps`
573
-
574
- Base props for form elements.
575
-
576
- ```typescript
577
- interface FormElementProps extends HTMLElementProps {
578
- action?: string
579
- method?: 'get' | 'post'
580
- encType?: string
581
- target?: string
582
- noValidate?: boolean
583
- autoComplete?: 'on' | 'off'
584
- onSubmit?: FormEventHandler
585
- onReset?: FormEventHandler
586
- }
587
- ```
588
-
589
- #### `FormFieldProps`
590
-
591
- Form field wrapper props.
592
-
593
- ```typescript
594
- interface FormFieldProps extends HTMLElementProps {
601
+ showCloseButton?: boolean
595
602
  /**
596
- * Field content.
603
+ * Whether clicking the overlay closes the modal.
597
604
  */
598
- children?: Children
605
+ closeOnOverlayClick?: boolean
599
606
  /**
600
- * Field label.
607
+ * Whether pressing Escape closes the modal.
601
608
  */
602
- label?: string
609
+ closeOnEscape?: boolean
603
610
  /**
604
- * Field name.
611
+ * Footer content (typically action buttons).
605
612
  */
606
- name?: string
613
+ footer?: Children
607
614
  /**
608
- * Error message.
615
+ * Whether the modal is centered vertically.
609
616
  */
610
- error?: string
617
+ centered?: boolean
611
618
  /**
612
- * Hint/help text.
619
+ * Whether to prevent body scroll when open.
613
620
  */
614
- hint?: string
621
+ preventScroll?: boolean
615
622
  /**
616
- * Whether the field is required.
623
+ * Accessible label for the close button.
624
+ * @default 'Close'
617
625
  */
618
- required?: boolean
626
+ closeLabel?: string
619
627
  }
620
628
  ```
621
629
 
622
- #### `FormProps`
630
+ #### `SpinnerProps`
623
631
 
624
- Props for the Form component (wraps inputs with submission handling and validation).
632
+ Props for the Spinner/loading indicator component.
625
633
 
626
634
  ```typescript
627
- interface FormProps extends FormElementProps {
635
+ interface SpinnerProps extends BaseProps {
628
636
  /**
629
- * Form content.
637
+ * Spinner size.
630
638
  */
631
- children?: Children
639
+ size?: Size
632
640
  /**
633
- * Submit handler with form data.
641
+ * Spinner color.
634
642
  */
635
- onFormSubmit?: (data: Record<string, unknown>) => void | Promise<void>
643
+ color?: ColorVariant | string
636
644
  /**
637
- * Whether the form is submitting.
645
+ * Loading label (for accessibility).
638
646
  */
639
- submitting?: boolean
647
+ label?: string
648
+ /**
649
+ * Spinner thickness.
650
+ */
651
+ thickness?: number
640
652
  }
641
653
  ```
642
654
 
643
- #### `GridProps`
655
+ #### `AvatarProps`
644
656
 
645
- Grid container props.
657
+ Props for the Avatar component.
646
658
 
647
659
  ```typescript
648
- interface GridProps extends HTMLElementProps {
649
- /**
650
- * Grid content.
651
- */
652
- children?: Children
660
+ interface AvatarProps extends HTMLElementProps {
653
661
  /**
654
- * Number of columns.
662
+ * Image source URL.
655
663
  */
656
- columns?: number | string
664
+ src?: string
657
665
  /**
658
- * Number of rows.
666
+ * Alt text for the image.
659
667
  */
660
- rows?: number | string
668
+ alt?: string
661
669
  /**
662
- * Gap between items.
670
+ * Name for fallback initials.
663
671
  */
664
- gap?: Size | string | number
672
+ name?: string
665
673
  /**
666
- * Column gap.
674
+ * Avatar size.
667
675
  */
668
- columnGap?: Size | string | number
676
+ size?: Size | number
669
677
  /**
670
- * Row gap.
678
+ * Whether the avatar is rounded.
671
679
  */
672
- rowGap?: Size | string | number
673
- }
674
- ```
675
-
676
- #### `HTMLElementProps`
677
-
678
- Base props for HTML elements.
679
- Framework bindings should extend this with framework-specific attributes.
680
-
681
- ```typescript
682
- interface HTMLElementProps extends BaseProps {
683
- id?: string
684
- title?: string
685
- tabIndex?: number
686
- role?: string
687
- 'aria-label'?: string
688
- 'aria-labelledby'?: string
689
- 'aria-describedby'?: string
690
- 'aria-hidden'?: boolean
691
- 'aria-disabled'?: boolean
692
- 'aria-expanded'?: boolean
693
- 'aria-selected'?: boolean
694
- 'aria-checked'?: boolean | 'mixed'
695
- 'aria-pressed'?: boolean | 'mixed'
696
- 'aria-invalid'?: boolean
697
- 'aria-required'?: boolean
698
- 'aria-readonly'?: boolean
699
- 'aria-busy'?: boolean
700
- 'aria-live'?: 'off' | 'polite' | 'assertive'
701
- onClick?: MouseEventHandler
702
- onDoubleClick?: MouseEventHandler
703
- onMouseEnter?: MouseEventHandler
704
- onMouseLeave?: MouseEventHandler
705
- onFocus?: FocusEventHandler
706
- onBlur?: FocusEventHandler
707
- onKeyDown?: KeyboardEventHandler
708
- onKeyUp?: KeyboardEventHandler
709
- onKeyPress?: KeyboardEventHandler
710
- }
711
- ```
712
-
713
- #### `IconProps`
714
-
715
- Props for {@link Icon}.
716
-
717
- Extends `SVGProps<SVGSVGElement>` so callers can pass any SVG / HTML
718
- attribute the underlying `<svg>` accepts, including `data-mol-id`,
719
- `aria-*`, `role`, event handlers, `style`, etc. — without the
720
- component needing to enumerate them.
721
-
722
- ```typescript
723
- interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'width' | 'height' | 'viewBox' | 'fill'> {
680
+ rounded?: boolean
724
681
  /**
725
- * Name of the glyph to look up in the bonded icon set. Typed as
726
- * {@link IconName} so a typo fails the type-check instead of throwing at
727
- * render time; sets with extra glyphs augment `CustomIconNames` in
728
- * `@molecule/app-icons` to widen it.
682
+ * Fallback element when no image.
729
683
  */
730
- name: IconName
731
- /** Width and height of the rendered SVG in pixels. Defaults to 20. */
732
- size?: number
733
- /** Class name forwarded to the root `<svg>`. */
734
- className?: string
735
- }
736
- ```
737
-
738
- #### `InputElementProps`
739
-
740
- Base props for input elements.
741
-
742
- ```typescript
743
- interface InputElementProps extends HTMLElementProps {
744
- name?: string
745
- value?: string | number | readonly string[]
746
- defaultValue?: string | number | readonly string[]
747
- placeholder?: string
748
- required?: boolean
749
- readOnly?: boolean
750
- autoFocus?: boolean
751
- autoComplete?: string
752
- maxLength?: number
753
- minLength?: number
754
- pattern?: string
755
- onChange?: ChangeEventHandler
756
- onInput?: FormEventHandler
684
+ fallback?: Children
757
685
  }
758
686
  ```
759
687
 
760
- #### `InputProps`
688
+ #### `BadgeProps`
761
689
 
762
- Props for the Input component (text field, email, password, etc.).
690
+ Props for the Badge component (status labels, counts, tags).
763
691
 
764
692
  ```typescript
765
- interface InputProps extends InputElementProps {
766
- /**
767
- * Input type.
768
- */
769
- type?: InputType
693
+ interface BadgeProps extends HTMLElementProps {
770
694
  /**
771
- * Input size.
695
+ * Badge content.
772
696
  */
773
- size?: Size
697
+ children?: Children
774
698
  /**
775
- * Horizontal text alignment inside the input (see
776
- * {@link InputClassOptions.align}). Defaults to the bond's own style.
699
+ * Badge color.
777
700
  */
778
- align?: 'left' | 'center'
701
+ color?: ColorVariant
779
702
  /**
780
- * Label text.
703
+ * Badge variant.
781
704
  */
782
- label?: string
705
+ variant?: 'solid' | 'outline' | 'subtle'
783
706
  /**
784
- * Error message.
707
+ * Badge size.
785
708
  */
786
- error?: string
709
+ size?: Size
787
710
  /**
788
- * Hint/help text.
711
+ * Whether the badge is rounded.
789
712
  */
790
- hint?: string
713
+ rounded?: boolean
714
+ }
715
+ ```
716
+
717
+ #### `TooltipProps`
718
+
719
+ Props for the Tooltip component (hover/focus popover with informational text).
720
+
721
+ ```typescript
722
+ interface TooltipProps extends HTMLElementProps {
791
723
  /**
792
- * Element to display on the left.
724
+ * Tooltip content.
793
725
  */
794
- leftElement?: Children
726
+ content: Children
795
727
  /**
796
- * Element to display on the right.
728
+ * Element that triggers the tooltip.
797
729
  */
798
- rightElement?: Children
730
+ children: Children
799
731
  /**
800
- * Whether to show a clear button.
732
+ * Tooltip placement.
801
733
  */
802
- clearable?: boolean
734
+ placement?: TooltipPlacement
803
735
  /**
804
- * Called when the clear button is clicked.
736
+ * Delay before showing (ms).
805
737
  */
806
- onClear?: () => void
738
+ delay?: number
807
739
  /**
808
- * Accessible label for the clear button.
809
- * @default 'Clear'
740
+ * Whether the tooltip has an arrow.
810
741
  */
811
- clearLabel?: string
742
+ hasArrow?: boolean
812
743
  }
813
744
  ```
814
745
 
815
- #### `LanguagePickerProps`
816
-
817
- Props for {@link LanguagePicker}.
746
+ #### `CardProps`
818
747
 
819
- Extends standard `<button>` attributes so callers can pass any extra
820
- `data-*`, `aria-*`, event handler, or `style` prop without forking the
821
- component. The named props let apps customize the trigger label, icon,
822
- size, and modal heading without spreading attribute concerns.
748
+ Props for the Card container component (elevated, outlined, or filled surface).
823
749
 
824
750
  ```typescript
825
- interface LanguagePickerProps extends Omit<
826
- ButtonHTMLAttributes<HTMLButtonElement>,
827
- 'aria-label' | 'onClick' | 'type' | 'children'
828
- > {
829
- /** i18n key for the trigger button label / aria-label. Defaults to `'footer.language'`. */
830
- labelKey?: string
831
- /** Fallback label if the i18n key is missing. Defaults to `'Language'`. */
832
- labelDefault?: string
833
- /** i18n key for the modal title. Defaults to `'languagePicker.modalTitle'`. */
834
- modalTitleKey?: string
835
- /** Fallback modal title if the i18n key is missing. Defaults to `'Choose language'`. */
836
- modalTitleDefault?: string
837
- /** Icon glyph to render before the current locale name. Defaults to `'globe'`. */
838
- icon?: IconName
839
- /** Pixel size for the rendered icon. Defaults to `16`. */
840
- iconSize?: number
751
+ interface CardProps extends HTMLElementProps {
841
752
  /**
842
- * What to render inside the trigger button.
843
- *
844
- * - `'name'` — globe icon + current locale's native name (e.g. `🌐 English`).
845
- * This is the default; matches the molecule-dev footer pattern.
846
- * - `'code'` — globe icon + lowercase locale code (e.g. `🌐 en`). Useful in
847
- * tight chrome where the long native name (e.g. "Bahasa Indonesia") would wrap.
848
- * - `'icon'` — globe icon only. Useful in icon-bar headers.
753
+ * Card content.
849
754
  */
850
- display?: 'name' | 'code' | 'icon'
851
- /** Optional className appended to the trigger button. */
852
- className?: string
853
- /** Optional render override: receives `{ open }` and replaces the default trigger. */
854
- renderTrigger?: (open: () => void) => ReactNode
755
+ children?: Children
756
+ /**
757
+ * Card variant.
758
+ */
759
+ variant?: 'elevated' | 'outlined' | 'filled'
760
+ /**
761
+ * Whether the card is interactive (clickable).
762
+ */
763
+ interactive?: boolean
764
+ /**
765
+ * Padding size.
766
+ */
767
+ padding?: Size | 'none'
855
768
  }
856
769
  ```
857
770
 
858
- #### `LoadErrorBannerProps`
771
+ #### `ContainerProps`
859
772
 
860
- Props for {@link LoadErrorBanner}. Rest props are forwarded to the root
861
- `<div>`, so they are typed as its attributes.
773
+ Props for the Container layout component.
862
774
 
863
775
  ```typescript
864
- interface LoadErrorBannerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
865
- /** The primary error line (e.g. the localized "Could not load X."). */
866
- message: React.ReactNode
867
- /** Secondary line under the message (status code, hint). */
868
- detail?: React.ReactNode
776
+ interface ContainerProps extends HTMLElementProps {
869
777
  /**
870
- * Called when Retry is clicked. Return the promise; while pending, the
871
- * button is disabled and shows "Retrying…". Omit for a display-only
872
- * banner.
778
+ * Container content.
873
779
  */
874
- onRetry?: () => void | Promise<void>
875
- /** Retry-button label. Falls back to a localized "Retry". */
876
- retryLabel?: React.ReactNode
877
- /** `data-mol-id` for the retry button (default `load-error-retry`). */
878
- retryMolId?: string
879
- /** Extra content between message and retry row (e.g. an error code). */
880
- children?: React.ReactNode
780
+ children?: Children
781
+ /**
782
+ * Maximum width.
783
+ */
784
+ maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | string
785
+ /**
786
+ * Whether to center the container.
787
+ */
788
+ centered?: boolean
789
+ /**
790
+ * Horizontal padding.
791
+ */
792
+ paddingX?: Size | string
881
793
  }
882
794
  ```
883
795
 
884
- #### `ModalProps`
796
+ #### `FlexProps`
885
797
 
886
- Props for the Modal/Dialog component.
798
+ Flex container props.
887
799
 
888
800
  ```typescript
889
- interface ModalProps extends HTMLElementProps {
801
+ interface FlexProps extends HTMLElementProps {
890
802
  /**
891
- * Whether the modal is open.
803
+ * Flex content.
892
804
  */
893
- open: boolean
805
+ children?: Children
894
806
  /**
895
- * Called when the modal should close.
807
+ * Flex direction.
896
808
  */
897
- onClose: () => void
809
+ direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
898
810
  /**
899
- * Modal title.
811
+ * Justify content.
900
812
  */
901
- title?: string
813
+ justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'
902
814
  /**
903
- * Modal content.
815
+ * Align items.
904
816
  */
905
- children?: Children
817
+ align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
906
818
  /**
907
- * Modal size.
819
+ * Flex wrap.
908
820
  */
909
- size?: ModalSize
821
+ wrap?: 'wrap' | 'nowrap' | 'wrap-reverse'
910
822
  /**
911
- * Whether to show a close button.
823
+ * Gap between items.
912
824
  */
913
- showCloseButton?: boolean
825
+ gap?: Size | string | number
826
+ }
827
+ ```
828
+
829
+ #### `GridProps`
830
+
831
+ Grid container props.
832
+
833
+ ```typescript
834
+ interface GridProps extends HTMLElementProps {
914
835
  /**
915
- * Whether clicking the overlay closes the modal.
836
+ * Grid content.
916
837
  */
917
- closeOnOverlayClick?: boolean
838
+ children?: Children
918
839
  /**
919
- * Whether pressing Escape closes the modal.
840
+ * Number of columns.
920
841
  */
921
- closeOnEscape?: boolean
842
+ columns?: number | string
922
843
  /**
923
- * Footer content (typically action buttons).
844
+ * Number of rows.
924
845
  */
925
- footer?: Children
846
+ rows?: number | string
926
847
  /**
927
- * Whether the modal is centered vertically.
848
+ * Gap between items.
928
849
  */
929
- centered?: boolean
850
+ gap?: Size | string | number
930
851
  /**
931
- * Whether to prevent body scroll when open.
852
+ * Column gap.
932
853
  */
933
- preventScroll?: boolean
854
+ columnGap?: Size | string | number
934
855
  /**
935
- * Accessible label for the close button.
936
- * @default 'Close'
856
+ * Row gap.
937
857
  */
938
- closeLabel?: string
858
+ rowGap?: Size | string | number
939
859
  }
940
860
  ```
941
861
 
942
- #### `PaginationProps`
862
+ #### `SpacerProps`
943
863
 
944
- Props for the Pagination component (page navigation with current page, total, page size, and change callbacks).
864
+ Props for the Spacer layout component (adds whitespace between elements).
945
865
 
946
866
  ```typescript
947
- interface PaginationProps extends BaseProps {
867
+ interface SpacerProps extends BaseProps {
948
868
  /**
949
- * Current page (1-indexed).
869
+ * Space size.
950
870
  */
951
- page: number
871
+ size?: Size | string | number
952
872
  /**
953
- * Total number of pages.
873
+ * Whether the spacer is horizontal.
954
874
  */
955
- totalPages: number
875
+ horizontal?: boolean
876
+ }
877
+ ```
878
+
879
+ #### `FormProps`
880
+
881
+ Props for the Form component (wraps inputs with submission handling and validation).
882
+
883
+ ```typescript
884
+ interface FormProps extends FormElementProps {
956
885
  /**
957
- * Page change handler.
886
+ * Form content.
958
887
  */
959
- onChange: (page: number) => void
888
+ children?: Children
960
889
  /**
961
- * Number of sibling pages to show.
890
+ * Submit handler with form data.
891
+ */
892
+ onFormSubmit?: (data: Record<string, unknown>) => void | Promise<void>
893
+ /**
894
+ * Whether the form is submitting.
895
+ */
896
+ submitting?: boolean
897
+ }
898
+ ```
899
+
900
+ #### `FormFieldProps`
901
+
902
+ Form field wrapper props.
903
+
904
+ ```typescript
905
+ interface FormFieldProps extends HTMLElementProps {
906
+ /**
907
+ * Field content.
962
908
  */
963
- siblings?: number
909
+ children?: Children
964
910
  /**
965
- * Number of boundary pages to show.
911
+ * Field label.
966
912
  */
967
- boundaries?: number
913
+ label?: string
968
914
  /**
969
- * Pagination size.
915
+ * Field name.
970
916
  */
971
- size?: Size
917
+ name?: string
972
918
  /**
973
- * Whether to show first/last buttons.
919
+ * Error message.
974
920
  */
975
- showFirstLast?: boolean
921
+ error?: string
976
922
  /**
977
- * Whether to show previous/next buttons.
923
+ * Hint/help text.
978
924
  */
979
- showPrevNext?: boolean
925
+ hint?: string
980
926
  /**
981
- * Accessible labels for pagination controls.
927
+ * Whether the field is required.
982
928
  */
983
- labels?: {
984
- nav?: string
985
- first?: string
986
- previous?: string
987
- next?: string
988
- last?: string
989
- goToPage?: (page: number) => string
990
- }
991
- }
992
- ```
993
-
994
- #### `PanelCloseProviderProps`
995
-
996
- Props for {@link PanelCloseProvider}.
997
-
998
- ```typescript
999
- interface PanelCloseProviderProps {
1000
- /** Callback that dismisses the enclosing drawer/modal. */
1001
- close: () => void
1002
- /** Panel content that may call {@link usePanelClose}. */
1003
- children: ReactNode
929
+ required?: boolean
1004
930
  }
1005
931
  ```
1006
932
 
1007
- #### `ProgressProps`
933
+ #### `AlertProps`
1008
934
 
1009
- Props for the Progress component.
935
+ Props for the Alert component.
1010
936
 
1011
937
  ```typescript
1012
- interface ProgressProps extends BaseProps {
938
+ interface AlertProps extends HTMLElementProps {
1013
939
  /**
1014
- * Progress value (0-100).
940
+ * Alert content.
1015
941
  */
1016
- value: number
1017
-
942
+ children?: Children
1018
943
  /**
1019
- * Maximum value.
944
+ * Alert title.
1020
945
  */
1021
- max?: number
1022
-
946
+ title?: string
1023
947
  /**
1024
- * Progress size.
948
+ * Alert status/type.
1025
949
  */
1026
- size?: Size
1027
-
950
+ status?: ColorVariant
1028
951
  /**
1029
- * Progress color.
952
+ * Alert variant.
1030
953
  */
1031
- color?: ColorVariant
1032
-
954
+ variant?: 'solid' | 'subtle' | 'outline' | 'left-accent'
1033
955
  /**
1034
- * Whether to show the value label.
956
+ * Whether the alert is dismissible.
1035
957
  */
1036
- showValue?: boolean
1037
-
958
+ dismissible?: boolean
1038
959
  /**
1039
- * Accessible label.
960
+ * Called when dismissed.
1040
961
  */
1041
- label?: string
1042
-
962
+ onDismiss?: () => void
1043
963
  /**
1044
- * Whether the progress is indeterminate.
964
+ * Icon to display.
1045
965
  */
1046
- indeterminate?: boolean
1047
- }
1048
- ```
1049
-
1050
- #### `PromptDialogProps`
1051
-
1052
- Props for {@link PromptDialog}.
1053
-
1054
- ```typescript
1055
- interface PromptDialogProps {
1056
- /** Whether the dialog is open. */
1057
- open: boolean
1058
- /** Called when the dialog should close (escape, backdrop, cancel, or a fulfilled {@link PromptDialogProps.onSubmit}). */
1059
- onClose: () => void
1060
- /** Dialog heading. */
1061
- title: React.ReactNode
1062
- /** Explanatory line under the title. */
1063
- description?: React.ReactNode
1064
- /** Input placeholder. */
1065
- placeholder?: string
1066
- /** Value the input starts from every time the dialog opens. */
1067
- initialValue?: string
966
+ icon?: Children
1068
967
  /**
1069
- * Called with the entered value on confirm. Resolve to close the dialog;
1070
- * reject or throw to keep it open (show the error via {@link PromptDialogProps.children}).
968
+ * Accessible label for the dismiss button.
969
+ * @default 'Dismiss'
1071
970
  */
1072
- onSubmit: (value: string) => void | Promise<void>
1073
- /** Confirm-button label. Falls back to a localized "Confirm". */
1074
- confirmLabel?: React.ReactNode
1075
- /** Cancel-button label. Falls back to a localized "Cancel". */
1076
- cancelLabel?: React.ReactNode
1077
- /** Render the confirm button in the error color (e.g. an irreversible reset). */
1078
- destructive?: boolean
1079
- /** `data-mol-id` for the text input. */
1080
- inputMolId?: string
1081
- /** `data-mol-id` for the confirm button. */
1082
- confirmMolId?: string
1083
- /** `data-mol-id` for the cancel button. */
1084
- cancelMolId?: string
1085
- /** Extra body content under the input (error banners, hints). */
1086
- children?: React.ReactNode
971
+ dismissLabel?: string
1087
972
  }
1088
973
  ```
1089
974
 
1090
- #### `RadioGroupProps`
975
+ #### `ToastProps`
1091
976
 
1092
- Props for the RadioGroup component.
977
+ Props for the Toast/notification component.
1093
978
 
1094
979
  ```typescript
1095
- interface RadioGroupProps<T = string> extends BaseProps {
980
+ interface ToastProps extends HTMLElementProps {
1096
981
  /**
1097
- * Radio options.
982
+ * Toast content.
1098
983
  */
1099
- options: RadioOption<T>[]
984
+ children?: Children
1100
985
  /**
1101
- * Current value.
986
+ * Toast title.
1102
987
  */
1103
- value?: T
988
+ title?: string
1104
989
  /**
1105
- * Change handler.
990
+ * Toast description.
1106
991
  */
1107
- onChange?: (value: T) => void
992
+ description?: string
1108
993
  /**
1109
- * Radio size.
994
+ * Toast status/type.
1110
995
  */
1111
- size?: Size
996
+ status?: ColorVariant
1112
997
  /**
1113
- * Group label.
998
+ * Duration in milliseconds (0 for persistent).
1114
999
  */
1115
- label?: string
1000
+ duration?: number
1116
1001
  /**
1117
- * Shared `name` attribute for the group's radio inputs (used for native
1118
- * form submission). When omitted, a unique per-instance name is generated
1119
- * so separate groups never merge — the visible `label` is deliberately
1120
- * NOT used as the name, because two groups with the same label (e.g. two
1121
- * "Size" pickers) would otherwise form ONE native radio group and
1122
- * deselect each other.
1002
+ * Whether the toast is dismissible.
1123
1003
  */
1124
- name?: string
1004
+ dismissible?: boolean
1125
1005
  /**
1126
- * Layout direction.
1006
+ * Called when dismissed.
1127
1007
  */
1128
- direction?: 'horizontal' | 'vertical'
1008
+ onDismiss?: () => void
1129
1009
  /**
1130
- * Error message.
1010
+ * Toast position.
1131
1011
  */
1132
- error?: string
1012
+ position?: 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left'
1013
+ /**
1014
+ * Accessible label for the close button.
1015
+ * @default 'Close'
1016
+ */
1017
+ closeLabel?: string
1133
1018
  }
1134
1019
  ```
1135
1020
 
1136
- #### `RadioOption`
1021
+ #### `TabItem`
1137
1022
 
1138
- A single option in a RadioGroup.
1023
+ A single tab in a Tabs component.
1139
1024
 
1140
1025
  ```typescript
1141
- interface RadioOption<T = string> {
1026
+ interface TabItem<T = string> {
1142
1027
  /**
1143
- * Option value.
1028
+ * Tab value/id.
1144
1029
  */
1145
1030
  value: T
1146
1031
  /**
1147
- * Display label.
1032
+ * Tab label.
1148
1033
  */
1149
1034
  label: Children
1150
1035
  /**
1151
- * Whether the option is disabled.
1036
+ * Tab content.
1037
+ */
1038
+ content?: Children
1039
+ /**
1040
+ * Whether the tab is disabled.
1152
1041
  */
1153
1042
  disabled?: boolean
1043
+ /**
1044
+ * Icon to display.
1045
+ */
1046
+ icon?: Children
1154
1047
  }
1155
1048
  ```
1156
1049
 
1157
- #### `ResponsiveAppShellContentProps`
1158
-
1159
- Props for the {@link ResponsiveAppShellContent} sub-component.
1160
-
1161
- ```typescript
1162
- interface ResponsiveAppShellContentProps {
1163
- /** The routed page content — typically an `<Outlet />`. */
1164
- children: ReactNode
1165
- /** Extra classes on the `<main>`. */
1166
- className?: string
1167
- /** Inline styles on the `<main>` (rarely needed — layout is owned). */
1168
- style?: React.CSSProperties
1169
- /** `data-mol-id` override. Default: `'shell-content'`. */
1170
- dataMolId?: string
1171
- /** `data-testid` override. */
1172
- testId?: string
1173
- }
1174
- ```
1175
-
1176
- #### `ResponsiveAppShellDrawerProps`
1050
+ #### `TabsProps`
1177
1051
 
1178
- Props for the {@link ResponsiveAppShellDrawer} sub-component.
1052
+ Props for the Tabs component (switchable tabbed content panels).
1179
1053
 
1180
1054
  ```typescript
1181
- interface ResponsiveAppShellDrawerProps {
1055
+ interface TabsProps<T = string> extends BaseProps {
1182
1056
  /**
1183
- * Nav content — the links, same as (or adapted from) the Sidebar's. Only
1184
- * mounted while the drawer is open on a below-breakpoint viewport.
1057
+ * Tab items.
1185
1058
  */
1186
- children: ReactNode
1059
+ items: TabItem<T>[]
1187
1060
  /**
1188
- * Header row content (typically the brand), rendered next to the close
1189
- * button.
1061
+ * Current active tab.
1190
1062
  */
1191
- header?: ReactNode
1063
+ value?: T
1192
1064
  /**
1193
- * Accessible name for the dialog and its `<nav>` landmark. Defaults to the
1194
- * `appShell.primaryNav` translation (English fallback `"Primary
1195
- * navigation"`).
1065
+ * Default active tab.
1196
1066
  */
1197
- navLabel?: string
1198
- /** Below-nav content (user card, sign-out), after the `<nav>`. */
1199
- footer?: ReactNode
1200
- /** Whether the panel shows a close (X) button. Default: `true`. */
1201
- showCloseButton?: boolean
1202
- /** Extra classes on the dialog panel. */
1203
- className?: string
1204
- /** `data-mol-id` override for the panel. Default: `'shell-drawer'`. */
1205
- dataMolId?: string
1206
- /** `data-mol-id` override for the close button. Default: `'shell-drawer-close'`. */
1207
- closeDataMolId?: string
1208
- /** `data-testid` override for the panel. */
1209
- testId?: string
1210
- }
1211
- ```
1212
-
1213
- #### `ResponsiveAppShellProps`
1214
-
1215
- Props for the {@link ResponsiveAppShell} root.
1216
-
1217
- ```typescript
1218
- interface ResponsiveAppShellProps {
1067
+ defaultValue?: T
1068
+ /**
1069
+ * Change handler.
1070
+ */
1071
+ onChange?: (value: T) => void
1219
1072
  /**
1220
- * The shell sub-components — `<ResponsiveAppShell.TopBar />`,
1221
- * `<ResponsiveAppShell.Sidebar />`, `<ResponsiveAppShell.Drawer />` and
1222
- * `<ResponsiveAppShell.Content />`.
1073
+ * Tab variant.
1223
1074
  */
1224
- children: ReactNode
1075
+ variant?: 'line' | 'enclosed' | 'soft-rounded' | 'solid-rounded'
1225
1076
  /**
1226
- * Sidebar (and drawer) width: `'sm'` (208px), `'md'` (240px, default),
1227
- * `'lg'` (256px) or an exact pixel number.
1077
+ * Tab size.
1228
1078
  */
1229
- sidebarWidth?: ShellSidebarWidth
1230
- /** Extra classes on the root flex-row container. */
1231
- className?: string
1079
+ size?: Size
1232
1080
  /**
1233
- * `data-mol-id` for the root container. Defaults to `'shell-root'`.
1081
+ * Whether tabs are fitted (take full width).
1234
1082
  */
1235
- dataMolId?: string
1083
+ fitted?: boolean
1236
1084
  }
1237
1085
  ```
1238
1086
 
1239
- #### `ResponsiveAppShellSidebarProps`
1087
+ #### `AccordionItem`
1240
1088
 
1241
- Props for the {@link ResponsiveAppShellSidebar} sub-component.
1089
+ A single item in an Accordion component.
1242
1090
 
1243
1091
  ```typescript
1244
- interface ResponsiveAppShellSidebarProps {
1092
+ interface AccordionItem<T = string> {
1245
1093
  /**
1246
- * Nav content — the links (they land inside the sidebar's `<nav>` landmark;
1247
- * pass `aria-current="page"` from the active one yourself). Typically the
1248
- * SAME element variable the Drawer receives, so only the mounted
1249
- * breakpoint's copy ever instantiates.
1094
+ * Item value/id.
1250
1095
  */
1251
- children: ReactNode
1096
+ value: T
1252
1097
  /**
1253
- * Accessible name for the sidebar's `<nav>` landmark. Defaults to the
1254
- * `appShell.primaryNav` translation (English fallback `"Primary
1255
- * navigation"`).
1098
+ * Item header/trigger.
1256
1099
  */
1257
- navLabel?: string
1100
+ header: Children
1258
1101
  /**
1259
- * Below-nav content (user card, quick action) — rendered after the `<nav>`
1260
- * in a bordered footer row, so it does not sit inside the nav landmark.
1102
+ * Item content.
1261
1103
  */
1262
- footer?: ReactNode
1263
- /** Extra classes on the `<aside>`. */
1264
- className?: string
1265
- /** `data-mol-id` override. Default: `'shell-sidebar'`. */
1266
- dataMolId?: string
1267
- /** `data-testid` override. */
1268
- testId?: string
1104
+ content: Children
1105
+ /**
1106
+ * Whether the item is disabled.
1107
+ */
1108
+ disabled?: boolean
1269
1109
  }
1270
1110
  ```
1271
1111
 
1272
- #### `ResponsiveAppShellTopBarProps`
1112
+ #### `AccordionProps`
1273
1113
 
1274
- Props for the {@link ResponsiveAppShellTopBar} sub-component.
1114
+ Props for the Accordion component.
1275
1115
 
1276
1116
  ```typescript
1277
- interface ResponsiveAppShellTopBarProps {
1117
+ interface AccordionProps<T = string> extends BaseProps {
1278
1118
  /**
1279
- * Brand/title node, rendered after the menu trigger — typically a
1280
- * `<Link to="/…">` with the app name or logo. The shell wraps it in a
1281
- * flex row; style the node itself.
1119
+ * Accordion items.
1282
1120
  */
1283
- brand?: ReactNode
1284
- /** Trailing actions — user menu, theme toggle, search, etc. */
1285
- actions?: ReactNode
1121
+ items: AccordionItem<T>[]
1286
1122
  /**
1287
- * Render the top bar only below the breakpoint (mount-conditioned, not
1288
- * CSS-hidden — no dead DOM on desktop). For apps whose desktop shell has
1289
- * no top bar (e.g. the sidebar carries everything). Default: `false`
1290
- * (top bar on every breakpoint).
1123
+ * Expanded item(s).
1124
+ */
1125
+ value?: T | T[]
1126
+ /**
1127
+ * Default expanded item(s).
1128
+ */
1129
+ defaultValue?: T | T[]
1130
+ /**
1131
+ * Change handler.
1132
+ */
1133
+ onChange?: (value: T | T[]) => void
1134
+ /**
1135
+ * Whether multiple items can be expanded.
1291
1136
  */
1292
- mobileOnly?: boolean
1293
- /** Extra classes on the `<header>`. */
1294
- className?: string
1295
- /** `data-mol-id` override. Default: `'shell-topbar'`. */
1296
- dataMolId?: string
1297
- /** `data-testid` override. */
1298
- testId?: string
1299
- }
1300
- ```
1301
-
1302
- #### `SelectElementProps`
1303
-
1304
- Base props for select elements.
1305
-
1306
- ```typescript
1307
- interface SelectElementProps extends HTMLElementProps {
1308
- name?: string
1309
- required?: boolean
1310
- autoFocus?: boolean
1311
1137
  multiple?: boolean
1312
- onChange?: ChangeEventHandler
1138
+ /**
1139
+ * Whether items can be collapsed.
1140
+ */
1141
+ collapsible?: boolean
1313
1142
  }
1314
1143
  ```
1315
1144
 
1316
- #### `SelectOption`
1145
+ #### `TableColumn`
1317
1146
 
1318
- A single option in a Select dropdown.
1147
+ Table column definition.
1319
1148
 
1320
1149
  ```typescript
1321
- interface SelectOption<T = string> {
1150
+ interface TableColumn<T> {
1322
1151
  /**
1323
- * Option value.
1152
+ * Column key (data property).
1324
1153
  */
1325
- value: T
1154
+ key: keyof T | string
1326
1155
  /**
1327
- * Display label.
1156
+ * Column header.
1328
1157
  */
1329
- label: string
1158
+ header: Children
1330
1159
  /**
1331
- * Whether the option is disabled.
1160
+ * Custom cell renderer.
1332
1161
  */
1333
- disabled?: boolean
1162
+ render?: (value: unknown, row: T, index: number) => Children
1334
1163
  /**
1335
- * Option group (for grouped selects).
1164
+ * Column width.
1336
1165
  */
1337
- group?: string
1166
+ width?: string | number
1167
+ /**
1168
+ * Whether the column is sortable.
1169
+ */
1170
+ sortable?: boolean
1171
+ /**
1172
+ * Text alignment.
1173
+ */
1174
+ align?: 'left' | 'center' | 'right'
1338
1175
  }
1339
1176
  ```
1340
1177
 
1341
- #### `SelectProps`
1178
+ #### `TableProps`
1342
1179
 
1343
- Props for the Select dropdown component (single or multi-select).
1180
+ Props for the Table component.
1344
1181
 
1345
1182
  ```typescript
1346
- interface SelectProps<T = string> extends SelectElementProps {
1183
+ interface TableProps<T> extends HTMLElementProps {
1347
1184
  /**
1348
- * Select options.
1185
+ * Table data.
1349
1186
  */
1350
- options: SelectOption<T>[]
1187
+ data: T[]
1351
1188
  /**
1352
- * Current value.
1189
+ * Column definitions.
1353
1190
  */
1354
- value?: T
1191
+ columns: TableColumn<T>[]
1355
1192
  /**
1356
- * Change handler (with typed value).
1193
+ * Row key extractor.
1357
1194
  */
1358
- onValueChange?: (value: T) => void
1195
+ rowKey?: keyof T | ((row: T) => string | number)
1359
1196
  /**
1360
- * Select size.
1197
+ * Whether to show borders.
1198
+ */
1199
+ bordered?: boolean
1200
+ /**
1201
+ * Whether rows are striped.
1202
+ */
1203
+ striped?: boolean
1204
+ /**
1205
+ * Whether rows are hoverable.
1206
+ */
1207
+ hoverable?: boolean
1208
+ /**
1209
+ * Table size.
1361
1210
  */
1362
1211
  size?: Size
1363
1212
  /**
1364
- * Label text.
1213
+ * Empty state content.
1365
1214
  */
1366
- label?: string
1215
+ emptyContent?: Children
1367
1216
  /**
1368
- * Placeholder text.
1217
+ * Loading state.
1369
1218
  */
1370
- placeholder?: string
1219
+ loading?: boolean
1371
1220
  /**
1372
- * Error message.
1221
+ * Sort configuration.
1373
1222
  */
1374
- error?: string
1223
+ sort?: {
1224
+ key: string
1225
+ direction: 'asc' | 'desc'
1226
+ }
1375
1227
  /**
1376
- * Hint/help text.
1228
+ * Sort change handler.
1377
1229
  */
1378
- hint?: string
1230
+ onSort?: (key: string, direction: 'asc' | 'desc') => void
1379
1231
  /**
1380
- * Whether to allow clearing the selection.
1232
+ * Row click handler.
1381
1233
  */
1382
- clearable?: boolean
1234
+ onRowClick?: (row: T, index: number) => void
1383
1235
  }
1384
1236
  ```
1385
1237
 
1386
- #### `SeparatorProps`
1238
+ #### `PaginationProps`
1387
1239
 
1388
- Props for the Separator component.
1240
+ Props for the Pagination component (page navigation with current page, total, page size, and change callbacks).
1389
1241
 
1390
1242
  ```typescript
1391
- interface SeparatorProps extends BaseProps {
1243
+ interface PaginationProps extends BaseProps {
1392
1244
  /**
1393
- * Orientation of the separator.
1245
+ * Current page (1-indexed).
1394
1246
  */
1395
- orientation?: 'horizontal' | 'vertical'
1396
-
1247
+ page: number
1397
1248
  /**
1398
- * Decorative separators are purely visual.
1249
+ * Total number of pages.
1399
1250
  */
1400
- decorative?: boolean
1401
- }
1402
- ```
1403
-
1404
- #### `SidebarUserCardProps`
1405
-
1406
- Props for the {@link SidebarUserCard} component.
1407
-
1408
- Extends standard `<button>` attributes so callers can pass extra
1409
- `data-*`, `aria-*`, `style`, or event handler props onto the trigger
1410
- button without forking. The named props below cover the common
1411
- customization points.
1412
-
1413
- ```typescript
1414
- interface SidebarUserCardProps extends Omit<
1415
- ButtonHTMLAttributes<HTMLButtonElement>,
1416
- 'aria-label' | 'onClick' | 'children'
1417
- > {
1251
+ totalPages: number
1418
1252
  /**
1419
- * Panel content shown inside the drawer/modal (typically the app's
1420
- * `SettingsPanel`). It can dismiss the drawer by calling
1421
- * `usePanelClose()` — no `onClose` prop-threading required.
1253
+ * Page change handler.
1422
1254
  */
1423
- children: ReactNode
1255
+ onChange: (page: number) => void
1424
1256
  /**
1425
- * Display name override. When omitted, falls back to
1426
- * `useAuth().user?.name`, then `email`, then a guest label.
1257
+ * Number of sibling pages to show.
1427
1258
  */
1428
- name?: string
1259
+ siblings?: number
1429
1260
  /**
1430
- * Secondary line under the name (role, plan, status, etc.).
1431
- * Apps typically pass something like `t('sidebar.memberStatus', {}, { defaultValue: 'Premium Member' })`.
1432
- * When omitted and the auth user has an email, the email is shown instead.
1261
+ * Number of boundary pages to show.
1433
1262
  */
1434
- secondaryLine?: string
1435
- /** Optional avatar image URL — overrides `useAuth().user?.avatarUrl`. */
1436
- avatarUrl?: string
1437
- /** i18n key for the trigger button's aria-label. Default: `'sidebarUserCard.open'`. */
1438
- ariaLabelKey?: string
1439
- /** Fallback aria-label if the i18n key is missing. Default: `'Open account menu'`. */
1440
- ariaLabelDefault?: string
1263
+ boundaries?: number
1264
+ /**
1265
+ * Pagination size.
1266
+ */
1267
+ size?: Size
1268
+ /**
1269
+ * Whether to show first/last buttons.
1270
+ */
1271
+ showFirstLast?: boolean
1441
1272
  /**
1442
- * `data-mol-id` for the trigger button. Defaults to
1443
- * `'sidebar-user-card'`. Pass a different value (e.g. `'user-menu'`)
1444
- * to disambiguate or align with an app's existing e2e selectors.
1273
+ * Whether to show previous/next buttons.
1445
1274
  */
1446
- dataMolId?: string
1275
+ showPrevNext?: boolean
1276
+ /**
1277
+ * Accessible labels for pagination controls.
1278
+ */
1279
+ labels?: {
1280
+ nav?: string
1281
+ first?: string
1282
+ previous?: string
1283
+ next?: string
1284
+ last?: string
1285
+ goToPage?: (page: number) => string
1286
+ }
1447
1287
  }
1448
1288
  ```
1449
1289
 
@@ -1476,290 +1316,530 @@ interface SkeletonProps extends BaseProps {
1476
1316
  }
1477
1317
  ```
1478
1318
 
1479
- #### `SpacerProps`
1319
+ #### `AuthGuardProps`
1480
1320
 
1481
- Props for the Spacer layout component (adds whitespace between elements).
1321
+ Props for {@link AuthGuard}.
1322
+
1323
+ All props are optional — the default behavior (loading tag → redirect
1324
+ to `/login` → `<Outlet />`) matches the bare-bones guard apps were
1325
+ shipping locally. The props let apps customize per-call without
1326
+ forking the component.
1482
1327
 
1483
1328
  ```typescript
1484
- interface SpacerProps extends BaseProps {
1329
+ interface AuthGuardProps {
1485
1330
  /**
1486
- * Space size.
1331
+ * Element rendered while `useAuth().state.initialized` is `false`.
1332
+ * Overrides the default `<div data-mol-id="auth-guard-loading">…</div>`
1333
+ * loading tag — pass a full-page spinner or any other UI you want
1334
+ * during the auth bootstrap window.
1487
1335
  */
1488
- size?: Size | string | number
1336
+ loadingFallback?: ReactNode
1489
1337
  /**
1490
- * Whether the spacer is horizontal.
1338
+ * i18n key used for the default loading-tag text. Defaults to
1339
+ * `'common.loading'`. Ignored when `loadingFallback` is set.
1491
1340
  */
1492
- horizontal?: boolean
1493
- }
1494
- ```
1495
-
1496
- #### `SpinnerProps`
1497
-
1498
- Props for the Spinner/loading indicator component.
1499
-
1500
- ```typescript
1501
- interface SpinnerProps extends BaseProps {
1341
+ loadingKey?: string
1502
1342
  /**
1503
- * Spinner size.
1343
+ * Fallback text if the i18n key is missing. Defaults to `'Loading...'`
1344
+ * (the project-canonical ASCII glyph — Phase C of the locale
1345
+ * canonicalization plan). Ignored when `loadingFallback` is set.
1504
1346
  */
1505
- size?: Size
1347
+ loadingDefault?: string
1506
1348
  /**
1507
- * Spinner color.
1349
+ * Path to redirect to when the user is not authenticated. Defaults to
1350
+ * `'/login'`. The current `useLocation()` is preserved as `state.from`
1351
+ * for post-login restoration.
1508
1352
  */
1509
- color?: ColorVariant | string
1353
+ loginPath?: string
1510
1354
  /**
1511
- * Loading label (for accessibility).
1355
+ * Callback invoked when `isAuthenticated` transitions to `true` (or is
1356
+ * already `true` on first render). Useful for one-shot per-app
1357
+ * bootstrap effects (e.g. seeding fixture data). The caller is
1358
+ * responsible for idempotency if the auth state can flip back and
1359
+ * forth — this fires on every transition.
1512
1360
  */
1513
- label?: string
1361
+ onAuthenticated?: () => void
1514
1362
  /**
1515
- * Spinner thickness.
1363
+ * Children to render when authenticated. Defaults to `<Outlet />`,
1364
+ * which is the React Router pattern this guard is designed for.
1516
1365
  */
1517
- thickness?: number
1366
+ children?: ReactNode
1518
1367
  }
1519
1368
  ```
1520
1369
 
1521
- #### `SwitchProps`
1370
+ #### `ConfirmButtonProps`
1522
1371
 
1523
- Props for the Switch/Toggle component.
1372
+ Props for {@link ConfirmButton}.
1524
1373
 
1525
1374
  ```typescript
1526
- interface SwitchProps extends InputElementProps {
1375
+ interface ConfirmButtonProps extends Omit<
1376
+ ButtonProps,
1377
+ 'onClick' | 'children' | 'onConfirm' | keyof React.DOMAttributes<HTMLButtonElement>
1378
+ > {
1527
1379
  /**
1528
- * Switch label.
1380
+ * Fired ONLY on the confirming (second) click — i.e. when the action
1381
+ * actually commits. Errors should be handled by the caller (render an
1382
+ * inline banner); while the returned promise is pending the button stays
1383
+ * in its confirming state and ignores further clicks.
1529
1384
  */
1530
- label?: Children
1385
+ onConfirm: () => void | Promise<void>
1531
1386
  /**
1532
- * Whether the switch is on.
1387
+ * Visible label in the idle (armed-to-be-clicked) state.
1533
1388
  */
1534
- checked?: boolean
1389
+ label: React.ReactNode
1535
1390
  /**
1536
- * Switch size.
1391
+ * Visible label in the armed state — the "click again to confirm" step.
1392
+ * Defaults to a localized "Confirm?" via the i18n bond.
1537
1393
  */
1538
- size?: Size
1394
+ confirmLabel?: React.ReactNode
1539
1395
  /**
1540
- * Color when on.
1396
+ * Visible label while {@link onConfirm} is pending. Defaults to a
1397
+ * localized "Working…".
1541
1398
  */
1542
- color?: ColorVariant
1399
+ pendingLabel?: React.ReactNode
1400
+ /**
1401
+ * Seconds before the armed state auto-disarms back to idle. Low-stakes
1402
+ * actions tolerate a long window; destructive ones should keep it short.
1403
+ * `0` disables auto-disarm (not recommended — a stray click then leaves
1404
+ * the button armed forever).
1405
+ */
1406
+ disarmSeconds?: number
1407
+ /**
1408
+ * Disable the control entirely (idle and confirming states).
1409
+ */
1410
+ disabled?: boolean
1411
+ /**
1412
+ * data-mol-id for the button (all states share one element).
1413
+ */
1414
+ testId?: string
1543
1415
  }
1544
1416
  ```
1545
1417
 
1546
- #### `TabItem`
1418
+ #### `ConfirmDialogProps`
1547
1419
 
1548
- A single tab in a Tabs component.
1420
+ Props for {@link ConfirmDialog}.
1549
1421
 
1550
1422
  ```typescript
1551
- interface TabItem<T = string> {
1552
- /**
1553
- * Tab value/id.
1554
- */
1555
- value: T
1556
- /**
1557
- * Tab label.
1558
- */
1559
- label: Children
1423
+ interface ConfirmDialogProps {
1424
+ /** Whether the dialog is open. */
1425
+ open: boolean
1426
+ /** Called when the dialog should close (escape, backdrop, cancel). */
1427
+ onClose: () => void
1428
+ /** Title. */
1429
+ title: ReactNode
1430
+ /** Body / warning text. */
1431
+ description: ReactNode
1432
+ /** Confirm-button label (e.g. "Delete"). */
1433
+ confirmLabel?: ReactNode
1434
+ /** Cancel-button label. */
1435
+ cancelLabel?: ReactNode
1436
+ /** Called when the user confirms. */
1437
+ onConfirm: () => void | Promise<void>
1438
+ /** Is the confirm action destructive? Defaults to true. */
1439
+ destructive?: boolean
1440
+ /** Extra body content between description and footer. */
1441
+ children?: ReactNode
1442
+ /** Disables both buttons. Set it yourself while your `onConfirm` promise is pending — the dialog does not track it and does not auto-close. */
1443
+ loading?: boolean
1444
+ }
1445
+ ```
1446
+
1447
+ #### `IconProps`
1448
+
1449
+ Props for {@link Icon}.
1450
+
1451
+ Extends `SVGProps<SVGSVGElement>` so callers can pass any SVG / HTML
1452
+ attribute the underlying `<svg>` accepts, including `data-mol-id`,
1453
+ `aria-*`, `role`, event handlers, `style`, etc. — without the
1454
+ component needing to enumerate them.
1455
+
1456
+ ```typescript
1457
+ interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'width' | 'height' | 'viewBox' | 'fill'> {
1560
1458
  /**
1561
- * Tab content.
1459
+ * Name of the glyph to look up in the bonded icon set. Typed as
1460
+ * {@link IconName} so a typo fails the type-check instead of throwing at
1461
+ * render time; sets with extra glyphs augment `CustomIconNames` in
1462
+ * `@molecule/app-icons` to widen it.
1562
1463
  */
1563
- content?: Children
1464
+ name: IconName
1465
+ /** Width and height of the rendered SVG in pixels. Defaults to 20. */
1466
+ size?: number
1467
+ /** Class name forwarded to the root `<svg>`. */
1468
+ className?: string
1469
+ }
1470
+ ```
1471
+
1472
+ #### `LanguagePickerProps`
1473
+
1474
+ Props for {@link LanguagePicker}.
1475
+
1476
+ Extends standard `<button>` attributes so callers can pass any extra
1477
+ `data-*`, `aria-*`, event handler, or `style` prop without forking the
1478
+ component. The named props let apps customize the trigger label, icon,
1479
+ size, and modal heading without spreading attribute concerns.
1480
+
1481
+ ```typescript
1482
+ interface LanguagePickerProps extends Omit<
1483
+ ButtonHTMLAttributes<HTMLButtonElement>,
1484
+ 'aria-label' | 'onClick' | 'type' | 'children'
1485
+ > {
1486
+ /** i18n key for the trigger button label / aria-label. Defaults to `'footer.language'`. */
1487
+ labelKey?: string
1488
+ /** Fallback label if the i18n key is missing. Defaults to `'Language'`. */
1489
+ labelDefault?: string
1490
+ /** i18n key for the modal title. Defaults to `'languagePicker.modalTitle'`. */
1491
+ modalTitleKey?: string
1492
+ /** Fallback modal title if the i18n key is missing. Defaults to `'Choose language'`. */
1493
+ modalTitleDefault?: string
1494
+ /** Icon glyph to render before the current locale name. Defaults to `'globe'`. */
1495
+ icon?: IconName
1496
+ /** Pixel size for the rendered icon. Defaults to `16`. */
1497
+ iconSize?: number
1564
1498
  /**
1565
- * Whether the tab is disabled.
1499
+ * What to render inside the trigger button.
1500
+ *
1501
+ * - `'name'` — globe icon + current locale's native name (e.g. `🌐 English`).
1502
+ * This is the default; matches the molecule-dev footer pattern.
1503
+ * - `'code'` — globe icon + lowercase locale code (e.g. `🌐 en`). Useful in
1504
+ * tight chrome where the long native name (e.g. "Bahasa Indonesia") would wrap.
1505
+ * - `'icon'` — globe icon only. Useful in icon-bar headers.
1566
1506
  */
1567
- disabled?: boolean
1507
+ display?: 'name' | 'code' | 'icon'
1508
+ /** Optional className appended to the trigger button. */
1509
+ className?: string
1510
+ /** Optional render override: receives `{ open }` and replaces the default trigger. */
1511
+ renderTrigger?: (open: () => void) => ReactNode
1512
+ }
1513
+ ```
1514
+
1515
+ #### `LoadErrorBannerProps`
1516
+
1517
+ Props for {@link LoadErrorBanner}. Rest props are forwarded to the root
1518
+ `<div>`, so they are typed as its attributes.
1519
+
1520
+ ```typescript
1521
+ interface LoadErrorBannerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
1522
+ /** The primary error line (e.g. the localized "Could not load X."). */
1523
+ message: React.ReactNode
1524
+ /** Secondary line under the message (status code, hint). */
1525
+ detail?: React.ReactNode
1568
1526
  /**
1569
- * Icon to display.
1527
+ * Called when Retry is clicked. Return the promise; while pending, the
1528
+ * button is disabled and shows "Retrying…". Omit for a display-only
1529
+ * banner.
1570
1530
  */
1571
- icon?: Children
1531
+ onRetry?: () => void | Promise<void>
1532
+ /** Retry-button label. Falls back to a localized "Retry". */
1533
+ retryLabel?: React.ReactNode
1534
+ /** `data-mol-id` for the retry button (default `load-error-retry`). */
1535
+ retryMolId?: string
1536
+ /** Extra content between message and retry row (e.g. an error code). */
1537
+ children?: React.ReactNode
1538
+ }
1539
+ ```
1540
+
1541
+ #### `PanelCloseProviderProps`
1542
+
1543
+ Props for {@link PanelCloseProvider}.
1544
+
1545
+ ```typescript
1546
+ interface PanelCloseProviderProps {
1547
+ /** Callback that dismisses the enclosing drawer/modal. */
1548
+ close: () => void
1549
+ /** Panel content that may call {@link usePanelClose}. */
1550
+ children: ReactNode
1572
1551
  }
1573
1552
  ```
1574
1553
 
1575
- #### `TableColumn`
1554
+ #### `ProgressProps`
1576
1555
 
1577
- Table column definition.
1556
+ Props for the Progress component.
1578
1557
 
1579
1558
  ```typescript
1580
- interface TableColumn<T> {
1559
+ interface ProgressProps extends BaseProps {
1581
1560
  /**
1582
- * Column key (data property).
1561
+ * Progress value (0-100).
1583
1562
  */
1584
- key: keyof T | string
1563
+ value: number
1564
+
1585
1565
  /**
1586
- * Column header.
1566
+ * Maximum value.
1587
1567
  */
1588
- header: Children
1568
+ max?: number
1569
+
1589
1570
  /**
1590
- * Custom cell renderer.
1571
+ * Progress size.
1591
1572
  */
1592
- render?: (value: unknown, row: T, index: number) => Children
1573
+ size?: Size
1574
+
1593
1575
  /**
1594
- * Column width.
1576
+ * Progress color.
1595
1577
  */
1596
- width?: string | number
1578
+ color?: ColorVariant
1579
+
1597
1580
  /**
1598
- * Whether the column is sortable.
1581
+ * Whether to show the value label.
1599
1582
  */
1600
- sortable?: boolean
1583
+ showValue?: boolean
1584
+
1601
1585
  /**
1602
- * Text alignment.
1586
+ * Accessible label.
1603
1587
  */
1604
- align?: 'left' | 'center' | 'right'
1588
+ label?: string
1589
+
1590
+ /**
1591
+ * Whether the progress is indeterminate.
1592
+ */
1593
+ indeterminate?: boolean
1605
1594
  }
1606
1595
  ```
1607
1596
 
1608
- #### `TableProps`
1597
+ #### `PromptDialogProps`
1609
1598
 
1610
- Props for the Table component.
1599
+ Props for {@link PromptDialog}.
1611
1600
 
1612
1601
  ```typescript
1613
- interface TableProps<T> extends HTMLElementProps {
1614
- /**
1615
- * Table data.
1616
- */
1617
- data: T[]
1618
- /**
1619
- * Column definitions.
1620
- */
1621
- columns: TableColumn<T>[]
1622
- /**
1623
- * Row key extractor.
1624
- */
1625
- rowKey?: keyof T | ((row: T) => string | number)
1626
- /**
1627
- * Whether to show borders.
1628
- */
1629
- bordered?: boolean
1630
- /**
1631
- * Whether rows are striped.
1632
- */
1633
- striped?: boolean
1634
- /**
1635
- * Whether rows are hoverable.
1636
- */
1637
- hoverable?: boolean
1602
+ interface PromptDialogProps {
1603
+ /** Whether the dialog is open. */
1604
+ open: boolean
1605
+ /** Called when the dialog should close (escape, backdrop, cancel, or a fulfilled {@link PromptDialogProps.onSubmit}). */
1606
+ onClose: () => void
1607
+ /** Dialog heading. */
1608
+ title: React.ReactNode
1609
+ /** Explanatory line under the title. */
1610
+ description?: React.ReactNode
1611
+ /** Input placeholder. */
1612
+ placeholder?: string
1613
+ /** Value the input starts from every time the dialog opens. */
1614
+ initialValue?: string
1638
1615
  /**
1639
- * Table size.
1616
+ * Called with the entered value on confirm. Resolve to close the dialog;
1617
+ * reject or throw to keep it open (show the error via {@link PromptDialogProps.children}).
1640
1618
  */
1641
- size?: Size
1619
+ onSubmit: (value: string) => void | Promise<void>
1620
+ /** Confirm-button label. Falls back to a localized "Confirm". */
1621
+ confirmLabel?: React.ReactNode
1622
+ /** Cancel-button label. Falls back to a localized "Cancel". */
1623
+ cancelLabel?: React.ReactNode
1624
+ /** Render the confirm button in the error color (e.g. an irreversible reset). */
1625
+ destructive?: boolean
1626
+ /** `data-mol-id` for the text input. */
1627
+ inputMolId?: string
1628
+ /** `data-mol-id` for the confirm button. */
1629
+ confirmMolId?: string
1630
+ /** `data-mol-id` for the cancel button. */
1631
+ cancelMolId?: string
1632
+ /** Extra body content under the input (error banners, hints). */
1633
+ children?: React.ReactNode
1634
+ }
1635
+ ```
1636
+
1637
+ #### `ResponsiveAppShellProps`
1638
+
1639
+ Props for the {@link ResponsiveAppShell} root.
1640
+
1641
+ ```typescript
1642
+ interface ResponsiveAppShellProps {
1642
1643
  /**
1643
- * Empty state content.
1644
+ * The shell sub-components — `<ResponsiveAppShell.TopBar />`,
1645
+ * `<ResponsiveAppShell.Sidebar />`, `<ResponsiveAppShell.Drawer />` and
1646
+ * `<ResponsiveAppShell.Content />`.
1644
1647
  */
1645
- emptyContent?: Children
1648
+ children: ReactNode
1646
1649
  /**
1647
- * Loading state.
1650
+ * Sidebar (and drawer) width: `'sm'` (208px), `'md'` (240px, default),
1651
+ * `'lg'` (256px) or an exact pixel number.
1648
1652
  */
1649
- loading?: boolean
1653
+ sidebarWidth?: ShellSidebarWidth
1654
+ /** Extra classes on the root flex-row container. */
1655
+ className?: string
1650
1656
  /**
1651
- * Sort configuration.
1657
+ * `data-mol-id` for the root container. Defaults to `'shell-root'`.
1652
1658
  */
1653
- sort?: {
1654
- key: string
1655
- direction: 'asc' | 'desc'
1656
- }
1659
+ dataMolId?: string
1660
+ }
1661
+ ```
1662
+
1663
+ #### `ResponsiveAppShellTopBarProps`
1664
+
1665
+ Props for the {@link ResponsiveAppShellTopBar} sub-component.
1666
+
1667
+ ```typescript
1668
+ interface ResponsiveAppShellTopBarProps {
1657
1669
  /**
1658
- * Sort change handler.
1670
+ * Brand/title node, rendered after the menu trigger — typically a
1671
+ * `<Link to="/…">` with the app name or logo. The shell wraps it in a
1672
+ * flex row; style the node itself.
1659
1673
  */
1660
- onSort?: (key: string, direction: 'asc' | 'desc') => void
1674
+ brand?: ReactNode
1675
+ /** Trailing actions — user menu, theme toggle, search, etc. */
1676
+ actions?: ReactNode
1661
1677
  /**
1662
- * Row click handler.
1678
+ * Render the top bar only below the breakpoint (mount-conditioned, not
1679
+ * CSS-hidden — no dead DOM on desktop). For apps whose desktop shell has
1680
+ * no top bar (e.g. the sidebar carries everything). Default: `false`
1681
+ * (top bar on every breakpoint).
1663
1682
  */
1664
- onRowClick?: (row: T, index: number) => void
1683
+ mobileOnly?: boolean
1684
+ /** Extra classes on the `<header>`. */
1685
+ className?: string
1686
+ /** `data-mol-id` override. Default: `'shell-topbar'`. */
1687
+ dataMolId?: string
1688
+ /** `data-testid` override. */
1689
+ testId?: string
1665
1690
  }
1666
1691
  ```
1667
1692
 
1668
- #### `TabsProps`
1693
+ #### `ResponsiveAppShellSidebarProps`
1669
1694
 
1670
- Props for the Tabs component (switchable tabbed content panels).
1695
+ Props for the {@link ResponsiveAppShellSidebar} sub-component.
1671
1696
 
1672
1697
  ```typescript
1673
- interface TabsProps<T = string> extends BaseProps {
1674
- /**
1675
- * Tab items.
1676
- */
1677
- items: TabItem<T>[]
1698
+ interface ResponsiveAppShellSidebarProps {
1678
1699
  /**
1679
- * Current active tab.
1700
+ * Nav content — the links (they land inside the sidebar's `<nav>` landmark;
1701
+ * pass `aria-current="page"` from the active one yourself). Typically the
1702
+ * SAME element variable the Drawer receives, so only the mounted
1703
+ * breakpoint's copy ever instantiates.
1680
1704
  */
1681
- value?: T
1705
+ children: ReactNode
1682
1706
  /**
1683
- * Default active tab.
1707
+ * Accessible name for the sidebar's `<nav>` landmark. Defaults to the
1708
+ * `appShell.primaryNav` translation (English fallback `"Primary
1709
+ * navigation"`).
1684
1710
  */
1685
- defaultValue?: T
1711
+ navLabel?: string
1686
1712
  /**
1687
- * Change handler.
1713
+ * Below-nav content (user card, quick action) — rendered after the `<nav>`
1714
+ * in a bordered footer row, so it does not sit inside the nav landmark.
1688
1715
  */
1689
- onChange?: (value: T) => void
1716
+ footer?: ReactNode
1717
+ /** Extra classes on the `<aside>`. */
1718
+ className?: string
1719
+ /** `data-mol-id` override. Default: `'shell-sidebar'`. */
1720
+ dataMolId?: string
1721
+ /** `data-testid` override. */
1722
+ testId?: string
1723
+ }
1724
+ ```
1725
+
1726
+ #### `ResponsiveAppShellDrawerProps`
1727
+
1728
+ Props for the {@link ResponsiveAppShellDrawer} sub-component.
1729
+
1730
+ ```typescript
1731
+ interface ResponsiveAppShellDrawerProps {
1690
1732
  /**
1691
- * Tab variant.
1733
+ * Nav content — the links, same as (or adapted from) the Sidebar's. Only
1734
+ * mounted while the drawer is open on a below-breakpoint viewport.
1692
1735
  */
1693
- variant?: 'line' | 'enclosed' | 'soft-rounded' | 'solid-rounded'
1736
+ children: ReactNode
1694
1737
  /**
1695
- * Tab size.
1738
+ * Header row content (typically the brand), rendered next to the close
1739
+ * button.
1696
1740
  */
1697
- size?: Size
1741
+ header?: ReactNode
1698
1742
  /**
1699
- * Whether tabs are fitted (take full width).
1743
+ * Accessible name for the dialog and its `<nav>` landmark. Defaults to the
1744
+ * `appShell.primaryNav` translation (English fallback `"Primary
1745
+ * navigation"`).
1700
1746
  */
1701
- fitted?: boolean
1747
+ navLabel?: string
1748
+ /** Below-nav content (user card, sign-out), after the `<nav>`. */
1749
+ footer?: ReactNode
1750
+ /** Whether the panel shows a close (X) button. Default: `true`. */
1751
+ showCloseButton?: boolean
1752
+ /** Extra classes on the dialog panel. */
1753
+ className?: string
1754
+ /** `data-mol-id` override for the panel. Default: `'shell-drawer'`. */
1755
+ dataMolId?: string
1756
+ /** `data-mol-id` override for the close button. Default: `'shell-drawer-close'`. */
1757
+ closeDataMolId?: string
1758
+ /** `data-testid` override for the panel. */
1759
+ testId?: string
1702
1760
  }
1703
1761
  ```
1704
1762
 
1705
- #### `TextareaElementProps`
1763
+ #### `ResponsiveAppShellContentProps`
1706
1764
 
1707
- Base props for textarea elements.
1765
+ Props for the {@link ResponsiveAppShellContent} sub-component.
1708
1766
 
1709
1767
  ```typescript
1710
- interface TextareaElementProps extends HTMLElementProps {
1711
- name?: string
1712
- value?: string
1713
- defaultValue?: string
1714
- placeholder?: string
1715
- required?: boolean
1716
- readOnly?: boolean
1717
- autoFocus?: boolean
1718
- rows?: number
1719
- cols?: number
1720
- maxLength?: number
1721
- minLength?: number
1722
- wrap?: 'hard' | 'soft' | 'off'
1723
- onChange?: ChangeEventHandler
1724
- onInput?: FormEventHandler
1768
+ interface ResponsiveAppShellContentProps {
1769
+ /** The routed page content — typically an `<Outlet />`. */
1770
+ children: ReactNode
1771
+ /** Extra classes on the `<main>`. */
1772
+ className?: string
1773
+ /** Inline styles on the `<main>` (rarely needed — layout is owned). */
1774
+ style?: React.CSSProperties
1775
+ /** `data-mol-id` override. Default: `'shell-content'`. */
1776
+ dataMolId?: string
1777
+ /** `data-testid` override. */
1778
+ testId?: string
1725
1779
  }
1726
1780
  ```
1727
1781
 
1728
- #### `TextareaProps`
1782
+ #### `SeparatorProps`
1729
1783
 
1730
- Props for the Textarea component.
1784
+ Props for the Separator component.
1731
1785
 
1732
1786
  ```typescript
1733
- interface TextareaProps extends TextareaElementProps {
1734
- /**
1735
- * Text size tier (see {@link TextareaClassOptions.size}) — pass the same
1736
- * `size` as a neighboring Input for identical font sizes.
1737
- */
1738
- size?: Size
1787
+ interface SeparatorProps extends BaseProps {
1739
1788
  /**
1740
- * Label text.
1789
+ * Orientation of the separator.
1741
1790
  */
1742
- label?: string
1791
+ orientation?: 'horizontal' | 'vertical'
1792
+
1743
1793
  /**
1744
- * Error message.
1794
+ * Decorative separators are purely visual.
1745
1795
  */
1746
- error?: string
1796
+ decorative?: boolean
1797
+ }
1798
+ ```
1799
+
1800
+ #### `SidebarUserCardProps`
1801
+
1802
+ Props for the {@link SidebarUserCard} component.
1803
+
1804
+ Extends standard `<button>` attributes so callers can pass extra
1805
+ `data-*`, `aria-*`, `style`, or event handler props onto the trigger
1806
+ button without forking. The named props below cover the common
1807
+ customization points.
1808
+
1809
+ ```typescript
1810
+ interface SidebarUserCardProps extends Omit<
1811
+ ButtonHTMLAttributes<HTMLButtonElement>,
1812
+ 'aria-label' | 'onClick' | 'children'
1813
+ > {
1747
1814
  /**
1748
- * Hint/help text.
1815
+ * Panel content shown inside the drawer/modal (typically the app's
1816
+ * `SettingsPanel`). It can dismiss the drawer by calling
1817
+ * `usePanelClose()` — no `onClose` prop-threading required.
1749
1818
  */
1750
- hint?: string
1819
+ children: ReactNode
1751
1820
  /**
1752
- * Whether the textarea auto-resizes.
1821
+ * Display name override. When omitted, falls back to
1822
+ * `useAuth().user?.name`, then `email`, then a guest label.
1753
1823
  */
1754
- autoResize?: boolean
1824
+ name?: string
1755
1825
  /**
1756
- * Minimum number of rows.
1826
+ * Secondary line under the name (role, plan, status, etc.).
1827
+ * Apps typically pass something like `t('sidebar.memberStatus', {}, { defaultValue: 'Premium Member' })`.
1828
+ * When omitted and the auth user has an email, the email is shown instead.
1757
1829
  */
1758
- minRows?: number
1830
+ secondaryLine?: string
1831
+ /** Optional avatar image URL — overrides `useAuth().user?.avatarUrl`. */
1832
+ avatarUrl?: string
1833
+ /** i18n key for the trigger button's aria-label. Default: `'sidebarUserCard.open'`. */
1834
+ ariaLabelKey?: string
1835
+ /** Fallback aria-label if the i18n key is missing. Default: `'Open account menu'`. */
1836
+ ariaLabelDefault?: string
1759
1837
  /**
1760
- * Maximum number of rows.
1838
+ * `data-mol-id` for the trigger button. Defaults to
1839
+ * `'sidebar-user-card'`. Pass a different value (e.g. `'user-menu'`)
1840
+ * to disambiguate or align with an app's existing e2e selectors.
1761
1841
  */
1762
- maxRows?: number
1842
+ dataMolId?: string
1763
1843
  }
1764
1844
  ```
1765
1845
 
@@ -1790,101 +1870,58 @@ interface ThemeToggleProps extends Omit<
1790
1870
  }
1791
1871
  ```
1792
1872
 
1793
- #### `ToastProps`
1794
-
1795
- Props for the Toast/notification component.
1796
-
1797
- ```typescript
1798
- interface ToastProps extends HTMLElementProps {
1799
- /**
1800
- * Toast content.
1801
- */
1802
- children?: Children
1803
- /**
1804
- * Toast title.
1805
- */
1806
- title?: string
1807
- /**
1808
- * Toast description.
1809
- */
1810
- description?: string
1811
- /**
1812
- * Toast status/type.
1813
- */
1814
- status?: ColorVariant
1815
- /**
1816
- * Duration in milliseconds (0 for persistent).
1817
- */
1818
- duration?: number
1819
- /**
1820
- * Whether the toast is dismissible.
1821
- */
1822
- dismissible?: boolean
1823
- /**
1824
- * Called when dismissed.
1825
- */
1826
- onDismiss?: () => void
1827
- /**
1828
- * Toast position.
1829
- */
1830
- position?: 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left'
1831
- /**
1832
- * Accessible label for the close button.
1833
- * @default 'Close'
1834
- */
1835
- closeLabel?: string
1836
- }
1837
- ```
1873
+ #### `UserMenuProps`
1838
1874
 
1839
- #### `TooltipProps`
1875
+ Props for {@link UserMenu}.
1840
1876
 
1841
- Props for the Tooltip component (hover/focus popover with informational text).
1877
+ The inner trigger is a Molecule `<Button>` whose own prop set
1878
+ conflicts with raw `ButtonHTMLAttributes` (color, value, size enums),
1879
+ so this component exposes a curated set of customization points
1880
+ instead of extending HTML attributes. For one-off extra attributes,
1881
+ pass them via `dataMolId` / `className` / `style` props.
1842
1882
 
1843
1883
  ```typescript
1844
- interface TooltipProps extends HTMLElementProps {
1845
- /**
1846
- * Tooltip content.
1847
- */
1848
- content: Children
1884
+ interface UserMenuProps {
1849
1885
  /**
1850
- * Element that triggers the tooltip.
1886
+ * Panel content shown inside the drawer/modal (typically the app's
1887
+ * `SettingsPanel`). It can dismiss the drawer by calling
1888
+ * `usePanelClose()` — no `onClose` prop-threading required.
1851
1889
  */
1852
- children: Children
1890
+ children: ReactNode
1853
1891
  /**
1854
- * Tooltip placement.
1892
+ * i18n key for the trigger button's aria-label. Defaults to
1893
+ * `'userMenu.open'`. Apps whose existing locales use a different key
1894
+ * (e.g. `'userMenu.openButton'`) can override.
1855
1895
  */
1856
- placement?: TooltipPlacement
1896
+ ariaLabelKey?: string
1897
+ /** Fallback aria-label if the i18n key is missing. Defaults to `"Open user menu"`. */
1898
+ ariaLabelDefault?: string
1899
+ /** Icon name for the trigger button. Defaults to `'user'`. */
1900
+ triggerIcon?: IconName
1901
+ /** Pixel size for the trigger icon. Defaults to 20. */
1902
+ triggerIconSize?: number
1857
1903
  /**
1858
- * Delay before showing (ms).
1904
+ * `data-mol-id` for the trigger button. Defaults to `'user-menu'`.
1905
+ * Pass an explicit value to disambiguate when the same page mounts
1906
+ * more than one UserMenu.
1859
1907
  */
1860
- delay?: number
1908
+ dataMolId?: string
1909
+ /** Extra className composed onto the trigger button. */
1910
+ className?: string
1911
+ /** Whether the trigger button is disabled. */
1912
+ disabled?: boolean
1861
1913
  /**
1862
- * Whether the tooltip has an arrow.
1914
+ * Override the trigger button's click handler. When provided, called
1915
+ * instead of opening the panel — hosts use this to intercept the click
1916
+ * (e.g. to open an auth modal for guest users).
1863
1917
  */
1864
- hasArrow?: boolean
1865
- }
1866
- ```
1867
-
1868
- #### `UserMenuPopoverPanelProps`
1869
-
1870
- Props for {@link UserMenuPopoverPanel}.
1871
-
1872
- ```typescript
1873
- interface UserMenuPopoverPanelProps {
1918
+ onClick?: () => void
1874
1919
  /**
1875
- * Panel body — typically a set of `<Link>` nav items and a
1876
- * `<UserMenuPopoverSignOut />`. Rendered inside a `<nav>` below the
1877
- * built-in identity header.
1920
+ * Which side of the viewport the panel opens from. Defaults to
1921
+ * `'right'`. Apps whose sidebar trigger sits on the left should pass
1922
+ * `'left'` so the panel opens adjacent to the trigger.
1878
1923
  */
1879
- children: ReactNode
1880
- /** Extra className composed onto the absolute-positioned panel. */
1881
- className?: string
1882
- /** i18n key for the panel's aria-label. Default: `'userMenu.panelLabel'`. */
1883
- ariaLabelKey?: string
1884
- /** Fallback aria-label if the i18n key is missing. Default: `'Account menu'`. */
1885
- ariaLabelDefault?: string
1886
- /** `data-mol-id` for the panel. Default: `'user-menu-panel'`. */
1887
- dataMolId?: string
1924
+ side?: 'left' | 'right'
1888
1925
  }
1889
1926
  ```
1890
1927
 
@@ -1909,23 +1946,6 @@ interface UserMenuPopoverProps {
1909
1946
  }
1910
1947
  ```
1911
1948
 
1912
- #### `UserMenuPopoverSignOutProps`
1913
-
1914
- Props for {@link UserMenuPopoverSignOut}.
1915
-
1916
- ```typescript
1917
- interface UserMenuPopoverSignOutProps {
1918
- /** i18n key for the button label. Default: `'userMenu.signOut'`. */
1919
- labelKey?: string
1920
- /** Fallback label if the i18n key is missing. Default: `'Sign out'`. */
1921
- labelDefault?: string
1922
- /** `data-mol-id` for the button. Default: `'user-menu-sign-out'`. */
1923
- dataMolId?: string
1924
- /** Extra className composed onto the button. */
1925
- className?: string
1926
- }
1927
- ```
1928
-
1929
1949
  #### `UserMenuPopoverTriggerProps`
1930
1950
 
1931
1951
  Props for {@link UserMenuPopoverTrigger}.
@@ -1933,89 +1953,58 @@ Props for {@link UserMenuPopoverTrigger}.
1933
1953
  ```typescript
1934
1954
  interface UserMenuPopoverTriggerProps {
1935
1955
  /** i18n key for the trigger's aria-label. Default: `'userMenu.open'`. */
1936
- ariaLabelKey?: string
1937
- /** Fallback aria-label if the i18n key is missing. Default: `'Open user menu'`. */
1938
- ariaLabelDefault?: string
1939
- /** `data-mol-id` for the trigger button. Default: `'user-menu'`. */
1940
- dataMolId?: string
1941
- /** Extra className composed onto the trigger button. */
1942
- className?: string
1943
- }
1944
- ```
1945
-
1946
- #### `UserMenuProps`
1947
-
1948
- Props for {@link UserMenu}.
1949
-
1950
- The inner trigger is a Molecule `<Button>` whose own prop set
1951
- conflicts with raw `ButtonHTMLAttributes` (color, value, size enums),
1952
- so this component exposes a curated set of customization points
1953
- instead of extending HTML attributes. For one-off extra attributes,
1954
- pass them via `dataMolId` / `className` / `style` props.
1955
-
1956
- ```typescript
1957
- interface UserMenuProps {
1958
- /**
1959
- * Panel content shown inside the drawer/modal (typically the app's
1960
- * `SettingsPanel`). It can dismiss the drawer by calling
1961
- * `usePanelClose()` — no `onClose` prop-threading required.
1962
- */
1963
- children: ReactNode
1964
- /**
1965
- * i18n key for the trigger button's aria-label. Defaults to
1966
- * `'userMenu.open'`. Apps whose existing locales use a different key
1967
- * (e.g. `'userMenu.openButton'`) can override.
1968
- */
1969
- ariaLabelKey?: string
1970
- /** Fallback aria-label if the i18n key is missing. Defaults to `"Open user menu"`. */
1971
- ariaLabelDefault?: string
1972
- /** Icon name for the trigger button. Defaults to `'user'`. */
1973
- triggerIcon?: IconName
1974
- /** Pixel size for the trigger icon. Defaults to 20. */
1975
- triggerIconSize?: number
1976
- /**
1977
- * `data-mol-id` for the trigger button. Defaults to `'user-menu'`.
1978
- * Pass an explicit value to disambiguate when the same page mounts
1979
- * more than one UserMenu.
1980
- */
1956
+ ariaLabelKey?: string
1957
+ /** Fallback aria-label if the i18n key is missing. Default: `'Open user menu'`. */
1958
+ ariaLabelDefault?: string
1959
+ /** `data-mol-id` for the trigger button. Default: `'user-menu'`. */
1981
1960
  dataMolId?: string
1982
1961
  /** Extra className composed onto the trigger button. */
1983
1962
  className?: string
1984
- /** Whether the trigger button is disabled. */
1985
- disabled?: boolean
1986
- /**
1987
- * Override the trigger button's click handler. When provided, called
1988
- * instead of opening the panel — hosts use this to intercept the click
1989
- * (e.g. to open an auth modal for guest users).
1990
- */
1991
- onClick?: () => void
1992
- /**
1993
- * Which side of the viewport the panel opens from. Defaults to
1994
- * `'right'`. Apps whose sidebar trigger sits on the left should pass
1995
- * `'left'` so the panel opens adjacent to the trigger.
1996
- */
1997
- side?: 'left' | 'right'
1998
1963
  }
1999
1964
  ```
2000
1965
 
2001
- ### Types
2002
-
2003
- #### `ButtonVariant`
1966
+ #### `UserMenuPopoverPanelProps`
2004
1967
 
2005
- Button visual variant styles.
1968
+ Props for {@link UserMenuPopoverPanel}.
2006
1969
 
2007
1970
  ```typescript
2008
- type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link'
1971
+ interface UserMenuPopoverPanelProps {
1972
+ /**
1973
+ * Panel body — typically a set of `<Link>` nav items and a
1974
+ * `<UserMenuPopoverSignOut />`. Rendered inside a `<nav>` below the
1975
+ * built-in identity header.
1976
+ */
1977
+ children: ReactNode
1978
+ /** Extra className composed onto the absolute-positioned panel. */
1979
+ className?: string
1980
+ /** i18n key for the panel's aria-label. Default: `'userMenu.panelLabel'`. */
1981
+ ariaLabelKey?: string
1982
+ /** Fallback aria-label if the i18n key is missing. Default: `'Account menu'`. */
1983
+ ariaLabelDefault?: string
1984
+ /** `data-mol-id` for the panel. Default: `'user-menu-panel'`. */
1985
+ dataMolId?: string
1986
+ }
2009
1987
  ```
2010
1988
 
2011
- #### `ChangeEventHandler`
1989
+ #### `UserMenuPopoverSignOutProps`
2012
1990
 
2013
- Framework-agnostic change event handler.
1991
+ Props for {@link UserMenuPopoverSignOut}.
2014
1992
 
2015
1993
  ```typescript
2016
- type ChangeEventHandler = EventHandler<Event>
1994
+ interface UserMenuPopoverSignOutProps {
1995
+ /** i18n key for the button label. Default: `'userMenu.signOut'`. */
1996
+ labelKey?: string
1997
+ /** Fallback label if the i18n key is missing. Default: `'Sign out'`. */
1998
+ labelDefault?: string
1999
+ /** `data-mol-id` for the button. Default: `'user-menu-sign-out'`. */
2000
+ dataMolId?: string
2001
+ /** Extra className composed onto the button. */
2002
+ className?: string
2003
+ }
2017
2004
  ```
2018
2005
 
2006
+ ### Types
2007
+
2019
2008
  #### `Children`
2020
2009
 
2021
2010
  Framework-agnostic child content.
@@ -2025,20 +2014,30 @@ Use `unknown` to allow any framework's node type (ReactNode, VNode, etc.).
2025
2014
  type Children = unknown
2026
2015
  ```
2027
2016
 
2028
- #### `ColorVariant`
2017
+ #### `EventHandler`
2029
2018
 
2030
- Semantic color variants used across components for status indication.
2019
+ Framework-agnostic event handler.
2031
2020
 
2032
2021
  ```typescript
2033
- type ColorVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info'
2022
+ type EventHandler<E = Event> = (event: E) => void
2034
2023
  ```
2035
2024
 
2036
- #### `EventHandler`
2025
+ - `event` — The DOM event object.
2037
2026
 
2038
- Framework-agnostic event handler.
2027
+ #### `MouseEventHandler`
2028
+
2029
+ Framework-agnostic mouse event handler.
2039
2030
 
2040
2031
  ```typescript
2041
- type EventHandler<E = Event> = (event: E) => void
2032
+ type MouseEventHandler = EventHandler<MouseEvent>
2033
+ ```
2034
+
2035
+ #### `KeyboardEventHandler`
2036
+
2037
+ Framework-agnostic keyboard event handler.
2038
+
2039
+ ```typescript
2040
+ type KeyboardEventHandler = EventHandler<KeyboardEvent>
2042
2041
  ```
2043
2042
 
2044
2043
  #### `FocusEventHandler`
@@ -2049,6 +2048,14 @@ Framework-agnostic focus event handler.
2049
2048
  type FocusEventHandler = EventHandler<FocusEvent>
2050
2049
  ```
2051
2050
 
2051
+ #### `ChangeEventHandler`
2052
+
2053
+ Framework-agnostic change event handler.
2054
+
2055
+ ```typescript
2056
+ type ChangeEventHandler = EventHandler<Event>
2057
+ ```
2058
+
2052
2059
  #### `FormEventHandler`
2053
2060
 
2054
2061
  Framework-agnostic form event handler.
@@ -2057,6 +2064,30 @@ Framework-agnostic form event handler.
2057
2064
  type FormEventHandler = EventHandler<Event>
2058
2065
  ```
2059
2066
 
2067
+ #### `Size`
2068
+
2069
+ Standard size scale used across all molecule UI components (buttons, inputs, badges, etc.).
2070
+
2071
+ ```typescript
2072
+ type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
2073
+ ```
2074
+
2075
+ #### `ColorVariant`
2076
+
2077
+ Semantic color variants used across components for status indication.
2078
+
2079
+ ```typescript
2080
+ type ColorVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info'
2081
+ ```
2082
+
2083
+ #### `ButtonVariant`
2084
+
2085
+ Button visual variant styles.
2086
+
2087
+ ```typescript
2088
+ type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link'
2089
+ ```
2090
+
2060
2091
  #### `InputType`
2061
2092
 
2062
2093
  Allowed HTML input type attribute values for the Input component.
@@ -2075,14 +2106,6 @@ type InputType =
2075
2106
  | 'datetime-local'
2076
2107
  ```
2077
2108
 
2078
- #### `KeyboardEventHandler`
2079
-
2080
- Framework-agnostic keyboard event handler.
2081
-
2082
- ```typescript
2083
- type KeyboardEventHandler = EventHandler<KeyboardEvent>
2084
- ```
2085
-
2086
2109
  #### `ModalSize`
2087
2110
 
2088
2111
  Modal size variants including full-screen.
@@ -2091,12 +2114,13 @@ Modal size variants including full-screen.
2091
2114
  type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'
2092
2115
  ```
2093
2116
 
2094
- #### `MouseEventHandler`
2117
+ #### `TooltipPlacement`
2095
2118
 
2096
- Framework-agnostic mouse event handler.
2119
+ Position where a tooltip renders relative to its trigger element (top, bottom, left, right, and corner variants).
2097
2120
 
2098
2121
  ```typescript
2099
- type MouseEventHandler = EventHandler<MouseEvent>
2122
+ type TooltipPlacement =
2123
+ 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'
2100
2124
  ```
2101
2125
 
2102
2126
  #### `ShellSidebarWidth`
@@ -2112,23 +2136,6 @@ as a token" case).
2112
2136
  type ShellSidebarWidth = 'sm' | 'md' | 'lg' | number
2113
2137
  ```
2114
2138
 
2115
- #### `Size`
2116
-
2117
- Standard size scale used across all molecule UI components (buttons, inputs, badges, etc.).
2118
-
2119
- ```typescript
2120
- type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
2121
- ```
2122
-
2123
- #### `TooltipPlacement`
2124
-
2125
- Position where a tooltip renders relative to its trigger element (top, bottom, left, right, and corner variants).
2126
-
2127
- ```typescript
2128
- type TooltipPlacement =
2129
- 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'
2130
- ```
2131
-
2132
2139
  ### Functions
2133
2140
 
2134
2141
  #### `AuthGuard(props)`
@@ -2159,18 +2166,6 @@ function AuthGuard({
2159
2166
 
2160
2167
  - `props` — {@link AuthGuardProps}
2161
2168
 
2162
- #### `cn(inputs)`
2163
-
2164
- Merge class name strings, filtering out falsy values (undefined, null, false).
2165
-
2166
- ```typescript
2167
- function cn(inputs?: (string | false | null | undefined)[]): string
2168
- ```
2169
-
2170
- - `inputs` — Class name strings or falsy values to be filtered out.
2171
-
2172
- **Returns:** A single space-separated class string.
2173
-
2174
2169
  #### `ConfirmDialog(props)`
2175
2170
 
2176
2171
  Are-you-sure-style confirmation modal for destructive actions.
@@ -2293,6 +2288,19 @@ function PanelCloseProvider({ close, children }: PanelCloseProviderProps): JSX.E
2293
2288
 
2294
2289
  **Returns:** The children wrapped in the close-context provider.
2295
2290
 
2291
+ #### `usePanelClose()`
2292
+
2293
+ Returns the callback that dismisses the drawer the current panel is
2294
+ mounted in. Safe to call anywhere — returns a no-op when no enclosing
2295
+ `UserMenu` / `SidebarUserCard` provides one (e.g. a `SettingsPanel`
2296
+ rendered as a standalone page).
2297
+
2298
+ ```typescript
2299
+ function usePanelClose(): () => void
2300
+ ```
2301
+
2302
+ **Returns:** A function that closes the enclosing drawer, or a no-op.
2303
+
2296
2304
  #### `PromptDialog(props)`
2297
2305
 
2298
2306
  Modal that asks the user for a short string, replacing `window.prompt`.
@@ -2318,54 +2326,50 @@ function PromptDialog({
2318
2326
 
2319
2327
  - `props` — Component props (see {@link PromptDialogProps}).
2320
2328
 
2321
- #### `ResponsiveAppShellContent(props)`
2329
+ #### `useIsDesktop(query)`
2322
2330
 
2323
- The shell's `<main>` landmark. Grows to fill the row and may shrink below
2324
- its content width, so page-level `overflow-x` strips scroll inside the
2325
- page instead of widening the whole shell.
2331
+ Whether the viewport is at least 768px wide (the fleet's `md` breakpoint).
2332
+
2333
+ Reads `window.matchMedia` synchronously in the state initializer, so the
2334
+ FIRST client render is already correct — no mobile-then-desktop swap frame
2335
+ (this is time-tracking's QA-hardened version; the naive
2336
+ "state starts false, sync in an effect" variant mounts the wrong shell for
2337
+ one frame and double-fetches route data on desktop). Subscribes to
2338
+ `change` events afterwards. Guarded for non-browser environments
2339
+ (SSR/node): returns `false` (the mobile shell) when no `window.matchMedia`
2340
+ exists.
2326
2341
 
2327
2342
  ```typescript
2328
- function ResponsiveAppShellContent({
2329
- children,
2330
- className,
2331
- style,
2332
- dataMolId = 'shell-content',
2333
- testId,
2334
- }: ResponsiveAppShellContentProps): JSX.Element
2343
+ function useIsDesktop(query?: string): boolean
2335
2344
  ```
2336
2345
 
2337
- - `props` — The page content and class/id overrides.
2346
+ - `query` — Override the media query. Defaults to `(min-width: 768px)`.
2338
2347
 
2339
- **Returns:** The main landmark.
2348
+ **Returns:** Whether the desktop shell should mount.
2340
2349
 
2341
- #### `ResponsiveAppShellDrawer(props)`
2350
+ #### `ResponsiveAppShellTopBar(props)`
2342
2351
 
2343
- The mobile nav drawer (<768px): a left-anchored dialog panel over a
2344
- backdrop, opened by the menu trigger the TopBar renders.
2352
+ The shell's `<header>` landmark: menu trigger (mobile, when a Drawer is
2353
+ composed), brand, and trailing actions.
2345
2354
 
2346
- Implements the WAI-ARIA APG dialog pattern — focus moves into the panel on
2347
- open and returns to the previously focused element (the trigger) on close,
2348
- Tab is trapped inside, Escape and backdrop clicks close, body scroll locks
2349
- (reference-counted with any stacked `<Modal>`), and the shell closes it on
2350
- SPA navigation. Renders nothing on desktop or while closed.
2355
+ Sticks to the top of the viewport by default. The menu trigger renders
2356
+ only while a `ResponsiveAppShell.Drawer` is part of the composition AND
2357
+ the viewport is below the breakpoint.
2351
2358
 
2352
2359
  ```typescript
2353
- function ResponsiveAppShellDrawer({
2354
- children,
2355
- header,
2356
- navLabel,
2357
- footer,
2358
- showCloseButton = true,
2360
+ function ResponsiveAppShellTopBar({
2361
+ brand,
2362
+ actions,
2363
+ mobileOnly = false,
2359
2364
  className,
2360
- dataMolId = 'shell-drawer',
2361
- closeDataMolId = 'shell-drawer-close',
2365
+ dataMolId = 'shell-topbar',
2362
2366
  testId,
2363
- }: ResponsiveAppShellDrawerProps): JSX.Element | null
2367
+ }: ResponsiveAppShellTopBarProps): JSX.Element | null
2364
2368
  ```
2365
2369
 
2366
- - `props` — Nav children, header/nav-label/footer slots, close-button and class/id overrides.
2370
+ - `props` — Brand/actions slots, `mobileOnly`, and class/id overrides.
2367
2371
 
2368
- **Returns:** The drawer portal while open on mobile, otherwise `null`.
2372
+ **Returns:** The header landmark, or `null` when `mobileOnly` is set on desktop.
2369
2373
 
2370
2374
  #### `ResponsiveAppShellSidebar(props)`
2371
2375
 
@@ -2390,29 +2394,54 @@ function ResponsiveAppShellSidebar({
2390
2394
 
2391
2395
  **Returns:** The sidebar landmarks, or `null` below the breakpoint.
2392
2396
 
2393
- #### `ResponsiveAppShellTopBar(props)`
2397
+ #### `ResponsiveAppShellDrawer(props)`
2398
+
2399
+ The mobile nav drawer (<768px): a left-anchored dialog panel over a
2400
+ backdrop, opened by the menu trigger the TopBar renders.
2401
+
2402
+ Implements the WAI-ARIA APG dialog pattern — focus moves into the panel on
2403
+ open and returns to the previously focused element (the trigger) on close,
2404
+ Tab is trapped inside, Escape and backdrop clicks close, body scroll locks
2405
+ (reference-counted with any stacked `<Modal>`), and the shell closes it on
2406
+ SPA navigation. Renders nothing on desktop or while closed.
2407
+
2408
+ ```typescript
2409
+ function ResponsiveAppShellDrawer({
2410
+ children,
2411
+ header,
2412
+ navLabel,
2413
+ footer,
2414
+ showCloseButton = true,
2415
+ className,
2416
+ dataMolId = 'shell-drawer',
2417
+ closeDataMolId = 'shell-drawer-close',
2418
+ testId,
2419
+ }: ResponsiveAppShellDrawerProps): JSX.Element | null
2420
+ ```
2421
+
2422
+ - `props` — Nav children, header/nav-label/footer slots, close-button and class/id overrides.
2423
+
2424
+ **Returns:** The drawer portal while open on mobile, otherwise `null`.
2394
2425
 
2395
- The shell's `<header>` landmark: menu trigger (mobile, when a Drawer is
2396
- composed), brand, and trailing actions.
2426
+ #### `ResponsiveAppShellContent(props)`
2397
2427
 
2398
- Sticks to the top of the viewport by default. The menu trigger renders
2399
- only while a `ResponsiveAppShell.Drawer` is part of the composition AND
2400
- the viewport is below the breakpoint.
2428
+ The shell's `<main>` landmark. Grows to fill the row and may shrink below
2429
+ its content width, so page-level `overflow-x` strips scroll inside the
2430
+ page instead of widening the whole shell.
2401
2431
 
2402
2432
  ```typescript
2403
- function ResponsiveAppShellTopBar({
2404
- brand,
2405
- actions,
2406
- mobileOnly = false,
2433
+ function ResponsiveAppShellContent({
2434
+ children,
2407
2435
  className,
2408
- dataMolId = 'shell-topbar',
2436
+ style,
2437
+ dataMolId = 'shell-content',
2409
2438
  testId,
2410
- }: ResponsiveAppShellTopBarProps): JSX.Element | null
2439
+ }: ResponsiveAppShellContentProps): JSX.Element
2411
2440
  ```
2412
2441
 
2413
- - `props` — Brand/actions slots, `mobileOnly`, and class/id overrides.
2442
+ - `props` — The page content and class/id overrides.
2414
2443
 
2415
- **Returns:** The header landmark, or `null` when `mobileOnly` is set on desktop.
2444
+ **Returns:** The main landmark.
2416
2445
 
2417
2446
  #### `SidebarUserCard(props)`
2418
2447
 
@@ -2474,6 +2503,16 @@ function ThemeToggle({
2474
2503
 
2475
2504
  - `props` — {@link ThemeToggleProps}
2476
2505
 
2506
+ #### `useToast()`
2507
+
2508
+ Hook to access the toast context for adding and removing toasts.
2509
+
2510
+ ```typescript
2511
+ function useToast(): ToastContextValue
2512
+ ```
2513
+
2514
+ **Returns:** The toast context value with toast management methods.
2515
+
2477
2516
  #### `ToastProvider(props)`
2478
2517
 
2479
2518
  Provider component that manages global toast state.
@@ -2491,40 +2530,6 @@ function ToastProvider({
2491
2530
 
2492
2531
  **Returns:** The rendered provider with toast container.
2493
2532
 
2494
- #### `useIsDesktop(query)`
2495
-
2496
- Whether the viewport is at least 768px wide (the fleet's `md` breakpoint).
2497
-
2498
- Reads `window.matchMedia` synchronously in the state initializer, so the
2499
- FIRST client render is already correct — no mobile-then-desktop swap frame
2500
- (this is time-tracking's QA-hardened version; the naive
2501
- "state starts false, sync in an effect" variant mounts the wrong shell for
2502
- one frame and double-fetches route data on desktop). Subscribes to
2503
- `change` events afterwards. Guarded for non-browser environments
2504
- (SSR/node): returns `false` (the mobile shell) when no `window.matchMedia`
2505
- exists.
2506
-
2507
- ```typescript
2508
- function useIsDesktop(query?: string): boolean
2509
- ```
2510
-
2511
- - `query` — Override the media query. Defaults to `(min-width: 768px)`.
2512
-
2513
- **Returns:** Whether the desktop shell should mount.
2514
-
2515
- #### `usePanelClose()`
2516
-
2517
- Returns the callback that dismisses the drawer the current panel is
2518
- mounted in. Safe to call anywhere — returns a no-op when no enclosing
2519
- `UserMenu` / `SidebarUserCard` provides one (e.g. a `SettingsPanel`
2520
- rendered as a standalone page).
2521
-
2522
- ```typescript
2523
- function usePanelClose(): () => void
2524
- ```
2525
-
2526
- **Returns:** A function that closes the enclosing drawer, or a no-op.
2527
-
2528
2533
  #### `UserMenu(props)`
2529
2534
 
2530
2535
  Avatar-style trigger that opens the app's settings panel in a drawer.
@@ -2570,6 +2575,24 @@ function UserMenuPopover({
2570
2575
 
2571
2576
  **Returns:** The relative-positioned popover container.
2572
2577
 
2578
+ #### `UserMenuPopoverTrigger(props)`
2579
+
2580
+ The trigger button: an initials avatar plus the account name and email,
2581
+ styled as a full-width sidebar card. Toggles the popover panel.
2582
+
2583
+ ```typescript
2584
+ function UserMenuPopoverTrigger({
2585
+ ariaLabelKey = 'userMenu.open',
2586
+ ariaLabelDefault = 'Open user menu',
2587
+ dataMolId = 'user-menu',
2588
+ className,
2589
+ }: UserMenuPopoverTriggerProps): React.JSX.Element
2590
+ ```
2591
+
2592
+ - `props` — aria-label overrides, `data-mol-id`, and className.
2593
+
2594
+ **Returns:** The popover trigger button.
2595
+
2573
2596
  #### `UserMenuPopoverPanel(props)`
2574
2597
 
2575
2598
  The popover panel: an absolutely-positioned card with a built-in
@@ -2597,6 +2620,19 @@ function UserMenuPopoverPanel({
2597
2620
 
2598
2621
  **Returns:** The popover panel, or `null` when closed.
2599
2622
 
2623
+ #### `useUserMenuPopoverClose()`
2624
+
2625
+ Returns a callback that closes the enclosing `UserMenuPopover`. Useful
2626
+ for nav-item `onClick` handlers that should dismiss the popover even
2627
+ when they don't change the route. Returns a no-op when called outside
2628
+ a `UserMenuPopover`.
2629
+
2630
+ ```typescript
2631
+ function useUserMenuPopoverClose(): () => void
2632
+ ```
2633
+
2634
+ **Returns:** A function that closes the popover.
2635
+
2600
2636
  #### `UserMenuPopoverSignOut(props)`
2601
2637
 
2602
2638
  The sign-out nav item — closes the popover and calls `auth.logout()`.
@@ -2615,46 +2651,17 @@ function UserMenuPopoverSignOut({
2615
2651
 
2616
2652
  **Returns:** The sign-out button.
2617
2653
 
2618
- #### `UserMenuPopoverTrigger(props)`
2619
-
2620
- The trigger button: an initials avatar plus the account name and email,
2621
- styled as a full-width sidebar card. Toggles the popover panel.
2622
-
2623
- ```typescript
2624
- function UserMenuPopoverTrigger({
2625
- ariaLabelKey = 'userMenu.open',
2626
- ariaLabelDefault = 'Open user menu',
2627
- dataMolId = 'user-menu',
2628
- className,
2629
- }: UserMenuPopoverTriggerProps): React.JSX.Element
2630
- ```
2631
-
2632
- - `props` — aria-label overrides, `data-mol-id`, and className.
2633
-
2634
- **Returns:** The popover trigger button.
2635
-
2636
- #### `useToast()`
2654
+ #### `cn(inputs)`
2637
2655
 
2638
- Hook to access the toast context for adding and removing toasts.
2656
+ Merge class name strings, filtering out falsy values (undefined, null, false).
2639
2657
 
2640
2658
  ```typescript
2641
- function useToast(): ToastContextValue
2659
+ function cn(inputs?: (string | false | null | undefined)[]): string
2642
2660
  ```
2643
2661
 
2644
- **Returns:** The toast context value with toast management methods.
2645
-
2646
- #### `useUserMenuPopoverClose()`
2647
-
2648
- Returns a callback that closes the enclosing `UserMenuPopover`. Useful
2649
- for nav-item `onClick` handlers that should dismiss the popover even
2650
- when they don't change the route. Returns a no-op when called outside
2651
- a `UserMenuPopover`.
2652
-
2653
- ```typescript
2654
- function useUserMenuPopoverClose(): () => void
2655
- ```
2662
+ - `inputs` — Class name strings or falsy values to be filtered out.
2656
2663
 
2657
- **Returns:** A function that closes the popover.
2664
+ **Returns:** A single space-separated class string.
2658
2665
 
2659
2666
  ### Constants
2660
2667
 
@@ -2724,53 +2731,53 @@ const Card: React.ForwardRefExoticComponent<
2724
2731
  >
2725
2732
  ```
2726
2733
 
2727
- #### `CardContent`
2734
+ #### `CardHeader`
2728
2735
 
2729
- Card content component.
2736
+ Card header component.
2730
2737
 
2731
2738
  ```typescript
2732
- const CardContent: React.ForwardRefExoticComponent<
2739
+ const CardHeader: React.ForwardRefExoticComponent<
2733
2740
  React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2734
2741
  >
2735
2742
  ```
2736
2743
 
2737
- #### `CardDescription`
2744
+ #### `CardTitle`
2738
2745
 
2739
- Card description component.
2746
+ Card title component.
2740
2747
 
2741
2748
  ```typescript
2742
- const CardDescription: React.ForwardRefExoticComponent<
2743
- React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>
2749
+ const CardTitle: React.ForwardRefExoticComponent<
2750
+ React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLHeadingElement>
2744
2751
  >
2745
2752
  ```
2746
2753
 
2747
- #### `CardFooter`
2754
+ #### `CardDescription`
2748
2755
 
2749
- Card footer component.
2756
+ Card description component.
2750
2757
 
2751
2758
  ```typescript
2752
- const CardFooter: React.ForwardRefExoticComponent<
2753
- React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2759
+ const CardDescription: React.ForwardRefExoticComponent<
2760
+ React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>
2754
2761
  >
2755
2762
  ```
2756
2763
 
2757
- #### `CardHeader`
2764
+ #### `CardContent`
2758
2765
 
2759
- Card header component.
2766
+ Card content component.
2760
2767
 
2761
2768
  ```typescript
2762
- const CardHeader: React.ForwardRefExoticComponent<
2769
+ const CardContent: React.ForwardRefExoticComponent<
2763
2770
  React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2764
2771
  >
2765
2772
  ```
2766
2773
 
2767
- #### `CardTitle`
2774
+ #### `CardFooter`
2768
2775
 
2769
- Card title component.
2776
+ Card footer component.
2770
2777
 
2771
2778
  ```typescript
2772
- const CardTitle: React.ForwardRefExoticComponent<
2773
- React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLHeadingElement>
2779
+ const CardFooter: React.ForwardRefExoticComponent<
2780
+ React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2774
2781
  >
2775
2782
  ```
2776
2783
 
@@ -2802,16 +2809,6 @@ const ConfirmButton: React.ForwardRefExoticComponent<
2802
2809
  >
2803
2810
  ```
2804
2811
 
2805
- #### `Container`
2806
-
2807
- Container component.
2808
-
2809
- ```typescript
2810
- const Container: React.ForwardRefExoticComponent<
2811
- ContainerProps & React.RefAttributes<HTMLDivElement>
2812
- >
2813
- ```
2814
-
2815
2812
  #### `Dropdown`
2816
2813
 
2817
2814
  Dropdown component.
@@ -2868,14 +2865,6 @@ const EmptyState: React.ForwardRefExoticComponent<
2868
2865
  >
2869
2866
  ```
2870
2867
 
2871
- #### `Flex`
2872
-
2873
- Flex container component.
2874
-
2875
- ```typescript
2876
- const Flex: React.ForwardRefExoticComponent<FlexProps & React.RefAttributes<HTMLDivElement>>
2877
- ```
2878
-
2879
2868
  #### `FloatingInput`
2880
2869
 
2881
2870
  An input with a floating label.
@@ -2917,12 +2906,16 @@ const FormField: React.ForwardRefExoticComponent<
2917
2906
  >
2918
2907
  ```
2919
2908
 
2920
- #### `Grid`
2909
+ #### `Label`
2921
2910
 
2922
- Grid container component.
2911
+ Label component.
2923
2912
 
2924
2913
  ```typescript
2925
- const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<HTMLDivElement>>
2914
+ const Label: React.ForwardRefExoticComponent<
2915
+ React.LabelHTMLAttributes<HTMLLabelElement> & {
2916
+ required?: boolean
2917
+ } & React.RefAttributes<HTMLLabelElement>
2918
+ >
2926
2919
  ```
2927
2920
 
2928
2921
  #### `Input`
@@ -2933,18 +2926,40 @@ Input component.
2933
2926
  const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>
2934
2927
  ```
2935
2928
 
2936
- #### `Label`
2929
+ #### `Container`
2937
2930
 
2938
- Label component.
2931
+ Container component.
2939
2932
 
2940
2933
  ```typescript
2941
- const Label: React.ForwardRefExoticComponent<
2942
- React.LabelHTMLAttributes<HTMLLabelElement> & {
2943
- required?: boolean
2944
- } & React.RefAttributes<HTMLLabelElement>
2934
+ const Container: React.ForwardRefExoticComponent<
2935
+ ContainerProps & React.RefAttributes<HTMLDivElement>
2945
2936
  >
2946
2937
  ```
2947
2938
 
2939
+ #### `Flex`
2940
+
2941
+ Flex container component.
2942
+
2943
+ ```typescript
2944
+ const Flex: React.ForwardRefExoticComponent<FlexProps & React.RefAttributes<HTMLDivElement>>
2945
+ ```
2946
+
2947
+ #### `Grid`
2948
+
2949
+ Grid container component.
2950
+
2951
+ ```typescript
2952
+ const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<HTMLDivElement>>
2953
+ ```
2954
+
2955
+ #### `Spacer`
2956
+
2957
+ Spacer component.
2958
+
2959
+ ```typescript
2960
+ const Spacer: React.ForwardRefExoticComponent<SpacerProps & React.RefAttributes<HTMLDivElement>>
2961
+ ```
2962
+
2948
2963
  #### `Modal`
2949
2964
 
2950
2965
  Modal component.
@@ -3073,16 +3088,6 @@ Skeleton component.
3073
3088
  const Skeleton: React.ForwardRefExoticComponent<SkeletonProps & React.RefAttributes<HTMLDivElement>>
3074
3089
  ```
3075
3090
 
3076
- #### `SkeletonCircle`
3077
-
3078
- Skeleton circle (avatar placeholder).
3079
-
3080
- ```typescript
3081
- const SkeletonCircle: React.ForwardRefExoticComponent<
3082
- { size?: number; className?: string } & React.RefAttributes<HTMLDivElement>
3083
- >
3084
- ```
3085
-
3086
3091
  #### `SkeletonText`
3087
3092
 
3088
3093
  Skeleton text line.
@@ -3093,12 +3098,14 @@ const SkeletonText: React.ForwardRefExoticComponent<
3093
3098
  >
3094
3099
  ```
3095
3100
 
3096
- #### `Spacer`
3101
+ #### `SkeletonCircle`
3097
3102
 
3098
- Spacer component.
3103
+ Skeleton circle (avatar placeholder).
3099
3104
 
3100
3105
  ```typescript
3101
- const Spacer: React.ForwardRefExoticComponent<SpacerProps & React.RefAttributes<HTMLDivElement>>
3106
+ const SkeletonCircle: React.ForwardRefExoticComponent<
3107
+ { size?: number; className?: string } & React.RefAttributes<HTMLDivElement>
3108
+ >
3102
3109
  ```
3103
3110
 
3104
3111
  #### `Spinner`
@@ -3176,6 +3183,8 @@ const ToastContainer: React.ForwardRefExoticComponent<
3176
3183
  >
3177
3184
  ```
3178
3185
 
3186
+ **Returns:** The rendered toast container element.
3187
+
3179
3188
  #### `Tooltip`
3180
3189
 
3181
3190
  Tooltip component.