@kerfjs/ui 5.0.0-beta.23 → 5.0.0-beta.24

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.
Files changed (193) hide show
  1. package/README.md +1 -0
  2. package/ai/compile-time-contracts-v1.json +2 -1
  3. package/ai/component-catalog-v2-overrides.json +5 -12
  4. package/ai/component-catalog-v2.json +43 -32
  5. package/ai/component-catalog.json +56 -37
  6. package/ai/public-api-signatures-v1.md +29 -16
  7. package/ai/skill.md +4 -4
  8. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  9. package/dist/app-tab.js +1 -1
  10. package/dist/browser/list.js +3 -0
  11. package/dist/catalog.d.ts +8 -4
  12. package/dist/catalog.js +19 -10
  13. package/dist/catalog.js.map +1 -1
  14. package/dist/{chunk-RYRIFZCT.js → chunk-7XRDUG4Y.js} +5 -5
  15. package/dist/{chunk-RYRIFZCT.js.map → chunk-7XRDUG4Y.js.map} +1 -1
  16. package/dist/{chunk-OHU6CI22.js → chunk-B3A3IVO5.js} +2 -2
  17. package/dist/{chunk-OHU6CI22.js.map → chunk-B3A3IVO5.js.map} +1 -1
  18. package/dist/{chunk-ELSJX4W7.js → chunk-FEAMR7S4.js} +2 -2
  19. package/dist/{chunk-ELSJX4W7.js.map → chunk-FEAMR7S4.js.map} +1 -1
  20. package/dist/{chunk-OZWU5ZPZ.js → chunk-IJBSZ4NX.js} +2 -2
  21. package/dist/{chunk-OZWU5ZPZ.js.map → chunk-IJBSZ4NX.js.map} +1 -1
  22. package/dist/chunk-J5BFYY7Q.js +35 -0
  23. package/dist/chunk-J5BFYY7Q.js.map +1 -0
  24. package/dist/{chunk-QQFJMRIB.js → chunk-KWWR5VMS.js} +2 -2
  25. package/dist/{chunk-QQFJMRIB.js.map → chunk-KWWR5VMS.js.map} +1 -1
  26. package/dist/{chunk-K57KRAOV.js → chunk-NWSEP5RT.js} +2 -2
  27. package/dist/{chunk-K57KRAOV.js.map → chunk-NWSEP5RT.js.map} +1 -1
  28. package/dist/{chunk-GP5DP5DL.js → chunk-OJWWHFH3.js} +39 -4
  29. package/dist/chunk-OJWWHFH3.js.map +1 -0
  30. package/dist/{chunk-DSNIYOZ3.js → chunk-PSKN344N.js} +2 -2
  31. package/dist/{chunk-DSNIYOZ3.js.map → chunk-PSKN344N.js.map} +1 -1
  32. package/dist/{chunk-W7YD6E4N.js → chunk-R7ZWUN64.js} +2 -2
  33. package/dist/{chunk-W7YD6E4N.js.map → chunk-R7ZWUN64.js.map} +1 -1
  34. package/dist/{chunk-PZQVSDLH.js → chunk-RKVQEH4J.js} +1 -1
  35. package/dist/chunk-RKVQEH4J.js.map +1 -0
  36. package/dist/{chunk-7L6EHUMV.js → chunk-SYDMYBPG.js} +3 -3
  37. package/dist/chunk-SYDMYBPG.js.map +1 -0
  38. package/dist/{chunk-W4CXQYSG.js → chunk-TB6DY7H5.js} +3 -1
  39. package/dist/chunk-TB6DY7H5.js.map +1 -0
  40. package/dist/{chunk-BBRXX6PF.js → chunk-UFZKLBCF.js} +2 -2
  41. package/dist/{chunk-BBRXX6PF.js.map → chunk-UFZKLBCF.js.map} +1 -1
  42. package/dist/{chunk-AASLYRGE.js → chunk-UKKSMZYT.js} +18 -7
  43. package/dist/chunk-UKKSMZYT.js.map +1 -0
  44. package/dist/{chunk-VLYV65LK.js → chunk-W5L2JSBY.js} +5 -3
  45. package/dist/chunk-W5L2JSBY.js.map +1 -0
  46. package/dist/{chunk-PIDTEQ3U.js → chunk-Y45PPBDV.js} +2 -2
  47. package/dist/{chunk-PIDTEQ3U.js.map → chunk-Y45PPBDV.js.map} +1 -1
  48. package/dist/divider-sides-267FA7sY.d.ts +4 -0
  49. package/dist/index.d.ts +3 -1
  50. package/dist/index.js +16 -15
  51. package/dist/list-action-row.js +1 -1
  52. package/dist/list-header.js +1 -1
  53. package/dist/list-item.js +1 -1
  54. package/dist/list.d.ts +19 -0
  55. package/dist/list.js +3 -0
  56. package/dist/list.js.map +1 -0
  57. package/dist/nav-stack.js +1 -1
  58. package/dist/panel-header.js +1 -1
  59. package/dist/segmented-control.js +1 -1
  60. package/dist/select.js +1 -1
  61. package/dist/skeleton.d.ts +1 -1
  62. package/dist/skeleton.js +1 -1
  63. package/dist/split-view.js +1 -1
  64. package/dist/state-banner.d.ts +4 -2
  65. package/dist/state-banner.js +1 -1
  66. package/dist/styles/catalog.css +8 -2
  67. package/dist/styles/list-item.css +6 -6
  68. package/dist/styles/list.css +43 -0
  69. package/dist/styles/state-banner.css +32 -1
  70. package/dist/styles/styles.css +1 -0
  71. package/dist/styles/sunken-panel.css +4 -0
  72. package/dist/styles/toolbar.css +38 -2
  73. package/dist/sunken-panel.d.ts +5 -2
  74. package/dist/sunken-panel.js +1 -1
  75. package/dist/toolbar-text.js +1 -1
  76. package/dist/toolbar.d.ts +5 -3
  77. package/dist/toolbar.js +1 -1
  78. package/dist/value-table.js +1 -1
  79. package/dist/wire-catalog.d.ts +4 -2
  80. package/dist/wire-catalog.js +95 -36
  81. package/dist/wire-catalog.js.map +1 -1
  82. package/dist/wire-tab-bars.js +1 -1
  83. package/dist/wire-token-search-fields.d.ts +1 -1
  84. package/dist/wire-token-search-fields.js +1 -1
  85. package/docs/accessibility.md +12 -3
  86. package/docs/catalog.md +17 -12
  87. package/docs/component-contract.md +14 -1
  88. package/docs/component-selection.md +6 -2
  89. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  90. package/docs/design/templates/empty-state/filtered.svg +1 -1
  91. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  92. package/docs/design/templates/empty-state/with-action.svg +1 -1
  93. package/docs/design/templates/empty-state-dark.svg +1 -7
  94. package/docs/design/templates/empty-state.svg +1 -7
  95. package/docs/design/templates/list/compact-dark.svg +1 -0
  96. package/docs/design/templates/list/compact.svg +1 -0
  97. package/docs/design/templates/list/stack-dark.svg +1 -0
  98. package/docs/design/templates/list/stack.svg +1 -0
  99. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  100. package/docs/design/templates/list-action-row/default.svg +1 -1
  101. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  102. package/docs/design/templates/list-action-row/selected.svg +1 -1
  103. package/docs/design/templates/list-action-row-dark.svg +1 -7
  104. package/docs/design/templates/list-action-row.svg +1 -7
  105. package/docs/design/templates/list-dark.svg +1 -0
  106. package/docs/design/templates/list-header/action-dark.svg +1 -1
  107. package/docs/design/templates/list-header/action.svg +1 -1
  108. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -1
  109. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -1
  110. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  111. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  112. package/docs/design/templates/list-header-dark.svg +1 -11
  113. package/docs/design/templates/list-header.svg +1 -11
  114. package/docs/design/templates/list-item/default-dark.svg +1 -1
  115. package/docs/design/templates/list-item/default.svg +1 -1
  116. package/docs/design/templates/list-item/multiline-dark.svg +1 -1
  117. package/docs/design/templates/list-item/multiline.svg +1 -1
  118. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  119. package/docs/design/templates/list-item/selected.svg +1 -1
  120. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  121. package/docs/design/templates/list-item/trailing.svg +1 -1
  122. package/docs/design/templates/list-item-dark.svg +1 -11
  123. package/docs/design/templates/list-item.svg +1 -11
  124. package/docs/design/templates/list.svg +1 -0
  125. package/docs/design/templates/panel-header/icon-actions-dark.svg +1 -1
  126. package/docs/design/templates/panel-header/icon-actions.svg +1 -1
  127. package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +1 -1
  128. package/docs/design/templates/panel-header/icon-summary-actions.svg +1 -1
  129. package/docs/design/templates/panel-header-dark.svg +1 -13
  130. package/docs/design/templates/panel-header.svg +1 -13
  131. package/docs/design/templates/segmented-control-dark.svg +1 -7
  132. package/docs/design/templates/segmented-control.svg +1 -7
  133. package/docs/design/templates/skeleton-dark.svg +1 -9
  134. package/docs/design/templates/skeleton.svg +1 -9
  135. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  136. package/docs/design/templates/state-banner/danger.svg +1 -1
  137. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  138. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  139. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  140. package/docs/design/templates/state-banner/info.svg +1 -1
  141. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  142. package/docs/design/templates/state-banner/success.svg +1 -1
  143. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  144. package/docs/design/templates/state-banner/warning.svg +1 -1
  145. package/docs/design/templates/state-banner-dark.svg +1 -11
  146. package/docs/design/templates/state-banner.svg +1 -11
  147. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  148. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  149. package/docs/design/templates/tab-bar-dark.svg +1 -5
  150. package/docs/design/templates/tab-bar.svg +1 -5
  151. package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
  152. package/docs/design/templates/token-search-field/empty.svg +1 -1
  153. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -1
  154. package/docs/design/templates/token-search-field/tokens.svg +1 -1
  155. package/docs/design/templates/token-search-field-dark.svg +1 -7
  156. package/docs/design/templates/token-search-field.svg +1 -7
  157. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  158. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  159. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -1
  160. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -1
  161. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -1
  162. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -1
  163. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -1
  164. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -1
  165. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
  166. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
  167. package/docs/design/templates/toolbar-control-group-dark.svg +1 -11
  168. package/docs/design/templates/toolbar-control-group.svg +1 -11
  169. package/docs/design/templates/toolbar-dark.svg +1 -5
  170. package/docs/design/templates/toolbar-text-dark.svg +1 -9
  171. package/docs/design/templates/toolbar-text.svg +1 -9
  172. package/docs/design/templates/toolbar.svg +1 -5
  173. package/docs/design/templates/value-table/details-dark.svg +1 -1
  174. package/docs/design/templates/value-table/details.svg +1 -1
  175. package/docs/design/templates/value-table-dark.svg +1 -5
  176. package/docs/design/templates/value-table.svg +1 -5
  177. package/docs/design/templates.md +25 -14
  178. package/docs/sunken-panel.md +11 -1
  179. package/docs/type-contracts.md +6 -3
  180. package/docs/ui-doctor.md +6 -4
  181. package/docs/ux-demo.md +1 -1
  182. package/doctor/index.mjs +5 -2
  183. package/llms.txt +15 -3
  184. package/package.json +8 -2
  185. package/traversal-exclusions.mjs +7 -1
  186. package/ux-demo/recipes/collapsible-sidebar.tsx +1 -1
  187. package/ux-demo/recipes/navigation-sidebar.tsx +1 -1
  188. package/dist/chunk-7L6EHUMV.js.map +0 -1
  189. package/dist/chunk-AASLYRGE.js.map +0 -1
  190. package/dist/chunk-GP5DP5DL.js.map +0 -1
  191. package/dist/chunk-PZQVSDLH.js.map +0 -1
  192. package/dist/chunk-VLYV65LK.js.map +0 -1
  193. package/dist/chunk-W4CXQYSG.js.map +0 -1
@@ -10,7 +10,7 @@ component picture without running the app.
10
10
  ## Coverage
11
11
 
12
12
  Templated components (each with light + dark variants): `PanelHeader`,
13
- `ToolbarControlGroup`, `Toolbar`, `ToolbarText`, `ListItem`, `ListHeader`,
13
+ `ToolbarControlGroup`, `Toolbar`, `ToolbarText`, `List`, `ListItem`, `ListHeader`,
14
14
  `ListActionRow`, `ValueTable`, `StateBanner`, `EmptyState`, `Skeleton`,
15
15
  `SegmentedControl`, `TabBar`/`AppTab`, and `TokenSearchField`.
16
16
 
@@ -27,7 +27,7 @@ catalog and the app-layouts docs cover those.
27
27
 
28
28
  ```
29
29
  docs/design/templates/
30
- panel-header.svg ← library: every variant, inlined (light)
30
+ panel-header.svg ← library: every variant, composed (light)
31
31
  panel-header-dark.svg ← library: dark theme
32
32
  panel-header/
33
33
  icon-summary-actions.svg ← one self-contained variant (light)
@@ -50,13 +50,12 @@ docs/design/templates/
50
50
  kerf UI design font stack is system-based, so the picture matches; a viewer
51
51
  without those fonts falls back to its own.
52
52
  - The **library** files (`<component>.svg` light, `<component>-dark.svg` dark) lay
53
- the variants out with captions and embed an inline **copy** of each variant as a
54
- positioned nested `<svg>`. Each is fully self-contained and renders everywhere —
55
- a browser, an `<img>`, GitHub, or a static rasterizer. (External
56
- `<use href="…#id">` and `<image href="…">` references render blank in many SVG
57
- viewers, so the library inlines copies instead. Each copy's local ids and
58
- domotion font-family names are namespaced so the inlined variants don't collide
59
- in the one document; the individual variant files stay individually reusable.)
53
+ the variants out with captions. The generator writes a temporary HTML page whose
54
+ `<img>` elements reference the individual variant SVGs, then captures that page
55
+ with domotion and `--flatten-nested-svg`. The final library is self-contained,
56
+ contains positioned groups rather than nested `<svg>` elements, and remains
57
+ reliable in design tools such as Sketch. The individual variant files stay
58
+ independently reusable.
60
59
 
61
60
  ## Building
62
61
 
@@ -67,6 +66,9 @@ npm run design-templates:build
67
66
  This renders each component's real `SafeHtml` (with its CSS subpaths + `foundation.css`
68
67
  tokens and representative sample data) into a standalone page and captures it with
69
68
  [`domotion-svg`](https://github.com/brianwestphal/domotion)'s `domotion capture`.
69
+ The capture command uses `--flatten-nested-svg`, which converts safely flattenable
70
+ inline SVGs (including component icons) to groups so design tools such as Sketch do
71
+ not have to interpret nested `<svg>` elements.
70
72
  `domotion` must be reachable: it resolves `DOMOTION_BIN`, then a local
71
73
  `node_modules/.bin/domotion`, then a sibling `../domotion` checkout.
72
74
 
@@ -79,7 +81,9 @@ component can render with or without an icon, include both.
79
81
  `npm run check:design-templates` (part of `npm run check`) is an offline gate
80
82
  that verifies every component + variant in the manifest has its committed output —
81
83
  a light and dark SVG per variant plus the two per-component library files — and
82
- that no stray template files linger for a removed component. It does **not**
84
+ that no stray template files linger for a removed component. It also rejects any
85
+ variant or library capture that still contains nested `<svg>` elements, guarding
86
+ the Sketch compatibility contract. It does **not**
83
87
  re-render (that needs domotion + a browser), so it catches a manifest entry whose
84
88
  templates were never generated or a half-regenerated set.
85
89
 
@@ -109,11 +113,18 @@ starting point and:
109
113
  tokens and `layout.css`), and any of your own component CSS.
110
114
  3. Enumerate the presentation combinations in the per-component manifest.
111
115
  4. Capture each variant with `domotion capture <page.html> --selector <css>
112
- --text-mode system-font -o <variant>.svg`, once per theme with
116
+ --text-mode system-font --flatten-nested-svg -o <variant>.svg`, once per theme with
113
117
  `--color-scheme light` / `--color-scheme dark` (if your components theme with
114
- `light-dark()`), then write a light and a dark library file that each embed an
115
- inline copy of every variant (namespacing each copy's ids/font-family names so
116
- they don't collide) rather than referencing them, so they render everywhere.
118
+ `light-dark()`).
119
+ 5. Build a light and dark HTML library page that references the generated variants
120
+ with `<img src="./component/variant.svg">`, and capture each page with the same
121
+ domotion options, including `--flatten-nested-svg`. Let domotion own embedding,
122
+ id isolation, and flattening instead of hand-assembling SVG markup.
117
123
 
118
124
  Maintaining these next to the components — and reviewing the captured SVGs on
119
125
  every component change — keeps the design source of truth honest.
126
+
127
+ ListItem templates retain the shared 18px leading icon and 44px row target;
128
+ regenerate both themes and library sheets when that geometry changes. The browser
129
+ pane/sidebar geometry checks cover the resulting 43px icon-label offset from the
130
+ section edge (17px content inset + 18px icon + 8px gap).
@@ -14,6 +14,15 @@ import { SunkenPanel } from '@kerfjs/ui/sunken-panel';
14
14
  </SunkenPanel>;
15
15
  ```
16
16
 
17
+ The default `shape="rounded"` uses the shared rounded-rectangle radius. Choose
18
+ `shape="square"` for a flush or edge-to-edge area that needs `border-radius: 0`:
19
+
20
+ ```tsx
21
+ <SunkenPanel shape="square">
22
+ <Workspace />
23
+ </SunkenPanel>
24
+ ```
25
+
17
26
  ## Ownership
18
27
 
19
28
  The root owns its lowered background, 8px padding, and 8px vertical gap.
@@ -40,4 +49,5 @@ Override the public properties at the composition boundary:
40
49
  - `--kui-sunken-panel-radius`
41
50
 
42
51
  The public root class is `.kui-sunken-panel`. Prefer the properties above over
43
- styling descendants.
52
+ styling descendants. The `square` shape deliberately overrides the radius
53
+ property with zero; use `rounded` when customizing the radius token.
@@ -23,7 +23,7 @@ public-signature artifact.
23
23
  | `KUI-T008` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
24
24
  | `KUI-T009` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
25
25
  | `KUI-T010` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
26
- | `KUI-T011` | Finite public variants have named exported union types, including tab activation, banner urgency, and all ToolbarControlGroup presentation axes. |
26
+ | `KUI-T011` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all ToolbarControlGroup presentation axes. |
27
27
 
28
28
  Literal identity inference is intentionally additive for dynamic applications.
29
29
  When choices or ids arrive at runtime and the state signal is correctly typed as
@@ -48,7 +48,7 @@ ordinary source/type gates:
48
48
  `SegmentedControl`, `TokenSearchField`, `PanelHeader`, and `ValueTable`;
49
49
  - finite variants exported or represented as literal props on `DisclosureArrow`,
50
50
  `FloatingToolbar`, `Pane`, `ResizableRegion`, `SegmentedControl`, `StateBanner`,
51
- `ToolbarText`, `CollapsiblePanel`, `Catalog`, and the wire helpers;
51
+ `SunkenPanel`, `ToolbarText`, `CollapsiblePanel`, `Catalog`, and the wire helpers;
52
52
  - required controlled-state callbacks on `wireResizableRegions`, `wireTabBars`,
53
53
  and `wireTabScaffold`;
54
54
  - mutually exclusive count/badge metadata on `ListHeader`; and
@@ -58,7 +58,7 @@ ordinary source/type gates:
58
58
 
59
59
  The remaining components (`LucideIcon`, `DisclosureArrow`, `Toolbar`,
60
60
  `ToolbarControlGroup`, `ListInsetControl`, `ListInsetText`, `LoadingSpinner`,
61
- `Skeleton`, `SunkenPanel`, `EmptyState`, `StateBanner`, `ValueTableRow`, and the
61
+ `Skeleton`, `EmptyState`, `StateBanner`, `ValueTableRow`, and the
62
62
  pure helpers) have independent props with no further conditional invalid state
63
63
  that TypeScript can truthfully remove. Optional labels on decorative icons and
64
64
  unnamed non-landmark surfaces are intentional variants, not missing contracts.
@@ -94,6 +94,9 @@ move errors into casts without making the integration safer.
94
94
  wanted.
95
95
  - Remove orphaned `summaryId`, or render the matching `summary`; add
96
96
  `wrap: true` anywhere `ToolbarText.maxLines` is used.
97
+ - Replace `Toolbar({ divider: false })` with `dividerSides: ''`; the default
98
+ remains a bottom divider, while canonical combinations such as `tr` and
99
+ `trbl` select more physical edges.
97
100
 
98
101
  JavaScript runtime behavior remains defensive for previously emitted calls, but
99
102
  new TypeScript builds report these invalid or ignored combinations.
package/docs/ui-doctor.md CHANGED
@@ -25,10 +25,12 @@ An unavailable or failed stage does not prevent independent stages from reportin
25
25
 
26
26
  `--full` is the default and analyzes the selected package. `--changed` reads tracked and untracked paths from Git unless one or more `--path` values are supplied. An empty changed set is a configuration error instead of a false-clean success. With `--package`, workspace-relative Git paths are converted to package-relative paths before TypeScript, ESLint, and analyzer selection; paths outside the selected package are ignored.
27
27
 
28
- Full traversal treats nested `.claude/worktrees` checkouts as tool-owned
29
- repositories rather than application source. Their files are excluded
30
- consistently from TypeScript, ESLint, analyzer discovery, and cache inputs, even
31
- when the nested checkout lives below another application directory.
28
+ Full traversal treats generated/tool-owned directories (`dist`, `coverage`,
29
+ `node_modules`, `.git`, `.kerf-cache`, `kerf-ui-evidence`, and nested
30
+ `.claude/worktrees` checkouts) as outside application source. Their files are
31
+ excluded consistently from TypeScript, the isolated ESLint pass, analyzer
32
+ discovery, and cache inputs, even when one lives below another application
33
+ directory.
32
34
 
33
35
  TypeScript constructs the selected package's program so compiler options retain their real meaning, while its root inputs are narrowed to changed source files. Use `--full` for release gates.
34
36
 
package/docs/ux-demo.md CHANGED
@@ -21,7 +21,7 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
21
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`.
22
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.
23
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.
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; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; PanelHeader demonstrates its plain top-toolbar identity, extra-large title, optional subtitle row, and bordered brand-filled icon group; 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
+ - 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; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; PanelHeader demonstrates its plain top-toolbar identity, extra-large title, optional subtitle row, and bordered brand-filled icon group; 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 with tone-tinted badges plus a scoped override; TabBar demonstrates overflow, edge autoscroll, and controlled pointer/keyboard reordering.
25
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
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
27
  - The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
package/doctor/index.mjs CHANGED
@@ -24,7 +24,10 @@ import { loadApplicationUiProfile } from '../ai/application-ui-profile.mjs';
24
24
  import { analyzeUiProject, UI_ANALYSIS_RULES } from '../analyzer/index.mjs';
25
25
  import { evaluateUi, UI_EVALUATION_RULES } from '../evaluator/index.mjs';
26
26
  import { isForeignRuleDefinitionDiagnostic } from './eslint-diagnostics.mjs';
27
- import { isUiTraversalExcluded } from '../traversal-exclusions.mjs';
27
+ import {
28
+ isUiTraversalExcluded,
29
+ UI_TRAVERSAL_ESLINT_IGNORES,
30
+ } from '../traversal-exclusions.mjs';
28
31
 
29
32
  export const UI_DOCTOR_SCHEMA_VERSION = 1;
30
33
  export const UI_DOCTOR_EXIT = Object.freeze({
@@ -847,7 +850,7 @@ async function runEslint({
847
850
  },
848
851
  },
849
852
  };
850
- const configs = [{ ignores: ['**/.claude/worktrees/**'] }, base];
853
+ const configs = [{ ignores: UI_TRAVERSAL_ESLINT_IGNORES }, base];
851
854
  if (usesTypeScript) {
852
855
  const parserModule = await importFrom(
853
856
  packageRoot,
package/llms.txt CHANGED
@@ -52,7 +52,9 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
52
52
  6. **Before calling an integration complete**, run
53
53
  [`kerf-ui-doctor`](./docs/ui-doctor.md). Its portable JSON report merges
54
54
  profile/catalog, TypeScript, Kerf ESLint, and static analyzer diagnostics;
55
- repair source-located errors until exit 0. Use full mode for release gates.
55
+ repair source-located errors until exit 0. Use full mode for release gates;
56
+ generated `dist`/`coverage`, dependency, cache, evidence, and nested-worktree
57
+ directories are excluded consistently from every static stage.
56
58
  [`kerf-ui-analyze`](./docs/ui-analyzer.md) remains available when only static
57
59
  layout diagnostics are wanted; its review findings are a bounded human/AI
58
60
  review queue rather than an objective aesthetic score.
@@ -76,6 +78,10 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
76
78
  own the geometry (8px inline margin + 1px border + 8px padding). Do not add a
77
79
  container padding on top of a content-item's own margin — pick one owner. Use
78
80
  `.kui-content` for 24px major vertical rhythm.
81
+ - **Use `List` for vertical layout.** It supplies a stretch-aligned column plus
82
+ optional standard/custom `gap`, `flex`, vertical scrolling, and canonical
83
+ `dividerSides` (`t`/`r`/`b`/`l` order). It adds no list semantics; children own
84
+ those, and only one bounded region should own scrolling.
79
85
  - **Keep Web Awesome on the shared inset tiers.** `webawesome.css` uses
80
86
  `--kui-wa-control-inset` (8px controls/items) and
81
87
  `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside
@@ -127,9 +133,11 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
127
133
  navigation stacks, tab selection and order, pane sizes, and `collapsed`/`expanded`
128
134
  disclosure flags in the app — they are data or persisted layout, and the app reads
129
135
  them to render. The `wire…` helpers own the _ephemeral_ parts: `wireNavStack` the
130
- push/pop animation, `wireTabBars` the overflow autoscroll and drag preview,
136
+ push/pop animation, `wireTabBars` the overflow autoscroll, drag preview, and
137
+ replacement focus after controlled automatic tab activation,
131
138
  `wireResizableRegions` the live drag preview; they report committed changes via
132
- callbacks. The one richer case is `wireTokenSearchFields`, which manages the
139
+ callbacks. Managed TokenSearchField clear also preserves open state and replacement
140
+ editor focus for continued typing. The one richer case is `wireTokenSearchFields`, which manages the
133
141
  collapsible field's expand/collapse/focus by default (on, per-behavior opt-out) and
134
142
  exposes the `expanded` signal on its handle — bind it in render or hand in your own
135
143
  via `collapsible.signals`. Do not hand-roll open/collapse/focus that helper
@@ -150,6 +158,10 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
150
158
  markup. Use the standalone `Skeleton` for a custom slot. Prefer it over `wa-skeleton`
151
159
  (the pure-Kerf primitives avoid Web Awesome), and never animate it — use
152
160
  `LoadingSpinner` for known busy activity instead.
161
+ - **Use a StateBanner badge only for compact supporting status.** Pass the
162
+ optional string `badge` for a terse count or status beside the title. It
163
+ inherits the banner tone and is announced with the banner, so keep its text
164
+ meaningful and never rely on color alone.
153
165
 
154
166
  ## Public exports
155
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.23",
3
+ "version": "5.0.0-beta.24",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -74,6 +74,11 @@
74
74
  "browser": "./dist/browser/toolbar-text.js",
75
75
  "import": "./dist/toolbar-text.js"
76
76
  },
77
+ "./list": {
78
+ "types": "./dist/list.d.ts",
79
+ "browser": "./dist/browser/list.js",
80
+ "import": "./dist/list.js"
81
+ },
77
82
  "./list-action-row": {
78
83
  "types": "./dist/list-action-row.d.ts",
79
84
  "browser": "./dist/browser/list-action-row.js",
@@ -267,6 +272,7 @@
267
272
  "./toolbar-control-group.css": "./dist/styles/toolbar-control-group.css",
268
273
  "./floating-toolbar.css": "./dist/styles/floating-toolbar.css",
269
274
  "./toolbar-text.css": "./dist/styles/toolbar-text.css",
275
+ "./list.css": "./dist/styles/list.css",
270
276
  "./list-action-row.css": "./dist/styles/list-action-row.css",
271
277
  "./list-item.css": "./dist/styles/list-item.css",
272
278
  "./list-header.css": "./dist/styles/list-header.css",
@@ -377,7 +383,7 @@
377
383
  "@typescript-eslint/eslint-plugin": "^8.65.0",
378
384
  "@typescript-eslint/parser": "^8.65.0",
379
385
  "@vitest/coverage-v8": "4.1.11",
380
- "domotion-svg": "^0.29.0",
386
+ "domotion-svg": "^0.30.1",
381
387
  "esbuild": "^0.25.0",
382
388
  "eslint": "^10.8.0",
383
389
  "eslint-plugin-simple-import-sort": "^12.1.1",
@@ -1,6 +1,6 @@
1
1
  import { relative, sep } from 'node:path';
2
2
 
3
- const ignoredDirectoryNames = new Set([
3
+ export const UI_TRAVERSAL_IGNORED_DIRECTORY_NAMES = Object.freeze([
4
4
  '.git',
5
5
  '.kerf-cache',
6
6
  'coverage',
@@ -8,6 +8,12 @@ const ignoredDirectoryNames = new Set([
8
8
  'kerf-ui-evidence',
9
9
  'node_modules',
10
10
  ]);
11
+ const ignoredDirectoryNames = new Set(UI_TRAVERSAL_IGNORED_DIRECTORY_NAMES);
12
+
13
+ export const UI_TRAVERSAL_ESLINT_IGNORES = Object.freeze([
14
+ ...UI_TRAVERSAL_IGNORED_DIRECTORY_NAMES.map((name) => `**/${name}/**`),
15
+ '**/.claude/worktrees/**',
16
+ ]);
11
17
 
12
18
  export function isUiTraversalExcluded(root, candidate) {
13
19
  const segments = relative(root, candidate).split(sep);
@@ -160,7 +160,7 @@ export const createRecipe: RecipeFactory = (announce) => {
160
160
  >
161
161
  <Toolbar
162
162
  label="Activity"
163
- divider
163
+ dividerSides="b"
164
164
  leading={
165
165
  <ToolbarControlGroup appearance="borderless" single>
166
166
  <ToolbarText text="Activity" size="small" />
@@ -92,7 +92,7 @@ export const createRecipe: RecipeFactory = (announce) => {
92
92
  <footer class="recipe-sidebar__footer kui-pane__footer">
93
93
  <Toolbar
94
94
  label="Sidebar actions"
95
- divider={false}
95
+ dividerSides=""
96
96
  leading={
97
97
  <ToolbarControlGroup appearance="borderless" single>
98
98
  <button
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/toolbar.tsx"],"names":[],"mappings":";;;AAWO,SAAS,OAAA,CAAQ;AAAA,EACtB,OAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA,GAAU,IAAA;AAAA,EACV,SAAA,GAAY;AACd,CAAA,EAAiB;AACf,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MACvC,gBAAA,EAAe,SAAA;AAAA,MACf,cAAA,EAAc,OAAO,OAAO,CAAA;AAAA,MAC5B,iBAAA,EAAiB,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,MACvC,YAAA,EAAY,KAAA;AAAA,MAEZ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,sBAAA,EAAwB,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,wBAC3C,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,qBAAA,EAAuB,QAAA,EAAA,MAAA,EAAO,CAAA;AAAA,wBACzC,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAyB,QAAA,EAAA,QAAA,EAAS;AAAA;AAAA;AAAA,GAC/C;AAEJ","file":"chunk-7L6EHUMV.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport interface ToolbarProps {\n leading?: SafeHtml;\n center?: SafeHtml;\n trailing?: SafeHtml;\n label?: string;\n divider?: boolean;\n className?: string;\n}\n\nexport function Toolbar({\n leading,\n center,\n trailing,\n label,\n divider = true,\n className = '',\n}: ToolbarProps) {\n return (\n <header\n class={`kui-toolbar ${className}`.trim()}\n data-component=\"toolbar\"\n data-divider={String(divider)}\n data-has-center={String(Boolean(center))}\n aria-label={label}\n >\n <div class=\"kui-toolbar__leading\">{leading}</div>\n <div class=\"kui-toolbar__center\">{center}</div>\n <div class=\"kui-toolbar__trailing\">{trailing}</div>\n </header>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/wire-tab-bars.ts"],"names":[],"mappings":"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","file":"chunk-AASLYRGE.js","sourcesContent":["import type { TabActivation } from './tab-bar.js';\n\nexport type TabReorderSource = 'pointer' | 'keyboard';\nexport type TabDropPosition = 'before' | 'after';\n\nexport interface TabReorder {\n barId: string;\n sourceId: string;\n targetId: string;\n position: TabDropPosition;\n source: TabReorderSource;\n}\n\nexport type { TabActivation } from './tab-bar.js';\n\nexport interface WireTabBarsOptions {\n onReorder: (change: TabReorder) => void;\n /**\n * How arrow / Home / End keys activate tabs (default `'automatic'`):\n * - `'automatic'` moves roving focus **and** selects the focused tab (clicks it).\n * - `'manual'` moves roving focus only; the user selects with Enter / Space / click\n * (the ARIA Tabs manual-activation pattern). Use this when activation is a heavy or\n * side-effecting action (e.g. a tab that loads a project) so arrowing through the\n * strip doesn't trigger it on every tab.\n *\n * A per-bar `data-tab-activation=\"manual\" | \"automatic\"` attribute (see the `TabBar`\n * `activation` prop) overrides this option for that strip.\n */\n activation?: TabActivation;\n}\n\ntype TabRoot = HTMLElement;\ntype TabBarRoot = HTMLElement;\n\nconst AUTO_SCROLL_EDGE_PX = 56;\nconst AUTO_SCROLL_MIN_PX_PER_SECOND = 180;\nconst AUTO_SCROLL_MAX_PX_PER_SECOND = 900;\n\nexport function reorderTabs<T>(\n items: readonly T[],\n getId: (item: T) => string,\n sourceId: string,\n targetId: string,\n position: TabDropPosition,\n): T[] {\n if (sourceId === targetId) return [...items];\n const source = items.find((item) => getId(item) === sourceId);\n if (!source || !items.some((item) => getId(item) === targetId))\n return [...items];\n const remaining = items.filter((item) => getId(item) !== sourceId);\n const targetIndex = remaining.findIndex((item) => getId(item) === targetId);\n remaining.splice(targetIndex + (position === 'after' ? 1 : 0), 0, source);\n return remaining;\n}\n\nfunction tabRoot(target: EventTarget | null): TabRoot | undefined {\n return target instanceof Element\n ? (target.closest<TabRoot>('[data-component=\"app-tab\"]') ?? undefined)\n : undefined;\n}\n\nfunction tabBar(tab: TabRoot): TabBarRoot | undefined {\n return tab.closest<TabBarRoot>('[data-component=\"tab-bar\"]') ?? undefined;\n}\n\nfunction tabId(tab: TabRoot): string | undefined {\n return tab.dataset.tabId || undefined;\n}\n\nfunction barId(bar: TabBarRoot): string | undefined {\n return bar.dataset.tabBarId || undefined;\n}\n\nfunction positionFor(event: DragEvent, tab: TabRoot): TabDropPosition {\n const bounds = tab.getBoundingClientRect();\n return event.clientX < bounds.left + bounds.width / 2 ? 'before' : 'after';\n}\n\nfunction tabsIn(bar: TabBarRoot): HTMLButtonElement[] {\n return [\n ...bar.querySelectorAll<HTMLButtonElement>(\n '[data-kui-tab-list] [role=\"tab\"]',\n ),\n ];\n}\n\nfunction reveal(tab: HTMLElement | null | undefined): void {\n tab?.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n}\n\n/** Wire reordering and keyboard navigation while leaving controlled state in the application. */\nexport function wireTabBars(\n root: HTMLElement | Document,\n { onReorder, activation = 'automatic' }: WireTabBarsOptions,\n): () => void {\n const ownerDocument = (\n root.nodeType === 9 ? (root as Document) : root.ownerDocument\n )!;\n const view = ownerDocument.defaultView!;\n let autoScroll:\n | {\n strip: HTMLElement;\n velocity: number;\n frame: number | undefined;\n previousTime: number | undefined;\n }\n | undefined;\n const stopAutoScroll = () => {\n if (!autoScroll) return;\n if (autoScroll.frame !== undefined)\n view.cancelAnimationFrame(autoScroll.frame);\n delete autoScroll.strip.dataset.tabAutoscroll;\n autoScroll = undefined;\n };\n const runAutoScroll = (time: number) => {\n const current = autoScroll;\n if (!current) return;\n current.frame = undefined;\n const elapsed =\n current.previousTime === undefined\n ? 1000 / 60\n : Math.min(40, Math.max(1, time - current.previousTime));\n current.previousTime = time;\n const maximum = Math.max(\n 0,\n current.strip.scrollWidth - current.strip.clientWidth,\n );\n const previous = current.strip.scrollLeft;\n current.strip.scrollLeft = Math.max(\n 0,\n Math.min(maximum, previous + (current.velocity * elapsed) / 1000),\n );\n if (current.strip.scrollLeft === previous) {\n stopAutoScroll();\n return;\n }\n current.frame = view.requestAnimationFrame(runAutoScroll);\n };\n const updateAutoScroll = (event: DragEvent, strip: HTMLElement) => {\n if (strip.scrollWidth <= strip.clientWidth) {\n stopAutoScroll();\n return;\n }\n const bounds = strip.getBoundingClientRect();\n const edge = Math.min(AUTO_SCROLL_EDGE_PX, bounds.width / 3);\n const startDistance = event.clientX - bounds.left;\n const endDistance = bounds.right - event.clientX;\n let direction = 0;\n let strength = 0;\n if (startDistance >= 0 && startDistance < edge) {\n direction = -1;\n strength = 1 - startDistance / edge;\n } else if (endDistance >= 0 && endDistance < edge) {\n direction = 1;\n strength = 1 - endDistance / edge;\n }\n if (direction === 0) {\n stopAutoScroll();\n return;\n }\n const maximum = Math.max(0, strip.scrollWidth - strip.clientWidth);\n if (\n (direction < 0 && strip.scrollLeft <= 0) ||\n (direction > 0 && strip.scrollLeft >= maximum)\n ) {\n stopAutoScroll();\n return;\n }\n const speed =\n AUTO_SCROLL_MIN_PX_PER_SECOND +\n (AUTO_SCROLL_MAX_PX_PER_SECOND - AUTO_SCROLL_MIN_PX_PER_SECOND) *\n strength *\n strength;\n if (autoScroll?.strip !== strip) stopAutoScroll();\n autoScroll ??= {\n strip,\n velocity: 0,\n frame: undefined,\n previousTime: undefined,\n };\n autoScroll.velocity = direction * speed;\n strip.dataset.tabAutoscroll = direction < 0 ? 'start' : 'end';\n autoScroll.frame ??= view.requestAnimationFrame(runAutoScroll);\n };\n let dragged: { barId: string; tabId: string } | undefined;\n const clearDropPositions = () =>\n root\n .querySelectorAll<HTMLElement>('[data-tab-drop-position]')\n .forEach((tab) => delete tab.dataset.tabDropPosition);\n const clear = () => {\n stopAutoScroll();\n dragged = undefined;\n root\n .querySelectorAll<HTMLElement>(\n '[data-tab-dragging], [data-tab-drop-position]',\n )\n .forEach((tab) => {\n delete tab.dataset.tabDragging;\n delete tab.dataset.tabDropPosition;\n });\n };\n const afterControlledRender = (sourceBarId: string, sourceTabId: string) =>\n globalThis.queueMicrotask(() => {\n const tab = [\n ...root.querySelectorAll<TabRoot>('[data-component=\"app-tab\"]'),\n ].find((candidate) => {\n const candidateBar = tabBar(candidate);\n return (\n tabId(candidate) === sourceTabId &&\n candidateBar !== undefined &&\n barId(candidateBar) === sourceBarId\n );\n });\n const button = tab?.querySelector<HTMLButtonElement>('[role=\"tab\"]');\n button?.focus();\n reveal(button);\n });\n\n const onDragStart = (event: Event) => {\n const dragEvent = event as DragEvent;\n const tab = tabRoot(event.target);\n const bar = tab && tabBar(tab);\n const sourceId = tab && tabId(tab);\n const sourceBarId = bar && barId(bar);\n if (\n !tab ||\n tab.getAttribute('draggable') !== 'true' ||\n !sourceId ||\n !sourceBarId\n )\n return;\n dragged = { barId: sourceBarId, tabId: sourceId };\n tab.dataset.tabDragging = 'true';\n if (dragEvent.dataTransfer) {\n dragEvent.dataTransfer.effectAllowed = 'move';\n dragEvent.dataTransfer.setData(\n 'application/x-kerf-tab',\n `${sourceBarId}:${sourceId}`,\n );\n }\n };\n const onDragOver = (event: Event) => {\n const dragEvent = event as DragEvent;\n const tab = tabRoot(event.target);\n const bar =\n event.target instanceof Element\n ? (event.target.closest<TabBarRoot>('[data-component=\"tab-bar\"]') ??\n undefined)\n : undefined;\n const targetId = tab && tabId(tab);\n const targetBarId = bar && barId(bar);\n if (!dragged || !bar || targetBarId !== dragged.barId) {\n stopAutoScroll();\n clearDropPositions();\n return;\n }\n dragEvent.preventDefault();\n const strip = bar.querySelector<HTMLElement>('[data-kui-tab-list]');\n if (strip) updateAutoScroll(dragEvent, strip);\n else stopAutoScroll();\n clearDropPositions();\n if (!tab || !targetId || targetId === dragged.tabId) return;\n tab.dataset.tabDropPosition = positionFor(dragEvent, tab);\n if (dragEvent.dataTransfer) dragEvent.dataTransfer.dropEffect = 'move';\n };\n const onDrop = (event: Event) => {\n const dragEvent = event as DragEvent;\n const tab = tabRoot(event.target);\n const bar = tab && tabBar(tab);\n const targetId = tab && tabId(tab);\n const targetBarId = bar && barId(bar);\n if (\n !dragged ||\n !tab ||\n !targetId ||\n targetId === dragged.tabId ||\n targetBarId !== dragged.barId\n ) {\n clear();\n return;\n }\n dragEvent.preventDefault();\n const change: TabReorder = {\n barId: dragged.barId,\n sourceId: dragged.tabId,\n targetId,\n position: positionFor(dragEvent, tab),\n source: 'pointer',\n };\n clear();\n onReorder(change);\n afterControlledRender(change.barId, change.sourceId);\n };\n const onKeyDown = (event: Event) => {\n const keyboardEvent = event as KeyboardEvent;\n const button =\n event.target instanceof Element\n ? event.target.closest<HTMLButtonElement>('[role=\"tab\"]')\n : null;\n const tab = button && tabRoot(button);\n const bar = tab && tabBar(tab);\n if (!button || !tab || !bar) return;\n if (keyboardEvent.key === 'Delete' || keyboardEvent.key === 'Backspace') {\n const close = tab.querySelector<HTMLButtonElement>('.kui-app-tab__close');\n if (!close) return;\n keyboardEvent.preventDefault();\n close.click();\n return;\n }\n const tabs = tabsIn(bar);\n const current = tabs.indexOf(button);\n if (current < 0) return;\n if (\n keyboardEvent.altKey &&\n keyboardEvent.shiftKey &&\n (keyboardEvent.key === 'ArrowLeft' || keyboardEvent.key === 'ArrowRight')\n ) {\n const target =\n tabs[current + (keyboardEvent.key === 'ArrowLeft' ? -1 : 1)];\n const sourceId = tabId(tab);\n const targetRoot = target && tabRoot(target);\n const targetId = targetRoot && tabId(targetRoot);\n const sourceBarId = barId(bar);\n if (\n !target ||\n !sourceId ||\n !targetId ||\n !sourceBarId ||\n tab.getAttribute('draggable') !== 'true'\n )\n return;\n keyboardEvent.preventDefault();\n onReorder({\n barId: sourceBarId,\n sourceId,\n targetId,\n position: keyboardEvent.key === 'ArrowLeft' ? 'before' : 'after',\n source: 'keyboard',\n });\n afterControlledRender(sourceBarId, sourceId);\n return;\n }\n let next: number | undefined;\n if (keyboardEvent.key === 'ArrowRight') next = (current + 1) % tabs.length;\n else if (keyboardEvent.key === 'ArrowLeft')\n next = (current - 1 + tabs.length) % tabs.length;\n else if (keyboardEvent.key === 'Home') next = 0;\n else if (keyboardEvent.key === 'End') next = tabs.length - 1;\n if (next === undefined) return;\n keyboardEvent.preventDefault();\n // A per-bar data-tab-activation attribute overrides the wireTabBars option.\n const perBar = bar.dataset.tabActivation;\n const mode: TabActivation =\n perBar === 'manual' || perBar === 'automatic' ? perBar : activation;\n tabs[next]?.focus();\n // Manual activation moves roving focus only; the user selects with Enter / Space\n // (native on the tab <button>) or click. Automatic also selects the focused tab.\n if (mode === 'automatic') tabs[next]?.click();\n reveal(tabs[next]);\n };\n const onFocusIn = (event: Event) => {\n const tab =\n event.target instanceof HTMLElement &&\n event.target.matches('[role=\"tab\"]')\n ? event.target\n : undefined;\n reveal(tab);\n };\n\n root.addEventListener('dragstart', onDragStart);\n root.addEventListener('dragover', onDragOver);\n root.addEventListener('drop', onDrop);\n root.addEventListener('dragend', clear);\n root.addEventListener('keydown', onKeyDown);\n root.addEventListener('focusin', onFocusIn);\n root\n .querySelectorAll<HTMLElement>(\n '[data-kui-tab-list] [role=\"tab\"][aria-selected=\"true\"]',\n )\n .forEach(reveal);\n\n return () => {\n clear();\n root.removeEventListener('dragstart', onDragStart);\n root.removeEventListener('dragover', onDragOver);\n root.removeEventListener('drop', onDrop);\n root.removeEventListener('dragend', clear);\n root.removeEventListener('keydown', onKeyDown);\n root.removeEventListener('focusin', onFocusIn);\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/wire-token-search-fields.ts"],"names":["block"],"mappings":"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","file":"chunk-GP5DP5DL.js","sourcesContent":["import { delegate, type Signal, signal } from 'kerfjs';\n\nimport {\n placeTokenSearchCaret,\n readTokenSearchField,\n} from './token-search-field.js';\n\nexport interface TokenSearchSubmit {\n id: string;\n editor: HTMLElement;\n}\n\n/** Reported to {@link WireTokenSearchFieldsOptions.onEdit} on every editor input. */\nexport interface TokenSearchEdit extends TokenSearchSubmit {\n /**\n * The `InputEvent` that mutated the editor — read `event.inputType` / `event.data`\n * to gate commit behavior (e.g. only parse a chip on whitespace-terminated input)\n * without keeping a separate `input` listener.\n */\n event: InputEvent;\n}\n\n/** Reported when adjacent-token keyboard deletion asks the app to drop a chip. */\nexport interface TokenSearchTokenRemoval {\n id: string;\n /** The `data-token-value` of the token the app should remove from its state. */\n value: string;\n editor: HTMLElement;\n /** `'backward'` = the token before the caret (Backspace); `'forward'` = after (Delete). */\n direction: 'backward' | 'forward';\n}\n\n/**\n * Opt-in keyboard behavior for the atomic token chips. Off unless `keyboard` is\n * set; each piece defaults on once opted in. The helper never mutates app state:\n * a removal is reported through {@link TokenSearchKeyboardOptions.onRemoveToken}\n * for the caller to apply, while caret movement past a chip is a pure ephemeral\n * mechanic the helper performs itself.\n */\ninterface TokenSearchKeyboardBaseOptions {\n /**\n * From a collapsed caret with no selection, Backspace removes the token\n * immediately before it and Delete the token immediately after — reported via\n * `onRemoveToken` — instead of deleting a character. Default: true.\n */\n /**\n * ArrowRight moves the caret past a trailing atomic token so text typed next\n * lands after the chip. Default: true.\n */\n moveCaretPastToken?: boolean;\n /** Apply the reported removal to your controlled state, then re-render. */\n}\n\nexport type TokenSearchKeyboardOptions = TokenSearchKeyboardBaseOptions &\n (\n | {\n removeAdjacentToken?: true;\n /** Apply the reported removal to your controlled state, then re-render. */\n onRemoveToken: (removal: TokenSearchTokenRemoval) => void;\n }\n | { removeAdjacentToken: false; onRemoveToken?: never }\n );\n\n/**\n * Managed collapsible behavior for the iconic TokenSearchField. Every piece is on\n * by default; disable a specific one to own it in the app. Provide `signals` to\n * drive app-owned `expanded` signals per field id instead of helper-created ones.\n */\nexport interface TokenSearchCollapsibleOptions {\n /** Expand the field and focus its editor when the iconic trigger is activated. Default: true. */\n expandOnActivate?: boolean;\n /** Collapse the field when focus leaves it while it is empty. Default: true. */\n collapseOnEmptyBlur?: boolean;\n /** Collapse an empty field on Escape and restore focus to its trigger. Default: true. */\n collapseOnEscape?: boolean;\n /** Focus the editor on expand and the trigger on Escape-collapse. Default: true. */\n manageFocus?: boolean;\n /**\n * Keep an empty field expanded when focus moves to a caller-owned surface\n * rendered outside the field — a suggestions dropdown, date picker, or help\n * popover shown beside it. Return true for any focus target that must NOT\n * trigger collapse-on-empty-blur. An element carrying `data-token-search-keep-open`\n * (or any node inside one) is always exempt, so this predicate is only needed\n * for surfaces you cannot mark declaratively.\n */\n keepOpenOn?: (target: Node | null) => boolean;\n /** App-owned `expanded` signals keyed by field id; adopted instead of helper-created. */\n signals?: Readonly<Record<string, Signal<boolean>>>;\n}\n\nexport interface WireTokenSearchFieldsOptions {\n onSubmit?: (submission: TokenSearchSubmit) => void;\n /** Fired on every editor `input`, after the browser mutates it, so a caller can drop its own `input` listener. */\n onEdit?: (edit: TokenSearchEdit) => void;\n /** Managed collapsible transient behavior. `true`/omitted = on with defaults; `false` = fully off. */\n collapsible?: boolean | TokenSearchCollapsibleOptions;\n /** Opt-in atomic-chip keyboard behavior (off by default). */\n keyboard?: false | TokenSearchKeyboardOptions;\n}\n\n/**\n * The value returned from {@link wireTokenSearchFields}: call it (or `dispose()`) to\n * tear down. When collapsible behavior is managed, it also exposes the transient\n * `expanded` state per field id so the app can read it in render, hand in its own\n * signal, or drive it imperatively.\n */\nexport interface TokenSearchFieldsHandle {\n (): void;\n dispose(): void;\n /** The managed `expanded` signal for a field id (adopted or helper-created); undefined when unmanaged. */\n expanded(id: string): Signal<boolean> | undefined;\n /** Expand the field (and, when focus is managed, focus its editor). */\n open(id: string): void;\n /** Collapse the field (and, when focus is managed, restore focus to its trigger). */\n close(id: string): void;\n}\n\ninterface PendingTokenDeletion {\n id: string;\n offset: number;\n tokenCount: number;\n selectedAll: boolean;\n}\n\nfunction editorFromEvent(\n root: HTMLElement,\n event: Event,\n): HTMLElement | undefined {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const editor = target.closest<HTMLElement>('[data-token-search-editor]');\n return editor && root.contains(editor) ? editor : undefined;\n}\n\nfunction caretQueryOffset(editor: HTMLElement): number | undefined {\n const selection = editor.ownerDocument.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const selectionRange = selection.getRangeAt(0);\n if (!editor.contains(selectionRange.startContainer)) return;\n const prefixRange = editor.ownerDocument.createRange();\n prefixRange.selectNodeContents(editor);\n prefixRange.setEnd(selectionRange.startContainer, selectionRange.startOffset);\n const prefix = editor.ownerDocument.createElement('div');\n prefix.append(prefixRange.cloneContents());\n return readTokenSearchField(prefix).query.length;\n}\n\nfunction replacementEditor(\n root: HTMLElement,\n id: string,\n): HTMLElement | undefined {\n return [\n ...root.querySelectorAll<HTMLElement>('[data-token-search-editor]'),\n ].find((editor) => editor.dataset.tokenSearchEditor === id);\n}\n\nfunction editorIsEmpty(editor: HTMLElement): boolean {\n const value = readTokenSearchField(editor);\n return value.query.length === 0 && value.tokens.length === 0;\n}\n\n/** Whether the active selection covers all logical text and tokens in the editor. */\nfunction selectionCoversEditor(editor: HTMLElement): boolean {\n // onBeforeInput calls this only after caretQueryOffset verified a live range.\n const selected = editor.ownerDocument.getSelection()!.getRangeAt(0);\n if (selected.collapsed || !editor.contains(selected.commonAncestorContainer))\n return false;\n // Browser select-all ranges are not structurally identical across platforms:\n // some use editor child offsets while others start/end inside the first/last\n // text nodes. Compare the selected logical value instead of DOM boundaries.\n const selectedHost = editor.ownerDocument.createElement('div');\n selectedHost.append(selected.cloneContents());\n const fullValue = readTokenSearchField(editor);\n const selectedValue = readTokenSearchField(selectedHost);\n return (\n selectedValue.query === fullValue.query &&\n selectedValue.tokens.length === fullValue.tokens.length &&\n selectedValue.tokens.every(\n (token, index) => token.value === fullValue.tokens[index]?.value,\n )\n );\n}\n\nconst TOKEN_SELECTOR = '[data-component=\"token-search-token\"]';\nconst TEXT_SELECTOR = '[data-token-search-text]';\nconst stripZwsp = (text: string): string => text.replaceAll('​', '');\n\n/**\n * A `contenteditable` host emptied by select-all + Delete (or Backspace) leaves a\n * bogus `<br>` in every engine: it renders as a stray newline and `readTokenSearchField`\n * reads it back as a space. Strip those line breaks after a delete, and when the field\n * is otherwise empty (no chips, no visible text) restore the canonical empty text span\n * and place the caret in it so typing resumes cleanly. Called only after the browser has\n * applied the delete, so an ordinary partial delete is never touched.\n */\nfunction normalizeEmptiedEditor(\n editor: HTMLElement,\n selectedAll = false,\n): void {\n const lineBreaks = editor.querySelectorAll('br');\n if (lineBreaks.length === 0 && !selectedAll) return;\n for (const lineBreak of lineBreaks) lineBreak.remove();\n if (!selectedAll && editor.querySelector(TOKEN_SELECTOR)) return;\n if (!selectedAll && stripZwsp(editor.textContent ?? '') !== '') return;\n const doc = editor.ownerDocument;\n const span = doc.createElement('span');\n span.setAttribute('data-token-search-text', '');\n span.setAttribute('data-empty', 'true');\n editor.replaceChildren(span);\n if (doc.activeElement !== editor) return;\n // The editor is the focused, connected editing host, so a selection exists.\n const selection = doc.getSelection()!;\n const range = doc.createRange();\n range.setStart(span, 0);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n\n/** The collapsed, in-editor caret range, or undefined when there is a selection or none. */\nfunction collapsedCaret(editor: HTMLElement): Range | undefined {\n const selection = editor.ownerDocument.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (!range.collapsed || !editor.contains(range.startContainer)) return;\n return range;\n}\n\n/** The direct child of `editor` that contains `node` (or `node` itself), else null. */\nfunction topBlock(editor: HTMLElement, node: Node): Node | null {\n let current: Node = node;\n while (current.parentNode && current.parentNode !== editor)\n current = current.parentNode;\n return current.parentNode === editor ? current : null;\n}\n\n/** A text node or text span holding no visible character (only zero-width spacers). */\nfunction isBlankText(node: Node): boolean {\n if (node.nodeType === Node.TEXT_NODE)\n return stripZwsp((node as CharacterData).data) === '';\n return (\n node instanceof Element &&\n node.matches(TEXT_SELECTOR) &&\n stripZwsp(node.textContent ?? '') === ''\n );\n}\n\n/** The nearest sibling block on `direction`, skipping blank text spacers. */\nfunction meaningfulSibling(\n block: Node,\n direction: 'backward' | 'forward',\n): Node | null {\n let sibling =\n direction === 'backward' ? block.previousSibling : block.nextSibling;\n while (sibling && isBlankText(sibling))\n sibling =\n direction === 'backward' ? sibling.previousSibling : sibling.nextSibling;\n return sibling;\n}\n\n/** The node immediately on `direction` of the caret, only when no visible character separates them. */\nfunction caretSideNode(\n editor: HTMLElement,\n range: Range,\n direction: 'backward' | 'forward',\n): Node | null {\n const { startContainer: container, startOffset: offset } = range;\n if (container.nodeType === Node.TEXT_NODE) {\n const text = (container as CharacterData).data;\n const side =\n direction === 'backward' ? text.slice(0, offset) : text.slice(offset);\n if (stripZwsp(side).length > 0) return null;\n // An in-editor text node always has a top block (itself or its wrapping span).\n return meaningfulSibling(topBlock(editor, container)!, direction);\n }\n const child = container.childNodes[\n direction === 'backward' ? offset - 1 : offset\n ] as Node | undefined;\n if (child) {\n // `child` is a descendant of the in-editor caret container, so it has a top block.\n const block = topBlock(editor, child)!;\n return isBlankText(child) ? meaningfulSibling(block, direction) : block;\n }\n const block = topBlock(editor, container);\n return block ? meaningfulSibling(block, direction) : null;\n}\n\n/** The atomic token chip adjacent to a collapsed caret on `direction`, if any. */\nfunction adjacentToken(\n editor: HTMLElement,\n direction: 'backward' | 'forward',\n): HTMLElement | undefined {\n const range = collapsedCaret(editor);\n if (!range) return;\n const node = caretSideNode(editor, range, direction);\n if (!node) return;\n const base = node instanceof Element ? node : node.parentElement;\n const chip = base?.closest<HTMLElement>(TOKEN_SELECTOR) ?? null;\n return chip && editor.contains(chip) ? chip : undefined;\n}\n\n/** Move the caret to just after an atomic token chip so typed text lands after it.\n * Only reached after {@link collapsedCaret} already found a live selection, and the\n * chip is a direct block of the editor. */\nfunction placeCaretAfterToken(editor: HTMLElement, chip: HTMLElement): void {\n const selection = editor.ownerDocument.getSelection()!;\n const range = editor.ownerDocument.createRange();\n range.setStartAfter(topBlock(editor, chip)!);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n editor.focus({ preventScroll: true });\n}\n\n/**\n * Wire every TokenSearchField under `root`: submit on Enter, preserve the caret across\n * controlled token deletion, and (by default) manage the collapsible field's transient\n * expand/collapse/focus. Returns a {@link TokenSearchFieldsHandle} — a disposer that also\n * exposes the managed `expanded` state per field id.\n */\nexport function wireTokenSearchFields(\n root: HTMLElement,\n {\n onSubmit,\n onEdit,\n collapsible = true,\n keyboard = false,\n }: WireTokenSearchFieldsOptions = {},\n): TokenSearchFieldsHandle {\n const managed = collapsible !== false;\n const config = typeof collapsible === 'object' ? collapsible : {};\n const expandOnActivate = managed && (config.expandOnActivate ?? true);\n const collapseOnEmptyBlur = managed && (config.collapseOnEmptyBlur ?? true);\n const collapseOnEscape = managed && (config.collapseOnEscape ?? true);\n const manageFocus = managed && (config.manageFocus ?? true);\n const keepOpenOn = config.keepOpenOn;\n const keyboardOn = keyboard !== false;\n const keyboardConfig = typeof keyboard === 'object' ? keyboard : undefined;\n const removeAdjacentToken =\n keyboardOn && (keyboardConfig?.removeAdjacentToken ?? true);\n const moveCaretPastToken =\n keyboardOn && (keyboardConfig?.moveCaretPastToken ?? true);\n const onRemoveToken = keyboardConfig?.onRemoveToken;\n const adopted = config.signals ?? {};\n const created = new Map<string, Signal<boolean>>();\n\n /** True when focus moving to `element` should keep an empty field expanded. */\n const isExemptTarget = (element: Element | null): boolean => {\n if (!element) return false;\n if (element.closest('[data-token-search-keep-open]')) return true;\n return keepOpenOn ? keepOpenOn(element) : false;\n };\n\n const signalFor = (id: string): Signal<boolean> => {\n const own = adopted[id];\n if (own) return own;\n let field = created.get(id);\n if (!field) {\n field = signal(false);\n created.set(id, field);\n }\n return field;\n };\n const setExpanded = (id: string, next: boolean) => {\n const state = signalFor(id);\n if (state.value !== next) state.value = next;\n };\n const view = () => root.ownerDocument.defaultView!;\n const focusAfterRender = (id: string, selector: string) => {\n view().requestAnimationFrame(() => {\n const target = root.querySelector<HTMLElement>(\n `[data-component=\"token-search-field\"][data-token-search-id=\"${CSS.escape(id)}\"] ${selector}`,\n );\n if (!target) return;\n if (target.matches('[data-token-search-editor]'))\n placeTokenSearchCaret(target);\n else target.focus();\n });\n };\n const openField = (id: string) => {\n setExpanded(id, true);\n if (manageFocus) focusAfterRender(id, '[data-token-search-editor]');\n };\n const closeField = (id: string) => {\n setExpanded(id, false);\n if (manageFocus) focusAfterRender(id, '.kui-token-search__expand');\n };\n\n const pending = new Map<string, PendingTokenDeletion>();\n const selectAllIntents = new WeakSet<HTMLElement>();\n // editorFromEvent's selector guarantees this data attribute is present.\n const intentId = (editor: HTMLElement): string =>\n editor.dataset.tokenSearchEditor!;\n const onBeforeInput = (event: Event) => {\n const inputEvent = event as InputEvent;\n const editor = editorFromEvent(root, event);\n if (\n !editor ||\n !inputEvent.inputType.startsWith('delete') ||\n editor.ownerDocument.activeElement !== editor\n )\n return;\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n const offset = caretQueryOffset(editor);\n if (!id || offset === undefined || field?.dataset.disabled === 'true')\n return;\n pending.set(id, {\n id,\n offset,\n tokenCount: editor.querySelectorAll(\n '[data-component=\"token-search-token\"]',\n ).length,\n selectedAll: selectionCoversEditor(editor),\n });\n };\n const onInput = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (!editor) return;\n const editorId = intentId(editor);\n const deletion = pending.get(editorId);\n if ((event as InputEvent).inputType?.startsWith('delete'))\n normalizeEmptiedEditor(editor, deletion?.selectedAll);\n if (onEdit) {\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (id && field?.dataset.disabled !== 'true')\n onEdit({ id, editor, event: event as InputEvent });\n }\n pending.delete(editorId);\n if (\n !deletion ||\n editor.querySelectorAll('[data-component=\"token-search-token\"]').length >=\n deletion.tokenCount\n )\n return;\n editor.ownerDocument.defaultView!.requestAnimationFrame(() => {\n const replacement = replacementEditor(root, deletion.id);\n if (!replacement) return;\n const active = replacement.ownerDocument.activeElement;\n if (\n active !== editor &&\n active !== replacement &&\n active !== replacement.ownerDocument.body\n )\n return;\n placeTokenSearchCaret(replacement, deletion.offset);\n });\n };\n root.addEventListener('beforeinput', onBeforeInput, true);\n root.addEventListener('input', onInput, true);\n\n const clearSelectAllIntent = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (editor) selectAllIntents.delete(editor);\n };\n const trackSelectAllIntent = (event: Event) => {\n const keyboardEvent = event as KeyboardEvent;\n const editor = editorFromEvent(root, event);\n if (!editor || keyboardEvent.isComposing) return;\n const fullDeletionInputType =\n keyboardEvent.key === 'Backspace'\n ? 'deleteContentBackward'\n : keyboardEvent.key === 'Delete'\n ? 'deleteContentForward'\n : undefined;\n if (\n keyboardEvent.key.toLowerCase() === 'a' &&\n (keyboardEvent.ctrlKey || keyboardEvent.metaKey) &&\n !keyboardEvent.altKey &&\n !keyboardEvent.shiftKey\n ) {\n // Capture this before target/bubble handlers can stop propagation.\n selectAllIntents.add(editor);\n return;\n }\n if (fullDeletionInputType && selectAllIntents.delete(editor)) {\n if (editor.parentElement?.dataset.disabled === 'true') return;\n // Native mixed-contenteditable deletion is not reliable: Linux engines\n // can leave contenteditable=false chips behind, and a controlled render\n // then restores them from application state. The preceding shortcut is\n // an unambiguous full-delete request, so own that transition and publish\n // the same bubbling input contract the native edit would have produced.\n keyboardEvent.preventDefault();\n normalizeEmptiedEditor(editor, true);\n editor.dispatchEvent(\n new InputEvent('input', {\n bubbles: true,\n inputType: fullDeletionInputType,\n }),\n );\n return;\n }\n if (\n keyboardEvent.key === 'ArrowLeft' ||\n keyboardEvent.key === 'ArrowRight' ||\n keyboardEvent.key === 'ArrowUp' ||\n keyboardEvent.key === 'ArrowDown' ||\n keyboardEvent.key === 'Home' ||\n keyboardEvent.key === 'End' ||\n keyboardEvent.key === 'PageUp' ||\n keyboardEvent.key === 'PageDown'\n )\n selectAllIntents.delete(editor);\n };\n root.addEventListener('keydown', trackSelectAllIntent, true);\n root.addEventListener('pointerdown', clearSelectAllIntent, true);\n root.addEventListener('focusout', clearSelectAllIntent, true);\n\n const disposers: Array<() => void> = [\n () => root.removeEventListener('beforeinput', onBeforeInput, true),\n () => root.removeEventListener('input', onInput, true),\n () => root.removeEventListener('keydown', trackSelectAllIntent, true),\n () => root.removeEventListener('pointerdown', clearSelectAllIntent, true),\n () => root.removeEventListener('focusout', clearSelectAllIntent, true),\n ];\n\n disposers.push(\n delegate(\n root,\n 'keydown',\n '[data-token-search-editor]',\n (event, element) => {\n const keyboardEvent = event as KeyboardEvent;\n const editor = element as HTMLElement;\n if (keyboardEvent.isComposing) return;\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (!id || field?.dataset.disabled === 'true') return;\n if (keyboardEvent.key === 'Enter') {\n keyboardEvent.preventDefault();\n onSubmit?.({ id, editor });\n return;\n }\n if (\n removeAdjacentToken &&\n (keyboardEvent.key === 'Backspace' || keyboardEvent.key === 'Delete')\n ) {\n const direction =\n keyboardEvent.key === 'Backspace' ? 'backward' : 'forward';\n const chip = adjacentToken(editor, direction);\n if (chip) {\n keyboardEvent.preventDefault();\n onRemoveToken?.({\n id,\n value: chip.dataset.tokenValue ?? '',\n editor,\n direction,\n });\n return;\n }\n }\n if (moveCaretPastToken && keyboardEvent.key === 'ArrowRight') {\n const chip = adjacentToken(editor, 'forward');\n if (chip) {\n keyboardEvent.preventDefault();\n placeCaretAfterToken(editor, chip);\n return;\n }\n }\n if (\n collapseOnEscape &&\n keyboardEvent.key === 'Escape' &&\n field?.dataset.collapsible === 'true' &&\n editorIsEmpty(editor)\n ) {\n keyboardEvent.preventDefault();\n closeField(id);\n }\n },\n ),\n );\n\n if (expandOnActivate) {\n disposers.push(\n delegate(\n root,\n 'click',\n '.kui-token-search__expand',\n (_event, element) => {\n // The selector guarantees a collapsible field ancestor; only skip a disabled one.\n const field = (element as HTMLElement).closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (id && field?.dataset.disabled !== 'true') openField(id);\n },\n ),\n );\n }\n\n if (collapseOnEmptyBlur) {\n // Pressing an in-field control (clear, trailing, token, or the trigger) must not\n // blur the editor — otherwise the transient blur would collapse the field before\n // the control's own handler runs. Keeping focus also keeps the click firing.\n disposers.push(\n delegate(\n root,\n 'mousedown',\n '[data-component=\"token-search-field\"][data-collapsible=\"true\"] button',\n (event) => {\n event.preventDefault();\n },\n ),\n );\n disposers.push(\n delegate(\n root,\n 'focusout',\n '[data-token-search-editor]',\n (event, element) => {\n const editor = element as HTMLElement;\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (\n !id ||\n field?.dataset.collapsible !== 'true' ||\n field.dataset.disabled === 'true'\n )\n return;\n const next = (event as FocusEvent).relatedTarget;\n if (next instanceof Node && field.contains(next)) return;\n if (isExemptTarget(next instanceof Element ? next : null)) return;\n if (!editorIsEmpty(editor)) return;\n view().queueMicrotask(() => {\n const active = field.ownerDocument.activeElement;\n if (!field.contains(active) && !isExemptTarget(active))\n setExpanded(id, false);\n });\n },\n ),\n );\n }\n\n const dispose = () => {\n for (const stop of disposers.splice(0)) stop();\n };\n const handle = (() => dispose()) as TokenSearchFieldsHandle;\n handle.dispose = dispose;\n handle.expanded = (id) => (managed ? signalFor(id) : undefined);\n handle.open = (id) => {\n if (managed) openField(id);\n };\n handle.close = (id) => {\n if (managed) closeField(id);\n };\n return handle;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/skeleton.tsx"],"names":[],"mappings":";;;AAcA,SAAS,UAAA,CACP,KAAA,EACA,MAAA,EACA,MAAA,EACoB;AACpB,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,KAAA,IAAS,SAAS,KAAK,CAAA,CAAA;AAAA,IACvB,MAAA,IAAU,UAAU,MAAM,CAAA,CAAA;AAAA,IAC1B,MAAA,IAAU,yBAAyB,MAAM,CAAA;AAAA,GAC3C,CAAE,OAAO,OAAO,CAAA;AAChB,EAAA,OAAO,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AAC1C;AAQO,SAAS,QAAA,CAAS;AAAA,EACvB,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAAkB;AAChB,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,IAAA,EAAM,QAAQ,KAAA,GAAQ,MAAA;AAAA,IACtB,YAAA,EAAc,KAAA;AAAA,IACd,aAAA,EAAe,QAAQ,MAAA,GAAa;AAAA,GACtC;AACA,EAAA,IAAI,KAAA,IAAS,QAAQ,CAAA,EAAG;AACtB,IAAA,uBACE,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,CAAA,mBAAA,EAAsB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,QAC9C,gBAAA,EAAe,UAAA;AAAA,QACf,KAAA,EAAO,KAAA,GAAQ,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA,GAAK,MAAA;AAAA,QACjC,GAAG,IAAA;AAAA,QAEH,QAAA,EAAA,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,OAAM,EAAG,CAAC,GAAG,KAAA,qBACjC,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,cAAA;AAAA,YACN,aAAA,EAAY,MAAA;AAAA,YACZ,KAAA,EAAO,UAAA;AAAA,cACL,KAAA,KAAU,KAAA,GAAQ,CAAA,GAAI,KAAA,GAAQ,MAAA;AAAA,cAC9B,MAAA;AAAA,cACA;AAAA;AACF;AAAA,SAEH;AAAA;AAAA,KACH;AAAA,EAEJ;AACA,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,aAAA,EAAgB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MACxC,gBAAA,EAAe,UAAA;AAAA,MACf,KAAA,EAAO,UAAA,CAAW,KAAA,EAAO,MAAA,EAAQ,MAAM,CAAA;AAAA,MACtC,GAAG;AAAA;AAAA,GACL;AAEL","file":"chunk-PZQVSDLH.js","sourcesContent":["export interface SkeletonProps {\n /** Width as any CSS length (e.g. `remify(120px)`, `60%`). Defaults to filling its slot. */\n width?: string;\n /** Height as any CSS length. Defaults to a single text line. */\n height?: string;\n /** Corner radius override (a CSS length). Defaults to the small radius token. */\n radius?: string;\n /** Render this many stacked lines (the last one shorter), for multi-line text. */\n lines?: number;\n /** Accessible label. Omit to keep the block decorative (`aria-hidden`). */\n label?: string;\n className?: string;\n}\n\nfunction blockStyle(\n width?: string,\n height?: string,\n radius?: string,\n): string | undefined {\n const parts = [\n width && `width:${width}`,\n height && `height:${height}`,\n radius && `--kui-skeleton-radius:${radius}`,\n ].filter(Boolean);\n return parts.length ? parts.join(';') : undefined;\n}\n\n/**\n * A subtle, deliberately **unanimated** loading placeholder block. Use it for a\n * value slot whose content is not yet known, on its own or via a component's\n * `placeholder` prop. Decorative by default (`aria-hidden`); pass `label` to\n * announce it. Sizes to its slot unless `width`/`height` are given.\n */\nexport function Skeleton({\n width,\n height,\n radius,\n lines,\n label,\n className = '',\n}: SkeletonProps) {\n const a11y = {\n role: label ? 'img' : undefined,\n 'aria-label': label,\n 'aria-hidden': label ? undefined : ('true' as const),\n };\n if (lines && lines > 1) {\n return (\n <span\n class={`kui-skeleton-lines ${className}`.trim()}\n data-component=\"skeleton\"\n style={width ? `width:${width}` : undefined}\n {...a11y}\n >\n {Array.from({ length: lines }, (_, index) => (\n <span\n class=\"kui-skeleton\"\n aria-hidden=\"true\"\n style={blockStyle(\n index === lines - 1 ? '60%' : undefined,\n height,\n radius,\n )}\n ></span>\n ))}\n </span>\n );\n }\n return (\n <span\n class={`kui-skeleton ${className}`.trim()}\n data-component=\"skeleton\"\n style={blockStyle(width, height, radius)}\n {...a11y}\n ></span>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/state-banner.tsx"],"names":[],"mappings":";;;AAoBO,SAAS,WAAA,CAAY;AAAA,EAC1B,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA,GAAO,MAAA;AAAA,EACP,OAAA,GAAU,QAAA;AAAA,EACV,SAAA,GAAY,EAAA;AAAA,EACZ,WAAA,GAAc;AAChB,CAAA,EAAqB;AACnB,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC5C,gBAAA,EAAe,cAAA;AAAA,MACf,WAAA,EAAW,IAAA;AAAA,MACX,kBAAA,EAAkB,cAAc,MAAA,GAAS,MAAA;AAAA,MACzC,IAAA,EAAM,OAAA;AAAA,MACN,WAAA,EAAW,OAAA,KAAY,OAAA,GAAU,WAAA,GAAc,QAAA;AAAA,MAC/C,WAAA,EAAW,cAAc,MAAA,GAAS,MAAA;AAAA,MAEjC,QAAA,EAAA;AAAA,QAAA,IAAA,oBAAQ,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,wBAAA,EAA0B,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,wBACpD,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,wBAAA,EACT,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,YAAQ,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,YAAS,KAAA,EAAM,MAAA,EAAO,IAAK,KAAA,EAAM,CAAA;AAAA,UAAA,CACvD,WAAA,IAAe,MAAA,qBACf,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,WAAA,uBAAe,QAAA,EAAA,EAAS,KAAA,EAAM,MAAA,EAAO,CAAA,GAAK,MAAA,EAAO;AAAA,SAAA,EAE5D,CAAA;AAAA,QACC,MAAA,oBAAU,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,4BAA4B,QAAA,EAAA,MAAA,EAAO;AAAA;AAAA;AAAA,GAC3D;AAEJ","file":"chunk-VLYV65LK.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Skeleton } from './skeleton.js';\n\nexport type StateBannerTone =\n 'neutral' | 'info' | 'success' | 'warning' | 'danger';\nexport type StateBannerUrgency = 'status' | 'alert';\n\nexport interface StateBannerProps {\n title: string;\n detail?: string;\n icon?: SafeHtml;\n action?: SafeHtml;\n tone?: StateBannerTone;\n urgency?: StateBannerUrgency;\n className?: string;\n /** Render the title and detail as unanimated loading skeletons, keeping the icon and tone. */\n placeholder?: boolean;\n}\n\nexport function StateBanner({\n title,\n detail,\n icon,\n action,\n tone = 'info',\n urgency = 'status',\n className = '',\n placeholder = false,\n}: StateBannerProps) {\n return (\n <section\n class={`kui-state-banner ${className}`.trim()}\n data-component=\"state-banner\"\n data-tone={tone}\n data-placeholder={placeholder ? 'true' : undefined}\n role={urgency}\n aria-live={urgency === 'alert' ? 'assertive' : 'polite'}\n aria-busy={placeholder ? 'true' : undefined}\n >\n {icon && <span class=\"kui-state-banner__icon\">{icon}</span>}\n <div class=\"kui-state-banner__copy\">\n <strong>{placeholder ? <Skeleton width=\"10em\" /> : title}</strong>\n {(placeholder || detail) && (\n <span>{placeholder ? <Skeleton width=\"16em\" /> : detail}</span>\n )}\n </div>\n {action && <div class=\"kui-state-banner__action\">{action}</div>}\n </section>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/sunken-panel.tsx"],"names":[],"mappings":";;;AAcO,SAAS,WAAA,CAAY;AAAA,EAC1B,QAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAAqB;AACnB,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC5C,gBAAA,EAAe,cAAA;AAAA,MACf,IAAA,EAAM,YAAY,QAAA,GAAW,MAAA;AAAA,MAC7B,YAAA,EAAY,SAAA;AAAA,MAEX;AAAA;AAAA,GACH;AAEJ","file":"chunk-W4CXQYSG.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport interface SunkenPanelProps {\n children?: SafeHtml | readonly SafeHtml[];\n /** Optional accessible landmark name for a distinct application region. */\n ariaLabel?: string;\n className?: string;\n}\n\n/**\n * A lowered application surface with one compact inset and a vertical content\n * stack. The panel owns its background and padding; children own their own\n * borders and internal geometry.\n */\nexport function SunkenPanel({\n children,\n ariaLabel,\n className = '',\n}: SunkenPanelProps) {\n return (\n <div\n class={`kui-sunken-panel ${className}`.trim()}\n data-component=\"sunken-panel\"\n role={ariaLabel ? 'region' : undefined}\n aria-label={ariaLabel}\n >\n {children}\n </div>\n );\n}\n"]}