@kerfjs/ui 5.0.0-beta.23 → 5.0.0-beta.25
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 +45 -23
- package/ai/application-ui-diagnostic-ids-v1.json +3 -0
- package/ai/application-ui-profile.defaults.json +1 -1
- package/ai/compile-time-contracts-v1.json +5 -12
- package/ai/component-catalog-v2-overrides.json +12 -49
- package/ai/component-catalog-v2.d.ts +1 -0
- package/ai/component-catalog-v2.json +458 -123
- package/ai/component-catalog-v2.schema.json +2 -1
- package/ai/component-catalog.json +658 -195
- package/ai/public-api-signatures-v1.md +160 -80
- package/ai/skill.md +22 -22
- package/ai/webawesome-jsx-signatures-v1.md +2 -1
- package/analyzer/cli.mjs +5 -2
- package/analyzer/index.d.mts +1 -0
- package/analyzer/index.mjs +117 -10
- package/dist/app-tab.d.ts +10 -2
- package/dist/app-tab.js +1 -1
- package/dist/browser/list-action-row.js +1 -0
- package/dist/browser/list-item.js +1 -0
- package/dist/browser/list.js +3 -0
- package/dist/browser/surface-scaffold.js +3 -0
- package/dist/catalog.d.ts +8 -4
- package/dist/catalog.js +21 -11
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-ELSJX4W7.js → chunk-4EF2CMYS.js} +25 -6
- package/dist/chunk-4EF2CMYS.js.map +1 -0
- package/dist/{chunk-OHU6CI22.js → chunk-B3A3IVO5.js} +2 -2
- package/dist/{chunk-OHU6CI22.js.map → chunk-B3A3IVO5.js.map} +1 -1
- package/dist/{chunk-K57KRAOV.js → chunk-FRVS5RFM.js} +24 -6
- package/dist/chunk-FRVS5RFM.js.map +1 -0
- package/dist/{chunk-DSNIYOZ3.js → chunk-GWEAPEZI.js} +16 -3
- package/dist/chunk-GWEAPEZI.js.map +1 -0
- package/dist/chunk-HP2B2L26.js +102 -0
- package/dist/chunk-HP2B2L26.js.map +1 -0
- package/dist/{chunk-OZWU5ZPZ.js → chunk-IJBSZ4NX.js} +2 -2
- package/dist/{chunk-OZWU5ZPZ.js.map → chunk-IJBSZ4NX.js.map} +1 -1
- package/dist/chunk-J5BFYY7Q.js +35 -0
- package/dist/chunk-J5BFYY7Q.js.map +1 -0
- package/dist/{chunk-GP5DP5DL.js → chunk-JFGXQBIP.js} +85 -24
- package/dist/chunk-JFGXQBIP.js.map +1 -0
- package/dist/{chunk-QQFJMRIB.js → chunk-KWWR5VMS.js} +2 -2
- package/dist/{chunk-QQFJMRIB.js.map → chunk-KWWR5VMS.js.map} +1 -1
- package/dist/chunk-OBLTAKSX.js +43 -0
- package/dist/chunk-OBLTAKSX.js.map +1 -0
- package/dist/{chunk-PIDTEQ3U.js → chunk-OT6RPYAP.js} +17 -3
- package/dist/chunk-OT6RPYAP.js.map +1 -0
- package/dist/{chunk-W7YD6E4N.js → chunk-R7ZWUN64.js} +2 -2
- package/dist/{chunk-W7YD6E4N.js.map → chunk-R7ZWUN64.js.map} +1 -1
- package/dist/{chunk-PZQVSDLH.js → chunk-RKVQEH4J.js} +1 -1
- package/dist/chunk-RKVQEH4J.js.map +1 -0
- package/dist/{chunk-7L6EHUMV.js → chunk-SYDMYBPG.js} +3 -3
- package/dist/chunk-SYDMYBPG.js.map +1 -0
- package/dist/{chunk-W4CXQYSG.js → chunk-TB6DY7H5.js} +3 -1
- package/dist/chunk-TB6DY7H5.js.map +1 -0
- package/dist/{chunk-AASLYRGE.js → chunk-UKKSMZYT.js} +18 -7
- package/dist/chunk-UKKSMZYT.js.map +1 -0
- package/dist/{chunk-BBRXX6PF.js → chunk-VCE4MPVE.js} +26 -4
- package/dist/chunk-VCE4MPVE.js.map +1 -0
- package/dist/{chunk-VLYV65LK.js → chunk-W5L2JSBY.js} +5 -3
- package/dist/chunk-W5L2JSBY.js.map +1 -0
- package/dist/{chunk-5VTB2BKP.js → chunk-WNWD54GR.js} +16 -2
- package/dist/chunk-WNWD54GR.js.map +1 -0
- package/dist/{chunk-M7JBER5U.js → chunk-X2U3QJCJ.js} +8 -2
- package/dist/chunk-X2U3QJCJ.js.map +1 -0
- package/dist/{chunk-DPDBVKNA.js → chunk-YMKH5XTF.js} +5 -3
- package/dist/chunk-YMKH5XTF.js.map +1 -0
- package/dist/collapsible-panel.d.ts +9 -1
- package/dist/collapsible-panel.js +36 -15
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/divider-sides-267FA7sY.d.ts +4 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +20 -19
- package/dist/list-action-row.d.ts +11 -1
- package/dist/list-action-row.js +2 -1
- package/dist/list-header.d.ts +15 -2
- package/dist/list-header.js +1 -1
- package/dist/list-item.d.ts +12 -1
- package/dist/list-item.js +2 -1
- package/dist/list.d.ts +19 -0
- package/dist/list.js +3 -0
- package/dist/list.js.map +1 -0
- package/dist/nav-stack.js +1 -1
- package/dist/resizable-region.d.ts +19 -2
- package/dist/resizable-region.js +1 -1
- package/dist/segmented-control.js +1 -1
- package/dist/select.d.ts +12 -1
- package/dist/select.js +1 -1
- package/dist/skeleton.d.ts +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/split-view.js +2 -2
- package/dist/state-banner.d.ts +4 -2
- package/dist/state-banner.js +1 -1
- package/dist/styles/app-tab.css +26 -0
- package/dist/styles/catalog.css +8 -2
- package/dist/styles/collapsible-panel.css +66 -4
- package/dist/styles/list-action-row.css +64 -0
- package/dist/styles/list-header.css +32 -0
- package/dist/styles/list-item.css +45 -6
- package/dist/styles/list.css +43 -0
- package/dist/styles/resizable-region.css +132 -0
- package/dist/styles/select.css +68 -0
- package/dist/styles/state-banner.css +32 -1
- package/dist/styles/styles.css +2 -1
- package/dist/styles/sunken-panel.css +4 -0
- package/dist/styles/surface-scaffold.css +51 -0
- package/dist/styles/tab-bar.css +24 -0
- package/dist/styles/toolbar-control-group.css +73 -1
- package/dist/styles/toolbar-text.css +1 -1
- package/dist/styles/toolbar.css +38 -2
- package/dist/styles/webawesome.css +12 -0
- package/dist/styles/workbench.css +89 -0
- package/dist/sunken-panel.d.ts +5 -2
- package/dist/sunken-panel.js +1 -1
- package/dist/surface-scaffold.d.ts +25 -0
- package/dist/surface-scaffold.js +3 -0
- package/dist/surface-scaffold.js.map +1 -0
- package/dist/tab-bar.d.ts +11 -2
- package/dist/tab-bar.js +1 -1
- package/dist/toolbar-control-group.d.ts +16 -2
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +5 -3
- package/dist/toolbar.js +1 -1
- package/dist/value-table.js +1 -1
- package/dist/webawesome.d.ts +1 -0
- package/dist/wire-catalog.d.ts +4 -2
- package/dist/wire-catalog.js +95 -36
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.d.ts +6 -1
- package/dist/wire-sidebar.js +27 -8
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-token-search-fields.d.ts +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +8 -0
- package/dist/workbench.js +42 -0
- package/dist/workbench.js.map +1 -1
- package/docs/accessibility.md +67 -15
- package/docs/catalog.md +17 -12
- package/docs/collapsible-panel.md +7 -0
- package/docs/component-contract.md +19 -9
- package/docs/component-selection.md +65 -31
- package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
- package/docs/design/templates/empty-state/filtered.svg +1 -1
- 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 -7
- package/docs/design/templates/empty-state.svg +1 -7
- package/docs/design/templates/list/compact-dark.svg +1 -0
- package/docs/design/templates/list/compact.svg +1 -0
- package/docs/design/templates/list/stack-dark.svg +1 -0
- package/docs/design/templates/list/stack.svg +1 -0
- 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 -7
- package/docs/design/templates/list-action-row.svg +1 -7
- package/docs/design/templates/list-dark.svg +1 -0
- package/docs/design/templates/list-header/action-dark.svg +1 -1
- package/docs/design/templates/list-header/action.svg +1 -1
- package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -1
- package/docs/design/templates/list-header/toggle-collapsed.svg +1 -1
- package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
- package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
- package/docs/design/templates/list-header-dark.svg +1 -11
- package/docs/design/templates/list-header.svg +1 -11
- 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/multiline-dark.svg +1 -1
- package/docs/design/templates/list-item/multiline.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 -11
- package/docs/design/templates/list-item.svg +1 -11
- package/docs/design/templates/list.svg +1 -0
- package/docs/design/templates/segmented-control-dark.svg +1 -7
- package/docs/design/templates/segmented-control.svg +1 -7
- package/docs/design/templates/skeleton-dark.svg +1 -9
- package/docs/design/templates/skeleton.svg +1 -9
- package/docs/design/templates/state-banner/danger-dark.svg +1 -1
- package/docs/design/templates/state-banner/danger.svg +1 -1
- package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
- package/docs/design/templates/state-banner/info-badge.svg +1 -0
- package/docs/design/templates/state-banner/info-dark.svg +1 -1
- package/docs/design/templates/state-banner/info.svg +1 -1
- package/docs/design/templates/state-banner/success-dark.svg +1 -1
- package/docs/design/templates/state-banner/success.svg +1 -1
- package/docs/design/templates/state-banner/warning-dark.svg +1 -1
- package/docs/design/templates/state-banner/warning.svg +1 -1
- package/docs/design/templates/state-banner-dark.svg +1 -11
- package/docs/design/templates/state-banner.svg +1 -11
- package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
- package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
- package/docs/design/templates/tab-bar-dark.svg +1 -5
- package/docs/design/templates/tab-bar.svg +1 -5
- package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
- package/docs/design/templates/token-search-field/empty.svg +1 -1
- package/docs/design/templates/token-search-field/tokens-dark.svg +1 -1
- package/docs/design/templates/token-search-field/tokens.svg +1 -1
- package/docs/design/templates/token-search-field-dark.svg +1 -7
- package/docs/design/templates/token-search-field.svg +1 -7
- package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
- package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -1
- package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -1
- package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -1
- package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
- package/docs/design/templates/toolbar-control-group-dark.svg +1 -11
- package/docs/design/templates/toolbar-control-group.svg +1 -11
- package/docs/design/templates/toolbar-dark.svg +1 -5
- package/docs/design/templates/toolbar-text-dark.svg +1 -9
- package/docs/design/templates/toolbar-text.svg +1 -9
- package/docs/design/templates/toolbar.svg +1 -5
- 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 -5
- package/docs/design/templates/value-table.svg +1 -5
- package/docs/design/templates.md +29 -20
- package/docs/examples/component-catalog-extension-v2.json +3 -6
- package/docs/examples/component-catalog-extension.json +1 -1
- package/docs/layout.md +7 -9
- package/docs/recipes.md +8 -7
- package/docs/sunken-panel.md +11 -1
- package/docs/surface-scaffold.md +17 -0
- package/docs/type-contracts.md +11 -10
- package/docs/ui-analyzer.md +19 -1
- package/docs/ui-doctor.md +7 -5
- package/docs/ux-demo.md +6 -3
- package/docs/webawesome-theme.md +4 -1
- package/docs/workbench.md +49 -2
- package/doctor/eslint-diagnostics.d.mts +16 -0
- package/doctor/eslint-diagnostics.mjs +17 -0
- package/doctor/index.mjs +21 -3
- package/llms.txt +33 -11
- package/package.json +14 -8
- package/traversal-exclusions.mjs +7 -1
- package/ux-demo/recipes/app-shell.tsx +36 -23
- package/ux-demo/recipes/collapsible-sidebar.tsx +23 -17
- package/ux-demo/recipes/composer-form.tsx +15 -6
- package/ux-demo/recipes/list-detail-dialog.tsx +31 -15
- package/ux-demo/recipes/list-workspace-states.tsx +16 -7
- package/ux-demo/recipes/loading-inspector.tsx +39 -18
- package/ux-demo/recipes/navigation-sidebar.tsx +1 -1
- package/ux-demo/recipes/recipes.css +7 -2
- package/ux-demo/recipes/workspace-header.tsx +17 -7
- package/dist/browser/panel-header.js +0 -7
- package/dist/chunk-5VTB2BKP.js.map +0 -1
- package/dist/chunk-7L6EHUMV.js.map +0 -1
- package/dist/chunk-AASLYRGE.js.map +0 -1
- package/dist/chunk-BBRXX6PF.js.map +0 -1
- package/dist/chunk-DPDBVKNA.js.map +0 -1
- package/dist/chunk-DSNIYOZ3.js.map +0 -1
- package/dist/chunk-ELSJX4W7.js.map +0 -1
- package/dist/chunk-GP5DP5DL.js.map +0 -1
- package/dist/chunk-K57KRAOV.js.map +0 -1
- package/dist/chunk-M7JBER5U.js.map +0 -1
- package/dist/chunk-NENBUYX5.js +0 -79
- package/dist/chunk-NENBUYX5.js.map +0 -1
- package/dist/chunk-PIDTEQ3U.js.map +0 -1
- package/dist/chunk-PZQVSDLH.js.map +0 -1
- package/dist/chunk-RYRIFZCT.js +0 -58
- package/dist/chunk-RYRIFZCT.js.map +0 -1
- package/dist/chunk-VLYV65LK.js.map +0 -1
- package/dist/chunk-W4CXQYSG.js.map +0 -1
- package/dist/panel-header.d.ts +0 -42
- package/dist/panel-header.js +0 -7
- package/dist/panel-header.js.map +0 -1
- package/dist/styles/panel-header.css +0 -64
- package/docs/design/templates/panel-header/icon-actions-dark.svg +0 -1
- package/docs/design/templates/panel-header/icon-actions.svg +0 -1
- package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +0 -1
- package/docs/design/templates/panel-header/icon-summary-actions.svg +0 -1
- package/docs/design/templates/panel-header/no-icon-dark.svg +0 -1
- package/docs/design/templates/panel-header/no-icon.svg +0 -1
- package/docs/design/templates/panel-header/page-heading-dark.svg +0 -1
- package/docs/design/templates/panel-header/page-heading.svg +0 -1
- package/docs/design/templates/panel-header/title-only-dark.svg +0 -1
- package/docs/design/templates/panel-header/title-only.svg +0 -1
- package/docs/design/templates/panel-header-dark.svg +0 -13
- package/docs/design/templates/panel-header.svg +0 -13
package/docs/accessibility.md
CHANGED
|
@@ -6,14 +6,47 @@ These are normative contracts for package components and consuming applications.
|
|
|
6
6
|
|
|
7
7
|
- All controls have accessible names and visible `:focus-visible` treatment.
|
|
8
8
|
- Decorative `LucideIcon` output is `aria-hidden`; pass `label` only when the SVG itself conveys meaning.
|
|
9
|
-
- `ListItem` uses native button Enter/Space behavior. `selected` maps to `aria-current="page"`; `pressed` maps to `aria-pressed`. Selected rows keep the normal foreground over their brand-tinted fill so text retains WCAG AA contrast in light and dark themes. Its `trailing` content is dormant and must not contain controls. Its `rootAttributes` slot accepts only application `data-*` metadata and deliberately cannot emit `role="menuitem"` in isolation—a true ARIA menu must own arrow, Home/End, Escape, and focus behavior as one widget.
|
|
9
|
+
- `ListItem` uses native button Enter/Space behavior. `selected` maps to `aria-current="page"`; `pressed` maps to `aria-pressed`. Selected rows keep the normal foreground over their brand-tinted fill so text retains WCAG AA contrast in light and dark themes. Its leading icon visual is 18px while the row retains its 44px minimum target; multiline icons align to the first text line. Its `trailing` content is dormant and must not contain controls. Its `rootAttributes` slot accepts only application `data-*` metadata and deliberately cannot emit `role="menuitem"` in isolation—a true ARIA menu must own arrow, Home/End, Escape, and focus behavior as one widget.
|
|
10
10
|
- `ListHeader` owns action naming, disabled state, and disclosure `aria-expanded`. Toggle mode supplies one decorative 18px `DisclosureArrow` when `actionIcon` is omitted; it mirrors `expanded` while the native button's accessible name stays stable. The application must update that controlled state and reveal or hide real content. A valid `count` is visually rendered in an `aria-hidden` neutral pill while the required localized `countLabel` becomes part of the owning heading or disclosure button's accessible name; zero remains a real count. Its narrow `triggerAttributes` slot may describe a native popover or controlled-content relationship with `popoverTarget`, `popoverTargetAction`, `aria-controls`, and `aria-haspopup`; the application owns the target surface and its focus/dismissal behavior.
|
|
11
|
+
- Dispose `wireTabBars` and `wireTokenSearchFields` with their owning view. Disposal cancels queued controlled-render focus restoration, so a torn-down view cannot reclaim focus from its successor.
|
|
11
12
|
- In any `.kui-pane`, menu rows, `ListHeader` actions, and toolbar groups keep a minimum 44px target in both dimensions. A `ListHeader` fills the available inline width and keeps that action at the logical end, including in RTL. Its action visual defaults to 18px through `--kui-list-header-action-icon-size`; do not reduce the target to the visible icon.
|
|
12
13
|
- `LoadingSpinner` is either labeled (`role="img"`) or hidden. Its rotation stops for reduced motion.
|
|
13
|
-
- `StateBanner` defaults to polite `role="status"`; use `urgency="alert"` only for an attention-requiring failure.
|
|
14
|
+
- `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.
|
|
14
15
|
- `EmptyState` reports busy state through `aria-busy` and never relies on an illustration as its label.
|
|
15
16
|
- `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.
|
|
16
17
|
- `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 override `--kui-disclosure-arrow-size` without changing that ownership. Configured directions animate over the shortest path; a 180-degree closed-to-open tie uses counterclockwise rotation.
|
|
18
|
+
- `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.
|
|
19
|
+
|
|
20
|
+
## Select
|
|
21
|
+
|
|
22
|
+
Supply a visible `label`, or `ariaLabel` when the surrounding interface already
|
|
23
|
+
provides visual context. A nonempty `label` takes precedence when both are
|
|
24
|
+
supplied. Kerf forwards that name through Web Awesome's internal label contract;
|
|
25
|
+
an `aria-label` on the custom-element host alone cannot name its shadow
|
|
26
|
+
combobox. With `ariaLabel` alone, Kerf visually hides the internal label without
|
|
27
|
+
adding height or spacing. This also applies to `renderSelected`: selected content
|
|
28
|
+
stays separate from the control's stable accessible name. Applications do not
|
|
29
|
+
need shadow-DOM patches or extra label styling.
|
|
30
|
+
|
|
31
|
+
Use `presentation="toolbar-borderless"` with `size="compact"` inside a
|
|
32
|
+
`ToolbarControlGroup`; set `focusRingOwner="group"` when that parent paints the
|
|
33
|
+
composed focus ring. `selectedPresentation="icon-only"` hides only the visible
|
|
34
|
+
selected label—the required `label` or `ariaLabel` still names the combobox.
|
|
35
|
+
Navigation selects can use intrinsic `presentation="navigation"` plus
|
|
36
|
+
`labelMaxWidth` for component-owned ellipsis. These props own the control's
|
|
37
|
+
appearance; its parent continues to own outer placement.
|
|
38
|
+
|
|
39
|
+
Use `hint` for persistent supporting text below the control; use
|
|
40
|
+
`placeholderText` only for the empty value shown inside the closed control.
|
|
41
|
+
Kerf passes hint text through Web Awesome's form-control contract, which renders
|
|
42
|
+
the hint part and connects the shadow combobox to it with `aria-describedby`.
|
|
43
|
+
Loading placeholders keep the same visible hint while replacing the interactive
|
|
44
|
+
control with inert chrome.
|
|
45
|
+
|
|
46
|
+
`tests/unit/components.test.tsx` covers name projection and visible/hidden label
|
|
47
|
+
variants. `tests/browser/select-accessibility.spec.ts` verifies actual accessible
|
|
48
|
+
names, unchanged unlabeled geometry, keyboard selection, controlled rerenders,
|
|
49
|
+
native hint wiring, and wide/narrow presentation in Chromium, Firefox, and WebKit.
|
|
17
50
|
|
|
18
51
|
## ListActionRow
|
|
19
52
|
|
|
@@ -43,21 +76,21 @@ The handle exposes separator role, orientation, name, minimum, maximum, and curr
|
|
|
43
76
|
|
|
44
77
|
The application owns persistence and collapsed/expanded policy. Keep the last expanded size outside the component and restore it when reopening. An optional `handleIcon` replaces only decorative dormant content; it must not contain controls or interactive roles because the separator remains the sole focus and interaction owner.
|
|
45
78
|
|
|
46
|
-
##
|
|
79
|
+
## Toolbar headings
|
|
47
80
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
`ToolbarText
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
81
|
+
Compose panel, dialog, and page headings as a plain `Toolbar`. Its leading zone
|
|
82
|
+
holds an optional icon `ToolbarControlGroup` and a direct extra-large
|
|
83
|
+
`ToolbarText`; controls belong in a trailing `ToolbarControlGroup`. By default
|
|
84
|
+
the title carries no native heading role, so for a **dialog or panel** the
|
|
85
|
+
application connects the title id and optional supporting-copy id to the owning
|
|
86
|
+
host through `aria-labelledby` and `aria-describedby`. For a **page or view**
|
|
87
|
+
title, pass `headingLevel` (usually `1`) to `ToolbarText`: it then exposes
|
|
55
88
|
`role="heading"` with a matching `aria-level`, giving the view a heading landmark
|
|
56
89
|
so screen-reader heading navigation and "main heading" semantics work — the same
|
|
57
|
-
role/level pair
|
|
58
|
-
|
|
90
|
+
role/level pair used throughout Kerf UI. Keep the levels meaningful and
|
|
91
|
+
non-skipping within a view. Pass trailing
|
|
59
92
|
controls as a labeled `ToolbarControlGroup` when that group needs an accessible
|
|
60
|
-
name.
|
|
93
|
+
name. Keep supporting copy as app-owned content below the toolbar.
|
|
61
94
|
|
|
62
95
|
## FloatingToolbar
|
|
63
96
|
|
|
@@ -73,6 +106,13 @@ and — via `position` and `--kui-floating-toolbar-inset` — where it sits.
|
|
|
73
106
|
|
|
74
107
|
`AppTab` renders one controlled tab. `TabBar` supplies the containing tab list,
|
|
75
108
|
fixed leading/trailing regions, and a horizontally scrollable strip.
|
|
109
|
+
Use `TabBar.presentation` for rail, segmented, or inspector chrome,
|
|
110
|
+
`allocation="fill"` when peers should divide the strip, and
|
|
111
|
+
`trailingPlacement="adjacent"` when an action belongs beside the final tab.
|
|
112
|
+
`AppTab` provides compact 32px, segmented, truncating-label, and icon-only
|
|
113
|
+
presentations. Icon-only tabs keep the required `name` as the tab button's
|
|
114
|
+
accessible name while visually hiding the duplicate label. These props own
|
|
115
|
+
component appearance only; the application still owns the bar's outer placement.
|
|
76
116
|
`AppTab.rootAttributes` accepts application `data-*` metadata only; runtime
|
|
77
117
|
filtering rejects roles plus case variants of component- or wiring-owned
|
|
78
118
|
action, identity, selection, drag, drop, and component attributes. An optional
|
|
@@ -86,7 +126,8 @@ stops on drop/drag end/disposal, and does not change keyboard behavior. It
|
|
|
86
126
|
returns a disposer.
|
|
87
127
|
|
|
88
128
|
Arrow / Home / End follow the ARIA Tabs **automatic-activation** pattern by
|
|
89
|
-
default: they move roving focus and select the focused tab.
|
|
129
|
+
default: they move roving focus and select the focused tab. If selection synchronously
|
|
130
|
+
replaces the strip, focus returns to the replacement with the same bar and tab IDs. Pass
|
|
90
131
|
`activation: 'manual'` (or set `data-tab-activation="manual"` on a strip via the
|
|
91
132
|
`TabBar` `activation` prop, which overrides the option per bar) for
|
|
92
133
|
**manual activation**: arrow keys move roving focus only and the user selects
|
|
@@ -123,7 +164,12 @@ and `placeTokenSearchCaret()` to restore a text caret without landing inside a
|
|
|
123
164
|
chip. Call `wireTokenSearchFields()` once at a stable root so Enter submits
|
|
124
165
|
without inserting a contenteditable line break and keyboard chip deletion
|
|
125
166
|
restores focus plus the text-relative caret after controlled rendering replaces
|
|
126
|
-
the editor
|
|
167
|
+
the editor. Restoration finishes after synchronous input listeners and before
|
|
168
|
+
another keystroke; it does not wait for an animation frame that could overwrite
|
|
169
|
+
a later selection. Select All + Backspace/Delete shares that replacement path
|
|
170
|
+
and keeps the adopted expanded signal open while managed focus is enabled.
|
|
171
|
+
Real outside focus, empty Escape, disposal, and removed fields retain their usual
|
|
172
|
+
behavior. The editor still wraps text visually at its inline edge. Editable text is DOM-owned between token changes; a clear handler empties
|
|
127
173
|
the editor's `textContent` before updating application state. Leading and
|
|
128
174
|
trailing controls share the first text line's fixed vertical center and remain
|
|
129
175
|
there as the editor wraps. In `collapsible` mode, the closed state is one named
|
|
@@ -147,6 +193,12 @@ originating `InputEvent` so a caller can gate on `inputType`/`data` — fires on
|
|
|
147
193
|
`input`, letting a caller drop its own `input` listener; the application still
|
|
148
194
|
owns query parsing and result-count/loading announcements.
|
|
149
195
|
|
|
196
|
+
Managed clear captures the action before application handlers run, keeps the adopted
|
|
197
|
+
expanded signal open during editor replacement, and focuses the current editor after
|
|
198
|
+
rendering so typing can continue. The app still owns clearing query/tokens and emptying
|
|
199
|
+
DOM-owned text. This focus step respects `manageFocus: false`, disposal, removed fields,
|
|
200
|
+
and focus deliberately moved to another control; no app-level reopen callback is needed.
|
|
201
|
+
|
|
150
202
|
## CollapsiblePanel / sidebar
|
|
151
203
|
|
|
152
204
|
`CollapsiblePanel` is a labeled `aside` region that is `aria-hidden` while
|
package/docs/catalog.md
CHANGED
|
@@ -109,9 +109,10 @@ const buttonPreview = (
|
|
|
109
109
|
);
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
The overlay selects every immediate child of a `CatalogExample
|
|
113
|
-
|
|
114
|
-
to be the specimen. Outside an example
|
|
112
|
+
The overlay selects every immediate child of a `CatalogExample`; the helper
|
|
113
|
+
marks its generated label and note so they are excluded automatically. It does
|
|
114
|
+
not recursively promote a nested child to be the specimen. Outside an example
|
|
115
|
+
row, it selects only top-level
|
|
115
116
|
`[data-component]` roots in the canvas and ignores nested component descendants.
|
|
116
117
|
These rules keep a row's label/group scaffolding out of the measurement and make
|
|
117
118
|
the authored nesting determine exactly what is inspected.
|
|
@@ -138,15 +139,19 @@ Pass the conditional `geometryOverlay` boolean to `Catalog`, then call
|
|
|
138
139
|
`wireCatalogGeometryOverlay(root)` once after the first render and retain its
|
|
139
140
|
disposer alongside `wireCatalog`'s.
|
|
140
141
|
|
|
141
|
-
| Overlay mark | Meaning | It is not
|
|
142
|
-
| ----------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
143
|
-
| Orange translucent band | A positive computed margin on the selected specimen, after subtracting the helper's alignment inset. | Padding, gap, or empty content. Zero and negative margins are not drawn.
|
|
144
|
-
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
142
|
+
| Overlay mark | Meaning | It is not |
|
|
143
|
+
| ----------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
144
|
+
| Orange translucent band | A positive computed margin on the selected specimen, after subtracting the helper's alignment inset. | Padding, gap, or empty content. Zero and negative margins are not drawn. |
|
|
145
|
+
| Accent solid edge | The selected specimen's computed border widths and radius, except `none`/`hidden` styles. | A focus ring, outline, child border, or metadata ownership claim. |
|
|
146
|
+
| Quiet dashed outline | The border-box bound of a transparent selected specimen with no visible border. | A real CSS border, padding edge, or proof that the specimen owns size. |
|
|
147
|
+
|
|
148
|
+
The overlay recomputes from live rendered styles when specimens resize, preview
|
|
149
|
+
markup changes, theme/root attributes change, or loaded/inline stylesheets
|
|
150
|
+
change. Component CSS is therefore the source of truth; do not duplicate margin
|
|
151
|
+
or border values in demo data. The overlay does not visualize padding, gaps,
|
|
152
|
+
negative/zero margins, scroll overflow, hit targets, or nested descendants.
|
|
153
|
+
Inspect computed styles and the machine-readable `geometry` metadata for those
|
|
154
|
+
facts. Opaque borderless specimens do not receive the dashed bound.
|
|
150
155
|
|
|
151
156
|
```tsx
|
|
152
157
|
<Catalog
|
|
@@ -20,6 +20,9 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
|
|
|
20
20
|
the fixed-size content slides out via `transform` (composited, clipped) — never
|
|
21
21
|
a per-frame width/height animation. The app owns the `collapsed` signal; `size`
|
|
22
22
|
overrides the CSS default width/height.
|
|
23
|
+
Reusable shell policies are typed props: `separator`, `collapseMotion`,
|
|
24
|
+
`contentOverflow`, and `presentation`. A collapsed panel may also receive a
|
|
25
|
+
`restoreControl`, which Kerf places at the safe-area-aware `restorePosition`.
|
|
23
26
|
- **`CollapsiblePanelToggle({ side, collapsed, action, panelId?, label? })`** and
|
|
24
27
|
**`collapsiblePanelToggleIcon(side, collapsed)`** — the standard toggle
|
|
25
28
|
affordance and its icon convention, so every sidebar reads the same: `PanelLeft*`
|
|
@@ -38,6 +41,10 @@ Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.
|
|
|
38
41
|
`deviceClass()` signal): the open panel floats over the content with a
|
|
39
42
|
dismissable backdrop, Escape and backdrop-click collapse it, and Tab is trapped
|
|
40
43
|
within the panel (the ARIA dialog pattern);
|
|
44
|
+
- accepts `compactPresentation: "hidden"` when a compact application replaces
|
|
45
|
+
the panel with different navigation instead of overlaying it;
|
|
46
|
+
- keeps compact overlays exclusive by default, collapsing another open panel
|
|
47
|
+
when a new one opens (`exclusiveCompact: false` opts out);
|
|
41
48
|
- **persists** the collapsed state to `storage` (default `localStorage`) under
|
|
42
49
|
`storageKey`, seeding the signal on wire-up.
|
|
43
50
|
|
|
@@ -193,6 +193,10 @@ an unlisted implementation class. Selectors such as `.kui-state-banner span`,
|
|
|
193
193
|
private structure. If no prop, token, or cataloged class expresses a recurring
|
|
194
194
|
need, request a supported hook instead of inferring one from rendered markup.
|
|
195
195
|
|
|
196
|
+
`ListItem` renders its leading icon and nested SVG at a root-scaled 18px by
|
|
197
|
+
default while retaining the row's 44px minimum interactive target. Multiline
|
|
198
|
+
rows align that 18px visual with the first inherited text line.
|
|
199
|
+
|
|
196
200
|
`DisclosureArrow` uses an 18px root-scaled visual by default. Override
|
|
197
201
|
`--kui-disclosure-arrow-size` on the component or its containing scope when a
|
|
198
202
|
consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
|
|
@@ -210,7 +214,9 @@ glyph defaults to 18px through `--kui-list-header-action-icon-size`.
|
|
|
210
214
|
|
|
211
215
|
`StateBanner` exposes instance-level `--kui-state-banner-background`,
|
|
212
216
|
`--kui-state-banner-border`, `--kui-state-banner-foreground`,
|
|
213
|
-
`--kui-state-banner-detail`,
|
|
217
|
+
`--kui-state-banner-detail`, `--kui-state-banner-badge-background`,
|
|
218
|
+
`--kui-state-banner-badge-foreground`, and action background variables. Its optional
|
|
219
|
+
badge is a compact pill beside the title and follows the banner tone by default. Its five built-in
|
|
214
220
|
tones can be rethemed globally with
|
|
215
221
|
`--kui-state-banner-{tone}-{background|border|foreground}`. Toolbar control,
|
|
216
222
|
segmented-control, app-tab, and tab-bar colors likewise use their public
|
|
@@ -231,6 +237,13 @@ header, one scrolling vertical `.kui-pane__content`, and an optional footer.
|
|
|
231
237
|
Logical-edge separator lines are independently opt-in and default off.
|
|
232
238
|
`@kerfjs/ui/layout.css` retains the pane roles and supplies the related content
|
|
233
239
|
geometry classes.
|
|
240
|
+
`List` is the corresponding layout-only vertical stack: its children stretch by
|
|
241
|
+
default, while `gap`, `flex`, and `scrollable` opt into standard/custom spacing,
|
|
242
|
+
flex growth, and vertical scroll ownership. `dividerSides` accepts canonical
|
|
243
|
+
physical top/right/bottom/left combinations such as `tr` and `trbl`; the stack
|
|
244
|
+
adds no list semantics, margin, or padding of its own. String props receive
|
|
245
|
+
browser CSS, so use `gap="var(--kui-space-2xs)"` for the root-scaled 4px token or
|
|
246
|
+
`gap="0.25rem"`; source-only `remify(4px)` is not valid at runtime.
|
|
234
247
|
`.kui-content` gives major children 24px vertical separation.
|
|
235
248
|
`.kui-content-item` gives one child 8px inline margin, a real 1px border,
|
|
236
249
|
8px padding, and 12px corners; border and background may be transparent without
|
|
@@ -250,14 +263,11 @@ into the section label. Do not add padding to pane shells,
|
|
|
250
263
|
double child-owned geometry with wrapper insets, or create competing scroll
|
|
251
264
|
owners. The [layout contract](./layout.md) lists the public roles and tokens.
|
|
252
265
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
when no icon is passed. The optional summary is a separate row aligned below the
|
|
259
|
-
title, so it cannot pull the icon group out of vertical alignment with the
|
|
260
|
-
title and action row.
|
|
266
|
+
Panel, dialog, and page headings are direct `Toolbar` compositions. The leading
|
|
267
|
+
zone holds an optional icon `ToolbarControlGroup` and a direct extra-large
|
|
268
|
+
`ToolbarText`; app actions belong in a trailing `ToolbarControlGroup`. Omit the
|
|
269
|
+
icon group when it has no content. Supporting copy is app-owned content below
|
|
270
|
+
the toolbar so it cannot pull the icon or actions out of alignment.
|
|
261
271
|
|
|
262
272
|
`ValueTable` composes typed `ValueTableRow` entries. A row owns its `dt`/`dd`
|
|
263
273
|
semantics and may receive a leading `SafeHtml` icon. Every row keeps 8px of
|