@estiva-app/ui 0.23.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AppShell.d.ts.map +1 -1
- package/dist/AttachmentCard.d.ts.map +1 -1
- package/dist/Form.d.ts.map +1 -1
- package/dist/IconButton.d.ts +9 -1
- package/dist/IconButton.d.ts.map +1 -1
- package/dist/ListColumn.d.ts +41 -0
- package/dist/ListColumn.d.ts.map +1 -0
- package/dist/PreviewCard.d.ts +9 -2
- package/dist/PreviewCard.d.ts.map +1 -1
- package/dist/SectionHeader.d.ts +7 -1
- package/dist/SectionHeader.d.ts.map +1 -1
- package/dist/Select.d.ts +12 -3
- package/dist/Select.d.ts.map +1 -1
- package/dist/Toolbar.d.ts +18 -0
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +13 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/eslint/index.js +2 -1
- package/dist/eslint/index.js.map +2 -2
- package/dist/eslint/no-restyled-part.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +189 -143
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/registry.json +214 -11
- package/src/AppShell.mdx +18 -1
- package/src/AppShell.test.tsx +16 -0
- package/src/AppShell.tsx +4 -1
- package/src/AttachmentCard.mdx +12 -1
- package/src/AttachmentCard.test.tsx +10 -0
- package/src/AttachmentCard.tsx +8 -5
- package/src/Avatar.mdx +20 -5
- package/src/AvatarGroup.mdx +4 -0
- package/src/Banner.mdx +17 -8
- package/src/Breadcrumb.mdx +12 -0
- package/src/Button.mdx +17 -5
- package/src/Button.tsx +2 -2
- package/src/Card.mdx +14 -1
- package/src/Checkbox.mdx +11 -0
- package/src/Chip.mdx +4 -0
- package/src/ChipInput.mdx +13 -1
- package/src/CollapsibleSection.mdx +12 -3
- package/src/CommandPalette.mdx +14 -2
- package/src/ConfirmDialog.mdx +13 -2
- package/src/ContainerHeader.mdx +15 -2
- package/src/DialogShell.mdx +15 -1
- package/src/Divider.mdx +12 -1
- package/src/EditableText.mdx +17 -1
- package/src/EmptyState.mdx +17 -6
- package/src/Field.mdx +13 -5
- package/src/FieldLine.mdx +9 -1
- package/src/FilePicker.mdx +8 -0
- package/src/Form.mdx +11 -1
- package/src/Form.test.tsx +26 -0
- package/src/Form.tsx +7 -0
- package/src/IconButton.mdx +17 -3
- package/src/IconButton.stories.tsx +3 -0
- package/src/IconButton.test.tsx +25 -0
- package/src/IconButton.tsx +61 -46
- package/src/IdentityMenu.mdx +10 -1
- package/src/InlineChip.mdx +11 -0
- package/src/Kbd.mdx +6 -2
- package/src/Link.mdx +13 -1
- package/src/ListColumn.mdx +87 -0
- package/src/ListColumn.stories.tsx +136 -0
- package/src/ListColumn.test.tsx +50 -0
- package/src/ListColumn.tsx +63 -0
- package/src/Menu.mdx +18 -1
- package/src/MenuItem.mdx +15 -2
- package/src/NavItem.mdx +12 -0
- package/src/Person.mdx +7 -0
- package/src/PersonTrigger.mdx +11 -1
- package/src/PersonTrigger.tsx +1 -1
- package/src/Popover.mdx +23 -0
- package/src/PreviewCard.mdx +19 -4
- package/src/PreviewCard.tsx +11 -4
- package/src/ProgressBar.mdx +8 -0
- package/src/Property.mdx +4 -0
- package/src/Rail.mdx +12 -1
- package/src/RailItem.mdx +12 -0
- package/src/RailItem.tsx +1 -1
- package/src/Reaction.mdx +10 -0
- package/src/Reaction.tsx +1 -1
- package/src/ReactionPicker.mdx +8 -0
- package/src/ScrollArea.mdx +16 -2
- package/src/SearchInput.mdx +9 -0
- package/src/SectionHeader.mdx +18 -1
- package/src/SectionHeader.stories.tsx +9 -0
- package/src/SectionHeader.test.tsx +9 -0
- package/src/SectionHeader.tsx +9 -3
- package/src/SectionLabel.mdx +10 -2
- package/src/Select.mdx +24 -4
- package/src/Select.stories.tsx +4 -1
- package/src/Select.test.tsx +29 -0
- package/src/Select.tsx +36 -14
- package/src/Sidebar.mdx +8 -0
- package/src/Skeleton.mdx +8 -0
- package/src/Skeleton.tsx +1 -1
- package/src/Tabs.mdx +12 -1
- package/src/TextInput.mdx +9 -0
- package/src/TextInput.tsx +1 -1
- package/src/Textarea.mdx +8 -0
- package/src/Toast.mdx +12 -1
- package/src/Toolbar.mdx +20 -2
- package/src/Toolbar.stories.tsx +19 -2
- package/src/Toolbar.test.tsx +24 -1
- package/src/Toolbar.tsx +22 -0
- package/src/Tooltip.mdx +27 -2
- package/src/Tooltip.stories.tsx +26 -0
- package/src/Tooltip.test.tsx +51 -0
- package/src/Tooltip.tsx +17 -4
- package/src/TopBar.mdx +11 -0
- package/src/eslint/no-rebuilt-behaviour.ts +1 -1
- package/src/eslint/no-restyled-part.ts +1 -0
- package/src/heights.test.tsx +78 -0
- package/src/index.ts +2 -1
- package/src/pages.test.ts +142 -0
- package/src/registry/registry.test.ts +16 -8
- package/tailwind-preset.js +22 -1
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"kind": "package",
|
|
5
5
|
"repo": "estiva-ui",
|
|
6
6
|
"package": "@estiva-app/ui",
|
|
7
|
-
"packageVersion": "0.
|
|
8
|
-
"exports":
|
|
9
|
-
"typeExports":
|
|
7
|
+
"packageVersion": "0.24.1",
|
|
8
|
+
"exports": 84,
|
|
9
|
+
"typeExports": 94,
|
|
10
10
|
"files": null
|
|
11
11
|
},
|
|
12
12
|
"storybook": {
|
|
@@ -397,7 +397,7 @@
|
|
|
397
397
|
"kind": "component",
|
|
398
398
|
"importPath": "@estiva-app/ui",
|
|
399
399
|
"sourceFile": "src/Button.tsx",
|
|
400
|
-
"purpose": "The push-button for an action: a verb, clicked once — \"Create\", \"Save\", \"Delete
|
|
400
|
+
"purpose": "The push-button for an action: a verb, clicked once — \"Create\", \"Save\", \"Delete\".",
|
|
401
401
|
"purposeFrom": "page",
|
|
402
402
|
"props": [
|
|
403
403
|
{
|
|
@@ -1436,7 +1436,7 @@
|
|
|
1436
1436
|
},
|
|
1437
1437
|
{
|
|
1438
1438
|
"id": "page-keys",
|
|
1439
|
-
"behaviour": "
|
|
1439
|
+
"behaviour": "Takes its keys by itself"
|
|
1440
1440
|
},
|
|
1441
1441
|
{
|
|
1442
1442
|
"id": "focus",
|
|
@@ -1927,6 +1927,12 @@
|
|
|
1927
1927
|
"required": false,
|
|
1928
1928
|
"note": "Why the action cannot succeed right now."
|
|
1929
1929
|
},
|
|
1930
|
+
{
|
|
1931
|
+
"name": "href",
|
|
1932
|
+
"takes": "text",
|
|
1933
|
+
"required": false,
|
|
1934
|
+
"note": "A link that looks like an icon button: an anchor, so the address stays real for a modified click or a new tab, as `Link` keeps it."
|
|
1935
|
+
},
|
|
1930
1936
|
{
|
|
1931
1937
|
"name": "children",
|
|
1932
1938
|
"takes": "anything",
|
|
@@ -2389,6 +2395,81 @@
|
|
|
2389
2395
|
"docPage": "src/Link.mdx",
|
|
2390
2396
|
"app": null
|
|
2391
2397
|
},
|
|
2398
|
+
{
|
|
2399
|
+
"name": "ListColumn",
|
|
2400
|
+
"repo": "estiva-ui",
|
|
2401
|
+
"kind": "component",
|
|
2402
|
+
"importPath": "@estiva-app/ui",
|
|
2403
|
+
"sourceFile": "src/ListColumn.tsx",
|
|
2404
|
+
"purpose": "The list column of a page: 290px wide with a line on its right, its name in a `ContainerHeader`, and the list under it, which scrolls.",
|
|
2405
|
+
"purposeFrom": "page",
|
|
2406
|
+
"props": [
|
|
2407
|
+
{
|
|
2408
|
+
"name": "title",
|
|
2409
|
+
"takes": "anything",
|
|
2410
|
+
"required": true,
|
|
2411
|
+
"note": "The column's name, in its header. A node for a title that is more than words."
|
|
2412
|
+
},
|
|
2413
|
+
{
|
|
2414
|
+
"name": "chevron",
|
|
2415
|
+
"takes": "true/false",
|
|
2416
|
+
"required": false,
|
|
2417
|
+
"note": "A chevron after the title, as `ContainerHeader` draws it."
|
|
2418
|
+
},
|
|
2419
|
+
{
|
|
2420
|
+
"name": "actions",
|
|
2421
|
+
"takes": "anything",
|
|
2422
|
+
"required": false,
|
|
2423
|
+
"note": "The column's own actions, at the header's right — a `Toolbar` of `ToolbarButton`s, or one `IconButton`."
|
|
2424
|
+
},
|
|
2425
|
+
{
|
|
2426
|
+
"name": "above",
|
|
2427
|
+
"takes": "anything",
|
|
2428
|
+
"required": false,
|
|
2429
|
+
"note": "A row between the header and the list that stays put while the list scrolls — a field that adds to the list."
|
|
2430
|
+
},
|
|
2431
|
+
{
|
|
2432
|
+
"name": "spacing",
|
|
2433
|
+
"takes": "rows | sections",
|
|
2434
|
+
"required": false,
|
|
2435
|
+
"note": "The room between rows. `rows` (2px) for a list of one kind of row; `sections` (4px) for groups with labels and dividers of their own."
|
|
2436
|
+
},
|
|
2437
|
+
{
|
|
2438
|
+
"name": "collapsed",
|
|
2439
|
+
"takes": "true/false",
|
|
2440
|
+
"required": false,
|
|
2441
|
+
"note": "Closes the column with the rail: it narrows to nothing and fades."
|
|
2442
|
+
},
|
|
2443
|
+
{
|
|
2444
|
+
"name": "children",
|
|
2445
|
+
"takes": "anything",
|
|
2446
|
+
"required": true,
|
|
2447
|
+
"note": "The rows."
|
|
2448
|
+
},
|
|
2449
|
+
{
|
|
2450
|
+
"name": "className",
|
|
2451
|
+
"takes": "text",
|
|
2452
|
+
"required": false,
|
|
2453
|
+
"note": "Placement only."
|
|
2454
|
+
}
|
|
2455
|
+
],
|
|
2456
|
+
"variants": [
|
|
2457
|
+
{
|
|
2458
|
+
"prop": "spacing",
|
|
2459
|
+
"values": [
|
|
2460
|
+
"rows",
|
|
2461
|
+
"sections"
|
|
2462
|
+
]
|
|
2463
|
+
}
|
|
2464
|
+
],
|
|
2465
|
+
"ownsBehaviours": [],
|
|
2466
|
+
"status": "stable",
|
|
2467
|
+
"migrationStage": null,
|
|
2468
|
+
"docsId": "layout-listcolumn--docs",
|
|
2469
|
+
"storyId": "layout-listcolumn--default",
|
|
2470
|
+
"docPage": "src/ListColumn.mdx",
|
|
2471
|
+
"app": null
|
|
2472
|
+
},
|
|
2392
2473
|
{
|
|
2393
2474
|
"name": "Menu",
|
|
2394
2475
|
"repo": "estiva-ui",
|
|
@@ -2477,7 +2558,7 @@
|
|
|
2477
2558
|
},
|
|
2478
2559
|
{
|
|
2479
2560
|
"id": "page-keys",
|
|
2480
|
-
"behaviour": "
|
|
2561
|
+
"behaviour": "Takes its keys by itself"
|
|
2481
2562
|
},
|
|
2482
2563
|
{
|
|
2483
2564
|
"id": "follow",
|
|
@@ -3019,7 +3100,7 @@
|
|
|
3019
3100
|
},
|
|
3020
3101
|
{
|
|
3021
3102
|
"id": "page-keys",
|
|
3022
|
-
"behaviour": "
|
|
3103
|
+
"behaviour": "Takes its keys by itself"
|
|
3023
3104
|
},
|
|
3024
3105
|
{
|
|
3025
3106
|
"id": "follow",
|
|
@@ -3076,7 +3157,13 @@
|
|
|
3076
3157
|
"name": "className",
|
|
3077
3158
|
"takes": "text",
|
|
3078
3159
|
"required": false,
|
|
3079
|
-
"note": "On the card's surface: its width
|
|
3160
|
+
"note": "On the card's surface: its width."
|
|
3161
|
+
},
|
|
3162
|
+
{
|
|
3163
|
+
"name": "contentClassName",
|
|
3164
|
+
"takes": "text",
|
|
3165
|
+
"required": false,
|
|
3166
|
+
"note": "On the scrolling content: its padding (default 12px) and rhythm."
|
|
3080
3167
|
},
|
|
3081
3168
|
{
|
|
3082
3169
|
"name": "wrapperClassName",
|
|
@@ -3587,6 +3674,12 @@
|
|
|
3587
3674
|
"required": false,
|
|
3588
3675
|
"note": "`hover` reveals the actions while the row is hovered or focused; `always` keeps them."
|
|
3589
3676
|
},
|
|
3677
|
+
{
|
|
3678
|
+
"name": "hover",
|
|
3679
|
+
"takes": "fill | none",
|
|
3680
|
+
"required": false,
|
|
3681
|
+
"note": "`fill` lights the row under the pointer when it does something (a toggle, actions); `none` keeps it still — a heading whose actions are always shown, where the buttons light up on their own (UIG-14, Katerina, 19 September)."
|
|
3682
|
+
},
|
|
3590
3683
|
{
|
|
3591
3684
|
"name": "render",
|
|
3592
3685
|
"takes": "useRender.RenderProp",
|
|
@@ -3607,6 +3700,13 @@
|
|
|
3607
3700
|
"hover",
|
|
3608
3701
|
"always"
|
|
3609
3702
|
]
|
|
3703
|
+
},
|
|
3704
|
+
{
|
|
3705
|
+
"prop": "hover",
|
|
3706
|
+
"values": [
|
|
3707
|
+
"fill",
|
|
3708
|
+
"none"
|
|
3709
|
+
]
|
|
3610
3710
|
}
|
|
3611
3711
|
],
|
|
3612
3712
|
"ownsBehaviours": [],
|
|
@@ -3719,6 +3819,12 @@
|
|
|
3719
3819
|
"required": false,
|
|
3720
3820
|
"note": null
|
|
3721
3821
|
},
|
|
3822
|
+
{
|
|
3823
|
+
"name": "disabledReason",
|
|
3824
|
+
"takes": "text",
|
|
3825
|
+
"required": false,
|
|
3826
|
+
"note": "Why it cannot be changed right now (UIG-14, Katerina, 19 September)."
|
|
3827
|
+
},
|
|
3722
3828
|
{
|
|
3723
3829
|
"name": "className",
|
|
3724
3830
|
"takes": "text",
|
|
@@ -3750,7 +3856,7 @@
|
|
|
3750
3856
|
},
|
|
3751
3857
|
{
|
|
3752
3858
|
"id": "page-keys",
|
|
3753
|
-
"behaviour": "
|
|
3859
|
+
"behaviour": "Takes its keys by itself"
|
|
3754
3860
|
},
|
|
3755
3861
|
{
|
|
3756
3862
|
"id": "follow",
|
|
@@ -3964,7 +4070,7 @@
|
|
|
3964
4070
|
},
|
|
3965
4071
|
{
|
|
3966
4072
|
"id": "page-keys",
|
|
3967
|
-
"behaviour": "
|
|
4073
|
+
"behaviour": "Takes its keys by itself"
|
|
3968
4074
|
},
|
|
3969
4075
|
{
|
|
3970
4076
|
"id": "walking",
|
|
@@ -4204,7 +4310,7 @@
|
|
|
4204
4310
|
},
|
|
4205
4311
|
{
|
|
4206
4312
|
"id": "page-keys",
|
|
4207
|
-
"behaviour": "
|
|
4313
|
+
"behaviour": "Takes its keys by itself"
|
|
4208
4314
|
},
|
|
4209
4315
|
{
|
|
4210
4316
|
"id": "walking",
|
|
@@ -4279,6 +4385,12 @@
|
|
|
4279
4385
|
"required": false,
|
|
4280
4386
|
"note": "Why the action cannot succeed right now."
|
|
4281
4387
|
},
|
|
4388
|
+
{
|
|
4389
|
+
"name": "href",
|
|
4390
|
+
"takes": "text",
|
|
4391
|
+
"required": false,
|
|
4392
|
+
"note": "A link that looks like an icon button: an anchor, so the address stays real for a modified click or a new tab, as `Link` keeps it."
|
|
4393
|
+
},
|
|
4282
4394
|
{
|
|
4283
4395
|
"name": "children",
|
|
4284
4396
|
"takes": "anything",
|
|
@@ -4346,6 +4458,91 @@
|
|
|
4346
4458
|
"docPage": null,
|
|
4347
4459
|
"app": null
|
|
4348
4460
|
},
|
|
4461
|
+
{
|
|
4462
|
+
"name": "ToolbarLink",
|
|
4463
|
+
"repo": "estiva-ui",
|
|
4464
|
+
"kind": "component",
|
|
4465
|
+
"importPath": "@estiva-app/ui",
|
|
4466
|
+
"sourceFile": "src/Toolbar.tsx",
|
|
4467
|
+
"purpose": "An `IconButton` that is a link, and an item of a `Toolbar`: the arrow keys reach it like the buttons beside it.",
|
|
4468
|
+
"purposeFrom": "comment",
|
|
4469
|
+
"props": [
|
|
4470
|
+
{
|
|
4471
|
+
"name": "href",
|
|
4472
|
+
"takes": "text",
|
|
4473
|
+
"required": true,
|
|
4474
|
+
"note": null
|
|
4475
|
+
},
|
|
4476
|
+
{
|
|
4477
|
+
"name": "ref",
|
|
4478
|
+
"takes": "Ref<HTMLAnchorElement>",
|
|
4479
|
+
"required": false,
|
|
4480
|
+
"note": null
|
|
4481
|
+
},
|
|
4482
|
+
{
|
|
4483
|
+
"name": "variant",
|
|
4484
|
+
"takes": "muted | outlined | primary | current | resolve",
|
|
4485
|
+
"required": false,
|
|
4486
|
+
"note": "`current` takes the colour of what it sits in — the ✕ on a `Banner` wears the banner's tone."
|
|
4487
|
+
},
|
|
4488
|
+
{
|
|
4489
|
+
"name": "glow",
|
|
4490
|
+
"takes": "true/false",
|
|
4491
|
+
"required": false,
|
|
4492
|
+
"note": "A glow in Signal — the send arrow while there is something to send."
|
|
4493
|
+
},
|
|
4494
|
+
{
|
|
4495
|
+
"name": "tooltip",
|
|
4496
|
+
"takes": "text",
|
|
4497
|
+
"required": false,
|
|
4498
|
+
"note": null
|
|
4499
|
+
},
|
|
4500
|
+
{
|
|
4501
|
+
"name": "tooltipShortcut",
|
|
4502
|
+
"takes": "text",
|
|
4503
|
+
"required": false,
|
|
4504
|
+
"note": "A key hint drawn as the `Kbd` chip inside the tooltip — for a button whose only other affordance is a keyboard shortcut."
|
|
4505
|
+
},
|
|
4506
|
+
{
|
|
4507
|
+
"name": "tooltipPlacement",
|
|
4508
|
+
"takes": "top | bottom",
|
|
4509
|
+
"required": false,
|
|
4510
|
+
"note": null
|
|
4511
|
+
},
|
|
4512
|
+
{
|
|
4513
|
+
"name": "children",
|
|
4514
|
+
"takes": "anything",
|
|
4515
|
+
"required": true,
|
|
4516
|
+
"note": "The icon: 16px, stroke 1.5."
|
|
4517
|
+
}
|
|
4518
|
+
],
|
|
4519
|
+
"variants": [
|
|
4520
|
+
{
|
|
4521
|
+
"prop": "variant",
|
|
4522
|
+
"values": [
|
|
4523
|
+
"muted",
|
|
4524
|
+
"outlined",
|
|
4525
|
+
"primary",
|
|
4526
|
+
"current",
|
|
4527
|
+
"resolve"
|
|
4528
|
+
]
|
|
4529
|
+
},
|
|
4530
|
+
{
|
|
4531
|
+
"prop": "tooltipPlacement",
|
|
4532
|
+
"values": [
|
|
4533
|
+
"top",
|
|
4534
|
+
"bottom"
|
|
4535
|
+
]
|
|
4536
|
+
}
|
|
4537
|
+
],
|
|
4538
|
+
"ownsBehaviours": [],
|
|
4539
|
+
"status": "stable",
|
|
4540
|
+
"migrationStage": null,
|
|
4541
|
+
"docsId": "primitives-toolbar--docs",
|
|
4542
|
+
"storyId": "primitives-toolbar--default",
|
|
4543
|
+
"docPage": null,
|
|
4544
|
+
"app": null
|
|
4545
|
+
},
|
|
4349
4546
|
{
|
|
4350
4547
|
"name": "ToolbarSeparator",
|
|
4351
4548
|
"repo": "estiva-ui",
|
|
@@ -4576,6 +4773,12 @@
|
|
|
4576
4773
|
"required": false,
|
|
4577
4774
|
"note": "Extra classes on the wrapper — e.g. `min-w-0 shrink` so a truncating label keeps truncating inside it."
|
|
4578
4775
|
},
|
|
4776
|
+
{
|
|
4777
|
+
"name": "inline",
|
|
4778
|
+
"takes": "true/false",
|
|
4779
|
+
"required": false,
|
|
4780
|
+
"note": "For a trigger inside a line of text — a reference, a name in a sentence: the wrapper is a `<span>`, because a `<div>` is not allowed inside a paragraph (UIG-14, Katerina, 19 September)."
|
|
4781
|
+
},
|
|
4579
4782
|
{
|
|
4580
4783
|
"name": "children",
|
|
4581
4784
|
"takes": "anything",
|
package/src/AppShell.mdx
CHANGED
|
@@ -52,7 +52,6 @@ flex column. A page is a flex child of `main`, and says one of two things:
|
|
|
52
52
|
Never `h-full`: the frame's content box is *at least* the viewport's
|
|
53
53
|
height and grows with a tall page — which is what lets the bar know the
|
|
54
54
|
page changed — so a percentage height has nothing to resolve against.
|
|
55
|
-
Measured on all four of Ship's pages (2026-09-09).
|
|
56
55
|
|
|
57
56
|
```tsx
|
|
58
57
|
import { AppShell, Banner, IdentityMenu, Rail, RailItem } from '@estiva-app/ui'
|
|
@@ -75,6 +74,24 @@ import { AppShell, Banner, IdentityMenu, Rail, RailItem } from '@estiva-app/ui'
|
|
|
75
74
|
- In the floating manner the card owns `overflow-hidden` — your content
|
|
76
75
|
manages its own scrolling inside it.
|
|
77
76
|
- Desktop only for now — no narrow-screen behaviour is provided.
|
|
77
|
+
- In the Signal theme the floating frame draws the control-room dot grid on
|
|
78
|
+
its ground, behind the card. Nothing to add: the preset makes it.
|
|
79
|
+
|
|
80
|
+
- In the floating manner the bar takes the top 52px; the card sits 16px from
|
|
81
|
+
the right and the bottom, with 16px corners, beside the 64px rail.
|
|
82
|
+
- In the floating manner the card owns `overflow-hidden`, so anything in it
|
|
83
|
+
that can grow sits in a **ScrollArea** — a list column most of all, which
|
|
84
|
+
**ListColumn** draws with its own. Without one it is cut off at the fold.
|
|
85
|
+
- **Planned:** `SplitLayout`, resizable panels, in `@estiva-app/ui/layout`
|
|
86
|
+
(migration stage 8). It may take the list and side columns' widths.
|
|
87
|
+
|
|
88
|
+
## What it owns
|
|
89
|
+
|
|
90
|
+
It does these by itself. Write none of them around it.
|
|
91
|
+
|
|
92
|
+
| It does | So you never write | Refused when written by hand |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Scrolls the page's content column, in a ScrollArea | `overflow-auto` on the page or on `main` | |
|
|
78
95
|
|
|
79
96
|
## Props
|
|
80
97
|
|
package/src/AppShell.test.tsx
CHANGED
|
@@ -36,4 +36,20 @@ describe('AppShell', () => {
|
|
|
36
36
|
expect(main.className).toContain('overflow-hidden')
|
|
37
37
|
expect(main.closest('[style*="overflow: scroll"]')).toBeNull()
|
|
38
38
|
})
|
|
39
|
+
|
|
40
|
+
it('carries the Signal canvas on the floating frame, and only there', () => {
|
|
41
|
+
const { container, unmount } = render(
|
|
42
|
+
<AppShell variant="floating" nav={<nav>Nav</nav>}>
|
|
43
|
+
<p>Page</p>
|
|
44
|
+
</AppShell>,
|
|
45
|
+
)
|
|
46
|
+
expect((container.firstElementChild as HTMLElement).className).toContain('signal-canvas')
|
|
47
|
+
unmount()
|
|
48
|
+
const solid = render(
|
|
49
|
+
<AppShell nav={<nav>Nav</nav>}>
|
|
50
|
+
<p>Page</p>
|
|
51
|
+
</AppShell>,
|
|
52
|
+
)
|
|
53
|
+
expect(solid.container.querySelector('.signal-canvas')).toBeNull()
|
|
54
|
+
})
|
|
39
55
|
})
|
package/src/AppShell.tsx
CHANGED
|
@@ -45,7 +45,10 @@ export function AppShell({ variant = 'solid', menu, logo, search, identity, bann
|
|
|
45
45
|
|
|
46
46
|
if (variant === 'floating') {
|
|
47
47
|
return (
|
|
48
|
-
|
|
48
|
+
// `signal-canvas`: in the Signal theme, the preset draws the control-room dot
|
|
49
|
+
// grid behind everything in the frame (Peek's, moved here with the frame:
|
|
50
|
+
// UIG-14, Katerina, 19 September — the canvas is the theme's, not an app's).
|
|
51
|
+
<div className="signal-canvas relative h-full min-h-0 overflow-hidden bg-bg-base">
|
|
49
52
|
{bar}
|
|
50
53
|
<div className="flex h-full pb-4 pr-4 pt-[52px]">
|
|
51
54
|
{nav}
|
package/src/AttachmentCard.mdx
CHANGED
|
@@ -53,10 +53,21 @@ import { AttachmentCard } from '@estiva-app/ui'
|
|
|
53
53
|
- The name truncates. When it is cut off, the full name is on hover; a name
|
|
54
54
|
that fits, and a size, show nothing extra. `noteHint` is always on hover, since
|
|
55
55
|
it says more than the line.
|
|
56
|
-
- The remove control is
|
|
56
|
+
- The remove control is a 20px round badge on the card's corner, a button
|
|
57
57
|
on Base UI's `Button` like InputChip's ✕ — not an `IconButton`, the 24px
|
|
58
58
|
square that fills on hover.
|
|
59
59
|
|
|
60
|
+
- **Planned:** a Lightbox that opens a picture full screen, in migration stage 7.
|
|
61
|
+
|
|
62
|
+
## What it owns
|
|
63
|
+
|
|
64
|
+
It does these by itself. Write none of them around it.
|
|
65
|
+
|
|
66
|
+
| It does | So you never write | Refused when written by hand |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| Stops the clicks on its picture, its download and its remove control, so they never also click the card or row around it | `stopPropagation` | |
|
|
69
|
+
| Shows the full name on hover when the name is cut off | a tooltip of your own | |
|
|
70
|
+
|
|
60
71
|
## Props
|
|
61
72
|
|
|
62
73
|
<Controls of={AttachmentCardStories.Document} />
|
|
@@ -169,4 +169,14 @@ describe('AttachmentCard', () => {
|
|
|
169
169
|
expect(onRemove).toHaveBeenCalledTimes(1)
|
|
170
170
|
expect(outside).not.toHaveBeenCalled()
|
|
171
171
|
})
|
|
172
|
+
|
|
173
|
+
it('the ✕ shows when the keyboard reaches it, not only on hover (C4)', async () => {
|
|
174
|
+
render(<AttachmentCard pending name="a.png" size={1} onRemove={() => {}} />)
|
|
175
|
+
const remove = screen.getByRole('button', { name: 'Remove a.png' })
|
|
176
|
+
// Hidden at rest; each of these reveals it. jsdom draws nothing, so the classes are the contract.
|
|
177
|
+
expect(remove.className).toContain('opacity-0')
|
|
178
|
+
for (const reveal of ['group-hover:opacity-100', 'group-focus-within:opacity-100', 'focus-visible:opacity-100']) expect(remove.className).toContain(reveal)
|
|
179
|
+
await userEvent.tab()
|
|
180
|
+
expect(document.activeElement).toBe(remove)
|
|
181
|
+
})
|
|
172
182
|
})
|
package/src/AttachmentCard.tsx
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
import { Card } from './Card'
|
|
21
21
|
import { IconButton } from './IconButton'
|
|
22
22
|
import { Link } from './Link'
|
|
23
|
-
import { WithTooltip } from './Tooltip'
|
|
23
|
+
import { WithTooltip, type WithTooltipProps } from './Tooltip'
|
|
24
24
|
import { cn } from './cn'
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -98,7 +98,7 @@ function TypeIcon({ name }: { name: string }) {
|
|
|
98
98
|
* the fallback face can fit and then not, in a line whose box never changes. The wrapper is `flex-col` so the
|
|
99
99
|
* text stretches across it, as wide as it is without one.
|
|
100
100
|
*/
|
|
101
|
-
function Truncating({ text, hint, className, wrapperClassName }: { text: string; hint?: string; className: string; wrapperClassName?: string }) {
|
|
101
|
+
function Truncating({ text, hint, className, wrapperClassName, placement }: { text: string; hint?: string; className: string; wrapperClassName?: string; placement?: WithTooltipProps['placement'] }) {
|
|
102
102
|
const ref = useRef<HTMLSpanElement>(null)
|
|
103
103
|
const [cut, setCut] = useState(false)
|
|
104
104
|
useLayoutEffect(() => {
|
|
@@ -127,7 +127,7 @@ function Truncating({ text, hint, className, wrapperClassName }: { text: string;
|
|
|
127
127
|
)
|
|
128
128
|
if (!hint && !cut) return line
|
|
129
129
|
return (
|
|
130
|
-
<WithTooltip label={hint ?? text} wrapperClassName={cn('min-w-0 flex-col', wrapperClassName)}>
|
|
130
|
+
<WithTooltip label={hint ?? text} placement={placement} wrapperClassName={cn('min-w-0 flex-col', wrapperClassName)}>
|
|
131
131
|
{line}
|
|
132
132
|
</WithTooltip>
|
|
133
133
|
)
|
|
@@ -206,7 +206,8 @@ export function AttachmentCard({
|
|
|
206
206
|
)}
|
|
207
207
|
</div>
|
|
208
208
|
<div className="flex flex-col gap-[1px] min-w-0">
|
|
209
|
-
|
|
209
|
+
{/* Below, not above: above, a cut name's tooltip covered the ✕ on the corner (UIG-14, C4). */}
|
|
210
|
+
<Truncating text={name} className={NAME_CLASSES} placement={onRemove ? 'bottom' : undefined} />
|
|
210
211
|
<Truncating
|
|
211
212
|
text={(failed || warning ? note : state === 'uploading' ? (note ?? 'Uploading…') : (note ?? sizeText)) ?? ''}
|
|
212
213
|
hint={noteHint}
|
|
@@ -219,7 +220,9 @@ export function AttachmentCard({
|
|
|
219
220
|
<BaseButton
|
|
220
221
|
type="button"
|
|
221
222
|
aria-label={`Remove ${name}`}
|
|
222
|
-
|
|
223
|
+
// Shows with the card's hover and with keyboard focus, as Download does: hover-only left it invisible to
|
|
224
|
+
// the keyboard that had reached it (UIG-14, C4, Katerina 19 September).
|
|
225
|
+
className="absolute -top-1.5 -right-1.5 size-5 rounded-full bg-bg-elevated border border-border-strong flex items-center justify-center text-text-secondary hover:text-text-primary opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 transition-opacity"
|
|
223
226
|
onClick={(event) => {
|
|
224
227
|
event.stopPropagation()
|
|
225
228
|
onRemove()
|
package/src/Avatar.mdx
CHANGED
|
@@ -13,13 +13,15 @@ theirs, or — when there is no name to take initials from — a silhouette.
|
|
|
13
13
|
## When
|
|
14
14
|
|
|
15
15
|
- Anywhere a person appears at a glance: a row, a card, a picker, a byline.
|
|
16
|
-
- The scale is 16 · 24 · 32 · 36 (default)
|
|
17
|
-
inventing sizes.
|
|
16
|
+
- The scale is 16 · 18 · 20 · 24 · 32 · 36 (default): 18 in a group's reply
|
|
17
|
+
row, 20 in a **Person**. Pick from it rather than inventing sizes.
|
|
18
18
|
|
|
19
19
|
## When not
|
|
20
20
|
|
|
21
21
|
- Several people at once → **AvatarGroup**.
|
|
22
|
-
- The face beside
|
|
22
|
+
- The face beside a name, with nothing else on the line → **Person**. A byline
|
|
23
|
+
that sets the name its own way — bold, with a time — is an Avatar beside its
|
|
24
|
+
own text.
|
|
23
25
|
- The face as a button that opens a menu → **PersonTrigger**.
|
|
24
26
|
|
|
25
27
|
## How
|
|
@@ -37,7 +39,7 @@ import { Avatar } from '@estiva-app/ui'
|
|
|
37
39
|
two words, skipping words that open with a symbol. An unnamed person is
|
|
38
40
|
the silhouette, not a `?` — a question mark reads as an error badge.
|
|
39
41
|
- The initials are centred on the capitals themselves — cap height to
|
|
40
|
-
baseline — not on the line of text around them
|
|
42
|
+
baseline — not on the line of text around them. A single face can
|
|
41
43
|
still sit up to half a pixel off: the screen rounds text to its pixel grid
|
|
42
44
|
wherever the tile lands.
|
|
43
45
|
- The colour behind initials is per person, chosen from the name, the same
|
|
@@ -52,7 +54,7 @@ import { Avatar } from '@estiva-app/ui'
|
|
|
52
54
|
**A face is silent by default**, and that is the important half: almost every
|
|
53
55
|
face in the suite sits beside the name it belongs to — in a `Person`, in a
|
|
54
56
|
`MenuItem`'s `leading`, in a row — and a picture that spoke there would say the
|
|
55
|
-
name twice. It used to
|
|
57
|
+
name twice. It used to: a `Person`
|
|
56
58
|
inside a button announced **"AD Ana Duarte"** (the initials read as text), and
|
|
57
59
|
with a picture **"Ana Duarte Ana Duarte"**.
|
|
58
60
|
|
|
@@ -66,6 +68,19 @@ a stack of members — and the tile becomes one image with one name.
|
|
|
66
68
|
|
|
67
69
|
<Canvas of={AvatarStories.Palette} />
|
|
68
70
|
|
|
71
|
+
- **Planned:** a Byline part — face · name · time — in migration stage 7.
|
|
72
|
+
|
|
73
|
+
- `initialsFor(name)` and `hueFor(name)` give the same initials and colour where
|
|
74
|
+
the part itself cannot be drawn.
|
|
75
|
+
|
|
76
|
+
## What it owns
|
|
77
|
+
|
|
78
|
+
It does these by itself. Write none of them around it.
|
|
79
|
+
|
|
80
|
+
| It does | So you never write | Refused when written by hand |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| Shows initials from the name when there is no picture, or when it fails to load | an `onError`, or initials of your own | |
|
|
83
|
+
|
|
69
84
|
## Props
|
|
70
85
|
|
|
71
86
|
<Controls of={AvatarStories.Initials} />
|
package/src/AvatarGroup.mdx
CHANGED
|
@@ -34,6 +34,10 @@ import { AvatarGroup } from '@estiva-app/ui'
|
|
|
34
34
|
- The ring rides on the Avatar itself (one box); don't wrap each face in a
|
|
35
35
|
clipping window — a window minus a border crops the initials.
|
|
36
36
|
|
|
37
|
+
## What it owns
|
|
38
|
+
|
|
39
|
+
Nothing. It only draws. Clicks and keys are yours.
|
|
40
|
+
|
|
37
41
|
## Props
|
|
38
42
|
|
|
39
43
|
<Controls of={AvatarGroupStories.ThreeMembers} />
|
package/src/Banner.mdx
CHANGED
|
@@ -12,8 +12,8 @@ line, one of four tones, gone when there is nothing to say.
|
|
|
12
12
|
|
|
13
13
|
## When
|
|
14
14
|
|
|
15
|
-
- The
|
|
16
|
-
|
|
15
|
+
- The state of the whole surface: the reason the last read failed, a read-only
|
|
16
|
+
notice.
|
|
17
17
|
- **`ok`** confirms, **`info`** informs, **`warning`** cautions,
|
|
18
18
|
**`error`** reports a failure — and only `error` announces itself
|
|
19
19
|
(`role="alert"`); the others are polite (`role="status"`).
|
|
@@ -22,11 +22,12 @@ line, one of four tones, gone when there is nothing to say.
|
|
|
22
22
|
|
|
23
23
|
## When not
|
|
24
24
|
|
|
25
|
-
- Feedback about one action, briefly → **Toast**.
|
|
25
|
+
- Feedback about one action, briefly → **Toast**. A failure is the exception:
|
|
26
|
+
it stays, in the Banner, until the person acts on it.
|
|
26
27
|
- Something that floats over the page and must **not** fade → still
|
|
27
28
|
**Toast**, with `durationMs: 0` and an action. A banner is the strip
|
|
28
29
|
under the header at the app's full width; a floating pill is not one, even
|
|
29
|
-
a permanent one
|
|
30
|
+
a permanent one.
|
|
30
31
|
- A standing property of one thing → **Chip** on that thing.
|
|
31
32
|
- More than one action, or a second line of text — that is a different
|
|
32
33
|
component (not in the package yet).
|
|
@@ -44,9 +45,8 @@ import { Banner } from '@estiva-app/ui'
|
|
|
44
45
|
- One line of text, `body-2`. If it needs a **second line**, it has outgrown
|
|
45
46
|
this component.
|
|
46
47
|
- `icon` puts a 16px icon before the line and `action` one small muted Button
|
|
47
|
-
at the end of it, both in the tone
|
|
48
|
-
the
|
|
49
|
-
and the text truncates. One action at most.
|
|
48
|
+
at the end of it, both in the tone. With either, the banner is one line and
|
|
49
|
+
the text truncates. One action at most.
|
|
50
50
|
|
|
51
51
|
<Canvas of={BannerStories.WithIconAndAction} />
|
|
52
52
|
|
|
@@ -56,11 +56,20 @@ import { Banner } from '@estiva-app/ui'
|
|
|
56
56
|
</Banner>
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
- `onDismiss` adds an ✕ at the right-hand end
|
|
59
|
+
- `onDismiss` adds an ✕ at the right-hand end. Use it where
|
|
60
60
|
the reader decides the notice is done with, rather than the app. The row
|
|
61
61
|
is 40px rather than 36px with it, because the button is taller than the
|
|
62
62
|
line of text; without it, nothing about the strip changes.
|
|
63
63
|
|
|
64
|
+
## What it owns
|
|
65
|
+
|
|
66
|
+
It does these by itself. Write none of them around it.
|
|
67
|
+
|
|
68
|
+
| It does | So you never write | Refused when written by hand |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| Says what it is to assistive technology: an alert for an error, a status for the rest | `role="alert"` or `role="status"` | ✓ |
|
|
71
|
+
| Draws its own ✕ when you pass `onDismiss`, and its one small action when you pass `action` | a close button or an action button of your own | |
|
|
72
|
+
|
|
64
73
|
## Props
|
|
65
74
|
|
|
66
75
|
<Controls of={BannerStories.Ok} />
|
package/src/Breadcrumb.mdx
CHANGED
|
@@ -56,6 +56,18 @@ import { Breadcrumb } from '@estiva-app/ui'
|
|
|
56
56
|
`min-w-0` container so it can truncate at all.
|
|
57
57
|
- The separators are `aria-hidden` — the trail reads as its places.
|
|
58
58
|
|
|
59
|
+
- 6px between each place and its separator.
|
|
60
|
+
|
|
61
|
+
## What it owns
|
|
62
|
+
|
|
63
|
+
It does these by itself. Write none of them around it.
|
|
64
|
+
|
|
65
|
+
| It does | So you never write | Refused when written by hand |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| Shortens a trail that does not fit, and shows a cut crumb in full on hover | truncation code, or a tooltip | |
|
|
68
|
+
| Names itself as a navigation, and marks the last crumb as the current page | `<nav>`, `aria-label` or `aria-current` | |
|
|
69
|
+
| Hides the separators from screen readers, so the trail reads as its places | `aria-hidden` on each separator | |
|
|
70
|
+
|
|
59
71
|
## Props
|
|
60
72
|
|
|
61
73
|
<Controls of={BreadcrumbStories.OnAnItem} />
|