@kerfjs/ui 5.0.0-beta.96 → 5.0.0-beta.98
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/ai/component-catalog.json +3 -1
- package/ai/components/list-action-row.md +1 -0
- package/ai/components/list-item.md +1 -0
- package/ai/public-api-signatures-v1.md +24 -10
- package/ai/skill.md +4 -4
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +18 -4
- package/dist/catalog.js +6 -2
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-BU23Z5HZ.js → chunk-527IAEWG.js} +5 -3
- package/dist/chunk-527IAEWG.js.map +1 -0
- package/dist/{chunk-AYHC62OZ.js → chunk-AZWE2FB5.js} +15 -15
- package/dist/chunk-AZWE2FB5.js.map +1 -0
- package/dist/{nav-stack-BvSKY448.d.ts → nav-stack-Cp3Y8kJ9.d.ts} +5 -1
- package/dist/nav-stack.d.ts +1 -1
- package/dist/nav-stack.js +1 -1
- package/dist/select-register.js +11 -0
- package/dist/select-register.js.map +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js +1 -1
- package/dist/styles/catalog/components/catalog-example-stack.css +5 -0
- package/dist/styles/components/actions/popup-menu/popup-menu.css +7 -0
- package/dist/styles/components/actions/toolbar/toolbar.css +19 -0
- package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +11 -3
- package/dist/styles/components/actions/toolbar-text/toolbar-text.css +9 -0
- package/dist/styles/components/collections/list-action-row/list-action-row.css +14 -0
- package/dist/styles/components/collections/list-item/list-item.css +14 -0
- package/dist/styles/components/forms/select/select.css +1 -0
- package/dist/styles/components/forms/token-search-field/token-search-field.css +23 -5
- package/dist/styles/foundation.css +26 -0
- package/dist/styles/list-action-row.css +14 -0
- package/dist/styles/list-item.css +14 -0
- package/dist/styles/popup-menu.css +7 -0
- package/dist/styles/select.css +1 -0
- package/dist/styles/token-search-field.css +23 -5
- package/dist/styles/toolbar-control-group.css +11 -3
- package/dist/styles/toolbar-text.css +9 -0
- package/dist/styles/toolbar.css +19 -0
- package/dist/styles/webawesome.css +18 -0
- package/dist/wire-catalog.d.ts +1 -1
- package/dist/workbench.d.ts +1 -1
- package/dist/workbench.js +1 -1
- package/docs/catalog.md +7 -1
- package/docs/component-contract.md +10 -2
- package/docs/component-selection.md +20 -1
- package/docs/nav-stack.md +20 -6
- package/docs/webawesome-theme.md +7 -0
- package/llms.txt +14 -1
- package/package.json +1 -1
- package/dist/chunk-AYHC62OZ.js.map +0 -1
- package/dist/chunk-BU23Z5HZ.js.map +0 -1
|
@@ -3766,6 +3766,7 @@
|
|
|
3766
3766
|
"interaction-revealed trailing action",
|
|
3767
3767
|
"trailing overflow menu",
|
|
3768
3768
|
"before, after, or paired group divider",
|
|
3769
|
+
"position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge",
|
|
3769
3770
|
"draggable row with dragging and drop-before / drop-after insertion states"
|
|
3770
3771
|
],
|
|
3771
3772
|
"accessibility": [
|
|
@@ -3932,7 +3933,8 @@
|
|
|
3932
3933
|
"draggable row with dragging and drop-before / drop-after insertion states",
|
|
3933
3934
|
"description and status",
|
|
3934
3935
|
"busy while retaining content",
|
|
3935
|
-
"before, after, or paired group divider"
|
|
3936
|
+
"before, after, or paired group divider",
|
|
3937
|
+
"position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge"
|
|
3936
3938
|
],
|
|
3937
3939
|
"accessibility": [
|
|
3938
3940
|
"ListItem uses native button activation and pressed maps to aria-pressed; ListItemLink uses native anchor activation and external opens a new tab with safe rel and an announced default label. Both map selected to aria-current; disabled or loading links omit href and leave the tab order. rootAttributes cannot add role=menuitem or replace owned ARIA; trailing is dormant content and must not contain controls. A draggable row reorders by pointer drag or, with wireListReorder, Alt+Shift+ArrowUp/ArrowDown; a placeholder is never draggable."
|
|
@@ -49,6 +49,7 @@ Exact prop names and types: [`@kerfjs/ui/list-action-row`](../public-api-signatu
|
|
|
49
49
|
- interaction-revealed trailing action
|
|
50
50
|
- trailing overflow menu
|
|
51
51
|
- before, after, or paired group divider
|
|
52
|
+
- position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge
|
|
52
53
|
- draggable row with dragging and drop-before / drop-after insertion states
|
|
53
54
|
|
|
54
55
|
**CSS-value props** (typed builders from `@kerfjs/ui/css-values`; raw CSS strings are rejected):
|
|
@@ -51,6 +51,7 @@ Exact prop names and types: [`@kerfjs/ui/list-item`](../public-api-signatures-v1
|
|
|
51
51
|
- description and status
|
|
52
52
|
- busy while retaining content
|
|
53
53
|
- before, after, or paired group divider
|
|
54
|
+
- position-aware divided-list corners: flat wherever a divider line (this row's or a neighbor's) meets the edge
|
|
54
55
|
|
|
55
56
|
**CSS-value props** (typed builders from `@kerfjs/ui/css-values`; raw CSS strings are rejected):
|
|
56
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Public API signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.98` and `kerfjs@5.0.0-beta.98`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
4
|
|
|
5
5
|
## `@kerfjs/ui/css-values`
|
|
6
6
|
|
|
@@ -1515,7 +1515,7 @@ export { type ListDropPosition, type ListReorder, type ListReorderSource, type L
|
|
|
1515
1515
|
## `@kerfjs/ui/nav-stack`
|
|
1516
1516
|
|
|
1517
1517
|
```ts
|
|
1518
|
-
export { c as NavStack, N as NavStackProps, d as NavStackToolbarConfig, a as NavStackView, e as NavStackViewBottomToolbar, f as NavStackViewToolbar } from './nav-stack-
|
|
1518
|
+
export { c as NavStack, N as NavStackProps, d as NavStackToolbarConfig, a as NavStackView, e as NavStackViewBottomToolbar, f as NavStackViewToolbar } from './nav-stack-Cp3Y8kJ9.js';
|
|
1519
1519
|
import 'kerfjs';
|
|
1520
1520
|
import './semantic-content-BbzjvSu9.js';
|
|
1521
1521
|
import './list.js';
|
|
@@ -1559,7 +1559,7 @@ export { type WireNavStackOptions, wireNavStack };
|
|
|
1559
1559
|
```ts
|
|
1560
1560
|
import * as kerfjs from 'kerfjs';
|
|
1561
1561
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
1562
|
-
import { N as NavStackProps, a as NavStackView } from './nav-stack-
|
|
1562
|
+
import { N as NavStackProps, a as NavStackView } from './nav-stack-Cp3Y8kJ9.js';
|
|
1563
1563
|
import { ResizableRegionProps } from './resizable-region.js';
|
|
1564
1564
|
import './list.js';
|
|
1565
1565
|
import './extension-attributes-mu8MFUl0.js';
|
|
@@ -1782,7 +1782,7 @@ export { Pane, type PaneAppearance, type PaneChromeDividers, type PaneChromePlac
|
|
|
1782
1782
|
```ts
|
|
1783
1783
|
import { SafeHtml } from 'kerfjs';
|
|
1784
1784
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
1785
|
-
import { b as NavPane, N as NavStackProps } from './nav-stack-
|
|
1785
|
+
import { b as NavPane, N as NavStackProps } from './nav-stack-Cp3Y8kJ9.js';
|
|
1786
1786
|
import { ListConfig } from './list.js';
|
|
1787
1787
|
import { PaneConfig } from './pane.js';
|
|
1788
1788
|
import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
|
|
@@ -2662,7 +2662,7 @@ import './toolbar.js';
|
|
|
2662
2662
|
import './sides-BPSWde0A.js';
|
|
2663
2663
|
import './pane.js';
|
|
2664
2664
|
import './workbench.js';
|
|
2665
|
-
import './nav-stack-
|
|
2665
|
+
import './nav-stack-Cp3Y8kJ9.js';
|
|
2666
2666
|
import './list.js';
|
|
2667
2667
|
import './extension-attributes-mu8MFUl0.js';
|
|
2668
2668
|
import './flex-alignment-4ms8ZbV8.js';
|
|
@@ -2726,7 +2726,11 @@ interface CatalogExampleProps {
|
|
|
2726
2726
|
/** Native named-slot assignment when composed inside a web component. */
|
|
2727
2727
|
slot?: string;
|
|
2728
2728
|
}
|
|
2729
|
-
/**
|
|
2729
|
+
/**
|
|
2730
|
+
* A labeled catalog specimen with optional explanatory text and alignment. A
|
|
2731
|
+
* supplied `label` also names the rendered `section`, so each specimen is an
|
|
2732
|
+
* addressable region; an unlabeled example stays an ordinary grouping.
|
|
2733
|
+
*/
|
|
2730
2734
|
declare function CatalogExample({ label, note, align, viewport, compactFallback, rootAttributes, className, children, slot, }: CatalogExampleProps): SafeHtml;
|
|
2731
2735
|
|
|
2732
2736
|
type CatalogExampleStackRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
@@ -2735,9 +2739,19 @@ type CatalogExampleStackRootAttributes = Readonly<Record<`data-${string}`, strin
|
|
|
2735
2739
|
'data-catalog-example-label'?: never;
|
|
2736
2740
|
'data-catalog-example-note'?: never;
|
|
2737
2741
|
'data-align'?: never;
|
|
2742
|
+
'data-width'?: never;
|
|
2738
2743
|
}>;
|
|
2744
|
+
/**
|
|
2745
|
+
* How wide a stack may grow: `reading` (default) caps it at a 736px reading
|
|
2746
|
+
* measure for component specimens; `full` lets it span the stage for
|
|
2747
|
+
* application-width compositions such as boards, app shells, drawers, and
|
|
2748
|
+
* split views.
|
|
2749
|
+
*/
|
|
2750
|
+
type CatalogExampleStackWidth = 'reading' | 'full';
|
|
2739
2751
|
interface CatalogExampleStackProps {
|
|
2740
2752
|
label?: string;
|
|
2753
|
+
/** Maximum width of the stack (default `reading`). */
|
|
2754
|
+
width?: CatalogExampleStackWidth;
|
|
2741
2755
|
rootAttributes?: CatalogExampleStackRootAttributes;
|
|
2742
2756
|
className?: string;
|
|
2743
2757
|
children?: KerfUiContent;
|
|
@@ -2745,7 +2759,7 @@ interface CatalogExampleStackProps {
|
|
|
2745
2759
|
slot?: string;
|
|
2746
2760
|
}
|
|
2747
2761
|
/** A vertically stacked group of catalog examples. */
|
|
2748
|
-
declare function CatalogExampleStack({ label, rootAttributes, className, children, slot, }: CatalogExampleStackProps): kerfjs.SafeHtml;
|
|
2762
|
+
declare function CatalogExampleStack({ label, width, rootAttributes, className, children, slot, }: CatalogExampleStackProps): kerfjs.SafeHtml;
|
|
2749
2763
|
|
|
2750
2764
|
/**
|
|
2751
2765
|
* Browser helpers for UX Review region captures from a catalog. The local
|
|
@@ -2773,7 +2787,7 @@ declare function uxReviewCaptureUrl({ projectDirectory, title, context, }: UxRev
|
|
|
2773
2787
|
*/
|
|
2774
2788
|
declare function loadUxReviewProject(pageUrl: string | URL, fetchImpl?: typeof globalThis.fetch): Promise<string | null>;
|
|
2775
2789
|
|
|
2776
|
-
export { Catalog, CatalogExample, type CatalogExampleAlign, type CatalogExampleProps, CatalogExampleStack, type CatalogExampleStackProps, type CatalogExampleViewport, CatalogProps, UX_REVIEW_PROJECT_PATH, type UxReviewCapture, loadUxReviewProject, uxReviewCaptureUrl };
|
|
2790
|
+
export { Catalog, CatalogExample, type CatalogExampleAlign, type CatalogExampleProps, CatalogExampleStack, type CatalogExampleStackProps, type CatalogExampleStackWidth, type CatalogExampleViewport, CatalogProps, UX_REVIEW_PROJECT_PATH, type UxReviewCapture, loadUxReviewProject, uxReviewCaptureUrl };
|
|
2777
2791
|
```
|
|
2778
2792
|
|
|
2779
2793
|
## `@kerfjs/ui/catalog-resources`
|
|
@@ -2786,7 +2800,7 @@ import './semantic-content-BbzjvSu9.js';
|
|
|
2786
2800
|
import './sides-BPSWde0A.js';
|
|
2787
2801
|
import './pane.js';
|
|
2788
2802
|
import './workbench.js';
|
|
2789
|
-
import './nav-stack-
|
|
2803
|
+
import './nav-stack-Cp3Y8kJ9.js';
|
|
2790
2804
|
import './list.js';
|
|
2791
2805
|
import './extension-attributes-mu8MFUl0.js';
|
|
2792
2806
|
import './flex-alignment-4ms8ZbV8.js';
|
|
@@ -2840,7 +2854,7 @@ import './semantic-content-BbzjvSu9.js';
|
|
|
2840
2854
|
import './sides-BPSWde0A.js';
|
|
2841
2855
|
import './pane.js';
|
|
2842
2856
|
import './workbench.js';
|
|
2843
|
-
import './nav-stack-
|
|
2857
|
+
import './nav-stack-Cp3Y8kJ9.js';
|
|
2844
2858
|
import './list.js';
|
|
2845
2859
|
import './extension-attributes-mu8MFUl0.js';
|
|
2846
2860
|
import './flex-alignment-4ms8ZbV8.js';
|
package/ai/skill.md
CHANGED
|
@@ -306,7 +306,7 @@ Hard rules:
|
|
|
306
306
|
11. Use token-controlled `TokenSearchField` when free text and removable structured filters share one editor. Editable text stays DOM-owned between token changes; to replace the text programmatically (reseeding a persistent dialog's field on reopen, applying a saved search) change the field's `revision` along with `query` for an unmanaged field, or call `model.replace({ query, tokens })` for a model-managed field; never re-key a wrapper. The leading icon, first text line, clear action, and trailing slot share one fixed row when content wraps. For automatic parsing, chips, suggestions, and evaluation, use createTokenSearchModel with grammar rules, pass it as TokenSearchField.model, and register it in wireTokenSearchFields models; a rule's `suggest(input, state)` receives committed tokens so it can exclude selected values. Otherwise the app owns parsing and suggestions; call `readTokenSearchField()` on input, empty `textContent` on clear, use `placeTokenSearchCaret()` after explicit controlled focus changes, and call `wireTokenSearchFields()` once so Enter submits without inserting a line break and keyboard chip deletion restores focus plus the text-relative caret after controlled replacement. `clearIcon` replaces the clear action's glyph (its `clearLabel` still names it). Enable `collapsible` for an animated iconic closed state, standalone or inside `ToolbarControlGroup`; the field keeps text or tokens expanded, and `wireTokenSearchFields()` manages the transient expand/collapse/focus by default (activate to reveal + focus, Escape or empty blur to collapse). Bind the field's `expanded` to the returned handle's `expanded(id)` signal or adopt your own via `collapsible.signals`; opt a behavior out only when the app must own it. Do not hand-roll the open handler, the focusout collapse, a clear-button mousedown guard, or reopening after controlled clear or Select All deletion — the helper keeps the replacement editor open and focused. Clear and deletion restoration finish at the replacement mutation checkpoint before the next input task, so shortcut-letter typing cannot escape to the page and delayed animation frames cannot overwrite a later selection. Persist both query and tokens returned by the DOM read. For real-app adoption it also provides a focusout keep-open exception (`data-token-search-keep-open` regions or `collapsible.keepOpenOn(target)`, so a sibling suggestions/date/help surface does not collapse an empty field), opt-in atomic-chip keyboard (`keyboard`: Backspace/Delete remove the adjacent chip via `onRemoveToken`, ArrowRight moves the caret past a trailing chip), and an `onEdit({id, editor, event})` input callback (the `InputEvent` lets you gate on `inputType`/`data`) — reach for these instead of re-adding hand-rolled keydown/input handlers around the field.
|
|
307
307
|
An application helper can call `model.commit(value)` for the active `name:` prefix when it computes a valid value outside suggestions; invalid values and missing prefixes leave the query unchanged.
|
|
308
308
|
12. Demo work uses public production component subpaths and their browser-selected CSS. Focused demos and recipes have no local stylesheet, inline style, or styling-only class; use public components and `CatalogExample.viewport` for unavoidable specimen constraints (a recipe declares its frame through its exported `presentation`). When a recipe needs a capability no component offers, report the component gap instead of adding CSS. Use exactly three demo kinds: a `component` is one component with variants/states, a `composition` is a focused container of components commonly used together, and a `recipe` is the recommended production approach to a task. Organize catalog routes into product-important functional groups; within each group put all components before compositions, order each kind by importance with display-name alphabetical tie-breaking, and put recipes after every component/composition group. Show `Composition` as an entry tag instead of repeating the word in its name. Give every public visual component its own category-grouped catalog route; list themed third-party components under a clearly labeled collapsible ecosystem section, with a focused route for each. For the complete taxonomy, focused/composition decision, `CatalogExample` / `CatalogExampleStack` row/group nesting, specimen structure and metadata ownership, follow the single [Catalog demo authoring contract](../docs/catalog.md#catalog-demo-authoring-contract), discovered machine-readably through [`catalog-authoring.json`](./catalog-authoring.json). Never infer structure from private `kui-catalog-*` classes. Project each component's deterministic repository-relative demo source and existing documentation path so the detail can expose `View demo source` and `Read guidance` links without a runtime export; also derive first-party component implementation paths from their canonical browser imports, and label Web Awesome documentation as Kerf integration guidance. Declare direct `uses` relationships so `Used by` stays derivable, and theme shell chrome through the same semantic tokens as the stage instead of drawing a substitute. Enable `wireCatalog({ revealSelection: true })` for long desktop sidebars so controlled selections remain visible without moving focus; keep its default compact media guard unless compact scrolling is an explicit product behavior, and use `revealCatalogEntry` for an initial deep link.
|
|
309
|
-
13. The Web Awesome theme makes Tooltip and Popover arrowless by default. Keep that default unless a pointer materially clarifies the anchor; opt back in with `--wa-tooltip-arrow-size`, `--kui-wa-popover-arrow-size`, or a popover's public `--arrow-size`, and use `without-arrow` when local no-arrow intent should survive theme changes. Its non-field chrome uses `--kui-wa-control-inset` (8px controls/items), `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside Accordion, Card, Details, Callout, and Include), and `--kui-wa-container-inset` (16px Tab Panel content and framed disclosure regions). Plain Details use the 8px surface inset on the trigger and keep the body flush; plain Accordion items use it on both trigger and body. Outlined and sunken Details use the 16px container inset on the trigger and 8px on the body; framed Accordion items use 16px on both. Dialog maps its body to the 8px surface tier and its footer to the 16px container tier independently of `--spacing`. Override those tiers instead of restyling individual parts. Filled badges use each variant's quiet fill with normal text so their compact copy stays WCAG-AA readable; override the pair with `--kui-wa-badge-filled-background` / `--kui-wa-badge-filled-foreground`, not host selectors. When a dialog provides another dismissal affordance, put `hide-actions` on the `wa-dialog` host to hide its directly exported `header-actions` part; never chain `::part()` selectors through internal parts. Checkbox and Radio Group option regions, the Color Picker trigger, and Slider's complete interactive region receive the shared 8px logical inline outer inset because those controls have no bordered field shell. Known Date field captions and bordered text-like field hints align with values at the 9px border-plus-padding inset. OTP Input's label uses the same uppercase xs/650 treatment as other field labels, and both its label and hint use that 9px inset.
|
|
309
|
+
13. The Web Awesome theme makes Tooltip and Popover arrowless by default. Keep that default unless a pointer materially clarifies the anchor; opt back in with `--wa-tooltip-arrow-size`, `--kui-wa-popover-arrow-size`, or a popover's public `--arrow-size`, and use `without-arrow` when local no-arrow intent should survive theme changes. Its non-field chrome uses `--kui-wa-control-inset` (8px controls/items), `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside Accordion, Card, Details, Callout, and Include), and `--kui-wa-container-inset` (16px Tab Panel content and framed disclosure regions). Plain Details use the 8px surface inset on the trigger and keep the body flush; plain Accordion items use it on both trigger and body. Outlined and sunken Details use the 16px container inset on the trigger and 8px on the body; framed Accordion items use 16px on both. Dialog maps its body to the 8px surface tier and its footer to the 16px container tier independently of `--spacing`. Override those tiers instead of restyling individual parts. Filled badges use each variant's quiet fill with normal text so their compact copy stays WCAG-AA readable; override the pair with `--kui-wa-badge-filled-background` / `--kui-wa-badge-filled-foreground`, not host selectors. The theme draws a dialog's or drawer's built-in close control as the same 40px borderless circle a single `ToolbarControlGroup` button uses, so do not restyle it. When a dialog provides another dismissal affordance, put `hide-actions` on the `wa-dialog` host to hide its directly exported `header-actions` part; never chain `::part()` selectors through internal parts. Checkbox and Radio Group option regions, the Color Picker trigger, and Slider's complete interactive region receive the shared 8px logical inline outer inset because those controls have no bordered field shell. Known Date field captions and bordered text-like field hints align with values at the 9px border-plus-padding inset. OTP Input's label uses the same uppercase xs/650 treatment as other field labels, and both its label and hint use that 9px inset.
|
|
310
310
|
14. Treat the complete Web Awesome catalog as support coverage, not a recommendation list. Its UX sidebar marks superseded and exceptional entries `Discouraged`. Use `openAnchoredSurface` from `@kerfjs/ui/anchored-surface` for arbitrary interactive help or popup content beside a control, or `openAnchoredSurfaceAt` at pointer coordinates; pass an accessible label and let the app own content/actions. It stays interactive inside a native `<dialog>`, `wa-dialog`, or `wa-drawer` (no host markup needed for the Web Awesome ones) and closes with that dialog. Consider Popup only when its lower-level behavior is specifically needed. Prefer Kerf `Select` over direct Dropdown/Dropdown Item/Select/Option composition, `SegmentedControl` over Button Group, `TabBar` or `SegmentedControl` over Web Awesome Tabs, `LucideIcon` over Web Awesome Icon, and `ResizableRegion` over Split Panel. Use Tree/Tree Item, Animated Image, and Comparison only for a specific required behavior; avoid Zoomable Frame. Never render a `Discouraged` element directly in application, demo, or recipe markup; reach it only through the Kerf component that wraps it (`PopupMenu` renders `wa-dropdown`, `Select` renders `wa-select` / `wa-option`), and treat a Kerf component gap as a request to file, not a reason to drop to the raw element.
|
|
311
311
|
15. Build sidebars, main areas, inspectors, and dialogs by rendering `Pane` (`@kerfjs/ui/pane`): an unpadded `.kui-pane` root, an optional `header`, one scrolling `.kui-pane__content`, and an optional `footer`; pick landmarks with `element` / `contentElement`. Never write a component's anatomy classes (`kui-pane`, `kui-toolbar`, `kui-list-item`, …) onto your own element to recreate it — render the component (`KUI-L103`). Only the catalog's `placeableClasses` (the `.kui-content` / `.kui-scroll-owner` / `.kui-control-cluster` / `.kui-inline-metadata` layout utilities, `.kui-app-root`, and `.kui-content-item` geometry on a non-div carrier) belong on elements you write. Use `Row` instead of a hand-written flex-row wrapper, `List` instead of a hand-written flex-column wrapper, and `Grid` instead of repeated equal-track CSS when children need a fixed positive count of evenly distributed columns. `Row` defaults to left/full with an `xs` gap and no wrapping; Grid defaults to an `xs` gap and keeps each track at `minmax(0, 1fr)`; List retains full/top and zero-gap defaults. The app owns Grid's responsive column-count changes. When a Row, List, or Grid is the layout root of a definite-height parent (an app root or a fixed-height frame), pass `fill` so it takes that full height, and put route/test/recipe `data-*` markers in its `rootAttributes`; never wrap a layout in a frame `Pane` just for height or a root attribute, because its content slot becomes a scroll owner that never scrolls. Inside a flex layout use `flex`, not `fill`. Use `List` when rows or sections also need flex growth, one vertical scroll owner, or physical-edge dividers. `dividerSides`, `textInsets`, and `controlInsets` use canonical physical `t`/`r`/`b`/`l` order; text geometry wins where text and control selections overlap. `ListInsetText` and `ListInsetControl` inset all four sides by default and accept the same `sides` grammar for selective edges. A dialog body is generally a `List`: set `DialogSurface bodyInset="none"` when its list children own geometry, and wrap bare dialog prose in `ListInsetText` so it aligns with bordered siblings without a second inset. Add `.kui-content` for 24px major vertical separation and render each ordinary surface-like child as `ContentItem` (`@kerfjs/ui/content-item`) for a child-owned 8px inline margin, 1px border, 8px padding, and 12px radius. For a chat transcript, set `bubble="start"` (other participants) or `bubble="end"` with `appearance="brand-loud"` (the person's own messages) instead of app width, alignment, or color CSS; the item fits its message up to 80% of the row. Choose `frame="framed"` (neutral border in the always-reserved 1px, same geometry) only for a real distinction and `shape="pill"` for 22px; do not hand-write `<div class="kui-content-item">` or its modifier classes. There is no filled variant: a lowered filled surface is `SunkenPanel`. Do not pad pane shells, duplicate item geometry in wrappers, or create nested scroll owners. Align text to text and icons to icons across a pane — a title, a row label, and bare prose share the same text column (`ListInsetText` puts bare text on it); a border is decoration and never the alignment anchor, so a bordered surface extends to the pane gutter instead of being indented to line its border up with a heading's text.
|
|
312
312
|
15a. Use `Text` from `@kerfjs/ui/text` for ordinary headings, paragraphs, and inline secondary text outside toolbar title zones. Omit `variant` for the default `p`, pass `h1`–`h6` according to the document outline, or use `variant="span"` inside a row, label, or table cell; ordinary native attributes pass through. Express supporting, error, compact, or code text with the independent finite `tone="quiet|danger"`, `size="compact"`, and `font="monospace"` props instead of global utility classes or appearance-only heading choices. Block Text variants own a transparent 1px border and the standard item padding; `span` owns no box geometry. Keep toolbar identity/title content on `ToolbarText` and list-aligned bare prose on `ListInsetText`. `ToolbarText` below `xlarge` is intentionally quiet identity text in default tone; a normal-color subsection title is `Text` with an `h2`–`h6` variant (or `ListHeader` for a list or menu section), never a recolored `ToolbarText`. Use `controlMargins` with canonical physical Sides for an exterior 8px control gutter without a Row wrapper; avoid stacking parent insets, and remember spans retain native inline margin behavior.
|
|
@@ -326,7 +326,7 @@ For a rail view heading, use `presentation="title"` for the 36px bold,
|
|
|
326
326
|
flush-start trigger and adjacent caret. Set `focusRingInset` when an ancestor
|
|
327
327
|
clips focus painting; never restyle Select shadow parts from application CSS.
|
|
328
328
|
|
|
329
|
-
19. Compose `ValueTable` from typed `ValueTableRow` entries instead of handwritten `dt`/`dd` wrappers. Pass `icon` for the optional 24px leading visual; the row owns 8px of root-scaled top and bottom padding, the 8px iconless or 40px icon-bearing separator start, and the common 8px right inset. 20. Use the standard direct `Toolbar` composition for a panel, dialog, or page heading, not a private wrapper or custom heading row. Put an optional icon in a `ToolbarControlGroup`, the title directly in the leading zone as extra-large `ToolbarText`, and actions in a trailing group. Set `headingLevel` for page/section landmarks. Supporting copy stays below the toolbar as app-owned content. The app owns modal behavior, focus, dismissal, command policy, ids, and action handling. 21. Space with the official five-step scale, picked by how connected two elements are — not by eye. `0` `--kui-space-none` = no separation (one unit); `4px` `--kui-space-2xs` = very minor air on a connected cluster; `8px` `--kui-space-xs` = standard, between elements within a group; `16px` `--kui-space-m` = minor, between homogeneous groups; `24px` `--kui-space-l` = major, between heterogeneous groups (the `.kui-content` rhythm). The 8px-vs-24px distinction is inside-a-group vs between-major-differing-regions. `--kui-space-s` (12px) and `--kui-space-xl` (32px) are off-scale exceptions. For `Row.gap`, `Grid.gap`, or `List.gap`, pass a finite shorthand such as `gap="xs"` or `gap="m"`; use `Spacer` for one intentional typed empty width/height or a flexible main-axis gap. When one token is insufficient, import typed builders from the CSS-free `@kerfjs/ui/css-values` subpath. Preserve property grammar: lengths for gap/Spacer/Skeleton geometry, `flex()` for Row/Grid/List flex, and a foreground color for choice icons: `uiColor()` with a `*-on-*` or text token (`success-on-quiet`, `text-quiet`) or `foregroundColorVar()`. Fill tokens (`*-fill-*`) are backgrounds, not foregrounds, and `SelectChoice.color` rejects them. Never cast between brands or emit raw row `style` declarations. `plus` is not standalone and must be wrapped in `calc`; `remify()` remains source-CSS syntax and is never a runtime prop value. See `docs/layout.md` "Spacing scale". 22. Pick a whole-screen layout from the opt-in, tree-shakeable subpaths by data + interaction + device, and derive responsiveness from `@kerfjs/ui/device-class`'s `deviceClass()` (`compact` = handset or portrait tablet = one pane at a time). Simple/flat → `NavStack` with one entry (single pane), plus `TabNavigator` (`@kerfjs/ui/tab-navigator`, iOS bottom tabs, each tab its own `NavStack`) for 2–5 co-equal sections on `compact`; show an unread count on a tab with its `badge` (a number or short string, rendered as the top-trailing danger `Badge` on the icon) plus a localized `badgeLabel` ("3 unread", folded into the tab's name as "Inbox, 3 unread"), never by concatenating the count into `label` or restyling the badge; for new content without a count pass `badge: true` (the text-free dot) with its required `badgeLabel` ("New activity"). Drill-down → `NavStack` (`@kerfjs/ui/nav-stack`), upgrading to `SplitView` (`@kerfjs/ui/split-view`, list-detail) once both panes fit (`atLeast('tablet')` landscape); `SplitView` collapses to a `NavStack` on `compact`. Keep each stack's ordered views controlled; put view-specific bottom chrome on `NavStackView.bottomToolbar` (or use the component-level persistent fallback), then call `wireNavStack` so content slides while the active view's top and bottom chrome cross-fade and focus moves into the new top view/restores on pop. Mark a preferred initial heading or control with `data-nav-focus` when DOM order is not sufficient. The stack's top chrome is a real `Toolbar`: put a view's title and groups on `NavStackView.toolbar` (`title`, `leading`, `center`, `trailing`), where its Toolbar configuration overrides stack-wide `toolbarConfig` defaults; configure `backIcon` / `backText` through the stack, never with CSS. Each view and the stack fallback use a structured `bottomToolbar` with an accessible `label`; a view can also provide `header` / `footer`, `headerList` / `footerList`, and `pane` configuration, which render a Pane around that view's scrolling content. `SplitView` forwards both of its inner components: `resizable` takes the list `ResizableRegion`'s `separator`, `handleIcon`, `contentOverflow`, and collapse props (`collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, `restorePosition`), and `compactStack` takes the compact stack's `toolbarConfig`, `backIcon`, `backText`, `hideToolbar`, `bottomToolbar`, plus `list` / `detail` view toolbars (structured `toolbar` and `bottomToolbar`). Complex tool with peripheral panels → `Workbench` (`@kerfjs/ui/workbench`, collapsible rails + drawer) `atLeast('desktop')`, degrading to `NavStack`/overlays below. Workbench panels are fixed-size unless a panel opts in with `resizable` (`true` or `{ min, max }`); then render `size={sizeSignal.value}` and call `wireWorkbench(root, { id, panels: { leftRail: { size: sizeSignal, storageKey? } }, deviceClass })` from `@kerfjs/ui/wire-workbench` for pointer drags, arrow/Shift+arrow/Home/End on the separator, persistence, and no resizing on `compact` classes. Inline rails, fixed or resizable, leave the work area `mainMinSize` px of width (a `Workbench` prop, default 320, `0` off), and an inline bottom drawer leaves it `mainMinHeight` px of height (default 120, `0` off): resizable panels stop growing there, rails shrink in proportion when the Workbench narrows and the drawer when it gets shorter, so do not add your own main-area `min-width` / `min-height`. Rails present as overlays below the `narrow` Workbench container breakpoint (704px) by default — `responsiveOverlayAt: "compact"` moves that to 448px and `"never"` keeps a rail inline — and a bottom drawer opts in the same way; do not derive `presentation` from `deviceClass`, and overlays never resize. At compact widths an overlay rail fills the Workbench less a 44px dismiss strip (`--kui-workbench-overlay-dismiss-margin`) on the side away from its edge; `compactOverlay: "full"` makes one rail fill it. Pass each such panel's `collapsed` signal to `wireWorkbench` too (`panels: { leftRail: { collapsed: navCollapsed } }`, `size` optional) so the overlay is transient like `wireSidebar`'s compact overlay: it collapses when the breakpoint begins to apply (the inline state returns when it ends), takes focus on its first control and keeps Tab inside it while open, and closes on Escape or an outside press with focus returned to its toggle (give each toggle `aria-controls` naming its panel's derived id, `<workbench id>-left-rail` / `-right-rail` / `-bottom-drawer`, so a panel open at wire-up has a focus target too); opening one overlay closes the other open overlays, so they never cover each other's controls; do not hand-roll those listeners (`dismissOverlays: false` opts out of all of it, `exclusiveOverlays: false` of exclusivity only). Collapse stays the app's `collapsed` flag and keeps the size, so an expanded panel returns at its last size. Let the Workbench compose panel toolbars: give each panel `toolbar: { label, title?, leading?, center?, trailing?, toggle: { action, name, showLabel?, hideLabel? } }` and the work area `mainToolbar` (and `mainBottomToolbar` for a drawer). Each of these toolbars takes the `Toolbar`'s configuration (`ToolbarConfig`: `dividerSides`, `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); configure a composed toolbar through those props (for example `dividerSides: ""` to drop its divider), never with CSS. Configure the composed panes and chrome lists the same way: a panel's `pane` (and `CollapsiblePanel`'s `pane`) and the Workbench's `mainPane` take `PaneConfig` (`contentElement`, `contentLabel`, `separators`, `safeAreaEdges` — for example `{ contentElement: "nav", contentLabel: "Files" }` for a navigator rail), and `mainHeaderList` / `mainFooterList` take `ListConfig` (`gap`, `hAlign`, `vAlign`, `dividerSides`, `textInsets`, `controlInsets`). Open, a panel's toolbar places groups in its leading, center, and trailing zones, with the toggle last; mark a ToolbarControlGroup relocateOnCollapse to keep it available when closed (pass marked groups directly or in arrays rather than JSX fragments); closed, marked groups follow zone order into the work area before the toggle — a left rail's lead `mainToolbar`, a right rail's end it, a drawer's trail `mainBottomToolbar` or float in a corner `FloatingToolbar` — and panel-only groups stay behind. A control sits near where its effect appears: a collapsed drawer's restore belongs in the bottom toolbar or a `FloatingToolbar` beside the drawer, not in a distant top toolbar. Do not hand-place panel toggles in the work-area toolbar or render a second copy, and handle only the toggle's `data-action`. A collapsed panel renders `inert` and `aria-hidden` by itself, on the rail/drawer and its content (its `restoreControl` stays outside and reachable), so do not add your own `tabindex`, `aria-hidden`, or `inert` to hide it. These are declarative (the app owns the stack/selection/collapsed/active state as signals) with disposer-returning `wire…` helpers; each stays out of the barrel, and its CSS-aware browser import loads the layout's CSS plus that of every component it renders (`Pane`, `Toolbar`, `List`, …), so do not hand-import `pane.css` or the other internal stylesheets; the companion `.css` subpath is only for pipelines without the `browser` condition. For a standalone collapsible rail or bottom drawer outside a full shell, use `CollapsiblePanel` + `CollapsiblePanelToggle` (`@kerfjs/ui/collapsible-panel`) with `wireSidebar` (`@kerfjs/ui/wire-sidebar`): the standard collapse animation and per-side icon convention (`PanelLeft*`/`PanelRight*`/`PanelBottom*`) plus toggle, focus, compact overlay, and persistence semantics. Give a standalone panel the same `toolbar` roles and render `CollapsiblePanelRelocated` in your work-area toolbar (first in leading for a left rail, last in trailing for a right rail, a bottom toolbar or a `FloatingToolbar` restoreControl for a drawer) instead of hand-placing a second toggle. A collapsed `CollapsiblePanel`, `ResizableRegion`, or Workbench panel renders `inert` and `aria-hidden` by itself, so do not hide collapsed content yourself either. Likewise an open side overlay (a Workbench rail overlay, a `wireSidebar` compact overlay, an overlay `CollapsiblePanel` or horizontal `ResizableRegion`) hides the covered work area's `FloatingToolbar`s and restore corners by itself until it closes, so do not hide them from overlay state. A compact overlay opens only on a user action: wire-up on a compact device and a wide-to-compact crossing collapse every panel, and a wide crossing restores the inline state. Seed the signal with `signal(device.value.compact)` and pass the panel's `inlineCollapsed` default so the first compact render has no overlay. Dialogs pick the same inner layout, then present per device class (full-screen modal on `compact`, inline on desktop). A list-detail dialog is a Workbench-shaped layout on roomy devices: a full-height list sidebar and a full-height main column, each a `Pane` with its own top `Toolbar`; the main column holds the primary xl title, the close control (`data-dialog="close"` in a `without-header` Web Awesome dialog), and the record actions, never a header spanning both columns. A top-level percentage-height shell needs a definite containing height: opt into `@kerfjs/ui/document.css` and put `.kui-app-root` on the one direct mount container, or provide equivalent application-owned geometry. The global baseline is deliberately absent from `styles.css` and component imports. See `docs/app-layouts.md`, `docs/document-baseline.md`, and `docs/collapsible-panel.md`. 23. Layouts and `Pane` are safe-area aware without configuration: backgrounds, separators, and dividers paint through a device's unsafe areas (a collapsible rail or drawer grows by the inset it docks to), content is padded only on the sides a region actually reaches, and block insets are scroll padding inside the scroller so first/last content can always be scrolled clear. Interior edges get nothing, and a collapsed rail hands its edge back to the center. Never add your own `env(safe-area-inset-*)` padding around a kerf layout or pane — that double-insets. In an app-owned arrangement of panes, pass `Pane.safeAreaEdges` (the sides that pane reaches; `[]` opts out); give an app bar or bottom bar that sits at a screen edge outside a Pane header or footer `Toolbar.safeAreaEdges` for the sides it reaches (for example `['block-start', 'inline-start', 'inline-end']`); the Workbench `mainToolbar` / `mainBottomToolbar` and panel `toolbar` configurations forward the same `safeAreaEdges` to their `Toolbar`. Do not set the internal `--kui-edge-inset-*` context yourself. The device insets are `--kui-safe-area-*` (defaulting to `env()`), overridable on `:root`. See `docs/app-layouts.md` "Safe areas".
|
|
329
|
+
19. Compose `ValueTable` from typed `ValueTableRow` entries instead of handwritten `dt`/`dd` wrappers. Pass `icon` for the optional 24px leading visual; the row owns 8px of root-scaled top and bottom padding, the 8px iconless or 40px icon-bearing separator start, and the common 8px right inset. 20. Use the standard direct `Toolbar` composition for a panel, dialog, or page heading, not a private wrapper or custom heading row. Put an optional icon in a `ToolbarControlGroup`, the title directly in the leading zone as extra-large `ToolbarText`, and actions in a trailing group. Set `headingLevel` for page/section landmarks. Supporting copy stays below the toolbar as app-owned content. The app owns modal behavior, focus, dismissal, command policy, ids, and action handling. 21. Space with the official five-step scale, picked by how connected two elements are — not by eye. `0` `--kui-space-none` = no separation (one unit); `4px` `--kui-space-2xs` = very minor air on a connected cluster; `8px` `--kui-space-xs` = standard, between elements within a group; `16px` `--kui-space-m` = minor, between homogeneous groups; `24px` `--kui-space-l` = major, between heterogeneous groups (the `.kui-content` rhythm). The 8px-vs-24px distinction is inside-a-group vs between-major-differing-regions. `--kui-space-s` (12px) and `--kui-space-xl` (32px) are off-scale exceptions. For `Row.gap`, `Grid.gap`, or `List.gap`, pass a finite shorthand such as `gap="xs"` or `gap="m"`; use `Spacer` for one intentional typed empty width/height or a flexible main-axis gap. When one token is insufficient, import typed builders from the CSS-free `@kerfjs/ui/css-values` subpath. Preserve property grammar: lengths for gap/Spacer/Skeleton geometry, `flex()` for Row/Grid/List flex, and a foreground color for choice icons: `uiColor()` with a `*-on-*` or text token (`success-on-quiet`, `text-quiet`) or `foregroundColorVar()`. Fill tokens (`*-fill-*`) are backgrounds, not foregrounds, and `SelectChoice.color` rejects them. Never cast between brands or emit raw row `style` declarations. `plus` is not standalone and must be wrapped in `calc`; `remify()` remains source-CSS syntax and is never a runtime prop value. See `docs/layout.md` "Spacing scale". 22. Pick a whole-screen layout from the opt-in, tree-shakeable subpaths by data + interaction + device, and derive responsiveness from `@kerfjs/ui/device-class`'s `deviceClass()` (`compact` = handset or portrait tablet = one pane at a time). Simple/flat → `NavStack` with one entry (single pane), plus `TabNavigator` (`@kerfjs/ui/tab-navigator`, iOS bottom tabs, each tab its own `NavStack`) for 2–5 co-equal sections on `compact`; show an unread count on a tab with its `badge` (a number or short string, rendered as the top-trailing danger `Badge` on the icon) plus a localized `badgeLabel` ("3 unread", folded into the tab's name as "Inbox, 3 unread"), never by concatenating the count into `label` or restyling the badge; for new content without a count pass `badge: true` (the text-free dot) with its required `badgeLabel` ("New activity"). Drill-down → `NavStack` (`@kerfjs/ui/nav-stack`), upgrading to `SplitView` (`@kerfjs/ui/split-view`, list-detail) once both panes fit (`atLeast('tablet')` landscape); `SplitView` collapses to a `NavStack` on `compact`. Keep each stack's ordered views controlled; put view-specific bottom chrome on `NavStackView.bottomToolbar` (or use the component-level persistent fallback), then call `wireNavStack` so content slides while the active view's top and bottom chrome cross-fade and focus moves into the new top view/restores on pop. Mark a preferred initial heading or control with `data-nav-focus` when DOM order is not sufficient. The stack's top chrome is a real `Toolbar`: put a view's title and groups on `NavStackView.toolbar` (`title`, `leading`, `center`, `trailing`), where its Toolbar configuration overrides stack-wide `toolbarConfig` defaults; the title leads, left-aligned and xlarge, at the root and steps down to large and centers (truncating before any control) once the back control shows, unless the view supplies `center` — do not restyle it to align; configure `backIcon` / `backText` through the stack, never with CSS. Each view and the stack fallback use a structured `bottomToolbar` with an accessible `label`; a view can also provide `header` / `footer`, `headerList` / `footerList`, and `pane` configuration, which render a Pane around that view's scrolling content. `SplitView` forwards both of its inner components: `resizable` takes the list `ResizableRegion`'s `separator`, `handleIcon`, `contentOverflow`, and collapse props (`collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, `restorePosition`), and `compactStack` takes the compact stack's `toolbarConfig`, `backIcon`, `backText`, `hideToolbar`, `bottomToolbar`, plus `list` / `detail` view toolbars (structured `toolbar` and `bottomToolbar`). Complex tool with peripheral panels → `Workbench` (`@kerfjs/ui/workbench`, collapsible rails + drawer) `atLeast('desktop')`, degrading to `NavStack`/overlays below. Workbench panels are fixed-size unless a panel opts in with `resizable` (`true` or `{ min, max }`); then render `size={sizeSignal.value}` and call `wireWorkbench(root, { id, panels: { leftRail: { size: sizeSignal, storageKey? } }, deviceClass })` from `@kerfjs/ui/wire-workbench` for pointer drags, arrow/Shift+arrow/Home/End on the separator, persistence, and no resizing on `compact` classes. Inline rails, fixed or resizable, leave the work area `mainMinSize` px of width (a `Workbench` prop, default 320, `0` off), and an inline bottom drawer leaves it `mainMinHeight` px of height (default 120, `0` off): resizable panels stop growing there, rails shrink in proportion when the Workbench narrows and the drawer when it gets shorter, so do not add your own main-area `min-width` / `min-height`. Rails present as overlays below the `narrow` Workbench container breakpoint (704px) by default — `responsiveOverlayAt: "compact"` moves that to 448px and `"never"` keeps a rail inline — and a bottom drawer opts in the same way; do not derive `presentation` from `deviceClass`, and overlays never resize. At compact widths an overlay rail fills the Workbench less a 44px dismiss strip (`--kui-workbench-overlay-dismiss-margin`) on the side away from its edge; `compactOverlay: "full"` makes one rail fill it. Pass each such panel's `collapsed` signal to `wireWorkbench` too (`panels: { leftRail: { collapsed: navCollapsed } }`, `size` optional) so the overlay is transient like `wireSidebar`'s compact overlay: it collapses when the breakpoint begins to apply (the inline state returns when it ends), takes focus on its first control and keeps Tab inside it while open, and closes on Escape or an outside press with focus returned to its toggle (give each toggle `aria-controls` naming its panel's derived id, `<workbench id>-left-rail` / `-right-rail` / `-bottom-drawer`, so a panel open at wire-up has a focus target too); opening one overlay closes the other open overlays, so they never cover each other's controls; do not hand-roll those listeners (`dismissOverlays: false` opts out of all of it, `exclusiveOverlays: false` of exclusivity only). Collapse stays the app's `collapsed` flag and keeps the size, so an expanded panel returns at its last size. Let the Workbench compose panel toolbars: give each panel `toolbar: { label, title?, leading?, center?, trailing?, toggle: { action, name, showLabel?, hideLabel? } }` and the work area `mainToolbar` (and `mainBottomToolbar` for a drawer). Each of these toolbars takes the `Toolbar`'s configuration (`ToolbarConfig`: `dividerSides`, `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); configure a composed toolbar through those props (for example `dividerSides: ""` to drop its divider), never with CSS. Configure the composed panes and chrome lists the same way: a panel's `pane` (and `CollapsiblePanel`'s `pane`) and the Workbench's `mainPane` take `PaneConfig` (`contentElement`, `contentLabel`, `separators`, `safeAreaEdges` — for example `{ contentElement: "nav", contentLabel: "Files" }` for a navigator rail), and `mainHeaderList` / `mainFooterList` take `ListConfig` (`gap`, `hAlign`, `vAlign`, `dividerSides`, `textInsets`, `controlInsets`). Open, a panel's toolbar places groups in its leading, center, and trailing zones, with the toggle last; mark a ToolbarControlGroup relocateOnCollapse to keep it available when closed (pass marked groups directly or in arrays rather than JSX fragments); closed, marked groups follow zone order into the work area before the toggle — a left rail's lead `mainToolbar`, a right rail's end it, a drawer's trail `mainBottomToolbar` or float in a corner `FloatingToolbar` — and panel-only groups stay behind. A control sits near where its effect appears: a collapsed drawer's restore belongs in the bottom toolbar or a `FloatingToolbar` beside the drawer, not in a distant top toolbar. Do not hand-place panel toggles in the work-area toolbar or render a second copy, and handle only the toggle's `data-action`. A collapsed panel renders `inert` and `aria-hidden` by itself, on the rail/drawer and its content (its `restoreControl` stays outside and reachable), so do not add your own `tabindex`, `aria-hidden`, or `inert` to hide it. These are declarative (the app owns the stack/selection/collapsed/active state as signals) with disposer-returning `wire…` helpers; each stays out of the barrel, and its CSS-aware browser import loads the layout's CSS plus that of every component it renders (`Pane`, `Toolbar`, `List`, …), so do not hand-import `pane.css` or the other internal stylesheets; the companion `.css` subpath is only for pipelines without the `browser` condition. For a standalone collapsible rail or bottom drawer outside a full shell, use `CollapsiblePanel` + `CollapsiblePanelToggle` (`@kerfjs/ui/collapsible-panel`) with `wireSidebar` (`@kerfjs/ui/wire-sidebar`): the standard collapse animation and per-side icon convention (`PanelLeft*`/`PanelRight*`/`PanelBottom*`) plus toggle, focus, compact overlay, and persistence semantics. Give a standalone panel the same `toolbar` roles and render `CollapsiblePanelRelocated` in your work-area toolbar (first in leading for a left rail, last in trailing for a right rail, a bottom toolbar or a `FloatingToolbar` restoreControl for a drawer) instead of hand-placing a second toggle. A collapsed `CollapsiblePanel`, `ResizableRegion`, or Workbench panel renders `inert` and `aria-hidden` by itself, so do not hide collapsed content yourself either. Likewise an open side overlay (a Workbench rail overlay, a `wireSidebar` compact overlay, an overlay `CollapsiblePanel` or horizontal `ResizableRegion`) hides the covered work area's `FloatingToolbar`s and restore corners by itself until it closes, so do not hide them from overlay state. A compact overlay opens only on a user action: wire-up on a compact device and a wide-to-compact crossing collapse every panel, and a wide crossing restores the inline state. Seed the signal with `signal(device.value.compact)` and pass the panel's `inlineCollapsed` default so the first compact render has no overlay. Dialogs pick the same inner layout, then present per device class (full-screen modal on `compact`, inline on desktop). A list-detail dialog is a Workbench-shaped layout on roomy devices: a full-height list sidebar and a full-height main column, each a `Pane` with its own top `Toolbar`; the main column holds the primary xl title, the close control (`data-dialog="close"` in a `without-header` Web Awesome dialog), and the record actions, never a header spanning both columns. A top-level percentage-height shell needs a definite containing height: opt into `@kerfjs/ui/document.css` and put `.kui-app-root` on the one direct mount container, or provide equivalent application-owned geometry. The global baseline is deliberately absent from `styles.css` and component imports. See `docs/app-layouts.md`, `docs/document-baseline.md`, and `docs/collapsible-panel.md`. 23. Layouts and `Pane` are safe-area aware without configuration: backgrounds, separators, and dividers paint through a device's unsafe areas (a collapsible rail or drawer grows by the inset it docks to), content is padded only on the sides a region actually reaches, and block insets are scroll padding inside the scroller so first/last content can always be scrolled clear. Interior edges get nothing, and a collapsed rail hands its edge back to the center. Never add your own `env(safe-area-inset-*)` padding around a kerf layout or pane — that double-insets. In an app-owned arrangement of panes, pass `Pane.safeAreaEdges` (the sides that pane reaches; `[]` opts out); give an app bar or bottom bar that sits at a screen edge outside a Pane header or footer `Toolbar.safeAreaEdges` for the sides it reaches (for example `['block-start', 'inline-start', 'inline-end']`); the Workbench `mainToolbar` / `mainBottomToolbar` and panel `toolbar` configurations forward the same `safeAreaEdges` to their `Toolbar`. Do not set the internal `--kui-edge-inset-*` context yourself. The device insets are `--kui-safe-area-*` (defaulting to `env()`), overridable on `:root`. See `docs/app-layouts.md` "Safe areas".
|
|
330
330
|
|
|
331
331
|
For application tabs, `AppTab presentation="icon-only"` retains its accessible `name`, `labelMaxWidth` truncates the visible name, and `attention` colors it through `--kui-app-tab-attention-color`. Configure TabBar strip geometry through public `--kui-tab-bar-strip-*` tokens.
|
|
332
332
|
|
|
@@ -338,7 +338,7 @@ Set `pinned` on the first `AppTab` when it must stay visible while peers scroll.
|
|
|
338
338
|
|
|
339
339
|
Use `--kui-resizable-region-background` for a region surface and `contentOverflow="visible"` while its anchored popup needs to escape. Choose a top or bottom `restorePosition`, typed `restoreInset`, or `restorePlacement="inline"` for its collapsed restore control. `FloatingToolbar placement="inline"` stays in normal flow; its per-edge inset tokens and `safeAreaInsets` configure floating placement.
|
|
340
340
|
|
|
341
|
-
Use `ListItem density="spacious"` for larger option rows, `multiline` plus `multilineIconAlign="center"` when its icon should center on wrapped copy, `divider` for row separators, and `state="drag-target"` for the drop target treatment. For a reorderable list, set `draggable` and `itemId` on each `ListItem`, `ListItemLink`, or `ListActionRow` and call `wireListReorder(root, { onReorder })` from `@kerfjs/ui/wire-list-reorder` once: it dims the dragged rows, draws the brand insertion line on the hovered row's `before`/`after` edge, supports Alt+Shift+ArrowUp/ArrowDown, and reports `{ listId, sourceIds, target: { id, position }, source }` (a selected or pressed row drags every selected row of its `List`; `data-list-id` on the `List` names it). Apply it with `reorderListItems` and re-render; the `dragging` and `dropPosition` props render the same states from app-owned drag state. Never hand-style drag rows. Public `--kui-list-item-*` tokens adjust row, icon, label, and trailing geometry and color; ListHeader height, title padding, and border tokens adjust section density.
|
|
341
|
+
Use `ListItem density="spacious"` for larger option rows, `multiline` plus `multilineIconAlign="center"` when its icon should center on wrapped copy, `divider` for row separators (for lines only between rows, every row but the last takes `divider="after"` and the last `"none"`; corners are flat wherever a divider line meets them, so the group rounds only its outer corners), and `state="drag-target"` for the drop target treatment. For a reorderable list, set `draggable` and `itemId` on each `ListItem`, `ListItemLink`, or `ListActionRow` and call `wireListReorder(root, { onReorder })` from `@kerfjs/ui/wire-list-reorder` once: it dims the dragged rows, draws the brand insertion line on the hovered row's `before`/`after` edge, supports Alt+Shift+ArrowUp/ArrowDown, and reports `{ listId, sourceIds, target: { id, position }, source }` (a selected or pressed row drags every selected row of its `List`; `data-list-id` on the `List` names it). Apply it with `reorderListItems` and re-render; the `dragging` and `dropPosition` props render the same states from app-owned drag state. Never hand-style drag rows. Public `--kui-list-item-*` tokens adjust row, icon, label, and trailing geometry and color; ListHeader height, title padding, and border tokens adjust section density.
|
|
342
342
|
|
|
343
343
|
Set `ListHeader.size` to `xs`, `sm`, `m`, `l`, or `xl` for label scale. The default `sm` remains the small uppercase style shared with `FieldLabel`; `xs` is 2xs and capitalized, while `m`/`l`/`xl` match themed h5/h4/h3 typography. Choose `headingLevel` separately from the document outline.
|
|
344
344
|
|
|
@@ -429,7 +429,7 @@ For a tab scene with drill-down, place a `NavStack` directly in `TabNavigatorTab
|
|
|
429
429
|
Use `Pane.deepInset` (also in `PaneConfig`) or `TabNavigatorTab.deepInset` for a plain scene when its scrolling content needs an extra 8px on all four sides, giving ordinary items a 16px inline gutter. The extra 8px is applied to the scroll surface, while nested Row/List/Grid item margins stay 8px. When a tab scene is a sole Pane or NavStack, configure deep inset on that child's Pane; the tab bar and top toolbar stay full width.
|
|
430
430
|
An edge-to-edge table or similar Pane child can read `--kui-pane-content-inset-inline-start` and `--kui-pane-content-inset-inline-end`: negate them for the child's logical margins, then add them to the child's text padding. The inherited values include routed safe areas and `deepInset`; keep the child in the Pane's single scroll slot. See `docs/app-layouts.md` for the CSS recipe.
|
|
431
431
|
|
|
432
|
-
Expanded search groups accept `expandedOverflow="visible"` to anchor app-owned suggestion/date/help surfaces below their relative root; collapsed/default groups retain existing clipping. Apps own surface placement/dismissal and use `data-token-search-keep-open` or `collapsible.keepOpenOn` for focus.
|
|
432
|
+
Do not grow a collapsible search past the room beside its sibling groups: when it does not fit, the siblings wrap onto a new row while it opens. Size the expanded search to fit (`--kui-token-search-expanded-width`, or `sizing="grow"` with a fitting `growBasis`), and if a useful search still cannot fit, set aside the other controls while it is open, with `visibility="yield-to-expanded-sibling"` on those groups (they leave a 480px-or-narrower toolbar while a sibling is expanded) or behind a "…" `PopupMenu` overflow group; the app chooses which controls yield. Expanded search groups accept `expandedOverflow="visible"` to anchor app-owned suggestion/date/help surfaces below their relative root; collapsed/default groups retain existing clipping. Apps own surface placement/dismissal and use `data-token-search-keep-open` or `collapsible.keepOpenOn` for focus.
|
|
433
433
|
|
|
434
434
|
`ToolbarText` and `ToolbarControlGroup` accept typed `hideBelow`/`showBelow`
|
|
435
435
|
lengths (for example `px(416)`). Wire `wireToolbarVisibility(root)` from
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web Awesome JSX signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from the emitted `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from the emitted `@kerfjs/ui@5.0.0-beta.98` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { KerfCustomElement } from 'kerfjs/jsx-runtime';
|
|
@@ -5,7 +5,7 @@ import './semantic-content-BbzjvSu9.js';
|
|
|
5
5
|
import './sides-BPSWde0A.js';
|
|
6
6
|
import './pane.js';
|
|
7
7
|
import './workbench.js';
|
|
8
|
-
import './nav-stack-
|
|
8
|
+
import './nav-stack-Cp3Y8kJ9.js';
|
|
9
9
|
import './list.js';
|
|
10
10
|
import './extension-attributes-mu8MFUl0.js';
|
|
11
11
|
import './flex-alignment-4ms8ZbV8.js';
|
package/dist/catalog.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import './toolbar.js';
|
|
|
7
7
|
import './sides-BPSWde0A.js';
|
|
8
8
|
import './pane.js';
|
|
9
9
|
import './workbench.js';
|
|
10
|
-
import './nav-stack-
|
|
10
|
+
import './nav-stack-Cp3Y8kJ9.js';
|
|
11
11
|
import './list.js';
|
|
12
12
|
import './extension-attributes-mu8MFUl0.js';
|
|
13
13
|
import './flex-alignment-4ms8ZbV8.js';
|
|
@@ -71,7 +71,11 @@ interface CatalogExampleProps {
|
|
|
71
71
|
/** Native named-slot assignment when composed inside a web component. */
|
|
72
72
|
slot?: string;
|
|
73
73
|
}
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* A labeled catalog specimen with optional explanatory text and alignment. A
|
|
76
|
+
* supplied `label` also names the rendered `section`, so each specimen is an
|
|
77
|
+
* addressable region; an unlabeled example stays an ordinary grouping.
|
|
78
|
+
*/
|
|
75
79
|
declare function CatalogExample({ label, note, align, viewport, compactFallback, rootAttributes, className, children, slot, }: CatalogExampleProps): SafeHtml;
|
|
76
80
|
|
|
77
81
|
type CatalogExampleStackRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
@@ -80,9 +84,19 @@ type CatalogExampleStackRootAttributes = Readonly<Record<`data-${string}`, strin
|
|
|
80
84
|
'data-catalog-example-label'?: never;
|
|
81
85
|
'data-catalog-example-note'?: never;
|
|
82
86
|
'data-align'?: never;
|
|
87
|
+
'data-width'?: never;
|
|
83
88
|
}>;
|
|
89
|
+
/**
|
|
90
|
+
* How wide a stack may grow: `reading` (default) caps it at a 736px reading
|
|
91
|
+
* measure for component specimens; `full` lets it span the stage for
|
|
92
|
+
* application-width compositions such as boards, app shells, drawers, and
|
|
93
|
+
* split views.
|
|
94
|
+
*/
|
|
95
|
+
type CatalogExampleStackWidth = 'reading' | 'full';
|
|
84
96
|
interface CatalogExampleStackProps {
|
|
85
97
|
label?: string;
|
|
98
|
+
/** Maximum width of the stack (default `reading`). */
|
|
99
|
+
width?: CatalogExampleStackWidth;
|
|
86
100
|
rootAttributes?: CatalogExampleStackRootAttributes;
|
|
87
101
|
className?: string;
|
|
88
102
|
children?: KerfUiContent;
|
|
@@ -90,7 +104,7 @@ interface CatalogExampleStackProps {
|
|
|
90
104
|
slot?: string;
|
|
91
105
|
}
|
|
92
106
|
/** A vertically stacked group of catalog examples. */
|
|
93
|
-
declare function CatalogExampleStack({ label, rootAttributes, className, children, slot, }: CatalogExampleStackProps): kerfjs.SafeHtml;
|
|
107
|
+
declare function CatalogExampleStack({ label, width, rootAttributes, className, children, slot, }: CatalogExampleStackProps): kerfjs.SafeHtml;
|
|
94
108
|
|
|
95
109
|
/**
|
|
96
110
|
* Browser helpers for UX Review region captures from a catalog. The local
|
|
@@ -118,4 +132,4 @@ declare function uxReviewCaptureUrl({ projectDirectory, title, context, }: UxRev
|
|
|
118
132
|
*/
|
|
119
133
|
declare function loadUxReviewProject(pageUrl: string | URL, fetchImpl?: typeof globalThis.fetch): Promise<string | null>;
|
|
120
134
|
|
|
121
|
-
export { Catalog, CatalogExample, type CatalogExampleAlign, type CatalogExampleProps, CatalogExampleStack, type CatalogExampleStackProps, type CatalogExampleViewport, CatalogProps, UX_REVIEW_PROJECT_PATH, type UxReviewCapture, loadUxReviewProject, uxReviewCaptureUrl };
|
|
135
|
+
export { Catalog, CatalogExample, type CatalogExampleAlign, type CatalogExampleProps, CatalogExampleStack, type CatalogExampleStackProps, type CatalogExampleStackWidth, type CatalogExampleViewport, CatalogProps, UX_REVIEW_PROJECT_PATH, type UxReviewCapture, loadUxReviewProject, uxReviewCaptureUrl };
|
package/dist/catalog.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Workbench } from './chunk-
|
|
1
|
+
import { Workbench } from './chunk-527IAEWG.js';
|
|
2
2
|
import { uxReviewCaptureUrl } from './chunk-6C6DLP3W.js';
|
|
3
3
|
export { UX_REVIEW_PROJECT_PATH, loadUxReviewProject, uxReviewCaptureUrl } from './chunk-6C6DLP3W.js';
|
|
4
4
|
|
|
@@ -622,6 +622,7 @@ function CatalogExample({
|
|
|
622
622
|
class: `kui-catalog-example ${className}`.trim(),
|
|
623
623
|
"data-catalog-example": true,
|
|
624
624
|
"data-align": align,
|
|
625
|
+
"aria-label": label,
|
|
625
626
|
slot,
|
|
626
627
|
children: [
|
|
627
628
|
label !== void 0 ? /* @__PURE__ */ jsx(
|
|
@@ -652,10 +653,12 @@ var protectedAttributes3 = /* @__PURE__ */ new Set([
|
|
|
652
653
|
"data-catalog-example-stack",
|
|
653
654
|
"data-catalog-example-label",
|
|
654
655
|
"data-catalog-example-note",
|
|
655
|
-
"data-align"
|
|
656
|
+
"data-align",
|
|
657
|
+
"data-width"
|
|
656
658
|
]);
|
|
657
659
|
function CatalogExampleStack({
|
|
658
660
|
label,
|
|
661
|
+
width = "reading",
|
|
659
662
|
rootAttributes = {},
|
|
660
663
|
className = "",
|
|
661
664
|
children,
|
|
@@ -671,6 +674,7 @@ function CatalogExampleStack({
|
|
|
671
674
|
...safeRootAttributes,
|
|
672
675
|
class: `kui-catalog-example-stack ${className}`.trim(),
|
|
673
676
|
"data-catalog-example-stack": true,
|
|
677
|
+
"data-width": width === "full" ? "full" : void 0,
|
|
674
678
|
"aria-label": label,
|
|
675
679
|
slot,
|
|
676
680
|
children
|