@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.18

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 (213) hide show
  1. package/README.md +108 -79
  2. package/ai/component-catalog-extension.schema.json +79 -0
  3. package/ai/component-catalog.json +499 -0
  4. package/ai/component-catalog.schema.json +15 -0
  5. package/ai/public-api-signatures-v1.md +67 -31
  6. package/ai/skill.md +58 -49
  7. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  8. package/dist/app-tab.d.ts +1 -1
  9. package/dist/app-tab.js +1 -1
  10. package/dist/catalog.d.ts +10 -3
  11. package/dist/catalog.js +279 -90
  12. package/dist/catalog.js.map +1 -1
  13. package/dist/chunk-43FUQH35.js +83 -0
  14. package/dist/chunk-43FUQH35.js.map +1 -0
  15. package/dist/{chunk-YGN7OMLT.js → chunk-4TRDV6RL.js} +2 -2
  16. package/dist/chunk-4TRDV6RL.js.map +1 -0
  17. package/dist/chunk-6ETZKKAE.js +38 -0
  18. package/dist/chunk-6ETZKKAE.js.map +1 -0
  19. package/dist/chunk-6WTETUZ6.js +21 -0
  20. package/dist/chunk-6WTETUZ6.js.map +1 -0
  21. package/dist/chunk-7L6EHUMV.js +31 -0
  22. package/dist/chunk-7L6EHUMV.js.map +1 -0
  23. package/dist/chunk-BBRXX6PF.js +108 -0
  24. package/dist/chunk-BBRXX6PF.js.map +1 -0
  25. package/dist/chunk-DPDBVKNA.js +113 -0
  26. package/dist/chunk-DPDBVKNA.js.map +1 -0
  27. package/dist/chunk-ELSJX4W7.js +68 -0
  28. package/dist/chunk-ELSJX4W7.js.map +1 -0
  29. package/dist/{chunk-6NLRBSVX.js → chunk-ENVTNLYC.js} +125 -68
  30. package/dist/chunk-ENVTNLYC.js.map +1 -0
  31. package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
  32. package/dist/chunk-FEY65TBV.js.map +1 -0
  33. package/dist/chunk-JTHUXDN2.js +58 -0
  34. package/dist/chunk-JTHUXDN2.js.map +1 -0
  35. package/dist/chunk-LPOMRC4C.js +25 -0
  36. package/dist/chunk-LPOMRC4C.js.map +1 -0
  37. package/dist/chunk-NENBUYX5.js +79 -0
  38. package/dist/chunk-NENBUYX5.js.map +1 -0
  39. package/dist/{chunk-XXMOARTH.js → chunk-NVWXKU37.js} +57 -16
  40. package/dist/chunk-NVWXKU37.js.map +1 -0
  41. package/dist/chunk-PIDTEQ3U.js +105 -0
  42. package/dist/chunk-PIDTEQ3U.js.map +1 -0
  43. package/dist/chunk-PX3YSS5C.js +32 -0
  44. package/dist/chunk-PX3YSS5C.js.map +1 -0
  45. package/dist/chunk-PZQVSDLH.js +61 -0
  46. package/dist/chunk-PZQVSDLH.js.map +1 -0
  47. package/dist/chunk-QIRXYKCE.js +113 -0
  48. package/dist/chunk-QIRXYKCE.js.map +1 -0
  49. package/dist/chunk-QO55FN2Y.js +20 -0
  50. package/dist/chunk-QO55FN2Y.js.map +1 -0
  51. package/dist/chunk-QQFJMRIB.js +45 -0
  52. package/dist/chunk-QQFJMRIB.js.map +1 -0
  53. package/dist/chunk-S3HKPI7I.js +218 -0
  54. package/dist/chunk-S3HKPI7I.js.map +1 -0
  55. package/dist/{chunk-WXMGNX2Y.js → chunk-S3PCZ7NV.js} +2 -2
  56. package/dist/chunk-S3PCZ7NV.js.map +1 -0
  57. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  58. package/dist/chunk-SRSJO5QE.js.map +1 -0
  59. package/dist/chunk-U5IFGQCD.js +117 -0
  60. package/dist/chunk-U5IFGQCD.js.map +1 -0
  61. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  62. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  63. package/dist/chunk-ZK2G3VR5.js +35 -0
  64. package/dist/chunk-ZK2G3VR5.js.map +1 -0
  65. package/dist/chunk-ZVI5YST2.js +41 -0
  66. package/dist/chunk-ZVI5YST2.js.map +1 -0
  67. package/dist/collapsible-panel.d.ts +2 -2
  68. package/dist/collapsible-panel.js +47 -6
  69. package/dist/collapsible-panel.js.map +1 -1
  70. package/dist/device-class.js +33 -5
  71. package/dist/device-class.js.map +1 -1
  72. package/dist/disclosure-arrow.js +1 -1
  73. package/dist/empty-state.d.ts +1 -1
  74. package/dist/empty-state.js +1 -1
  75. package/dist/floating-toolbar.d.ts +1 -1
  76. package/dist/floating-toolbar.js +1 -1
  77. package/dist/index.js +25 -25
  78. package/dist/list-action-row.d.ts +1 -1
  79. package/dist/list-action-row.js +1 -1
  80. package/dist/list-header.d.ts +1 -1
  81. package/dist/list-header.js +1 -1
  82. package/dist/list-inset-control.d.ts +1 -1
  83. package/dist/list-inset-control.js +1 -1
  84. package/dist/list-inset-text.d.ts +1 -1
  85. package/dist/list-inset-text.js +1 -1
  86. package/dist/list-item.d.ts +1 -1
  87. package/dist/list-item.js +1 -1
  88. package/dist/loading-spinner.js +1 -1
  89. package/dist/nav-stack.d.ts +1 -1
  90. package/dist/nav-stack.js +1 -1
  91. package/dist/panel-header.d.ts +1 -1
  92. package/dist/panel-header.js +1 -1
  93. package/dist/resizable-region.d.ts +1 -1
  94. package/dist/resizable-region.js +1 -1
  95. package/dist/segmented-control.js +1 -1
  96. package/dist/select.d.ts +1 -1
  97. package/dist/select.js +1 -1
  98. package/dist/skeleton.d.ts +1 -1
  99. package/dist/skeleton.js +1 -1
  100. package/dist/split-view.d.ts +1 -1
  101. package/dist/split-view.js +70 -10
  102. package/dist/split-view.js.map +1 -1
  103. package/dist/state-banner.d.ts +1 -1
  104. package/dist/state-banner.js +1 -1
  105. package/dist/styles/catalog.css +26 -0
  106. package/dist/tab-bar.d.ts +1 -1
  107. package/dist/tab-bar.js +1 -1
  108. package/dist/tab-scaffold.d.ts +1 -1
  109. package/dist/tab-scaffold.js +43 -8
  110. package/dist/tab-scaffold.js.map +1 -1
  111. package/dist/token-search-field.js +1 -1
  112. package/dist/toolbar-control-group.d.ts +1 -1
  113. package/dist/toolbar-control-group.js +1 -1
  114. package/dist/toolbar-text.js +1 -1
  115. package/dist/toolbar.d.ts +1 -1
  116. package/dist/toolbar.js +1 -1
  117. package/dist/value-table.d.ts +2 -2
  118. package/dist/value-table.js +1 -1
  119. package/dist/wire-catalog.d.ts +31 -2
  120. package/dist/wire-catalog.js +203 -8
  121. package/dist/wire-catalog.js.map +1 -1
  122. package/dist/wire-nav-stack.js +22 -7
  123. package/dist/wire-nav-stack.js.map +1 -1
  124. package/dist/wire-resizable-regions.d.ts +1 -1
  125. package/dist/wire-resizable-regions.js +1 -1
  126. package/dist/wire-sidebar.js +52 -41
  127. package/dist/wire-sidebar.js.map +1 -1
  128. package/dist/wire-tab-bars.js +1 -1
  129. package/dist/wire-tab-scaffold.js +9 -4
  130. package/dist/wire-tab-scaffold.js.map +1 -1
  131. package/dist/wire-token-search-fields.d.ts +1 -1
  132. package/dist/wire-token-search-fields.js +1 -1
  133. package/dist/workbench.d.ts +1 -1
  134. package/dist/workbench.js +56 -9
  135. package/dist/workbench.js.map +1 -1
  136. package/docs/app-layouts.md +7 -7
  137. package/docs/catalog.md +108 -24
  138. package/docs/collapsible-panel.md +38 -11
  139. package/docs/component-contract.md +30 -2
  140. package/docs/component-selection.md +71 -63
  141. package/docs/design/templates.md +1 -1
  142. package/docs/design-philosophy.md +5 -5
  143. package/docs/device-class.md +8 -8
  144. package/docs/examples/command-palette-adapter.tsx +67 -17
  145. package/docs/examples/component-catalog-extension.json +45 -0
  146. package/docs/layout.md +19 -19
  147. package/docs/nav-stack.md +15 -6
  148. package/docs/recipes.md +4 -4
  149. package/docs/split-view.md +3 -3
  150. package/docs/tab-scaffold.md +16 -7
  151. package/docs/webawesome-theme.md +8 -8
  152. package/docs/workbench.md +18 -5
  153. package/llms.txt +20 -14
  154. package/package.json +6 -4
  155. package/ux-demo/recipes/app-shell.tsx +206 -10
  156. package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
  157. package/ux-demo/recipes/compact-toolbar.tsx +114 -12
  158. package/ux-demo/recipes/composer-form.tsx +106 -18
  159. package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
  160. package/ux-demo/recipes/list-workspace-states.tsx +165 -8
  161. package/ux-demo/recipes/loaders.ts +5 -2
  162. package/ux-demo/recipes/loading-inspector.tsx +124 -41
  163. package/ux-demo/recipes/mount-recipe.ts +27 -6
  164. package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
  165. package/ux-demo/recipes/navigation-stack.tsx +61 -19
  166. package/ux-demo/recipes/types.ts +3 -1
  167. package/ux-demo/recipes/workspace-header.tsx +57 -2
  168. package/dist/chunk-2Z5TWHKQ.js +0 -34
  169. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  170. package/dist/chunk-37T3VNIZ.js +0 -19
  171. package/dist/chunk-37T3VNIZ.js.map +0 -1
  172. package/dist/chunk-55DATV3A.js +0 -10
  173. package/dist/chunk-55DATV3A.js.map +0 -1
  174. package/dist/chunk-5ATCDSQS.js +0 -42
  175. package/dist/chunk-5ATCDSQS.js.map +0 -1
  176. package/dist/chunk-5E2HVJ33.js +0 -10
  177. package/dist/chunk-5E2HVJ33.js.map +0 -1
  178. package/dist/chunk-6NLRBSVX.js.map +0 -1
  179. package/dist/chunk-7BR3DO2A.js.map +0 -1
  180. package/dist/chunk-7JB7VPRI.js +0 -34
  181. package/dist/chunk-7JB7VPRI.js.map +0 -1
  182. package/dist/chunk-7LDCTU7D.js +0 -134
  183. package/dist/chunk-7LDCTU7D.js.map +0 -1
  184. package/dist/chunk-AHQI52QO.js.map +0 -1
  185. package/dist/chunk-AQNKJRFH.js +0 -79
  186. package/dist/chunk-AQNKJRFH.js.map +0 -1
  187. package/dist/chunk-AVZHJN6C.js +0 -14
  188. package/dist/chunk-AVZHJN6C.js.map +0 -1
  189. package/dist/chunk-B24C4A6T.js +0 -22
  190. package/dist/chunk-B24C4A6T.js.map +0 -1
  191. package/dist/chunk-CH4SQ6H5.js +0 -39
  192. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  193. package/dist/chunk-DAFFDO33.js +0 -14
  194. package/dist/chunk-DAFFDO33.js.map +0 -1
  195. package/dist/chunk-I7INRJO4.js +0 -17
  196. package/dist/chunk-I7INRJO4.js.map +0 -1
  197. package/dist/chunk-L4OKFDJY.js +0 -24
  198. package/dist/chunk-L4OKFDJY.js.map +0 -1
  199. package/dist/chunk-M5JRI6MN.js +0 -27
  200. package/dist/chunk-M5JRI6MN.js.map +0 -1
  201. package/dist/chunk-RNPGFQ33.js +0 -10
  202. package/dist/chunk-RNPGFQ33.js.map +0 -1
  203. package/dist/chunk-VPCTCUED.js +0 -10
  204. package/dist/chunk-VPCTCUED.js.map +0 -1
  205. package/dist/chunk-WRTAQ7BZ.js +0 -23
  206. package/dist/chunk-WRTAQ7BZ.js.map +0 -1
  207. package/dist/chunk-WVPYVDXY.js +0 -15
  208. package/dist/chunk-WVPYVDXY.js.map +0 -1
  209. package/dist/chunk-WXMGNX2Y.js.map +0 -1
  210. package/dist/chunk-XXMOARTH.js.map +0 -1
  211. package/dist/chunk-YGN7OMLT.js.map +0 -1
  212. package/dist/chunk-ZQQ6P4SV.js +0 -20
  213. package/dist/chunk-ZQQ6P4SV.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { placeTokenSearchCaret, readTokenSearchField } from './chunk-7LDCTU7D.js';
1
+ import { placeTokenSearchCaret, readTokenSearchField } from './chunk-S3HKPI7I.js';
2
2
  import { delegate, signal } from 'kerfjs';
3
3
 
4
4
  function editorFromEvent(root, event) {
@@ -20,7 +20,9 @@ function caretQueryOffset(editor) {
20
20
  return readTokenSearchField(prefix).query.length;
21
21
  }
22
22
  function replacementEditor(root, id) {
23
- return [...root.querySelectorAll("[data-token-search-editor]")].find((editor) => editor.dataset.tokenSearchEditor === id);
23
+ return [
24
+ ...root.querySelectorAll("[data-token-search-editor]")
25
+ ].find((editor) => editor.dataset.tokenSearchEditor === id);
24
26
  }
25
27
  function editorIsEmpty(editor) {
26
28
  const value = readTokenSearchField(editor);
@@ -28,7 +30,8 @@ function editorIsEmpty(editor) {
28
30
  }
29
31
  function selectionCoversEditor(editor) {
30
32
  const selected = editor.ownerDocument.getSelection().getRangeAt(0);
31
- if (selected.collapsed || !editor.contains(selected.commonAncestorContainer)) return false;
33
+ if (selected.collapsed || !editor.contains(selected.commonAncestorContainer))
34
+ return false;
32
35
  const contents = editor.ownerDocument.createRange();
33
36
  contents.selectNodeContents(editor);
34
37
  const RangeCtor = editor.ownerDocument.defaultView.Range;
@@ -65,16 +68,19 @@ function collapsedCaret(editor) {
65
68
  }
66
69
  function topBlock(editor, node) {
67
70
  let current = node;
68
- while (current.parentNode && current.parentNode !== editor) current = current.parentNode;
71
+ while (current.parentNode && current.parentNode !== editor)
72
+ current = current.parentNode;
69
73
  return current.parentNode === editor ? current : null;
70
74
  }
71
75
  function isBlankText(node) {
72
- if (node.nodeType === Node.TEXT_NODE) return stripZwsp(node.data) === "";
76
+ if (node.nodeType === Node.TEXT_NODE)
77
+ return stripZwsp(node.data) === "";
73
78
  return node instanceof Element && node.matches(TEXT_SELECTOR) && stripZwsp(node.textContent ?? "") === "";
74
79
  }
75
80
  function meaningfulSibling(block, direction) {
76
81
  let sibling = direction === "backward" ? block.previousSibling : block.nextSibling;
77
- while (sibling && isBlankText(sibling)) sibling = direction === "backward" ? sibling.previousSibling : sibling.nextSibling;
82
+ while (sibling && isBlankText(sibling))
83
+ sibling = direction === "backward" ? sibling.previousSibling : sibling.nextSibling;
78
84
  return sibling;
79
85
  }
80
86
  function caretSideNode(editor, range, direction) {
@@ -111,7 +117,12 @@ function placeCaretAfterToken(editor, chip) {
111
117
  selection.addRange(range);
112
118
  editor.focus({ preventScroll: true });
113
119
  }
114
- function wireTokenSearchFields(root, { onSubmit, onEdit, collapsible = true, keyboard = false } = {}) {
120
+ function wireTokenSearchFields(root, {
121
+ onSubmit,
122
+ onEdit,
123
+ collapsible = true,
124
+ keyboard = false
125
+ } = {}) {
115
126
  const managed = collapsible !== false;
116
127
  const config = typeof collapsible === "object" ? collapsible : {};
117
128
  const expandOnActivate = managed && (config.expandOnActivate ?? true);
@@ -152,7 +163,8 @@ function wireTokenSearchFields(root, { onSubmit, onEdit, collapsible = true, key
152
163
  `[data-component="token-search-field"][data-token-search-id="${CSS.escape(id)}"] ${selector}`
153
164
  );
154
165
  if (!target) return;
155
- if (target.matches("[data-token-search-editor]")) placeTokenSearchCaret(target);
166
+ if (target.matches("[data-token-search-editor]"))
167
+ placeTokenSearchCaret(target);
156
168
  else target.focus();
157
169
  });
158
170
  };
@@ -168,15 +180,21 @@ function wireTokenSearchFields(root, { onSubmit, onEdit, collapsible = true, key
168
180
  const onBeforeInput = (event) => {
169
181
  const inputEvent = event;
170
182
  const editor = editorFromEvent(root, event);
171
- if (!editor || !inputEvent.inputType.startsWith("delete") || editor.ownerDocument.activeElement !== editor) return;
172
- const field = editor.closest('[data-component="token-search-field"]');
183
+ if (!editor || !inputEvent.inputType.startsWith("delete") || editor.ownerDocument.activeElement !== editor)
184
+ return;
185
+ const field = editor.closest(
186
+ '[data-component="token-search-field"]'
187
+ );
173
188
  const id = field?.dataset.tokenSearchId;
174
189
  const offset = caretQueryOffset(editor);
175
- if (!id || offset === void 0 || field?.dataset.disabled === "true") return;
190
+ if (!id || offset === void 0 || field?.dataset.disabled === "true")
191
+ return;
176
192
  pending.set(editor, {
177
193
  id,
178
194
  offset,
179
- tokenCount: editor.querySelectorAll('[data-component="token-search-token"]').length,
195
+ tokenCount: editor.querySelectorAll(
196
+ '[data-component="token-search-token"]'
197
+ ).length,
180
198
  selectedAll: selectionCoversEditor(editor)
181
199
  });
182
200
  };
@@ -184,19 +202,25 @@ function wireTokenSearchFields(root, { onSubmit, onEdit, collapsible = true, key
184
202
  const editor = editorFromEvent(root, event);
185
203
  if (!editor) return;
186
204
  const deletion = pending.get(editor);
187
- if (event.inputType?.startsWith("delete")) normalizeEmptiedEditor(editor, deletion?.selectedAll);
205
+ if (event.inputType?.startsWith("delete"))
206
+ normalizeEmptiedEditor(editor, deletion?.selectedAll);
188
207
  if (onEdit) {
189
- const field = editor.closest('[data-component="token-search-field"]');
208
+ const field = editor.closest(
209
+ '[data-component="token-search-field"]'
210
+ );
190
211
  const id = field?.dataset.tokenSearchId;
191
- if (id && field?.dataset.disabled !== "true") onEdit({ id, editor, event });
212
+ if (id && field?.dataset.disabled !== "true")
213
+ onEdit({ id, editor, event });
192
214
  }
193
215
  pending.delete(editor);
194
- if (!deletion || editor.querySelectorAll('[data-component="token-search-token"]').length >= deletion.tokenCount) return;
216
+ if (!deletion || editor.querySelectorAll('[data-component="token-search-token"]').length >= deletion.tokenCount)
217
+ return;
195
218
  editor.ownerDocument.defaultView.requestAnimationFrame(() => {
196
219
  const replacement = replacementEditor(root, deletion.id);
197
220
  if (!replacement) return;
198
221
  const active = replacement.ownerDocument.activeElement;
199
- if (active !== editor && active !== replacement && active !== replacement.ownerDocument.body) return;
222
+ if (active !== editor && active !== replacement && active !== replacement.ownerDocument.body)
223
+ return;
200
224
  placeTokenSearchCaret(replacement, deletion.offset);
201
225
  });
202
226
  };
@@ -207,71 +231,104 @@ function wireTokenSearchFields(root, { onSubmit, onEdit, collapsible = true, key
207
231
  () => root.removeEventListener("input", onInput, true)
208
232
  ];
209
233
  disposers.push(
210
- delegate(root, "keydown", "[data-token-search-editor]", (event, element) => {
211
- const keyboardEvent = event;
212
- const editor = element;
213
- if (keyboardEvent.isComposing) return;
214
- const field = editor.closest('[data-component="token-search-field"]');
215
- const id = field?.dataset.tokenSearchId;
216
- if (!id || field?.dataset.disabled === "true") return;
217
- if (keyboardEvent.key === "Enter") {
218
- keyboardEvent.preventDefault();
219
- onSubmit?.({ id, editor });
220
- return;
221
- }
222
- if (removeAdjacentToken && (keyboardEvent.key === "Backspace" || keyboardEvent.key === "Delete")) {
223
- const direction = keyboardEvent.key === "Backspace" ? "backward" : "forward";
224
- const chip = adjacentToken(editor, direction);
225
- if (chip) {
234
+ delegate(
235
+ root,
236
+ "keydown",
237
+ "[data-token-search-editor]",
238
+ (event, element) => {
239
+ const keyboardEvent = event;
240
+ const editor = element;
241
+ if (keyboardEvent.isComposing) return;
242
+ const field = editor.closest(
243
+ '[data-component="token-search-field"]'
244
+ );
245
+ const id = field?.dataset.tokenSearchId;
246
+ if (!id || field?.dataset.disabled === "true") return;
247
+ if (keyboardEvent.key === "Enter") {
226
248
  keyboardEvent.preventDefault();
227
- onRemoveToken?.({ id, value: chip.dataset.tokenValue ?? "", editor, direction });
249
+ onSubmit?.({ id, editor });
228
250
  return;
229
251
  }
230
- }
231
- if (moveCaretPastToken && keyboardEvent.key === "ArrowRight") {
232
- const chip = adjacentToken(editor, "forward");
233
- if (chip) {
252
+ if (removeAdjacentToken && (keyboardEvent.key === "Backspace" || keyboardEvent.key === "Delete")) {
253
+ const direction = keyboardEvent.key === "Backspace" ? "backward" : "forward";
254
+ const chip = adjacentToken(editor, direction);
255
+ if (chip) {
256
+ keyboardEvent.preventDefault();
257
+ onRemoveToken?.({
258
+ id,
259
+ value: chip.dataset.tokenValue ?? "",
260
+ editor,
261
+ direction
262
+ });
263
+ return;
264
+ }
265
+ }
266
+ if (moveCaretPastToken && keyboardEvent.key === "ArrowRight") {
267
+ const chip = adjacentToken(editor, "forward");
268
+ if (chip) {
269
+ keyboardEvent.preventDefault();
270
+ placeCaretAfterToken(editor, chip);
271
+ return;
272
+ }
273
+ }
274
+ if (collapseOnEscape && keyboardEvent.key === "Escape" && field?.dataset.collapsible === "true" && editorIsEmpty(editor)) {
234
275
  keyboardEvent.preventDefault();
235
- placeCaretAfterToken(editor, chip);
236
- return;
276
+ closeField(id);
237
277
  }
238
278
  }
239
- if (collapseOnEscape && keyboardEvent.key === "Escape" && field?.dataset.collapsible === "true" && editorIsEmpty(editor)) {
240
- keyboardEvent.preventDefault();
241
- closeField(id);
242
- }
243
- })
279
+ )
244
280
  );
245
281
  if (expandOnActivate) {
246
282
  disposers.push(
247
- delegate(root, "click", ".kui-token-search__expand", (_event, element) => {
248
- const field = element.closest('[data-component="token-search-field"]');
249
- const id = field?.dataset.tokenSearchId;
250
- if (id && field?.dataset.disabled !== "true") openField(id);
251
- })
283
+ delegate(
284
+ root,
285
+ "click",
286
+ ".kui-token-search__expand",
287
+ (_event, element) => {
288
+ const field = element.closest(
289
+ '[data-component="token-search-field"]'
290
+ );
291
+ const id = field?.dataset.tokenSearchId;
292
+ if (id && field?.dataset.disabled !== "true") openField(id);
293
+ }
294
+ )
252
295
  );
253
296
  }
254
297
  if (collapseOnEmptyBlur) {
255
298
  disposers.push(
256
- delegate(root, "mousedown", '[data-component="token-search-field"][data-collapsible="true"] button', (event) => {
257
- event.preventDefault();
258
- })
299
+ delegate(
300
+ root,
301
+ "mousedown",
302
+ '[data-component="token-search-field"][data-collapsible="true"] button',
303
+ (event) => {
304
+ event.preventDefault();
305
+ }
306
+ )
259
307
  );
260
308
  disposers.push(
261
- delegate(root, "focusout", "[data-token-search-editor]", (event, element) => {
262
- const editor = element;
263
- const field = editor.closest('[data-component="token-search-field"]');
264
- const id = field?.dataset.tokenSearchId;
265
- if (!id || field?.dataset.collapsible !== "true" || field.dataset.disabled === "true") return;
266
- const next = event.relatedTarget;
267
- if (next instanceof Node && field.contains(next)) return;
268
- if (isExemptTarget(next instanceof Element ? next : null)) return;
269
- if (!editorIsEmpty(editor)) return;
270
- view().queueMicrotask(() => {
271
- const active = field.ownerDocument.activeElement;
272
- if (!field.contains(active) && !isExemptTarget(active)) setExpanded(id, false);
273
- });
274
- })
309
+ delegate(
310
+ root,
311
+ "focusout",
312
+ "[data-token-search-editor]",
313
+ (event, element) => {
314
+ const editor = element;
315
+ const field = editor.closest(
316
+ '[data-component="token-search-field"]'
317
+ );
318
+ const id = field?.dataset.tokenSearchId;
319
+ if (!id || field?.dataset.collapsible !== "true" || field.dataset.disabled === "true")
320
+ return;
321
+ const next = event.relatedTarget;
322
+ if (next instanceof Node && field.contains(next)) return;
323
+ if (isExemptTarget(next instanceof Element ? next : null)) return;
324
+ if (!editorIsEmpty(editor)) return;
325
+ view().queueMicrotask(() => {
326
+ const active = field.ownerDocument.activeElement;
327
+ if (!field.contains(active) && !isExemptTarget(active))
328
+ setExpanded(id, false);
329
+ });
330
+ }
331
+ )
275
332
  );
276
333
  }
277
334
  const dispose = () => {
@@ -291,4 +348,4 @@ function wireTokenSearchFields(root, { onSubmit, onEdit, collapsible = true, key
291
348
 
292
349
  export { wireTokenSearchFields };
293
350
 
294
- //# sourceMappingURL=chunk-6NLRBSVX.js.map
351
+ //# sourceMappingURL=chunk-ENVTNLYC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/wire-token-search-fields.ts"],"names":["block"],"mappings":"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","file":"chunk-ENVTNLYC.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 */\nexport interface TokenSearchKeyboardOptions {\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 removeAdjacentToken?: boolean;\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 onRemoveToken?: (removal: TokenSearchTokenRemoval) => void;\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). `true` = on with defaults. */\n keyboard?: boolean | 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 every child of the editing host. */\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 const contents = editor.ownerDocument.createRange();\n contents.selectNodeContents(editor);\n const RangeCtor = editor.ownerDocument.defaultView!.Range;\n return (\n selected.compareBoundaryPoints(RangeCtor.START_TO_START, contents) <= 0 &&\n selected.compareBoundaryPoints(RangeCtor.END_TO_END, contents) >= 0\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 : {};\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 WeakMap<HTMLElement, PendingTokenDeletion>();\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(editor, {\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 deletion = pending.get(editor);\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(editor);\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 disposers: Array<() => void> = [\n () => root.removeEventListener('beforeinput', onBeforeInput, true),\n () => root.removeEventListener('input', onInput, 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,11 +1,15 @@
1
1
  import { jsx } from 'kerfjs/jsx-runtime';
2
2
 
3
3
  // src/list-inset-text.tsx
4
- function ListInsetText({ children, horizontalOnly = false, className = "" }) {
4
+ function ListInsetText({
5
+ children,
6
+ horizontalOnly = false,
7
+ className = ""
8
+ }) {
5
9
  const cls = `kui-list-inset-text${horizontalOnly ? " kui-list-inset-text--horizontal" : ""} ${className}`.trim();
6
10
  return /* @__PURE__ */ jsx("div", { class: cls, "data-component": "list-inset-text", children });
7
11
  }
8
12
 
9
13
  export { ListInsetText };
10
14
 
11
- //# sourceMappingURL=chunk-AHQI52QO.js.map
15
+ //# sourceMappingURL=chunk-FEY65TBV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/list-inset-text.tsx"],"names":[],"mappings":";;;AAuBO,SAAS,aAAA,CAAc;AAAA,EAC5B,QAAA;AAAA,EACA,cAAA,GAAiB,KAAA;AAAA,EACjB,SAAA,GAAY;AACd,CAAA,EAAuB;AACrB,EAAA,MAAM,GAAA,GACJ,sBAAsB,cAAA,GAAiB,kCAAA,GAAqC,EAAE,CAAA,CAAA,EAAI,SAAS,GAAG,IAAA,EAAK;AACrG,EAAA,2BACG,KAAA,EAAA,EAAI,KAAA,EAAO,GAAA,EAAK,gBAAA,EAAe,mBAC7B,QAAA,EACH,CAAA;AAEJ","file":"chunk-FEY65TBV.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport interface ListInsetTextProps {\n /** Text (or inline content) that carries no margin, border, or padding of its own. */\n children: SafeHtml | SafeHtml[] | string;\n /**\n * Keep only the horizontal geometry (inline margin, left/right border, and\n * left/right padding) and drop the vertical margin, border, and padding. Use it\n * when the text edge must still align with bordered items but the line should not\n * add its own vertical box space — tight text layout inside a content region.\n */\n horizontalOnly?: boolean;\n className?: string;\n}\n\n/**\n * Gives bare text the content-item geometry — an 8px inline margin, a 1px\n * transparent border, and 8px padding — so a plain string lines up with\n * bordered `.kui-content` items (its text edge lands at the same 17px inset).\n * Use it for text elements that have no margin, border, or padding of their own.\n * Pass `horizontalOnly` to keep the horizontal inset but drop the vertical box\n * space for tight text layout.\n */\nexport function ListInsetText({\n children,\n horizontalOnly = false,\n className = '',\n}: ListInsetTextProps) {\n const cls =\n `kui-list-inset-text${horizontalOnly ? ' kui-list-inset-text--horizontal' : ''} ${className}`.trim();\n return (\n <div class={cls} data-component=\"list-inset-text\">\n {children}\n </div>\n );\n}\n"]}
@@ -0,0 +1,58 @@
1
+ import { ToolbarText } from './chunk-S3PCZ7NV.js';
2
+ import { ToolbarControlGroup } from './chunk-ZK2G3VR5.js';
3
+ import { Toolbar } from './chunk-7L6EHUMV.js';
4
+ import { Skeleton } from './chunk-PZQVSDLH.js';
5
+ import { jsxs, jsx, Fragment } from 'kerfjs/jsx-runtime';
6
+
7
+ function PanelHeader({
8
+ title,
9
+ titleId,
10
+ summary,
11
+ summaryId,
12
+ icon,
13
+ iconClassName = "",
14
+ actions,
15
+ headingLevel,
16
+ placeholder = false
17
+ }) {
18
+ const identity = /* @__PURE__ */ jsxs(Fragment, { children: [
19
+ icon && /* @__PURE__ */ jsx(
20
+ ToolbarControlGroup,
21
+ {
22
+ single: true,
23
+ className: `kui-panel-header__icon ${iconClassName}`.trim(),
24
+ children: icon
25
+ }
26
+ ),
27
+ /* @__PURE__ */ jsx(
28
+ ToolbarText,
29
+ {
30
+ text: title,
31
+ size: "xlarge",
32
+ id: titleId,
33
+ className: "kui-panel-header__title",
34
+ headingLevel,
35
+ placeholder
36
+ }
37
+ )
38
+ ] });
39
+ return /* @__PURE__ */ jsxs(
40
+ "div",
41
+ {
42
+ class: "kui-panel-header",
43
+ "data-component": "panel-header",
44
+ "data-has-icon": String(Boolean(icon)),
45
+ "data-has-actions": String(Boolean(actions)),
46
+ "data-has-summary": String(Boolean(summary)),
47
+ "data-placeholder": placeholder ? "true" : void 0,
48
+ children: [
49
+ /* @__PURE__ */ jsx(Toolbar, { leading: identity, trailing: actions, divider: false }),
50
+ summary && /* @__PURE__ */ jsx("p", { class: "kui-panel-header__summary", id: summaryId, children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "18em" }) : summary })
51
+ ]
52
+ }
53
+ );
54
+ }
55
+
56
+ export { PanelHeader };
57
+
58
+ //# sourceMappingURL=chunk-JTHUXDN2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/panel-header.tsx"],"names":[],"mappings":";;;;;;AAsCO,SAAS,WAAA,CAAY;AAAA,EAC1B,KAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,IAAA;AAAA,EACA,aAAA,GAAgB,EAAA;AAAA,EAChB,OAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA,GAAc;AAChB,CAAA,EAAqB;AACnB,EAAA,MAAM,2BACJ,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,IAAA,oBACC,GAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QACC,MAAA,EAAM,IAAA;AAAA,QACN,SAAA,EAAW,CAAA,uBAAA,EAA0B,aAAa,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,QAEzD,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,oBAEF,GAAA;AAAA,MAAC,WAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,KAAA;AAAA,QACN,IAAA,EAAK,QAAA;AAAA,QACL,EAAA,EAAI,OAAA;AAAA,QACJ,SAAA,EAAU,yBAAA;AAAA,QACV,YAAA;AAAA,QACA;AAAA;AAAA;AACF,GAAA,EACF,CAAA;AAGF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,kBAAA;AAAA,MACN,gBAAA,EAAe,cAAA;AAAA,MACf,eAAA,EAAe,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAAA,MACnC,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA;AAAA,MACzC,kBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAC,CAAA;AAAA,MACzC,kBAAA,EAAkB,cAAc,MAAA,GAAS,MAAA;AAAA,MAEzC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,WAAQ,OAAA,EAAS,QAAA,EAAU,QAAA,EAAU,OAAA,EAAS,SAAS,KAAA,EAAO,CAAA;AAAA,QAC9D,OAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,KAAA,EAAM,2BAAA,EAA4B,EAAA,EAAI,SAAA,EACtC,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,MAAA,EAAO,IAAK,OAAA,EAC7C;AAAA;AAAA;AAAA,GAEJ;AAEJ","file":"chunk-JTHUXDN2.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Skeleton } from './skeleton.js';\nimport { Toolbar } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\nimport { type HeadingLevel, ToolbarText } from './toolbar-text.js';\n\nexport interface PanelHeaderProps {\n title: string;\n titleId: string;\n summary?: string;\n summaryId?: string;\n icon?: SafeHtml;\n iconClassName?: string;\n actions?: SafeHtml;\n /**\n * Expose the title as a heading landmark (`role=\"heading\"` + `aria-level`). Set it\n * for a PAGE or view heading so screen-reader heading navigation works and the view\n * has a primary heading; omit it (the default) for a dialog title, which is instead\n * referenced via `aria-labelledby={titleId}` and needs no heading landmark.\n */\n headingLevel?: HeadingLevel;\n /** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */\n placeholder?: boolean;\n}\n\n/**\n * The heading of a panel, dialog, or page: a plain `Toolbar` whose leading zone\n * holds an optional icon control group and the title as extra-large `ToolbarText`,\n * whose trailing zone holds the app's action controls, and with an optional\n * subtitle on its own row, left-aligned with the title.\n *\n * PanelHeader overrides no Toolbar styles — it is just a Toolbar with an xl title.\n * The only styling it adds is the icon group's fill/border color and the subtitle.\n * When no icon is provided, the icon group is omitted entirely. The `actions` slot\n * is passed straight into the toolbar's trailing zone; the app supplies whatever\n * trailing controls it needs (typically a `ToolbarControlGroup`).\n */\nexport function PanelHeader({\n title,\n titleId,\n summary,\n summaryId,\n icon,\n iconClassName = '',\n actions,\n headingLevel,\n placeholder = false,\n}: PanelHeaderProps) {\n const identity = (\n <>\n {icon && (\n <ToolbarControlGroup\n single\n className={`kui-panel-header__icon ${iconClassName}`.trim()}\n >\n {icon}\n </ToolbarControlGroup>\n )}\n <ToolbarText\n text={title}\n size=\"xlarge\"\n id={titleId}\n className=\"kui-panel-header__title\"\n headingLevel={headingLevel}\n placeholder={placeholder}\n />\n </>\n );\n\n return (\n <div\n class=\"kui-panel-header\"\n data-component=\"panel-header\"\n data-has-icon={String(Boolean(icon))}\n data-has-actions={String(Boolean(actions))}\n data-has-summary={String(Boolean(summary))}\n data-placeholder={placeholder ? 'true' : undefined}\n >\n <Toolbar leading={identity} trailing={actions} divider={false} />\n {summary && (\n <p class=\"kui-panel-header__summary\" id={summaryId}>\n {placeholder ? <Skeleton width=\"18em\" /> : summary}\n </p>\n )}\n </div>\n );\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { jsx } from 'kerfjs/jsx-runtime';
2
+
3
+ // src/floating-toolbar.tsx
4
+ function FloatingToolbar({
5
+ children,
6
+ label,
7
+ position = "bottom-end",
8
+ className = ""
9
+ }) {
10
+ return /* @__PURE__ */ jsx(
11
+ "div",
12
+ {
13
+ class: `kui-floating-toolbar ${className}`.trim(),
14
+ "data-component": "floating-toolbar",
15
+ "data-position": position,
16
+ role: "toolbar",
17
+ "aria-label": label,
18
+ children
19
+ }
20
+ );
21
+ }
22
+
23
+ export { FloatingToolbar };
24
+
25
+ //# sourceMappingURL=chunk-LPOMRC4C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/floating-toolbar.tsx"],"names":[],"mappings":";;;AA4BO,SAAS,eAAA,CAAgB;AAAA,EAC9B,QAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW,YAAA;AAAA,EACX,SAAA,GAAY;AACd,CAAA,EAAyB;AACvB,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,qBAAA,EAAwB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAChD,gBAAA,EAAe,kBAAA;AAAA,MACf,eAAA,EAAe,QAAA;AAAA,MACf,IAAA,EAAK,SAAA;AAAA,MACL,YAAA,EAAY,KAAA;AAAA,MAEX;AAAA;AAAA,GACH;AAEJ","file":"chunk-LPOMRC4C.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\n/** Where a {@link FloatingToolbar} floats within its positioned container. */\nexport type FloatingToolbarPosition =\n 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n\nexport interface FloatingToolbarProps {\n /** Toolbar contents — normally one or more `ToolbarControlGroup`s. */\n children: SafeHtml | SafeHtml[];\n /** Accessible name for the toolbar (required — it exposes `role=\"toolbar\"`). */\n label: string;\n /**\n * Corner or edge it floats to inside its nearest positioned ancestor.\n * Default: `'bottom-end'`.\n */\n position?: FloatingToolbarPosition;\n className?: string;\n}\n\n/**\n * A toolbar that floats above the main content of its nearest positioned\n * ancestor — a transparent, forced-dark cluster of controls (e.g. a drawer\n * restore button) that sits over the content but NOT over dialogs or overlays\n * (it is not in the top layer). It is inset from the container edges by\n * `--kui-floating-toolbar-inset` (default `--kui-space-m`, i.e. 8px more than a\n * top toolbar's own inset); override that token to move it. The app owns the\n * controls and their behavior — wire them with `delegate()` as usual.\n */\nexport function FloatingToolbar({\n children,\n label,\n position = 'bottom-end',\n className = '',\n}: FloatingToolbarProps) {\n return (\n <div\n class={`kui-floating-toolbar ${className}`.trim()}\n data-component=\"floating-toolbar\"\n data-position={position}\n role=\"toolbar\"\n aria-label={label}\n >\n {children}\n </div>\n );\n}\n"]}
@@ -0,0 +1,79 @@
1
+ import { jsxs, jsx, Fragment } from 'kerfjs/jsx-runtime';
2
+
3
+ // src/resizable-region.tsx
4
+ var clampRegionSize = (size, min, max) => Math.min(max, Math.max(min, Math.round(size)));
5
+ var resizeRegionFromPointer = (startSize, delta, edge) => startSize + delta * (edge === "start" ? -1 : 1);
6
+ function ResizeGrip({ axis }) {
7
+ return /* @__PURE__ */ jsx(
8
+ "svg",
9
+ {
10
+ "aria-hidden": "true",
11
+ viewBox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ "stroke-width": "2",
15
+ "stroke-linecap": "round",
16
+ children: axis === "horizontal" ? /* @__PURE__ */ jsxs(Fragment, { children: [
17
+ /* @__PURE__ */ jsx("path", { d: "M9 6v12" }),
18
+ /* @__PURE__ */ jsx("path", { d: "M15 6v12" })
19
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
20
+ /* @__PURE__ */ jsx("path", { d: "M6 9h12" }),
21
+ /* @__PURE__ */ jsx("path", { d: "M6 15h12" })
22
+ ] })
23
+ }
24
+ );
25
+ }
26
+ function ResizableRegion({
27
+ id,
28
+ label,
29
+ size,
30
+ min,
31
+ max,
32
+ axis = "horizontal",
33
+ edge = "end",
34
+ collapsed = false,
35
+ transitioning = false,
36
+ handleIcon,
37
+ children
38
+ }) {
39
+ const expandedSize = clampRegionSize(size, min, max);
40
+ const resolved = collapsed ? 0 : expandedSize;
41
+ const orientation = axis === "horizontal" ? "vertical" : "horizontal";
42
+ return /* @__PURE__ */ jsxs(
43
+ "section",
44
+ {
45
+ class: "kui-resizable-region",
46
+ "data-component": "resizable-region",
47
+ "data-region-id": id,
48
+ "data-axis": axis,
49
+ "data-edge": edge,
50
+ "data-collapsed": String(collapsed),
51
+ "data-transitioning": String(transitioning),
52
+ style: `--kui-resizable-region-size:${resolved}px;--kui-resizable-region-expanded-size:${expandedSize}px`,
53
+ "aria-label": label,
54
+ children: [
55
+ /* @__PURE__ */ jsx("div", { class: "kui-resizable-region__content", children }),
56
+ /* @__PURE__ */ jsx(
57
+ "div",
58
+ {
59
+ class: "kui-resizable-region__handle",
60
+ role: "separator",
61
+ tabindex: "0",
62
+ "aria-label": `Resize ${label}`,
63
+ "aria-orientation": orientation,
64
+ "aria-valuemin": collapsed ? 0 : min,
65
+ "aria-valuemax": max,
66
+ "aria-valuenow": resolved,
67
+ "data-kui-resize-handle": true,
68
+ "data-region-id": id,
69
+ children: /* @__PURE__ */ jsx("span", { class: "kui-resizable-region__handle-icon", "aria-hidden": "true", children: handleIcon ?? /* @__PURE__ */ jsx(ResizeGrip, { axis }) })
70
+ }
71
+ )
72
+ ]
73
+ }
74
+ );
75
+ }
76
+
77
+ export { ResizableRegion, clampRegionSize, resizeRegionFromPointer };
78
+
79
+ //# sourceMappingURL=chunk-NENBUYX5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resizable-region.tsx"],"names":[],"mappings":";;;AAoBO,IAAM,eAAA,GAAkB,CAAC,IAAA,EAAc,GAAA,EAAa,QACzD,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,GAAA,EAAK,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAC;AACxC,IAAM,uBAAA,GAA0B,CACrC,SAAA,EACA,KAAA,EACA,SACG,SAAA,GAAY,KAAA,IAAS,IAAA,KAAS,OAAA,GAAU,EAAA,GAAK,CAAA;AAElD,SAAS,UAAA,CAAW,EAAE,IAAA,EAAK,EAAkC;AAC3D,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAY,MAAA;AAAA,MACZ,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,MAAA,EAAO,cAAA;AAAA,MACP,cAAA,EAAa,GAAA;AAAA,MACb,gBAAA,EAAe,OAAA;AAAA,MAEd,QAAA,EAAA,IAAA,KAAS,+BACR,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,SAAA,EAAU,CAAA;AAAA,wBAClB,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,UAAA,EAAW;AAAA,OAAA,EACrB,oBAEA,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,SAAA,EAAU,CAAA;AAAA,wBAClB,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,UAAA,EAAW;AAAA,OAAA,EACrB;AAAA;AAAA,GAEJ;AAEJ;AAEO,SAAS,eAAA,CAAgB;AAAA,EAC9B,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA,GAAO,YAAA;AAAA,EACP,IAAA,GAAO,KAAA;AAAA,EACP,SAAA,GAAY,KAAA;AAAA,EACZ,aAAA,GAAgB,KAAA;AAAA,EAChB,UAAA;AAAA,EACA;AACF,CAAA,EAAyB;AACvB,EAAA,MAAM,YAAA,GAAe,eAAA,CAAgB,IAAA,EAAM,GAAA,EAAK,GAAG,CAAA;AACnD,EAAA,MAAM,QAAA,GAAW,YAAY,CAAA,GAAI,YAAA;AACjC,EAAA,MAAM,WAAA,GAAc,IAAA,KAAS,YAAA,GAAe,UAAA,GAAa,YAAA;AACzD,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,sBAAA;AAAA,MACN,gBAAA,EAAe,kBAAA;AAAA,MACf,gBAAA,EAAgB,EAAA;AAAA,MAChB,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAW,IAAA;AAAA,MACX,gBAAA,EAAgB,OAAO,SAAS,CAAA;AAAA,MAChC,oBAAA,EAAoB,OAAO,aAAa,CAAA;AAAA,MACxC,KAAA,EAAO,CAAA,4BAAA,EAA+B,QAAQ,CAAA,wCAAA,EAA2C,YAAY,CAAA,EAAA,CAAA;AAAA,MACrG,YAAA,EAAY,KAAA;AAAA,MAEZ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,+BAAA,EAAiC,QAAA,EAAS,CAAA;AAAA,wBACrD,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,8BAAA;AAAA,YACN,IAAA,EAAK,WAAA;AAAA,YACL,QAAA,EAAS,GAAA;AAAA,YACT,YAAA,EAAY,UAAU,KAAK,CAAA,CAAA;AAAA,YAC3B,kBAAA,EAAkB,WAAA;AAAA,YAClB,eAAA,EAAe,YAAY,CAAA,GAAI,GAAA;AAAA,YAC/B,eAAA,EAAe,GAAA;AAAA,YACf,eAAA,EAAe,QAAA;AAAA,YACf,wBAAA,EAAsB,IAAA;AAAA,YACtB,gBAAA,EAAgB,EAAA;AAAA,YAEhB,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,mCAAA,EAAoC,aAAA,EAAY,QACzD,QAAA,EAAA,UAAA,oBAAc,GAAA,CAAC,UAAA,EAAA,EAAW,IAAA,EAAY,CAAA,EACzC;AAAA;AAAA;AACF;AAAA;AAAA,GACF;AAEJ","file":"chunk-NENBUYX5.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport type ResizableRegionAxis = 'horizontal' | 'vertical';\nexport type ResizableRegionEdge = 'start' | 'end';\n\nexport interface ResizableRegionProps {\n id: string;\n label: string;\n size: number;\n min: number;\n max: number;\n axis?: ResizableRegionAxis;\n edge?: ResizableRegionEdge;\n collapsed?: boolean;\n transitioning?: boolean;\n /** Decorative dormant content for the separator handle. Must not contain interactive descendants. */\n handleIcon?: SafeHtml;\n children: SafeHtml | SafeHtml[];\n}\n\nexport const clampRegionSize = (size: number, min: number, max: number) =>\n Math.min(max, Math.max(min, Math.round(size)));\nexport const resizeRegionFromPointer = (\n startSize: number,\n delta: number,\n edge: ResizableRegionEdge,\n) => startSize + delta * (edge === 'start' ? -1 : 1);\n\nfunction ResizeGrip({ axis }: { axis: ResizableRegionAxis }) {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n >\n {axis === 'horizontal' ? (\n <>\n <path d=\"M9 6v12\"></path>\n <path d=\"M15 6v12\"></path>\n </>\n ) : (\n <>\n <path d=\"M6 9h12\"></path>\n <path d=\"M6 15h12\"></path>\n </>\n )}\n </svg>\n );\n}\n\nexport function ResizableRegion({\n id,\n label,\n size,\n min,\n max,\n axis = 'horizontal',\n edge = 'end',\n collapsed = false,\n transitioning = false,\n handleIcon,\n children,\n}: ResizableRegionProps) {\n const expandedSize = clampRegionSize(size, min, max);\n const resolved = collapsed ? 0 : expandedSize;\n const orientation = axis === 'horizontal' ? 'vertical' : 'horizontal';\n return (\n <section\n class=\"kui-resizable-region\"\n data-component=\"resizable-region\"\n data-region-id={id}\n data-axis={axis}\n data-edge={edge}\n data-collapsed={String(collapsed)}\n data-transitioning={String(transitioning)}\n style={`--kui-resizable-region-size:${resolved}px;--kui-resizable-region-expanded-size:${expandedSize}px`}\n aria-label={label}\n >\n <div class=\"kui-resizable-region__content\">{children}</div>\n <div\n class=\"kui-resizable-region__handle\"\n role=\"separator\"\n tabindex=\"0\"\n aria-label={`Resize ${label}`}\n aria-orientation={orientation}\n aria-valuemin={collapsed ? 0 : min}\n aria-valuemax={max}\n aria-valuenow={resolved}\n data-kui-resize-handle\n data-region-id={id}\n >\n <span class=\"kui-resizable-region__handle-icon\" aria-hidden=\"true\">\n {handleIcon ?? <ResizeGrip axis={axis} />}\n </span>\n </div>\n </section>\n );\n}\n"]}