@molecule/app-ui-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/LICENSE +115 -0
  2. package/README.md +2786 -0
  3. package/dist/components/Accordion.d.ts +12 -0
  4. package/dist/components/Accordion.d.ts.map +1 -0
  5. package/dist/components/Accordion.js +80 -0
  6. package/dist/components/Accordion.js.map +1 -0
  7. package/dist/components/Alert.d.ts +26 -0
  8. package/dist/components/Alert.d.ts.map +1 -0
  9. package/dist/components/Alert.js +53 -0
  10. package/dist/components/Alert.js.map +1 -0
  11. package/dist/components/AuthGuard.d.ts +66 -0
  12. package/dist/components/AuthGuard.d.ts.map +1 -0
  13. package/dist/components/AuthGuard.js +42 -0
  14. package/dist/components/AuthGuard.js.map +1 -0
  15. package/dist/components/Avatar.d.ts +12 -0
  16. package/dist/components/Avatar.d.ts.map +1 -0
  17. package/dist/components/Avatar.js +25 -0
  18. package/dist/components/Avatar.js.map +1 -0
  19. package/dist/components/Badge.d.ts +12 -0
  20. package/dist/components/Badge.d.ts.map +1 -0
  21. package/dist/components/Badge.js +18 -0
  22. package/dist/components/Badge.js.map +1 -0
  23. package/dist/components/Button.d.ts +12 -0
  24. package/dist/components/Button.d.ts.map +1 -0
  25. package/dist/components/Button.js +19 -0
  26. package/dist/components/Button.js.map +1 -0
  27. package/dist/components/Card.d.ts +34 -0
  28. package/dist/components/Card.d.ts.map +1 -0
  29. package/dist/components/Card.js +71 -0
  30. package/dist/components/Card.js.map +1 -0
  31. package/dist/components/Checkbox.d.ts +12 -0
  32. package/dist/components/Checkbox.d.ts.map +1 -0
  33. package/dist/components/Checkbox.js +41 -0
  34. package/dist/components/Checkbox.js.map +1 -0
  35. package/dist/components/Dropdown.d.ts +38 -0
  36. package/dist/components/Dropdown.d.ts.map +1 -0
  37. package/dist/components/Dropdown.js +352 -0
  38. package/dist/components/Dropdown.js.map +1 -0
  39. package/dist/components/EmptyState.d.ts +15 -0
  40. package/dist/components/EmptyState.d.ts.map +1 -0
  41. package/dist/components/EmptyState.js +20 -0
  42. package/dist/components/EmptyState.js.map +1 -0
  43. package/dist/components/FloatingInput.d.ts +22 -0
  44. package/dist/components/FloatingInput.d.ts.map +1 -0
  45. package/dist/components/FloatingInput.js +38 -0
  46. package/dist/components/FloatingInput.js.map +1 -0
  47. package/dist/components/Form.d.ts +22 -0
  48. package/dist/components/Form.d.ts.map +1 -0
  49. package/dist/components/Form.js +81 -0
  50. package/dist/components/Form.js.map +1 -0
  51. package/dist/components/Icon.d.ts +48 -0
  52. package/dist/components/Icon.d.ts.map +1 -0
  53. package/dist/components/Icon.js +46 -0
  54. package/dist/components/Icon.js.map +1 -0
  55. package/dist/components/Input.d.ts +12 -0
  56. package/dist/components/Input.d.ts.map +1 -0
  57. package/dist/components/Input.js +25 -0
  58. package/dist/components/Input.js.map +1 -0
  59. package/dist/components/LanguagePicker.d.ts +60 -0
  60. package/dist/components/LanguagePicker.d.ts.map +1 -0
  61. package/dist/components/LanguagePicker.js +45 -0
  62. package/dist/components/LanguagePicker.js.map +1 -0
  63. package/dist/components/Layout.d.ts +24 -0
  64. package/dist/components/Layout.d.ts.map +1 -0
  65. package/dist/components/Layout.js +104 -0
  66. package/dist/components/Layout.js.map +1 -0
  67. package/dist/components/Modal.d.ts +32 -0
  68. package/dist/components/Modal.d.ts.map +1 -0
  69. package/dist/components/Modal.js +235 -0
  70. package/dist/components/Modal.js.map +1 -0
  71. package/dist/components/PageHeader.d.ts +15 -0
  72. package/dist/components/PageHeader.d.ts.map +1 -0
  73. package/dist/components/PageHeader.js +20 -0
  74. package/dist/components/PageHeader.js.map +1 -0
  75. package/dist/components/PageShell.d.ts +15 -0
  76. package/dist/components/PageShell.d.ts.map +1 -0
  77. package/dist/components/PageShell.js +20 -0
  78. package/dist/components/PageShell.js.map +1 -0
  79. package/dist/components/Pagination.d.ts +12 -0
  80. package/dist/components/Pagination.d.ts.map +1 -0
  81. package/dist/components/Pagination.js +78 -0
  82. package/dist/components/Pagination.js.map +1 -0
  83. package/dist/components/PanelClose.d.ts +40 -0
  84. package/dist/components/PanelClose.d.ts.map +1 -0
  85. package/dist/components/PanelClose.js +32 -0
  86. package/dist/components/PanelClose.js.map +1 -0
  87. package/dist/components/Progress.d.ts +45 -0
  88. package/dist/components/Progress.d.ts.map +1 -0
  89. package/dist/components/Progress.js +21 -0
  90. package/dist/components/Progress.js.map +1 -0
  91. package/dist/components/RadioGroup.d.ts +12 -0
  92. package/dist/components/RadioGroup.d.ts.map +1 -0
  93. package/dist/components/RadioGroup.js +34 -0
  94. package/dist/components/RadioGroup.js.map +1 -0
  95. package/dist/components/Select.d.ts +12 -0
  96. package/dist/components/Select.d.ts.map +1 -0
  97. package/dist/components/Select.js +57 -0
  98. package/dist/components/Select.js.map +1 -0
  99. package/dist/components/Separator.d.ts +25 -0
  100. package/dist/components/Separator.d.ts.map +1 -0
  101. package/dist/components/Separator.js +18 -0
  102. package/dist/components/Separator.js.map +1 -0
  103. package/dist/components/SidebarUserCard.d.ts +60 -0
  104. package/dist/components/SidebarUserCard.d.ts.map +1 -0
  105. package/dist/components/SidebarUserCard.js +45 -0
  106. package/dist/components/SidebarUserCard.js.map +1 -0
  107. package/dist/components/Skeleton.d.ts +26 -0
  108. package/dist/components/Skeleton.d.ts.map +1 -0
  109. package/dist/components/Skeleton.js +45 -0
  110. package/dist/components/Skeleton.js.map +1 -0
  111. package/dist/components/Spinner.d.ts +17 -0
  112. package/dist/components/Spinner.d.ts.map +1 -0
  113. package/dist/components/Spinner.js +32 -0
  114. package/dist/components/Spinner.js.map +1 -0
  115. package/dist/components/Switch.d.ts +12 -0
  116. package/dist/components/Switch.d.ts.map +1 -0
  117. package/dist/components/Switch.js +52 -0
  118. package/dist/components/Switch.js.map +1 -0
  119. package/dist/components/Table.d.ts +12 -0
  120. package/dist/components/Table.d.ts.map +1 -0
  121. package/dist/components/Table.js +53 -0
  122. package/dist/components/Table.js.map +1 -0
  123. package/dist/components/Tabs.d.ts +12 -0
  124. package/dist/components/Tabs.d.ts.map +1 -0
  125. package/dist/components/Tabs.js +72 -0
  126. package/dist/components/Tabs.js.map +1 -0
  127. package/dist/components/Textarea.d.ts +12 -0
  128. package/dist/components/Textarea.d.ts.map +1 -0
  129. package/dist/components/Textarea.js +66 -0
  130. package/dist/components/Textarea.js.map +1 -0
  131. package/dist/components/ThemeToggle.d.ts +43 -0
  132. package/dist/components/ThemeToggle.d.ts.map +1 -0
  133. package/dist/components/ThemeToggle.js +30 -0
  134. package/dist/components/ThemeToggle.js.map +1 -0
  135. package/dist/components/Toast.d.ts +61 -0
  136. package/dist/components/Toast.d.ts.map +1 -0
  137. package/dist/components/Toast.js +159 -0
  138. package/dist/components/Toast.js.map +1 -0
  139. package/dist/components/Tooltip.d.ts +21 -0
  140. package/dist/components/Tooltip.d.ts.map +1 -0
  141. package/dist/components/Tooltip.js +245 -0
  142. package/dist/components/Tooltip.js.map +1 -0
  143. package/dist/components/UserMenu.d.ts +59 -0
  144. package/dist/components/UserMenu.d.ts.map +1 -0
  145. package/dist/components/UserMenu.js +34 -0
  146. package/dist/components/UserMenu.js.map +1 -0
  147. package/dist/components/UserMenuPopover.d.ts +139 -0
  148. package/dist/components/UserMenuPopover.d.ts.map +1 -0
  149. package/dist/components/UserMenuPopover.js +173 -0
  150. package/dist/components/UserMenuPopover.js.map +1 -0
  151. package/dist/components/index.d.ts +43 -0
  152. package/dist/components/index.d.ts.map +1 -0
  153. package/dist/components/index.js +43 -0
  154. package/dist/components/index.js.map +1 -0
  155. package/dist/index.d.ts +131 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +131 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/types.d.ts +7 -0
  160. package/dist/types.d.ts.map +1 -0
  161. package/dist/types.js +7 -0
  162. package/dist/types.js.map +1 -0
  163. package/dist/utilities/index.d.ts +8 -0
  164. package/dist/utilities/index.d.ts.map +1 -0
  165. package/dist/utilities/index.js +8 -0
  166. package/dist/utilities/index.js.map +1 -0
  167. package/dist/utilities/initials.d.ts +13 -0
  168. package/dist/utilities/initials.d.ts.map +1 -0
  169. package/dist/utilities/initials.js +23 -0
  170. package/dist/utilities/initials.js.map +1 -0
  171. package/dist/utilities/renderIcon.d.ts +21 -0
  172. package/dist/utilities/renderIcon.d.ts.map +1 -0
  173. package/dist/utilities/renderIcon.js +40 -0
  174. package/dist/utilities/renderIcon.js.map +1 -0
  175. package/dist/utilities.d.ts +12 -0
  176. package/dist/utilities.d.ts.map +1 -0
  177. package/dist/utilities.js +14 -0
  178. package/dist/utilities.js.map +1 -0
  179. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,2786 @@
1
+ <!--
2
+ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
+ Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
+ Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
+ To change this document, edit the module-level JSDoc in src/index.ts.
6
+ Generated: 2026-08-04T00:41:31.054Z
7
+ -->
8
+
9
+ # @molecule/app-ui-react
10
+
11
+ > **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
12
+ > It is written to be read by coding agents as much as by people, and is generated from this
13
+ > package's source — edit `src/index.ts` JSDoc, not this file.
14
+
15
+ React UI components for molecule.dev.
16
+
17
+ Provides React implementations of the `@molecule/app-ui` component
18
+ interfaces using the UIClassMap abstraction from `@molecule/app-ui`.
19
+
20
+ ## Quick Start
21
+
22
+ ```tsx
23
+ import { setClassMap } from '@molecule/app-ui'
24
+ import { classMap } from '@molecule/app-ui-tailwind'
25
+ import { Button, Modal, Icon, EmptyState } from '@molecule/app-ui-react'
26
+ import { useState } from 'react'
27
+
28
+ // Once at startup, before first render — components throw without it:
29
+ setClassMap(classMap)
30
+
31
+ function ConfirmDelete({ onConfirm }: { onConfirm: () => void }) {
32
+ const [open, setOpen] = useState(false)
33
+ return (
34
+ <>
35
+ <Button color="error" onClick={() => setOpen(true)}>
36
+ <Icon name="trash" size={16} /> Delete
37
+ </Button>
38
+ <Modal
39
+ open={open}
40
+ onClose={() => setOpen(false)}
41
+ title="Delete item?"
42
+ data-mol-id="confirm-delete"
43
+ >
44
+ <EmptyState title="This cannot be undone" />
45
+ <Button color="error" onClick={onConfirm}>
46
+ Confirm
47
+ </Button>
48
+ </Modal>
49
+ </>
50
+ )
51
+ }
52
+ ```
53
+
54
+ ## Type
55
+
56
+ `framework`
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ npm install @molecule/app-ui-react @molecule/app-i18n @molecule/app-icons @molecule/app-react @molecule/app-ui react react-dom react-router
62
+ npm install -D @types/react @types/react-dom
63
+ ```
64
+
65
+ ## API
66
+
67
+ ### Interfaces
68
+
69
+ #### `AccordionItem`
70
+
71
+ A single item in an Accordion component.
72
+
73
+ ```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
91
+ }
92
+ ```
93
+
94
+ #### `AccordionProps`
95
+
96
+ Props for the Accordion component.
97
+
98
+ ```typescript
99
+ interface AccordionProps<T = string> extends BaseProps {
100
+ /**
101
+ * Accordion items.
102
+ */
103
+ items: AccordionItem<T>[]
104
+ /**
105
+ * Expanded item(s).
106
+ */
107
+ value?: T | T[]
108
+ /**
109
+ * Default expanded item(s).
110
+ */
111
+ defaultValue?: T | T[]
112
+ /**
113
+ * Change handler.
114
+ */
115
+ onChange?: (value: T | T[]) => void
116
+ /**
117
+ * Whether multiple items can be expanded.
118
+ */
119
+ multiple?: boolean
120
+ /**
121
+ * Whether items can be collapsed.
122
+ */
123
+ collapsible?: boolean
124
+ }
125
+ ```
126
+
127
+ #### `AlertProps`
128
+
129
+ Props for the Alert component.
130
+
131
+ ```typescript
132
+ interface AlertProps extends HTMLElementProps {
133
+ /**
134
+ * Alert content.
135
+ */
136
+ children?: Children
137
+ /**
138
+ * Alert title.
139
+ */
140
+ title?: string
141
+ /**
142
+ * Alert status/type.
143
+ */
144
+ status?: ColorVariant
145
+ /**
146
+ * Alert variant.
147
+ */
148
+ variant?: 'solid' | 'subtle' | 'outline' | 'left-accent'
149
+ /**
150
+ * Whether the alert is dismissible.
151
+ */
152
+ dismissible?: boolean
153
+ /**
154
+ * Called when dismissed.
155
+ */
156
+ onDismiss?: () => void
157
+ /**
158
+ * Icon to display.
159
+ */
160
+ icon?: Children
161
+ /**
162
+ * Accessible label for the dismiss button.
163
+ * @default 'Dismiss'
164
+ */
165
+ dismissLabel?: string
166
+ }
167
+ ```
168
+
169
+ #### `AuthGuardProps`
170
+
171
+ Props for {@link AuthGuard}.
172
+
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.
177
+
178
+ ```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
187
+ /**
188
+ * i18n key used for the default loading-tag text. Defaults to
189
+ * `'common.loading'`. Ignored when `loadingFallback` is set.
190
+ */
191
+ loadingKey?: string
192
+ /**
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.
196
+ */
197
+ loadingDefault?: string
198
+ /**
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.
202
+ */
203
+ loginPath?: string
204
+ /**
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.
210
+ */
211
+ onAuthenticated?: () => void
212
+ /**
213
+ * Children to render when authenticated. Defaults to `<Outlet />`,
214
+ * which is the React Router pattern this guard is designed for.
215
+ */
216
+ children?: ReactNode
217
+ }
218
+ ```
219
+
220
+ #### `AvatarProps`
221
+
222
+ Props for the Avatar component.
223
+
224
+ ```typescript
225
+ interface AvatarProps extends HTMLElementProps {
226
+ /**
227
+ * Image source URL.
228
+ */
229
+ src?: string
230
+ /**
231
+ * Alt text for the image.
232
+ */
233
+ alt?: string
234
+ /**
235
+ * Name for fallback initials.
236
+ */
237
+ name?: string
238
+ /**
239
+ * Avatar size.
240
+ */
241
+ size?: Size | number
242
+ /**
243
+ * Whether the avatar is rounded.
244
+ */
245
+ rounded?: boolean
246
+ /**
247
+ * Fallback element when no image.
248
+ */
249
+ fallback?: Children
250
+ }
251
+ ```
252
+
253
+ #### `BadgeProps`
254
+
255
+ Props for the Badge component (status labels, counts, tags).
256
+
257
+ ```typescript
258
+ interface BadgeProps extends HTMLElementProps {
259
+ /**
260
+ * Badge content.
261
+ */
262
+ children?: Children
263
+ /**
264
+ * Badge color.
265
+ */
266
+ color?: ColorVariant
267
+ /**
268
+ * Badge variant.
269
+ */
270
+ variant?: 'solid' | 'outline' | 'subtle'
271
+ /**
272
+ * Badge size.
273
+ */
274
+ size?: Size
275
+ /**
276
+ * Whether the badge is rounded.
277
+ */
278
+ rounded?: boolean
279
+ }
280
+ ```
281
+
282
+ #### `BaseProps`
283
+
284
+ Base props shared by all components.
285
+
286
+ ```typescript
287
+ interface BaseProps {
288
+ /**
289
+ * Additional CSS class name(s).
290
+ */
291
+ className?: string
292
+ /**
293
+ * Inline styles.
294
+ */
295
+ style?: CSSProperties
296
+ /**
297
+ * Test ID for automated testing.
298
+ */
299
+ testId?: string
300
+ /**
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-*`.)
305
+ */
306
+ automationId?: string
307
+ /**
308
+ * Whether the component is disabled.
309
+ */
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
324
+ }
325
+ ```
326
+
327
+ #### `ButtonProps`
328
+
329
+ Props for the Button component.
330
+
331
+ ```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
349
+ /**
350
+ * Whether the button is in a loading state.
351
+ */
352
+ loading?: boolean
353
+ /**
354
+ * Loading text to display.
355
+ */
356
+ loadingText?: string
357
+ /**
358
+ * Whether the button takes full width.
359
+ */
360
+ fullWidth?: boolean
361
+ /**
362
+ * Icon to display before the label.
363
+ */
364
+ leftIcon?: Children
365
+ /**
366
+ * Icon to display after the label.
367
+ */
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 {
378
+ /**
379
+ * Card content.
380
+ */
381
+ children?: Children
382
+ /**
383
+ * Card variant.
384
+ */
385
+ variant?: 'elevated' | 'outlined' | 'filled'
386
+ /**
387
+ * Whether the card is interactive (clickable).
388
+ */
389
+ interactive?: boolean
390
+ /**
391
+ * Padding size.
392
+ */
393
+ padding?: Size | 'none'
394
+ }
395
+ ```
396
+
397
+ #### `CheckboxProps`
398
+
399
+ Props for the Checkbox component.
400
+
401
+ ```typescript
402
+ interface CheckboxProps extends InputElementProps {
403
+ /**
404
+ * Checkbox label.
405
+ */
406
+ label?: Children
407
+ /**
408
+ * Whether the checkbox is checked.
409
+ */
410
+ checked?: boolean
411
+ /**
412
+ * Whether the checkbox is in an indeterminate state.
413
+ */
414
+ indeterminate?: boolean
415
+ /**
416
+ * Checkbox size.
417
+ */
418
+ size?: Size
419
+ /**
420
+ * Error message.
421
+ */
422
+ error?: string
423
+ }
424
+ ```
425
+
426
+ #### `ContainerProps`
427
+
428
+ Props for the Container layout component.
429
+
430
+ ```typescript
431
+ interface ContainerProps extends HTMLElementProps {
432
+ /**
433
+ * Container content.
434
+ */
435
+ children?: Children
436
+ /**
437
+ * Maximum width.
438
+ */
439
+ maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | string
440
+ /**
441
+ * Whether to center the container.
442
+ */
443
+ centered?: boolean
444
+ /**
445
+ * Horizontal padding.
446
+ */
447
+ paddingX?: Size | string
448
+ }
449
+ ```
450
+
451
+ #### `CSSProperties`
452
+
453
+ Framework-agnostic CSS properties.
454
+ Mirrors React.CSSProperties but without React dependency.
455
+
456
+ ```typescript
457
+ interface CSSProperties {
458
+ [key: string]: string | number | undefined
459
+ }
460
+ ```
461
+
462
+ #### `FlexProps`
463
+
464
+ Flex container props.
465
+
466
+ ```typescript
467
+ interface FlexProps extends HTMLElementProps {
468
+ /**
469
+ * Flex content.
470
+ */
471
+ children?: Children
472
+ /**
473
+ * Flex direction.
474
+ */
475
+ direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
476
+ /**
477
+ * Justify content.
478
+ */
479
+ justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'
480
+ /**
481
+ * Align items.
482
+ */
483
+ align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'
484
+ /**
485
+ * Flex wrap.
486
+ */
487
+ wrap?: 'wrap' | 'nowrap' | 'wrap-reverse'
488
+ /**
489
+ * Gap between items.
490
+ */
491
+ gap?: Size | string | number
492
+ }
493
+ ```
494
+
495
+ #### `FormElementProps`
496
+
497
+ Base props for form elements.
498
+
499
+ ```typescript
500
+ interface FormElementProps extends HTMLElementProps {
501
+ action?: string
502
+ method?: 'get' | 'post'
503
+ encType?: string
504
+ target?: string
505
+ noValidate?: boolean
506
+ autoComplete?: 'on' | 'off'
507
+ onSubmit?: FormEventHandler
508
+ onReset?: FormEventHandler
509
+ }
510
+ ```
511
+
512
+ #### `FormFieldProps`
513
+
514
+ Form field wrapper props.
515
+
516
+ ```typescript
517
+ interface FormFieldProps extends HTMLElementProps {
518
+ /**
519
+ * Field content.
520
+ */
521
+ children?: Children
522
+ /**
523
+ * Field label.
524
+ */
525
+ label?: string
526
+ /**
527
+ * Field name.
528
+ */
529
+ name?: string
530
+ /**
531
+ * Error message.
532
+ */
533
+ error?: string
534
+ /**
535
+ * Hint/help text.
536
+ */
537
+ hint?: string
538
+ /**
539
+ * Whether the field is required.
540
+ */
541
+ required?: boolean
542
+ }
543
+ ```
544
+
545
+ #### `FormProps`
546
+
547
+ Props for the Form component (wraps inputs with submission handling and validation).
548
+
549
+ ```typescript
550
+ interface FormProps extends FormElementProps {
551
+ /**
552
+ * Form content.
553
+ */
554
+ children?: Children
555
+ /**
556
+ * Submit handler with form data.
557
+ */
558
+ onFormSubmit?: (data: Record<string, unknown>) => void | Promise<void>
559
+ /**
560
+ * Whether the form is submitting.
561
+ */
562
+ submitting?: boolean
563
+ }
564
+ ```
565
+
566
+ #### `GridProps`
567
+
568
+ Grid container props.
569
+
570
+ ```typescript
571
+ interface GridProps extends HTMLElementProps {
572
+ /**
573
+ * Grid content.
574
+ */
575
+ children?: Children
576
+ /**
577
+ * Number of columns.
578
+ */
579
+ columns?: number | string
580
+ /**
581
+ * Number of rows.
582
+ */
583
+ rows?: number | string
584
+ /**
585
+ * Gap between items.
586
+ */
587
+ gap?: Size | string | number
588
+ /**
589
+ * Column gap.
590
+ */
591
+ columnGap?: Size | string | number
592
+ /**
593
+ * Row gap.
594
+ */
595
+ rowGap?: Size | string | number
596
+ }
597
+ ```
598
+
599
+ #### `HTMLElementProps`
600
+
601
+ Base props for HTML elements.
602
+ Framework bindings should extend this with framework-specific attributes.
603
+
604
+ ```typescript
605
+ interface HTMLElementProps extends BaseProps {
606
+ id?: string
607
+ title?: string
608
+ tabIndex?: number
609
+ role?: string
610
+ 'aria-label'?: string
611
+ 'aria-labelledby'?: string
612
+ 'aria-describedby'?: string
613
+ 'aria-hidden'?: boolean
614
+ 'aria-disabled'?: boolean
615
+ 'aria-expanded'?: boolean
616
+ 'aria-selected'?: boolean
617
+ 'aria-checked'?: boolean | 'mixed'
618
+ 'aria-pressed'?: boolean | 'mixed'
619
+ 'aria-invalid'?: boolean
620
+ 'aria-required'?: boolean
621
+ 'aria-readonly'?: boolean
622
+ 'aria-busy'?: boolean
623
+ 'aria-live'?: 'off' | 'polite' | 'assertive'
624
+ onClick?: MouseEventHandler
625
+ onDoubleClick?: MouseEventHandler
626
+ onMouseEnter?: MouseEventHandler
627
+ onMouseLeave?: MouseEventHandler
628
+ onFocus?: FocusEventHandler
629
+ onBlur?: FocusEventHandler
630
+ onKeyDown?: KeyboardEventHandler
631
+ onKeyUp?: KeyboardEventHandler
632
+ onKeyPress?: KeyboardEventHandler
633
+ }
634
+ ```
635
+
636
+ #### `IconProps`
637
+
638
+ Props for {@link Icon}.
639
+
640
+ Extends `SVGProps<SVGSVGElement>` so callers can pass any SVG / HTML
641
+ attribute the underlying `<svg>` accepts, including `data-mol-id`,
642
+ `aria-*`, `role`, event handlers, `style`, etc. — without the
643
+ component needing to enumerate them.
644
+
645
+ ```typescript
646
+ interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'width' | 'height' | 'viewBox' | 'fill'> {
647
+ /**
648
+ * Name of the glyph to look up in the bonded icon set. Typed as
649
+ * {@link IconName} so a typo fails the type-check instead of throwing at
650
+ * render time; sets with extra glyphs augment `CustomIconNames` in
651
+ * `@molecule/app-icons` to widen it.
652
+ */
653
+ name: IconName
654
+ /** Width and height of the rendered SVG in pixels. Defaults to 20. */
655
+ size?: number
656
+ /** Class name forwarded to the root `<svg>`. */
657
+ className?: string
658
+ }
659
+ ```
660
+
661
+ #### `InputElementProps`
662
+
663
+ Base props for input elements.
664
+
665
+ ```typescript
666
+ interface InputElementProps extends HTMLElementProps {
667
+ name?: string
668
+ value?: string | number | readonly string[]
669
+ defaultValue?: string | number | readonly string[]
670
+ placeholder?: string
671
+ required?: boolean
672
+ readOnly?: boolean
673
+ autoFocus?: boolean
674
+ autoComplete?: string
675
+ maxLength?: number
676
+ minLength?: number
677
+ pattern?: string
678
+ onChange?: ChangeEventHandler
679
+ onInput?: FormEventHandler
680
+ }
681
+ ```
682
+
683
+ #### `InputProps`
684
+
685
+ Props for the Input component (text field, email, password, etc.).
686
+
687
+ ```typescript
688
+ interface InputProps extends InputElementProps {
689
+ /**
690
+ * Input type.
691
+ */
692
+ type?: InputType
693
+ /**
694
+ * Input size.
695
+ */
696
+ size?: Size
697
+ /**
698
+ * Horizontal text alignment inside the input (see
699
+ * {@link InputClassOptions.align}). Defaults to the bond's own style.
700
+ */
701
+ align?: 'left' | 'center'
702
+ /**
703
+ * Label text.
704
+ */
705
+ label?: string
706
+ /**
707
+ * Error message.
708
+ */
709
+ error?: string
710
+ /**
711
+ * Hint/help text.
712
+ */
713
+ hint?: string
714
+ /**
715
+ * Element to display on the left.
716
+ */
717
+ leftElement?: Children
718
+ /**
719
+ * Element to display on the right.
720
+ */
721
+ rightElement?: Children
722
+ /**
723
+ * Whether to show a clear button.
724
+ */
725
+ clearable?: boolean
726
+ /**
727
+ * Called when the clear button is clicked.
728
+ */
729
+ onClear?: () => void
730
+ /**
731
+ * Accessible label for the clear button.
732
+ * @default 'Clear'
733
+ */
734
+ clearLabel?: string
735
+ }
736
+ ```
737
+
738
+ #### `LanguagePickerProps`
739
+
740
+ Props for {@link LanguagePicker}.
741
+
742
+ Extends standard `<button>` attributes so callers can pass any extra
743
+ `data-*`, `aria-*`, event handler, or `style` prop without forking the
744
+ component. The named props let apps customize the trigger label, icon,
745
+ size, and modal heading without spreading attribute concerns.
746
+
747
+ ```typescript
748
+ interface LanguagePickerProps extends Omit<
749
+ ButtonHTMLAttributes<HTMLButtonElement>,
750
+ 'aria-label' | 'onClick' | 'type' | 'children'
751
+ > {
752
+ /** i18n key for the trigger button label / aria-label. Defaults to `'footer.language'`. */
753
+ labelKey?: string
754
+ /** Fallback label if the i18n key is missing. Defaults to `'Language'`. */
755
+ labelDefault?: string
756
+ /** i18n key for the modal title. Defaults to `'languagePicker.modalTitle'`. */
757
+ modalTitleKey?: string
758
+ /** Fallback modal title if the i18n key is missing. Defaults to `'Choose language'`. */
759
+ modalTitleDefault?: string
760
+ /** Icon glyph to render before the current locale name. Defaults to `'globe'`. */
761
+ icon?: IconName
762
+ /** Pixel size for the rendered icon. Defaults to `16`. */
763
+ iconSize?: number
764
+ /**
765
+ * What to render inside the trigger button.
766
+ *
767
+ * - `'name'` — globe icon + current locale's native name (e.g. `🌐 English`).
768
+ * This is the default; matches the molecule-dev footer pattern.
769
+ * - `'code'` — globe icon + lowercase locale code (e.g. `🌐 en`). Useful in
770
+ * tight chrome where the long native name (e.g. "Bahasa Indonesia") would wrap.
771
+ * - `'icon'` — globe icon only. Useful in icon-bar headers.
772
+ */
773
+ display?: 'name' | 'code' | 'icon'
774
+ /** Optional className appended to the trigger button. */
775
+ className?: string
776
+ /** Optional render override: receives `{ open }` and replaces the default trigger. */
777
+ renderTrigger?: (open: () => void) => ReactNode
778
+ }
779
+ ```
780
+
781
+ #### `ModalProps`
782
+
783
+ Props for the Modal/Dialog component.
784
+
785
+ ```typescript
786
+ interface ModalProps extends HTMLElementProps {
787
+ /**
788
+ * Whether the modal is open.
789
+ */
790
+ open: boolean
791
+ /**
792
+ * Called when the modal should close.
793
+ */
794
+ onClose: () => void
795
+ /**
796
+ * Modal title.
797
+ */
798
+ title?: string
799
+ /**
800
+ * Modal content.
801
+ */
802
+ children?: Children
803
+ /**
804
+ * Modal size.
805
+ */
806
+ size?: ModalSize
807
+ /**
808
+ * Whether to show a close button.
809
+ */
810
+ showCloseButton?: boolean
811
+ /**
812
+ * Whether clicking the overlay closes the modal.
813
+ */
814
+ closeOnOverlayClick?: boolean
815
+ /**
816
+ * Whether pressing Escape closes the modal.
817
+ */
818
+ closeOnEscape?: boolean
819
+ /**
820
+ * Footer content (typically action buttons).
821
+ */
822
+ footer?: Children
823
+ /**
824
+ * Whether the modal is centered vertically.
825
+ */
826
+ centered?: boolean
827
+ /**
828
+ * Whether to prevent body scroll when open.
829
+ */
830
+ preventScroll?: boolean
831
+ /**
832
+ * Accessible label for the close button.
833
+ * @default 'Close'
834
+ */
835
+ closeLabel?: string
836
+ }
837
+ ```
838
+
839
+ #### `PaginationProps`
840
+
841
+ Props for the Pagination component (page navigation with current page, total, page size, and change callbacks).
842
+
843
+ ```typescript
844
+ interface PaginationProps extends BaseProps {
845
+ /**
846
+ * Current page (1-indexed).
847
+ */
848
+ page: number
849
+ /**
850
+ * Total number of pages.
851
+ */
852
+ totalPages: number
853
+ /**
854
+ * Page change handler.
855
+ */
856
+ onChange: (page: number) => void
857
+ /**
858
+ * Number of sibling pages to show.
859
+ */
860
+ siblings?: number
861
+ /**
862
+ * Number of boundary pages to show.
863
+ */
864
+ boundaries?: number
865
+ /**
866
+ * Pagination size.
867
+ */
868
+ size?: Size
869
+ /**
870
+ * Whether to show first/last buttons.
871
+ */
872
+ showFirstLast?: boolean
873
+ /**
874
+ * Whether to show previous/next buttons.
875
+ */
876
+ showPrevNext?: boolean
877
+ /**
878
+ * Accessible labels for pagination controls.
879
+ */
880
+ labels?: {
881
+ nav?: string
882
+ first?: string
883
+ previous?: string
884
+ next?: string
885
+ last?: string
886
+ goToPage?: (page: number) => string
887
+ }
888
+ }
889
+ ```
890
+
891
+ #### `PanelCloseProviderProps`
892
+
893
+ Props for {@link PanelCloseProvider}.
894
+
895
+ ```typescript
896
+ interface PanelCloseProviderProps {
897
+ /** Callback that dismisses the enclosing drawer/modal. */
898
+ close: () => void
899
+ /** Panel content that may call {@link usePanelClose}. */
900
+ children: ReactNode
901
+ }
902
+ ```
903
+
904
+ #### `ProgressProps`
905
+
906
+ Props for the Progress component.
907
+
908
+ ```typescript
909
+ interface ProgressProps extends BaseProps {
910
+ /**
911
+ * Progress value (0-100).
912
+ */
913
+ value: number
914
+
915
+ /**
916
+ * Maximum value.
917
+ */
918
+ max?: number
919
+
920
+ /**
921
+ * Progress size.
922
+ */
923
+ size?: Size
924
+
925
+ /**
926
+ * Progress color.
927
+ */
928
+ color?: ColorVariant
929
+
930
+ /**
931
+ * Whether to show the value label.
932
+ */
933
+ showValue?: boolean
934
+
935
+ /**
936
+ * Accessible label.
937
+ */
938
+ label?: string
939
+
940
+ /**
941
+ * Whether the progress is indeterminate.
942
+ */
943
+ indeterminate?: boolean
944
+ }
945
+ ```
946
+
947
+ #### `RadioGroupProps`
948
+
949
+ Props for the RadioGroup component.
950
+
951
+ ```typescript
952
+ interface RadioGroupProps<T = string> extends BaseProps {
953
+ /**
954
+ * Radio options.
955
+ */
956
+ options: RadioOption<T>[]
957
+ /**
958
+ * Current value.
959
+ */
960
+ value?: T
961
+ /**
962
+ * Change handler.
963
+ */
964
+ onChange?: (value: T) => void
965
+ /**
966
+ * Radio size.
967
+ */
968
+ size?: Size
969
+ /**
970
+ * Group label.
971
+ */
972
+ label?: string
973
+ /**
974
+ * Shared `name` attribute for the group's radio inputs (used for native
975
+ * form submission). When omitted, a unique per-instance name is generated
976
+ * so separate groups never merge — the visible `label` is deliberately
977
+ * NOT used as the name, because two groups with the same label (e.g. two
978
+ * "Size" pickers) would otherwise form ONE native radio group and
979
+ * deselect each other.
980
+ */
981
+ name?: string
982
+ /**
983
+ * Layout direction.
984
+ */
985
+ direction?: 'horizontal' | 'vertical'
986
+ /**
987
+ * Error message.
988
+ */
989
+ error?: string
990
+ }
991
+ ```
992
+
993
+ #### `RadioOption`
994
+
995
+ A single option in a RadioGroup.
996
+
997
+ ```typescript
998
+ interface RadioOption<T = string> {
999
+ /**
1000
+ * Option value.
1001
+ */
1002
+ value: T
1003
+ /**
1004
+ * Display label.
1005
+ */
1006
+ label: Children
1007
+ /**
1008
+ * Whether the option is disabled.
1009
+ */
1010
+ disabled?: boolean
1011
+ }
1012
+ ```
1013
+
1014
+ #### `SelectElementProps`
1015
+
1016
+ Base props for select elements.
1017
+
1018
+ ```typescript
1019
+ interface SelectElementProps extends HTMLElementProps {
1020
+ name?: string
1021
+ required?: boolean
1022
+ autoFocus?: boolean
1023
+ multiple?: boolean
1024
+ onChange?: ChangeEventHandler
1025
+ }
1026
+ ```
1027
+
1028
+ #### `SelectOption`
1029
+
1030
+ A single option in a Select dropdown.
1031
+
1032
+ ```typescript
1033
+ interface SelectOption<T = string> {
1034
+ /**
1035
+ * Option value.
1036
+ */
1037
+ value: T
1038
+ /**
1039
+ * Display label.
1040
+ */
1041
+ label: string
1042
+ /**
1043
+ * Whether the option is disabled.
1044
+ */
1045
+ disabled?: boolean
1046
+ /**
1047
+ * Option group (for grouped selects).
1048
+ */
1049
+ group?: string
1050
+ }
1051
+ ```
1052
+
1053
+ #### `SelectProps`
1054
+
1055
+ Props for the Select dropdown component (single or multi-select).
1056
+
1057
+ ```typescript
1058
+ interface SelectProps<T = string> extends SelectElementProps {
1059
+ /**
1060
+ * Select options.
1061
+ */
1062
+ options: SelectOption<T>[]
1063
+ /**
1064
+ * Current value.
1065
+ */
1066
+ value?: T
1067
+ /**
1068
+ * Change handler (with typed value).
1069
+ */
1070
+ onValueChange?: (value: T) => void
1071
+ /**
1072
+ * Select size.
1073
+ */
1074
+ size?: Size
1075
+ /**
1076
+ * Label text.
1077
+ */
1078
+ label?: string
1079
+ /**
1080
+ * Placeholder text.
1081
+ */
1082
+ placeholder?: string
1083
+ /**
1084
+ * Error message.
1085
+ */
1086
+ error?: string
1087
+ /**
1088
+ * Hint/help text.
1089
+ */
1090
+ hint?: string
1091
+ /**
1092
+ * Whether to allow clearing the selection.
1093
+ */
1094
+ clearable?: boolean
1095
+ }
1096
+ ```
1097
+
1098
+ #### `SeparatorProps`
1099
+
1100
+ Props for the Separator component.
1101
+
1102
+ ```typescript
1103
+ interface SeparatorProps extends BaseProps {
1104
+ /**
1105
+ * Orientation of the separator.
1106
+ */
1107
+ orientation?: 'horizontal' | 'vertical'
1108
+
1109
+ /**
1110
+ * Decorative separators are purely visual.
1111
+ */
1112
+ decorative?: boolean
1113
+ }
1114
+ ```
1115
+
1116
+ #### `SidebarUserCardProps`
1117
+
1118
+ Props for the {@link SidebarUserCard} component.
1119
+
1120
+ Extends standard `<button>` attributes so callers can pass extra
1121
+ `data-*`, `aria-*`, `style`, or event handler props onto the trigger
1122
+ button without forking. The named props below cover the common
1123
+ customization points.
1124
+
1125
+ ```typescript
1126
+ interface SidebarUserCardProps extends Omit<
1127
+ ButtonHTMLAttributes<HTMLButtonElement>,
1128
+ 'aria-label' | 'onClick' | 'children'
1129
+ > {
1130
+ /**
1131
+ * Panel content shown inside the drawer/modal (typically the app's
1132
+ * `SettingsPanel`). It can dismiss the drawer by calling
1133
+ * `usePanelClose()` — no `onClose` prop-threading required.
1134
+ */
1135
+ children: ReactNode
1136
+ /**
1137
+ * Display name override. When omitted, falls back to
1138
+ * `useAuth().user?.name`, then `email`, then a guest label.
1139
+ */
1140
+ name?: string
1141
+ /**
1142
+ * Secondary line under the name (role, plan, status, etc.).
1143
+ * Apps typically pass something like `t('sidebar.memberStatus', {}, { defaultValue: 'Premium Member' })`.
1144
+ * When omitted and the auth user has an email, the email is shown instead.
1145
+ */
1146
+ secondaryLine?: string
1147
+ /** Optional avatar image URL — overrides `useAuth().user?.avatarUrl`. */
1148
+ avatarUrl?: string
1149
+ /** i18n key for the trigger button's aria-label. Default: `'sidebarUserCard.open'`. */
1150
+ ariaLabelKey?: string
1151
+ /** Fallback aria-label if the i18n key is missing. Default: `'Open account menu'`. */
1152
+ ariaLabelDefault?: string
1153
+ /**
1154
+ * `data-mol-id` for the trigger button. Defaults to
1155
+ * `'sidebar-user-card'`. Pass a different value (e.g. `'user-menu'`)
1156
+ * to disambiguate or align with an app's existing e2e selectors.
1157
+ */
1158
+ dataMolId?: string
1159
+ }
1160
+ ```
1161
+
1162
+ #### `SkeletonProps`
1163
+
1164
+ Props for the Skeleton loading placeholder component.
1165
+
1166
+ ```typescript
1167
+ interface SkeletonProps extends BaseProps {
1168
+ /**
1169
+ * Skeleton width.
1170
+ */
1171
+ width?: string | number
1172
+ /**
1173
+ * Skeleton height.
1174
+ */
1175
+ height?: string | number
1176
+ /**
1177
+ * Whether the skeleton is circular.
1178
+ */
1179
+ circle?: boolean
1180
+ /**
1181
+ * Border radius.
1182
+ */
1183
+ borderRadius?: string | number
1184
+ /**
1185
+ * Animation type.
1186
+ */
1187
+ animation?: 'pulse' | 'wave' | 'none'
1188
+ }
1189
+ ```
1190
+
1191
+ #### `SpacerProps`
1192
+
1193
+ Props for the Spacer layout component (adds whitespace between elements).
1194
+
1195
+ ```typescript
1196
+ interface SpacerProps extends BaseProps {
1197
+ /**
1198
+ * Space size.
1199
+ */
1200
+ size?: Size | string | number
1201
+ /**
1202
+ * Whether the spacer is horizontal.
1203
+ */
1204
+ horizontal?: boolean
1205
+ }
1206
+ ```
1207
+
1208
+ #### `SpinnerProps`
1209
+
1210
+ Props for the Spinner/loading indicator component.
1211
+
1212
+ ```typescript
1213
+ interface SpinnerProps extends BaseProps {
1214
+ /**
1215
+ * Spinner size.
1216
+ */
1217
+ size?: Size
1218
+ /**
1219
+ * Spinner color.
1220
+ */
1221
+ color?: ColorVariant | string
1222
+ /**
1223
+ * Loading label (for accessibility).
1224
+ */
1225
+ label?: string
1226
+ /**
1227
+ * Spinner thickness.
1228
+ */
1229
+ thickness?: number
1230
+ }
1231
+ ```
1232
+
1233
+ #### `SwitchProps`
1234
+
1235
+ Props for the Switch/Toggle component.
1236
+
1237
+ ```typescript
1238
+ interface SwitchProps extends InputElementProps {
1239
+ /**
1240
+ * Switch label.
1241
+ */
1242
+ label?: Children
1243
+ /**
1244
+ * Whether the switch is on.
1245
+ */
1246
+ checked?: boolean
1247
+ /**
1248
+ * Switch size.
1249
+ */
1250
+ size?: Size
1251
+ /**
1252
+ * Color when on.
1253
+ */
1254
+ color?: ColorVariant
1255
+ }
1256
+ ```
1257
+
1258
+ #### `TabItem`
1259
+
1260
+ A single tab in a Tabs component.
1261
+
1262
+ ```typescript
1263
+ interface TabItem<T = string> {
1264
+ /**
1265
+ * Tab value/id.
1266
+ */
1267
+ value: T
1268
+ /**
1269
+ * Tab label.
1270
+ */
1271
+ label: Children
1272
+ /**
1273
+ * Tab content.
1274
+ */
1275
+ content?: Children
1276
+ /**
1277
+ * Whether the tab is disabled.
1278
+ */
1279
+ disabled?: boolean
1280
+ /**
1281
+ * Icon to display.
1282
+ */
1283
+ icon?: Children
1284
+ }
1285
+ ```
1286
+
1287
+ #### `TableColumn`
1288
+
1289
+ Table column definition.
1290
+
1291
+ ```typescript
1292
+ interface TableColumn<T> {
1293
+ /**
1294
+ * Column key (data property).
1295
+ */
1296
+ key: keyof T | string
1297
+ /**
1298
+ * Column header.
1299
+ */
1300
+ header: Children
1301
+ /**
1302
+ * Custom cell renderer.
1303
+ */
1304
+ render?: (value: unknown, row: T, index: number) => Children
1305
+ /**
1306
+ * Column width.
1307
+ */
1308
+ width?: string | number
1309
+ /**
1310
+ * Whether the column is sortable.
1311
+ */
1312
+ sortable?: boolean
1313
+ /**
1314
+ * Text alignment.
1315
+ */
1316
+ align?: 'left' | 'center' | 'right'
1317
+ }
1318
+ ```
1319
+
1320
+ #### `TableProps`
1321
+
1322
+ Props for the Table component.
1323
+
1324
+ ```typescript
1325
+ interface TableProps<T> extends HTMLElementProps {
1326
+ /**
1327
+ * Table data.
1328
+ */
1329
+ data: T[]
1330
+ /**
1331
+ * Column definitions.
1332
+ */
1333
+ columns: TableColumn<T>[]
1334
+ /**
1335
+ * Row key extractor.
1336
+ */
1337
+ rowKey?: keyof T | ((row: T) => string | number)
1338
+ /**
1339
+ * Whether to show borders.
1340
+ */
1341
+ bordered?: boolean
1342
+ /**
1343
+ * Whether rows are striped.
1344
+ */
1345
+ striped?: boolean
1346
+ /**
1347
+ * Whether rows are hoverable.
1348
+ */
1349
+ hoverable?: boolean
1350
+ /**
1351
+ * Table size.
1352
+ */
1353
+ size?: Size
1354
+ /**
1355
+ * Empty state content.
1356
+ */
1357
+ emptyContent?: Children
1358
+ /**
1359
+ * Loading state.
1360
+ */
1361
+ loading?: boolean
1362
+ /**
1363
+ * Sort configuration.
1364
+ */
1365
+ sort?: {
1366
+ key: string
1367
+ direction: 'asc' | 'desc'
1368
+ }
1369
+ /**
1370
+ * Sort change handler.
1371
+ */
1372
+ onSort?: (key: string, direction: 'asc' | 'desc') => void
1373
+ /**
1374
+ * Row click handler.
1375
+ */
1376
+ onRowClick?: (row: T, index: number) => void
1377
+ }
1378
+ ```
1379
+
1380
+ #### `TabsProps`
1381
+
1382
+ Props for the Tabs component (switchable tabbed content panels).
1383
+
1384
+ ```typescript
1385
+ interface TabsProps<T = string> extends BaseProps {
1386
+ /**
1387
+ * Tab items.
1388
+ */
1389
+ items: TabItem<T>[]
1390
+ /**
1391
+ * Current active tab.
1392
+ */
1393
+ value?: T
1394
+ /**
1395
+ * Default active tab.
1396
+ */
1397
+ defaultValue?: T
1398
+ /**
1399
+ * Change handler.
1400
+ */
1401
+ onChange?: (value: T) => void
1402
+ /**
1403
+ * Tab variant.
1404
+ */
1405
+ variant?: 'line' | 'enclosed' | 'soft-rounded' | 'solid-rounded'
1406
+ /**
1407
+ * Tab size.
1408
+ */
1409
+ size?: Size
1410
+ /**
1411
+ * Whether tabs are fitted (take full width).
1412
+ */
1413
+ fitted?: boolean
1414
+ }
1415
+ ```
1416
+
1417
+ #### `TextareaElementProps`
1418
+
1419
+ Base props for textarea elements.
1420
+
1421
+ ```typescript
1422
+ interface TextareaElementProps extends HTMLElementProps {
1423
+ name?: string
1424
+ value?: string
1425
+ defaultValue?: string
1426
+ placeholder?: string
1427
+ required?: boolean
1428
+ readOnly?: boolean
1429
+ autoFocus?: boolean
1430
+ rows?: number
1431
+ cols?: number
1432
+ maxLength?: number
1433
+ minLength?: number
1434
+ wrap?: 'hard' | 'soft' | 'off'
1435
+ onChange?: ChangeEventHandler
1436
+ onInput?: FormEventHandler
1437
+ }
1438
+ ```
1439
+
1440
+ #### `TextareaProps`
1441
+
1442
+ Props for the Textarea component.
1443
+
1444
+ ```typescript
1445
+ interface TextareaProps extends TextareaElementProps {
1446
+ /**
1447
+ * Text size tier (see {@link TextareaClassOptions.size}) — pass the same
1448
+ * `size` as a neighboring Input for identical font sizes.
1449
+ */
1450
+ size?: Size
1451
+ /**
1452
+ * Label text.
1453
+ */
1454
+ label?: string
1455
+ /**
1456
+ * Error message.
1457
+ */
1458
+ error?: string
1459
+ /**
1460
+ * Hint/help text.
1461
+ */
1462
+ hint?: string
1463
+ /**
1464
+ * Whether the textarea auto-resizes.
1465
+ */
1466
+ autoResize?: boolean
1467
+ /**
1468
+ * Minimum number of rows.
1469
+ */
1470
+ minRows?: number
1471
+ /**
1472
+ * Maximum number of rows.
1473
+ */
1474
+ maxRows?: number
1475
+ }
1476
+ ```
1477
+
1478
+ #### `ThemeToggleProps`
1479
+
1480
+ Props for {@link ThemeToggle}.
1481
+
1482
+ Extends standard `<button>` attributes so callers can pass any extra
1483
+ `data-*`, `aria-*`, event handler, or `style` prop without forking the
1484
+ component. The handful of explicitly named props below let apps swap
1485
+ the icon glyphs, label, or size without spreading attribute concerns.
1486
+
1487
+ ```typescript
1488
+ interface ThemeToggleProps extends Omit<
1489
+ ButtonHTMLAttributes<HTMLButtonElement>,
1490
+ 'aria-label' | 'aria-pressed' | 'onClick' | 'type'
1491
+ > {
1492
+ /** i18n key for the `aria-label`. Defaults to `'theme.toggle'`. */
1493
+ ariaLabelKey?: string
1494
+ /** Fallback `aria-label` if the i18n key is missing. Defaults to `'Toggle theme'`. */
1495
+ ariaLabelDefault?: string
1496
+ /** Icon name to render in dark mode. Defaults to `'moon'`. */
1497
+ darkIcon?: IconName
1498
+ /** Icon name to render in light mode. Defaults to `'sun'`. */
1499
+ lightIcon?: IconName
1500
+ /** Pixel size for the rendered icon. Defaults to `20`. */
1501
+ iconSize?: number
1502
+ }
1503
+ ```
1504
+
1505
+ #### `ToastProps`
1506
+
1507
+ Props for the Toast/notification component.
1508
+
1509
+ ```typescript
1510
+ interface ToastProps extends HTMLElementProps {
1511
+ /**
1512
+ * Toast content.
1513
+ */
1514
+ children?: Children
1515
+ /**
1516
+ * Toast title.
1517
+ */
1518
+ title?: string
1519
+ /**
1520
+ * Toast description.
1521
+ */
1522
+ description?: string
1523
+ /**
1524
+ * Toast status/type.
1525
+ */
1526
+ status?: ColorVariant
1527
+ /**
1528
+ * Duration in milliseconds (0 for persistent).
1529
+ */
1530
+ duration?: number
1531
+ /**
1532
+ * Whether the toast is dismissible.
1533
+ */
1534
+ dismissible?: boolean
1535
+ /**
1536
+ * Called when dismissed.
1537
+ */
1538
+ onDismiss?: () => void
1539
+ /**
1540
+ * Toast position.
1541
+ */
1542
+ position?: 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left'
1543
+ /**
1544
+ * Accessible label for the close button.
1545
+ * @default 'Close'
1546
+ */
1547
+ closeLabel?: string
1548
+ }
1549
+ ```
1550
+
1551
+ #### `TooltipProps`
1552
+
1553
+ Props for the Tooltip component (hover/focus popover with informational text).
1554
+
1555
+ ```typescript
1556
+ interface TooltipProps extends HTMLElementProps {
1557
+ /**
1558
+ * Tooltip content.
1559
+ */
1560
+ content: Children
1561
+ /**
1562
+ * Element that triggers the tooltip.
1563
+ */
1564
+ children: Children
1565
+ /**
1566
+ * Tooltip placement.
1567
+ */
1568
+ placement?: TooltipPlacement
1569
+ /**
1570
+ * Delay before showing (ms).
1571
+ */
1572
+ delay?: number
1573
+ /**
1574
+ * Whether the tooltip has an arrow.
1575
+ */
1576
+ hasArrow?: boolean
1577
+ }
1578
+ ```
1579
+
1580
+ #### `UserMenuPopoverPanelProps`
1581
+
1582
+ Props for {@link UserMenuPopoverPanel}.
1583
+
1584
+ ```typescript
1585
+ interface UserMenuPopoverPanelProps {
1586
+ /**
1587
+ * Panel body — typically a set of `<Link>` nav items and a
1588
+ * `<UserMenuPopoverSignOut />`. Rendered inside a `<nav>` below the
1589
+ * built-in identity header.
1590
+ */
1591
+ children: ReactNode
1592
+ /** Extra className composed onto the absolute-positioned panel. */
1593
+ className?: string
1594
+ /** i18n key for the panel's aria-label. Default: `'userMenu.panelLabel'`. */
1595
+ ariaLabelKey?: string
1596
+ /** Fallback aria-label if the i18n key is missing. Default: `'Account menu'`. */
1597
+ ariaLabelDefault?: string
1598
+ /** `data-mol-id` for the panel. Default: `'user-menu-panel'`. */
1599
+ dataMolId?: string
1600
+ }
1601
+ ```
1602
+
1603
+ #### `UserMenuPopoverProps`
1604
+
1605
+ Props for {@link UserMenuPopover}.
1606
+
1607
+ ```typescript
1608
+ interface UserMenuPopoverProps {
1609
+ /**
1610
+ * The trigger and panel — typically `<UserMenuPopoverTrigger />` and
1611
+ * `<UserMenuPopoverPanel>`.
1612
+ */
1613
+ children: ReactNode
1614
+ /**
1615
+ * Label shown when there is no authenticated user. Defaults to the
1616
+ * `userMenuPopover.guest` translation (English fallback `"Account"`).
1617
+ */
1618
+ guestName?: string
1619
+ /** Extra className composed onto the relative-positioned container. */
1620
+ className?: string
1621
+ }
1622
+ ```
1623
+
1624
+ #### `UserMenuPopoverSignOutProps`
1625
+
1626
+ Props for {@link UserMenuPopoverSignOut}.
1627
+
1628
+ ```typescript
1629
+ interface UserMenuPopoverSignOutProps {
1630
+ /** i18n key for the button label. Default: `'userMenu.signOut'`. */
1631
+ labelKey?: string
1632
+ /** Fallback label if the i18n key is missing. Default: `'Sign out'`. */
1633
+ labelDefault?: string
1634
+ /** `data-mol-id` for the button. Default: `'user-menu-sign-out'`. */
1635
+ dataMolId?: string
1636
+ /** Extra className composed onto the button. */
1637
+ className?: string
1638
+ }
1639
+ ```
1640
+
1641
+ #### `UserMenuPopoverTriggerProps`
1642
+
1643
+ Props for {@link UserMenuPopoverTrigger}.
1644
+
1645
+ ```typescript
1646
+ interface UserMenuPopoverTriggerProps {
1647
+ /** i18n key for the trigger's aria-label. Default: `'userMenu.open'`. */
1648
+ ariaLabelKey?: string
1649
+ /** Fallback aria-label if the i18n key is missing. Default: `'Open user menu'`. */
1650
+ ariaLabelDefault?: string
1651
+ /** `data-mol-id` for the trigger button. Default: `'user-menu'`. */
1652
+ dataMolId?: string
1653
+ /** Extra className composed onto the trigger button. */
1654
+ className?: string
1655
+ }
1656
+ ```
1657
+
1658
+ #### `UserMenuProps`
1659
+
1660
+ Props for {@link UserMenu}.
1661
+
1662
+ The inner trigger is a Molecule `<Button>` whose own prop set
1663
+ conflicts with raw `ButtonHTMLAttributes` (color, value, size enums),
1664
+ so this component exposes a curated set of customization points
1665
+ instead of extending HTML attributes. For one-off extra attributes,
1666
+ pass them via `dataMolId` / `className` / `style` props.
1667
+
1668
+ ```typescript
1669
+ interface UserMenuProps {
1670
+ /**
1671
+ * Panel content shown inside the drawer/modal (typically the app's
1672
+ * `SettingsPanel`). It can dismiss the drawer by calling
1673
+ * `usePanelClose()` — no `onClose` prop-threading required.
1674
+ */
1675
+ children: ReactNode
1676
+ /**
1677
+ * i18n key for the trigger button's aria-label. Defaults to
1678
+ * `'userMenu.open'`. Apps whose existing locales use a different key
1679
+ * (e.g. `'userMenu.openButton'`) can override.
1680
+ */
1681
+ ariaLabelKey?: string
1682
+ /** Fallback aria-label if the i18n key is missing. Defaults to `"Open user menu"`. */
1683
+ ariaLabelDefault?: string
1684
+ /** Icon name for the trigger button. Defaults to `'user'`. */
1685
+ triggerIcon?: IconName
1686
+ /** Pixel size for the trigger icon. Defaults to 20. */
1687
+ triggerIconSize?: number
1688
+ /**
1689
+ * `data-mol-id` for the trigger button. Defaults to `'user-menu'`.
1690
+ * Pass an explicit value to disambiguate when the same page mounts
1691
+ * more than one UserMenu.
1692
+ */
1693
+ dataMolId?: string
1694
+ /** Extra className composed onto the trigger button. */
1695
+ className?: string
1696
+ /** Whether the trigger button is disabled. */
1697
+ disabled?: boolean
1698
+ /**
1699
+ * Override the trigger button's click handler. When provided, called
1700
+ * instead of opening the panel — hosts use this to intercept the click
1701
+ * (e.g. to open an auth modal for guest users).
1702
+ */
1703
+ onClick?: () => void
1704
+ }
1705
+ ```
1706
+
1707
+ ### Types
1708
+
1709
+ #### `ButtonVariant`
1710
+
1711
+ Button visual variant styles.
1712
+
1713
+ ```typescript
1714
+ type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'link'
1715
+ ```
1716
+
1717
+ #### `ChangeEventHandler`
1718
+
1719
+ Framework-agnostic change event handler.
1720
+
1721
+ ```typescript
1722
+ type ChangeEventHandler = EventHandler<Event>
1723
+ ```
1724
+
1725
+ #### `Children`
1726
+
1727
+ Framework-agnostic child content.
1728
+ Use `unknown` to allow any framework's node type (ReactNode, VNode, etc.).
1729
+
1730
+ ```typescript
1731
+ type Children = unknown
1732
+ ```
1733
+
1734
+ #### `ColorVariant`
1735
+
1736
+ Semantic color variants used across components for status indication.
1737
+
1738
+ ```typescript
1739
+ type ColorVariant = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info'
1740
+ ```
1741
+
1742
+ #### `EventHandler`
1743
+
1744
+ Framework-agnostic event handler.
1745
+
1746
+ ```typescript
1747
+ type EventHandler<E = Event> = (event: E) => void
1748
+ ```
1749
+
1750
+ #### `FocusEventHandler`
1751
+
1752
+ Framework-agnostic focus event handler.
1753
+
1754
+ ```typescript
1755
+ type FocusEventHandler = EventHandler<FocusEvent>
1756
+ ```
1757
+
1758
+ #### `FormEventHandler`
1759
+
1760
+ Framework-agnostic form event handler.
1761
+
1762
+ ```typescript
1763
+ type FormEventHandler = EventHandler<Event>
1764
+ ```
1765
+
1766
+ #### `InputType`
1767
+
1768
+ Allowed HTML input type attribute values for the Input component.
1769
+
1770
+ ```typescript
1771
+ type InputType =
1772
+ | 'text'
1773
+ | 'email'
1774
+ | 'password'
1775
+ | 'number'
1776
+ | 'tel'
1777
+ | 'url'
1778
+ | 'search'
1779
+ | 'date'
1780
+ | 'time'
1781
+ | 'datetime-local'
1782
+ ```
1783
+
1784
+ #### `KeyboardEventHandler`
1785
+
1786
+ Framework-agnostic keyboard event handler.
1787
+
1788
+ ```typescript
1789
+ type KeyboardEventHandler = EventHandler<KeyboardEvent>
1790
+ ```
1791
+
1792
+ #### `ModalSize`
1793
+
1794
+ Modal size variants including full-screen.
1795
+
1796
+ ```typescript
1797
+ type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'
1798
+ ```
1799
+
1800
+ #### `MouseEventHandler`
1801
+
1802
+ Framework-agnostic mouse event handler.
1803
+
1804
+ ```typescript
1805
+ type MouseEventHandler = EventHandler<MouseEvent>
1806
+ ```
1807
+
1808
+ #### `Size`
1809
+
1810
+ Standard size scale used across all molecule UI components (buttons, inputs, badges, etc.).
1811
+
1812
+ ```typescript
1813
+ type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
1814
+ ```
1815
+
1816
+ #### `TooltipPlacement`
1817
+
1818
+ Position where a tooltip renders relative to its trigger element (top, bottom, left, right, and corner variants).
1819
+
1820
+ ```typescript
1821
+ type TooltipPlacement =
1822
+ 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'
1823
+ ```
1824
+
1825
+ ### Functions
1826
+
1827
+ #### `AuthGuard(props)`
1828
+
1829
+ Route-element guard for authenticated sections of a React Router tree.
1830
+
1831
+ - While `useAuth().state.initialized` is `false`, renders the
1832
+ `loadingFallback` (or the default `<div data-mol-id="auth-guard-loading">{t('common.loading')}</div>`).
1833
+ - If the user is not authenticated, redirects to `loginPath` carrying
1834
+ the attempted location in `state.from` for post-login restoration.
1835
+ - Otherwise renders `children` (or `<Outlet />` if none).
1836
+
1837
+ The default loading tag carries `data-mol-id="auth-guard-loading"`
1838
+ so AI agents and e2e tests can target it reliably. When the caller
1839
+ passes a custom `loadingFallback`, it's the caller's responsibility
1840
+ to include any data-mol-id they need.
1841
+
1842
+ ```typescript
1843
+ function AuthGuard({
1844
+ loadingFallback,
1845
+ loadingKey = 'common.loading',
1846
+ loadingDefault = 'Loading...',
1847
+ loginPath = '/login',
1848
+ onAuthenticated,
1849
+ children,
1850
+ }?: AuthGuardProps): ReactNode
1851
+ ```
1852
+
1853
+ - `props` — {@link AuthGuardProps}
1854
+
1855
+ #### `cn(inputs)`
1856
+
1857
+ Merge class name strings, filtering out falsy values (undefined, null, false).
1858
+
1859
+ ```typescript
1860
+ function cn(inputs?: (string | false | null | undefined)[]): string
1861
+ ```
1862
+
1863
+ - `inputs` — Class name strings or falsy values to be filtered out.
1864
+
1865
+ **Returns:** A single space-separated class string.
1866
+
1867
+ #### `Icon(props)`
1868
+
1869
+ Renders an SVG glyph looked up by `name` from the bonded
1870
+ `@molecule/app-icons` set.
1871
+
1872
+ Handles two icon-data shapes returned by the bond:
1873
+
1874
+ 1. Pre-rendered SVG markup (`icon.svg`) — injected via
1875
+ `dangerouslySetInnerHTML`. The bond is the trust boundary; only
1876
+ bond a set that controls its own SVG strings.
1877
+ 2. Structured paths (`icon.paths`) — rendered as discrete `<path>`
1878
+ children, with optional stroke styling forwarded from the icon set.
1879
+
1880
+ Any extra HTML/SVG attribute (e.g. `data-mol-id`, `aria-label`,
1881
+ `role="img"`, `onClick`) is forwarded to the root `<svg>` via spread.
1882
+
1883
+ Decorative by default: when the caller passes no `aria-label` /
1884
+ `aria-labelledby` / `role`, the SVG is rendered `aria-hidden` +
1885
+ `focusable="false"` so screen readers skip it (an unnamed inline SVG is
1886
+ announced as a stray "image" by some combos). Passing any of those props
1887
+ opts the icon into the accessibility tree.
1888
+
1889
+ ```typescript
1890
+ function Icon({ name, size = 20, className, ...rest }: IconProps): React.JSX.Element
1891
+ ```
1892
+
1893
+ - `props` — {@link IconProps}
1894
+
1895
+ **Returns:** An `<svg>` element rendering the named glyph.
1896
+
1897
+ #### `LanguagePicker(props)`
1898
+
1899
+ Globe-icon button that opens a modal grid of every locale registered
1900
+ with the bonded i18n provider. Clicking a locale calls `setLocale`
1901
+ and closes the modal.
1902
+
1903
+ Reads `locale`, `setLocale`, and `locales` from {@link useTranslation},
1904
+ so the list of choices stays in sync with whatever set the
1905
+ `setupI18nDefault` (or any other i18n setup) registered. No hardcoded
1906
+ language list — adding a locale to the i18n bond adds it to the picker.
1907
+
1908
+ Molecule-convention defaults baked in:
1909
+
1910
+ - `data-mol-id="language-picker-trigger"` on the trigger button
1911
+ - `data-mol-id="language-picker-modal"` on the modal dialog
1912
+ - `data-mol-id="language-picker-option-<code>"` on each locale button
1913
+ - `data-active` on the currently-selected locale button
1914
+ - `aria-label` from the `footer.language` i18n key (default `"Language"`)
1915
+
1916
+ ```typescript
1917
+ function LanguagePicker({
1918
+ labelKey = 'footer.language',
1919
+ labelDefault = 'Language',
1920
+ modalTitleKey = 'languagePicker.modalTitle',
1921
+ modalTitleDefault = 'Choose language',
1922
+ icon = 'globe',
1923
+ iconSize = 16,
1924
+ display = 'name',
1925
+ className,
1926
+ renderTrigger,
1927
+ ...rest
1928
+ }?: LanguagePickerProps): JSX.Element
1929
+ ```
1930
+
1931
+ - `props` — {@link LanguagePickerProps}
1932
+
1933
+ #### `PanelCloseProvider(props)`
1934
+
1935
+ Provides the panel-close callback to descendants. Rendered internally
1936
+ by `UserMenu` and `SidebarUserCard` around their `children`; apps do
1937
+ not normally render this directly.
1938
+
1939
+ ```typescript
1940
+ function PanelCloseProvider({ close, children }: PanelCloseProviderProps): JSX.Element
1941
+ ```
1942
+
1943
+ - `props` — The close callback and the panel content.
1944
+
1945
+ **Returns:** The children wrapped in the close-context provider.
1946
+
1947
+ #### `SidebarUserCard(props)`
1948
+
1949
+ Sidebar-resident user-account card: avatar + name + status line, opens
1950
+ the app's settings drawer on click.
1951
+
1952
+ Drop-in replacement for `<UserMenu />` when the trigger lives inside a
1953
+ vertical sidebar (e.g. as the `userMenu` slot of `<SidebarLayout>`).
1954
+ Reads name/email/avatar from `useAuth()` by default; pass explicit
1955
+ `name` / `secondaryLine` / `avatarUrl` props to override.
1956
+
1957
+ Ships with `data-mol-id="sidebar-user-card"` on the trigger button
1958
+ by default for AI-agent / e2e selection. Callers can override by
1959
+ passing `data-mol-id` as an extra prop.
1960
+
1961
+ ```typescript
1962
+ function SidebarUserCard({
1963
+ children,
1964
+ name,
1965
+ secondaryLine,
1966
+ avatarUrl,
1967
+ ariaLabelKey = 'sidebarUserCard.open',
1968
+ ariaLabelDefault = 'Open account menu',
1969
+ dataMolId = 'sidebar-user-card',
1970
+ className,
1971
+ ...rest
1972
+ }: SidebarUserCardProps): JSX.Element
1973
+ ```
1974
+
1975
+ #### `ThemeToggle(props)`
1976
+
1977
+ Button that flips the wired theme bond between light and dark.
1978
+
1979
+ Reads `mode` and `toggleTheme` from `useTheme()` and shows the
1980
+ configured dark/light icon accordingly. Ships with molecule
1981
+ conventions out of the box:
1982
+
1983
+ - `data-mol-id="theme-toggle"` for AI-agent / e2e selection
1984
+ - `data-mode={mode}` so tests can assert current state via DOM
1985
+ - `aria-pressed={mode === 'dark'}` for screen-reader state
1986
+ - `aria-label` from the `theme.toggle` i18n key (default `"Toggle theme"`)
1987
+
1988
+ Every per-app variant the fleet was carrying — extra `data-*` attrs,
1989
+ additional `aria-*` flags, custom event handlers — is now absorbed
1990
+ via the spread of unknown props. Apps that need different icons or
1991
+ label text use the named props.
1992
+
1993
+ ```typescript
1994
+ function ThemeToggle({
1995
+ ariaLabelKey = 'theme.toggle',
1996
+ ariaLabelDefault = 'Toggle theme',
1997
+ darkIcon = 'moon',
1998
+ lightIcon = 'sun',
1999
+ iconSize = 20,
2000
+ className,
2001
+ ...rest
2002
+ }?: ThemeToggleProps): JSX.Element
2003
+ ```
2004
+
2005
+ - `props` — {@link ThemeToggleProps}
2006
+
2007
+ #### `ToastProvider(props)`
2008
+
2009
+ Provider component that manages global toast state.
2010
+
2011
+ ```typescript
2012
+ function ToastProvider({
2013
+ children,
2014
+ position = 'bottom-right',
2015
+ }: ToastProviderProps): React.JSX.Element
2016
+ ```
2017
+
2018
+ - `props` — The component props.
2019
+ - `props.children` — The child elements to render within the provider.
2020
+ - `props.position` — The default position for toasts.
2021
+
2022
+ **Returns:** The rendered provider with toast container.
2023
+
2024
+ #### `usePanelClose()`
2025
+
2026
+ Returns the callback that dismisses the drawer the current panel is
2027
+ mounted in. Safe to call anywhere — returns a no-op when no enclosing
2028
+ `UserMenu` / `SidebarUserCard` provides one (e.g. a `SettingsPanel`
2029
+ rendered as a standalone page).
2030
+
2031
+ ```typescript
2032
+ function usePanelClose(): () => void
2033
+ ```
2034
+
2035
+ **Returns:** A function that closes the enclosing drawer, or a no-op.
2036
+
2037
+ #### `UserMenu(props)`
2038
+
2039
+ Avatar-style trigger that opens the app's settings panel in a drawer.
2040
+
2041
+ The panel content is passed as `children` so apps can mount their own
2042
+ `SettingsPanel` (which diverges per app) inside the shared drawer
2043
+ chrome. Panel content dismisses the drawer via `usePanelClose()`.
2044
+
2045
+ Ships with `data-mol-id="user-menu"` on the trigger button by
2046
+ default for AI-agent / e2e selection.
2047
+
2048
+ ```typescript
2049
+ function UserMenu({
2050
+ children,
2051
+ ariaLabelKey = 'userMenu.open',
2052
+ ariaLabelDefault = 'Open user menu',
2053
+ triggerIcon = 'user',
2054
+ triggerIconSize = 20,
2055
+ dataMolId = 'user-menu',
2056
+ className,
2057
+ disabled,
2058
+ onClick,
2059
+ }: UserMenuProps): JSX.Element
2060
+ ```
2061
+
2062
+ #### `UserMenuPopover(props)`
2063
+
2064
+ Container for the inline popover account menu. Owns the open state and
2065
+ the auto-dismiss behaviour (route change, `popstate`, outside click,
2066
+ `Escape`), and provides the resolved account identity to its
2067
+ sub-components via context.
2068
+
2069
+ ```typescript
2070
+ function UserMenuPopover({
2071
+ children,
2072
+ guestName,
2073
+ className,
2074
+ }: UserMenuPopoverProps): React.JSX.Element
2075
+ ```
2076
+
2077
+ - `props` — The popover children, optional guest label, and className.
2078
+
2079
+ **Returns:** The relative-positioned popover container.
2080
+
2081
+ #### `UserMenuPopoverPanel(props)`
2082
+
2083
+ The popover panel: an absolutely-positioned card with a built-in
2084
+ identity header (name + email) and a `<nav>` wrapping the caller's nav
2085
+ items. Renders nothing while the popover is closed.
2086
+
2087
+ Provides only the structural concerns (absolute positioning above the
2088
+ trigger, `rounded-xl` border frame, the header/nav layout). Cosmetic
2089
+ choices — width, background, padding, shadow — are per-app: pass them
2090
+ via `className`. `cn()` concatenates (it does not tailwind-merge), so
2091
+ the panel never bakes a width/background the caller would have to
2092
+ fight.
2093
+
2094
+ ```typescript
2095
+ function UserMenuPopoverPanel({
2096
+ children,
2097
+ className,
2098
+ ariaLabelKey = 'userMenu.panelLabel',
2099
+ ariaLabelDefault = 'Account menu',
2100
+ dataMolId = 'user-menu-panel',
2101
+ }: UserMenuPopoverPanelProps): React.JSX.Element | null
2102
+ ```
2103
+
2104
+ - `props` — The nav children, className, and aria-label overrides.
2105
+
2106
+ **Returns:** The popover panel, or `null` when closed.
2107
+
2108
+ #### `UserMenuPopoverSignOut(props)`
2109
+
2110
+ The sign-out nav item — closes the popover and calls `auth.logout()`.
2111
+ Drop it in as the last child of `<UserMenuPopoverPanel>`.
2112
+
2113
+ ```typescript
2114
+ function UserMenuPopoverSignOut({
2115
+ labelKey = 'userMenu.signOut',
2116
+ labelDefault = 'Sign out',
2117
+ dataMolId = 'user-menu-sign-out',
2118
+ className,
2119
+ }: UserMenuPopoverSignOutProps): React.JSX.Element
2120
+ ```
2121
+
2122
+ - `props` — Label overrides, `data-mol-id`, and className.
2123
+
2124
+ **Returns:** The sign-out button.
2125
+
2126
+ #### `UserMenuPopoverTrigger(props)`
2127
+
2128
+ The trigger button: an initials avatar plus the account name and email,
2129
+ styled as a full-width sidebar card. Toggles the popover panel.
2130
+
2131
+ ```typescript
2132
+ function UserMenuPopoverTrigger({
2133
+ ariaLabelKey = 'userMenu.open',
2134
+ ariaLabelDefault = 'Open user menu',
2135
+ dataMolId = 'user-menu',
2136
+ className,
2137
+ }: UserMenuPopoverTriggerProps): React.JSX.Element
2138
+ ```
2139
+
2140
+ - `props` — aria-label overrides, `data-mol-id`, and className.
2141
+
2142
+ **Returns:** The popover trigger button.
2143
+
2144
+ #### `useToast()`
2145
+
2146
+ Hook to access the toast context for adding and removing toasts.
2147
+
2148
+ ```typescript
2149
+ function useToast(): ToastContextValue
2150
+ ```
2151
+
2152
+ **Returns:** The toast context value with toast management methods.
2153
+
2154
+ #### `useUserMenuPopoverClose()`
2155
+
2156
+ Returns a callback that closes the enclosing `UserMenuPopover`. Useful
2157
+ for nav-item `onClick` handlers that should dismiss the popover even
2158
+ when they don't change the route. Returns a no-op when called outside
2159
+ a `UserMenuPopover`.
2160
+
2161
+ ```typescript
2162
+ function useUserMenuPopoverClose(): () => void
2163
+ ```
2164
+
2165
+ **Returns:** A function that closes the popover.
2166
+
2167
+ ### Constants
2168
+
2169
+ #### `Accordion`
2170
+
2171
+ Accordion component.
2172
+
2173
+ ```typescript
2174
+ const Accordion: React.ForwardRefExoticComponent<
2175
+ AccordionProps<string> & React.RefAttributes<HTMLDivElement>
2176
+ >
2177
+ ```
2178
+
2179
+ #### `Alert`
2180
+
2181
+ Alert component.
2182
+
2183
+ `role="alert"` is assertive: it interrupts a screen reader immediately,
2184
+ which is correct ONLY for content that appears dynamically (a validation
2185
+ error after submit, a save failure). An Alert rendered statically with
2186
+ the rest of the page (an informational banner already in the initial
2187
+ render) has nothing to interrupt — announcing it assertively on mount is
2188
+ the same over-announcing trap the Toast role fix addresses. `live`
2189
+ (default `true`, matching the previous unconditional behavior so no
2190
+ existing dynamic-error usage silently goes quiet) makes this honest and
2191
+ caller-controlled: pass `live={false}` for a banner that is part of the
2192
+ page's normal content, and it announces politely (`role="status"`)
2193
+ instead of interrupting.
2194
+
2195
+ ```typescript
2196
+ const Alert: React.ForwardRefExoticComponent<
2197
+ AlertProps & { live?: boolean } & React.RefAttributes<HTMLDivElement>
2198
+ >
2199
+ ```
2200
+
2201
+ #### `Avatar`
2202
+
2203
+ Avatar component.
2204
+
2205
+ ```typescript
2206
+ const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLDivElement>>
2207
+ ```
2208
+
2209
+ #### `Badge`
2210
+
2211
+ Badge component.
2212
+
2213
+ ```typescript
2214
+ const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>
2215
+ ```
2216
+
2217
+ #### `Button`
2218
+
2219
+ Button component.
2220
+
2221
+ ```typescript
2222
+ const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>
2223
+ ```
2224
+
2225
+ #### `Card`
2226
+
2227
+ Card component.
2228
+
2229
+ ```typescript
2230
+ const Card: React.ForwardRefExoticComponent<
2231
+ CardProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
2232
+ >
2233
+ ```
2234
+
2235
+ #### `CardContent`
2236
+
2237
+ Card content component.
2238
+
2239
+ ```typescript
2240
+ const CardContent: React.ForwardRefExoticComponent<
2241
+ React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2242
+ >
2243
+ ```
2244
+
2245
+ #### `CardDescription`
2246
+
2247
+ Card description component.
2248
+
2249
+ ```typescript
2250
+ const CardDescription: React.ForwardRefExoticComponent<
2251
+ React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>
2252
+ >
2253
+ ```
2254
+
2255
+ #### `CardFooter`
2256
+
2257
+ Card footer component.
2258
+
2259
+ ```typescript
2260
+ const CardFooter: React.ForwardRefExoticComponent<
2261
+ React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2262
+ >
2263
+ ```
2264
+
2265
+ #### `CardHeader`
2266
+
2267
+ Card header component.
2268
+
2269
+ ```typescript
2270
+ const CardHeader: React.ForwardRefExoticComponent<
2271
+ React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
2272
+ >
2273
+ ```
2274
+
2275
+ #### `CardTitle`
2276
+
2277
+ Card title component.
2278
+
2279
+ ```typescript
2280
+ const CardTitle: React.ForwardRefExoticComponent<
2281
+ React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLHeadingElement>
2282
+ >
2283
+ ```
2284
+
2285
+ #### `Checkbox`
2286
+
2287
+ Checkbox component.
2288
+
2289
+ ```typescript
2290
+ const Checkbox: React.ForwardRefExoticComponent<
2291
+ CheckboxProps & React.RefAttributes<HTMLInputElement>
2292
+ >
2293
+ ```
2294
+
2295
+ #### `Container`
2296
+
2297
+ Container component.
2298
+
2299
+ ```typescript
2300
+ const Container: React.ForwardRefExoticComponent<
2301
+ ContainerProps & React.RefAttributes<HTMLDivElement>
2302
+ >
2303
+ ```
2304
+
2305
+ #### `Dropdown`
2306
+
2307
+ Dropdown component.
2308
+
2309
+ Implements the WAI-ARIA APG menu-button pattern. The trigger is made a
2310
+ real, keyboard-operable control: if `trigger` is a single element (a
2311
+ `<button>`, an icon `<Button>`, …) it is cloned with `aria-haspopup`,
2312
+ `aria-expanded`, `aria-controls`, and the open/keyboard handlers merged
2313
+ onto it directly — no extra wrapper, no double focus stop. If `trigger`
2314
+ is not a single element (text, a fragment, multiple nodes), it is wrapped
2315
+ in a `role="button" tabIndex={0}` container instead so keyboard/AT users
2316
+ can still reach it. Enter/Space/ArrowDown open the menu and move focus to
2317
+ the first item (ArrowUp opens to the last item); once open, ArrowUp/Down/
2318
+ Home/End roving-navigate the `role="menuitem"` items, Escape closes and
2319
+ returns focus to the trigger, and Tab closes the menu in sync with focus
2320
+ leaving it (matching native menus, which do not trap Tab).
2321
+
2322
+ ```typescript
2323
+ const Dropdown: React.ForwardRefExoticComponent<
2324
+ DropdownProps<string> & React.RefAttributes<HTMLDivElement>
2325
+ >
2326
+ ```
2327
+
2328
+ #### `DropdownLabel`
2329
+
2330
+ Dropdown label for grouping items.
2331
+
2332
+ ```typescript
2333
+ const DropdownLabel: React.ForwardRefExoticComponent<
2334
+ { children: React.ReactNode; className?: string } & React.RefAttributes<HTMLDivElement>
2335
+ >
2336
+ ```
2337
+
2338
+ #### `DropdownSeparator`
2339
+
2340
+ Dropdown separator for dividing groups.
2341
+
2342
+ ```typescript
2343
+ const DropdownSeparator: React.ForwardRefExoticComponent<
2344
+ { className?: string } & React.RefAttributes<HTMLDivElement>
2345
+ >
2346
+ ```
2347
+
2348
+ #### `EmptyState`
2349
+
2350
+ EmptyState component.
2351
+
2352
+ Displays a centered placeholder with an optional icon, title, description,
2353
+ and a primary action when a list or section has no content.
2354
+
2355
+ ```typescript
2356
+ const EmptyState: React.ForwardRefExoticComponent<
2357
+ EmptyStateProps & React.RefAttributes<HTMLDivElement>
2358
+ >
2359
+ ```
2360
+
2361
+ #### `Flex`
2362
+
2363
+ Flex container component.
2364
+
2365
+ ```typescript
2366
+ const Flex: React.ForwardRefExoticComponent<FlexProps & React.RefAttributes<HTMLDivElement>>
2367
+ ```
2368
+
2369
+ #### `FloatingInput`
2370
+
2371
+ An input with a floating label.
2372
+
2373
+ Shows the placeholder text as a small uppercase label always visible at
2374
+ the top of the input. On focus the label turns primary-colored.
2375
+
2376
+ Works as both a controlled and an uncontrolled input: when `value` is
2377
+ omitted, the component tracks its own state seeded from `defaultValue`
2378
+ and still forwards every `onChange` event to the caller.
2379
+
2380
+ The floating text is a real `<label htmlFor>` (not a bare `<span>`), so
2381
+ it is the input's programmatic accessible name via label association —
2382
+ previously the accessible name came only from `placeholder` (stripped by
2383
+ some AT/browser combos once the field has a value), and clicking the
2384
+ floating text did nothing because it wasn't associated with anything.
2385
+ `id` falls back to `useId()` when the caller doesn't pass one, mirroring
2386
+ Input/Select/Textarea's id-collision fix.
2387
+
2388
+ ```typescript
2389
+ const FloatingInput: ForwardRefExoticComponent<FloatingInputProps & RefAttributes<HTMLInputElement>>
2390
+ ```
2391
+
2392
+ #### `Form`
2393
+
2394
+ Form component.
2395
+
2396
+ ```typescript
2397
+ const Form: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>
2398
+ ```
2399
+
2400
+ #### `FormField`
2401
+
2402
+ Form field wrapper component.
2403
+
2404
+ ```typescript
2405
+ const FormField: React.ForwardRefExoticComponent<
2406
+ FormFieldProps & React.RefAttributes<HTMLDivElement>
2407
+ >
2408
+ ```
2409
+
2410
+ #### `Grid`
2411
+
2412
+ Grid container component.
2413
+
2414
+ ```typescript
2415
+ const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<HTMLDivElement>>
2416
+ ```
2417
+
2418
+ #### `Input`
2419
+
2420
+ Input component.
2421
+
2422
+ ```typescript
2423
+ const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>
2424
+ ```
2425
+
2426
+ #### `Label`
2427
+
2428
+ Label component.
2429
+
2430
+ ```typescript
2431
+ const Label: React.ForwardRefExoticComponent<
2432
+ React.LabelHTMLAttributes<HTMLLabelElement> & {
2433
+ required?: boolean
2434
+ } & React.RefAttributes<HTMLLabelElement>
2435
+ >
2436
+ ```
2437
+
2438
+ #### `Modal`
2439
+
2440
+ Modal component.
2441
+
2442
+ Renders into a `document.body` portal. Forwards any extra `data-*` or
2443
+ `aria-*` props on the rest spread to the inner dialog `<div>` (e.g.
2444
+ callers commonly pass `data-mol-id="some-modal"` for AI-agent / e2e
2445
+ selectors).
2446
+
2447
+ The internal close button always carries `data-mol-id="modal-close"`
2448
+ as the molecule-convention default for the one fixed interactive
2449
+ element inside the chrome.
2450
+
2451
+ Implements the WAI-ARIA APG dialog (modal) pattern: on open, focus moves
2452
+ to the first focusable element inside the dialog (or the dialog itself
2453
+ when it has none); Tab/Shift+Tab are trapped inside the dialog; on close,
2454
+ focus returns to whatever was focused before the dialog opened. Stacked
2455
+ dialogs (a confirm above a drawer) each register on a module-level stack —
2456
+ Escape and the Tab trap only act for the TOPMOST dialog, and the body
2457
+ scroll lock is reference-counted so closing one of several open dialogs
2458
+ never unlocks scroll behind the ones still open.
2459
+
2460
+ ```typescript
2461
+ const Modal: React.ForwardRefExoticComponent<
2462
+ ModalProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
2463
+ >
2464
+ ```
2465
+
2466
+ #### `PageHeader`
2467
+
2468
+ PageHeader component.
2469
+
2470
+ Renders a page title with optional breadcrumb trail, description, and
2471
+ action buttons for a consistent page heading area.
2472
+
2473
+ ```typescript
2474
+ const PageHeader: React.ForwardRefExoticComponent<
2475
+ PageHeaderProps & React.RefAttributes<HTMLDivElement>
2476
+ >
2477
+ ```
2478
+
2479
+ #### `PageShell`
2480
+
2481
+ PageShell component.
2482
+
2483
+ Provides the top-level layout for authenticated pages with an optional
2484
+ collapsible sidebar, a top bar, and a scrollable main content area.
2485
+
2486
+ ```typescript
2487
+ const PageShell: React.ForwardRefExoticComponent<
2488
+ PageShellProps & React.RefAttributes<HTMLDivElement>
2489
+ >
2490
+ ```
2491
+
2492
+ #### `Pagination`
2493
+
2494
+ Pagination component.
2495
+
2496
+ ```typescript
2497
+ const Pagination: React.ForwardRefExoticComponent<
2498
+ PaginationProps & React.RefAttributes<HTMLElement>
2499
+ >
2500
+ ```
2501
+
2502
+ #### `Progress`
2503
+
2504
+ Progress component.
2505
+
2506
+ ```typescript
2507
+ const Progress: React.ForwardRefExoticComponent<ProgressProps & React.RefAttributes<HTMLDivElement>>
2508
+ ```
2509
+
2510
+ #### `RadioGroup`
2511
+
2512
+ RadioGroup component.
2513
+
2514
+ ```typescript
2515
+ const RadioGroup: React.ForwardRefExoticComponent<
2516
+ RadioGroupProps<string> & React.RefAttributes<HTMLDivElement>
2517
+ >
2518
+ ```
2519
+
2520
+ #### `Select`
2521
+
2522
+ Select component.
2523
+
2524
+ ```typescript
2525
+ const Select: React.ForwardRefExoticComponent<
2526
+ SelectProps<string> & React.RefAttributes<HTMLSelectElement>
2527
+ >
2528
+ ```
2529
+
2530
+ #### `Separator`
2531
+
2532
+ Separator component.
2533
+
2534
+ ```typescript
2535
+ const Separator: React.ForwardRefExoticComponent<
2536
+ SeparatorProps & React.RefAttributes<HTMLDivElement>
2537
+ >
2538
+ ```
2539
+
2540
+ #### `Skeleton`
2541
+
2542
+ Skeleton component.
2543
+
2544
+ ```typescript
2545
+ const Skeleton: React.ForwardRefExoticComponent<SkeletonProps & React.RefAttributes<HTMLDivElement>>
2546
+ ```
2547
+
2548
+ #### `SkeletonCircle`
2549
+
2550
+ Skeleton circle (avatar placeholder).
2551
+
2552
+ ```typescript
2553
+ const SkeletonCircle: React.ForwardRefExoticComponent<
2554
+ { size?: number; className?: string } & React.RefAttributes<HTMLDivElement>
2555
+ >
2556
+ ```
2557
+
2558
+ #### `SkeletonText`
2559
+
2560
+ Skeleton text line.
2561
+
2562
+ ```typescript
2563
+ const SkeletonText: React.ForwardRefExoticComponent<
2564
+ { lines?: number; className?: string } & React.RefAttributes<HTMLDivElement>
2565
+ >
2566
+ ```
2567
+
2568
+ #### `Spacer`
2569
+
2570
+ Spacer component.
2571
+
2572
+ ```typescript
2573
+ const Spacer: React.ForwardRefExoticComponent<SpacerProps & React.RefAttributes<HTMLDivElement>>
2574
+ ```
2575
+
2576
+ #### `Spinner`
2577
+
2578
+ Spinner component.
2579
+
2580
+ Extracts data-* and aria-* props from the rest spread so callers can
2581
+ pass `data-mol-id`, custom `aria-*` overrides, etc. without forking.
2582
+
2583
+ ```typescript
2584
+ const Spinner: React.ForwardRefExoticComponent<
2585
+ SpinnerProps & { 'data-mol-id'?: string } & React.RefAttributes<HTMLDivElement>
2586
+ >
2587
+ ```
2588
+
2589
+ #### `Switch`
2590
+
2591
+ Switch component.
2592
+
2593
+ ```typescript
2594
+ const Switch: React.ForwardRefExoticComponent<SwitchProps & React.RefAttributes<HTMLButtonElement>>
2595
+ ```
2596
+
2597
+ #### `Table`
2598
+
2599
+ Table component.
2600
+
2601
+ ```typescript
2602
+ const Table: React.ForwardRefExoticComponent<
2603
+ TableProps<Record<string, unknown>> & React.RefAttributes<HTMLTableElement>
2604
+ >
2605
+ ```
2606
+
2607
+ #### `Tabs`
2608
+
2609
+ Tabs component.
2610
+
2611
+ ```typescript
2612
+ const Tabs: React.ForwardRefExoticComponent<TabsProps<string> & React.RefAttributes<HTMLDivElement>>
2613
+ ```
2614
+
2615
+ #### `Textarea`
2616
+
2617
+ Textarea component.
2618
+
2619
+ ```typescript
2620
+ const Textarea: React.ForwardRefExoticComponent<
2621
+ TextareaProps & React.RefAttributes<HTMLTextAreaElement>
2622
+ >
2623
+ ```
2624
+
2625
+ #### `Toast`
2626
+
2627
+ Single Toast component.
2628
+
2629
+ The auto-dismiss countdown pauses on hover AND focus (WCAG 2.2.1) and
2630
+ resumes with whatever time was left — a slow reader or a keyboard/AT
2631
+ user interacting with the toast never has it disappear mid-read. The
2632
+ announced role follows `status`: `warning`/`error` get the assertive
2633
+ `role="alert"`; every other status (`info`, `success`, the default) gets
2634
+ the polite `role="status"` so routine confirmations don't interrupt a
2635
+ screen reader mid-sentence the way an assertive announcement does.
2636
+
2637
+ ```typescript
2638
+ const Toast: React.ForwardRefExoticComponent<ToastProps & React.RefAttributes<HTMLDivElement>>
2639
+ ```
2640
+
2641
+ #### `ToastContainer`
2642
+
2643
+ Container that positions toasts on screen via a portal.
2644
+
2645
+ ```typescript
2646
+ const ToastContainer: React.ForwardRefExoticComponent<
2647
+ ToastContainerProps & React.RefAttributes<HTMLDivElement>
2648
+ >
2649
+ ```
2650
+
2651
+ #### `Tooltip`
2652
+
2653
+ Tooltip component.
2654
+
2655
+ `children` must be a single valid React element (e.g. one `<button>` or
2656
+ one custom component that forwards `aria-describedby`) for the tooltip's
2657
+ content to be programmatically associated with it — this is what lets a
2658
+ screen reader announce the tooltip text for the actually-focused control.
2659
+ A non-element `children` (plain text, a fragment, multiple nodes) still
2660
+ shows the tooltip visually on hover/focus, but without that association.
2661
+ `hasArrow` renders a small themed pointer at the resolved `placement`
2662
+ edge.
2663
+
2664
+ ```typescript
2665
+ const Tooltip: React.ForwardRefExoticComponent<TooltipProps & React.RefAttributes<HTMLDivElement>>
2666
+ ```
2667
+
2668
+ ## Injection Notes
2669
+
2670
+ ### Requirements
2671
+
2672
+ Peer dependencies:
2673
+
2674
+ - `@molecule/app-i18n` ^1.0.0
2675
+ - `@molecule/app-icons` ^1.0.0
2676
+ - `@molecule/app-react` ^1.0.0
2677
+ - `@molecule/app-ui` ^1.0.0
2678
+ - `react` ^18.0.0 || ^19.0.0
2679
+ - `react-dom` ^18.0.0 || ^19.0.0
2680
+ - `react-router` ^7.0.0 || ^8.0.0
2681
+
2682
+ ### Runtime Dependencies
2683
+
2684
+ - `@molecule/app-i18n`
2685
+ - `@molecule/app-icons`
2686
+ - `@molecule/app-react`
2687
+ - `@molecule/app-ui`
2688
+ - `react`
2689
+ - `react-dom`
2690
+ - `react-router`
2691
+
2692
+ Wiring prerequisites — get these right before debugging anything else:
2693
+
2694
+ - **A ClassMap bond must be set before first render.** Every component resolves styling via
2695
+ `getClassMap()` from `@molecule/app-ui`, which THROWS ("No UIClassMap has been set") until
2696
+ `setClassMap(...)` runs with a bond like `@molecule/app-ui-tailwind`. Scaffolded apps do
2697
+ this in `bonds/index.ts` — keep that import first in `main.tsx`.
2698
+ - **Some components require molecule providers from `@molecule/app-react`** and throw without
2699
+ them: `UserMenu`, `UserMenuPopover`, `LanguagePicker`, `SidebarUserCard`, `AuthGuard`, and
2700
+ `ThemeToggle` need `I18nProvider` (via `MoleculeProvider i18n={...}`); `ThemeToggle` also
2701
+ needs `ThemeProvider`; `AuthGuard` also needs `AuthProvider`. The primitive components
2702
+ (Button, Modal, Input, …) need only the ClassMap.
2703
+ - **Router-linked components** (`UserMenu`, `UserMenuPopover`, `SidebarUserCard`, `Dropdown`
2704
+ item `href`s, `AuthGuard` redirects) render react-router `<Link>`/navigation — they need a
2705
+ react-router context (`<BrowserRouter>`) and, in workspace dev setups, the Vite
2706
+ `resolve.dedupe: ['react', 'react-dom', 'react-router', 'react-router']` entry; a
2707
+ duplicate copy surfaces as "useHref may be used only in the context of a <Router>".
2708
+ - **`UserMenu` panel content is `children`** (rendered inside the popover, with
2709
+ `PanelClose`/`usePanelClose` available) — there is no `renderPanel` prop.
2710
+ - **`Icon` names are kebab-case `IconName`s from `@molecule/app-icons`** — an unknown name is
2711
+ a runtime error, not a blank. Extend via `CustomIconNames` augmentation, never raw SVG.
2712
+ - **Name collisions with feature packages** — several feature packages export a
2713
+ same-named component; import from the package whose props/behavior you want:
2714
+ - `EmptyState` — also `@molecule/app-empty-state-react` (adds an icon badge,
2715
+ per-brand `className`/`dataMolId`, and a companion `<CtaCard>`). THIS one is the
2716
+ primitive icon/title/description/action variant.
2717
+ - `PageHeader` — also `@molecule/app-page-chrome-react` (adds `subtitle`, `icon`,
2718
+ `meta`, `emphasis` + a `<HeroSection>`). THIS one takes
2719
+ `title`/`description`/`actions`/`breadcrumbs`.
2720
+ - `Pagination` — the low-level page-window control (no "showing X of Y" text, no
2721
+ page-size selector); for those use `<PaginationBar>` from
2722
+ `@molecule/app-pagination-bar-react`.
2723
+
2724
+ A11y contracts worth knowing before you debug "it doesn't look like it's
2725
+ doing anything" on these components:
2726
+
2727
+ - **`Modal`** implements the WAI-ARIA APG dialog pattern: opening moves
2728
+ focus to the first focusable element inside the dialog (or the dialog
2729
+ itself when it has none); Tab/Shift+Tab are trapped inside; closing
2730
+ restores focus to whatever opened it. Stacked dialogs (a confirm above a
2731
+ drawer) register on a module-level stack — Escape and the Tab trap only
2732
+ act for the TOPMOST dialog, and the body scroll lock is
2733
+ reference-counted, so closing one of several open dialogs never unlocks
2734
+ scroll behind the ones still open. `centered={false}` top-anchors the
2735
+ dialog instead of vertically centering it (an inline-style exception —
2736
+ `UIClassMap` has no `dialogWrapper({ centered })` resolver yet).
2737
+ - **`Dropdown`** implements the WAI-ARIA APG menu-button pattern: the
2738
+ `trigger` is made a real, keyboard-operable control (cloned with
2739
+ `aria-haspopup`/`aria-expanded`/`aria-controls` when it's a single
2740
+ element; wrapped in a `role="button" tabIndex={0}` container otherwise).
2741
+ Enter/Space/ArrowDown open the menu and focus the first item (ArrowUp
2742
+ opens to the last); once open, ArrowUp/Down/Home/End roving-navigate the
2743
+ `menuitem`s, Escape closes and returns focus to the trigger, and Tab
2744
+ closes the menu in sync with focus leaving it (native menus don't trap
2745
+ Tab). `width="trigger"` never renders literal `width: 'trigger'` CSS on
2746
+ the not-yet-measurable first-open frame — it renders unset instead.
2747
+ - **`Tooltip`** requires a single element as `children` for its content to
2748
+ be programmatically associated (`aria-describedby`, injected via
2749
+ `cloneElement`) with the actually-focused/hovered control — a non-element
2750
+ `children` still shows visually but without that association.
2751
+ `hasArrow` renders a small themed pointer at the resolved `placement`.
2752
+ - **`Toast`** pauses its auto-dismiss countdown on hover AND focus (WCAG
2753
+ 2.2.1) and resumes with whatever time was left. The announced role
2754
+ follows `status`: `warning`/`error` get the assertive `role="alert"`;
2755
+ every other status gets the polite `role="status"` so a routine
2756
+ confirmation doesn't interrupt a screen reader mid-sentence.
2757
+ - **`Alert`** takes a `live` prop (default `true`, matching the previous
2758
+ unconditional behavior): `live={false}` switches it from the assertive
2759
+ `role="alert"` to the polite `role="status"` for a banner that's part of
2760
+ the page's normal (not dynamically-appearing) content.
2761
+ - **`UserMenuPopover*`**: `UserMenuPopoverPanel` is a disclosure region
2762
+ (`aria-expanded` + `aria-controls` on the trigger, no role on the panel
2763
+ itself), NOT `role="menu"` — it renders a header plus a `<nav>` of
2764
+ arbitrary links, which is invalid content for `role="menu"` (that role
2765
+ may contain ONLY `menuitem` descendants).
2766
+ - **`Switch`** dispatches a REAL native `change` Event through its hidden
2767
+ checkbox — `event.preventDefault()`, `event.currentTarget`, and
2768
+ `event.stopPropagation()` all behave like they do for any native input
2769
+ (previously the handler received a synthesized `{ target: { checked } }`
2770
+ object that crashed on any of those).
2771
+ - **`Tabs`** implements the WAI-ARIA APG tabs pattern: roving tabindex
2772
+ (only the active tab is in the Tab order) with ArrowLeft/ArrowRight/
2773
+ Home/End moving focus and selection.
2774
+ - **`FormField`** wires `aria-describedby` from its error paragraph onto
2775
+ the child input automatically (falling back to a `useId()`-derived id
2776
+ when no `name` prop is given) — don't duplicate the association by hand.
2777
+ - **`Progress`** clamps `aria-valuenow` into `[0, max]` to match the
2778
+ clamped visual bar, so out-of-range values never announce impossible
2779
+ percentages.
2780
+ - **`Textarea`** `autoResize` also works uncontrolled (`defaultValue` +
2781
+ user typing): it listens to `input` events rather than only reacting to
2782
+ the controlled `value` prop.
2783
+
2784
+ ## Translations
2785
+
2786
+ Translation strings are provided by `@molecule/app-locales-ui`.