@kerfjs/ui 5.0.0-beta.55 → 5.0.0-beta.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/ai/compile-time-contracts-v1.json +2 -2
- package/ai/component-catalog-v2.json +149 -39
- package/ai/component-catalog.json +202 -51
- package/ai/public-api-signatures-v1.md +439 -97
- package/ai/skill.md +43 -40
- package/ai/webawesome-jsx-signatures-v1.md +8 -2
- package/dist/app-tab.js +1 -1
- package/dist/badge.d.ts +35 -7
- package/dist/badge.js +1 -1
- package/dist/browser/content-item.js +3 -0
- package/dist/browser/select.js +1 -0
- package/dist/catalog-resources.d.ts +12 -1
- package/dist/catalog.d.ts +14 -3
- package/dist/catalog.js +52 -43
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
- package/dist/chunk-2G2ZJQYK.js.map +1 -0
- package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
- package/dist/chunk-5I7QGQVT.js.map +1 -0
- package/dist/{chunk-RNRUVPJ3.js → chunk-63ZWBGE3.js} +3 -2
- package/dist/chunk-63ZWBGE3.js.map +1 -0
- package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
- package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
- package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
- package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
- package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
- package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
- package/dist/{chunk-7GUQYHKA.js → chunk-AK67F6QN.js} +4 -1
- package/dist/chunk-AK67F6QN.js.map +1 -0
- package/dist/chunk-BFPBS5Y4.js +250 -0
- package/dist/chunk-BFPBS5Y4.js.map +1 -0
- package/dist/{chunk-5OLVUEND.js → chunk-DG6G5EPF.js} +4 -6
- package/dist/chunk-DG6G5EPF.js.map +1 -0
- package/dist/{chunk-MTM43SJO.js → chunk-G33XC2NB.js} +1 -1
- package/dist/chunk-G33XC2NB.js.map +1 -0
- package/dist/{chunk-TZ5IHWB2.js → chunk-K6UNVKDK.js} +3 -3
- package/dist/{chunk-TZ5IHWB2.js.map → chunk-K6UNVKDK.js.map} +1 -1
- package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
- package/dist/chunk-KROD7KZK.js.map +1 -0
- package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
- package/dist/chunk-M7QV3IHH.js.map +1 -0
- package/dist/{chunk-RNZAKSME.js → chunk-MA6Z6EIM.js} +3 -3
- package/dist/{chunk-RNZAKSME.js.map → chunk-MA6Z6EIM.js.map} +1 -1
- package/dist/chunk-MA73TA6D.js +42 -0
- package/dist/chunk-MA73TA6D.js.map +1 -0
- package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
- package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
- package/dist/{chunk-T22EM4ET.js → chunk-MOBRFZH3.js} +81 -31
- package/dist/chunk-MOBRFZH3.js.map +1 -0
- package/dist/chunk-MP2GDBQZ.js +50 -0
- package/dist/chunk-MP2GDBQZ.js.map +1 -0
- package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
- package/dist/chunk-NAPE7WUS.js.map +1 -0
- package/dist/{chunk-BSKEH3UC.js → chunk-NBYTIVHS.js} +2 -2
- package/dist/{chunk-BSKEH3UC.js.map → chunk-NBYTIVHS.js.map} +1 -1
- package/dist/chunk-O3EXIBEZ.js +114 -0
- package/dist/chunk-O3EXIBEZ.js.map +1 -0
- package/dist/{chunk-R754MHXX.js → chunk-PK4N5QTO.js} +7 -6
- package/dist/chunk-PK4N5QTO.js.map +1 -0
- package/dist/{chunk-EAX2GSS4.js → chunk-QQOTQTDD.js} +51 -20
- package/dist/chunk-QQOTQTDD.js.map +1 -0
- package/dist/{chunk-LZXQVUGN.js → chunk-T4UZTNZ4.js} +4 -4
- package/dist/{chunk-LZXQVUGN.js.map → chunk-T4UZTNZ4.js.map} +1 -1
- package/dist/{chunk-N7FHFNT6.js → chunk-V65EOWNF.js} +33 -5
- package/dist/chunk-V65EOWNF.js.map +1 -0
- package/dist/{chunk-GUIHMIT2.js → chunk-VNPQDCQZ.js} +3 -3
- package/dist/{chunk-GUIHMIT2.js.map → chunk-VNPQDCQZ.js.map} +1 -1
- package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
- package/dist/chunk-VZOFZPSO.js.map +1 -0
- package/dist/{chunk-4BIMLITI.js → chunk-WLG6SSNT.js} +5 -3
- package/dist/chunk-WLG6SSNT.js.map +1 -0
- package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
- package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +14 -3
- package/dist/collapsible-panel.js +13 -16
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +46 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +5 -11
- package/dist/css-values.js +1 -1
- package/dist/disclosure-arrow.d.ts +4 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/floating-toolbar.d.ts +17 -6
- package/dist/floating-toolbar.js +1 -1
- package/dist/grid.js +1 -1
- package/dist/help-tags-register.d.ts +13 -0
- package/dist/help-tags-register.js +9 -0
- package/dist/help-tags-register.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +27 -26
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +14 -1
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +3 -10
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +10 -3
- package/dist/list.js +1 -1
- package/dist/nav-stack.d.ts +38 -5
- package/dist/nav-stack.js +4 -1
- package/dist/pane.d.ts +20 -2
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-BFQxFITu.d.ts → panel-toolbar-C8sF-YZC.d.ts} +12 -1
- package/dist/popup-menu-register.js +3 -2
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.js +1 -1
- package/dist/row.d.ts +1 -1
- package/dist/row.js +1 -1
- package/dist/select-register.js +70 -3
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +46 -8
- package/dist/select.js +2 -1
- package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.d.ts +31 -3
- package/dist/split-view.js +33 -5
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/badge.css +13 -0
- package/dist/styles/catalog/components/catalog-example.css +1 -1
- package/dist/styles/catalog/components/catalog-stage.css +1 -1
- package/dist/styles/collapsible-panel.css +192 -39
- package/dist/styles/content-item.css +30 -0
- package/dist/styles/floating-toolbar.css +5 -0
- package/dist/styles/foundation.css +28 -19
- package/dist/styles/layout.css +1 -21
- package/dist/styles/list-action-row.css +13 -1
- package/dist/styles/list-inset-text.css +1 -2
- package/dist/styles/list-item.css +14 -1
- package/dist/styles/list.css +1 -1
- package/dist/styles/nav-stack.css +29 -64
- package/dist/styles/pane.css +33 -1
- package/dist/styles/popup-menu.css +78 -0
- package/dist/styles/resizable-region.css +53 -10
- package/dist/styles/select.css +39 -12
- package/dist/styles/split-view.css +21 -25
- package/dist/styles/tab-scaffold.css +36 -14
- package/dist/styles/text.css +1 -1
- package/dist/styles/token-search-field.css +4 -4
- package/dist/styles/toolbar-control-group.css +31 -12
- package/dist/styles/toolbar.css +14 -5
- package/dist/styles/value-table.css +19 -2
- package/dist/styles/webawesome.css +3 -1
- package/dist/styles/workbench.css +134 -31
- package/dist/tab-scaffold.d.ts +35 -1
- package/dist/tab-scaffold.js +50 -16
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.d.ts +4 -2
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +12 -4
- package/dist/toolbar.js +1 -1
- package/dist/{types-D6vzj-VT.d.ts → types-DXAGogOS.d.ts} +39 -6
- package/dist/value-table.js +1 -1
- package/dist/webawesome.d.ts +7 -1
- package/dist/wire-catalog.d.ts +12 -1
- package/dist/wire-catalog.js +10 -2
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +59 -22
- package/dist/workbench.js +1 -1
- package/docs/accessibility.md +116 -7
- package/docs/app-layouts.md +9 -7
- package/docs/catalog.md +17 -3
- package/docs/collapsible-panel.md +26 -7
- package/docs/component-contract.md +36 -10
- package/docs/component-selection.md +41 -40
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
- package/docs/design/templates/empty-state/with-action.svg +1 -1
- package/docs/design/templates/empty-state-dark.svg +1 -1
- package/docs/design/templates/empty-state.svg +1 -1
- package/docs/design/templates/list/compact-dark.svg +1 -1
- package/docs/design/templates/list/compact.svg +1 -1
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-action-row/default-dark.svg +1 -1
- package/docs/design/templates/list-action-row/default.svg +1 -1
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
- package/docs/design/templates/list-action-row/selected.svg +1 -1
- package/docs/design/templates/list-action-row-dark.svg +1 -1
- package/docs/design/templates/list-action-row.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-item/default-dark.svg +1 -1
- package/docs/design/templates/list-item/default.svg +1 -1
- package/docs/design/templates/list-item/selected-dark.svg +1 -1
- package/docs/design/templates/list-item/selected.svg +1 -1
- package/docs/design/templates/list-item/trailing-dark.svg +1 -1
- package/docs/design/templates/list-item/trailing.svg +1 -1
- package/docs/design/templates/list-item-dark.svg +1 -1
- package/docs/design/templates/list-item.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/value-table/details-dark.svg +1 -1
- package/docs/design/templates/value-table/details.svg +1 -1
- package/docs/design/templates/value-table-dark.svg +1 -1
- package/docs/design/templates/value-table.svg +1 -1
- package/docs/design-philosophy.md +1 -1
- package/docs/examples/command-palette-adapter.tsx +3 -2
- package/docs/layout.md +69 -29
- package/docs/nav-stack.md +45 -1
- package/docs/recipes.md +4 -3
- package/docs/split-view.md +46 -2
- package/docs/tab-scaffold.md +50 -1
- package/docs/type-contracts.md +17 -17
- package/docs/ux-demo.md +2 -2
- package/docs/webawesome-theme.md +1 -2
- package/docs/workbench.md +45 -9
- package/llms.txt +32 -4
- package/package.json +13 -2
- package/ux-demo/recipes/collapsible-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-stack.tsx +3 -2
- package/dist/chunk-3NBL3OUQ.js.map +0 -1
- package/dist/chunk-4BIMLITI.js.map +0 -1
- package/dist/chunk-5I22LMCV.js.map +0 -1
- package/dist/chunk-5NDQABWK.js.map +0 -1
- package/dist/chunk-5OLVUEND.js.map +0 -1
- package/dist/chunk-7GUQYHKA.js.map +0 -1
- package/dist/chunk-D7GWXIAS.js.map +0 -1
- package/dist/chunk-DQA5FMOX.js +0 -85
- package/dist/chunk-DQA5FMOX.js.map +0 -1
- package/dist/chunk-EAX2GSS4.js.map +0 -1
- package/dist/chunk-HMQ2ZDGG.js.map +0 -1
- package/dist/chunk-MTM43SJO.js.map +0 -1
- package/dist/chunk-N7FHFNT6.js.map +0 -1
- package/dist/chunk-R754MHXX.js.map +0 -1
- package/dist/chunk-RNRUVPJ3.js.map +0 -1
- package/dist/chunk-T22EM4ET.js.map +0 -1
- package/dist/chunk-WZ2GLEY4.js.map +0 -1
- package/dist/chunk-XD7DWYXG.js +0 -34
- package/dist/chunk-XD7DWYXG.js.map +0 -1
package/docs/accessibility.md
CHANGED
|
@@ -16,7 +16,7 @@ These are normative contracts for package components and consuming applications.
|
|
|
16
16
|
- `StateBanner` defaults to polite `role="status"`; use `urgency="alert"` only for an attention-requiring failure. Its optional `badge` is persistent inline status/count content beside the title and is announced as part of the banner; keep it terse and do not rely on color alone for its meaning.
|
|
17
17
|
- `EmptyState` reports busy state through `aria-busy` and never relies on an illustration as its label.
|
|
18
18
|
- `Select` follows the Web Awesome host's standard `input`/`change` events. Application tests verify the live `value`, focus, and events—not attributes alone. Its decorative option icons and value-dependent selected content remain present after controlled rerenders, so the visible choice does not silently lose its non-text cue.
|
|
19
|
-
- `DisclosureArrow` is an 18px root-scaled decorative visual by default, not an interaction target. Its owning native control supplies a stable accessible name, pointer and keyboard interaction, and `aria-expanded`; multiple arrows keep independently controlled state. Consumers may
|
|
19
|
+
- `DisclosureArrow` is an 18px root-scaled decorative visual by default, not an interaction target. Its owning native control supplies a stable accessible name, pointer and keyboard interaction, and `aria-expanded`; multiple arrows keep independently controlled state. Consumers may resize it with the typed `size` prop without changing that ownership. Configured directions animate over the shortest path; a 180-degree closed-to-open tie uses counterclockwise rotation.
|
|
20
20
|
- `List` is layout-only and adds no `list` role. Children own their native or ARIA semantics. Give a scrollable List a bounded block size, avoid nested scroll owners, and keep focused children visible while scrolling.
|
|
21
21
|
|
|
22
22
|
## Select
|
|
@@ -30,6 +30,27 @@ adding height or spacing. This also applies to `renderSelected`: selected conten
|
|
|
30
30
|
stays separate from the control's stable accessible name. Applications do not
|
|
31
31
|
need shadow-DOM patches or extra label styling.
|
|
32
32
|
|
|
33
|
+
Set `multiple` (with an array `value`) to let the person choose any number
|
|
34
|
+
of choices. The popup stays open while they toggle choices with the pointer,
|
|
35
|
+
Enter, or Space, and closes on an outside press, Escape, or focus leaving,
|
|
36
|
+
returning focus to the combobox. The listbox is `aria-multiselectable`, each
|
|
37
|
+
chosen option shows its check, and the closed control reads the chosen labels
|
|
38
|
+
in choice order as one short localized list (the `placeholderText` when none
|
|
39
|
+
are chosen) instead of a removable tag per choice. `change` and `input` report
|
|
40
|
+
the value array; in a form, every chosen value is submitted under `name`.
|
|
41
|
+
|
|
42
|
+
A toolbar filter menu (a "Filter by label" funnel) is a multiple Select with
|
|
43
|
+
`selectedPresentation="icon-only"` and a fixed `triggerIcon`; the types accept
|
|
44
|
+
`triggerIcon` only there, and require it there, because no single chosen
|
|
45
|
+
choice has an icon to show. The trigger keeps the icon-only pill geometry
|
|
46
|
+
below: the fixed icon, then, while any choice is chosen, a compact brand
|
|
47
|
+
`Badge` with the count 4px after it, then the caret. The badge is hidden from
|
|
48
|
+
assistive technology; instead the combobox's accessible name ends with the
|
|
49
|
+
chosen labels in choice order ("Filter by label: Bug, Docs", just "Filter by
|
|
50
|
+
label" when none are chosen), and its hidden value text stays empty so screen
|
|
51
|
+
readers do not announce the list twice. With a visible `label` the same summary
|
|
52
|
+
reads in the label, standing in for the hidden value.
|
|
53
|
+
|
|
33
54
|
Use `presentation="toolbar-borderless"` inside a `ToolbarControlGroup`, with
|
|
34
55
|
`size="compact"` in a compact group; set `focusRingOwner="group"` when that
|
|
35
56
|
parent paints the composed focus ring. `selectedPresentation="icon-only"` hides
|
|
@@ -41,7 +62,12 @@ trigger (8px inline padding on both sides, 12px from the icon to the caret, a
|
|
|
41
62
|
choice list. Inside a group the trigger is inset evenly on every side (2px in a
|
|
42
63
|
default group, 1px in a compact one) with a concentric radius; the group grows
|
|
43
64
|
to the trigger's width, so a single group is wider than it is tall and its
|
|
44
|
-
focus ring follows the pill while focused
|
|
65
|
+
focus ring follows the pill while focused. While the listbox is open the
|
|
66
|
+
trigger drops its ring, as a `PopupMenu` trigger does: the open popup and its
|
|
67
|
+
current option show where focus is, and the ring returns when the listbox
|
|
68
|
+
closes with focus still on the control. A group that owns the ring
|
|
69
|
+
(`focusRing="outline"` or `"halo"`) drops it the same way while a Select
|
|
70
|
+
listbox or `PopupMenu` inside the group is open.
|
|
45
71
|
Beside other controls in one group, the icon-only trigger is one more segment:
|
|
46
72
|
it keeps the group's gap and its siblings' block inset, height, item radius,
|
|
47
73
|
and hover pill. In a group with per-control rings (`focusRing="control"`, the
|
|
@@ -81,6 +107,79 @@ repeated and out-of-order completions, cancellation, instance isolation, and
|
|
|
81
107
|
removal. `tests/browser/select-lifecycle.spec.ts` repeats animation/resize/reopen
|
|
82
108
|
sequences at wide and narrow widths in Chromium, Firefox, and WebKit.
|
|
83
109
|
|
|
110
|
+
### Help tags on icon-only triggers
|
|
111
|
+
|
|
112
|
+
An icon-only control has no visible title, so sighted pointer and keyboard users
|
|
113
|
+
would otherwise see only its icon (and a filter's count). Following the Apple
|
|
114
|
+
HIG convention for toolbar items, three kinds of icon-only control show a help
|
|
115
|
+
tag: a Web Awesome `wa-tooltip` in the theme's tooltip palette, below the
|
|
116
|
+
control.
|
|
117
|
+
|
|
118
|
+
- an icon-only `Select` (`selectedPresentation="icon-only"`, single or
|
|
119
|
+
`multiple`);
|
|
120
|
+
- an icon-only `PopupMenu` (named by `label` rather than visible `text`);
|
|
121
|
+
- an icon-only `<button>` or link (`<a href>`) inside a `ToolbarControlGroup`,
|
|
122
|
+
named by a non-empty `aria-label`, with no visible text, no native `title`,
|
|
123
|
+
and no Web Awesome tooltip `for` it.
|
|
124
|
+
|
|
125
|
+
Tags are on by default and take no props. One document-level installer covers
|
|
126
|
+
all three kinds, and any of `@kerfjs/ui/select/register`,
|
|
127
|
+
`@kerfjs/ui/popup-menu/register`, or `@kerfjs/ui/help-tags/register` installs
|
|
128
|
+
it (once per document, however many are imported). An application whose
|
|
129
|
+
toolbars have icon-only buttons but no registered `Select` or `PopupMenu`
|
|
130
|
+
imports `@kerfjs/ui/help-tags/register`, which registers only the tooltip
|
|
131
|
+
element. Pure `SafeHtml` rendering stays zero-JS: without an installer, nothing
|
|
132
|
+
shows a tag.
|
|
133
|
+
|
|
134
|
+
- **Text.** The tag says what the accessible name says: a filter's name and
|
|
135
|
+
chosen labels ("Filter by label: Bug, Docs", or "Filter by label" when none
|
|
136
|
+
are chosen), a single Select's name and current choice ("Rendering balance:
|
|
137
|
+
Balanced"), a menu's `label` ("Sort tickets"), or a toolbar button's
|
|
138
|
+
`aria-label` ("Pin view"). It updates with the selection.
|
|
139
|
+
- **Showing.** It appears after the pointer rests on the control for 500ms, at
|
|
140
|
+
once when a neighboring tag closed moments ago (so scanning along a toolbar
|
|
141
|
+
stays quick, across buttons, Selects, and menus alike), and immediately on
|
|
142
|
+
keyboard focus (`:focus-visible`). A pointer press that focuses the control
|
|
143
|
+
and touch input never show it.
|
|
144
|
+
- **Hiding.** It hides when the pointer and keyboard focus have both left the
|
|
145
|
+
control, on a press, on Escape, and whenever a popup opens. It does not come
|
|
146
|
+
back when the popup closes and focus returns to the trigger, or while the
|
|
147
|
+
pointer stays on a pressed button; it returns after the pointer moves onto
|
|
148
|
+
something else or focus leaves and comes back.
|
|
149
|
+
- **Assistive technology.** The tag is `aria-hidden` and never joins the
|
|
150
|
+
control's `aria-labelledby` or `aria-describedby` (kerf anchors it directly
|
|
151
|
+
rather than through `for`), so the accessible name is unchanged and announced
|
|
152
|
+
once; the accessibility tree is identical with the tag open or closed.
|
|
153
|
+
- **Isolation.** A Select's or PopupMenu's tag lives in the control's own
|
|
154
|
+
shadow root, so the morph never touches it and light-DOM `:has([open])`
|
|
155
|
+
selectors do not see it. A plain button cannot host a shadow root, so its tag
|
|
156
|
+
lives in one `aria-hidden`, `data-morph-skip` layer at the end of `<body>`
|
|
157
|
+
(fixed and zero-sized, so it never joins a grid or flex body's flow, and
|
|
158
|
+
re-attached if a body re-render drops it) and leaves that layer once hidden.
|
|
159
|
+
It copies the button's `color-scheme`, so it matches a subtree theme, and its
|
|
160
|
+
popup renders in the browser's top layer, so it shows above a modal dialog
|
|
161
|
+
that holds the button. Tags' `wa-show` / `wa-hide` lifecycle events stop at
|
|
162
|
+
the tag, so a listener on the control (or a delegated one above it) hears only
|
|
163
|
+
the popup; a document capture-phase listener still observes them. A long tag
|
|
164
|
+
wraps at the tooltip's maximum width and keeps 8px clear of the viewport
|
|
165
|
+
edge.
|
|
166
|
+
|
|
167
|
+
A labeled Select, a `PopupMenu` with visible `text`, and a toolbar button with
|
|
168
|
+
visible text get no tag: their visible text already names them. A button that
|
|
169
|
+
carries a native `title`, or that the application has already given a
|
|
170
|
+
`wa-tooltip` `for` its `id`, keeps that and gets no second tag, so nothing is
|
|
171
|
+
shown twice. Zero-JS components that name an icon control with a native `title`
|
|
172
|
+
(the `ListHeader` action, the `AppTab` close button, the `TokenSearchField`
|
|
173
|
+
reveal and clear buttons, and `SegmentedControl` choice titles) keep the
|
|
174
|
+
browser's own tooltip, which needs no script; the installer deliberately skips
|
|
175
|
+
them rather than stacking a second tag on the first. Icon-only buttons outside
|
|
176
|
+
a `ToolbarControlGroup` are application markup and keep whatever naming the
|
|
177
|
+
application gives them.
|
|
178
|
+
`tests/unit/help-tag.test.ts` walks the hover, focus, press, Escape, popup, and
|
|
179
|
+
warm-window transitions for every kind; `tests/browser/select-help-tag.spec.ts`
|
|
180
|
+
and `tests/browser/toolbar-help-tag.spec.ts` check the real elements in
|
|
181
|
+
Chromium.
|
|
182
|
+
|
|
84
183
|
## PopupMenu
|
|
85
184
|
|
|
86
185
|
`PopupMenu` renders a Web Awesome dropdown, so the menu roles, arrow-key and
|
|
@@ -88,8 +187,13 @@ typeahead navigation, Escape, and focus return to the trigger come from
|
|
|
88
187
|
`wa-dropdown`. Kerf's part is the trigger's name. A Web Awesome button takes its
|
|
89
188
|
name from its content and ignores an `aria-label` on the host, so an icon-only
|
|
90
189
|
trigger requires `label`, which renders as visually hidden text inside the
|
|
91
|
-
button; a trigger with visible `text` is named by that text.
|
|
92
|
-
|
|
190
|
+
button; a trigger with visible `text` is named by that text. An icon-only
|
|
191
|
+
trigger also shows its `label` as an `aria-hidden` help tag on hover and
|
|
192
|
+
keyboard focus (see [Help tags on icon-only triggers](#help-tags-on-icon-only-triggers)). Group headings
|
|
193
|
+
render as the same uppercase group titles a grouped `Select` shows, and dividers
|
|
194
|
+
are presentational. A keyboard-focused item is the menu's current row, painted
|
|
195
|
+
with the Select's current-option fill rather than a second focus ring inside the
|
|
196
|
+
open popup. A disabled item stays in the menu but cannot be
|
|
93
197
|
chosen; disable the whole trigger only when every command is unavailable.
|
|
94
198
|
|
|
95
199
|
## ListActionRow
|
|
@@ -183,10 +287,15 @@ forced to a dark color scheme, but it is **not** in the top layer, so it never
|
|
|
183
287
|
covers dialogs, popovers, or other overlays. Its children are the app's controls
|
|
184
288
|
(normally `ToolbarControlGroup`s), which keep their own names, focus, and
|
|
185
289
|
keyboard behavior; the application owns their actions, the toolbar's visibility,
|
|
186
|
-
and — via `position` and
|
|
187
|
-
or an ancestor — where it sits. Inside a `Workbench`, `CollapsiblePanel`, or
|
|
290
|
+
and — via `position` and the typed `inset` prop — where it sits. Inside a `Workbench`, `CollapsiblePanel`, or
|
|
188
291
|
`ResizableRegion` `restoreControl` the restore corner owns the inset, so the
|
|
189
|
-
toolbar floats from that corner.
|
|
292
|
+
toolbar floats from that corner. While one of those layouts has a side overlay
|
|
293
|
+
open over the toolbar's region (a Workbench rail overlay, a `wireSidebar`
|
|
294
|
+
compact overlay, an overlay `CollapsiblePanel` or horizontal
|
|
295
|
+
`ResizableRegion`), the toolbar is hidden (`visibility: hidden`), so it is
|
|
296
|
+
unfocusable and out of the accessibility tree rather than a control stranded
|
|
297
|
+
behind the overlay's focus trap; it returns when the overlay closes. The
|
|
298
|
+
overlay's own floating toolbars stay.
|
|
190
299
|
|
|
191
300
|
## Tabs
|
|
192
301
|
|
package/docs/app-layouts.md
CHANGED
|
@@ -79,13 +79,15 @@ nothing routes that edge, while the bar's surface and divider still reach the
|
|
|
79
79
|
screen edge. A claimed toolbar inside a `Pane` header or footer adds nothing
|
|
80
80
|
extra, because the pane already owns those edges.
|
|
81
81
|
|
|
82
|
-
Pass `safeAreaEdges={[]}` for a pane that never sits at a screen edge.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
Pass `safeAreaEdges={[]}` for a pane that never sits at a screen edge. In an
|
|
83
|
+
arrangement you own, give each `Pane` (and each edge-claiming `Toolbar`)
|
|
84
|
+
`safeAreaEdges` listing only the sides its region reaches. The toolbar
|
|
85
|
+
configurations layouts accept (a Workbench `mainToolbar` / `mainBottomToolbar`,
|
|
86
|
+
and a Workbench panel's or `CollapsiblePanel`'s `toolbar`) forward
|
|
87
|
+
`safeAreaEdges` to their `Toolbar` the same way.
|
|
88
|
+
A `CollapsiblePanel` clears the edge it covers for its direct flex siblings
|
|
89
|
+
automatically; a panel wrapped in your own grid cell cannot see its siblings,
|
|
90
|
+
so pass the neighboring panes' `safeAreaEdges` yourself.
|
|
89
91
|
|
|
90
92
|
The device insets come from `--kui-safe-area-block-start`, `-block-end`,
|
|
91
93
|
`-inline-start`, and `-inline-end`, which default to `env(safe-area-inset-*)`.
|
package/docs/catalog.md
CHANGED
|
@@ -396,9 +396,23 @@ revealCatalogEntry(app, initial, { block: "center" });
|
|
|
396
396
|
Pass the same signal as `wireCatalog`'s `collapsed` option so the sidebar is
|
|
397
397
|
wired as a Workbench rail (transient on small screens, focus handed to the
|
|
398
398
|
relocated toggle).
|
|
399
|
-
- **`headerPlacement` / `footerPlacement`** choose whether the entry toolbar and
|
|
400
|
-
status + resource footer stay pinned (`fixed
|
|
401
|
-
(`scroll`)
|
|
399
|
+
- **`headerPlacement` / `footerPlacement`** choose whether the entry toolbar and
|
|
400
|
+
description, and the status + resource footer, stay pinned (`fixed`), scroll with
|
|
401
|
+
the preview (`scroll`), or stay pinned while the entry pane is tall enough and
|
|
402
|
+
scroll with the preview when it is short (`auto`, the default) — so a short
|
|
403
|
+
window or large text never squeezes the preview out.
|
|
404
|
+
- **`sidebar`** configures the sidebar rail — it forwards to the Workbench's left
|
|
405
|
+
rail: `size` (default 288px), `resizable` (`true` or `{ min, max }`),
|
|
406
|
+
`separator`, `collapseMotion`, `presentation`, `responsiveOverlayAt` (default
|
|
407
|
+
`narrow`), `compactOverlay` (default `inset`), and `toolbar` (the sidebar
|
|
408
|
+
header's `ToolbarConfig`). A resizable sidebar's width is app state like
|
|
409
|
+
`collapsed`: render your size signal as `sidebar.size` and pass the same signal
|
|
410
|
+
as `wireCatalog`'s `sidebarSize` (plus `sidebarStorageKey` to remember it).
|
|
411
|
+
- **`mainToolbar` / `footerToolbar`** take the entry toolbar's and the resource
|
|
412
|
+
footer toolbar's `ToolbarConfig` (`dividerSides`, `centerAlign`, `responsive`,
|
|
413
|
+
`responsiveAt`, `safeAreaEdges`). The defaults are a wrapping entry toolbar
|
|
414
|
+
and a divider-free footer toolbar that stacks at `narrow`; an omitted or
|
|
415
|
+
`undefined` field keeps them. Configure these instead of styling the shell.
|
|
402
416
|
- **`theme`** is a global preference — the app's signal; `wireCatalog` only reports
|
|
403
417
|
the toggle, the app applies the theme (the shell reads `theme` to show the toggle's
|
|
404
418
|
opposite-state label). Omit `theme` to hide the toggle entirely.
|
|
@@ -57,7 +57,15 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
|
|
|
57
57
|
the rest of the page, including under the compact overlay's backdrop. The
|
|
58
58
|
control takes `--kui-collapsible-panel-restore-z`, which defaults to two less
|
|
59
59
|
than `--kui-collapsible-panel-overlay-z` (38); the backdrop defaults to one
|
|
60
|
-
less (39), so moving the overlay z-index moves both.
|
|
60
|
+
less (39), so moving the overlay z-index moves both. While a left or right
|
|
61
|
+
overlay is open (the `wireSidebar` compact overlay, or
|
|
62
|
+
`presentation="overlay"`), the content's floating controls — restore
|
|
63
|
+
corners and any `FloatingToolbar` — are also hidden outright (out of the
|
|
64
|
+
tab order and the accessibility tree), so they never paint over the overlay
|
|
65
|
+
whatever stacking context the app creates; they return as it closes. The
|
|
66
|
+
overlay's own floating controls stay, and a bottom overlay hides nothing. A
|
|
67
|
+
horizontal `presentation="overlay"` `ResizableRegion` does the same for its
|
|
68
|
+
siblings. Escape, a backdrop
|
|
61
69
|
press, or the panel's own close control reveals the control again, and a
|
|
62
70
|
collapsed overlay leaves it clickable. `ResizableRegion`'s `restoreControl`
|
|
63
71
|
follows the same rules, two below `--kui-resizable-region-overlay-z` (39).
|
|
@@ -118,8 +126,19 @@ Give a panel a `toolbar` (the same roles as a
|
|
|
118
126
|
[Workbench panel toolbar](workbench.md#panel-toolbars)) and it composes its own
|
|
119
127
|
top toolbar over a `Pane`, with an optional `footer` below its content:
|
|
120
128
|
|
|
121
|
-
- `title` and `panelOnly` groups lead it and are available only while it is open
|
|
122
|
-
|
|
129
|
+
- `title` and `panelOnly` groups lead it and are available only while it is open,
|
|
130
|
+
as is optional `center` content;
|
|
131
|
+
- `constant` groups and the standard `toggle: { action, name, showLabel?,
|
|
132
|
+
hideLabel? }` trail it.
|
|
133
|
+
|
|
134
|
+
The toolbar also takes the `Toolbar`'s configuration (`dividerSides`,
|
|
135
|
+
`centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); it keeps its
|
|
136
|
+
bottom divider unless `dividerSides` says otherwise. The `Pane` under it takes
|
|
137
|
+
the panel's `pane` (`PaneConfig`: `contentElement`, `contentLabel`,
|
|
138
|
+
`separators`, `safeAreaEdges`) — for example `{ contentElement: "nav",
|
|
139
|
+
contentLabel: "Sections" }` for a navigation rail. An omitted or `undefined`
|
|
140
|
+
field keeps the `Pane` default; without a `toolbar` there is no `Pane`, so
|
|
141
|
+
`pane` is ignored.
|
|
123
142
|
|
|
124
143
|
A standalone panel does not own the rest of the screen, so the app places a
|
|
125
144
|
`CollapsiblePanelRelocated` in its own work-area toolbar: it renders the panel's
|
|
@@ -289,10 +308,10 @@ panel to the compact overlay (`wireSidebar`) where the viewport cannot hold it.
|
|
|
289
308
|
|
|
290
309
|
A panel grows by the unsafe inset of the edge it docks to and pads its content
|
|
291
310
|
for every edge it touches except its interior edge. While expanded inline, it
|
|
292
|
-
also clears that edge for
|
|
293
|
-
the inset when the panel collapses. When you wrap the panel in your own grid
|
|
294
|
-
cell,
|
|
295
|
-
|
|
311
|
+
also clears that edge for every other direct child of its container, so a
|
|
312
|
+
neighboring pane gains the inset when the panel collapses. When you wrap the panel in your own grid
|
|
313
|
+
cell, pass each sibling `Pane` a `safeAreaEdges` that omits the edge the panel
|
|
314
|
+
covers. See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
|
|
296
315
|
|
|
297
316
|
## When to use which
|
|
298
317
|
|
|
@@ -258,11 +258,15 @@ rows align that 18px visual with the first inherited text line. The row clips
|
|
|
258
258
|
descendant painting to its rounded root so labels, status, and dormant trailing
|
|
259
259
|
content cannot escape its visible boundary. Rows with descriptions grow enough
|
|
260
260
|
to keep their owned two-line label stack readable; use `multiline` when the
|
|
261
|
-
primary label should wrap rather than truncate.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
primary label should wrap rather than truncate. A single-line row ends its
|
|
262
|
+
primary label and description with an ellipsis before the trailing status
|
|
263
|
+
slot, even when the label is one long word; a `multiline` row wraps instead,
|
|
264
|
+
breaking a word wider than the label column (a long component or file name)
|
|
265
|
+
rather than letting it run under the trailing slot. `ListActionRow` labels
|
|
266
|
+
follow the same single-line and `multiline` rules before the trailing action.
|
|
267
|
+
|
|
268
|
+
`DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
|
|
269
|
+
`size` prop when a consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
|
|
266
270
|
glyph contract, `--kui-disclosure-icon-scale: .5`; changing one contract does
|
|
267
271
|
not implicitly change the other. Direction changes take the shortest rotation
|
|
268
272
|
path; a 180-degree closed-to-open tie uses counterclockwise rotation.
|
|
@@ -341,9 +345,10 @@ and do not type-check there. Never exchange these property grammars. List rows e
|
|
|
341
345
|
`className`, public tokens, and semantic props instead of unrestricted `style`
|
|
342
346
|
declarations.
|
|
343
347
|
`.kui-content` gives major children 24px vertical separation.
|
|
344
|
-
`.kui-content-item` gives
|
|
345
|
-
8px
|
|
346
|
-
|
|
348
|
+
`ContentItem` (`@kerfjs/ui/content-item`, rendering `.kui-content-item`) gives
|
|
349
|
+
one child 8px inline margin, a real 1px border, 8px padding, and 12px corners;
|
|
350
|
+
the border stays transparent unless `frame="framed"`, so framing never changes
|
|
351
|
+
geometry. `shape="pill"` selects the 22px radius.
|
|
347
352
|
|
|
348
353
|
`ToolbarControlGroup` is the unit of toolbar organization, even for dormant
|
|
349
354
|
text. Each group reserves `calc(2px + remify(42px))`, or 44px, with 8px between
|
|
@@ -363,7 +368,13 @@ can remain square. A compact icon `<button>` is a 32px circle, so a selected
|
|
|
363
368
|
compact segment never becomes an oval. An icon-only `Select` joins a group as
|
|
364
369
|
one more segment with its siblings' inset, radius, hover, and focus ring; only a
|
|
365
370
|
lone Select grows the group to its icon-and-caret pill. Set `menuInset` to configure the dropdown menu surface
|
|
366
|
-
without application `::part(menu)` CSS
|
|
371
|
+
without application `::part(menu)` CSS; the default `standard` keeps each menu's
|
|
372
|
+
own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
|
|
373
|
+
`PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
|
|
374
|
+
`PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
|
|
375
|
+
open popup, fade-in surface, surface inset, row height and padding, reserved
|
|
376
|
+
check column, current-row fill, and group titles, all read from one private
|
|
377
|
+
popup-choice contract in `foundation.css`. Compact mixed controls retain the standard
|
|
367
378
|
item padding, omit an internal separator, and let the raised selected item paint
|
|
368
379
|
over the outer border instead of shrinking to an inset highlight. The Web
|
|
369
380
|
Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
|
|
@@ -374,7 +385,12 @@ choose `responsive="stack"` with `responsiveAt="compact" | "narrow"`,
|
|
|
374
385
|
`responsive="wrap"` for a heading whose title must stay whole, or
|
|
375
386
|
`responsive="center-priority"` instead of selecting its zone classes from a
|
|
376
387
|
parent stylesheet. No policy clips an action: the trailing zone, and a stacked
|
|
377
|
-
center zone, wrap whole groups onto another row.
|
|
388
|
+
center zone, wrap whole groups onto another row. The center zone never
|
|
389
|
+
compresses below its content width, so when the leading identity, center, and
|
|
390
|
+
trailing zones share a row that is too narrow, the leading title is what gives
|
|
391
|
+
way: it truncates with an ellipsis (as a platform toolbar's title does) instead
|
|
392
|
+
of the center group painting over it. When everything fits, the center group
|
|
393
|
+
keeps its place, centered in the track between the leading and trailing zones.
|
|
378
394
|
`ListHeader` similarly separates its dormant title and
|
|
379
395
|
optional count or badge from its optional 44px action. Use the mutually
|
|
380
396
|
exclusive `count`/`countLabel` pair for non-negative safe-integer section
|
|
@@ -400,6 +416,16 @@ padding + 24px icon + 8px gap) and 8px from the right edge for an icon-bearing
|
|
|
400
416
|
row. Applications own the values, formatting, and whether an icon is decorative
|
|
401
417
|
or meaningfully labeled.
|
|
402
418
|
|
|
419
|
+
A row follows the settings-style key/value priority: the value keeps its
|
|
420
|
+
content and the label gives way. The label and value are two content-sized
|
|
421
|
+
columns that share the row's free space equally, each stopping once its content
|
|
422
|
+
fits. A short value therefore stays whole on one line beside any label, and a
|
|
423
|
+
long label takes the remaining width, wrapping at its spaces and ending a word
|
|
424
|
+
wider than its column (a long component or file name) in an ellipsis before the
|
|
425
|
+
value rather than running under it. A short label keeps its width beside a
|
|
426
|
+
long value, which wraps; when both are long they split the row, so neither is
|
|
427
|
+
starved.
|
|
428
|
+
|
|
403
429
|
## Imports and side effects
|
|
404
430
|
|
|
405
431
|
Every component has an explicit JS and CSS subpath. In CSS-aware browser builds,
|