@estiva-app/ui 0.21.1 → 0.23.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 (108) hide show
  1. package/README.md +21 -0
  2. package/dist/Avatar.d.ts +3 -0
  3. package/dist/Avatar.d.ts.map +1 -1
  4. package/dist/Banner.d.ts +20 -2
  5. package/dist/Banner.d.ts.map +1 -1
  6. package/dist/ChipInput.d.ts +3 -0
  7. package/dist/ChipInput.d.ts.map +1 -1
  8. package/dist/CommandPalette.d.ts +6 -0
  9. package/dist/CommandPalette.d.ts.map +1 -1
  10. package/dist/ContainerHeader.d.ts +25 -0
  11. package/dist/ContainerHeader.d.ts.map +1 -0
  12. package/dist/EmptyState.d.ts +10 -1
  13. package/dist/EmptyState.d.ts.map +1 -1
  14. package/dist/IdentityMenu.d.ts +3 -0
  15. package/dist/IdentityMenu.d.ts.map +1 -1
  16. package/dist/Menu.d.ts +7 -0
  17. package/dist/Menu.d.ts.map +1 -1
  18. package/dist/Skeleton.d.ts +2 -0
  19. package/dist/Skeleton.d.ts.map +1 -1
  20. package/dist/Toast.d.ts +5 -0
  21. package/dist/Toast.d.ts.map +1 -1
  22. package/dist/Toolbar.d.ts +4 -0
  23. package/dist/Toolbar.d.ts.map +1 -1
  24. package/dist/Tooltip.d.ts +4 -0
  25. package/dist/Tooltip.d.ts.map +1 -1
  26. package/dist/gates/app-checks.d.ts.map +1 -1
  27. package/dist/gates/{chunk-ZGJ2J5NU.js → chunk-EA33NP5B.js} +275 -11
  28. package/dist/gates/chunk-EA33NP5B.js.map +7 -0
  29. package/dist/gates/{chunk-AUXD4GCY.js → chunk-GTQZEHPC.js} +15 -1
  30. package/dist/gates/chunk-GTQZEHPC.js.map +7 -0
  31. package/dist/gates/cli.js +1 -1
  32. package/dist/gates/create-app.d.ts +2 -0
  33. package/dist/gates/create-app.d.ts.map +1 -1
  34. package/dist/gates/create-app.js +1 -1
  35. package/dist/gates/index.js +25 -3
  36. package/dist/gates/index.js.map +2 -2
  37. package/dist/gates/status.d.ts +2 -0
  38. package/dist/gates/status.d.ts.map +1 -1
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +69 -48
  42. package/dist/index.js.map +4 -4
  43. package/dist/registry/app-DQI6WLHR.js +10 -0
  44. package/dist/registry/app-DQI6WLHR.js.map +7 -0
  45. package/dist/registry/app.d.ts +21 -0
  46. package/dist/registry/app.d.ts.map +1 -0
  47. package/dist/registry/build-LGFCCOLR.js +27 -0
  48. package/dist/registry/build-LGFCCOLR.js.map +7 -0
  49. package/dist/registry/build.d.ts +95 -0
  50. package/dist/registry/build.d.ts.map +1 -0
  51. package/dist/registry/chunk-E4JNV7PC.js +155 -0
  52. package/dist/registry/chunk-E4JNV7PC.js.map +7 -0
  53. package/dist/registry/chunk-NJN4MQAM.js +397 -0
  54. package/dist/registry/chunk-NJN4MQAM.js.map +7 -0
  55. package/dist/registry/chunk-W2B2G7OE.js +188 -0
  56. package/dist/registry/chunk-W2B2G7OE.js.map +7 -0
  57. package/dist/registry/chunk-WMFF3MPP.js +648 -0
  58. package/dist/registry/chunk-WMFF3MPP.js.map +7 -0
  59. package/dist/registry/cli.d.ts +2 -0
  60. package/dist/registry/cli.d.ts.map +1 -0
  61. package/dist/registry/cli.js +176 -0
  62. package/dist/registry/cli.js.map +7 -0
  63. package/dist/registry/find.d.ts +54 -0
  64. package/dist/registry/find.d.ts.map +1 -0
  65. package/dist/registry/index.d.ts +17 -0
  66. package/dist/registry/index.d.ts.map +1 -0
  67. package/dist/registry/index.js +34 -0
  68. package/dist/registry/index.js.map +7 -0
  69. package/dist/registry/schema.d.ts +224 -0
  70. package/dist/registry/schema.d.ts.map +1 -0
  71. package/package.json +15 -2
  72. package/registry.json +4615 -0
  73. package/src/Avatar.tsx +3 -0
  74. package/src/Banner.mdx +17 -4
  75. package/src/Banner.stories.tsx +22 -0
  76. package/src/Banner.test.tsx +35 -0
  77. package/src/Banner.tsx +34 -9
  78. package/src/ChipInput.tsx +3 -0
  79. package/src/CommandPalette.tsx +6 -0
  80. package/src/ContainerHeader.mdx +56 -0
  81. package/src/ContainerHeader.stories.tsx +62 -0
  82. package/src/ContainerHeader.test.tsx +47 -0
  83. package/src/ContainerHeader.tsx +45 -0
  84. package/src/EmptyState.mdx +12 -0
  85. package/src/EmptyState.stories.tsx +6 -1
  86. package/src/EmptyState.test.tsx +18 -1
  87. package/src/EmptyState.tsx +14 -1
  88. package/src/IdentityMenu.tsx +3 -0
  89. package/src/Menu.tsx +7 -0
  90. package/src/Skeleton.tsx +2 -0
  91. package/src/Toast.tsx +5 -0
  92. package/src/Toolbar.tsx +4 -0
  93. package/src/Tooltip.tsx +4 -0
  94. package/src/gates/app-checks.ts +23 -1
  95. package/src/gates/create-app.test.ts +77 -6
  96. package/src/gates/create-app.ts +288 -15
  97. package/src/gates/status.ts +16 -0
  98. package/src/index.ts +1 -0
  99. package/src/registry/app.test.ts +562 -0
  100. package/src/registry/app.ts +854 -0
  101. package/src/registry/build.ts +679 -0
  102. package/src/registry/cli.ts +204 -0
  103. package/src/registry/find.ts +232 -0
  104. package/src/registry/index.ts +31 -0
  105. package/src/registry/registry.test.ts +448 -0
  106. package/src/registry/schema.ts +419 -0
  107. package/dist/gates/chunk-AUXD4GCY.js.map +0 -7
  108. package/dist/gates/chunk-ZGJ2J5NU.js.map +0 -7
package/registry.json ADDED
@@ -0,0 +1,4615 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "builtFrom": {
4
+ "kind": "package",
5
+ "repo": "estiva-ui",
6
+ "package": "@estiva-app/ui",
7
+ "packageVersion": "0.23.0",
8
+ "exports": 82,
9
+ "typeExports": 92,
10
+ "files": null
11
+ },
12
+ "storybook": {
13
+ "docsPath": "/?path=/docs/{docsId}",
14
+ "storyPath": "/?path=/story/{storyId}",
15
+ "devUrl": "http://localhost:6008"
16
+ },
17
+ "entries": [
18
+ {
19
+ "name": "AppShell",
20
+ "repo": "estiva-ui",
21
+ "kind": "component",
22
+ "importPath": "@estiva-app/ui",
23
+ "sourceFile": "src/AppShell.tsx",
24
+ "purpose": "The frame of an app, in the two manners that pair: `solid` — the structured frame, a solid TopBar over a Sidebar and the content beside it — and `floating` — the TopBar floating over the top edge, a Rail standing on the background, and the content living in the rounded card.",
25
+ "purposeFrom": "page",
26
+ "props": [
27
+ {
28
+ "name": "variant",
29
+ "takes": "solid | floating",
30
+ "required": false,
31
+ "note": null
32
+ },
33
+ {
34
+ "name": "menu",
35
+ "takes": "anything",
36
+ "required": false,
37
+ "note": "The top bar's menu button, in an app whose navigation collapses."
38
+ },
39
+ {
40
+ "name": "logo",
41
+ "takes": "anything",
42
+ "required": false,
43
+ "note": "The top bar's left: the app's logo mark, or its name as text."
44
+ },
45
+ {
46
+ "name": "search",
47
+ "takes": "anything",
48
+ "required": false,
49
+ "note": "The top bar's centre — a search field, when there is one."
50
+ },
51
+ {
52
+ "name": "identity",
53
+ "takes": "anything",
54
+ "required": false,
55
+ "note": "The top bar's right cluster — an `IdentityMenu`."
56
+ },
57
+ {
58
+ "name": "banner",
59
+ "takes": "anything",
60
+ "required": false,
61
+ "note": "A `Banner`, or nothing — drawn at the top of the content area."
62
+ },
63
+ {
64
+ "name": "nav",
65
+ "takes": "anything",
66
+ "required": true,
67
+ "note": "The navigation: a `Sidebar` in the solid manner, a `Rail` in the floating one."
68
+ },
69
+ {
70
+ "name": "children",
71
+ "takes": "anything",
72
+ "required": true,
73
+ "note": null
74
+ }
75
+ ],
76
+ "variants": [
77
+ {
78
+ "prop": "variant",
79
+ "values": [
80
+ "solid",
81
+ "floating"
82
+ ]
83
+ }
84
+ ],
85
+ "ownsBehaviours": [],
86
+ "status": "stable",
87
+ "migrationStage": null,
88
+ "docsId": "frame-appshell--docs",
89
+ "storyId": "frame-appshell--solid",
90
+ "docPage": "src/AppShell.mdx",
91
+ "app": null
92
+ },
93
+ {
94
+ "name": "AttachmentCard",
95
+ "repo": "estiva-ui",
96
+ "kind": "component",
97
+ "importPath": "@estiva-app/ui",
98
+ "sourceFile": "src/AttachmentCard.tsx",
99
+ "purpose": "Something attached — a document or an image — drawn as a card: posted, or waiting to be sent.",
100
+ "purposeFrom": "page",
101
+ "props": [
102
+ {
103
+ "name": "name",
104
+ "takes": "text",
105
+ "required": true,
106
+ "note": "The name it was attached under, extension included: it decides the icon and the type label."
107
+ },
108
+ {
109
+ "name": "size",
110
+ "takes": "number",
111
+ "required": false,
112
+ "note": "In bytes."
113
+ },
114
+ {
115
+ "name": "contentType",
116
+ "takes": "text",
117
+ "required": false,
118
+ "note": "Its MIME type, where known: an `image/…` type is an image whatever its name."
119
+ },
120
+ {
121
+ "name": "href",
122
+ "takes": "text",
123
+ "required": false,
124
+ "note": "Where a document opens, in a new tab. Without it the row is dimmed and opens nothing."
125
+ },
126
+ {
127
+ "name": "src",
128
+ "takes": "text",
129
+ "required": false,
130
+ "note": "The picture an image card draws. Without it an image is drawn as a row."
131
+ },
132
+ {
133
+ "name": "onOpen",
134
+ "takes": "a handler",
135
+ "required": false,
136
+ "note": "What a click on an image's picture does — the app's full-screen view."
137
+ },
138
+ {
139
+ "name": "onDownload",
140
+ "takes": "a handler",
141
+ "required": false,
142
+ "note": "Shows a download control on hover or focus, and calls this."
143
+ },
144
+ {
145
+ "name": "pending",
146
+ "takes": "true/false",
147
+ "required": false,
148
+ "note": "Waiting to be sent: the composer's 200px row, with a remove control on its corner."
149
+ },
150
+ {
151
+ "name": "onRemove",
152
+ "takes": "a handler",
153
+ "required": false,
154
+ "note": "Removes a pending card."
155
+ },
156
+ {
157
+ "name": "state",
158
+ "takes": "ready | loading | unreadable | uploading | failed | warning",
159
+ "required": false,
160
+ "note": "`ready` · `loading` (an image on its way) · `unreadable` (it could not be read) · `uploading`, `failed`, `warning` (while pending)."
161
+ },
162
+ {
163
+ "name": "note",
164
+ "takes": "text",
165
+ "required": false,
166
+ "note": "The line under the name, in place of its type and size — why it failed, or what the warning is."
167
+ },
168
+ {
169
+ "name": "noteHint",
170
+ "takes": "text",
171
+ "required": false,
172
+ "note": "The note's full words, on hover, where the line is short."
173
+ }
174
+ ],
175
+ "variants": [
176
+ {
177
+ "prop": "state",
178
+ "values": [
179
+ "ready",
180
+ "loading",
181
+ "unreadable",
182
+ "uploading",
183
+ "failed",
184
+ "warning"
185
+ ]
186
+ }
187
+ ],
188
+ "ownsBehaviours": [],
189
+ "status": "stable",
190
+ "migrationStage": null,
191
+ "docsId": "components-attachmentcard--docs",
192
+ "storyId": "components-attachmentcard--document",
193
+ "docPage": "src/AttachmentCard.mdx",
194
+ "app": null
195
+ },
196
+ {
197
+ "name": "Avatar",
198
+ "repo": "estiva-ui",
199
+ "kind": "component",
200
+ "importPath": "@estiva-app/ui",
201
+ "sourceFile": "src/Avatar.tsx",
202
+ "purpose": "A person's face: their picture, or their initials on a colour that is theirs, or — when there is no name to take initials from — a silhouette.",
203
+ "purposeFrom": "page",
204
+ "props": [
205
+ {
206
+ "name": "src",
207
+ "takes": "text",
208
+ "required": false,
209
+ "note": "The picture URL, resolved by the caller."
210
+ },
211
+ {
212
+ "name": "name",
213
+ "takes": "text",
214
+ "required": false,
215
+ "note": "The person's name — where the initials and the colour come from."
216
+ },
217
+ {
218
+ "name": "alt",
219
+ "takes": "text",
220
+ "required": false,
221
+ "note": "Alt text for the picture; the name when absent."
222
+ },
223
+ {
224
+ "name": "size",
225
+ "takes": "number",
226
+ "required": false,
227
+ "note": "Pixels. The scale: 16 · 24 · 32 · 36 (default)."
228
+ },
229
+ {
230
+ "name": "label",
231
+ "takes": "text",
232
+ "required": false,
233
+ "note": "Say the person's name out loud, for a face that stands on its own — `PersonTrigger`'s compact shape, a stack of members."
234
+ },
235
+ {
236
+ "name": "className",
237
+ "takes": "text",
238
+ "required": false,
239
+ "note": null
240
+ }
241
+ ],
242
+ "variants": [],
243
+ "ownsBehaviours": [
244
+ {
245
+ "id": "base-ui",
246
+ "behaviour": "Is built on Base UI"
247
+ }
248
+ ],
249
+ "status": "stable",
250
+ "migrationStage": null,
251
+ "docsId": "primitives-avatar--docs",
252
+ "storyId": "primitives-avatar--initials",
253
+ "docPage": "src/Avatar.mdx",
254
+ "app": null
255
+ },
256
+ {
257
+ "name": "AvatarGroup",
258
+ "repo": "estiva-ui",
259
+ "kind": "component",
260
+ "importPath": "@estiva-app/ui",
261
+ "sourceFile": "src/AvatarGroup.tsx",
262
+ "purpose": "Up to three overlapping 24px faces with a surface-coloured ring — the member stack for anywhere a group is shown at a glance.",
263
+ "purposeFrom": "page",
264
+ "props": [
265
+ {
266
+ "name": "members",
267
+ "takes": "AvatarGroupMember[]",
268
+ "required": true,
269
+ "note": null
270
+ },
271
+ {
272
+ "name": "size",
273
+ "takes": "number",
274
+ "required": false,
275
+ "note": "Face size in pixels; the overlap follows it. 24 is the members pill, 18 the replies row (Katerina, 2026-09-03) — that row drew its own stack for two months for want of this one number, and drifted while it did."
276
+ }
277
+ ],
278
+ "variants": [],
279
+ "ownsBehaviours": [],
280
+ "status": "stable",
281
+ "migrationStage": null,
282
+ "docsId": "primitives-avatargroup--docs",
283
+ "storyId": "primitives-avatargroup--three-members",
284
+ "docPage": "src/AvatarGroup.mdx",
285
+ "app": null
286
+ },
287
+ {
288
+ "name": "Banner",
289
+ "repo": "estiva-ui",
290
+ "kind": "component",
291
+ "importPath": "@estiva-app/ui",
292
+ "sourceFile": "src/Banner.tsx",
293
+ "purpose": "The strip under the header where the app says something happened: one line, one of four tones, gone when there is nothing to say.",
294
+ "purposeFrom": "page",
295
+ "props": [
296
+ {
297
+ "name": "tone",
298
+ "takes": "ok | error | info | warning",
299
+ "required": true,
300
+ "note": null
301
+ },
302
+ {
303
+ "name": "children",
304
+ "takes": "anything",
305
+ "required": true,
306
+ "note": "The one line. Text, or text with a name in `font-medium`."
307
+ },
308
+ {
309
+ "name": "icon",
310
+ "takes": "anything",
311
+ "required": false,
312
+ "note": "A 16px icon before the line, in the tone's colour (Katerina, 2026-09-18: Peek's composer strip became a Banner)."
313
+ },
314
+ {
315
+ "name": "action",
316
+ "takes": "a handler",
317
+ "required": false,
318
+ "note": "The one thing to do: the package's Button, muted and small, at the end of the line."
319
+ },
320
+ {
321
+ "name": "onDismiss",
322
+ "takes": "a handler",
323
+ "required": false,
324
+ "note": "Adds an `✕` at the right-hand end. Absent: the app removes the banner."
325
+ },
326
+ {
327
+ "name": "dismissLabel",
328
+ "takes": "text",
329
+ "required": false,
330
+ "note": "The dismiss button's accessible name. Defaults to \"Dismiss\"."
331
+ },
332
+ {
333
+ "name": "className",
334
+ "takes": "text",
335
+ "required": false,
336
+ "note": null
337
+ }
338
+ ],
339
+ "variants": [
340
+ {
341
+ "prop": "tone",
342
+ "values": [
343
+ "ok",
344
+ "error",
345
+ "info",
346
+ "warning"
347
+ ]
348
+ }
349
+ ],
350
+ "ownsBehaviours": [
351
+ {
352
+ "id": "role",
353
+ "behaviour": "Says what it is to assistive technology"
354
+ }
355
+ ],
356
+ "status": "stable",
357
+ "migrationStage": null,
358
+ "docsId": "feedback-banner--docs",
359
+ "storyId": "feedback-banner--ok",
360
+ "docPage": "src/Banner.mdx",
361
+ "app": null
362
+ },
363
+ {
364
+ "name": "Breadcrumb",
365
+ "repo": "estiva-ui",
366
+ "kind": "component",
367
+ "importPath": "@estiva-app/ui",
368
+ "sourceFile": "src/Breadcrumb.tsx",
369
+ "purpose": "A trail: where you are, and the way back up.",
370
+ "purposeFrom": "page",
371
+ "props": [
372
+ {
373
+ "name": "items",
374
+ "takes": "Crumb[]",
375
+ "required": true,
376
+ "note": null
377
+ },
378
+ {
379
+ "name": "className",
380
+ "takes": "text",
381
+ "required": false,
382
+ "note": null
383
+ }
384
+ ],
385
+ "variants": [],
386
+ "ownsBehaviours": [],
387
+ "status": "stable",
388
+ "migrationStage": null,
389
+ "docsId": "navigation-breadcrumb--docs",
390
+ "storyId": "navigation-breadcrumb--on-an-item",
391
+ "docPage": "src/Breadcrumb.mdx",
392
+ "app": null
393
+ },
394
+ {
395
+ "name": "Button",
396
+ "repo": "estiva-ui",
397
+ "kind": "component",
398
+ "importPath": "@estiva-app/ui",
399
+ "sourceFile": "src/Button.tsx",
400
+ "purpose": "The push-button for an action: a verb, clicked once — \"Create\", \"Save\", \"Delete project\".",
401
+ "purposeFrom": "page",
402
+ "props": [
403
+ {
404
+ "name": "variant",
405
+ "takes": "primary | outlined | muted | destructive | resolve",
406
+ "required": false,
407
+ "note": null
408
+ },
409
+ {
410
+ "name": "size",
411
+ "takes": "default | small",
412
+ "required": false,
413
+ "note": null
414
+ },
415
+ {
416
+ "name": "leadingIcon",
417
+ "takes": "anything",
418
+ "required": false,
419
+ "note": "16px, stroke 1.5 on the default size; 14px on small."
420
+ },
421
+ {
422
+ "name": "disabledReason",
423
+ "takes": "text",
424
+ "required": false,
425
+ "note": "Why the action cannot succeed right now."
426
+ },
427
+ {
428
+ "name": "children",
429
+ "takes": "anything",
430
+ "required": true,
431
+ "note": null
432
+ }
433
+ ],
434
+ "variants": [
435
+ {
436
+ "prop": "variant",
437
+ "values": [
438
+ "primary",
439
+ "outlined",
440
+ "muted",
441
+ "destructive",
442
+ "resolve"
443
+ ]
444
+ },
445
+ {
446
+ "prop": "size",
447
+ "values": [
448
+ "default",
449
+ "small"
450
+ ]
451
+ }
452
+ ],
453
+ "ownsBehaviours": [
454
+ {
455
+ "id": "base-ui",
456
+ "behaviour": "Is built on Base UI"
457
+ },
458
+ {
459
+ "id": "role",
460
+ "behaviour": "Says what it is to assistive technology"
461
+ },
462
+ {
463
+ "id": "tab-stop",
464
+ "behaviour": "Is reachable with Tab"
465
+ }
466
+ ],
467
+ "status": "stable",
468
+ "migrationStage": null,
469
+ "docsId": "primitives-button--docs",
470
+ "storyId": "primitives-button--primary",
471
+ "docPage": "src/Button.mdx",
472
+ "app": null
473
+ },
474
+ {
475
+ "name": "Card",
476
+ "repo": "estiva-ui",
477
+ "kind": "component",
478
+ "importPath": "@estiva-app/ui",
479
+ "sourceFile": "src/Card.tsx",
480
+ "purpose": "A box that stands for one thing — drawn as its frame: 8px corners, a fill and a hairline.",
481
+ "purposeFrom": "page",
482
+ "props": [
483
+ {
484
+ "name": "fill",
485
+ "takes": "surface | elevated | inset | none",
486
+ "required": false,
487
+ "note": "What the card sits on. Default `surface`."
488
+ },
489
+ {
490
+ "name": "href",
491
+ "takes": "text",
492
+ "required": false,
493
+ "note": "The whole card is a link: an anchor, and its hairline answers the pointer."
494
+ },
495
+ {
496
+ "name": "hover",
497
+ "takes": "none | hairline | fill",
498
+ "required": false,
499
+ "note": "How it answers the pointer. Default `hairline` with an `href`, `none` without."
500
+ },
501
+ {
502
+ "name": "quietUntilHover",
503
+ "takes": "true/false",
504
+ "required": false,
505
+ "note": "No hairline until it is pointed at — a row in a feed that shows its edge only when you are on it."
506
+ },
507
+ {
508
+ "name": "hovered",
509
+ "takes": "true/false",
510
+ "required": false,
511
+ "note": "Draw the hover look now, whatever the pointer does."
512
+ },
513
+ {
514
+ "name": "selected",
515
+ "takes": "true/false",
516
+ "required": false,
517
+ "note": "The one you are on: the selected fill, a subtle hairline, and no hover."
518
+ },
519
+ {
520
+ "name": "active",
521
+ "takes": "true/false",
522
+ "required": false,
523
+ "note": "Being changed in place: the selected fill with the accent hairline, and no hover."
524
+ },
525
+ {
526
+ "name": "attention",
527
+ "takes": "accent | warning",
528
+ "required": false,
529
+ "note": "A hairline that asks to be looked at — something new (`accent`), or urgent (`warning`)."
530
+ },
531
+ {
532
+ "name": "unreadable",
533
+ "takes": "true/false",
534
+ "required": false,
535
+ "note": "It stands for something that could not be read: the hairline is dashed."
536
+ },
537
+ {
538
+ "name": "clip",
539
+ "takes": "true/false",
540
+ "required": false,
541
+ "note": "What is inside is cut to the card's rounded corners: a strip or a picture that runs edge to edge (UIG-9, 17 September; the apps passed `overflow-hidden`)."
542
+ },
543
+ {
544
+ "name": "children",
545
+ "takes": "anything",
546
+ "required": true,
547
+ "note": null
548
+ }
549
+ ],
550
+ "variants": [
551
+ {
552
+ "prop": "fill",
553
+ "values": [
554
+ "surface",
555
+ "elevated",
556
+ "inset",
557
+ "none"
558
+ ]
559
+ },
560
+ {
561
+ "prop": "hover",
562
+ "values": [
563
+ "none",
564
+ "hairline",
565
+ "fill"
566
+ ]
567
+ },
568
+ {
569
+ "prop": "attention",
570
+ "values": [
571
+ "accent",
572
+ "warning"
573
+ ]
574
+ }
575
+ ],
576
+ "ownsBehaviours": [],
577
+ "status": "stable",
578
+ "migrationStage": null,
579
+ "docsId": "primitives-card--docs",
580
+ "storyId": "primitives-card--surface",
581
+ "docPage": "src/Card.mdx",
582
+ "app": null
583
+ },
584
+ {
585
+ "name": "Checkbox",
586
+ "repo": "estiva-ui",
587
+ "kind": "component",
588
+ "importPath": "@estiva-app/ui",
589
+ "sourceFile": "src/Checkbox.tsx",
590
+ "purpose": "A 16px square that fills with the accent when checked.",
591
+ "purposeFrom": "page",
592
+ "props": [
593
+ {
594
+ "name": "checked",
595
+ "takes": "true/false",
596
+ "required": true,
597
+ "note": null
598
+ },
599
+ {
600
+ "name": "onChange",
601
+ "takes": "a handler",
602
+ "required": false,
603
+ "note": null
604
+ },
605
+ {
606
+ "name": "disabled",
607
+ "takes": "true/false",
608
+ "required": false,
609
+ "note": null
610
+ },
611
+ {
612
+ "name": "label",
613
+ "takes": "text",
614
+ "required": false,
615
+ "note": "Words beside the box. With `onChange`, clicking them toggles it too, and they name it, so no `aria-label` is needed."
616
+ },
617
+ {
618
+ "name": "row",
619
+ "takes": "true/false",
620
+ "required": false,
621
+ "note": "The whole row is the target: `leading`, then the words, then the box at the end; the row fills on hover and while checked."
622
+ },
623
+ {
624
+ "name": "leading",
625
+ "takes": "anything",
626
+ "required": false,
627
+ "note": "In a `row`, a picture before the words: an icon, a status."
628
+ },
629
+ {
630
+ "name": "aria-label",
631
+ "takes": "text",
632
+ "required": false,
633
+ "note": null
634
+ },
635
+ {
636
+ "name": "aria-required",
637
+ "takes": "boolean | 'true' | 'false'",
638
+ "required": false,
639
+ "note": "Set by a `Field` with `required`; a caller inside one owes nothing."
640
+ },
641
+ {
642
+ "name": "className",
643
+ "takes": "text",
644
+ "required": false,
645
+ "note": null
646
+ }
647
+ ],
648
+ "variants": [],
649
+ "ownsBehaviours": [
650
+ {
651
+ "id": "base-ui",
652
+ "behaviour": "Is built on Base UI"
653
+ },
654
+ {
655
+ "id": "role",
656
+ "behaviour": "Says what it is to assistive technology"
657
+ }
658
+ ],
659
+ "status": "stable",
660
+ "migrationStage": null,
661
+ "docsId": "inputs-checkbox--docs",
662
+ "storyId": "inputs-checkbox--unchecked",
663
+ "docPage": "src/Checkbox.mdx",
664
+ "app": null
665
+ },
666
+ {
667
+ "name": "Chip",
668
+ "repo": "estiva-ui",
669
+ "kind": "component",
670
+ "importPath": "@estiva-app/ui",
671
+ "sourceFile": "src/Chip.tsx",
672
+ "purpose": "A 20px pill for a small piece of standing information — a status, a count, a category — in one of six colour types.",
673
+ "purposeFrom": "page",
674
+ "props": [
675
+ {
676
+ "name": "type",
677
+ "takes": "neutral | brand | info | warning | success | error",
678
+ "required": false,
679
+ "note": null
680
+ },
681
+ {
682
+ "name": "label",
683
+ "takes": "text",
684
+ "required": false,
685
+ "note": null
686
+ },
687
+ {
688
+ "name": "leadingIcon",
689
+ "takes": "anything",
690
+ "required": false,
691
+ "note": null
692
+ },
693
+ {
694
+ "name": "trailingIcon",
695
+ "takes": "anything",
696
+ "required": false,
697
+ "note": null
698
+ },
699
+ {
700
+ "name": "className",
701
+ "takes": "text",
702
+ "required": false,
703
+ "note": null
704
+ }
705
+ ],
706
+ "variants": [
707
+ {
708
+ "prop": "type",
709
+ "values": [
710
+ "neutral",
711
+ "brand",
712
+ "info",
713
+ "warning",
714
+ "success",
715
+ "error"
716
+ ]
717
+ }
718
+ ],
719
+ "ownsBehaviours": [],
720
+ "status": "stable",
721
+ "migrationStage": null,
722
+ "docsId": "primitives-chip--docs",
723
+ "storyId": "primitives-chip--neutral",
724
+ "docPage": "src/Chip.mdx",
725
+ "app": null
726
+ },
727
+ {
728
+ "name": "ChipInput",
729
+ "repo": "estiva-ui",
730
+ "kind": "component",
731
+ "importPath": "@estiva-app/ui",
732
+ "sourceFile": "src/ChipInput.tsx",
733
+ "purpose": "A multi-select input: chips for the chosen, a typeahead for the rest.",
734
+ "purposeFrom": "page",
735
+ "props": [
736
+ {
737
+ "name": "value",
738
+ "takes": "T[]",
739
+ "required": true,
740
+ "note": null
741
+ },
742
+ {
743
+ "name": "onChange",
744
+ "takes": "a handler",
745
+ "required": true,
746
+ "note": null
747
+ },
748
+ {
749
+ "name": "options",
750
+ "takes": "T[]",
751
+ "required": true,
752
+ "note": "The directory the typeahead searches."
753
+ },
754
+ {
755
+ "name": "placeholder",
756
+ "takes": "text",
757
+ "required": false,
758
+ "note": null
759
+ },
760
+ {
761
+ "name": "autoFocus",
762
+ "takes": "true/false",
763
+ "required": false,
764
+ "note": null
765
+ },
766
+ {
767
+ "name": "excludeIds",
768
+ "takes": "string[]",
769
+ "required": false,
770
+ "note": "Option ids excluded from the suggestion list (e.g., the current user)."
771
+ },
772
+ {
773
+ "name": "chipLeading",
774
+ "takes": "a handler",
775
+ "required": false,
776
+ "note": "Before a chip's label, 16px — a face, an icon."
777
+ },
778
+ {
779
+ "name": "rowLeading",
780
+ "takes": "a handler",
781
+ "required": false,
782
+ "note": "Before a suggestion row's label, 32px."
783
+ },
784
+ {
785
+ "name": "aria-required",
786
+ "takes": "boolean | 'true' | 'false'",
787
+ "required": false,
788
+ "note": "Set by a `Field` with `required`; a caller inside one owes nothing."
789
+ },
790
+ {
791
+ "name": "aria-label",
792
+ "takes": "text",
793
+ "required": false,
794
+ "note": "The field's name, for a caller that is not inside a `Field` — a `Field`'s label names it already."
795
+ },
796
+ {
797
+ "name": "aria-labelledby",
798
+ "takes": "text",
799
+ "required": false,
800
+ "note": "The id of what names the field on the page — a visible \"To:\", say."
801
+ }
802
+ ],
803
+ "variants": [],
804
+ "ownsBehaviours": [
805
+ {
806
+ "id": "base-ui",
807
+ "behaviour": "Is built on Base UI"
808
+ },
809
+ {
810
+ "id": "portal",
811
+ "behaviour": "Floats on top of the page"
812
+ },
813
+ {
814
+ "id": "walking",
815
+ "behaviour": "Moves through its items with the arrow keys"
816
+ },
817
+ {
818
+ "id": "role",
819
+ "behaviour": "Says what it is to assistive technology"
820
+ }
821
+ ],
822
+ "status": "stable",
823
+ "migrationStage": null,
824
+ "docsId": "inputs-chipinput--docs",
825
+ "storyId": "inputs-chipinput--type-to-search",
826
+ "docPage": "src/ChipInput.mdx",
827
+ "app": null
828
+ },
829
+ {
830
+ "name": "cn",
831
+ "repo": "estiva-ui",
832
+ "kind": "helper",
833
+ "importPath": "@estiva-app/ui",
834
+ "sourceFile": "src/cn.ts",
835
+ "purpose": "Merge class names, last-one-wins on conflicting Tailwind utilities.",
836
+ "purposeFrom": "comment",
837
+ "props": [],
838
+ "variants": [],
839
+ "ownsBehaviours": [],
840
+ "status": "stable",
841
+ "migrationStage": null,
842
+ "docsId": null,
843
+ "storyId": null,
844
+ "docPage": null,
845
+ "app": null
846
+ },
847
+ {
848
+ "name": "CollapsibleSection",
849
+ "repo": "estiva-ui",
850
+ "kind": "component",
851
+ "importPath": "@estiva-app/ui",
852
+ "sourceFile": "src/CollapsibleSection.tsx",
853
+ "purpose": "A section that opens and closes: a SectionHeader whose title is the toggle, and the rows under it, sliding shut and open.",
854
+ "purposeFrom": "page",
855
+ "props": [
856
+ {
857
+ "name": "title",
858
+ "takes": "text",
859
+ "required": true,
860
+ "note": null
861
+ },
862
+ {
863
+ "name": "defaultOpen",
864
+ "takes": "true/false",
865
+ "required": false,
866
+ "note": "Open unless told otherwise."
867
+ },
868
+ {
869
+ "name": "open",
870
+ "takes": "true/false",
871
+ "required": false,
872
+ "note": "The caller owns the state."
873
+ },
874
+ {
875
+ "name": "onOpenChange",
876
+ "takes": "a handler",
877
+ "required": false,
878
+ "note": null
879
+ },
880
+ {
881
+ "name": "storageKey",
882
+ "takes": "text",
883
+ "required": false,
884
+ "note": "Remember open or closed in this browser, under this key."
885
+ },
886
+ {
887
+ "name": "trailing",
888
+ "takes": "anything",
889
+ "required": false,
890
+ "note": "Beside the title and always visible, before the actions — a count."
891
+ },
892
+ {
893
+ "name": "actions",
894
+ "takes": "SectionAction[]",
895
+ "required": false,
896
+ "note": "Beside the title, revealed on hover or focus — `SectionHeader`'s."
897
+ },
898
+ {
899
+ "name": "showActions",
900
+ "takes": "hover | always",
901
+ "required": false,
902
+ "note": null
903
+ },
904
+ {
905
+ "name": "children",
906
+ "takes": "anything",
907
+ "required": true,
908
+ "note": "The rows."
909
+ },
910
+ {
911
+ "name": "className",
912
+ "takes": "text",
913
+ "required": false,
914
+ "note": "On the section's box: `mt-2` between groups, `shrink-0` in a scrolling column."
915
+ },
916
+ {
917
+ "name": "contentClassName",
918
+ "takes": "text",
919
+ "required": false,
920
+ "note": "On the box the rows sit in: the gap between them."
921
+ }
922
+ ],
923
+ "variants": [
924
+ {
925
+ "prop": "showActions",
926
+ "values": [
927
+ "hover",
928
+ "always"
929
+ ]
930
+ }
931
+ ],
932
+ "ownsBehaviours": [
933
+ {
934
+ "id": "base-ui",
935
+ "behaviour": "Is built on Base UI"
936
+ }
937
+ ],
938
+ "status": "stable",
939
+ "migrationStage": null,
940
+ "docsId": "navigation-collapsiblesection--docs",
941
+ "storyId": "navigation-collapsiblesection--default",
942
+ "docPage": "src/CollapsibleSection.mdx",
943
+ "app": null
944
+ },
945
+ {
946
+ "name": "CommandPalette",
947
+ "repo": "estiva-ui",
948
+ "kind": "component",
949
+ "importPath": "@estiva-app/ui",
950
+ "sourceFile": "src/CommandPalette.tsx",
951
+ "purpose": "A window that searches and runs things: a field, rows in groups, and a footer naming the keys that work right now.",
952
+ "purposeFrom": "page",
953
+ "props": [
954
+ {
955
+ "name": "open",
956
+ "takes": "true/false",
957
+ "required": true,
958
+ "note": null
959
+ },
960
+ {
961
+ "name": "onOpenChange",
962
+ "takes": "a handler",
963
+ "required": true,
964
+ "note": null
965
+ },
966
+ {
967
+ "name": "label",
968
+ "takes": "text",
969
+ "required": true,
970
+ "note": "The window's name for a screen reader — there is no title on screen."
971
+ },
972
+ {
973
+ "name": "where",
974
+ "takes": "text",
975
+ "required": false,
976
+ "note": "The footer's left side: where the palette was opened from."
977
+ },
978
+ {
979
+ "name": "modKey",
980
+ "takes": "text",
981
+ "required": false,
982
+ "note": "How the footer spells the modifier in `Ctrl+Backspace` and `Ctrl+Enter` — `Cmd` on a Mac."
983
+ },
984
+ {
985
+ "name": "children",
986
+ "takes": "anything",
987
+ "required": true,
988
+ "note": "One level: a `CommandPaletteSearch` or a `CommandPaletteForm`."
989
+ }
990
+ ],
991
+ "variants": [],
992
+ "ownsBehaviours": [
993
+ {
994
+ "id": "base-ui",
995
+ "behaviour": "Is built on Base UI"
996
+ },
997
+ {
998
+ "id": "portal",
999
+ "behaviour": "Floats on top of the page"
1000
+ },
1001
+ {
1002
+ "id": "focus",
1003
+ "behaviour": "Holds focus inside while open, and gives it back"
1004
+ },
1005
+ {
1006
+ "id": "walking",
1007
+ "behaviour": "Moves through its items with the arrow keys"
1008
+ },
1009
+ {
1010
+ "id": "role",
1011
+ "behaviour": "Says what it is to assistive technology"
1012
+ }
1013
+ ],
1014
+ "status": "stable",
1015
+ "migrationStage": null,
1016
+ "docsId": "overlays-commandpalette--docs",
1017
+ "storyId": "overlays-commandpalette--first-level",
1018
+ "docPage": "src/CommandPalette.mdx",
1019
+ "app": null
1020
+ },
1021
+ {
1022
+ "name": "CommandPaletteAnswer",
1023
+ "repo": "estiva-ui",
1024
+ "kind": "component",
1025
+ "importPath": "@estiva-app/ui",
1026
+ "sourceFile": "src/CommandPalette.tsx",
1027
+ "purpose": "A written answer, with marks that point at the rows it came from.",
1028
+ "purposeFrom": "comment",
1029
+ "props": [
1030
+ {
1031
+ "name": "children",
1032
+ "takes": "text",
1033
+ "required": true,
1034
+ "note": "The answer's text. A blank line starts a new paragraph, and a number in square brackets — `[1]` — is drawn as a small mark pointing at the row of the same number below."
1035
+ },
1036
+ {
1037
+ "name": "note",
1038
+ "takes": "text",
1039
+ "required": false,
1040
+ "note": "A quiet line under the answer — what a key will do now."
1041
+ }
1042
+ ],
1043
+ "variants": [],
1044
+ "ownsBehaviours": [],
1045
+ "status": "stable",
1046
+ "migrationStage": null,
1047
+ "docsId": "overlays-commandpalette--docs",
1048
+ "storyId": "overlays-commandpalette--first-level",
1049
+ "docPage": null,
1050
+ "app": null
1051
+ },
1052
+ {
1053
+ "name": "CommandPaletteForm",
1054
+ "repo": "estiva-ui",
1055
+ "kind": "component",
1056
+ "importPath": "@estiva-app/ui",
1057
+ "sourceFile": "src/CommandPalette.tsx",
1058
+ "purpose": "The palette as a form: fields, one submit button, and Ctrl+Enter — both ways in run Base UI's field check.",
1059
+ "purposeFrom": "comment",
1060
+ "props": [
1061
+ {
1062
+ "name": "chip",
1063
+ "takes": "CommandPaletteChip",
1064
+ "required": true,
1065
+ "note": "Names what the form makes, and goes back when removed."
1066
+ },
1067
+ {
1068
+ "name": "icon",
1069
+ "takes": "anything",
1070
+ "required": false,
1071
+ "note": "Before the chip, 16px — the mark of whatever the form writes to."
1072
+ },
1073
+ {
1074
+ "name": "submitLabel",
1075
+ "takes": "text",
1076
+ "required": true,
1077
+ "note": "The button's word, and the footer's beside Ctrl+Enter."
1078
+ },
1079
+ {
1080
+ "name": "onSubmit",
1081
+ "takes": "a handler",
1082
+ "required": true,
1083
+ "note": null
1084
+ },
1085
+ {
1086
+ "name": "submitWaits",
1087
+ "takes": "text",
1088
+ "required": false,
1089
+ "note": "Why submitting has to wait — nothing changed yet."
1090
+ },
1091
+ {
1092
+ "name": "working",
1093
+ "takes": "{ button: string; line: string }",
1094
+ "required": false,
1095
+ "note": "While the thing is being made: the fields lock, the button reads `button`, and `line` says what is happening."
1096
+ },
1097
+ {
1098
+ "name": "error",
1099
+ "takes": "text",
1100
+ "required": false,
1101
+ "note": "What went wrong, beside the button."
1102
+ },
1103
+ {
1104
+ "name": "children",
1105
+ "takes": "anything",
1106
+ "required": true,
1107
+ "note": "The fields, each in a `Field`."
1108
+ }
1109
+ ],
1110
+ "variants": [],
1111
+ "ownsBehaviours": [],
1112
+ "status": "stable",
1113
+ "migrationStage": null,
1114
+ "docsId": "overlays-commandpalette--docs",
1115
+ "storyId": "overlays-commandpalette--first-level",
1116
+ "docPage": null,
1117
+ "app": null
1118
+ },
1119
+ {
1120
+ "name": "CommandPaletteQuote",
1121
+ "repo": "estiva-ui",
1122
+ "kind": "component",
1123
+ "importPath": "@estiva-app/ui",
1124
+ "sourceFile": "src/CommandPalette.tsx",
1125
+ "purpose": "Text written to be used elsewhere, set off by a rule at its left edge.",
1126
+ "purposeFrom": "comment",
1127
+ "props": [
1128
+ {
1129
+ "name": "children",
1130
+ "takes": "text",
1131
+ "required": true,
1132
+ "note": "Text written for someone to use — shown as it will be used, line breaks kept."
1133
+ }
1134
+ ],
1135
+ "variants": [],
1136
+ "ownsBehaviours": [],
1137
+ "status": "stable",
1138
+ "migrationStage": null,
1139
+ "docsId": "overlays-commandpalette--docs",
1140
+ "storyId": "overlays-commandpalette--first-level",
1141
+ "docPage": null,
1142
+ "app": null
1143
+ },
1144
+ {
1145
+ "name": "CommandPaletteSearch",
1146
+ "repo": "estiva-ui",
1147
+ "kind": "component",
1148
+ "importPath": "@estiva-app/ui",
1149
+ "sourceFile": "src/CommandPalette.tsx",
1150
+ "purpose": "The palette as a search: a query field, rows in labelled groups walked with the arrow keys, and what to show while nothing has arrived and when nothing matches.",
1151
+ "purposeFrom": "comment",
1152
+ "props": [
1153
+ {
1154
+ "name": "query",
1155
+ "takes": "text",
1156
+ "required": true,
1157
+ "note": null
1158
+ },
1159
+ {
1160
+ "name": "onQueryChange",
1161
+ "takes": "a handler",
1162
+ "required": true,
1163
+ "note": null
1164
+ },
1165
+ {
1166
+ "name": "placeholder",
1167
+ "takes": "text",
1168
+ "required": true,
1169
+ "note": null
1170
+ },
1171
+ {
1172
+ "name": "groups",
1173
+ "takes": "CommandPaletteGroup[]",
1174
+ "required": true,
1175
+ "note": null
1176
+ },
1177
+ {
1178
+ "name": "chip",
1179
+ "takes": "CommandPaletteChip",
1180
+ "required": false,
1181
+ "note": "The level you are in. Without one, this is the first level and there is nowhere to go back to."
1182
+ },
1183
+ {
1184
+ "name": "pending",
1185
+ "takes": "text",
1186
+ "required": false,
1187
+ "note": "A line under the rows while more are on their way — \"Searching…\"."
1188
+ },
1189
+ {
1190
+ "name": "notes",
1191
+ "takes": "string[]",
1192
+ "required": false,
1193
+ "note": "Quiet lines under the rows, for what a person should know about them and cannot act on — \"2 more where you cannot open them\", \"the search was refused, so this list is incomplete\"."
1194
+ },
1195
+ {
1196
+ "name": "empty",
1197
+ "takes": "text",
1198
+ "required": false,
1199
+ "note": "The line when there are no rows. Leave it out while rows are still on their way."
1200
+ },
1201
+ {
1202
+ "name": "children",
1203
+ "takes": "anything",
1204
+ "required": false,
1205
+ "note": "Above the rows: a `CommandPaletteWorking`, `CommandPaletteAnswer` or `CommandPaletteQuote`."
1206
+ }
1207
+ ],
1208
+ "variants": [],
1209
+ "ownsBehaviours": [],
1210
+ "status": "stable",
1211
+ "migrationStage": null,
1212
+ "docsId": "overlays-commandpalette--docs",
1213
+ "storyId": "overlays-commandpalette--first-level",
1214
+ "docPage": null,
1215
+ "app": null
1216
+ },
1217
+ {
1218
+ "name": "CommandPaletteWorking",
1219
+ "repo": "estiva-ui",
1220
+ "kind": "component",
1221
+ "importPath": "@estiva-app/ui",
1222
+ "sourceFile": "src/CommandPalette.tsx",
1223
+ "purpose": "A line saying what is being worked on, with grey bars where the result will land.",
1224
+ "purposeFrom": "comment",
1225
+ "props": [
1226
+ {
1227
+ "name": "children",
1228
+ "takes": "anything",
1229
+ "required": true,
1230
+ "note": "What is happening — \"Reading 12 messages…\"."
1231
+ },
1232
+ {
1233
+ "name": "bars",
1234
+ "takes": "0 | 1 | 2 | 3",
1235
+ "required": false,
1236
+ "note": "Grey bars under the line, where the result will be."
1237
+ }
1238
+ ],
1239
+ "variants": [],
1240
+ "ownsBehaviours": [],
1241
+ "status": "stable",
1242
+ "migrationStage": null,
1243
+ "docsId": "overlays-commandpalette--docs",
1244
+ "storyId": "overlays-commandpalette--first-level",
1245
+ "docPage": null,
1246
+ "app": null
1247
+ },
1248
+ {
1249
+ "name": "ConfirmDialog",
1250
+ "repo": "estiva-ui",
1251
+ "kind": "component",
1252
+ "importPath": "@estiva-app/ui",
1253
+ "sourceFile": "src/ConfirmDialog.tsx",
1254
+ "purpose": "A question with two answers, asked before something a person would want back.",
1255
+ "purposeFrom": "page",
1256
+ "props": [
1257
+ {
1258
+ "name": "title",
1259
+ "takes": "text",
1260
+ "required": true,
1261
+ "note": null
1262
+ },
1263
+ {
1264
+ "name": "children",
1265
+ "takes": "anything",
1266
+ "required": true,
1267
+ "note": "The body — plain sentences, body-2."
1268
+ },
1269
+ {
1270
+ "name": "confirmLabel",
1271
+ "takes": "text",
1272
+ "required": true,
1273
+ "note": null
1274
+ },
1275
+ {
1276
+ "name": "destructive",
1277
+ "takes": "true/false",
1278
+ "required": false,
1279
+ "note": null
1280
+ },
1281
+ {
1282
+ "name": "onConfirm",
1283
+ "takes": "a handler",
1284
+ "required": true,
1285
+ "note": null
1286
+ },
1287
+ {
1288
+ "name": "onClose",
1289
+ "takes": "a handler",
1290
+ "required": true,
1291
+ "note": null
1292
+ }
1293
+ ],
1294
+ "variants": [],
1295
+ "ownsBehaviours": [
1296
+ {
1297
+ "id": "base-ui",
1298
+ "behaviour": "Is built on Base UI"
1299
+ },
1300
+ {
1301
+ "id": "portal",
1302
+ "behaviour": "Floats on top of the page"
1303
+ },
1304
+ {
1305
+ "id": "role",
1306
+ "behaviour": "Says what it is to assistive technology"
1307
+ }
1308
+ ],
1309
+ "status": "stable",
1310
+ "migrationStage": null,
1311
+ "docsId": "overlays-confirmdialog--docs",
1312
+ "storyId": "overlays-confirmdialog--destructive",
1313
+ "docPage": "src/ConfirmDialog.mdx",
1314
+ "app": null
1315
+ },
1316
+ {
1317
+ "name": "ContainerHeader",
1318
+ "repo": "estiva-ui",
1319
+ "kind": "component",
1320
+ "importPath": "@estiva-app/ui",
1321
+ "sourceFile": "src/ContainerHeader.tsx",
1322
+ "purpose": "The bar across the top of a column — a list, a thread, a side panel: its title, and the buttons that act on the whole column at the right edge. 48px, with a hairline under it.",
1323
+ "purposeFrom": "page",
1324
+ "props": [
1325
+ {
1326
+ "name": "title",
1327
+ "takes": "anything",
1328
+ "required": true,
1329
+ "note": "A string keeps the one-line treatment; a node is drawn as given."
1330
+ },
1331
+ {
1332
+ "name": "chevron",
1333
+ "takes": "true/false",
1334
+ "required": false,
1335
+ "note": "A chevron after the title, for a title that opens something."
1336
+ },
1337
+ {
1338
+ "name": "actions",
1339
+ "takes": "anything",
1340
+ "required": false,
1341
+ "note": "The column's own buttons, at the right edge: IconButtons with tooltips, 4px apart."
1342
+ },
1343
+ {
1344
+ "name": "className",
1345
+ "takes": "text",
1346
+ "required": false,
1347
+ "note": null
1348
+ }
1349
+ ],
1350
+ "variants": [],
1351
+ "ownsBehaviours": [],
1352
+ "status": "stable",
1353
+ "migrationStage": null,
1354
+ "docsId": "navigation-containerheader--docs",
1355
+ "storyId": "navigation-containerheader--default",
1356
+ "docPage": "src/ContainerHeader.mdx",
1357
+ "app": null
1358
+ },
1359
+ {
1360
+ "name": "DialogShell",
1361
+ "repo": "estiva-ui",
1362
+ "kind": "component",
1363
+ "importPath": "@estiva-app/ui",
1364
+ "sourceFile": "src/DialogShell.tsx",
1365
+ "purpose": "The dialog, minus what it says: the portal, the backdrop, a 502px card, a 48px header with the title and a close button, a body, and a 48px footer for the buttons.",
1366
+ "purposeFrom": "page",
1367
+ "props": [
1368
+ {
1369
+ "name": "title",
1370
+ "takes": "text",
1371
+ "required": true,
1372
+ "note": "Labels the dialog for assistive tech, and renders as the header text unless `headerContent` replaces it."
1373
+ },
1374
+ {
1375
+ "name": "onClose",
1376
+ "takes": "a handler",
1377
+ "required": true,
1378
+ "note": null
1379
+ },
1380
+ {
1381
+ "name": "headerContent",
1382
+ "takes": "anything",
1383
+ "required": false,
1384
+ "note": "Replaces the title text in the header — a back button beside the title, a count chip after it."
1385
+ },
1386
+ {
1387
+ "name": "footer",
1388
+ "takes": "anything",
1389
+ "required": false,
1390
+ "note": "Absent: no footer row, and the body keeps the card's own bottom edge (a roster that simply ends)."
1391
+ },
1392
+ {
1393
+ "name": "children",
1394
+ "takes": "anything",
1395
+ "required": true,
1396
+ "note": null
1397
+ },
1398
+ {
1399
+ "name": "bodyClassName",
1400
+ "takes": "text",
1401
+ "required": false,
1402
+ "note": "Extra classes on the body: its layout and any padding override (`flex flex-col gap-6`, `p-0 py-2`)."
1403
+ },
1404
+ {
1405
+ "name": "bodyMaxHeight",
1406
+ "takes": "text",
1407
+ "required": false,
1408
+ "note": "How tall the body may get before it scrolls, as the cap class — `max-h-[400px]`, `max-h-[70vh]`."
1409
+ },
1410
+ {
1411
+ "name": "width",
1412
+ "takes": "number",
1413
+ "required": false,
1414
+ "note": null
1415
+ },
1416
+ {
1417
+ "name": "alert",
1418
+ "takes": "true/false",
1419
+ "required": false,
1420
+ "note": "A question that has to be answered rather than clicked away: a press on the backdrop no longer closes it, and it announces itself as an alert."
1421
+ }
1422
+ ],
1423
+ "variants": [],
1424
+ "ownsBehaviours": [
1425
+ {
1426
+ "id": "base-ui",
1427
+ "behaviour": "Is built on Base UI"
1428
+ },
1429
+ {
1430
+ "id": "portal",
1431
+ "behaviour": "Floats on top of the page"
1432
+ },
1433
+ {
1434
+ "id": "press-outside",
1435
+ "behaviour": "Closes on a press outside"
1436
+ },
1437
+ {
1438
+ "id": "page-keys",
1439
+ "behaviour": "Closes on Escape, and takes its keys, by itself"
1440
+ },
1441
+ {
1442
+ "id": "focus",
1443
+ "behaviour": "Holds focus inside while open, and gives it back"
1444
+ },
1445
+ {
1446
+ "id": "scroll-lock",
1447
+ "behaviour": "Stops the page behind it scrolling"
1448
+ },
1449
+ {
1450
+ "id": "role",
1451
+ "behaviour": "Says what it is to assistive technology"
1452
+ }
1453
+ ],
1454
+ "status": "stable",
1455
+ "migrationStage": null,
1456
+ "docsId": "overlays-dialogshell--docs",
1457
+ "storyId": "overlays-dialogshell--default",
1458
+ "docPage": "src/DialogShell.mdx",
1459
+ "app": null
1460
+ },
1461
+ {
1462
+ "name": "Divider",
1463
+ "repo": "estiva-ui",
1464
+ "kind": "component",
1465
+ "importPath": "@estiva-app/ui",
1466
+ "sourceFile": "src/Divider.tsx",
1467
+ "purpose": "A hairline in `border-subtle`. Horizontal it is inset 12px each side; `orientation=\"vertical\"` stands it up to its row's height, no inset.",
1468
+ "purposeFrom": "page",
1469
+ "props": [
1470
+ {
1471
+ "name": "orientation",
1472
+ "takes": "horizontal | vertical",
1473
+ "required": false,
1474
+ "note": null
1475
+ },
1476
+ {
1477
+ "name": "label",
1478
+ "takes": "text",
1479
+ "required": false,
1480
+ "note": "Words in the middle of the line — \"New since you last read this\", a date."
1481
+ },
1482
+ {
1483
+ "name": "tone",
1484
+ "takes": "default | warning",
1485
+ "required": false,
1486
+ "note": "`warning` for a line that asks for attention: the label in the warning colour, the lines in its wash."
1487
+ },
1488
+ {
1489
+ "name": "className",
1490
+ "takes": "text",
1491
+ "required": false,
1492
+ "note": null
1493
+ }
1494
+ ],
1495
+ "variants": [
1496
+ {
1497
+ "prop": "orientation",
1498
+ "values": [
1499
+ "horizontal",
1500
+ "vertical"
1501
+ ]
1502
+ },
1503
+ {
1504
+ "prop": "tone",
1505
+ "values": [
1506
+ "default",
1507
+ "warning"
1508
+ ]
1509
+ }
1510
+ ],
1511
+ "ownsBehaviours": [
1512
+ {
1513
+ "id": "base-ui",
1514
+ "behaviour": "Is built on Base UI"
1515
+ },
1516
+ {
1517
+ "id": "role",
1518
+ "behaviour": "Says what it is to assistive technology"
1519
+ }
1520
+ ],
1521
+ "status": "stable",
1522
+ "migrationStage": null,
1523
+ "docsId": "primitives-divider--docs",
1524
+ "storyId": "primitives-divider--default",
1525
+ "docPage": "src/Divider.mdx",
1526
+ "app": null
1527
+ },
1528
+ {
1529
+ "name": "EditableText",
1530
+ "repo": "estiva-ui",
1531
+ "kind": "component",
1532
+ "importPath": "@estiva-app/ui",
1533
+ "sourceFile": "src/EditableText.tsx",
1534
+ "purpose": "Text you click to edit. It reads as text until clicked; then it is a field.",
1535
+ "purposeFrom": "page",
1536
+ "props": [
1537
+ {
1538
+ "name": "value",
1539
+ "takes": "text",
1540
+ "required": true,
1541
+ "note": null
1542
+ },
1543
+ {
1544
+ "name": "placeholder",
1545
+ "takes": "text",
1546
+ "required": true,
1547
+ "note": null
1548
+ },
1549
+ {
1550
+ "name": "onCommit",
1551
+ "takes": "a handler",
1552
+ "required": true,
1553
+ "note": "Resolve `true` when saved; `false` (or throw) keeps the field open with the text."
1554
+ },
1555
+ {
1556
+ "name": "multiline",
1557
+ "takes": "true/false",
1558
+ "required": false,
1559
+ "note": null
1560
+ },
1561
+ {
1562
+ "name": "className",
1563
+ "takes": "text",
1564
+ "required": false,
1565
+ "note": "Applied to both the text and the field, so they are the same size."
1566
+ },
1567
+ {
1568
+ "name": "label",
1569
+ "takes": "text",
1570
+ "required": true,
1571
+ "note": "The accessible name of the field — \"Title\", \"Description\"."
1572
+ },
1573
+ {
1574
+ "name": "display",
1575
+ "takes": "text",
1576
+ "required": false,
1577
+ "note": "What to *show* when not editing, when that differs from what is edited — a value carrying a raw reference that the caller renders as a live object below the text, say."
1578
+ },
1579
+ {
1580
+ "name": "displayNode",
1581
+ "takes": "anything",
1582
+ "required": false,
1583
+ "note": "What to *draw* when not editing, when the value is structured rather than a line of prose."
1584
+ },
1585
+ {
1586
+ "name": "readOnly",
1587
+ "takes": "true/false",
1588
+ "required": false,
1589
+ "note": "Show the value only — no edit affordance."
1590
+ }
1591
+ ],
1592
+ "variants": [],
1593
+ "ownsBehaviours": [],
1594
+ "status": "stable",
1595
+ "migrationStage": null,
1596
+ "docsId": "inputs-editabletext--docs",
1597
+ "storyId": "inputs-editabletext--title",
1598
+ "docPage": "src/EditableText.mdx",
1599
+ "app": null
1600
+ },
1601
+ {
1602
+ "name": "EmptyState",
1603
+ "repo": "estiva-ui",
1604
+ "kind": "component",
1605
+ "importPath": "@estiva-app/ui",
1606
+ "sourceFile": "src/EmptyState.tsx",
1607
+ "purpose": "The place where content will be once there is some, in two manners: a 16px icon over a centred line when the whole page is empty, the line alone and left-aligned when one section of a page is.",
1608
+ "purposeFrom": "page",
1609
+ "props": [
1610
+ {
1611
+ "name": "icon",
1612
+ "takes": "anything",
1613
+ "required": false,
1614
+ "note": "16px, stroke 1.5. A speech bubble when absent."
1615
+ },
1616
+ {
1617
+ "name": "message",
1618
+ "takes": "text",
1619
+ "required": true,
1620
+ "note": null
1621
+ },
1622
+ {
1623
+ "name": "scope",
1624
+ "takes": "page | section",
1625
+ "required": false,
1626
+ "note": "`page` when the whole page is empty; `section` when one part of it is."
1627
+ },
1628
+ {
1629
+ "name": "action",
1630
+ "takes": "a handler",
1631
+ "required": false,
1632
+ "note": "The one thing to do about it — \"New topic\", \"Try again\" — drawn 16px under the line as the package's Button, outlined (Katerina, 2026-09-18)."
1633
+ },
1634
+ {
1635
+ "name": "className",
1636
+ "takes": "text",
1637
+ "required": false,
1638
+ "note": null
1639
+ }
1640
+ ],
1641
+ "variants": [
1642
+ {
1643
+ "prop": "scope",
1644
+ "values": [
1645
+ "page",
1646
+ "section"
1647
+ ]
1648
+ }
1649
+ ],
1650
+ "ownsBehaviours": [],
1651
+ "status": "stable",
1652
+ "migrationStage": null,
1653
+ "docsId": "feedback-emptystate--docs",
1654
+ "storyId": "feedback-emptystate--page",
1655
+ "docPage": "src/EmptyState.mdx",
1656
+ "app": null
1657
+ },
1658
+ {
1659
+ "name": "EnterHint",
1660
+ "repo": "estiva-ui",
1661
+ "kind": "component",
1662
+ "importPath": "@estiva-app/ui",
1663
+ "sourceFile": "src/Menu.tsx",
1664
+ "purpose": "The keyboard hint a picker row shows while highlighted — hand-rolled in five files before this (2026-09-01), and drawn as its own thing until 2026-09-05, when it became the `Kbd` chip every other key hint uses.",
1665
+ "purposeFrom": "comment",
1666
+ "props": [
1667
+ {
1668
+ "name": "target",
1669
+ "takes": "text",
1670
+ "required": false,
1671
+ "note": null
1672
+ }
1673
+ ],
1674
+ "variants": [],
1675
+ "ownsBehaviours": [],
1676
+ "status": "stable",
1677
+ "migrationStage": null,
1678
+ "docsId": "overlays-menu--docs",
1679
+ "storyId": "overlays-menu--items",
1680
+ "docPage": null,
1681
+ "app": null
1682
+ },
1683
+ {
1684
+ "name": "Field",
1685
+ "repo": "estiva-ui",
1686
+ "kind": "component",
1687
+ "importPath": "@estiva-app/ui",
1688
+ "sourceFile": "src/Field.tsx",
1689
+ "purpose": "A label over a control — the form row. The label is the `input-label` token; `required` marks it with the error-coloured asterisk.",
1690
+ "purposeFrom": "page",
1691
+ "props": [
1692
+ {
1693
+ "name": "label",
1694
+ "takes": "text",
1695
+ "required": true,
1696
+ "note": null
1697
+ },
1698
+ {
1699
+ "name": "required",
1700
+ "takes": "true/false",
1701
+ "required": false,
1702
+ "note": "Draws the asterisk and marks the control `aria-required`, so the mark means something to a reader who cannot see it."
1703
+ },
1704
+ {
1705
+ "name": "helper",
1706
+ "takes": "text",
1707
+ "required": false,
1708
+ "note": "A hint under the control — what the format is, what happens if it is left empty."
1709
+ },
1710
+ {
1711
+ "name": "error",
1712
+ "takes": "text",
1713
+ "required": false,
1714
+ "note": "What is wrong, in the same place as the helper and in the error colour."
1715
+ },
1716
+ {
1717
+ "name": "children",
1718
+ "takes": "anything",
1719
+ "required": true,
1720
+ "note": null
1721
+ }
1722
+ ],
1723
+ "variants": [],
1724
+ "ownsBehaviours": [
1725
+ {
1726
+ "id": "base-ui",
1727
+ "behaviour": "Is built on Base UI"
1728
+ }
1729
+ ],
1730
+ "status": "stable",
1731
+ "migrationStage": null,
1732
+ "docsId": "inputs-field--docs",
1733
+ "storyId": "inputs-field--default",
1734
+ "docPage": "src/Field.mdx",
1735
+ "app": null
1736
+ },
1737
+ {
1738
+ "name": "FieldLine",
1739
+ "repo": "estiva-ui",
1740
+ "kind": "component",
1741
+ "importPath": "@estiva-app/ui",
1742
+ "sourceFile": "src/Field.tsx",
1743
+ "purpose": "The small line a Field draws under a control — on its own, for the places where there is no single control to draw it under.",
1744
+ "purposeFrom": "page",
1745
+ "props": [
1746
+ {
1747
+ "name": "tone",
1748
+ "takes": "helper | warning | error",
1749
+ "required": false,
1750
+ "note": "`helper` (muted) is a hint; `warning` (amber) and `error` (red) are outcomes."
1751
+ },
1752
+ {
1753
+ "name": "children",
1754
+ "takes": "anything",
1755
+ "required": true,
1756
+ "note": null
1757
+ },
1758
+ {
1759
+ "name": "className",
1760
+ "takes": "text",
1761
+ "required": false,
1762
+ "note": null
1763
+ }
1764
+ ],
1765
+ "variants": [
1766
+ {
1767
+ "prop": "tone",
1768
+ "values": [
1769
+ "helper",
1770
+ "warning",
1771
+ "error"
1772
+ ]
1773
+ }
1774
+ ],
1775
+ "ownsBehaviours": [
1776
+ {
1777
+ "id": "role",
1778
+ "behaviour": "Says what it is to assistive technology"
1779
+ }
1780
+ ],
1781
+ "status": "stable",
1782
+ "migrationStage": null,
1783
+ "docsId": "inputs-field-line--docs",
1784
+ "storyId": "inputs-field-line--helper",
1785
+ "docPage": "src/FieldLine.mdx",
1786
+ "app": null
1787
+ },
1788
+ {
1789
+ "name": "FilePicker",
1790
+ "repo": "estiva-ui",
1791
+ "kind": "component",
1792
+ "importPath": "@estiva-app/ui",
1793
+ "sourceFile": "src/FilePicker.tsx",
1794
+ "purpose": "The browser's file picker, with nothing drawn.",
1795
+ "purposeFrom": "page",
1796
+ "props": [
1797
+ {
1798
+ "name": "onPick",
1799
+ "takes": "a handler",
1800
+ "required": true,
1801
+ "note": "The chosen files, in the order the picker gave them."
1802
+ }
1803
+ ],
1804
+ "variants": [],
1805
+ "ownsBehaviours": [],
1806
+ "status": "stable",
1807
+ "migrationStage": null,
1808
+ "docsId": "inputs-filepicker--docs",
1809
+ "storyId": "inputs-filepicker--default",
1810
+ "docPage": "src/FilePicker.mdx",
1811
+ "app": null
1812
+ },
1813
+ {
1814
+ "name": "Form",
1815
+ "repo": "estiva-ui",
1816
+ "kind": "component",
1817
+ "importPath": "@estiva-app/ui",
1818
+ "sourceFile": "src/Form.tsx",
1819
+ "purpose": "The fields and the button that sends them.",
1820
+ "purposeFrom": "page",
1821
+ "props": [
1822
+ {
1823
+ "name": "onSubmit",
1824
+ "takes": "a handler",
1825
+ "required": true,
1826
+ "note": "Enter in a field, or a submit button. The page's own submit is already prevented."
1827
+ },
1828
+ {
1829
+ "name": "busy",
1830
+ "takes": "true/false",
1831
+ "required": false,
1832
+ "note": "While sending: every field and button inside is switched off, and focus waits on the form."
1833
+ },
1834
+ {
1835
+ "name": "enterSends",
1836
+ "takes": "true/false",
1837
+ "required": false,
1838
+ "note": "Whether Enter in a one-line field sends."
1839
+ },
1840
+ {
1841
+ "name": "children",
1842
+ "takes": "anything",
1843
+ "required": true,
1844
+ "note": null
1845
+ }
1846
+ ],
1847
+ "variants": [],
1848
+ "ownsBehaviours": [
1849
+ {
1850
+ "id": "base-ui",
1851
+ "behaviour": "Is built on Base UI"
1852
+ }
1853
+ ],
1854
+ "status": "stable",
1855
+ "migrationStage": null,
1856
+ "docsId": "inputs-form--docs",
1857
+ "storyId": "inputs-form--default",
1858
+ "docPage": "src/Form.mdx",
1859
+ "app": null
1860
+ },
1861
+ {
1862
+ "name": "hueFor",
1863
+ "repo": "estiva-ui",
1864
+ "kind": "helper",
1865
+ "importPath": "@estiva-app/ui",
1866
+ "sourceFile": "src/Avatar.tsx",
1867
+ "purpose": "The colour a person's initials sit on, chosen from a key: the same key always gives the same hue, so a face reads as theirs in every app.",
1868
+ "purposeFrom": "comment",
1869
+ "props": [],
1870
+ "variants": [],
1871
+ "ownsBehaviours": [],
1872
+ "status": "stable",
1873
+ "migrationStage": null,
1874
+ "docsId": "primitives-avatar--docs",
1875
+ "storyId": "primitives-avatar--initials",
1876
+ "docPage": null,
1877
+ "app": null
1878
+ },
1879
+ {
1880
+ "name": "IconButton",
1881
+ "repo": "estiva-ui",
1882
+ "kind": "component",
1883
+ "importPath": "@estiva-app/ui",
1884
+ "sourceFile": "src/IconButton.tsx",
1885
+ "purpose": "A square button around a 16px icon: 4px padding, 8px radius, three variants.",
1886
+ "purposeFrom": "page",
1887
+ "props": [
1888
+ {
1889
+ "name": "variant",
1890
+ "takes": "muted | outlined | primary | current | resolve",
1891
+ "required": false,
1892
+ "note": "`current` takes the colour of what it sits in — the ✕ on a `Banner` wears the banner's tone."
1893
+ },
1894
+ {
1895
+ "name": "pressed",
1896
+ "takes": "true/false",
1897
+ "required": false,
1898
+ "note": "On, like a Bold button while the selection is bold: the active fill, and `aria-pressed`."
1899
+ },
1900
+ {
1901
+ "name": "glow",
1902
+ "takes": "true/false",
1903
+ "required": false,
1904
+ "note": "A glow in Signal — the send arrow while there is something to send."
1905
+ },
1906
+ {
1907
+ "name": "tooltip",
1908
+ "takes": "text",
1909
+ "required": false,
1910
+ "note": null
1911
+ },
1912
+ {
1913
+ "name": "tooltipShortcut",
1914
+ "takes": "text",
1915
+ "required": false,
1916
+ "note": "A key hint drawn as the `Kbd` chip inside the tooltip — for a button whose only other affordance is a keyboard shortcut."
1917
+ },
1918
+ {
1919
+ "name": "tooltipPlacement",
1920
+ "takes": "top | bottom",
1921
+ "required": false,
1922
+ "note": null
1923
+ },
1924
+ {
1925
+ "name": "disabledReason",
1926
+ "takes": "text",
1927
+ "required": false,
1928
+ "note": "Why the action cannot succeed right now."
1929
+ },
1930
+ {
1931
+ "name": "children",
1932
+ "takes": "anything",
1933
+ "required": true,
1934
+ "note": "The icon: 16px, stroke 1.5."
1935
+ }
1936
+ ],
1937
+ "variants": [
1938
+ {
1939
+ "prop": "variant",
1940
+ "values": [
1941
+ "muted",
1942
+ "outlined",
1943
+ "primary",
1944
+ "current",
1945
+ "resolve"
1946
+ ]
1947
+ },
1948
+ {
1949
+ "prop": "tooltipPlacement",
1950
+ "values": [
1951
+ "top",
1952
+ "bottom"
1953
+ ]
1954
+ }
1955
+ ],
1956
+ "ownsBehaviours": [
1957
+ {
1958
+ "id": "base-ui",
1959
+ "behaviour": "Is built on Base UI"
1960
+ },
1961
+ {
1962
+ "id": "role",
1963
+ "behaviour": "Says what it is to assistive technology"
1964
+ },
1965
+ {
1966
+ "id": "tab-stop",
1967
+ "behaviour": "Is reachable with Tab"
1968
+ }
1969
+ ],
1970
+ "status": "stable",
1971
+ "migrationStage": null,
1972
+ "docsId": "primitives-iconbutton--docs",
1973
+ "storyId": "primitives-iconbutton--muted",
1974
+ "docPage": "src/IconButton.mdx",
1975
+ "app": null
1976
+ },
1977
+ {
1978
+ "name": "IdentityMenu",
1979
+ "repo": "estiva-ui",
1980
+ "kind": "component",
1981
+ "importPath": "@estiva-app/ui",
1982
+ "sourceFile": "src/IdentityMenu.tsx",
1983
+ "purpose": "Who you are, and where you are: the identity trigger for a top bar, and the menu it opens — ready-made, because every app needs one and it is built of nothing but shared parts.",
1984
+ "purposeFrom": "page",
1985
+ "props": [
1986
+ {
1987
+ "name": "me",
1988
+ "takes": "Identity",
1989
+ "required": true,
1990
+ "note": null
1991
+ },
1992
+ {
1993
+ "name": "signedIn",
1994
+ "takes": "true/false",
1995
+ "required": true,
1996
+ "note": "Signed in through Estiva ID, as opposed to a browser-held key."
1997
+ },
1998
+ {
1999
+ "name": "relayUrl",
2000
+ "takes": "text",
2001
+ "required": false,
2002
+ "note": "Names the workspace; absent hides the workspace section."
2003
+ },
2004
+ {
2005
+ "name": "idBase",
2006
+ "takes": "text",
2007
+ "required": false,
2008
+ "note": "Estiva ID's base URL when this build offers sign-in; absent = anonymous-only build."
2009
+ },
2010
+ {
2011
+ "name": "onCopyKey",
2012
+ "takes": "a handler",
2013
+ "required": false,
2014
+ "note": "\"Copy public key\" appears only when the app can supply one."
2015
+ },
2016
+ {
2017
+ "name": "onSignOut",
2018
+ "takes": "a handler",
2019
+ "required": false,
2020
+ "note": null
2021
+ },
2022
+ {
2023
+ "name": "compact",
2024
+ "takes": "true/false",
2025
+ "required": false,
2026
+ "note": "Face-only trigger, 36px — no chevron, no name beside it."
2027
+ },
2028
+ {
2029
+ "name": "className",
2030
+ "takes": "text",
2031
+ "required": false,
2032
+ "note": null
2033
+ },
2034
+ {
2035
+ "name": "children",
2036
+ "takes": "anything",
2037
+ "required": false,
2038
+ "note": "App-specific rows, drawn as their own group between the workspace section and the actions."
2039
+ }
2040
+ ],
2041
+ "variants": [],
2042
+ "ownsBehaviours": [],
2043
+ "status": "stable",
2044
+ "migrationStage": null,
2045
+ "docsId": "navigation-identitymenu--docs",
2046
+ "storyId": "navigation-identitymenu--anonymous",
2047
+ "docPage": "src/IdentityMenu.mdx",
2048
+ "app": null
2049
+ },
2050
+ {
2051
+ "name": "IdentityPanel",
2052
+ "repo": "estiva-ui",
2053
+ "kind": "component",
2054
+ "importPath": "@estiva-app/ui",
2055
+ "sourceFile": "src/IdentityMenu.tsx",
2056
+ "purpose": "The identity rows on a panel of their own, with no menu around them — for a docs page, or anywhere the panel is already placed.",
2057
+ "purposeFrom": "comment",
2058
+ "props": [
2059
+ {
2060
+ "name": "onClose",
2061
+ "takes": "a handler",
2062
+ "required": false,
2063
+ "note": "Called when a row asks the menu to close."
2064
+ },
2065
+ {
2066
+ "name": "me",
2067
+ "takes": "Identity",
2068
+ "required": true,
2069
+ "note": null
2070
+ },
2071
+ {
2072
+ "name": "signedIn",
2073
+ "takes": "true/false",
2074
+ "required": true,
2075
+ "note": "Signed in through Estiva ID, as opposed to a browser-held key."
2076
+ },
2077
+ {
2078
+ "name": "relayUrl",
2079
+ "takes": "text",
2080
+ "required": false,
2081
+ "note": "Names the workspace; absent hides the workspace section."
2082
+ },
2083
+ {
2084
+ "name": "idBase",
2085
+ "takes": "text",
2086
+ "required": false,
2087
+ "note": "Estiva ID's base URL when this build offers sign-in; absent = anonymous-only build."
2088
+ },
2089
+ {
2090
+ "name": "onCopyKey",
2091
+ "takes": "a handler",
2092
+ "required": false,
2093
+ "note": "\"Copy public key\" appears only when the app can supply one."
2094
+ },
2095
+ {
2096
+ "name": "onSignOut",
2097
+ "takes": "a handler",
2098
+ "required": false,
2099
+ "note": null
2100
+ },
2101
+ {
2102
+ "name": "className",
2103
+ "takes": "text",
2104
+ "required": false,
2105
+ "note": null
2106
+ },
2107
+ {
2108
+ "name": "children",
2109
+ "takes": "anything",
2110
+ "required": false,
2111
+ "note": "App-specific rows, drawn as their own group between the workspace section and the actions."
2112
+ }
2113
+ ],
2114
+ "variants": [],
2115
+ "ownsBehaviours": [],
2116
+ "status": "stable",
2117
+ "migrationStage": null,
2118
+ "docsId": "navigation-identitymenu--docs",
2119
+ "storyId": "navigation-identitymenu--anonymous",
2120
+ "docPage": null,
2121
+ "app": null
2122
+ },
2123
+ {
2124
+ "name": "initialsFor",
2125
+ "repo": "estiva-ui",
2126
+ "kind": "helper",
2127
+ "importPath": "@estiva-app/ui",
2128
+ "sourceFile": "src/Avatar.tsx",
2129
+ "purpose": "Peek's rule, sharpened: the first letter of the first two words — counting only words that begin with a letter or digit, so \"Claude (steered by Katerina Kelepouri)\" shows \"C\", never \"C(\" (Katerina, 2026-09-01: a name carrying such symbols gets a single letter rather than one of them).",
2130
+ "purposeFrom": "comment",
2131
+ "props": [],
2132
+ "variants": [],
2133
+ "ownsBehaviours": [],
2134
+ "status": "stable",
2135
+ "migrationStage": null,
2136
+ "docsId": "primitives-avatar--docs",
2137
+ "storyId": "primitives-avatar--initials",
2138
+ "docPage": null,
2139
+ "app": null
2140
+ },
2141
+ {
2142
+ "name": "INLINE_CHIP_CLASSES",
2143
+ "repo": "estiva-ui",
2144
+ "kind": "helper",
2145
+ "importPath": "@estiva-app/ui",
2146
+ "sourceFile": "src/InlineChip.tsx",
2147
+ "purpose": "The shape every tone shares. Exported for a rich-text editor that renders chips from strings.",
2148
+ "purposeFrom": "comment",
2149
+ "props": [],
2150
+ "variants": [],
2151
+ "ownsBehaviours": [],
2152
+ "status": "stable",
2153
+ "migrationStage": null,
2154
+ "docsId": "components-inlinechip--docs",
2155
+ "storyId": "components-inlinechip--neutral",
2156
+ "docPage": null,
2157
+ "app": null
2158
+ },
2159
+ {
2160
+ "name": "INLINE_CHIP_TONE_CLASSES",
2161
+ "repo": "estiva-ui",
2162
+ "kind": "helper",
2163
+ "importPath": "@estiva-app/ui",
2164
+ "sourceFile": "src/InlineChip.tsx",
2165
+ "purpose": "What a chip is made of, by what it stands for.",
2166
+ "purposeFrom": "comment",
2167
+ "props": [],
2168
+ "variants": [],
2169
+ "ownsBehaviours": [],
2170
+ "status": "stable",
2171
+ "migrationStage": null,
2172
+ "docsId": "components-inlinechip--docs",
2173
+ "storyId": "components-inlinechip--neutral",
2174
+ "docPage": null,
2175
+ "app": null
2176
+ },
2177
+ {
2178
+ "name": "InlineChip",
2179
+ "repo": "estiva-ui",
2180
+ "kind": "component",
2181
+ "importPath": "@estiva-app/ui",
2182
+ "sourceFile": "src/InlineChip.tsx",
2183
+ "purpose": "A word in a sentence that stands for something — a person, a place, a thing — drawn as a small tinted box exactly one line high, with its words level with the text around it.",
2184
+ "purposeFrom": "page",
2185
+ "props": [
2186
+ {
2187
+ "name": "tone",
2188
+ "takes": "InlineChipTone",
2189
+ "required": false,
2190
+ "note": "What the chip stands for. Default `neutral`."
2191
+ },
2192
+ {
2193
+ "name": "icon",
2194
+ "takes": "anything",
2195
+ "required": false,
2196
+ "note": "Drawn before the label in a 16px box: a 16px icon, or a 14px one it centres."
2197
+ },
2198
+ {
2199
+ "name": "href",
2200
+ "takes": "text",
2201
+ "required": false,
2202
+ "note": "Where the chip leads. With it the chip is an anchor; without it, a span."
2203
+ },
2204
+ {
2205
+ "name": "children",
2206
+ "takes": "anything",
2207
+ "required": true,
2208
+ "note": null
2209
+ }
2210
+ ],
2211
+ "variants": [],
2212
+ "ownsBehaviours": [],
2213
+ "status": "stable",
2214
+ "migrationStage": null,
2215
+ "docsId": "components-inlinechip--docs",
2216
+ "storyId": "components-inlinechip--neutral",
2217
+ "docPage": "src/InlineChip.mdx",
2218
+ "app": null
2219
+ },
2220
+ {
2221
+ "name": "inlineChipClassName",
2222
+ "repo": "estiva-ui",
2223
+ "kind": "helper",
2224
+ "importPath": "@estiva-app/ui",
2225
+ "sourceFile": "src/InlineChip.tsx",
2226
+ "purpose": "The chip's classes for a tone, with anything the caller adds.",
2227
+ "purposeFrom": "comment",
2228
+ "props": [],
2229
+ "variants": [],
2230
+ "ownsBehaviours": [],
2231
+ "status": "stable",
2232
+ "migrationStage": null,
2233
+ "docsId": "components-inlinechip--docs",
2234
+ "storyId": "components-inlinechip--neutral",
2235
+ "docPage": null,
2236
+ "app": null
2237
+ },
2238
+ {
2239
+ "name": "InputChip",
2240
+ "repo": "estiva-ui",
2241
+ "kind": "component",
2242
+ "importPath": "@estiva-app/ui",
2243
+ "sourceFile": "src/ChipInput.tsx",
2244
+ "purpose": "A chip standing on its own: a label, an optional leading icon, an optional ✕.",
2245
+ "purposeFrom": "comment",
2246
+ "props": [
2247
+ {
2248
+ "name": "label",
2249
+ "takes": "text",
2250
+ "required": true,
2251
+ "note": null
2252
+ },
2253
+ {
2254
+ "name": "leading",
2255
+ "takes": "anything",
2256
+ "required": false,
2257
+ "note": "Before the label, 16px — an Avatar, an icon."
2258
+ },
2259
+ {
2260
+ "name": "onRemove",
2261
+ "takes": "a handler",
2262
+ "required": false,
2263
+ "note": "Draws the ✕; absent, the chip is display-only."
2264
+ },
2265
+ {
2266
+ "name": "removeLabel",
2267
+ "takes": "text",
2268
+ "required": false,
2269
+ "note": "The ✕'s name for a screen reader. `Remove <label>` when not given."
2270
+ },
2271
+ {
2272
+ "name": "truncate",
2273
+ "takes": "true/false",
2274
+ "required": false,
2275
+ "note": "Cut a long label with an ellipsis once the chip is capped, by a `max-w-*` on `className`."
2276
+ },
2277
+ {
2278
+ "name": "className",
2279
+ "takes": "text",
2280
+ "required": false,
2281
+ "note": null
2282
+ }
2283
+ ],
2284
+ "variants": [],
2285
+ "ownsBehaviours": [],
2286
+ "status": "stable",
2287
+ "migrationStage": null,
2288
+ "docsId": "inputs-chipinput--docs",
2289
+ "storyId": "inputs-chipinput--type-to-search",
2290
+ "docPage": null,
2291
+ "app": null
2292
+ },
2293
+ {
2294
+ "name": "Kbd",
2295
+ "repo": "estiva-ui",
2296
+ "kind": "component",
2297
+ "importPath": "@estiva-app/ui",
2298
+ "sourceFile": "src/Kbd.tsx",
2299
+ "purpose": "The small chip that names the key which does the same thing.",
2300
+ "purposeFrom": "page",
2301
+ "props": [
2302
+ {
2303
+ "name": "children",
2304
+ "takes": "anything",
2305
+ "required": true,
2306
+ "note": null
2307
+ },
2308
+ {
2309
+ "name": "className",
2310
+ "takes": "text",
2311
+ "required": false,
2312
+ "note": null
2313
+ }
2314
+ ],
2315
+ "variants": [],
2316
+ "ownsBehaviours": [],
2317
+ "status": "stable",
2318
+ "migrationStage": null,
2319
+ "docsId": "primitives-kbd--docs",
2320
+ "storyId": "primitives-kbd--default",
2321
+ "docPage": "src/Kbd.mdx",
2322
+ "app": null
2323
+ },
2324
+ {
2325
+ "name": "Link",
2326
+ "repo": "estiva-ui",
2327
+ "kind": "component",
2328
+ "importPath": "@estiva-app/ui",
2329
+ "sourceFile": "src/Link.tsx",
2330
+ "purpose": "A link, in one of four looks. It is a real anchor with a real address, and the app decides how it navigates.",
2331
+ "purposeFrom": "page",
2332
+ "props": [
2333
+ {
2334
+ "name": "href",
2335
+ "takes": "text",
2336
+ "required": true,
2337
+ "note": null
2338
+ },
2339
+ {
2340
+ "name": "variant",
2341
+ "takes": "text | quiet | underlined | plain",
2342
+ "required": false,
2343
+ "note": "Default `text`."
2344
+ },
2345
+ {
2346
+ "name": "external",
2347
+ "takes": "true/false",
2348
+ "required": false,
2349
+ "note": "Another site, or another app: opens in a new tab, with `noopener noreferrer` so the page it opens cannot reach back into this one."
2350
+ },
2351
+ {
2352
+ "name": "truncate",
2353
+ "takes": "true/false",
2354
+ "required": false,
2355
+ "note": "One line, cut with an ellipsis when it does not fit — a title that is a link."
2356
+ },
2357
+ {
2358
+ "name": "children",
2359
+ "takes": "anything",
2360
+ "required": true,
2361
+ "note": null
2362
+ }
2363
+ ],
2364
+ "variants": [
2365
+ {
2366
+ "prop": "variant",
2367
+ "values": [
2368
+ "text",
2369
+ "quiet",
2370
+ "underlined",
2371
+ "plain"
2372
+ ]
2373
+ }
2374
+ ],
2375
+ "ownsBehaviours": [
2376
+ {
2377
+ "id": "role",
2378
+ "behaviour": "Says what it is to assistive technology"
2379
+ },
2380
+ {
2381
+ "id": "tab-stop",
2382
+ "behaviour": "Is reachable with Tab"
2383
+ }
2384
+ ],
2385
+ "status": "stable",
2386
+ "migrationStage": null,
2387
+ "docsId": "navigation-link--docs",
2388
+ "storyId": "navigation-link--text",
2389
+ "docPage": "src/Link.mdx",
2390
+ "app": null
2391
+ },
2392
+ {
2393
+ "name": "Menu",
2394
+ "repo": "estiva-ui",
2395
+ "kind": "component",
2396
+ "importPath": "@estiva-app/ui",
2397
+ "sourceFile": "src/Menu.tsx",
2398
+ "purpose": "A list of actions from a trigger. The menu owns the trigger, so a caller writes no open state, no placement and no dismiss — it hands over the control and the rows, and everything else is Base UI's.",
2399
+ "purposeFrom": "page",
2400
+ "props": [
2401
+ {
2402
+ "name": "trigger",
2403
+ "takes": "anything",
2404
+ "required": true,
2405
+ "note": "The control that opens the menu. Any element that forwards its ref and spreads its props — this package's `Button`, `IconButton` and `PersonTrigger` all do."
2406
+ },
2407
+ {
2408
+ "name": "align",
2409
+ "takes": "left | right",
2410
+ "required": false,
2411
+ "note": "Which of the menu's edges hangs from the trigger's."
2412
+ },
2413
+ {
2414
+ "name": "openOnHover",
2415
+ "takes": "true/false",
2416
+ "required": false,
2417
+ "note": "Open on hover, and close shortly after the pointer leaves — for a control that only appears while the pointer is on a card."
2418
+ },
2419
+ {
2420
+ "name": "open",
2421
+ "takes": "true/false",
2422
+ "required": false,
2423
+ "note": "Controlled, for a caller that must know or must force it."
2424
+ },
2425
+ {
2426
+ "name": "onOpenChange",
2427
+ "takes": "a handler",
2428
+ "required": false,
2429
+ "note": null
2430
+ },
2431
+ {
2432
+ "name": "actionsRef",
2433
+ "takes": "a handler",
2434
+ "required": false,
2435
+ "note": "Base UI's imperative handle. `actions.current?.close()` shuts the menu — for a row that must close it before opening what it opens."
2436
+ },
2437
+ {
2438
+ "name": "children",
2439
+ "takes": "anything",
2440
+ "required": true,
2441
+ "note": null
2442
+ },
2443
+ {
2444
+ "name": "className",
2445
+ "takes": "text",
2446
+ "required": false,
2447
+ "note": "On the menu's surface — its width. Not its padding: see `contentClassName`."
2448
+ },
2449
+ {
2450
+ "name": "contentClassName",
2451
+ "takes": "text",
2452
+ "required": false,
2453
+ "note": "The padding around the rows, as a class."
2454
+ }
2455
+ ],
2456
+ "variants": [
2457
+ {
2458
+ "prop": "align",
2459
+ "values": [
2460
+ "left",
2461
+ "right"
2462
+ ]
2463
+ }
2464
+ ],
2465
+ "ownsBehaviours": [
2466
+ {
2467
+ "id": "base-ui",
2468
+ "behaviour": "Is built on Base UI"
2469
+ },
2470
+ {
2471
+ "id": "portal",
2472
+ "behaviour": "Floats on top of the page"
2473
+ },
2474
+ {
2475
+ "id": "press-outside",
2476
+ "behaviour": "Closes on a press outside"
2477
+ },
2478
+ {
2479
+ "id": "page-keys",
2480
+ "behaviour": "Closes on Escape, and takes its keys, by itself"
2481
+ },
2482
+ {
2483
+ "id": "follow",
2484
+ "behaviour": "Stays attached to its anchor on scroll and resize"
2485
+ },
2486
+ {
2487
+ "id": "walking",
2488
+ "behaviour": "Moves through its items with the arrow keys"
2489
+ },
2490
+ {
2491
+ "id": "role",
2492
+ "behaviour": "Says what it is to assistive technology"
2493
+ }
2494
+ ],
2495
+ "status": "stable",
2496
+ "migrationStage": null,
2497
+ "docsId": "overlays-menu--docs",
2498
+ "storyId": "overlays-menu--items",
2499
+ "docPage": "src/Menu.mdx",
2500
+ "app": null
2501
+ },
2502
+ {
2503
+ "name": "MenuItem",
2504
+ "repo": "estiva-ui",
2505
+ "kind": "component",
2506
+ "importPath": "@estiva-app/ui",
2507
+ "sourceFile": "src/Menu.tsx",
2508
+ "purpose": "The row of a menu: label, and around it everything a row can carry — a `leading` icon or face, a `description` second line, a `shortcut` kbd chip, a `submenu` chevron, a `trailing` anything (which wins over the other two), `destructive` in the error colour, `selected` as the fill.",
2509
+ "purposeFrom": "page",
2510
+ "props": [
2511
+ {
2512
+ "name": "label",
2513
+ "takes": "text",
2514
+ "required": false,
2515
+ "note": null
2516
+ },
2517
+ {
2518
+ "name": "children",
2519
+ "takes": "anything",
2520
+ "required": false,
2521
+ "note": "Replaces the label/description block — for rows whose middle is richer than text (the launcher's form rows)."
2522
+ },
2523
+ {
2524
+ "name": "size",
2525
+ "takes": "default | tall",
2526
+ "required": false,
2527
+ "note": "`tall` is the picker row — content height with a 40px floor, px-3, gap-3, room for a 32px face or icon tile and the description line."
2528
+ },
2529
+ {
2530
+ "name": "description",
2531
+ "takes": "text",
2532
+ "required": false,
2533
+ "note": "A second line under the label — a role, an address — 12px, secondary, truncating."
2534
+ },
2535
+ {
2536
+ "name": "leading",
2537
+ "takes": "anything",
2538
+ "required": false,
2539
+ "note": "Before the label: a 16px icon (stroke 1.5, secondary), or an Avatar, for rows led by a face."
2540
+ },
2541
+ {
2542
+ "name": "trailing",
2543
+ "takes": "anything",
2544
+ "required": false,
2545
+ "note": "At the right edge: a hint, a value — anything."
2546
+ },
2547
+ {
2548
+ "name": "hint",
2549
+ "takes": "anything",
2550
+ "required": false,
2551
+ "note": "Shown at the right edge only while this row is the one you are pointing at or have arrowed onto — an `EnterHint`, typically."
2552
+ },
2553
+ {
2554
+ "name": "shortcut",
2555
+ "takes": "text",
2556
+ "required": false,
2557
+ "note": "A keyboard hint, drawn as the kbd chip."
2558
+ },
2559
+ {
2560
+ "name": "submenu",
2561
+ "takes": "true/false",
2562
+ "required": false,
2563
+ "note": "The row opens another menu: draws the chevron at the right edge."
2564
+ },
2565
+ {
2566
+ "name": "destructive",
2567
+ "takes": "true/false",
2568
+ "required": false,
2569
+ "note": null
2570
+ },
2571
+ {
2572
+ "name": "selected",
2573
+ "takes": "true/false",
2574
+ "required": false,
2575
+ "note": "The row the menu currently points at (a submenu's chosen value)."
2576
+ }
2577
+ ],
2578
+ "variants": [
2579
+ {
2580
+ "prop": "size",
2581
+ "values": [
2582
+ "default",
2583
+ "tall"
2584
+ ]
2585
+ }
2586
+ ],
2587
+ "ownsBehaviours": [],
2588
+ "status": "stable",
2589
+ "migrationStage": null,
2590
+ "docsId": "overlays-menuitem--docs",
2591
+ "storyId": "overlays-menuitem--default",
2592
+ "docPage": "src/MenuItem.mdx",
2593
+ "app": null
2594
+ },
2595
+ {
2596
+ "name": "MenuPanel",
2597
+ "repo": "estiva-ui",
2598
+ "kind": "component",
2599
+ "importPath": "@estiva-app/ui",
2600
+ "sourceFile": "src/Menu.tsx",
2601
+ "purpose": "The menu's surface without the menu: the elevated box, the rows' padding, and a divider that runs the full width of what it separates.",
2602
+ "purposeFrom": "comment",
2603
+ "props": [
2604
+ {
2605
+ "name": "children",
2606
+ "takes": "anything",
2607
+ "required": false,
2608
+ "note": "Optional only because Base UI fills it in when this is a `render` target: `Menu.Popup` supplies the children."
2609
+ }
2610
+ ],
2611
+ "variants": [],
2612
+ "ownsBehaviours": [],
2613
+ "status": "stable",
2614
+ "migrationStage": null,
2615
+ "docsId": "overlays-menu--docs",
2616
+ "storyId": "overlays-menu--items",
2617
+ "docPage": null,
2618
+ "app": null
2619
+ },
2620
+ {
2621
+ "name": "MenuRow",
2622
+ "repo": "estiva-ui",
2623
+ "kind": "component",
2624
+ "importPath": "@estiva-app/ui",
2625
+ "sourceFile": "src/Menu.tsx",
2626
+ "purpose": "A non-interactive row inside a menu, at the item's own geometry.",
2627
+ "purposeFrom": "comment",
2628
+ "props": [
2629
+ {
2630
+ "name": "children",
2631
+ "takes": "anything",
2632
+ "required": true,
2633
+ "note": null
2634
+ },
2635
+ {
2636
+ "name": "className",
2637
+ "takes": "text",
2638
+ "required": false,
2639
+ "note": null
2640
+ }
2641
+ ],
2642
+ "variants": [],
2643
+ "ownsBehaviours": [],
2644
+ "status": "stable",
2645
+ "migrationStage": null,
2646
+ "docsId": "overlays-menu--docs",
2647
+ "storyId": "overlays-menu--items",
2648
+ "docPage": null,
2649
+ "app": null
2650
+ },
2651
+ {
2652
+ "name": "MenuSection",
2653
+ "repo": "estiva-ui",
2654
+ "kind": "component",
2655
+ "importPath": "@estiva-app/ui",
2656
+ "sourceFile": "src/Menu.tsx",
2657
+ "purpose": "A section heading inside a menu: the 32px row with a SectionLabel, read secondary — a heading inside a menu labels the rows, it is not one of them (Katerina, 2026-09-01).",
2658
+ "purposeFrom": "comment",
2659
+ "props": [
2660
+ {
2661
+ "name": "label",
2662
+ "takes": "text",
2663
+ "required": true,
2664
+ "note": null
2665
+ },
2666
+ {
2667
+ "name": "children",
2668
+ "takes": "anything",
2669
+ "required": true,
2670
+ "note": null
2671
+ },
2672
+ {
2673
+ "name": "className",
2674
+ "takes": "text",
2675
+ "required": false,
2676
+ "note": null
2677
+ }
2678
+ ],
2679
+ "variants": [],
2680
+ "ownsBehaviours": [],
2681
+ "status": "stable",
2682
+ "migrationStage": null,
2683
+ "docsId": "overlays-menu--docs",
2684
+ "storyId": "overlays-menu--items",
2685
+ "docPage": null,
2686
+ "app": null
2687
+ },
2688
+ {
2689
+ "name": "MenuSub",
2690
+ "repo": "estiva-ui",
2691
+ "kind": "component",
2692
+ "importPath": "@estiva-app/ui",
2693
+ "sourceFile": "src/Menu.tsx",
2694
+ "purpose": "A row that opens another menu beside it; its rows are this row's children.",
2695
+ "purposeFrom": "comment",
2696
+ "props": [
2697
+ {
2698
+ "name": "label",
2699
+ "takes": "text",
2700
+ "required": true,
2701
+ "note": "The trigger row's label."
2702
+ },
2703
+ {
2704
+ "name": "leading",
2705
+ "takes": "anything",
2706
+ "required": false,
2707
+ "note": null
2708
+ },
2709
+ {
2710
+ "name": "selected",
2711
+ "takes": "true/false",
2712
+ "required": false,
2713
+ "note": "Mark the trigger row as holding a current value."
2714
+ },
2715
+ {
2716
+ "name": "children",
2717
+ "takes": "anything",
2718
+ "required": true,
2719
+ "note": "The submenu's rows."
2720
+ },
2721
+ {
2722
+ "name": "className",
2723
+ "takes": "text",
2724
+ "required": false,
2725
+ "note": "On the submenu panel."
2726
+ }
2727
+ ],
2728
+ "variants": [],
2729
+ "ownsBehaviours": [],
2730
+ "status": "stable",
2731
+ "migrationStage": null,
2732
+ "docsId": "overlays-menu--docs",
2733
+ "storyId": "overlays-menu--items",
2734
+ "docPage": null,
2735
+ "app": null
2736
+ },
2737
+ {
2738
+ "name": "NavItem",
2739
+ "repo": "estiva-ui",
2740
+ "kind": "component",
2741
+ "importPath": "@estiva-app/ui",
2742
+ "sourceFile": "src/NavItem.tsx",
2743
+ "purpose": "One row of a sidebar: an optional 16px icon, a label, and an optional count — a muted mono number whose tooltip says what it counts.",
2744
+ "purposeFrom": "page",
2745
+ "props": [
2746
+ {
2747
+ "name": "label",
2748
+ "takes": "text",
2749
+ "required": true,
2750
+ "note": null
2751
+ },
2752
+ {
2753
+ "name": "href",
2754
+ "takes": "text",
2755
+ "required": true,
2756
+ "note": null
2757
+ },
2758
+ {
2759
+ "name": "count",
2760
+ "takes": "number",
2761
+ "required": false,
2762
+ "note": "`0` or absent renders no counter."
2763
+ },
2764
+ {
2765
+ "name": "countLabel",
2766
+ "takes": "text",
2767
+ "required": false,
2768
+ "note": "What the count counts, for the tooltip — \"18 open\", \"5 active\"."
2769
+ },
2770
+ {
2771
+ "name": "active",
2772
+ "takes": "true/false",
2773
+ "required": false,
2774
+ "note": null
2775
+ },
2776
+ {
2777
+ "name": "icon",
2778
+ "takes": "anything",
2779
+ "required": false,
2780
+ "note": "16px, stroke 1.5."
2781
+ },
2782
+ {
2783
+ "name": "className",
2784
+ "takes": "text",
2785
+ "required": false,
2786
+ "note": null
2787
+ }
2788
+ ],
2789
+ "variants": [],
2790
+ "ownsBehaviours": [],
2791
+ "status": "stable",
2792
+ "migrationStage": null,
2793
+ "docsId": "frame-navitem--docs",
2794
+ "storyId": "frame-navitem--default",
2795
+ "docPage": "src/NavItem.mdx",
2796
+ "app": null
2797
+ },
2798
+ {
2799
+ "name": "Person",
2800
+ "repo": "estiva-ui",
2801
+ "kind": "component",
2802
+ "importPath": "@estiva-app/ui",
2803
+ "sourceFile": "src/Person.tsx",
2804
+ "purpose": "A face beside a name — the inline mention of a human.",
2805
+ "purposeFrom": "page",
2806
+ "props": [
2807
+ {
2808
+ "name": "name",
2809
+ "takes": "text",
2810
+ "required": false,
2811
+ "note": null
2812
+ },
2813
+ {
2814
+ "name": "picture",
2815
+ "takes": "text",
2816
+ "required": false,
2817
+ "note": null
2818
+ },
2819
+ {
2820
+ "name": "fallback",
2821
+ "takes": "text",
2822
+ "required": false,
2823
+ "note": "Shown in place of a missing name."
2824
+ },
2825
+ {
2826
+ "name": "size",
2827
+ "takes": "number",
2828
+ "required": false,
2829
+ "note": null
2830
+ },
2831
+ {
2832
+ "name": "className",
2833
+ "takes": "text",
2834
+ "required": false,
2835
+ "note": null
2836
+ }
2837
+ ],
2838
+ "variants": [],
2839
+ "ownsBehaviours": [],
2840
+ "status": "stable",
2841
+ "migrationStage": null,
2842
+ "docsId": "components-person--docs",
2843
+ "storyId": "components-person--named",
2844
+ "docPage": "src/Person.mdx",
2845
+ "app": null
2846
+ },
2847
+ {
2848
+ "name": "PersonTrigger",
2849
+ "repo": "estiva-ui",
2850
+ "kind": "component",
2851
+ "importPath": "@estiva-app/ui",
2852
+ "sourceFile": "src/PersonTrigger.tsx",
2853
+ "purpose": "The person, as the button that opens a menu.",
2854
+ "purposeFrom": "page",
2855
+ "props": [
2856
+ {
2857
+ "name": "open",
2858
+ "takes": "true/false",
2859
+ "required": false,
2860
+ "note": "Whether what it opens is open — the row shape holds its hover fill while so."
2861
+ },
2862
+ {
2863
+ "name": "compact",
2864
+ "takes": "true/false",
2865
+ "required": false,
2866
+ "note": "Face only — no chevron, no hover fill. Defaults the face to 36px; the row shape to 22px."
2867
+ },
2868
+ {
2869
+ "name": "name",
2870
+ "takes": "text",
2871
+ "required": false,
2872
+ "note": null
2873
+ },
2874
+ {
2875
+ "name": "picture",
2876
+ "takes": "text",
2877
+ "required": false,
2878
+ "note": null
2879
+ },
2880
+ {
2881
+ "name": "fallback",
2882
+ "takes": "text",
2883
+ "required": false,
2884
+ "note": "Shown in place of a missing name."
2885
+ },
2886
+ {
2887
+ "name": "size",
2888
+ "takes": "number",
2889
+ "required": false,
2890
+ "note": null
2891
+ }
2892
+ ],
2893
+ "variants": [],
2894
+ "ownsBehaviours": [],
2895
+ "status": "stable",
2896
+ "migrationStage": null,
2897
+ "docsId": "components-persontrigger--docs",
2898
+ "storyId": "components-persontrigger--row",
2899
+ "docPage": "src/PersonTrigger.mdx",
2900
+ "app": null
2901
+ },
2902
+ {
2903
+ "name": "Popover",
2904
+ "repo": "estiva-ui",
2905
+ "kind": "component",
2906
+ "importPath": "@estiva-app/ui",
2907
+ "sourceFile": "src/Popover.tsx",
2908
+ "purpose": "A floating panel from a trigger: the same elevated surface a Menu draws, with none of a menu's semantics.",
2909
+ "purposeFrom": "page",
2910
+ "props": [
2911
+ {
2912
+ "name": "trigger",
2913
+ "takes": "anything",
2914
+ "required": false,
2915
+ "note": "The control that opens the panel. Any element that forwards its ref and spreads its props — this package's `Button`, `IconButton` and `PersonTrigger` all do."
2916
+ },
2917
+ {
2918
+ "name": "anchor",
2919
+ "takes": "HTMLElement | DOMRect | null",
2920
+ "required": false,
2921
+ "note": "For a panel with no trigger element: an element, or a rect the caller measured — a text selection's."
2922
+ },
2923
+ {
2924
+ "name": "align",
2925
+ "takes": "left | center | right",
2926
+ "required": false,
2927
+ "note": "Which of the panel's edges hangs from the trigger's, or `center` to put the panel's middle over the anchor's."
2928
+ },
2929
+ {
2930
+ "name": "side",
2931
+ "takes": "top | bottom",
2932
+ "required": false,
2933
+ "note": "Which side of the trigger, or of the anchor, the panel prefers."
2934
+ },
2935
+ {
2936
+ "name": "open",
2937
+ "takes": "true/false",
2938
+ "required": false,
2939
+ "note": "Controlled, for a caller that must know or must force it."
2940
+ },
2941
+ {
2942
+ "name": "onOpenChange",
2943
+ "takes": "a handler",
2944
+ "required": false,
2945
+ "note": null
2946
+ },
2947
+ {
2948
+ "name": "finalFocus",
2949
+ "takes": "RefObject<HTMLElement | null>",
2950
+ "required": false,
2951
+ "note": "Where focus goes when the panel closes. With a `trigger` it goes back to the trigger and this is not needed."
2952
+ },
2953
+ {
2954
+ "name": "actionsRef",
2955
+ "takes": "a handler",
2956
+ "required": false,
2957
+ "note": "Base UI's imperative handle. `actions.current?.close()` shuts the panel — for the Cancel and Save buttons a form panel ends with."
2958
+ },
2959
+ {
2960
+ "name": "ariaLabel",
2961
+ "takes": "text",
2962
+ "required": false,
2963
+ "note": "Names the panel for assistive tech. A panel with a visible heading can point at it instead, with `aria-labelledby`."
2964
+ },
2965
+ {
2966
+ "name": "children",
2967
+ "takes": "anything",
2968
+ "required": true,
2969
+ "note": null
2970
+ },
2971
+ {
2972
+ "name": "className",
2973
+ "takes": "text",
2974
+ "required": false,
2975
+ "note": "On the panel's surface — its width. Not its padding: see `contentClassName`."
2976
+ },
2977
+ {
2978
+ "name": "contentClassName",
2979
+ "takes": "text",
2980
+ "required": false,
2981
+ "note": "The padding around the children, as a class."
2982
+ },
2983
+ {
2984
+ "name": "maxHeight",
2985
+ "takes": "text",
2986
+ "required": false,
2987
+ "note": "A cap on the scrolling box, as a class — `max-h-[360px]`."
2988
+ }
2989
+ ],
2990
+ "variants": [
2991
+ {
2992
+ "prop": "align",
2993
+ "values": [
2994
+ "left",
2995
+ "center",
2996
+ "right"
2997
+ ]
2998
+ },
2999
+ {
3000
+ "prop": "side",
3001
+ "values": [
3002
+ "top",
3003
+ "bottom"
3004
+ ]
3005
+ }
3006
+ ],
3007
+ "ownsBehaviours": [
3008
+ {
3009
+ "id": "base-ui",
3010
+ "behaviour": "Is built on Base UI"
3011
+ },
3012
+ {
3013
+ "id": "portal",
3014
+ "behaviour": "Floats on top of the page"
3015
+ },
3016
+ {
3017
+ "id": "press-outside",
3018
+ "behaviour": "Closes on a press outside"
3019
+ },
3020
+ {
3021
+ "id": "page-keys",
3022
+ "behaviour": "Closes on Escape, and takes its keys, by itself"
3023
+ },
3024
+ {
3025
+ "id": "follow",
3026
+ "behaviour": "Stays attached to its anchor on scroll and resize"
3027
+ }
3028
+ ],
3029
+ "status": "stable",
3030
+ "migrationStage": null,
3031
+ "docsId": "overlays-popover--docs",
3032
+ "storyId": "overlays-popover--default",
3033
+ "docPage": "src/Popover.mdx",
3034
+ "app": null
3035
+ },
3036
+ {
3037
+ "name": "PreviewCard",
3038
+ "repo": "estiva-ui",
3039
+ "kind": "component",
3040
+ "importPath": "@estiva-app/ui",
3041
+ "sourceFile": "src/PreviewCard.tsx",
3042
+ "purpose": "More of a thing, on hover.",
3043
+ "purposeFrom": "page",
3044
+ "props": [
3045
+ {
3046
+ "name": "content",
3047
+ "takes": "anything",
3048
+ "required": true,
3049
+ "note": "What the card holds. Rendered only while it is open."
3050
+ },
3051
+ {
3052
+ "name": "children",
3053
+ "takes": "anything",
3054
+ "required": true,
3055
+ "note": "The row, name or avatar the card previews."
3056
+ },
3057
+ {
3058
+ "name": "side",
3059
+ "takes": "top | bottom | left | right",
3060
+ "required": false,
3061
+ "note": "Which side of the trigger to prefer. It flips when that side has no room."
3062
+ },
3063
+ {
3064
+ "name": "delay",
3065
+ "takes": "number",
3066
+ "required": false,
3067
+ "note": "Before it opens, in ms. Long enough that crossing a list does not flash a card at every row."
3068
+ },
3069
+ {
3070
+ "name": "closeDelay",
3071
+ "takes": "number",
3072
+ "required": false,
3073
+ "note": "After the pointer leaves, in ms — the grace that lets you cross the gap into the card."
3074
+ },
3075
+ {
3076
+ "name": "className",
3077
+ "takes": "text",
3078
+ "required": false,
3079
+ "note": "On the card's surface: its width, its padding, a max height."
3080
+ },
3081
+ {
3082
+ "name": "wrapperClassName",
3083
+ "takes": "text",
3084
+ "required": false,
3085
+ "note": "Extra classes on the trigger wrapper — e.g."
3086
+ }
3087
+ ],
3088
+ "variants": [
3089
+ {
3090
+ "prop": "side",
3091
+ "values": [
3092
+ "top",
3093
+ "bottom",
3094
+ "left",
3095
+ "right"
3096
+ ]
3097
+ }
3098
+ ],
3099
+ "ownsBehaviours": [
3100
+ {
3101
+ "id": "base-ui",
3102
+ "behaviour": "Is built on Base UI"
3103
+ },
3104
+ {
3105
+ "id": "portal",
3106
+ "behaviour": "Floats on top of the page"
3107
+ },
3108
+ {
3109
+ "id": "press-outside",
3110
+ "behaviour": "Closes on a press outside"
3111
+ },
3112
+ {
3113
+ "id": "follow",
3114
+ "behaviour": "Stays attached to its anchor on scroll and resize"
3115
+ }
3116
+ ],
3117
+ "status": "stable",
3118
+ "migrationStage": null,
3119
+ "docsId": "overlays-previewcard--docs",
3120
+ "storyId": "overlays-previewcard--default",
3121
+ "docPage": "src/PreviewCard.mdx",
3122
+ "app": null
3123
+ },
3124
+ {
3125
+ "name": "ProgressBar",
3126
+ "repo": "estiva-ui",
3127
+ "kind": "component",
3128
+ "importPath": "@estiva-app/ui",
3129
+ "sourceFile": "src/ProgressBar.tsx",
3130
+ "purpose": "How much of something is done: a thin rounded track with a success-coloured fill.",
3131
+ "purposeFrom": "page",
3132
+ "props": [
3133
+ {
3134
+ "name": "value",
3135
+ "takes": "number",
3136
+ "required": true,
3137
+ "note": "How many are done."
3138
+ },
3139
+ {
3140
+ "name": "max",
3141
+ "takes": "number",
3142
+ "required": true,
3143
+ "note": "How many there are. At `0` the bar is empty."
3144
+ },
3145
+ {
3146
+ "name": "label",
3147
+ "takes": "text",
3148
+ "required": true,
3149
+ "note": "The accessible name — \"Items done\"."
3150
+ },
3151
+ {
3152
+ "name": "variant",
3153
+ "takes": "default | quiet",
3154
+ "required": false,
3155
+ "note": "Default `default`."
3156
+ },
3157
+ {
3158
+ "name": "className",
3159
+ "takes": "text",
3160
+ "required": false,
3161
+ "note": "Placement only: a width, a margin, `flex-1` in a row."
3162
+ }
3163
+ ],
3164
+ "variants": [
3165
+ {
3166
+ "prop": "variant",
3167
+ "values": [
3168
+ "default",
3169
+ "quiet"
3170
+ ]
3171
+ }
3172
+ ],
3173
+ "ownsBehaviours": [
3174
+ {
3175
+ "id": "base-ui",
3176
+ "behaviour": "Is built on Base UI"
3177
+ },
3178
+ {
3179
+ "id": "role",
3180
+ "behaviour": "Says what it is to assistive technology"
3181
+ }
3182
+ ],
3183
+ "status": "stable",
3184
+ "migrationStage": null,
3185
+ "docsId": "feedback-progressbar--docs",
3186
+ "storyId": "feedback-progressbar--default",
3187
+ "docPage": "src/ProgressBar.mdx",
3188
+ "app": null
3189
+ },
3190
+ {
3191
+ "name": "Property",
3192
+ "repo": "estiva-ui",
3193
+ "kind": "component",
3194
+ "importPath": "@estiva-app/ui",
3195
+ "sourceFile": "src/Property.tsx",
3196
+ "purpose": "A labelled property — \"Status\", \"Lead\", and whatever else a surface declares.",
3197
+ "purposeFrom": "page",
3198
+ "props": [
3199
+ {
3200
+ "name": "label",
3201
+ "takes": "text",
3202
+ "required": true,
3203
+ "note": null
3204
+ },
3205
+ {
3206
+ "name": "layout",
3207
+ "takes": "row | stacked",
3208
+ "required": false,
3209
+ "note": null
3210
+ },
3211
+ {
3212
+ "name": "children",
3213
+ "takes": "anything",
3214
+ "required": true,
3215
+ "note": null
3216
+ },
3217
+ {
3218
+ "name": "className",
3219
+ "takes": "text",
3220
+ "required": false,
3221
+ "note": null
3222
+ }
3223
+ ],
3224
+ "variants": [
3225
+ {
3226
+ "prop": "layout",
3227
+ "values": [
3228
+ "row",
3229
+ "stacked"
3230
+ ]
3231
+ }
3232
+ ],
3233
+ "ownsBehaviours": [],
3234
+ "status": "stable",
3235
+ "migrationStage": null,
3236
+ "docsId": "primitives-property--docs",
3237
+ "storyId": "primitives-property--row",
3238
+ "docPage": "src/Property.mdx",
3239
+ "app": null
3240
+ },
3241
+ {
3242
+ "name": "Rail",
3243
+ "repo": "estiva-ui",
3244
+ "kind": "component",
3245
+ "importPath": "@estiva-app/ui",
3246
+ "sourceFile": "src/Rail.tsx",
3247
+ "purpose": "The 64px strip of icon tiles down the left of an app.",
3248
+ "purposeFrom": "page",
3249
+ "props": [
3250
+ {
3251
+ "name": "aria-label",
3252
+ "takes": "text",
3253
+ "required": false,
3254
+ "note": "Names the navigation region for assistive tech."
3255
+ },
3256
+ {
3257
+ "name": "children",
3258
+ "takes": "anything",
3259
+ "required": true,
3260
+ "note": null
3261
+ },
3262
+ {
3263
+ "name": "className",
3264
+ "takes": "text",
3265
+ "required": false,
3266
+ "note": null
3267
+ }
3268
+ ],
3269
+ "variants": [],
3270
+ "ownsBehaviours": [],
3271
+ "status": "stable",
3272
+ "migrationStage": null,
3273
+ "docsId": "frame-rail--docs",
3274
+ "storyId": "frame-rail--default",
3275
+ "docPage": "src/Rail.mdx",
3276
+ "app": null
3277
+ },
3278
+ {
3279
+ "name": "RailItem",
3280
+ "repo": "estiva-ui",
3281
+ "kind": "component",
3282
+ "importPath": "@estiva-app/ui",
3283
+ "sourceFile": "src/RailItem.tsx",
3284
+ "purpose": "One tile of an icon rail: the icon in its hover tile, a 9px label under it.",
3285
+ "purposeFrom": "page",
3286
+ "props": [
3287
+ {
3288
+ "name": "href",
3289
+ "takes": "text",
3290
+ "required": true,
3291
+ "note": null
3292
+ },
3293
+ {
3294
+ "name": "icon",
3295
+ "takes": "anything",
3296
+ "required": true,
3297
+ "note": "16px, stroke 1.5."
3298
+ },
3299
+ {
3300
+ "name": "label",
3301
+ "takes": "text",
3302
+ "required": true,
3303
+ "note": null
3304
+ },
3305
+ {
3306
+ "name": "active",
3307
+ "takes": "true/false",
3308
+ "required": false,
3309
+ "note": null
3310
+ },
3311
+ {
3312
+ "name": "className",
3313
+ "takes": "text",
3314
+ "required": false,
3315
+ "note": null
3316
+ }
3317
+ ],
3318
+ "variants": [],
3319
+ "ownsBehaviours": [],
3320
+ "status": "stable",
3321
+ "migrationStage": null,
3322
+ "docsId": "frame-railitem--docs",
3323
+ "storyId": "frame-railitem--default",
3324
+ "docPage": "src/RailItem.mdx",
3325
+ "app": null
3326
+ },
3327
+ {
3328
+ "name": "Reaction",
3329
+ "repo": "estiva-ui",
3330
+ "kind": "component",
3331
+ "importPath": "@estiva-app/ui",
3332
+ "sourceFile": "src/Reaction.tsx",
3333
+ "purpose": "An emoji, how many people chose it, and whether you are one of them.",
3334
+ "purposeFrom": "page",
3335
+ "props": [
3336
+ {
3337
+ "name": "emoji",
3338
+ "takes": "anything",
3339
+ "required": true,
3340
+ "note": "The emoji, drawn decoratively — name the control with `aria-label`."
3341
+ },
3342
+ {
3343
+ "name": "count",
3344
+ "takes": "number",
3345
+ "required": true,
3346
+ "note": "How many people reacted. Drawn as it is."
3347
+ },
3348
+ {
3349
+ "name": "pressed",
3350
+ "takes": "true/false",
3351
+ "required": false,
3352
+ "note": "You are one of them: the accent tint and edge, and `aria-pressed`."
3353
+ },
3354
+ {
3355
+ "name": "aria-label",
3356
+ "takes": "text",
3357
+ "required": true,
3358
+ "note": "Names the control. Required — the emoji is decorative and the count is the only visible text, so without this it is announced as a bare number."
3359
+ }
3360
+ ],
3361
+ "variants": [],
3362
+ "ownsBehaviours": [
3363
+ {
3364
+ "id": "base-ui",
3365
+ "behaviour": "Is built on Base UI"
3366
+ }
3367
+ ],
3368
+ "status": "stable",
3369
+ "migrationStage": null,
3370
+ "docsId": "components-reaction--docs",
3371
+ "storyId": "components-reaction--default",
3372
+ "docPage": "src/Reaction.mdx",
3373
+ "app": null
3374
+ },
3375
+ {
3376
+ "name": "ReactionPicker",
3377
+ "repo": "estiva-ui",
3378
+ "kind": "component",
3379
+ "importPath": "@estiva-app/ui",
3380
+ "sourceFile": "src/ReactionPicker.tsx",
3381
+ "purpose": "The reactions on offer, to choose one from — icon buttons holding emoji, on a Toolbar.",
3382
+ "purposeFrom": "page",
3383
+ "props": [
3384
+ {
3385
+ "name": "options",
3386
+ "takes": "ReactionOption[]",
3387
+ "required": true,
3388
+ "note": "What is on offer, in the order it is drawn."
3389
+ },
3390
+ {
3391
+ "name": "onSelect",
3392
+ "takes": "a handler",
3393
+ "required": true,
3394
+ "note": null
3395
+ },
3396
+ {
3397
+ "name": "aria-label",
3398
+ "takes": "text",
3399
+ "required": false,
3400
+ "note": "Names the row. Default \"Reactions\"."
3401
+ },
3402
+ {
3403
+ "name": "surface",
3404
+ "takes": "true/false",
3405
+ "required": false,
3406
+ "note": "The elevated box around the row, from `Toolbar`."
3407
+ },
3408
+ {
3409
+ "name": "className",
3410
+ "takes": "text",
3411
+ "required": false,
3412
+ "note": "The row's layout — its gap, its padding."
3413
+ }
3414
+ ],
3415
+ "variants": [],
3416
+ "ownsBehaviours": [],
3417
+ "status": "stable",
3418
+ "migrationStage": null,
3419
+ "docsId": "components-reactionpicker--docs",
3420
+ "storyId": "components-reactionpicker--default",
3421
+ "docPage": "src/ReactionPicker.mdx",
3422
+ "app": null
3423
+ },
3424
+ {
3425
+ "name": "ScrollArea",
3426
+ "repo": "estiva-ui",
3427
+ "kind": "component",
3428
+ "importPath": "@estiva-app/ui",
3429
+ "sourceFile": "src/ScrollArea.tsx",
3430
+ "purpose": "A region that scrolls without taking width for its scrollbar.",
3431
+ "purposeFrom": "page",
3432
+ "props": [
3433
+ {
3434
+ "name": "orientation",
3435
+ "takes": "vertical | horizontal | both",
3436
+ "required": false,
3437
+ "note": null
3438
+ },
3439
+ {
3440
+ "name": "className",
3441
+ "takes": "text",
3442
+ "required": false,
3443
+ "note": "On the region: its size and placement."
3444
+ },
3445
+ {
3446
+ "name": "viewportClassName",
3447
+ "takes": "text",
3448
+ "required": false,
3449
+ "note": "On the viewport, the box that scrolls: a `max-h-*` cap."
3450
+ },
3451
+ {
3452
+ "name": "contentClassName",
3453
+ "takes": "text",
3454
+ "required": false,
3455
+ "note": "On the content, the box the children sit in: padding, gap, layout."
3456
+ },
3457
+ {
3458
+ "name": "viewportRef",
3459
+ "takes": "Ref<HTMLDivElement>",
3460
+ "required": false,
3461
+ "note": "The scrolling box itself, for a region that reads or drives its own scrolling: `ref.current.scrollTop`, `scrollTo`, `scrollHeight`."
3462
+ },
3463
+ {
3464
+ "name": "onScroll",
3465
+ "takes": "UIEventHandler<HTMLDivElement>",
3466
+ "required": false,
3467
+ "note": "Fires as the viewport scrolls — the unread policy's input, beside `viewportRef`."
3468
+ },
3469
+ {
3470
+ "name": "children",
3471
+ "takes": "anything",
3472
+ "required": true,
3473
+ "note": null
3474
+ }
3475
+ ],
3476
+ "variants": [
3477
+ {
3478
+ "prop": "orientation",
3479
+ "values": [
3480
+ "vertical",
3481
+ "horizontal",
3482
+ "both"
3483
+ ]
3484
+ }
3485
+ ],
3486
+ "ownsBehaviours": [
3487
+ {
3488
+ "id": "base-ui",
3489
+ "behaviour": "Is built on Base UI"
3490
+ },
3491
+ {
3492
+ "id": "scroll",
3493
+ "behaviour": "Scrolls with our scrollbar"
3494
+ }
3495
+ ],
3496
+ "status": "stable",
3497
+ "migrationStage": null,
3498
+ "docsId": "layout-scrollarea--docs",
3499
+ "storyId": "layout-scrollarea--default",
3500
+ "docPage": "src/ScrollArea.mdx",
3501
+ "app": null
3502
+ },
3503
+ {
3504
+ "name": "SearchInput",
3505
+ "repo": "estiva-ui",
3506
+ "kind": "component",
3507
+ "importPath": "@estiva-app/ui",
3508
+ "sourceFile": "src/SearchInput.tsx",
3509
+ "purpose": "An inset field with a hairline border that strengthens on hover and on focus, and an optional keyboard hint at the right edge.",
3510
+ "purposeFrom": "page",
3511
+ "props": [
3512
+ {
3513
+ "name": "shortcut",
3514
+ "takes": "text",
3515
+ "required": false,
3516
+ "note": "A keyboard hint drawn at the right edge, e.g."
3517
+ },
3518
+ {
3519
+ "name": "className",
3520
+ "takes": "text",
3521
+ "required": false,
3522
+ "note": null
3523
+ }
3524
+ ],
3525
+ "variants": [],
3526
+ "ownsBehaviours": [
3527
+ {
3528
+ "id": "base-ui",
3529
+ "behaviour": "Is built on Base UI"
3530
+ }
3531
+ ],
3532
+ "status": "stable",
3533
+ "migrationStage": null,
3534
+ "docsId": "inputs-searchinput--docs",
3535
+ "storyId": "inputs-searchinput--default",
3536
+ "docPage": "src/SearchInput.mdx",
3537
+ "app": null
3538
+ },
3539
+ {
3540
+ "name": "SectionHeader",
3541
+ "repo": "estiva-ui",
3542
+ "kind": "component",
3543
+ "importPath": "@estiva-app/ui",
3544
+ "sourceFile": "src/SectionHeader.tsx",
3545
+ "purpose": "The 32px row a section starts with: a SectionLabel, and actions that appear on hover or focus as IconButtons with tooltips.",
3546
+ "purposeFrom": "page",
3547
+ "props": [
3548
+ {
3549
+ "name": "title",
3550
+ "takes": "text",
3551
+ "required": true,
3552
+ "note": null
3553
+ },
3554
+ {
3555
+ "name": "chevron",
3556
+ "takes": "true/false",
3557
+ "required": false,
3558
+ "note": "Collapsible: draws the chevron and makes the title a button that toggles."
3559
+ },
3560
+ {
3561
+ "name": "isExpanded",
3562
+ "takes": "true/false",
3563
+ "required": false,
3564
+ "note": null
3565
+ },
3566
+ {
3567
+ "name": "onToggle",
3568
+ "takes": "a handler",
3569
+ "required": false,
3570
+ "note": null
3571
+ },
3572
+ {
3573
+ "name": "trailing",
3574
+ "takes": "anything",
3575
+ "required": false,
3576
+ "note": "Beside the title and always visible, before the actions — a count."
3577
+ },
3578
+ {
3579
+ "name": "actions",
3580
+ "takes": "SectionAction[]",
3581
+ "required": false,
3582
+ "note": "Right-aligned, in the order given."
3583
+ },
3584
+ {
3585
+ "name": "showActions",
3586
+ "takes": "hover | always",
3587
+ "required": false,
3588
+ "note": "`hover` reveals the actions while the row is hovered or focused; `always` keeps them."
3589
+ },
3590
+ {
3591
+ "name": "render",
3592
+ "takes": "useRender.RenderProp",
3593
+ "required": false,
3594
+ "note": "What the title renders as, in Base UI's manner."
3595
+ },
3596
+ {
3597
+ "name": "className",
3598
+ "takes": "text",
3599
+ "required": false,
3600
+ "note": null
3601
+ }
3602
+ ],
3603
+ "variants": [
3604
+ {
3605
+ "prop": "showActions",
3606
+ "values": [
3607
+ "hover",
3608
+ "always"
3609
+ ]
3610
+ }
3611
+ ],
3612
+ "ownsBehaviours": [],
3613
+ "status": "stable",
3614
+ "migrationStage": null,
3615
+ "docsId": "navigation-sectionheader--docs",
3616
+ "storyId": "navigation-sectionheader--plain",
3617
+ "docPage": "src/SectionHeader.mdx",
3618
+ "app": null
3619
+ },
3620
+ {
3621
+ "name": "SectionLabel",
3622
+ "repo": "estiva-ui",
3623
+ "kind": "component",
3624
+ "importPath": "@estiva-app/ui",
3625
+ "sourceFile": "src/SectionLabel.tsx",
3626
+ "purpose": "The section-title span. Every section heading — sidebar sections, menu headings, panel titles — renders through it, so a change of voice is one edit. 12px / 500, primary text; some themes restyle it (the toolbar shows how).",
3627
+ "purposeFrom": "page",
3628
+ "props": [
3629
+ {
3630
+ "name": "children",
3631
+ "takes": "anything",
3632
+ "required": true,
3633
+ "note": null
3634
+ },
3635
+ {
3636
+ "name": "tone",
3637
+ "takes": "primary | secondary",
3638
+ "required": false,
3639
+ "note": null
3640
+ },
3641
+ {
3642
+ "name": "className",
3643
+ "takes": "text",
3644
+ "required": false,
3645
+ "note": null
3646
+ }
3647
+ ],
3648
+ "variants": [
3649
+ {
3650
+ "prop": "tone",
3651
+ "values": [
3652
+ "primary",
3653
+ "secondary"
3654
+ ]
3655
+ }
3656
+ ],
3657
+ "ownsBehaviours": [],
3658
+ "status": "stable",
3659
+ "migrationStage": null,
3660
+ "docsId": "primitives-sectionlabel--docs",
3661
+ "storyId": "primitives-sectionlabel--default",
3662
+ "docPage": "src/SectionLabel.mdx",
3663
+ "app": null
3664
+ },
3665
+ {
3666
+ "name": "Select",
3667
+ "repo": "estiva-ui",
3668
+ "kind": "component",
3669
+ "importPath": "@estiva-app/ui",
3670
+ "sourceFile": "src/Select.tsx",
3671
+ "purpose": "One value for a form field: a button that shows the choice and opens a portalled listbox under itself.",
3672
+ "purposeFrom": "page",
3673
+ "props": [
3674
+ {
3675
+ "name": "value",
3676
+ "takes": "text",
3677
+ "required": true,
3678
+ "note": null
3679
+ },
3680
+ {
3681
+ "name": "onChange",
3682
+ "takes": "a handler",
3683
+ "required": true,
3684
+ "note": null
3685
+ },
3686
+ {
3687
+ "name": "options",
3688
+ "takes": "SelectOption[]",
3689
+ "required": true,
3690
+ "note": null
3691
+ },
3692
+ {
3693
+ "name": "size",
3694
+ "takes": "default | small",
3695
+ "required": false,
3696
+ "note": null
3697
+ },
3698
+ {
3699
+ "name": "ariaLabel",
3700
+ "takes": "text",
3701
+ "required": false,
3702
+ "note": null
3703
+ },
3704
+ {
3705
+ "name": "aria-required",
3706
+ "takes": "boolean | 'true' | 'false'",
3707
+ "required": false,
3708
+ "note": "Set by a `Field` with `required`; a caller inside one owes nothing."
3709
+ },
3710
+ {
3711
+ "name": "placeholder",
3712
+ "takes": "text",
3713
+ "required": false,
3714
+ "note": null
3715
+ },
3716
+ {
3717
+ "name": "disabled",
3718
+ "takes": "true/false",
3719
+ "required": false,
3720
+ "note": null
3721
+ },
3722
+ {
3723
+ "name": "className",
3724
+ "takes": "text",
3725
+ "required": false,
3726
+ "note": null
3727
+ }
3728
+ ],
3729
+ "variants": [
3730
+ {
3731
+ "prop": "size",
3732
+ "values": [
3733
+ "default",
3734
+ "small"
3735
+ ]
3736
+ }
3737
+ ],
3738
+ "ownsBehaviours": [
3739
+ {
3740
+ "id": "base-ui",
3741
+ "behaviour": "Is built on Base UI"
3742
+ },
3743
+ {
3744
+ "id": "portal",
3745
+ "behaviour": "Floats on top of the page"
3746
+ },
3747
+ {
3748
+ "id": "press-outside",
3749
+ "behaviour": "Closes on a press outside"
3750
+ },
3751
+ {
3752
+ "id": "page-keys",
3753
+ "behaviour": "Closes on Escape, and takes its keys, by itself"
3754
+ },
3755
+ {
3756
+ "id": "follow",
3757
+ "behaviour": "Stays attached to its anchor on scroll and resize"
3758
+ },
3759
+ {
3760
+ "id": "walking",
3761
+ "behaviour": "Moves through its items with the arrow keys"
3762
+ },
3763
+ {
3764
+ "id": "role",
3765
+ "behaviour": "Says what it is to assistive technology"
3766
+ }
3767
+ ],
3768
+ "status": "stable",
3769
+ "migrationStage": null,
3770
+ "docsId": "inputs-select--docs",
3771
+ "storyId": "inputs-select--default",
3772
+ "docPage": "src/Select.mdx",
3773
+ "app": null
3774
+ },
3775
+ {
3776
+ "name": "Sidebar",
3777
+ "repo": "estiva-ui",
3778
+ "kind": "component",
3779
+ "importPath": "@estiva-app/ui",
3780
+ "sourceFile": "src/Sidebar.tsx",
3781
+ "purpose": "The navigation column: 240px, a hairline on its right, the surface behind it, scrolling independently of the content beside it.",
3782
+ "purposeFrom": "page",
3783
+ "props": [
3784
+ {
3785
+ "name": "aria-label",
3786
+ "takes": "text",
3787
+ "required": false,
3788
+ "note": "Names the navigation region for assistive tech."
3789
+ },
3790
+ {
3791
+ "name": "children",
3792
+ "takes": "anything",
3793
+ "required": true,
3794
+ "note": null
3795
+ },
3796
+ {
3797
+ "name": "className",
3798
+ "takes": "text",
3799
+ "required": false,
3800
+ "note": null
3801
+ }
3802
+ ],
3803
+ "variants": [],
3804
+ "ownsBehaviours": [],
3805
+ "status": "stable",
3806
+ "migrationStage": null,
3807
+ "docsId": "frame-sidebar--docs",
3808
+ "storyId": "frame-sidebar--composed",
3809
+ "docPage": "src/Sidebar.mdx",
3810
+ "app": null
3811
+ },
3812
+ {
3813
+ "name": "SkeletonBar",
3814
+ "repo": "estiva-ui",
3815
+ "kind": "component",
3816
+ "importPath": "@estiva-app/ui",
3817
+ "sourceFile": "src/Skeleton.tsx",
3818
+ "purpose": "One pulsing bar at the inset colour: the piece every placeholder here is built from.",
3819
+ "purposeFrom": "comment",
3820
+ "props": [
3821
+ {
3822
+ "name": "className",
3823
+ "takes": "text",
3824
+ "required": false,
3825
+ "note": null
3826
+ },
3827
+ {
3828
+ "name": "style",
3829
+ "takes": "CSSProperties",
3830
+ "required": false,
3831
+ "note": null
3832
+ }
3833
+ ],
3834
+ "variants": [],
3835
+ "ownsBehaviours": [],
3836
+ "status": "stable",
3837
+ "migrationStage": null,
3838
+ "docsId": "feedback-skeleton--docs",
3839
+ "storyId": "feedback-skeleton--list",
3840
+ "docPage": null,
3841
+ "app": null
3842
+ },
3843
+ {
3844
+ "name": "SkeletonList",
3845
+ "repo": "estiva-ui",
3846
+ "kind": "component",
3847
+ "importPath": "@estiva-app/ui",
3848
+ "sourceFile": "src/Skeleton.tsx",
3849
+ "purpose": "Rows of varied widths, so the placeholder does not read as a pattern.",
3850
+ "purposeFrom": "comment",
3851
+ "props": [
3852
+ {
3853
+ "name": "rows",
3854
+ "takes": "number",
3855
+ "required": false,
3856
+ "note": null
3857
+ },
3858
+ {
3859
+ "name": "className",
3860
+ "takes": "text",
3861
+ "required": false,
3862
+ "note": null
3863
+ }
3864
+ ],
3865
+ "variants": [],
3866
+ "ownsBehaviours": [],
3867
+ "status": "stable",
3868
+ "migrationStage": null,
3869
+ "docsId": "feedback-skeleton--docs",
3870
+ "storyId": "feedback-skeleton--list",
3871
+ "docPage": null,
3872
+ "app": null
3873
+ },
3874
+ {
3875
+ "name": "SkeletonRow",
3876
+ "repo": "estiva-ui",
3877
+ "kind": "component",
3878
+ "importPath": "@estiva-app/ui",
3879
+ "sourceFile": "src/Skeleton.tsx",
3880
+ "purpose": "A 32px row: a 16px square and a bar, like a row with a face and a name.",
3881
+ "purposeFrom": "comment",
3882
+ "props": [
3883
+ {
3884
+ "name": "barWidth",
3885
+ "takes": "number",
3886
+ "required": false,
3887
+ "note": null
3888
+ }
3889
+ ],
3890
+ "variants": [],
3891
+ "ownsBehaviours": [],
3892
+ "status": "stable",
3893
+ "migrationStage": null,
3894
+ "docsId": "feedback-skeleton--docs",
3895
+ "storyId": "feedback-skeleton--list",
3896
+ "docPage": null,
3897
+ "app": null
3898
+ },
3899
+ {
3900
+ "name": "Tabs",
3901
+ "repo": "estiva-ui",
3902
+ "kind": "component",
3903
+ "importPath": "@estiva-app/ui",
3904
+ "sourceFile": "src/Tabs.tsx",
3905
+ "purpose": "A row of tabs for switching between views of one thing.",
3906
+ "purposeFrom": "page",
3907
+ "props": [
3908
+ {
3909
+ "name": "tabs",
3910
+ "takes": "TabDef<T>[]",
3911
+ "required": true,
3912
+ "note": null
3913
+ },
3914
+ {
3915
+ "name": "active",
3916
+ "takes": "T",
3917
+ "required": true,
3918
+ "note": null
3919
+ },
3920
+ {
3921
+ "name": "onChange",
3922
+ "takes": "a handler",
3923
+ "required": true,
3924
+ "note": null
3925
+ },
3926
+ {
3927
+ "name": "size",
3928
+ "takes": "default | small",
3929
+ "required": false,
3930
+ "note": "`default` 14px; `small` 12px, the denser geometry."
3931
+ },
3932
+ {
3933
+ "name": "aria-label",
3934
+ "takes": "text",
3935
+ "required": false,
3936
+ "note": "Names the row for assistive tech — \"Views\", \"Filters\"."
3937
+ },
3938
+ {
3939
+ "name": "aria-labelledby",
3940
+ "takes": "text",
3941
+ "required": false,
3942
+ "note": null
3943
+ },
3944
+ {
3945
+ "name": "className",
3946
+ "takes": "text",
3947
+ "required": false,
3948
+ "note": "Lands on the outer box, around the row."
3949
+ }
3950
+ ],
3951
+ "variants": [
3952
+ {
3953
+ "prop": "size",
3954
+ "values": [
3955
+ "default",
3956
+ "small"
3957
+ ]
3958
+ }
3959
+ ],
3960
+ "ownsBehaviours": [
3961
+ {
3962
+ "id": "base-ui",
3963
+ "behaviour": "Is built on Base UI"
3964
+ },
3965
+ {
3966
+ "id": "page-keys",
3967
+ "behaviour": "Closes on Escape, and takes its keys, by itself"
3968
+ },
3969
+ {
3970
+ "id": "walking",
3971
+ "behaviour": "Moves through its items with the arrow keys"
3972
+ },
3973
+ {
3974
+ "id": "role",
3975
+ "behaviour": "Says what it is to assistive technology"
3976
+ }
3977
+ ],
3978
+ "status": "stable",
3979
+ "migrationStage": null,
3980
+ "docsId": "navigation-tabs--docs",
3981
+ "storyId": "navigation-tabs--with-counts",
3982
+ "docPage": "src/Tabs.mdx",
3983
+ "app": null
3984
+ },
3985
+ {
3986
+ "name": "Textarea",
3987
+ "repo": "estiva-ui",
3988
+ "kind": "component",
3989
+ "importPath": "@estiva-app/ui",
3990
+ "sourceFile": "src/Textarea.tsx",
3991
+ "purpose": "TextInput's look on a multi-line field that does not resize.",
3992
+ "purposeFrom": "page",
3993
+ "props": [],
3994
+ "variants": [],
3995
+ "ownsBehaviours": [],
3996
+ "status": "stable",
3997
+ "migrationStage": null,
3998
+ "docsId": "inputs-textarea--docs",
3999
+ "storyId": "inputs-textarea--empty",
4000
+ "docPage": "src/Textarea.mdx",
4001
+ "app": null
4002
+ },
4003
+ {
4004
+ "name": "TextInput",
4005
+ "repo": "estiva-ui",
4006
+ "kind": "component",
4007
+ "importPath": "@estiva-app/ui",
4008
+ "sourceFile": "src/TextInput.tsx",
4009
+ "purpose": "The single-line field: inset surface, 8px radius, 14px text, a stronger border on hover, the focus border in every theme.",
4010
+ "purposeFrom": "page",
4011
+ "props": [
4012
+ {
4013
+ "name": "size",
4014
+ "takes": "default | small",
4015
+ "required": false,
4016
+ "note": "`small` is 24px tall with 12px text — the small `Select`'s size, so a field can share a dense row with small selects (D67, 2026-09-13: Peek's reference widget hand-built one because this was 38px)."
4017
+ }
4018
+ ],
4019
+ "variants": [
4020
+ {
4021
+ "prop": "size",
4022
+ "values": [
4023
+ "default",
4024
+ "small"
4025
+ ]
4026
+ }
4027
+ ],
4028
+ "ownsBehaviours": [
4029
+ {
4030
+ "id": "base-ui",
4031
+ "behaviour": "Is built on Base UI"
4032
+ }
4033
+ ],
4034
+ "status": "stable",
4035
+ "migrationStage": null,
4036
+ "docsId": "inputs-textinput--docs",
4037
+ "storyId": "inputs-textinput--empty",
4038
+ "docPage": "src/TextInput.mdx",
4039
+ "app": null
4040
+ },
4041
+ {
4042
+ "name": "Toast",
4043
+ "repo": "estiva-ui",
4044
+ "kind": "component",
4045
+ "importPath": "@estiva-app/ui",
4046
+ "sourceFile": "src/Toast.tsx",
4047
+ "purpose": "A pill that says what just happened — three types, an optional leading check, an optional action — and ToastProvider/useToast, which own the positioning (bottom-left), the portal, and the auto-dismiss.",
4048
+ "purposeFrom": "page",
4049
+ "props": [
4050
+ {
4051
+ "name": "label",
4052
+ "takes": "text",
4053
+ "required": true,
4054
+ "note": null
4055
+ },
4056
+ {
4057
+ "name": "type",
4058
+ "takes": "success | brand | neutral | warning | error",
4059
+ "required": false,
4060
+ "note": "Which of the five this is. It decides the surface in the light themes, and under Signal — where every pill is the same dark overlay — the icon and its colour."
4061
+ },
4062
+ {
4063
+ "name": "leadingIcon",
4064
+ "takes": "true/false",
4065
+ "required": false,
4066
+ "note": "Show the leading icon — a check, a `!` or an `×`, per `type`."
4067
+ },
4068
+ {
4069
+ "name": "actionLabel",
4070
+ "takes": "text",
4071
+ "required": false,
4072
+ "note": "When set together with onAction, renders a clickable action on the right side."
4073
+ },
4074
+ {
4075
+ "name": "onAction",
4076
+ "takes": "a handler",
4077
+ "required": false,
4078
+ "note": null
4079
+ },
4080
+ {
4081
+ "name": "className",
4082
+ "takes": "text",
4083
+ "required": false,
4084
+ "note": null
4085
+ }
4086
+ ],
4087
+ "variants": [
4088
+ {
4089
+ "prop": "type",
4090
+ "values": [
4091
+ "success",
4092
+ "brand",
4093
+ "neutral",
4094
+ "warning",
4095
+ "error"
4096
+ ]
4097
+ }
4098
+ ],
4099
+ "ownsBehaviours": [
4100
+ {
4101
+ "id": "base-ui",
4102
+ "behaviour": "Is built on Base UI"
4103
+ },
4104
+ {
4105
+ "id": "portal",
4106
+ "behaviour": "Floats on top of the page"
4107
+ },
4108
+ {
4109
+ "id": "role",
4110
+ "behaviour": "Says what it is to assistive technology"
4111
+ }
4112
+ ],
4113
+ "status": "stable",
4114
+ "migrationStage": null,
4115
+ "docsId": "feedback-toast--docs",
4116
+ "storyId": "feedback-toast--neutral",
4117
+ "docPage": "src/Toast.mdx",
4118
+ "app": null
4119
+ },
4120
+ {
4121
+ "name": "ToastProvider",
4122
+ "repo": "estiva-ui",
4123
+ "kind": "component",
4124
+ "importPath": "@estiva-app/ui",
4125
+ "sourceFile": "src/Toast.tsx",
4126
+ "purpose": "Mount once, near the top of an app. It owns the stack, the timers and the portal every toast goes through, and it is what `useToast` talks to.",
4127
+ "purposeFrom": "comment",
4128
+ "props": [
4129
+ {
4130
+ "name": "children",
4131
+ "takes": "anything",
4132
+ "required": true,
4133
+ "note": null
4134
+ }
4135
+ ],
4136
+ "variants": [],
4137
+ "ownsBehaviours": [],
4138
+ "status": "stable",
4139
+ "migrationStage": null,
4140
+ "docsId": "feedback-toast--docs",
4141
+ "storyId": "feedback-toast--neutral",
4142
+ "docPage": null,
4143
+ "app": null
4144
+ },
4145
+ {
4146
+ "name": "Toolbar",
4147
+ "repo": "estiva-ui",
4148
+ "kind": "component",
4149
+ "importPath": "@estiva-app/ui",
4150
+ "sourceFile": "src/Toolbar.tsx",
4151
+ "purpose": "A strip of controls that behaves as one control: Tab in, arrow keys along, Tab out — on the elevated box a floating strip needs.",
4152
+ "purposeFrom": "page",
4153
+ "props": [
4154
+ {
4155
+ "name": "aria-label",
4156
+ "takes": "text",
4157
+ "required": true,
4158
+ "note": "Names the strip for assistive tech — \"Formatting\", \"Reactions\"."
4159
+ },
4160
+ {
4161
+ "name": "orientation",
4162
+ "takes": "horizontal | vertical",
4163
+ "required": false,
4164
+ "note": "`horizontal` walks with ← →, `vertical` with ↑ ↓."
4165
+ },
4166
+ {
4167
+ "name": "loopFocus",
4168
+ "takes": "true/false",
4169
+ "required": false,
4170
+ "note": "Whether the arrow keys wrap at the ends."
4171
+ },
4172
+ {
4173
+ "name": "surface",
4174
+ "takes": "true/false",
4175
+ "required": false,
4176
+ "note": "The elevated box around the strip. On by default — a toolbar floats, and this is what floating looks like here."
4177
+ },
4178
+ {
4179
+ "name": "children",
4180
+ "takes": "anything",
4181
+ "required": true,
4182
+ "note": null
4183
+ },
4184
+ {
4185
+ "name": "className",
4186
+ "takes": "text",
4187
+ "required": false,
4188
+ "note": "The row's own layout — its gap, its padding, its wrapping."
4189
+ }
4190
+ ],
4191
+ "variants": [
4192
+ {
4193
+ "prop": "orientation",
4194
+ "values": [
4195
+ "horizontal",
4196
+ "vertical"
4197
+ ]
4198
+ }
4199
+ ],
4200
+ "ownsBehaviours": [
4201
+ {
4202
+ "id": "base-ui",
4203
+ "behaviour": "Is built on Base UI"
4204
+ },
4205
+ {
4206
+ "id": "page-keys",
4207
+ "behaviour": "Closes on Escape, and takes its keys, by itself"
4208
+ },
4209
+ {
4210
+ "id": "walking",
4211
+ "behaviour": "Moves through its items with the arrow keys"
4212
+ },
4213
+ {
4214
+ "id": "role",
4215
+ "behaviour": "Says what it is to assistive technology"
4216
+ }
4217
+ ],
4218
+ "status": "stable",
4219
+ "migrationStage": null,
4220
+ "docsId": "primitives-toolbar--docs",
4221
+ "storyId": "primitives-toolbar--default",
4222
+ "docPage": "src/Toolbar.mdx",
4223
+ "app": null
4224
+ },
4225
+ {
4226
+ "name": "ToolbarButton",
4227
+ "repo": "estiva-ui",
4228
+ "kind": "component",
4229
+ "importPath": "@estiva-app/ui",
4230
+ "sourceFile": "src/Toolbar.tsx",
4231
+ "purpose": "An `IconButton` that is an item of a `Toolbar`: the arrow keys reach it, and a disabled one stays in the walk so its reason can still be read.",
4232
+ "purposeFrom": "comment",
4233
+ "props": [
4234
+ {
4235
+ "name": "ref",
4236
+ "takes": "Ref<HTMLButtonElement>",
4237
+ "required": false,
4238
+ "note": null
4239
+ },
4240
+ {
4241
+ "name": "variant",
4242
+ "takes": "muted | outlined | primary | current | resolve",
4243
+ "required": false,
4244
+ "note": "`current` takes the colour of what it sits in — the ✕ on a `Banner` wears the banner's tone."
4245
+ },
4246
+ {
4247
+ "name": "pressed",
4248
+ "takes": "true/false",
4249
+ "required": false,
4250
+ "note": "On, like a Bold button while the selection is bold: the active fill, and `aria-pressed`."
4251
+ },
4252
+ {
4253
+ "name": "glow",
4254
+ "takes": "true/false",
4255
+ "required": false,
4256
+ "note": "A glow in Signal — the send arrow while there is something to send."
4257
+ },
4258
+ {
4259
+ "name": "tooltip",
4260
+ "takes": "text",
4261
+ "required": false,
4262
+ "note": null
4263
+ },
4264
+ {
4265
+ "name": "tooltipShortcut",
4266
+ "takes": "text",
4267
+ "required": false,
4268
+ "note": "A key hint drawn as the `Kbd` chip inside the tooltip — for a button whose only other affordance is a keyboard shortcut."
4269
+ },
4270
+ {
4271
+ "name": "tooltipPlacement",
4272
+ "takes": "top | bottom",
4273
+ "required": false,
4274
+ "note": null
4275
+ },
4276
+ {
4277
+ "name": "disabledReason",
4278
+ "takes": "text",
4279
+ "required": false,
4280
+ "note": "Why the action cannot succeed right now."
4281
+ },
4282
+ {
4283
+ "name": "children",
4284
+ "takes": "anything",
4285
+ "required": true,
4286
+ "note": "The icon: 16px, stroke 1.5."
4287
+ }
4288
+ ],
4289
+ "variants": [
4290
+ {
4291
+ "prop": "variant",
4292
+ "values": [
4293
+ "muted",
4294
+ "outlined",
4295
+ "primary",
4296
+ "current",
4297
+ "resolve"
4298
+ ]
4299
+ },
4300
+ {
4301
+ "prop": "tooltipPlacement",
4302
+ "values": [
4303
+ "top",
4304
+ "bottom"
4305
+ ]
4306
+ }
4307
+ ],
4308
+ "ownsBehaviours": [],
4309
+ "status": "stable",
4310
+ "migrationStage": null,
4311
+ "docsId": "primitives-toolbar--docs",
4312
+ "storyId": "primitives-toolbar--default",
4313
+ "docPage": null,
4314
+ "app": null
4315
+ },
4316
+ {
4317
+ "name": "ToolbarInput",
4318
+ "repo": "estiva-ui",
4319
+ "kind": "component",
4320
+ "importPath": "@estiva-app/ui",
4321
+ "sourceFile": "src/Toolbar.tsx",
4322
+ "purpose": "A `TextInput` that is an item of a `Toolbar`, so the arrow keys walk into the field and out of it again.",
4323
+ "purposeFrom": "comment",
4324
+ "props": [
4325
+ {
4326
+ "name": "size",
4327
+ "takes": "default | small",
4328
+ "required": false,
4329
+ "note": "`small` is 24px tall with 12px text — the small `Select`'s size, so a field can share a dense row with small selects (D67, 2026-09-13: Peek's reference widget hand-built one because this was 38px)."
4330
+ }
4331
+ ],
4332
+ "variants": [
4333
+ {
4334
+ "prop": "size",
4335
+ "values": [
4336
+ "default",
4337
+ "small"
4338
+ ]
4339
+ }
4340
+ ],
4341
+ "ownsBehaviours": [],
4342
+ "status": "stable",
4343
+ "migrationStage": null,
4344
+ "docsId": "primitives-toolbar--docs",
4345
+ "storyId": "primitives-toolbar--default",
4346
+ "docPage": null,
4347
+ "app": null
4348
+ },
4349
+ {
4350
+ "name": "ToolbarSeparator",
4351
+ "repo": "estiva-ui",
4352
+ "kind": "component",
4353
+ "importPath": "@estiva-app/ui",
4354
+ "sourceFile": "src/Toolbar.tsx",
4355
+ "purpose": "The hairline between two groups of controls.",
4356
+ "purposeFrom": "comment",
4357
+ "props": [
4358
+ {
4359
+ "name": "className",
4360
+ "takes": "text",
4361
+ "required": false,
4362
+ "note": null
4363
+ }
4364
+ ],
4365
+ "variants": [],
4366
+ "ownsBehaviours": [],
4367
+ "status": "stable",
4368
+ "migrationStage": null,
4369
+ "docsId": "primitives-toolbar--docs",
4370
+ "storyId": "primitives-toolbar--default",
4371
+ "docPage": null,
4372
+ "app": null
4373
+ },
4374
+ {
4375
+ "name": "Tooltip",
4376
+ "repo": "estiva-ui",
4377
+ "kind": "component",
4378
+ "importPath": "@estiva-app/ui",
4379
+ "sourceFile": "src/Tooltip.tsx",
4380
+ "purpose": "A 30px elevated pill with a caption, and WithTooltip, the wrapper that shows it beside a trigger — on hover, and on keyboard focus.",
4381
+ "purposeFrom": "page",
4382
+ "props": [
4383
+ {
4384
+ "name": "label",
4385
+ "takes": "text",
4386
+ "required": true,
4387
+ "note": null
4388
+ },
4389
+ {
4390
+ "name": "shortcut",
4391
+ "takes": "text",
4392
+ "required": false,
4393
+ "note": "The key that does the same thing, drawn as the `Kbd` chip after the label."
4394
+ }
4395
+ ],
4396
+ "variants": [],
4397
+ "ownsBehaviours": [
4398
+ {
4399
+ "id": "base-ui",
4400
+ "behaviour": "Is built on Base UI"
4401
+ },
4402
+ {
4403
+ "id": "portal",
4404
+ "behaviour": "Floats on top of the page"
4405
+ },
4406
+ {
4407
+ "id": "follow",
4408
+ "behaviour": "Stays attached to its anchor on scroll and resize"
4409
+ },
4410
+ {
4411
+ "id": "role",
4412
+ "behaviour": "Says what it is to assistive technology"
4413
+ }
4414
+ ],
4415
+ "status": "stable",
4416
+ "migrationStage": null,
4417
+ "docsId": "primitives-tooltip--docs",
4418
+ "storyId": "primitives-tooltip--default",
4419
+ "docPage": "src/Tooltip.mdx",
4420
+ "app": null
4421
+ },
4422
+ {
4423
+ "name": "TooltipProvider",
4424
+ "repo": "estiva-ui",
4425
+ "kind": "component",
4426
+ "importPath": "@estiva-app/ui",
4427
+ "sourceFile": "src/Tooltip.tsx",
4428
+ "purpose": "Mount once at the top of an app: it makes every tooltip below it share one delay, so the second and third open instantly while the group is warm.",
4429
+ "purposeFrom": "comment",
4430
+ "props": [
4431
+ {
4432
+ "name": "delay",
4433
+ "takes": "number",
4434
+ "required": false,
4435
+ "note": "Before the first tooltip in the group opens."
4436
+ },
4437
+ {
4438
+ "name": "closeDelay",
4439
+ "takes": "number",
4440
+ "required": false,
4441
+ "note": "Before one closes. Default: immediately, as it always has."
4442
+ },
4443
+ {
4444
+ "name": "timeout",
4445
+ "takes": "number",
4446
+ "required": false,
4447
+ "note": "How long after one closes its neighbours still open instantly."
4448
+ },
4449
+ {
4450
+ "name": "children",
4451
+ "takes": "anything",
4452
+ "required": true,
4453
+ "note": null
4454
+ }
4455
+ ],
4456
+ "variants": [],
4457
+ "ownsBehaviours": [],
4458
+ "status": "stable",
4459
+ "migrationStage": null,
4460
+ "docsId": "primitives-tooltip--docs",
4461
+ "storyId": "primitives-tooltip--default",
4462
+ "docPage": null,
4463
+ "app": null
4464
+ },
4465
+ {
4466
+ "name": "TopBar",
4467
+ "repo": "estiva-ui",
4468
+ "kind": "component",
4469
+ "importPath": "@estiva-app/ui",
4470
+ "sourceFile": "src/TopBar.tsx",
4471
+ "purpose": "The 52px top bar: `menu` and `logo` on the left, a `search` slot in the centre, the identity cluster on the right.",
4472
+ "purposeFrom": "page",
4473
+ "props": [
4474
+ {
4475
+ "name": "variant",
4476
+ "takes": "solid | floating",
4477
+ "required": false,
4478
+ "note": null
4479
+ },
4480
+ {
4481
+ "name": "menu",
4482
+ "takes": "anything",
4483
+ "required": false,
4484
+ "note": "Far left: the menu button, in an app whose navigation collapses."
4485
+ },
4486
+ {
4487
+ "name": "logo",
4488
+ "takes": "anything",
4489
+ "required": false,
4490
+ "note": "Beside the menu button: the app's logo mark, or its name as text."
4491
+ },
4492
+ {
4493
+ "name": "search",
4494
+ "takes": "anything",
4495
+ "required": false,
4496
+ "note": "The centre: a search field, or a launcher affordance — or nothing; the slot holds its place."
4497
+ },
4498
+ {
4499
+ "name": "right",
4500
+ "takes": "anything",
4501
+ "required": false,
4502
+ "note": "The right cluster — an `IdentityMenu` and its neighbours."
4503
+ },
4504
+ {
4505
+ "name": "className",
4506
+ "takes": "text",
4507
+ "required": false,
4508
+ "note": null
4509
+ }
4510
+ ],
4511
+ "variants": [
4512
+ {
4513
+ "prop": "variant",
4514
+ "values": [
4515
+ "solid",
4516
+ "floating"
4517
+ ]
4518
+ }
4519
+ ],
4520
+ "ownsBehaviours": [],
4521
+ "status": "stable",
4522
+ "migrationStage": null,
4523
+ "docsId": "frame-topbar--docs",
4524
+ "storyId": "frame-topbar--solid",
4525
+ "docPage": "src/TopBar.mdx",
4526
+ "app": null
4527
+ },
4528
+ {
4529
+ "name": "useToast",
4530
+ "repo": "estiva-ui",
4531
+ "kind": "hook",
4532
+ "importPath": "@estiva-app/ui",
4533
+ "sourceFile": "src/Toast.tsx",
4534
+ "purpose": "How anything under a `ToastProvider` raises a toast (`showToast`) or takes one away (`dismissToast`).",
4535
+ "purposeFrom": "comment",
4536
+ "props": [],
4537
+ "variants": [],
4538
+ "ownsBehaviours": [],
4539
+ "status": "stable",
4540
+ "migrationStage": null,
4541
+ "docsId": "feedback-toast--docs",
4542
+ "storyId": "feedback-toast--neutral",
4543
+ "docPage": null,
4544
+ "app": null
4545
+ },
4546
+ {
4547
+ "name": "WithTooltip",
4548
+ "repo": "estiva-ui",
4549
+ "kind": "component",
4550
+ "importPath": "@estiva-app/ui",
4551
+ "sourceFile": "src/Tooltip.tsx",
4552
+ "purpose": "A tooltip on something that cannot be its own trigger — a span, a `Chip`, an icon.",
4553
+ "purposeFrom": "comment",
4554
+ "props": [
4555
+ {
4556
+ "name": "label",
4557
+ "takes": "text",
4558
+ "required": true,
4559
+ "note": null
4560
+ },
4561
+ {
4562
+ "name": "shortcut",
4563
+ "takes": "text",
4564
+ "required": false,
4565
+ "note": "Passed straight to the surface — see `TooltipProps.shortcut`."
4566
+ },
4567
+ {
4568
+ "name": "placement",
4569
+ "takes": "top | bottom",
4570
+ "required": false,
4571
+ "note": null
4572
+ },
4573
+ {
4574
+ "name": "wrapperClassName",
4575
+ "takes": "text",
4576
+ "required": false,
4577
+ "note": "Extra classes on the wrapper — e.g. `min-w-0 shrink` so a truncating label keeps truncating inside it."
4578
+ },
4579
+ {
4580
+ "name": "children",
4581
+ "takes": "anything",
4582
+ "required": true,
4583
+ "note": null
4584
+ }
4585
+ ],
4586
+ "variants": [
4587
+ {
4588
+ "prop": "placement",
4589
+ "values": [
4590
+ "top",
4591
+ "bottom"
4592
+ ]
4593
+ }
4594
+ ],
4595
+ "ownsBehaviours": [
4596
+ {
4597
+ "id": "base-ui",
4598
+ "behaviour": "Is built on Base UI"
4599
+ },
4600
+ {
4601
+ "id": "role",
4602
+ "behaviour": "Says what it is to assistive technology"
4603
+ }
4604
+ ],
4605
+ "status": "stable",
4606
+ "migrationStage": null,
4607
+ "docsId": "primitives-tooltip--docs",
4608
+ "storyId": "primitives-tooltip--default",
4609
+ "docPage": null,
4610
+ "app": null
4611
+ }
4612
+ ],
4613
+ "excluded": [],
4614
+ "filesWithoutParts": []
4615
+ }