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

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 (156) hide show
  1. package/README.md +9 -8
  2. package/ai/component-catalog.json +379 -174
  3. package/ai/public-api-signatures-v1.md +387 -33
  4. package/ai/skill.md +15 -7
  5. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  6. package/dist/app-tab.d.ts +3 -1
  7. package/dist/app-tab.js +2 -1
  8. package/dist/browser/app-tab.js +1 -0
  9. package/dist/browser/menu-action-row.js +1 -0
  10. package/dist/browser/menu-header.js +1 -0
  11. package/dist/browser/menu-item.js +1 -0
  12. package/dist/browser/panel-header.js +7 -0
  13. package/dist/browser/segmented-control.js +1 -0
  14. package/dist/browser/select.js +1 -0
  15. package/dist/browser/skeleton.js +3 -0
  16. package/dist/browser/state-banner.js +1 -0
  17. package/dist/browser/toolbar-text.js +1 -0
  18. package/dist/browser/value-table.js +1 -0
  19. package/dist/chunk-2RJBFNB6.js +172 -0
  20. package/dist/chunk-2RJBFNB6.js.map +1 -0
  21. package/dist/{chunk-XZXRLY5Q.js → chunk-2Z5TWHKQ.js} +7 -6
  22. package/dist/chunk-2Z5TWHKQ.js.map +1 -0
  23. package/dist/{chunk-EGHL5S4P.js → chunk-3YD6ZNRA.js} +8 -7
  24. package/dist/chunk-3YD6ZNRA.js.map +1 -0
  25. package/dist/chunk-B24C4A6T.js +22 -0
  26. package/dist/chunk-B24C4A6T.js.map +1 -0
  27. package/dist/{chunk-NPPD2A6O.js → chunk-H6URQGJI.js} +8 -6
  28. package/dist/chunk-H6URQGJI.js.map +1 -0
  29. package/dist/chunk-I7INRJO4.js +17 -0
  30. package/dist/chunk-I7INRJO4.js.map +1 -0
  31. package/dist/chunk-KJYXOTG3.js +10 -0
  32. package/dist/chunk-KJYXOTG3.js.map +1 -0
  33. package/dist/{chunk-CTQKI2XL.js → chunk-LC3YSAZC.js} +14 -3
  34. package/dist/chunk-LC3YSAZC.js.map +1 -0
  35. package/dist/chunk-N3SUXLLS.js +23 -0
  36. package/dist/chunk-N3SUXLLS.js.map +1 -0
  37. package/dist/{chunk-R6JHHBKQ.js → chunk-PONXLV5U.js} +5 -5
  38. package/dist/chunk-PONXLV5U.js.map +1 -0
  39. package/dist/chunk-TZNCCM5H.js +20 -0
  40. package/dist/chunk-TZNCCM5H.js.map +1 -0
  41. package/dist/{chunk-TRNBHPNW.js → chunk-YGN7OMLT.js} +11 -8
  42. package/dist/chunk-YGN7OMLT.js.map +1 -0
  43. package/dist/chunk-YKUUZPED.js +24 -0
  44. package/dist/chunk-YKUUZPED.js.map +1 -0
  45. package/dist/device-class.d.ts +62 -0
  46. package/dist/device-class.js +75 -0
  47. package/dist/device-class.js.map +1 -0
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.js +15 -15
  50. package/dist/menu-action-row.d.ts +3 -1
  51. package/dist/menu-action-row.js +2 -1
  52. package/dist/menu-header.d.ts +3 -1
  53. package/dist/menu-header.js +2 -1
  54. package/dist/menu-item.d.ts +3 -1
  55. package/dist/menu-item.js +2 -1
  56. package/dist/nav-stack.d.ts +38 -0
  57. package/dist/nav-stack.js +5 -0
  58. package/dist/nav-stack.js.map +1 -0
  59. package/dist/panel-header.d.ts +28 -0
  60. package/dist/panel-header.js +7 -0
  61. package/dist/panel-header.js.map +1 -0
  62. package/dist/segmented-control.d.ts +3 -1
  63. package/dist/segmented-control.js +2 -1
  64. package/dist/select.d.ts +5 -2
  65. package/dist/select.js +2 -1
  66. package/dist/skeleton.d.ts +24 -0
  67. package/dist/skeleton.js +3 -0
  68. package/dist/skeleton.js.map +1 -0
  69. package/dist/split-view.d.ts +42 -0
  70. package/dist/split-view.js +21 -0
  71. package/dist/split-view.js.map +1 -0
  72. package/dist/state-banner.d.ts +3 -1
  73. package/dist/state-banner.js +2 -1
  74. package/dist/styles/foundation.css +21 -0
  75. package/dist/styles/menu-header.css +19 -2
  76. package/dist/styles/nav-stack.css +112 -0
  77. package/dist/styles/panel-header.css +64 -0
  78. package/dist/styles/select.css +42 -0
  79. package/dist/styles/skeleton.css +31 -0
  80. package/dist/styles/split-view.css +35 -0
  81. package/dist/styles/styles.css +2 -2
  82. package/dist/styles/tab-scaffold.css +84 -0
  83. package/dist/styles/toolbar-control-group.css +52 -2
  84. package/dist/styles/toolbar-text.css +11 -0
  85. package/dist/styles/toolbar.css +9 -0
  86. package/dist/styles/workbench.css +94 -0
  87. package/dist/tab-scaffold.d.ts +30 -0
  88. package/dist/tab-scaffold.js +16 -0
  89. package/dist/tab-scaffold.js.map +1 -0
  90. package/dist/toolbar-text.d.ts +6 -2
  91. package/dist/toolbar-text.js +2 -1
  92. package/dist/value-table.d.ts +3 -1
  93. package/dist/value-table.js +2 -1
  94. package/dist/wire-nav-stack.d.ts +15 -0
  95. package/dist/wire-nav-stack.js +88 -0
  96. package/dist/wire-nav-stack.js.map +1 -0
  97. package/dist/wire-tab-scaffold.d.ts +11 -0
  98. package/dist/wire-tab-scaffold.js +16 -0
  99. package/dist/wire-tab-scaffold.js.map +1 -0
  100. package/dist/wire-token-search-fields.d.ts +46 -4
  101. package/dist/wire-token-search-fields.js +1 -1
  102. package/dist/workbench.d.ts +33 -0
  103. package/dist/workbench.js +17 -0
  104. package/dist/workbench.js.map +1 -0
  105. package/docs/accessibility.md +10 -10
  106. package/docs/app-layouts.md +57 -0
  107. package/docs/component-contract.md +46 -9
  108. package/docs/component-selection.md +57 -7
  109. package/docs/design-philosophy.md +23 -1
  110. package/docs/device-class.md +54 -0
  111. package/docs/layout.md +33 -8
  112. package/docs/nav-stack.md +47 -0
  113. package/docs/recipes.md +17 -5
  114. package/docs/split-view.md +49 -0
  115. package/docs/tab-scaffold.md +41 -0
  116. package/docs/ux-demo.md +3 -3
  117. package/docs/workbench.md +47 -0
  118. package/llms.txt +116 -43
  119. package/package.json +43 -11
  120. package/ux-demo/recipes/app-shell.tsx +3 -3
  121. package/ux-demo/recipes/composer-form.tsx +2 -2
  122. package/ux-demo/recipes/list-workspace-states.tsx +2 -2
  123. package/ux-demo/recipes/loaders.ts +2 -0
  124. package/ux-demo/recipes/master-detail-dialog.tsx +2 -2
  125. package/ux-demo/recipes/mount-recipe.ts +3 -0
  126. package/ux-demo/recipes/navigation-stack.tsx +76 -0
  127. package/ux-demo/recipes/recipes.css +19 -8
  128. package/ux-demo/recipes/workspace-header.tsx +2 -2
  129. package/dist/browser/dialog-header.js +0 -5
  130. package/dist/browser/page-header.js +0 -3
  131. package/dist/chunk-2PES33HS.js +0 -13
  132. package/dist/chunk-2PES33HS.js.map +0 -1
  133. package/dist/chunk-CTQKI2XL.js.map +0 -1
  134. package/dist/chunk-EGHL5S4P.js.map +0 -1
  135. package/dist/chunk-GY5WH7TO.js +0 -10
  136. package/dist/chunk-GY5WH7TO.js.map +0 -1
  137. package/dist/chunk-H5AGGVU5.js +0 -75
  138. package/dist/chunk-H5AGGVU5.js.map +0 -1
  139. package/dist/chunk-K3G72I6D.js +0 -24
  140. package/dist/chunk-K3G72I6D.js.map +0 -1
  141. package/dist/chunk-NPPD2A6O.js.map +0 -1
  142. package/dist/chunk-R6JHHBKQ.js.map +0 -1
  143. package/dist/chunk-S3TPM2LP.js +0 -23
  144. package/dist/chunk-S3TPM2LP.js.map +0 -1
  145. package/dist/chunk-TRNBHPNW.js.map +0 -1
  146. package/dist/chunk-VHW5YNIB.js +0 -17
  147. package/dist/chunk-VHW5YNIB.js.map +0 -1
  148. package/dist/chunk-XZXRLY5Q.js.map +0 -1
  149. package/dist/dialog-header.d.ts +0 -15
  150. package/dist/dialog-header.js +0 -5
  151. package/dist/dialog-header.js.map +0 -1
  152. package/dist/page-header.d.ts +0 -9
  153. package/dist/page-header.js +0 -3
  154. package/dist/page-header.js.map +0 -1
  155. package/dist/styles/dialog-header.css +0 -87
  156. package/dist/styles/page-header.css +0 -33
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/app-tab.css';
3
4
  export * from '../app-tab.js';
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/menu-action-row.css';
3
4
  export * from '../menu-action-row.js';
@@ -1,5 +1,6 @@
1
1
  import '../styles/foundation.css';
2
2
  import '../styles/lucide-icon.css';
3
3
  import '../styles/disclosure-arrow.css';
4
+ import '../styles/skeleton.css';
4
5
  import '../styles/menu-header.css';
5
6
  export * from '../menu-header.js';
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/menu-item.css';
3
4
  export * from '../menu-item.js';
@@ -0,0 +1,7 @@
1
+ import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
3
+ import '../styles/toolbar.css';
4
+ import '../styles/toolbar-control-group.css';
5
+ import '../styles/toolbar-text.css';
6
+ import '../styles/panel-header.css';
7
+ export * from '../panel-header.js';
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/segmented-control.css';
3
4
  export * from '../segmented-control.js';
@@ -1,4 +1,5 @@
1
1
  import '../styles/foundation.css';
2
2
  import '../styles/lucide-icon.css';
3
+ import '../styles/skeleton.css';
3
4
  import '../styles/select.css';
4
5
  export * from '../select.js';
@@ -0,0 +1,3 @@
1
+ import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
3
+ export * from '../skeleton.js';
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/state-banner.css';
3
4
  export * from '../state-banner.js';
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/toolbar-text.css';
3
4
  export * from '../toolbar-text.js';
@@ -1,3 +1,4 @@
1
1
  import '../styles/foundation.css';
2
+ import '../styles/skeleton.css';
2
3
  import '../styles/value-table.css';
3
4
  export * from '../value-table.js';
@@ -0,0 +1,172 @@
1
+ import { placeTokenSearchCaret, readTokenSearchField } from './chunk-7LDCTU7D.js';
2
+ import { delegate, signal } from 'kerfjs';
3
+
4
+ function editorFromEvent(root, event) {
5
+ const target = event.target;
6
+ if (!(target instanceof Element)) return;
7
+ const editor = target.closest("[data-token-search-editor]");
8
+ return editor && root.contains(editor) ? editor : void 0;
9
+ }
10
+ function caretQueryOffset(editor) {
11
+ const selection = editor.ownerDocument.getSelection();
12
+ if (!selection || selection.rangeCount === 0) return;
13
+ const selectionRange = selection.getRangeAt(0);
14
+ if (!editor.contains(selectionRange.startContainer)) return;
15
+ const prefixRange = editor.ownerDocument.createRange();
16
+ prefixRange.selectNodeContents(editor);
17
+ prefixRange.setEnd(selectionRange.startContainer, selectionRange.startOffset);
18
+ const prefix = editor.ownerDocument.createElement("div");
19
+ prefix.append(prefixRange.cloneContents());
20
+ return readTokenSearchField(prefix).query.length;
21
+ }
22
+ function replacementEditor(root, id) {
23
+ return [...root.querySelectorAll("[data-token-search-editor]")].find((editor) => editor.dataset.tokenSearchEditor === id);
24
+ }
25
+ function editorIsEmpty(editor) {
26
+ const value = readTokenSearchField(editor);
27
+ return value.query.length === 0 && value.tokens.length === 0;
28
+ }
29
+ function wireTokenSearchFields(root, { onSubmit, collapsible = true } = {}) {
30
+ const managed = collapsible !== false;
31
+ const config = typeof collapsible === "object" ? collapsible : {};
32
+ const expandOnActivate = managed && (config.expandOnActivate ?? true);
33
+ const collapseOnEmptyBlur = managed && (config.collapseOnEmptyBlur ?? true);
34
+ const collapseOnEscape = managed && (config.collapseOnEscape ?? true);
35
+ const manageFocus = managed && (config.manageFocus ?? true);
36
+ const adopted = config.signals ?? {};
37
+ const created = /* @__PURE__ */ new Map();
38
+ const signalFor = (id) => {
39
+ const own = adopted[id];
40
+ if (own) return own;
41
+ let field = created.get(id);
42
+ if (!field) {
43
+ field = signal(false);
44
+ created.set(id, field);
45
+ }
46
+ return field;
47
+ };
48
+ const setExpanded = (id, next) => {
49
+ const state = signalFor(id);
50
+ if (state.value !== next) state.value = next;
51
+ };
52
+ const view = () => root.ownerDocument.defaultView;
53
+ const focusAfterRender = (id, selector) => {
54
+ view().requestAnimationFrame(() => {
55
+ const target = root.querySelector(
56
+ `[data-component="token-search-field"][data-token-search-id="${CSS.escape(id)}"] ${selector}`
57
+ );
58
+ if (!target) return;
59
+ if (target.matches("[data-token-search-editor]")) placeTokenSearchCaret(target);
60
+ else target.focus();
61
+ });
62
+ };
63
+ const openField = (id) => {
64
+ setExpanded(id, true);
65
+ if (manageFocus) focusAfterRender(id, "[data-token-search-editor]");
66
+ };
67
+ const closeField = (id) => {
68
+ setExpanded(id, false);
69
+ if (manageFocus) focusAfterRender(id, ".kui-token-search__expand");
70
+ };
71
+ const pending = /* @__PURE__ */ new WeakMap();
72
+ const onBeforeInput = (event) => {
73
+ const inputEvent = event;
74
+ const editor = editorFromEvent(root, event);
75
+ if (!editor || !inputEvent.inputType.startsWith("delete") || editor.ownerDocument.activeElement !== editor) return;
76
+ const field = editor.closest('[data-component="token-search-field"]');
77
+ const id = field?.dataset.tokenSearchId;
78
+ const offset = caretQueryOffset(editor);
79
+ if (!id || offset === void 0 || field?.dataset.disabled === "true") return;
80
+ pending.set(editor, {
81
+ id,
82
+ offset,
83
+ tokenCount: editor.querySelectorAll('[data-component="token-search-token"]').length
84
+ });
85
+ };
86
+ const onInput = (event) => {
87
+ const editor = editorFromEvent(root, event);
88
+ if (!editor) return;
89
+ const deletion = pending.get(editor);
90
+ pending.delete(editor);
91
+ if (!deletion || editor.querySelectorAll('[data-component="token-search-token"]').length >= deletion.tokenCount) return;
92
+ editor.ownerDocument.defaultView.requestAnimationFrame(() => {
93
+ const replacement = replacementEditor(root, deletion.id);
94
+ if (!replacement) return;
95
+ const active = replacement.ownerDocument.activeElement;
96
+ if (active !== editor && active !== replacement && active !== replacement.ownerDocument.body) return;
97
+ placeTokenSearchCaret(replacement, deletion.offset);
98
+ });
99
+ };
100
+ root.addEventListener("beforeinput", onBeforeInput, true);
101
+ root.addEventListener("input", onInput, true);
102
+ const disposers = [
103
+ () => root.removeEventListener("beforeinput", onBeforeInput, true),
104
+ () => root.removeEventListener("input", onInput, true)
105
+ ];
106
+ disposers.push(
107
+ delegate(root, "keydown", "[data-token-search-editor]", (event, element) => {
108
+ const keyboardEvent = event;
109
+ const editor = element;
110
+ if (keyboardEvent.isComposing) return;
111
+ const field = editor.closest('[data-component="token-search-field"]');
112
+ const id = field?.dataset.tokenSearchId;
113
+ if (!id || field?.dataset.disabled === "true") return;
114
+ if (keyboardEvent.key === "Enter") {
115
+ keyboardEvent.preventDefault();
116
+ onSubmit?.({ id, editor });
117
+ return;
118
+ }
119
+ if (collapseOnEscape && keyboardEvent.key === "Escape" && field?.dataset.collapsible === "true" && editorIsEmpty(editor)) {
120
+ keyboardEvent.preventDefault();
121
+ closeField(id);
122
+ }
123
+ })
124
+ );
125
+ if (expandOnActivate) {
126
+ disposers.push(
127
+ delegate(root, "click", ".kui-token-search__expand", (_event, element) => {
128
+ const field = element.closest('[data-component="token-search-field"]');
129
+ const id = field?.dataset.tokenSearchId;
130
+ if (id && field?.dataset.disabled !== "true") openField(id);
131
+ })
132
+ );
133
+ }
134
+ if (collapseOnEmptyBlur) {
135
+ disposers.push(
136
+ delegate(root, "mousedown", '[data-component="token-search-field"][data-collapsible="true"] button', (event) => {
137
+ event.preventDefault();
138
+ })
139
+ );
140
+ disposers.push(
141
+ delegate(root, "focusout", "[data-token-search-editor]", (event, element) => {
142
+ const editor = element;
143
+ const field = editor.closest('[data-component="token-search-field"]');
144
+ const id = field?.dataset.tokenSearchId;
145
+ if (!id || field?.dataset.collapsible !== "true" || field.dataset.disabled === "true") return;
146
+ const next = event.relatedTarget;
147
+ if (next instanceof Node && field.contains(next)) return;
148
+ if (!editorIsEmpty(editor)) return;
149
+ view().queueMicrotask(() => {
150
+ if (!field.contains(field.ownerDocument.activeElement)) setExpanded(id, false);
151
+ });
152
+ })
153
+ );
154
+ }
155
+ const dispose = () => {
156
+ for (const stop of disposers.splice(0)) stop();
157
+ };
158
+ const handle = (() => dispose());
159
+ handle.dispose = dispose;
160
+ handle.expanded = (id) => managed ? signalFor(id) : void 0;
161
+ handle.open = (id) => {
162
+ if (managed) openField(id);
163
+ };
164
+ handle.close = (id) => {
165
+ if (managed) closeField(id);
166
+ };
167
+ return handle;
168
+ }
169
+
170
+ export { wireTokenSearchFields };
171
+
172
+ //# sourceMappingURL=chunk-2RJBFNB6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/wire-token-search-fields.ts"],"names":[],"mappings":"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","file":"chunk-2RJBFNB6.js","sourcesContent":["import { delegate, type Signal,signal } from 'kerfjs';\n\nimport { placeTokenSearchCaret, readTokenSearchField } from './token-search-field.js';\n\nexport interface TokenSearchSubmit {\n id: string;\n editor: HTMLElement;\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 /** 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 /** Managed collapsible transient behavior. `true`/omitted = on with defaults; `false` = fully off. */\n collapsible?: boolean | TokenSearchCollapsibleOptions;\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}\n\nfunction editorFromEvent(root: HTMLElement, event: Event): 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(root: HTMLElement, id: string): HTMLElement | undefined {\n return [...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/**\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 { onSubmit, collapsible = true }: 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 adopted = config.signals ?? {};\n const created = new Map<string, Signal<boolean>>();\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]')) 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 (!editor || !inputEvent.inputType.startsWith('delete') || editor.ownerDocument.activeElement !== editor) return;\n const field = editor.closest<HTMLElement>('[data-component=\"token-search-field\"]');\n const id = field?.dataset.tokenSearchId;\n const offset = caretQueryOffset(editor);\n if (!id || offset === undefined || field?.dataset.disabled === 'true') return;\n pending.set(editor, {\n id,\n offset,\n tokenCount: editor.querySelectorAll('[data-component=\"token-search-token\"]').length,\n });\n };\n const onInput = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (!editor) return;\n const deletion = pending.get(editor);\n pending.delete(editor);\n if (!deletion || editor.querySelectorAll('[data-component=\"token-search-token\"]').length >= deletion.tokenCount) 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 (active !== editor && active !== replacement && active !== replacement.ownerDocument.body) 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(root, 'keydown', '[data-token-search-editor]', (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>('[data-component=\"token-search-field\"]');\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 (collapseOnEscape && keyboardEvent.key === 'Escape' && field?.dataset.collapsible === 'true' && editorIsEmpty(editor)) {\n keyboardEvent.preventDefault();\n closeField(id);\n }\n }),\n );\n\n if (expandOnActivate) {\n disposers.push(\n delegate(root, 'click', '.kui-token-search__expand', (_event, element) => {\n // The selector guarantees a collapsible field ancestor; only skip a disabled one.\n const field = (element as HTMLElement).closest<HTMLElement>('[data-component=\"token-search-field\"]');\n const id = field?.dataset.tokenSearchId;\n if (id && field?.dataset.disabled !== 'true') openField(id);\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(root, 'mousedown', '[data-component=\"token-search-field\"][data-collapsible=\"true\"] button', (event) => {\n event.preventDefault();\n }),\n );\n disposers.push(\n delegate(root, 'focusout', '[data-token-search-editor]', (event, element) => {\n const editor = element as HTMLElement;\n const field = editor.closest<HTMLElement>('[data-component=\"token-search-field\"]');\n const id = field?.dataset.tokenSearchId;\n if (!id || field?.dataset.collapsible !== 'true' || field.dataset.disabled === 'true') return;\n const next = (event as FocusEvent).relatedTarget;\n if (next instanceof Node && field.contains(next)) return;\n if (!editorIsEmpty(editor)) return;\n view().queueMicrotask(() => {\n if (!field.contains(field.ownerDocument.activeElement)) setExpanded(id, false);\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,4 +1,5 @@
1
1
  import { filterDataAttributes } from './chunk-7BR3DO2A.js';
2
+ import { Skeleton } from './chunk-B24C4A6T.js';
2
3
  import { jsxs, jsx } from 'kerfjs/jsx-runtime';
3
4
 
4
5
  var PROTECTED_ROOT_DATA_ATTRIBUTES = /* @__PURE__ */ new Set([
@@ -15,14 +16,14 @@ function CloseIcon() {
15
16
  /* @__PURE__ */ jsx("path", { d: "M17 7 7 17" })
16
17
  ] });
17
18
  }
18
- function AppTab({ id, name, selected = false, closable = true, draggable = false, leading, trailing, closeIcon, selectAction = "select-tab", closeAction = "close-tab", className = "", rootAttributes = {} }) {
19
+ function AppTab({ id, name, selected = false, closable = true, draggable = false, leading, trailing, closeIcon, selectAction = "select-tab", closeAction = "close-tab", className = "", placeholder = false, rootAttributes = {} }) {
19
20
  const keyshortcuts = [closable ? "Delete Backspace" : "", draggable ? "Alt+Shift+ArrowLeft Alt+Shift+ArrowRight" : ""].filter(Boolean).join(" ");
20
21
  const extensionAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);
21
- return /* @__PURE__ */ jsxs("div", { ...extensionAttributes, class: `kui-app-tab ${className}`.trim(), "data-component": "app-tab", "data-tab-id": id, "data-selected": String(selected), draggable: draggable ? "true" : "false", children: [
22
- closable && /* @__PURE__ */ jsx("button", { type: "button", tabindex: "-1", class: "kui-app-tab__close", "data-action": closeAction, "data-tab-id": id, "aria-label": `Close ${name}`, title: `Close ${name}`, children: /* @__PURE__ */ jsx("span", { class: "kui-app-tab__close-icon", "aria-hidden": "true", children: closeIcon ?? /* @__PURE__ */ jsx(CloseIcon, {}) }) }),
23
- /* @__PURE__ */ jsxs("button", { type: "button", class: "kui-app-tab__select", role: "tab", "aria-selected": String(selected), "aria-keyshortcuts": keyshortcuts || void 0, "data-action": selectAction, "data-tab-id": id, tabindex: selected ? "0" : "-1", children: [
22
+ return /* @__PURE__ */ jsxs("div", { ...extensionAttributes, class: `kui-app-tab ${className}`.trim(), "data-component": "app-tab", "data-tab-id": id, "data-selected": String(selected), "data-placeholder": placeholder ? "true" : void 0, draggable: placeholder ? "false" : draggable ? "true" : "false", "aria-busy": placeholder ? "true" : void 0, children: [
23
+ closable && /* @__PURE__ */ jsx("button", { type: "button", tabindex: "-1", class: "kui-app-tab__close", "data-action": placeholder ? void 0 : closeAction, "data-tab-id": id, disabled: placeholder || void 0, "aria-label": `Close ${name}`, title: `Close ${name}`, children: /* @__PURE__ */ jsx("span", { class: "kui-app-tab__close-icon", "aria-hidden": "true", children: closeIcon ?? /* @__PURE__ */ jsx(CloseIcon, {}) }) }),
24
+ /* @__PURE__ */ jsxs("button", { type: "button", class: "kui-app-tab__select", role: "tab", "aria-selected": String(selected), "aria-keyshortcuts": placeholder ? void 0 : keyshortcuts || void 0, "data-action": placeholder ? void 0 : selectAction, "data-tab-id": id, disabled: placeholder || void 0, tabindex: placeholder ? "-1" : selected ? "0" : "-1", children: [
24
25
  leading,
25
- /* @__PURE__ */ jsx("span", { class: "kui-app-tab__name", children: name }),
26
+ /* @__PURE__ */ jsx("span", { class: "kui-app-tab__name", children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "7em" }) : name }),
26
27
  closable || trailing ? /* @__PURE__ */ jsx("span", { class: "kui-app-tab__trailing", children: trailing }) : void 0
27
28
  ] })
28
29
  ] });
@@ -30,4 +31,4 @@ function AppTab({ id, name, selected = false, closable = true, draggable = false
30
31
 
31
32
  export { AppTab };
32
33
 
33
- //# sourceMappingURL=chunk-XZXRLY5Q.js.map
34
+ //# sourceMappingURL=chunk-2Z5TWHKQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/app-tab.tsx"],"names":[],"mappings":"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","file":"chunk-2Z5TWHKQ.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { filterDataAttributes } from './extension-attributes.js';\nimport { Skeleton } from './skeleton.js';\n\nconst PROTECTED_ROOT_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-tab-id',\n 'data-selected',\n 'data-tab-dragging',\n 'data-tab-drop-position',\n]);\n\ntype AppTabRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-tab-id'?: never;\n 'data-selected'?: never;\n 'data-tab-dragging'?: never;\n 'data-tab-drop-position'?: never;\n }\n>;\n\nexport interface AppTabProps {\n id: string;\n name: string;\n selected?: boolean;\n closable?: boolean;\n draggable?: boolean;\n leading?: SafeHtml;\n trailing?: SafeHtml;\n /** Decorative dormant content for the close button. Must not contain interactive descendants. */\n closeIcon?: SafeHtml;\n selectAction?: string;\n closeAction?: string;\n className?: string;\n /** Render as an unanimated loading skeleton, disabling select/close and dragging. */\n placeholder?: boolean;\n rootAttributes?: AppTabRootAttributes;\n}\n\nfunction CloseIcon() {\n return <svg aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\"><path d=\"m7 7 10 10\"></path><path d=\"M17 7 7 17\"></path></svg>;\n}\n\nexport function AppTab({ id, name, selected = false, closable = true, draggable = false, leading, trailing, closeIcon, selectAction = 'select-tab', closeAction = 'close-tab', className = '', placeholder = false, rootAttributes = {} }: AppTabProps) {\n const keyshortcuts = [closable ? 'Delete Backspace' : '', draggable ? 'Alt+Shift+ArrowLeft Alt+Shift+ArrowRight' : ''].filter(Boolean).join(' ');\n const extensionAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);\n return <div {...extensionAttributes} class={`kui-app-tab ${className}`.trim()} data-component=\"app-tab\" data-tab-id={id} data-selected={String(selected)} data-placeholder={placeholder ? 'true' : undefined} draggable={placeholder ? 'false' : draggable ? 'true' : 'false'} aria-busy={placeholder ? 'true' : undefined}>\n {closable && <button type=\"button\" tabindex=\"-1\" class=\"kui-app-tab__close\" data-action={placeholder ? undefined : closeAction} data-tab-id={id} disabled={placeholder || undefined} aria-label={`Close ${name}`} title={`Close ${name}`}><span class=\"kui-app-tab__close-icon\" aria-hidden=\"true\">{closeIcon ?? <CloseIcon />}</span></button>}\n <button type=\"button\" class=\"kui-app-tab__select\" role=\"tab\" aria-selected={String(selected)} aria-keyshortcuts={placeholder ? undefined : keyshortcuts || undefined} data-action={placeholder ? undefined : selectAction} data-tab-id={id} disabled={placeholder || undefined} tabindex={placeholder ? '-1' : selected ? '0' : '-1'}>\n {leading}<span class=\"kui-app-tab__name\">{placeholder ? <Skeleton width=\"7em\" /> : name}</span>{closable || trailing ? <span class=\"kui-app-tab__trailing\">{trailing}</span> : undefined}\n </button>\n </div>;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { filterDataAttributes, filterControlAttributes } from './chunk-7BR3DO2A.js';
2
+ import { Skeleton } from './chunk-B24C4A6T.js';
2
3
  import { jsxs, jsx } from 'kerfjs/jsx-runtime';
3
4
 
4
5
  var PROTECTED_ROOT_DATA_ATTRIBUTES = /* @__PURE__ */ new Set([
@@ -16,18 +17,18 @@ var PROTECTED_TRAILING_DATA_ATTRIBUTES = /* @__PURE__ */ new Set([
16
17
  "data-action",
17
18
  "data-item-id"
18
19
  ]);
19
- function MenuActionRow({ label, icon, action, itemId, selected = false, pressed, accessibleLabel, title, multiline = false, state, disabled = false, tabIndex, trailingAction, trailingActionLabel, trailingActionIcon, trailingActionDisabled = false, trailingActionTitle, className = "", style, rootAttributes = {}, trailingActionAttributes = {} }) {
20
+ function MenuActionRow({ label, icon, action, itemId, selected = false, pressed, accessibleLabel, title, multiline = false, state, disabled = false, tabIndex, placeholder = false, trailingAction, trailingActionLabel, trailingActionIcon, trailingActionDisabled = false, trailingActionTitle, className = "", style, rootAttributes = {}, trailingActionAttributes = {} }) {
20
21
  const extensionRootAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);
21
22
  const extensionTrailingAttributes = filterControlAttributes(trailingActionAttributes, PROTECTED_TRAILING_DATA_ATTRIBUTES);
22
- return /* @__PURE__ */ jsxs("div", { ...extensionRootAttributes, class: `kui-menu-action-row ${className}`.trim(), style, "data-component": "menu-action-row", "data-item-id": itemId, "data-has-icon": String(Boolean(icon)), "data-multiline": multiline ? "true" : void 0, "data-state": state, "data-selected": String(selected), "data-pressed": pressed === void 0 ? void 0 : String(pressed), children: [
23
- /* @__PURE__ */ jsxs("button", { type: "button", class: "kui-menu-action-row__primary", title, disabled, tabindex: tabIndex, "data-action": action, "data-item-id": itemId, "aria-label": accessibleLabel, "aria-current": selected ? "page" : void 0, "aria-pressed": pressed === void 0 ? void 0 : String(pressed), children: [
24
- icon && /* @__PURE__ */ jsx("span", { class: "kui-menu-action-row__icon", children: icon }),
25
- /* @__PURE__ */ jsx("span", { class: "kui-menu-action-row__label", children: label })
23
+ return /* @__PURE__ */ jsxs("div", { ...extensionRootAttributes, class: `kui-menu-action-row ${className}`.trim(), style, "data-component": "menu-action-row", "data-item-id": itemId, "data-has-icon": String(Boolean(icon)), "data-multiline": multiline ? "true" : void 0, "data-state": state, "data-selected": String(selected), "data-pressed": pressed === void 0 ? void 0 : String(pressed), "data-placeholder": placeholder ? "true" : void 0, "aria-busy": placeholder ? "true" : void 0, children: [
24
+ /* @__PURE__ */ jsxs("button", { type: "button", class: "kui-menu-action-row__primary", title: placeholder ? void 0 : title, disabled: disabled || placeholder, tabindex: placeholder ? -1 : tabIndex, "data-action": placeholder ? void 0 : action, "data-item-id": itemId, "aria-label": accessibleLabel, "aria-current": selected ? "page" : void 0, "aria-pressed": pressed === void 0 ? void 0 : String(pressed), children: [
25
+ icon && /* @__PURE__ */ jsx("span", { class: "kui-menu-action-row__icon", children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "1em", height: "1em" }) : icon }),
26
+ /* @__PURE__ */ jsx("span", { class: "kui-menu-action-row__label", children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "9em" }) : label })
26
27
  ] }),
27
- /* @__PURE__ */ jsx("button", { ...extensionTrailingAttributes, type: "button", class: "kui-menu-action-row__trailing-action", "data-action": trailingAction, "data-item-id": itemId, "aria-label": trailingActionLabel, title: trailingActionTitle ?? trailingActionLabel, disabled: trailingActionDisabled || void 0, children: trailingActionIcon })
28
+ /* @__PURE__ */ jsx("button", { ...extensionTrailingAttributes, type: "button", class: "kui-menu-action-row__trailing-action", "data-action": placeholder ? void 0 : trailingAction, "data-item-id": itemId, "aria-label": trailingActionLabel, title: trailingActionTitle ?? trailingActionLabel, disabled: trailingActionDisabled || placeholder || void 0, children: trailingActionIcon })
28
29
  ] });
29
30
  }
30
31
 
31
32
  export { MenuActionRow };
32
33
 
33
- //# sourceMappingURL=chunk-EGHL5S4P.js.map
34
+ //# sourceMappingURL=chunk-3YD6ZNRA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/menu-action-row.tsx"],"names":[],"mappings":"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","file":"chunk-3YD6ZNRA.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { filterControlAttributes, filterDataAttributes } from './extension-attributes.js';\nimport { Skeleton } from './skeleton.js';\n\nconst PROTECTED_ROOT_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-item-id',\n 'data-has-icon',\n 'data-multiline',\n 'data-state',\n 'data-selected',\n 'data-pressed',\n]);\nconst PROTECTED_TRAILING_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-item-id',\n]);\n\ntype MenuActionRowRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-item-id'?: never;\n 'data-has-icon'?: never;\n 'data-multiline'?: never;\n 'data-state'?: never;\n 'data-selected'?: never;\n 'data-pressed'?: never;\n }\n>;\n\ntype MenuActionRowTrailingAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-item-id'?: never;\n popoverTarget?: string;\n popoverTargetAction?: 'toggle' | 'show' | 'hide';\n 'aria-controls'?: string;\n 'aria-haspopup'?: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | 'true';\n }\n>;\n\nexport interface MenuActionRowProps {\n /** Visible dormant content for the primary button. Must not contain interactive descendants. */\n label: string | SafeHtml;\n /** Decorative dormant content for the primary button. Must not contain interactive descendants. */\n icon?: SafeHtml;\n action: string;\n itemId?: string;\n selected?: boolean;\n pressed?: boolean;\n accessibleLabel?: string;\n title?: string;\n multiline?: boolean;\n state?: string;\n disabled?: boolean;\n tabIndex?: number;\n /** Render as an unanimated loading skeleton, disabling both actions. */\n placeholder?: boolean;\n trailingAction: string;\n trailingActionLabel: string;\n /** Decorative dormant content for the trailing button. Must not contain interactive descendants. */\n trailingActionIcon: SafeHtml;\n trailingActionDisabled?: boolean;\n trailingActionTitle?: string;\n className?: string;\n style?: string;\n rootAttributes?: MenuActionRowRootAttributes;\n trailingActionAttributes?: MenuActionRowTrailingAttributes;\n}\n\nexport function MenuActionRow({ label, icon, action, itemId, selected = false, pressed, accessibleLabel, title, multiline = false, state, disabled = false, tabIndex, placeholder = false, trailingAction, trailingActionLabel, trailingActionIcon, trailingActionDisabled = false, trailingActionTitle, className = '', style, rootAttributes = {}, trailingActionAttributes = {} }: MenuActionRowProps) {\n const extensionRootAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);\n const extensionTrailingAttributes = filterControlAttributes(trailingActionAttributes, PROTECTED_TRAILING_DATA_ATTRIBUTES);\n\n return <div {...extensionRootAttributes} class={`kui-menu-action-row ${className}`.trim()} style={style} data-component=\"menu-action-row\" data-item-id={itemId} data-has-icon={String(Boolean(icon))} data-multiline={multiline ? 'true' : undefined} data-state={state} data-selected={String(selected)} data-pressed={pressed === undefined ? undefined : String(pressed)} data-placeholder={placeholder ? 'true' : undefined} aria-busy={placeholder ? 'true' : undefined}>\n <button type=\"button\" class=\"kui-menu-action-row__primary\" title={placeholder ? undefined : title} disabled={disabled || placeholder} tabindex={placeholder ? -1 : tabIndex} data-action={placeholder ? undefined : action} data-item-id={itemId} aria-label={accessibleLabel} aria-current={selected ? 'page' : undefined} aria-pressed={pressed === undefined ? undefined : String(pressed)}>\n {icon && <span class=\"kui-menu-action-row__icon\">{placeholder ? <Skeleton width=\"1em\" height=\"1em\" /> : icon}</span>}\n <span class=\"kui-menu-action-row__label\">{placeholder ? <Skeleton width=\"9em\" /> : label}</span>\n </button>\n <button {...extensionTrailingAttributes} type=\"button\" class=\"kui-menu-action-row__trailing-action\" data-action={placeholder ? undefined : trailingAction} data-item-id={itemId} aria-label={trailingActionLabel} title={trailingActionTitle ?? trailingActionLabel} disabled={trailingActionDisabled || placeholder || undefined}>{trailingActionIcon}</button>\n </div>;\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { jsx } from 'kerfjs/jsx-runtime';
2
+
3
+ // src/skeleton.tsx
4
+ function blockStyle(width, height, radius) {
5
+ const parts = [
6
+ width && `width:${width}`,
7
+ height && `height:${height}`,
8
+ radius && `--kui-skeleton-radius:${radius}`
9
+ ].filter(Boolean);
10
+ return parts.length ? parts.join(";") : void 0;
11
+ }
12
+ function Skeleton({ width, height, radius, lines, label, className = "" }) {
13
+ const a11y = { role: label ? "img" : void 0, "aria-label": label, "aria-hidden": label ? void 0 : "true" };
14
+ if (lines && lines > 1) {
15
+ return /* @__PURE__ */ jsx("span", { class: `kui-skeleton-lines ${className}`.trim(), "data-component": "skeleton", style: width ? `width:${width}` : void 0, ...a11y, children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ jsx("span", { class: "kui-skeleton", "aria-hidden": "true", style: blockStyle(index === lines - 1 ? "60%" : void 0, height, radius) })) });
16
+ }
17
+ return /* @__PURE__ */ jsx("span", { class: `kui-skeleton ${className}`.trim(), "data-component": "skeleton", style: blockStyle(width, height, radius), ...a11y });
18
+ }
19
+
20
+ export { Skeleton };
21
+
22
+ //# sourceMappingURL=chunk-B24C4A6T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/skeleton.tsx"],"names":[],"mappings":";;;AAcA,SAAS,UAAA,CAAW,KAAA,EAAgB,MAAA,EAAiB,MAAA,EAAqC;AACxF,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,EAAE,KAAA,EAAO,MAAA,EAAQ,QAAQ,KAAA,EAAO,KAAA,EAAO,SAAA,GAAY,EAAA,EAAG,EAAkB;AAC/F,EAAA,MAAM,IAAA,GAAO,EAAE,IAAA,EAAM,KAAA,GAAQ,KAAA,GAAQ,MAAA,EAAW,YAAA,EAAc,KAAA,EAAO,aAAA,EAAe,KAAA,GAAQ,MAAA,GAAa,MAAA,EAAiB;AAC1H,EAAA,IAAI,KAAA,IAAS,QAAQ,CAAA,EAAG;AACtB,IAAA,uBAAO,GAAA,CAAC,UAAK,KAAA,EAAO,CAAA,mBAAA,EAAsB,SAAS,CAAA,CAAA,CAAG,IAAA,IAAQ,gBAAA,EAAe,UAAA,EAAW,OAAO,KAAA,GAAQ,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA,GAAK,MAAA,EAAY,GAAG,IAAA,EACtI,QAAA,EAAA,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,OAAM,EAAG,CAAC,GAAG,KAAA,qBAAU,GAAA,CAAC,UAAK,KAAA,EAAM,cAAA,EAAe,eAAY,MAAA,EAAO,KAAA,EAAO,WAAW,KAAA,KAAU,KAAA,GAAQ,IAAI,KAAA,GAAQ,MAAA,EAAW,QAAQ,MAAM,CAAA,EAAG,CAAO,CAAA,EAChL,CAAA;AAAA,EACF;AACA,EAAA,2BAAQ,MAAA,EAAA,EAAK,KAAA,EAAO,CAAA,aAAA,EAAgB,SAAS,GAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,UAAA,EAAW,OAAO,UAAA,CAAW,KAAA,EAAO,QAAQ,MAAM,CAAA,EAAI,GAAG,IAAA,EAAM,CAAA;AACxI","file":"chunk-B24C4A6T.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(width?: string, height?: string, radius?: string): 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({ width, height, radius, lines, label, className = '' }: SkeletonProps) {\n const a11y = { role: label ? 'img' : undefined, 'aria-label': label, 'aria-hidden': label ? undefined : ('true' as const) };\n if (lines && lines > 1) {\n return <span class={`kui-skeleton-lines ${className}`.trim()} data-component=\"skeleton\" style={width ? `width:${width}` : undefined} {...a11y}>\n {Array.from({ length: lines }, (_, index) => <span class=\"kui-skeleton\" aria-hidden=\"true\" style={blockStyle(index === lines - 1 ? '60%' : undefined, height, radius)}></span>)}\n </span>;\n }\n return <span class={`kui-skeleton ${className}`.trim()} data-component=\"skeleton\" style={blockStyle(width, height, radius)} {...a11y}></span>;\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { DisclosureArrow } from './chunk-56RJXPHG.js';
2
2
  import { filterDataAttributes, filterControlAttributes } from './chunk-7BR3DO2A.js';
3
+ import { Skeleton } from './chunk-B24C4A6T.js';
3
4
  import { jsx, jsxs } from 'kerfjs/jsx-runtime';
4
5
 
5
6
  var PROTECTED_ROOT_DATA_ATTRIBUTES = /* @__PURE__ */ new Set([
@@ -10,7 +11,7 @@ var PROTECTED_ROOT_DATA_ATTRIBUTES = /* @__PURE__ */ new Set([
10
11
  "data-toggle"
11
12
  ]);
12
13
  var PROTECTED_TRIGGER_DATA_ATTRIBUTES = /* @__PURE__ */ new Set(["data-action"]);
13
- function MenuHeader({ label, count, countLabel, badge, action, actionLabel, actionIcon, actionDisabled = false, disabledReason, expanded, toggle = false, rootAttributes = {}, triggerAttributes = {} }) {
14
+ function MenuHeader({ label, count, countLabel, badge, action, actionLabel, actionIcon, actionDisabled = false, disabledReason, expanded, toggle = false, placeholder = false, rootAttributes = {}, triggerAttributes = {} }) {
14
15
  const extensionRootAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);
15
16
  const extensionTriggerAttributes = filterControlAttributes(triggerAttributes, PROTECTED_TRIGGER_DATA_ATTRIBUTES);
16
17
  const normalizedCount = typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
@@ -18,23 +19,24 @@ function MenuHeader({ label, count, countLabel, badge, action, actionLabel, acti
18
19
  const renderedBadge = normalizedCount === void 0 ? badge : void 0;
19
20
  const renderedActionIcon = actionIcon ?? (toggle ? /* @__PURE__ */ jsx(DisclosureArrow, { open: Boolean(expanded) }) : void 0);
20
21
  const accessibleLabel = normalizedCount === void 0 ? void 0 : `${label}, ${normalizedCountLabel}`;
21
- const indicator = normalizedCount === void 0 ? renderedBadge && /* @__PURE__ */ jsx("span", { class: "kui-menu-header__badge", children: renderedBadge }) : /* @__PURE__ */ jsx("span", { class: "kui-menu-header__count", "aria-hidden": "true", children: normalizedCount });
22
+ const indicator = placeholder ? (normalizedCount !== void 0 || renderedBadge) && /* @__PURE__ */ jsx("span", { class: "kui-menu-header__badge", children: /* @__PURE__ */ jsx(Skeleton, { width: "1.75em" }) }) : normalizedCount === void 0 ? renderedBadge && /* @__PURE__ */ jsx("span", { class: "kui-menu-header__badge", children: renderedBadge }) : /* @__PURE__ */ jsx("span", { class: "kui-menu-header__count", "aria-hidden": "true", children: normalizedCount });
23
+ const busy = placeholder ? "true" : void 0;
22
24
  if (toggle) {
23
- return /* @__PURE__ */ jsx("header", { ...extensionRootAttributes, class: "kui-menu-header", "data-component": "menu-header", "data-has-badge": String(Boolean(renderedBadge)), "data-has-count": String(normalizedCount !== void 0), "data-toggle": "true", children: /* @__PURE__ */ jsxs("button", { ...extensionTriggerAttributes, type: "button", class: "kui-menu-header__title kui-menu-header__toggle", "data-action": action, "aria-label": accessibleLabel, "aria-expanded": String(Boolean(expanded)), children: [
25
+ return /* @__PURE__ */ jsx("header", { ...extensionRootAttributes, class: "kui-menu-header", "data-component": "menu-header", "data-has-badge": String(Boolean(renderedBadge)), "data-has-count": String(normalizedCount !== void 0), "data-toggle": "true", "data-placeholder": placeholder ? "true" : void 0, "aria-busy": busy, children: /* @__PURE__ */ jsxs("button", { ...extensionTriggerAttributes, type: "button", class: "kui-menu-header__title kui-menu-header__toggle", "data-action": placeholder ? void 0 : action, disabled: placeholder || void 0, "aria-label": accessibleLabel, "aria-expanded": String(Boolean(expanded)), children: [
24
26
  /* @__PURE__ */ jsx("span", { class: "kui-menu-header__label", children: label }),
25
27
  indicator,
26
28
  renderedActionIcon && /* @__PURE__ */ jsx("span", { class: "kui-menu-header__action-layer", children: renderedActionIcon })
27
29
  ] }) });
28
30
  }
29
- return /* @__PURE__ */ jsxs("header", { ...extensionRootAttributes, class: "kui-menu-header", "data-component": "menu-header", "data-has-badge": String(Boolean(renderedBadge)), "data-has-count": String(normalizedCount !== void 0), "data-toggle": "false", children: [
31
+ return /* @__PURE__ */ jsxs("header", { ...extensionRootAttributes, class: "kui-menu-header", "data-component": "menu-header", "data-has-badge": String(Boolean(renderedBadge)), "data-has-count": String(normalizedCount !== void 0), "data-toggle": "false", "data-placeholder": placeholder ? "true" : void 0, "aria-busy": busy, children: [
30
32
  /* @__PURE__ */ jsxs("div", { class: "kui-menu-header__title", children: [
31
33
  /* @__PURE__ */ jsx("h2", { class: "kui-menu-header__label", "aria-label": accessibleLabel, children: label }),
32
34
  indicator
33
35
  ] }),
34
- action && /* @__PURE__ */ jsx("button", { ...extensionTriggerAttributes, type: "button", class: "kui-menu-header__action", "data-action": action, "aria-label": actionLabel, title: actionDisabled ? disabledReason : actionLabel, disabled: actionDisabled || void 0, children: renderedActionIcon })
36
+ action && /* @__PURE__ */ jsx("button", { ...extensionTriggerAttributes, type: "button", class: "kui-menu-header__action", "data-action": placeholder ? void 0 : action, "aria-label": actionLabel, title: actionDisabled ? disabledReason : actionLabel, disabled: actionDisabled || placeholder || void 0, children: renderedActionIcon })
35
37
  ] });
36
38
  }
37
39
 
38
40
  export { MenuHeader };
39
41
 
40
- //# sourceMappingURL=chunk-NPPD2A6O.js.map
42
+ //# sourceMappingURL=chunk-H6URQGJI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/menu-header.tsx"],"names":[],"mappings":"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","file":"chunk-H6URQGJI.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { DisclosureArrow } from './disclosure-arrow.js';\nimport { filterControlAttributes, filterDataAttributes } from './extension-attributes.js';\nimport { Skeleton } from './skeleton.js';\n\nconst PROTECTED_ROOT_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-has-badge',\n 'data-has-count',\n 'data-toggle',\n]);\nconst PROTECTED_TRIGGER_DATA_ATTRIBUTES = new Set(['data-action']);\n\ntype MenuHeaderRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-has-badge'?: never;\n 'data-has-count'?: never;\n 'data-toggle'?: never;\n }\n>;\n\ntype MenuHeaderTriggerAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-action'?: never;\n popoverTarget?: string;\n popoverTargetAction?: 'toggle' | 'show' | 'hide';\n 'aria-controls'?: string;\n 'aria-haspopup'?: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | 'true';\n }\n>;\n\ninterface MenuHeaderBaseProps {\n label: string;\n action?: string;\n actionLabel?: string;\n actionIcon?: SafeHtml;\n actionDisabled?: boolean;\n disabledReason?: string;\n expanded?: boolean;\n toggle?: boolean;\n /** Render as an unanimated loading skeleton: keep the label and action affordance, disable interaction. */\n placeholder?: boolean;\n rootAttributes?: MenuHeaderRootAttributes;\n triggerAttributes?: MenuHeaderTriggerAttributes;\n}\n\ntype MenuHeaderIndicatorProps =\n | { count: number; countLabel: string; badge?: never }\n | { count?: never; countLabel?: never; badge?: SafeHtml };\n\nexport type MenuHeaderProps = MenuHeaderBaseProps & MenuHeaderIndicatorProps;\n\nexport function MenuHeader({ label, count, countLabel, badge, action, actionLabel, actionIcon, actionDisabled = false, disabledReason, expanded, toggle = false, placeholder = false, rootAttributes = {}, triggerAttributes = {} }: MenuHeaderProps) {\n const extensionRootAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);\n const extensionTriggerAttributes = filterControlAttributes(triggerAttributes, PROTECTED_TRIGGER_DATA_ATTRIBUTES);\n const normalizedCount = typeof count === 'number' && Number.isSafeInteger(count) && count >= 0 ? count : undefined;\n const normalizedCountLabel = normalizedCount === undefined\n ? undefined\n : typeof countLabel === 'string' && countLabel.trim() ? countLabel : String(normalizedCount);\n const renderedBadge = normalizedCount === undefined ? badge : undefined;\n const renderedActionIcon = actionIcon ?? (toggle ? <DisclosureArrow open={Boolean(expanded)} /> : undefined);\n const accessibleLabel = normalizedCount === undefined ? undefined : `${label}, ${normalizedCountLabel}`;\n const indicator = placeholder\n ? ((normalizedCount !== undefined || renderedBadge) && <span class=\"kui-menu-header__badge\"><Skeleton width=\"1.75em\" /></span>)\n : normalizedCount === undefined\n ? renderedBadge && <span class=\"kui-menu-header__badge\">{renderedBadge}</span>\n : <span class=\"kui-menu-header__count\" aria-hidden=\"true\">{normalizedCount}</span>;\n const busy = placeholder ? ('true' as const) : undefined;\n if (toggle) {\n return <header {...extensionRootAttributes} class=\"kui-menu-header\" data-component=\"menu-header\" data-has-badge={String(Boolean(renderedBadge))} data-has-count={String(normalizedCount !== undefined)} data-toggle=\"true\" data-placeholder={placeholder ? 'true' : undefined} aria-busy={busy}><button {...extensionTriggerAttributes} type=\"button\" class=\"kui-menu-header__title kui-menu-header__toggle\" data-action={placeholder ? undefined : action} disabled={placeholder || undefined} aria-label={accessibleLabel} aria-expanded={String(Boolean(expanded))}><span class=\"kui-menu-header__label\">{label}</span>{indicator}{renderedActionIcon && <span class=\"kui-menu-header__action-layer\">{renderedActionIcon}</span>}</button></header>;\n }\n return <header {...extensionRootAttributes} class=\"kui-menu-header\" data-component=\"menu-header\" data-has-badge={String(Boolean(renderedBadge))} data-has-count={String(normalizedCount !== undefined)} data-toggle=\"false\" data-placeholder={placeholder ? 'true' : undefined} aria-busy={busy}><div class=\"kui-menu-header__title\"><h2 class=\"kui-menu-header__label\" aria-label={accessibleLabel}>{label}</h2>{indicator}</div>{action && <button {...extensionTriggerAttributes} type=\"button\" class=\"kui-menu-header__action\" data-action={placeholder ? undefined : action} aria-label={actionLabel} title={actionDisabled ? disabledReason : actionLabel} disabled={actionDisabled || placeholder || undefined}>{renderedActionIcon}</button>}</header>;\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import { Skeleton } from './chunk-B24C4A6T.js';
2
+ import { jsxs, jsx } from 'kerfjs/jsx-runtime';
3
+
4
+ function StateBanner({ title, detail, icon, action, tone = "info", urgency = "status", className = "", placeholder = false }) {
5
+ return /* @__PURE__ */ jsxs("section", { class: `kui-state-banner ${className}`.trim(), "data-component": "state-banner", "data-tone": tone, "data-placeholder": placeholder ? "true" : void 0, role: urgency, "aria-live": urgency === "alert" ? "assertive" : "polite", "aria-busy": placeholder ? "true" : void 0, children: [
6
+ icon && /* @__PURE__ */ jsx("span", { class: "kui-state-banner__icon", children: icon }),
7
+ /* @__PURE__ */ jsxs("div", { class: "kui-state-banner__copy", children: [
8
+ /* @__PURE__ */ jsx("strong", { children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "10em" }) : title }),
9
+ (placeholder || detail) && /* @__PURE__ */ jsx("span", { children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "16em" }) : detail })
10
+ ] }),
11
+ action && /* @__PURE__ */ jsx("div", { class: "kui-state-banner__action", children: action })
12
+ ] });
13
+ }
14
+
15
+ export { StateBanner };
16
+
17
+ //# sourceMappingURL=chunk-I7INRJO4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/state-banner.tsx"],"names":[],"mappings":";;;AAkBO,SAAS,WAAA,CAAY,EAAE,KAAA,EAAO,MAAA,EAAQ,MAAM,MAAA,EAAQ,IAAA,GAAO,MAAA,EAAQ,OAAA,GAAU,QAAA,EAAU,SAAA,GAAY,EAAA,EAAI,WAAA,GAAc,OAAM,EAAqB;AACrJ,EAAA,uBAAO,IAAA,CAAC,SAAA,EAAA,EAAQ,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,cAAA,EAAe,WAAA,EAAW,IAAA,EAAM,kBAAA,EAAkB,cAAc,MAAA,GAAS,MAAA,EAAW,IAAA,EAAM,OAAA,EAAS,WAAA,EAAW,OAAA,KAAY,OAAA,GAAU,WAAA,GAAc,QAAA,EAAU,WAAA,EAAW,WAAA,GAAc,MAAA,GAAS,MAAA,EACzQ,QAAA,EAAA;AAAA,IAAA,IAAA,oBAAQ,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,wBAAA,EAA0B,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,oBACpD,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,wBAAA,EAAyB,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,YAAQ,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,YAAS,KAAA,EAAM,MAAA,EAAO,IAAK,KAAA,EAAM,CAAA;AAAA,MAAA,CAAW,WAAA,IAAe,MAAA,qBAAW,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,WAAA,uBAAe,QAAA,EAAA,EAAS,KAAA,EAAM,MAAA,EAAO,CAAA,GAAK,MAAA,EAAO;AAAA,KAAA,EAAQ,CAAA;AAAA,IACjM,MAAA,oBAAU,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,4BAA4B,QAAA,EAAA,MAAA,EAAO;AAAA,GAAA,EAC3D,CAAA;AACF","file":"chunk-I7INRJO4.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Skeleton } from './skeleton.js';\n\nexport type StateBannerTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nexport interface StateBannerProps {\n title: string;\n detail?: string;\n icon?: SafeHtml;\n action?: SafeHtml;\n tone?: StateBannerTone;\n urgency?: 'status' | 'alert';\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({ title, detail, icon, action, tone = 'info', urgency = 'status', className = '', placeholder = false }: StateBannerProps) {\n return <section class={`kui-state-banner ${className}`.trim()} data-component=\"state-banner\" data-tone={tone} data-placeholder={placeholder ? 'true' : undefined} role={urgency} aria-live={urgency === 'alert' ? 'assertive' : 'polite'} aria-busy={placeholder ? 'true' : undefined}>\n {icon && <span class=\"kui-state-banner__icon\">{icon}</span>}\n <div class=\"kui-state-banner__copy\"><strong>{placeholder ? <Skeleton width=\"10em\" /> : title}</strong>{(placeholder || detail) && <span>{placeholder ? <Skeleton width=\"16em\" /> : detail}</span>}</div>\n {action && <div class=\"kui-state-banner__action\">{action}</div>}\n </section>;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { Skeleton } from './chunk-B24C4A6T.js';
2
+ import { jsx } from 'kerfjs/jsx-runtime';
3
+
4
+ function ToolbarText({ text, size = "default", className = "", id, placeholder = false }) {
5
+ return /* @__PURE__ */ jsx("span", { class: `kui-toolbar-text ${className}`.trim(), "data-component": "toolbar-text", "data-size": size, "data-placeholder": placeholder ? "true" : void 0, id, "aria-busy": placeholder ? "true" : void 0, children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "8em" }) : text });
6
+ }
7
+
8
+ export { ToolbarText };
9
+
10
+ //# sourceMappingURL=chunk-KJYXOTG3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/toolbar-text.tsx"],"names":[],"mappings":";;;AAcO,SAAS,WAAA,CAAY,EAAE,IAAA,EAAM,IAAA,GAAO,SAAA,EAAW,YAAY,EAAA,EAAI,EAAA,EAAI,WAAA,GAAc,KAAA,EAAM,EAAqB;AACjH,EAAA,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,cAAA,EAAe,WAAA,EAAW,IAAA,EAAM,kBAAA,EAAkB,WAAA,GAAc,MAAA,GAAS,MAAA,EAAW,EAAA,EAAQ,WAAA,EAAW,WAAA,GAAc,MAAA,GAAS,MAAA,EAAY,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,QAAA,EAAA,EAAS,KAAA,EAAM,KAAA,EAAM,CAAA,GAAK,IAAA,EAAK,CAAA;AACrQ","file":"chunk-KJYXOTG3.js","sourcesContent":["import { Skeleton } from './skeleton.js';\n\nexport type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';\n\nexport interface ToolbarTextProps {\n text: string;\n size?: ToolbarTextSize;\n className?: string;\n /** Optional id, e.g. so a dialog can reference the title via aria-labelledby. */\n id?: string;\n /** Render the text as an unanimated loading skeleton instead of its value. */\n placeholder?: boolean;\n}\n\nexport function ToolbarText({ text, size = 'default', className = '', id, placeholder = false }: ToolbarTextProps) {\n return <span class={`kui-toolbar-text ${className}`.trim()} data-component=\"toolbar-text\" data-size={size} data-placeholder={placeholder ? 'true' : undefined} id={id} aria-busy={placeholder ? 'true' : undefined}>{placeholder ? <Skeleton width=\"8em\" /> : text}</span>;\n}\n"]}
@@ -1,7 +1,18 @@
1
1
  import { LucideIcon } from './chunk-W2FK7ZNY.js';
2
+ import { Skeleton } from './chunk-B24C4A6T.js';
3
+ import { ChevronDown } from 'lucide';
2
4
  import { jsxs, jsx, Fragment } from 'kerfjs/jsx-runtime';
3
5
 
4
- function Select({ name, value, label, ariaLabel, choices, className = "", placeholder, disabled = false, fitMenu = false, renderSelected }) {
6
+ function Select({ name, value, label, ariaLabel, choices, className = "", placeholderText, disabled = false, fitMenu = false, renderSelected, placeholder = false }) {
7
+ if (placeholder) {
8
+ return /* @__PURE__ */ jsxs("div", { class: `kui-select kui-select--placeholder ${className}`.trim(), "data-component": "select", "data-placeholder": "true", "aria-busy": "true", children: [
9
+ label && /* @__PURE__ */ jsx("span", { class: "kui-select__placeholder-label", children: label }),
10
+ /* @__PURE__ */ jsxs("span", { class: "kui-select__placeholder-box", "aria-label": ariaLabel, role: "img", children: [
11
+ /* @__PURE__ */ jsx(Skeleton, { width: "10em" }),
12
+ /* @__PURE__ */ jsx("span", { class: "kui-select__placeholder-chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx(LucideIcon, { icon: ChevronDown, name: "chevron-down" }) })
13
+ ] })
14
+ ] });
15
+ }
5
16
  const selected = choices.find((choice) => choice.value === value);
6
17
  const icon = (choice, selectedIcon = false) => /* @__PURE__ */ jsx("span", { "data-key": `${name}:${choice.value}:${selectedIcon ? "selected" : "option"}`, "data-morph-skip": true, slot: "start", class: `kui-select__icon${selectedIcon ? " kui-select__icon--selected" : ""}`, style: choice.color ? `color:${choice.color}` : void 0, children: choice.icon ? /* @__PURE__ */ jsx(LucideIcon, { icon: choice.icon, name: choice.iconName ?? choice.label.toLowerCase().replaceAll(" ", "-") }) : null });
7
18
  const option = (choice) => /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -13,7 +24,7 @@ function Select({ name, value, label, ariaLabel, choices, className = "", placeh
13
24
  ] });
14
25
  const groups = [...new Set(choices.map((choice) => choice.group).filter((group) => Boolean(group)))];
15
26
  const ungrouped = choices.filter((choice) => !choice.group);
16
- return /* @__PURE__ */ jsxs("wa-select", { class: `kui-select${renderSelected ? " kui-select--custom-selected" : ""}${fitMenu ? " kui-select--fit-menu" : ""} ${className}`.trim(), "data-component": "select", name, label, "aria-label": ariaLabel, value, placeholder, disabled, children: [
27
+ return /* @__PURE__ */ jsxs("wa-select", { class: `kui-select${renderSelected ? " kui-select--custom-selected" : ""}${fitMenu ? " kui-select--fit-menu" : ""} ${className}`.trim(), "data-component": "select", name, label, "aria-label": ariaLabel, value, placeholder: placeholderText, disabled, children: [
17
28
  selected && (renderSelected ? /* @__PURE__ */ jsx("span", { "data-key": `${name}:${value}:custom-selected`, slot: "start", class: "kui-select__custom-selected", children: renderSelected(selected) }) : selected.icon ? icon(selected, true) : null),
18
29
  ungrouped.map(option),
19
30
  groups.map((group, index) => /* @__PURE__ */ jsxs("div", { class: `kui-select__group${index > 0 || ungrouped.length > 0 ? " kui-select__group--separated" : ""}`, role: "group", "aria-label": group, children: [
@@ -25,4 +36,4 @@ function Select({ name, value, label, ariaLabel, choices, className = "", placeh
25
36
 
26
37
  export { Select };
27
38
 
28
- //# sourceMappingURL=chunk-CTQKI2XL.js.map
39
+ //# sourceMappingURL=chunk-LC3YSAZC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/select.tsx"],"names":[],"mappings":"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","file":"chunk-LC3YSAZC.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\nimport { ChevronDown } from 'lucide';\n\nimport { LucideIcon, type LucideNode } from './lucide-icon.js';\nimport { Skeleton } from './skeleton.js';\n\nexport interface SelectChoice<Value extends string = string> {\n value: Value;\n label: string;\n icon?: LucideNode;\n iconName?: string;\n color?: string;\n group?: string;\n separatorBefore?: boolean;\n}\n\nexport interface SelectProps<Value extends string = string> {\n name: string;\n value: Value;\n label?: string;\n ariaLabel?: string;\n choices: readonly SelectChoice<Value>[];\n className?: string;\n /** Empty-value hint text shown in the closed control (the native select placeholder). */\n placeholderText?: string;\n disabled?: boolean;\n fitMenu?: boolean;\n renderSelected?: (choice: SelectChoice<Value>) => SafeHtml;\n /** Render as an unanimated loading skeleton: the label above a static, empty control box. */\n placeholder?: boolean;\n}\n\nexport function Select<Value extends string>({ name, value, label, ariaLabel, choices, className = '', placeholderText, disabled = false, fitMenu = false, renderSelected, placeholder = false }: SelectProps<Value>) {\n if (placeholder) {\n return <div class={`kui-select kui-select--placeholder ${className}`.trim()} data-component=\"select\" data-placeholder=\"true\" aria-busy=\"true\">\n {label && <span class=\"kui-select__placeholder-label\">{label}</span>}\n <span class=\"kui-select__placeholder-box\" aria-label={ariaLabel} role=\"img\">\n <Skeleton width=\"10em\" />\n <span class=\"kui-select__placeholder-chevron\" aria-hidden=\"true\"><LucideIcon icon={ChevronDown} name=\"chevron-down\" /></span>\n </span>\n </div>;\n }\n const selected = choices.find((choice) => choice.value === value);\n const icon = (choice: SelectChoice<Value>, selectedIcon = false) => <span data-key={`${name}:${choice.value}:${selectedIcon ? 'selected' : 'option'}`} data-morph-skip slot=\"start\" class={`kui-select__icon${selectedIcon ? ' kui-select__icon--selected' : ''}`} style={choice.color ? `color:${choice.color}` : undefined}>{choice.icon ? <LucideIcon icon={choice.icon} name={choice.iconName ?? choice.label.toLowerCase().replaceAll(' ', '-')} /> : null}</span>;\n const option = (choice: SelectChoice<Value>) => <>{choice.separatorBefore && <wa-divider></wa-divider>}<wa-option value={choice.value}>{choice.icon ? icon(choice) : null}{choice.label}</wa-option></>;\n const groups = [...new Set(choices.map((choice) => choice.group).filter((group): group is string => Boolean(group)))];\n const ungrouped = choices.filter((choice) => !choice.group);\n return <wa-select class={`kui-select${renderSelected ? ' kui-select--custom-selected' : ''}${fitMenu ? ' kui-select--fit-menu' : ''} ${className}`.trim()} data-component=\"select\" name={name} label={label} aria-label={ariaLabel} value={value} placeholder={placeholderText} disabled={disabled}>\n {selected && (renderSelected ? <span data-key={`${name}:${value}:custom-selected`} slot=\"start\" class=\"kui-select__custom-selected\">{renderSelected(selected)}</span> : selected.icon ? icon(selected, true) : null)}\n {ungrouped.map(option)}\n {groups.map((group, index) => <div class={`kui-select__group${index > 0 || ungrouped.length > 0 ? ' kui-select__group--separated' : ''}`} role=\"group\" aria-label={group}><span class=\"kui-select__group-title\">{group}</span>{choices.filter((choice) => choice.group === group).map(option)}</div>)}\n </wa-select>;\n}\n"]}