@kerfjs/ui 5.0.0-beta.3 → 5.0.0-beta.4

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 CHANGED
@@ -8,8 +8,9 @@ For connective application patterns, use the seven [production composition
8
8
  recipes](./docs/recipes.md). Each has a stable catalog route, runnable state,
9
9
  public-subpath source, semantic layout ownership, and explicit application
10
10
  customization boundaries. The composer recipe demonstrates one coherent form
11
- surface with three transparent content sections; only persistent feedback adds
12
- a nested semantic `StateBanner` surface.
11
+ surface with `DialogHeader` hierarchy and field/action controls aligned to the
12
+ shared 8px gutter; only persistent feedback adds a nested semantic
13
+ `StateBanner` surface.
13
14
 
14
15
  When no primitive matches, keep policy application-owned while reusing the
15
16
  layout vocabulary. The typed
@@ -79,6 +80,8 @@ JavaScript callers cannot bypass those protections with case-variant names.
79
80
  sibling primary and trailing native-button actions with independent names,
80
81
  disabled states, focus, and click ownership. Its `label`, `icon`, and
81
82
  `trailingActionIcon` slots are dormant content and must not contain controls.
83
+ In either component's multiline mode, the leading icon remains aligned with
84
+ the first text line as the label wraps below it.
82
85
  For section quantities, pass a non-negative safe-integer `count` together with
83
86
  the localized full spoken phrase in `countLabel`, for example
84
87
  `count={3} countLabel="3 notes"`. This renders the standard neutral count pill
@@ -244,25 +244,31 @@
244
244
  "purpose": "Provide one reusable pane, toolbar, content stack, and content-item geometry across sidebars, main areas, and dialogs.",
245
245
  "publicExports": [],
246
246
  "useWhen": [
247
- "Build sidebars, main areas, or dialogs from an unpadded pane with optional toolbar/footer and one content stack."
247
+ "Build sidebars, main areas, inspectors, or dialogs from an unpadded pane with optional toolbar/footer and one content stack.",
248
+ "Relocate a hidden pane's restore control into the adjacent main toolbar on the same logical edge."
248
249
  ],
249
250
  "avoidWhen": [
250
- "Do not pad the pane itself or add wrapper insets around children that already own content-item geometry."
251
+ "Do not pad the pane itself or add wrapper insets around children that already own content-item geometry.",
252
+ "Do not leave an empty icon-only rail after collapsing a pane."
251
253
  ],
252
254
  "alternatives": [],
253
255
  "appOwns": [
254
256
  "layout hierarchy",
255
257
  "reading width",
256
- "responsive relocation"
258
+ "responsive relocation",
259
+ "pane visibility and matching collapse/restore controls"
257
260
  ],
258
261
  "variants": [
259
262
  "toolbar + content",
260
263
  "toolbar + content + footer",
261
264
  "rounded content item",
262
- "pill content item"
265
+ "pill content item",
266
+ "hidden inline-start pane restored from main-toolbar leading",
267
+ "hidden inline-end pane restored from main-toolbar trailing"
263
268
  ],
264
269
  "accessibility": [
265
- "Keep reading and focus order coherent when controls wrap or panes relocate, and preserve one scroll owner per pane."
270
+ "Keep reading and focus order coherent when controls wrap or panes relocate, and preserve one scroll owner per pane.",
271
+ "When collapse replaces one control with its counterpart in another toolbar, move focus to the newly rendered restore or collapse control."
266
272
  ],
267
273
  "delivery": {
268
274
  "manualCssImport": "@kerfjs/ui/layout.css",
@@ -4424,12 +4430,12 @@
4424
4430
  "category": "Recipes",
4425
4431
  "kind": "recipe",
4426
4432
  "source": "kerf",
4427
- "purpose": "One visible publishing-form surface with exactly three transparent 8/1/8 content sections, 24px major rhythm, and a conditional StateBanner as its only nested semantic surface.",
4428
- "uses": ["select", "state-banner", "wa-input", "wa-textarea", "wa-button", "layout"],
4433
+ "purpose": "One visible publishing-form surface with DialogHeader hierarchy, fields and actions on the shared 8px control gutter, 24px major rhythm, and a conditional StateBanner as its only nested semantic surface.",
4434
+ "uses": ["dialog-header", "select", "state-banner", "wa-input", "wa-textarea", "wa-button", "layout"],
4429
4435
  "useWhen": ["A short form needs one coherent surface, consistent field/action rhythm, and persistent validation feedback."],
4430
4436
  "avoidWhen": ["Do not turn each form section into another visible card or use the recipe as a generic form engine or transport abstraction."],
4431
4437
  "appOwns": ["validation rules", "draft persistence", "permissions", "transport"],
4432
- "accessibility": ["Production fields own labels and help; invalid submission creates an assertive persistent StateBanner while successful submission creates a polite persistent banner."],
4438
+ "accessibility": ["The form references DialogHeader's title and summary ids; production fields own labels and help; invalid submission creates an assertive persistent StateBanner while successful submission creates a polite persistent banner."],
4433
4439
  "delivery": { "sideEffects": ["lazy-recipe-css", "individual-custom-element-registration"] },
4434
4440
  "links": { "catalogRoute": "?component=recipe-composer-form", "documentation": "docs/recipes.md#composer-form", "recipe": "docs/recipes.md#composer-form" }
4435
4441
  },
@@ -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` and `kerfjs@5.0.0-beta.3`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.4` and `kerfjs@5.0.0-beta.4`. 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/disclosure-arrow`
6
6
 
package/ai/skill.md CHANGED
@@ -27,8 +27,8 @@ Quick routing:
27
27
 
28
28
  | Need | Choose | Nearest alternatives / boundary |
29
29
  | --- | --- | --- |
30
- | Navigation row | `MenuItem` | Use an ordinary link or button when sidebar/menu anatomy and state do not apply. |
31
- | Navigation row with a trailing action | `MenuActionRow` | Use `MenuItem` when the trailing region is dormant; never put controls inside either component's SafeHtml slots. |
30
+ | Navigation row | `MenuItem` | Use an ordinary link or button when sidebar/menu anatomy and state do not apply. Multiline leading icons stay aligned with the first text line. |
31
+ | Navigation row with a trailing action | `MenuActionRow` | Use `MenuItem` when the trailing region is dormant; never put controls inside either component's SafeHtml slots. Multiline leading icons stay aligned with the first text line. |
32
32
  | Page chrome or heading | `Toolbar`, `PageHeader`, or `DialogHeader` | Toolbar is persistent chrome; page and dialog headers identify different scopes. |
33
33
  | Exclusive choice | `TabBar`, `SegmentedControl`, or `Select` | Tabs switch tabpanels; segments expose a few choices; Select handles a longer value list. |
34
34
  | Status or absent content | `StateBanner` or `EmptyState` | Web Awesome callouts suit ecosystem content; toasts are transient and never the only record of important state. |
@@ -61,8 +61,9 @@ Hard rules:
61
61
  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.
62
62
  14. Treat the complete Web Awesome catalog as support coverage, not a recommendation list. Consider Popup when it replaces custom anchored positioning. 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.
63
63
  15. Build sidebars, main areas, inspectors, and dialogs from `@kerfjs/ui/layout.css`: an unpadded `.kui-pane`, optional `.kui-pane__toolbar`, one scrolling `.kui-pane__content`, and optional `.kui-pane__footer`. Add `.kui-content` for 24px major vertical separation and `.kui-content-item` for a child-owned 8px inline margin, 1px transparent-or-visible border, 8px padding, and 12px radius. Use the pill modifier for 22px. Do not pad pane shells or duplicate item geometry in wrappers.
64
+ 16. Keep a visible collapsible pane's collapse control in its own toolbar. When hidden, move its restore control into the adjacent main toolbar on the corresponding logical edge: leading for an inline-start sidebar and trailing for an inline-end inspector. Collapse the pane completely; do not preserve an empty icon-only rail.
64
65
  16. Wrap every toolbar item, including dormant text, in `ToolbarControlGroup`. A group remains 44px outside (`calc(2px + remify(42px))`) when its border/background are transparent; use 8px between groups and inside items. Split dormant and interactive regions: `MenuHeader` fills the available inline width and keeps its label and mutually exclusive semantic count or non-count `badge` together, with an independent logical-end 44px action unless disclosure mode makes the title cluster the button. Its action visual defaults to 18px through `--kui-menu-header-action-icon-size`; never shrink the target to match it. Pass every non-negative safe-integer section quantity through `count` with a localized full spoken `countLabel`; never concatenate it into `label` or put a number in `badge`. `MenuItem.trailing` is dormant; use `MenuActionRow` when primary and trailing actions need sibling 44px native buttons. Its `label`, `icon`, and `trailingActionIcon` slots are also dormant and cannot contain controls. Let panes relocate at narrow widths instead of shrinking targets.
65
- 17. When a recurring concept has no matching export or production recipe, keep its semantics in a thin application adapter while reusing the public layout vocabulary. The composer recipe uses one visible form surface, exactly three transparent 8/1/8 content sections, 24px major rhythm, and a conditional StateBanner as its only nested semantic surface; do not turn every section into a card. The application-local `../docs/examples/command-palette-adapter.tsx` is reference source for one such missing concept, not an `@kerfjs/ui` runtime export or catalog recipe. The application owns its registration, ranking, history, permissions, availability, shortcut policy, focus policy, dispatch, and copy. If a missing concept recurs across products, open an upstream component or recipe request.
66
+ 17. When a recurring concept has no matching export or production recipe, keep its semantics in a thin application adapter while reusing the public layout vocabulary. The composer recipe uses one visible form surface, `DialogHeader` title/summary ids, shared 8px field/action gutters, 24px major rhythm, and a conditional StateBanner as its only nested semantic surface; do not turn every section into a card or double-inset intrinsically bordered controls. The application-local `../docs/examples/command-palette-adapter.tsx` is reference source for one such missing concept, not an `@kerfjs/ui` runtime export or catalog recipe. The application owns its registration, ranking, history, permissions, availability, shortcut policy, focus policy, dispatch, and copy. If a missing concept recurs across products, open an upstream component or recipe request.
66
67
  18. 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.
67
68
  19. Use `DialogHeader` for dialog hierarchy, not a custom heading row. Its real top `Toolbar` puts the optional 24px icon in a 34px circular background and the first title line in a borderless `ToolbarControlGroup`, centered against the automatic action `ToolbarControlGroup`; pass action children directly and add a localized `actionsLabel` when that group needs a name. Its optional `summary`/`summaryId` row stays below the title. The app owns modal behavior, focus, dismissal, command policy, and action handling.
68
69
 
@@ -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` 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.
3
+ Generated from the emitted `@kerfjs/ui@5.0.0-beta.4` 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';
@@ -117,6 +117,12 @@
117
117
  white-space: normal;
118
118
  }
119
119
 
120
+ .kui-menu-action-row[data-multiline="true"] .kui-menu-action-row__icon {
121
+ inset-block-start: calc(
122
+ var(--kui-layout-item-padding, 0.5rem) + (1lh / 2)
123
+ );
124
+ }
125
+
120
126
  .kui-menu-action-row__trailing-action {
121
127
  display: grid;
122
128
  width: 2.75rem;
@@ -104,6 +104,11 @@
104
104
  white-space: normal;
105
105
  }
106
106
 
107
+ .kui-menu-item[data-multiline="true"] .kui-menu-item__icon {
108
+ align-self: start;
109
+ margin-block-start: calc((1lh - 1.5rem) / 2);
110
+ }
111
+
107
112
  .kui-menu-item__trailing {
108
113
  display: inline-flex;
109
114
  min-width: 0;
@@ -22,5 +22,12 @@
22
22
  letter-spacing: -0.025em;
23
23
  }
24
24
  .kui-page-header__action {
25
+ margin-inline-end: calc(
26
+ -1 *
27
+ (
28
+ var(--kui-layout-item-padding, 0.5rem) +
29
+ var(--kui-layout-item-border-width, 1px)
30
+ )
31
+ );
25
32
  flex: none;
26
33
  }
@@ -51,6 +51,9 @@ and disposal.
51
51
  contain controls. When a row needs an independently interactive trailing
52
52
  region, `MenuActionRow` owns the noninteractive root and the two sibling native
53
53
  buttons; the application owns their delegated behavior and controlled state.
54
+ Both row components align a leading icon with the first label line when
55
+ `multiline` allows the label to wrap; additional lines extend below that fixed
56
+ visual anchor.
54
57
 
55
58
  ### Public CSS anatomy
56
59
 
@@ -56,7 +56,7 @@ an upstream component or recipe request.
56
56
  | Navigation row — `MenuItem` | A pane or navigation area needs a selectable, disabled, dormant-trailing, or multiline action row. | Do not put a control in `trailing`; use `MenuActionRow` when the trailing region must be independently interactive. Use an `<a>` for navigation that must retain link behavior, a native `<button>` for an ordinary action, or implement the complete ARIA menu widget. | Delegate its `data-action`; compose inside a `.kui-content` section. Put domain event/drop metadata in `rootAttributes` rather than adding wrapper markup. | Routing, selection, permissions, copy, action handling, and domain `data-*` values. | `@kerfjs/ui/menu-item` | [Pane geometry](../README.md#pane-and-content-geometry) |
57
57
  | Navigation row with trailing action — `MenuActionRow` | A full-width row needs a selectable primary action and an independently focusable trailing action. | Use `MenuItem` when trailing content is dormant metadata. Do not put controls inside the row's `label`, `icon`, or `trailingActionIcon` SafeHtml slots. Do not use `AppTab` outside tablist semantics or `ToolbarControlGroup` outside a toolbar. | Delegate both action strings; update controlled selection and any popover/context-menu state in the app. | Routing, selection, both action policies, domain metadata, and popover/context-menu behavior. | `@kerfjs/ui/menu-action-row` | [Accessibility](./accessibility.md#menuactionrow) |
58
58
  | Navigation section heading — `MenuHeader` | A menu section needs a full-width label, semantic count, non-count badge, logical-end action, or real disclosure state. | Do not concatenate counts into `label` or put numeric content in `badge`; use `count` with the localized full phrase in `countLabel`. Do not add a disclosure arrow to navigation that reveals nothing. Do not shrink its 44px action target to the 18px visual. Do not use it as a page or dialog title; use `PageHeader` or `DialogHeader`. | Delegate its optional action; the app controls expanded state and revealed content. Toggle mode supplies `DisclosureArrow` unless `actionIcon` replaces it. Use `triggerAttributes` only for domain `data-*` or a native popover relationship. | Section organization, valid count and localized count label, disclosure state and content, non-count badge content, popover target behavior, and policy. | `@kerfjs/ui/menu-header` | [Pane geometry](../README.md#pane-and-content-geometry) |
59
- | Application layout composition | A sidebar, main area, inspector, or dialog needs shared toolbar/content/footer and child geometry. | Do not pad the pane shell, wrap child-owned geometry in competing insets, or invent unrelated centered measures. | Use `.kui-pane` and one `.kui-pane__content`; add `.kui-content` and `.kui-content-item` as needed. | Layout hierarchy, reading width, scroll ownership, and responsive relocation. | `@kerfjs/ui/layout.css` | [Pane anatomy](./layout.md#anatomy) |
59
+ | Application layout composition | A sidebar, main area, inspector, or dialog needs shared toolbar/content/footer and child geometry. | Do not pad the pane shell, wrap child-owned geometry in competing insets, invent unrelated centered measures, or leave an icon-only rail for a hidden pane. | Use `.kui-pane` and one `.kui-pane__content`; add `.kui-content` and `.kui-content-item` as needed. A visible pane owns collapse in its toolbar; move a hidden inline-start pane's restore control to the main toolbar leading edge and an inline-end pane's restore control to its trailing edge. | Layout hierarchy, reading width, scroll ownership, responsive relocation, and pane visibility state. | `@kerfjs/ui/layout.css` | [Pane anatomy](./layout.md#anatomy) |
60
60
  | Menu composition | Navigation sections need full-size rows and the same content-item geometry as every other pane. | Do not add sidebar-specific wrapper padding, shrink targets to icon size, nest an interactive trailing control in `MenuItem`, or use a chevron on a row that does not disclose content. Use ordinary links for a different navigation contract. | Compose `MenuHeader`, `MenuItem`, and `MenuActionRow` in `.kui-content`; use `MenuHeader` toggle mode with real controlled content, and use `.kui-content-item` for other surfaces plus a pane footer for toolbar actions. | Information architecture, disclosure content and state, responsive drawer/shell behavior, and token overrides. | `@kerfjs/ui/layout.css` | [Pane geometry](../README.md#pane-and-content-geometry) |
61
61
  | Resizable application pane — `ResizableRegion`, `clampRegionSize`, `resizeRegionFromPointer` | A controlled split pane needs the Kerf separator, collapse state, pointer plus keyboard resizing, or a product-specific decorative grip. | Do not use it for a static two-column layout; use CSS grid. Prefer it over Web Awesome `wa-split-panel` unless that component's distinct API is required. Keep `handleIcon` noninteractive. | Call `wireResizableRegions` from `@kerfjs/ui/wire-resizable-regions` once and retain its disposer. | Size signal, min/max policy, collapse policy, persistence, and optional decorative handle icon. | `@kerfjs/ui/resizable-region` | [ResizableRegion contract](./accessibility.md#resizableregion) |
62
62
  | One application tab — `AppTab` | A controlled app tab needs selection, close, drag, leading/trailing anatomy, safe domain metadata, or a product-specific close glyph. | Do not render it alone or use it for a small settings choice; compose in `TabBar`, or use `SegmentedControl`. Keep `closeIcon` noninteractive. | Compose in `TabBar`; let `wireTabBars` manage interaction. Put only domain `data-*` values in `rootAttributes`. | Tab identity, order, selection, close policy, content, and domain metadata values. | `@kerfjs/ui/app-tab` | [Tabs contract](./accessibility.md#tabs) |
package/docs/layout.md CHANGED
@@ -38,9 +38,11 @@ changing its geometry by setting `--kui-content-item-border` and
38
38
  `--kui-content-item-background`.
39
39
 
40
40
  A visible parent surface does not make every child another visible card. The
41
- composer recipe keeps its form as the single surface and uses three transparent
42
- content items for the introduction, fields, and footer. A conditional
43
- `StateBanner` remains visibly distinct because it communicates semantic status.
41
+ composer recipe keeps its form as the single surface, uses `DialogHeader` for
42
+ its task hierarchy, and places field and action control edges on the shared 8px
43
+ inline gutter instead of nesting them inside another padded content item. A
44
+ conditional `StateBanner` remains visibly distinct because it communicates
45
+ semantic status.
44
46
 
45
47
  ## Public roles and tokens
46
48
 
@@ -64,6 +66,8 @@ also keeps 8px of root-scaled block padding independently of its semantic inline
64
66
  inset. Most interactive rows and toolbar groups are 44px tall.
65
67
  Toolbar groups reserve a real 1px outer border around a 42px inner area, even
66
68
  when their border and background are transparent.
69
+ `PageHeader` keeps its title on the shared inset while its action border aligns
70
+ with the logical edge of the following `.kui-content-item` border.
67
71
  `DialogHeader` applies the same rule internally: its icon/title identity is a
68
72
  borderless group in a top toolbar, its direct action children are wrapped in a
69
73
  contained group, and its optional subtitle is a separate row aligned below the
@@ -87,8 +91,15 @@ title. The icon visual is 24px inside a 34px circular background.
87
91
  replaces it.
88
92
  `MenuActionRow` uses a noninteractive row root around sibling 44px primary
89
93
  and trailing buttons. `MenuItem.trailing` remains dormant content.
94
+ In multiline `MenuItem` and `MenuActionRow` rows, the leading icon stays
95
+ centered on the label's first line rather than the full wrapped label.
90
96
  6. Reading width, column placement, and responsive relocation remain application
91
97
  decisions. The shared classes define local geometry, not the whole shell.
98
+ 7. A visible collapsible pane owns its collapse control in that pane's toolbar.
99
+ When the pane is hidden, move the restore control into the adjacent main
100
+ toolbar on the same logical edge: an inline-start pane restores from the
101
+ main toolbar's leading group, and an inline-end pane restores from its
102
+ trailing group. Do not leave an otherwise empty icon-only rail behind.
92
103
 
93
104
  At narrow widths or 200% zoom, relocate or stack panes before shrinking targets.
94
105
  The 8/1/8 item contract and 44px controls remain stable, so screenshots and
package/docs/recipes.md CHANGED
@@ -33,6 +33,10 @@ specific dispatch; either way, wire once at a stable root and retain disposal.
33
33
  Use `Toolbar`, controlled `ResizableRegion` panes, and one
34
34
  `.kui-pane__content` scroll owner per pane. The recipe owns the shell topology;
35
35
  the app owns routing, responsive pane visibility, sizes, persistence, and data.
36
+ Keep each visible pane's collapse action in its own toolbar. Once hidden, put
37
+ its restore action in the adjacent main toolbar on the same logical edge:
38
+ leading for an inline-start sidebar and trailing for an inline-end inspector.
39
+ Collapse the pane completely rather than preserving an empty icon rail.
36
40
  Adapt only public `--kui-layout-*` and component variables.
37
41
 
38
42
  ## Navigation sidebar
@@ -66,17 +70,21 @@ adapter restores the invoking control consistently after the hide event.
66
70
  anatomy. The application owns open state, selection, dismissal policy, and
67
71
  record actions. Pass the dialog action children directly; `DialogHeader` places
68
72
  them in its top toolbar's action group and uses the localized `actionsLabel`.
73
+ The header sits on the dialog edge while retaining its internal control inset;
74
+ the selected title receives the full content gutter, the metadata table fills
75
+ the available detail width between the usual outer margins, and the action
76
+ cluster uses one outer gutter without a second content-item inset.
69
77
  Do not rebuild the dialog or reach into private shadow parts.
70
78
 
71
79
  ## Composer form
72
80
 
73
81
  [Open the recipe](../ux-demo/?component=recipe-composer-form) · [TSX source](../ux-demo/recipes/composer-form.tsx)
74
82
 
75
- Production fields own labels, help, and native focus; semantic layout classes
76
- compose one visible form surface from exactly three transparent content items:
77
- introduction, fields, and a footer containing actions plus ownership guidance.
78
- The three sections retain 8px margin, 1px transparent border, and 8px padding,
79
- with 24px between major children and 8px inside each section. The app owns
83
+ `DialogHeader` supplies the task title and summary, with their ids referenced
84
+ by the form. Production fields own labels, help, and native focus. The field
85
+ and footer control edges sit directly on the shared 8px inline gutter rather
86
+ than acquiring a second content-item padding inset; major children remain 24px
87
+ apart and related controls use 8px gaps. The app owns
80
88
  validation, drafts, permissions, and transport. Persistent error or success
81
89
  feedback is the only nested semantic surface and uses `StateBanner`, not a toast.
82
90
  Because upgraded Web Awesome fields retain live value properties, controlled
package/docs/ux-demo.md CHANGED
@@ -1,28 +1,30 @@
1
1
  # UX catalog contract
2
2
 
3
- Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation.
3
+ Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation. The development server allows repo-owned assets used by the catalog, and its production bundle uses relative asset URLs so the complete catalog remains intact below preview and proxy paths.
4
4
 
5
5
  Seven lazy production-composition routes live under the `Recipes` category.
6
6
  Each `?component=recipe-*` route uses public package primitives, real wiring,
7
7
  deterministic state, and semantic layout owners from the [recipe guide](./recipes.md).
8
8
 
9
9
  - It imports public component subpaths, exercising their browser-selected reachable CSS rather than a catalog-only style path.
10
- - The `MenuActionRow` route demonstrates sibling primary/trailing native controls, independent disabled states, controlled selection, and an application-owned native popover relationship without nesting controls.
10
+ - The `MenuActionRow` route demonstrates sibling primary/trailing native controls, independent disabled states, controlled selection, first-line leading-icon alignment for wrapped labels, and an application-owned native popover relationship without nesting controls. The `MenuItem` route demonstrates the same multiline leading-icon anchor alongside its single-control navigation contract.
11
11
  - The `AppTab` route demonstrates a runtime-filtered domain metadata slot and a decorative replacement close icon without changing TabBar selection, close, reorder, or focus ownership. The `ResizableRegion` route likewise replaces only the decorative handle glyph while retaining separator semantics and shared wiring.
12
12
  - Every first-party visual component and every free Web Awesome 3.12 component has its own stable `?component=<id>` URL and focused demo. Composite header, menu, feedback, and theme scenarios remain addressable alongside their subcomponents; the root opens the first Kerf component.
13
13
  - `ai/component-catalog.json` is the canonical catalog metadata. A deterministic checked-in projection supplies the demo's unique id, category, kind (`component`, `composition`, or `recipe`), source (`kerf` or `webawesome`), name, description, direct `uses` dependencies, existing documentation path, and demo-source path; first-party, recipe, and Web Awesome renderer maps are exhaustively typed against its generated id unions. Demo paths resolve to `ui/ux-demo/main.tsx`, the matching `ui/ux-demo/recipes/*.tsx` file, or `ui/ux-demo/webawesome-demos.tsx` according to the canonical entry. First-party component entries additionally derive `ui/src/<browser-subpath>.tsx` from their canonical `delivery.browserImport`.
14
- - Every detail header visibly pairs `View demo source` with `Read guidance`; first-party component details also expose `View component source`. Web Awesome details say `Read Kerf integration guidance` to distinguish the local integration contract from the upstream component implementation. All links show their repository-relative path and use deploy-safe absolute GitHub blob URLs with contextual new-tab names; the demo does not depend on a local source server or add a package runtime export.
14
+ - Every detail footer groups compact `Demo source` and `Guidance` actions; first-party component details also expose `Component source`. Web Awesome details say `Integration guidance` to distinguish the local integration contract from the upstream component implementation. Each button retains its repository-relative path in the DOM for verification and uses a deploy-safe absolute GitHub blob URL with a contextual new-tab name; the demo does not depend on a local source server or add a package runtime export. At phone widths, the resource group and related-component selector stack as full-width rows, with any resource overflow contained locally so labels cannot overlap the selector or widen the document.
15
15
  - The master/detail shell groups first-party routes by category with production `MenuHeader` and `MenuItem` components. The 70 ecosystem components live in a separate `Web Awesome` disclosure with seven subgroups, so they remain discoverable without being presented as first-class `@kerfjs/ui` exports. Direct Web Awesome routes open the disclosure and reveal the selected row at wide sizes; narrow layouts keep the expanded list in document flow rather than introducing a competing nested scroller.
16
- - The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. At narrow widths, the focused `ResizableRegion` specimen moves its committed-width status below the controlled pane while retaining local horizontal access when the pane is resized wider than the stage; its split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
17
- - The composer-form recipe demonstrates one coherent visible form surface with exactly three transparent 8/1/8 content sections and 24px major rhythm. Its conditional error or success `StateBanner` is the only nested semantic surface. Reset synchronizes the upgraded Web Awesome fields' live value properties with their empty controlled attributes and announces `Draft reset`; browser coverage preserves behavior and verifies wide, narrow, dark, validation, success, reset, 200% zoom, and forced-colors states.
16
+ - The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with the subtitle in its own aligned row like `DialogHeader`; the current-view heading is also a toolbar. Collapsing the catalog removes the pane completely and moves its restore action to the main toolbar's leading edge instead of leaving an icon-only rail. The selected view description remains inset below the page toolbar. The checkerboard belongs to the complete scrollable preview region rather than a nested card. A lightly separated footer keeps live status above compact source, guidance, and relationship groups. The focused `ResizableRegion` specimen stretches its surface through the available stage height and reports committed width in that shared status footer; narrow layouts retain local horizontal access when the pane is resized wider than the stage, and the split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
17
+ - The composer-form recipe demonstrates one coherent visible form surface with `DialogHeader` title/summary hierarchy, fields and actions on the shared 8px control gutter, and 24px major rhythm. Its conditional error or success `StateBanner` is the only nested semantic surface. Reset synchronizes the upgraded Web Awesome fields' live value properties with their empty controlled attributes and announces `Draft reset`; browser coverage preserves behavior and verifies wide, narrow, dark, validation, success, reset, 200% zoom, and forced-colors states.
18
+ - The master-detail dialog recipe places its header directly on the dialog edge while preserving the header's internal inset, gives the selected project title the complete outer-plus-inner content gutter, lets the value table fill the available detail column between the shared outer margins, and keeps record actions on one outer gutter without an extra content-item inset. Browser geometry coverage protects those relationships at wide and narrow widths.
18
19
  - Catalog-only brand marks, preview dimensions, checkerboard tiles, and the compound display-settings control retain local geometry because they are specimen chrome or intrinsic control anatomy rather than reusable application spacing roles.
19
20
  - The menu composition route demonstrates toolbar/content/footer anatomy, 24px major gaps, 8/1/8 child geometry, the full-width `MenuHeader` count-or-badge/action split, logical-end 44px action targets with 18px visuals, and 44px row/header/toolbar targets. Its one chevron is a production 18px `DisclosureArrow` inside a controlled Tools header that actually reveals and hides content; ordinary Projects navigation has no false disclosure affordance. Browser assertions cover stable naming, expanded/content transitions, visual rotation, node identity, reduced motion, RTL alignment and containment, and wide, narrow, dark, and 200% layouts. The focused MenuHeader route separately shows the shared neutral count pill for Attachments, Notes (including zero), and Duplicates plus a non-count legacy badge, full-width logical-end actions, and no disclosure without content.
20
21
  - The `DisclosureArrow` route renders the production 18px root-scaled default without a catalog-only size override. Its two native buttons independently control the default right-to-down chevron and a recognizable right-facing replacement arrow with left-to-up custom directions; both use shortest-path rotation and their names stay stable while `aria-expanded` communicates state. Browser coverage verifies the custom clockwise path, pointer and native keyboard activation, focus, narrow and 200%-zoom stacking with contained labels, consumer sizing, and the independent `.5` Web Awesome glyph scale retained by Kerf `Select`.
21
- - A detail with relationships renders one grouped selector: `Uses` links to direct dependencies and `Used by` links to reverse dependents. Choosing either navigates to that component's demo. The footer is absent when both groups are empty; no duplicate relationship summary is rendered.
22
+ - A detail with relationships renders one grouped footer selector: `Uses` links to direct dependencies and `Used by` links to reverse dependents. Choosing either navigates to that component's demo. The relationship group is absent when both sets are empty; no duplicate summary is rendered.
22
23
  - Demo-only CSS supplies only the catalog shell and stages; component appearance stays in package CSS. Decorative chrome and Web Awesome controls share the same semantic system palette instead of carrying a separate demo identity.
23
24
  - Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions. The Web Awesome theme route remains the broad system view, while individual action, form, layout, navigation, feedback, media, and helper routes provide focused specimens; MenuItem and MenuHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; DialogHeader demonstrates its top-toolbar identity/action groups, optional subtitle row, and 24px icon inside a 34px circle; the Select route verifies that option icons survive unrelated Kerf rerenders and selected slot content follows value changes; the Animation route exposes preset, easing, duration, playback-rate, and transport controls with live lifecycle status; observer routes provide user-driven intersection, mutation, and resize events with live results; ToolbarControlGroup exposes all eight Hot Sheet 2 variants, loads the Web Awesome registrations needed by its popup specimen, and preserves the upgraded dropdown's managed light-DOM children across Kerf rerenders; the Toolbar route composes a collapsible TokenSearchField inside a group, animates between the empty iconic and complete field states, stays open while populated, and focuses the revealed editor; SegmentedControl covers toolbar, rounded-rectangle, pill, equal-width, and disabled presentations; TokenSearchField covers editable ordered chips, pointer and keyboard removal, caret-preserving controlled deletion, editing, clearing, free text, disabled state, and fixed first-line alignment while content wraps; StateBanner exposes every built-in tone plus a scoped override; TabBar demonstrates overflow, edge autoscroll, and controlled pointer/keyboard reordering.
24
- - Settings exercise light/dark, increased contrast, and reduced motion without changing component code, and expose each preference through `aria-pressed`.
25
- - The action log is an `aria-live` region, making interactions visible to both people and browser tests.
25
+ - Recipe ownership notes are hidden by default. A page-toolbar toggle reveals them as floating warning-toned notes with a folded corner, keeping instructional copy visually distinct and removable from the specimen flow.
26
+ - Settings exercise light/dark, increased contrast, and reduced motion without changing component code. The theme action starts from the operating system's effective color scheme, always names the appearance it will switch to, and installs an explicit light or dark override when activated; contrast and reduced motion expose their independent preferences through `aria-pressed`.
27
+ - The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
26
28
  - The focused Toast route calls Web Awesome's documented programmatic stack API and notes that Hot Sheet 2 still uses its own app-level toast implementation; the catalog demonstrates ecosystem support without implying current product adoption.
27
29
  - Browser coverage walks every Kerf, composition, and Web Awesome route, checks every listed Web Awesome custom element is registered in its focused specimen, exercises the ecosystem disclosure and both relationship directions, validates offline source/guidance hrefs and accessible wide/narrow/200%-zoom wrapping, and covers tab selection/reordering/overflow, semantic palettes and scoped overrides, light/dark rendering, toolbar popup and responsive find behavior, single/multiline search alignment, menu alignment, banner urgency, keyboard resizing, live custom-element values, and representative wide/narrow captures.
28
30
  - The production build keeps the catalog shell and Kerf routes in the entry chunk, then dynamically imports the complete Web Awesome specimen and registration surface when an ecosystem route, the broad Web Awesome theme route, or the ToolbarControlGroup popup specimen is selected. Directly addressed routes pass through the same loader.
package/llms.txt CHANGED
@@ -32,11 +32,11 @@ Public components: `LucideIcon`, `DisclosureArrow`, `Toolbar`, `ToolbarControlGr
32
32
 
33
33
  `DialogHeader` composes a real top `Toolbar`: its borderless identity group keeps the optional 24px icon in a 34px circular background and the first title line centered against an automatic action `ToolbarControlGroup`. Pass action children directly and add a localized `actionsLabel` when that group needs a name. The optional `summary`/`summaryId` row remains below the title; the application owns modal focus, dismissal, commands, and action handling.
34
34
 
35
- Pane and navigation composition: import `@kerfjs/ui/layout.css` and use an unpadded `.kui-pane` with optional `.kui-pane__toolbar`, one scrolling `.kui-pane__content`, and optional `.kui-pane__footer`. Add `.kui-content` for 24px major vertical gaps. Use `.kui-content-item` for children that own 8px inline margin, 1px transparent-or-visible border, 8px padding, and 12px rounded corners; the pill modifier uses 22px. This vocabulary applies equally to sidebars, main areas, inspectors, and dialogs.
35
+ Pane and navigation composition: import `@kerfjs/ui/layout.css` and use an unpadded `.kui-pane` with optional `.kui-pane__toolbar`, one scrolling `.kui-pane__content`, and optional `.kui-pane__footer`. Add `.kui-content` for 24px major vertical gaps. Use `.kui-content-item` for children that own 8px inline margin, 1px transparent-or-visible border, 8px padding, and 12px rounded corners; the pill modifier uses 22px. This vocabulary applies equally to sidebars, main areas, inspectors, and dialogs. A visible collapsible pane owns collapse in its own toolbar. When hidden, move restore into the adjacent main toolbar on the same logical edge—leading for an inline-start pane, trailing for inline-end—and remove the pane instead of leaving an icon-only rail.
36
36
 
37
- Composer form recipe: keep the form as one visible surface with exactly three transparent 8/1/8 content sections—introduction, fields, and actions-plus-ownership footer—separated by the 24px major rhythm. A conditional `StateBanner` is the only nested semantic surface. Do not make every form section another card. When resetting controlled upgraded Web Awesome fields, synchronize their live `value` properties as well as the rendered value attributes.
37
+ Composer form recipe: keep the form as one visible surface, use `DialogHeader` title/summary ids to label and describe it, and align field and action control edges on the shared 8px inline gutter without a second content-item padding inset. Retain 24px major rhythm. A conditional `StateBanner` is the only nested semantic surface. Do not make every form section another card. When resetting controlled upgraded Web Awesome fields, synchronize their live `value` properties as well as the rendered value attributes.
38
38
 
39
- Toolbar and split-item geometry: wrap every toolbar item, including dormant text, in `ToolbarControlGroup`. Groups stay 44px outside (`calc(2px + remify(42px))`) even when their border and background are transparent, with 8px between groups and inside items. `MenuHeader` fills the available inline width and separates its dormant title/count-or-badge cluster from its optional logical-end 44px action; the visible action glyph defaults to 18px through `--kui-menu-header-action-icon-size`, while disclosure mode makes the title cluster the action. `MenuActionRow` keeps primary and trailing 44px actions as sibling native buttons inside a noninteractive row. Do not pad pane shells or add competing wrapper insets. See `docs/layout.md`.
39
+ Toolbar and split-item geometry: wrap every toolbar item, including dormant text, in `ToolbarControlGroup`. Groups stay 44px outside (`calc(2px + remify(42px))`) even when their border and background are transparent, with 8px between groups and inside items. `MenuHeader` fills the available inline width and separates its dormant title/count-or-badge cluster from its optional logical-end 44px action; the visible action glyph defaults to 18px through `--kui-menu-header-action-icon-size`, while disclosure mode makes the title cluster the action. `MenuActionRow` keeps primary and trailing 44px actions as sibling native buttons inside a noninteractive row. Multiline `MenuItem` and `MenuActionRow` leading icons stay centered on the first text line while later lines extend below. Do not pad pane shells or add competing wrapper insets. See `docs/layout.md`.
40
40
 
41
41
  Import visual components from explicit JavaScript subpaths. A CSS-aware browser bundler selects generated wrappers that bring in the foundation, the component CSS, and styles for reachable UI subcomponents; unrelated CSS stays out. The root barrel and `@kerfjs/ui/unstyled` are CSS-free; use `styles.css` with the root barrel only when the complete layer is intentional. Manual CSS exports remain available for custom pipelines, and application overrides follow package styles in the cascade. Direct `wa-*` JSX uses `import type {} from '@kerfjs/ui/webawesome'`, the side-effect-free declaration boundary synchronized with all 70 catalog-supported elements. `@kerfjs/ui/webawesome.css` is the optional CSS-only theme; it includes Web Awesome's base stylesheet, registers no elements, and remains overridable through public `--wa-*` tokens. CSS, its generated browser wrappers, and `@kerfjs/ui/select/register` are the declared side effects. `kerfjs` is an external peer. The Web Awesome peer is optional and needed for its components. `wireTabBars` includes proximity-based horizontal edge autoscroll during same-bar drag reordering.
42
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.3",
3
+ "version": "5.0.0-beta.4",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -6,6 +6,7 @@ import '@awesome.me/webawesome/dist/components/input/input.js';
6
6
  import '@awesome.me/webawesome/dist/components/textarea/textarea.js';
7
7
  import './recipes.css';
8
8
 
9
+ import { DialogHeader } from '@kerfjs/ui/dialog-header';
9
10
  import { Select } from '@kerfjs/ui/select';
10
11
  import { StateBanner } from '@kerfjs/ui/state-banner';
11
12
  import { signal } from 'kerfjs';
@@ -28,16 +29,16 @@ export const createRecipe: RecipeFactory = (announce) => {
28
29
  const body = signal('The tablet layout now keeps navigation, content, and inspector focus order aligned.');
29
30
  const audience = signal('team');
30
31
  const status = signal<'idle' | 'error' | 'saved'>('idle');
31
- const render = () => <form class="kui-recipe recipe-form kui-recipe__surface kui-content" data-recipe="recipe-composer-form" noValidate>
32
- <header class="recipe-form__section recipe-form__introduction kui-content-item"><h2>Publish workspace update</h2><p class="kui-recipe__muted">Share a concise, actionable update with collaborators.</p></header>
32
+ const render = () => <form class="kui-recipe recipe-form kui-recipe__surface kui-content" data-recipe="recipe-composer-form" aria-labelledby="recipe-composer-title" aria-describedby="recipe-composer-summary" noValidate>
33
+ <DialogHeader title="Publish workspace update" titleId="recipe-composer-title" summary="Share a concise, actionable update with collaborators." summaryId="recipe-composer-summary" />
33
34
  {status.value === 'error' && <StateBanner title="Add a title before publishing" detail="The update body and audience are preserved." tone="danger" urgency="alert" />}
34
35
  {status.value === 'saved' && <StateBanner title="Update published" detail="The team audience can now read it." tone="success" />}
35
- <div class="recipe-form__section recipe-form__fields kui-content-item">
36
+ <div class="recipe-form__section recipe-form__fields">
36
37
  <wa-input name="recipe-title" label="Update title" hint="Summarize the outcome in one line." required value={title.value}></wa-input>
37
38
  <wa-textarea name="recipe-body" label="Details" hint="Include decisions, owners, and the next checkpoint." rows="5" maxlength="400" with-count value={body.value}></wa-textarea>
38
39
  <Select name="recipe-audience" value={audience.value} label="Audience" choices={[{ value: 'team', label: 'Workspace team' }, { value: 'reviewers', label: 'Reviewers' }, { value: 'organization', label: 'Entire organization' }]} />
39
40
  </div>
40
- <footer class="recipe-form__section recipe-form__footer kui-content-item"><div class="recipe-form__actions kui-control-cluster"><wa-button appearance="outlined" data-action="recipe-action" data-recipe-command="reset">Reset</wa-button><wa-button variant="brand" appearance="accent" data-action="recipe-action" data-recipe-command="submit">Publish update</wa-button></div><p class="kui-recipe__ownership">The recipe owns field, message, and action rhythm. The app owns validation rules, draft persistence, permissions, and transport.</p></footer>
41
+ <footer class="recipe-form__section recipe-form__footer"><div class="recipe-form__actions kui-control-cluster"><wa-button appearance="outlined" data-action="recipe-action" data-recipe-command="reset">Reset</wa-button><wa-button variant="brand" appearance="accent" data-action="recipe-action" data-recipe-command="submit">Publish update</wa-button></div><p class="kui-recipe__ownership">The recipe owns field, message, and action rhythm. The app owns validation rules, draft persistence, permissions, and transport.</p></footer>
41
42
  </form>;
42
43
  return {
43
44
  render,
@@ -27,7 +27,7 @@ interface RecipeDialogElement extends HTMLElement {
27
27
  export const createRecipe: RecipeFactory = (announce) => {
28
28
  const selected = signal<keyof typeof records>('alpha');
29
29
  const open = { value: false };
30
- const render = () => <section class="kui-recipe kui-content" data-recipe="recipe-master-detail-dialog"><button class="kui-recipe__button kui-content-item" data-primary="true" type="button" data-action="recipe-action" data-recipe-command="open">Open project details</button><p class="kui-recipe__ownership kui-content-item">Web Awesome owns modal focus and dismissal. The recipe owns header/body/master-detail anatomy; the app owns open state, selection, and policy.</p><wa-dialog class="recipe-dialog" label="Project details" without-header open={open.value}><div class="recipe-dialog__pane kui-pane"><DialogHeader title="Project details" titleId="recipe-dialog-title" summary="Compare delivery state without leaving the workspace." summaryId="recipe-dialog-summary" icon={<LucideIcon icon={FileText} name="file-text" />} actions={<wa-button appearance="plain" data-action="recipe-action" data-recipe-command="close">Close</wa-button>} actionsLabel="Project detail actions" /><div class="recipe-master-detail kui-pane__content"><nav class="recipe-master-detail__master kui-pane" aria-label="Projects"><MenuHeader label="Recent projects" /><div class="kui-pane__content kui-content"><section>{Object.entries(records).map(([id, record]) => <MenuItem action="recipe-action" itemId={id} label={record.name} selected={selected.value === id} multiline />)}</section></div></nav><section class="recipe-master-detail__detail kui-content" aria-live="polite"><h3 class="kui-recipe__pane-title kui-content-item">{records[selected.value].name}</h3><ValueTable label="Project details"><ValueTableRow label="Owner" value={records[selected.value].owner} /><ValueTableRow label="Status" value={records[selected.value].state} /><ValueTableRow label="Updated" value={records[selected.value].updated} /></ValueTable><div class="kui-control-cluster kui-content-item"><wa-button appearance="outlined" data-action="recipe-action" data-recipe-command="archive">Archive</wa-button><wa-button variant="brand" appearance="accent" data-action="recipe-action" data-recipe-command="open-record">Open project</wa-button></div></section></div></div></wa-dialog></section>;
30
+ const render = () => <section class="kui-recipe kui-content" data-recipe="recipe-master-detail-dialog"><button class="kui-recipe__button kui-content-item" data-primary="true" type="button" data-action="recipe-action" data-recipe-command="open">Open project details</button><p class="kui-recipe__ownership kui-content-item">Web Awesome owns modal focus and dismissal. The recipe owns header/body/master-detail anatomy; the app owns open state, selection, and policy.</p><wa-dialog class="recipe-dialog" label="Project details" without-header open={open.value}><div class="recipe-dialog__pane kui-pane"><DialogHeader title="Project details" titleId="recipe-dialog-title" summary="Compare delivery state without leaving the workspace." summaryId="recipe-dialog-summary" icon={<LucideIcon icon={FileText} name="file-text" />} actions={<wa-button appearance="plain" data-action="recipe-action" data-recipe-command="close">Close</wa-button>} actionsLabel="Project detail actions" /><div class="recipe-master-detail kui-pane__content"><nav class="recipe-master-detail__master kui-pane" aria-label="Projects"><MenuHeader label="Recent projects" /><div class="kui-pane__content kui-content"><section>{Object.entries(records).map(([id, record]) => <MenuItem action="recipe-action" itemId={id} label={record.name} selected={selected.value === id} multiline />)}</section></div></nav><section class="recipe-master-detail__detail kui-content" aria-live="polite"><h3 class="recipe-master-detail__title kui-recipe__pane-title kui-content-item">{records[selected.value].name}</h3><ValueTable label="Project details"><ValueTableRow label="Owner" value={records[selected.value].owner} /><ValueTableRow label="Status" value={records[selected.value].state} /><ValueTableRow label="Updated" value={records[selected.value].updated} /></ValueTable><div class="recipe-master-detail__actions kui-control-cluster"><wa-button appearance="outlined" data-action="recipe-action" data-recipe-command="archive">Archive</wa-button><wa-button variant="brand" appearance="accent" data-action="recipe-action" data-recipe-command="open-record">Open project</wa-button></div></section></div></div></wa-dialog></section>;
31
31
  return {
32
32
  render,
33
33
  action(command, element) {
@@ -119,7 +119,7 @@
119
119
 
120
120
  .recipe-master-detail {
121
121
  display: grid;
122
- width: min(58rem, 100%);
122
+ width: 100%;
123
123
  min-height: 25rem;
124
124
  grid-template-columns: minmax(13rem, 0.8fr) minmax(18rem, 1.4fr);
125
125
  }
@@ -130,10 +130,19 @@
130
130
  min-width: 0;
131
131
  padding-block: var(--kui-layout-item-gap);
132
132
  }
133
+ .recipe-master-detail__title {
134
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
135
+ }
136
+ .recipe-master-detail__actions {
137
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
138
+ }
133
139
  .recipe-dialog {
134
140
  --spacing: 0;
135
141
  --width: min(62rem, calc(100vw - 2rem));
136
142
  }
143
+ .recipe-dialog .kui-dialog-header {
144
+ margin-inline: 0;
145
+ }
137
146
 
138
147
  .recipe-form {
139
148
  width: min(38rem, 100%);
@@ -141,17 +150,24 @@
141
150
  padding-block: var(--kui-layout-item-gap);
142
151
  }
143
152
  .recipe-form__section {
144
- --kui-content-item-border: transparent;
145
- --kui-content-item-background: transparent;
146
153
  display: grid;
154
+ min-width: 0;
155
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
147
156
  gap: var(--kui-layout-item-gap);
148
157
  }
149
- .recipe-form__introduction > :where(h2, p) {
150
- margin: 0;
151
- }
152
158
  .recipe-form__fields {
153
159
  align-content: start;
154
160
  }
161
+ .recipe-form__fields wa-input::part(form-control-label),
162
+ .recipe-form__fields wa-input::part(hint),
163
+ .recipe-form__fields wa-textarea::part(form-control-label),
164
+ .recipe-form__fields wa-textarea::part(hint),
165
+ .recipe-form__fields .kui-select::part(form-control-label) {
166
+ padding-inline: remify(8px);
167
+ }
168
+ .recipe-form__fields wa-textarea::part(textarea) {
169
+ padding-inline: remify(8px);
170
+ }
155
171
  .recipe-form__footer {
156
172
  align-content: start;
157
173
  }