@kerfjs/ui 5.0.0-beta.62 → 5.0.0-beta.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/ai/component-catalog-extension.schema.json +13 -0
- package/ai/component-catalog.json +13 -2
- package/ai/component-composition.json +15 -2
- package/ai/components/list-item.md +1 -1
- package/ai/components/workbench.md +4 -2
- package/ai/public-api-signatures-v1.md +151 -44
- package/ai/skill.md +9 -5
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/index.mjs +3 -2
- package/catalog-projection-cli.mjs +96 -0
- package/catalog-projection.d.mts +55 -0
- package/catalog-projection.mjs +62 -0
- package/dist/browser/catalog.js +1 -1
- package/dist/browser/collapsible-panel.js +2 -0
- package/dist/browser/nav-stack.js +1 -0
- package/dist/browser/split-view.js +1 -0
- package/dist/browser/toolbar-control-group.js +1 -0
- package/dist/browser/workbench.js +1 -0
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +2 -2
- package/dist/catalog.js +11 -10
- package/dist/catalog.js.map +1 -1
- package/dist/chip.d.ts +9 -3
- package/dist/chip.js +1 -1
- package/dist/{chunk-UCKKT6KO.js → chunk-2EKHENQK.js} +7 -1
- package/dist/chunk-2EKHENQK.js.map +1 -0
- package/dist/{chunk-OD2VXAPL.js → chunk-3BYFWTP3.js} +4 -3
- package/dist/chunk-3BYFWTP3.js.map +1 -0
- package/dist/{chunk-5Q3N6EV7.js → chunk-5IJ6UGNZ.js} +3 -3
- package/dist/{chunk-5Q3N6EV7.js.map → chunk-5IJ6UGNZ.js.map} +1 -1
- package/dist/{chunk-KROD7KZK.js → chunk-AUVG54KC.js} +2 -2
- package/dist/{chunk-KROD7KZK.js.map → chunk-AUVG54KC.js.map} +1 -1
- package/dist/{chunk-AUKT3KMG.js → chunk-CQHN45XR.js} +17 -2
- package/dist/chunk-CQHN45XR.js.map +1 -0
- package/dist/{chunk-SWVW56CV.js → chunk-EN4LDR5Y.js} +2 -2
- package/dist/{chunk-SWVW56CV.js.map → chunk-EN4LDR5Y.js.map} +1 -1
- package/dist/{chunk-4MG3KXJM.js → chunk-F7OCOBTG.js} +2 -2
- package/dist/{chunk-4MG3KXJM.js.map → chunk-F7OCOBTG.js.map} +1 -1
- package/dist/{chunk-KYDDCJXU.js → chunk-HXCMWANP.js} +4 -4
- package/dist/{chunk-KYDDCJXU.js.map → chunk-HXCMWANP.js.map} +1 -1
- package/dist/{chunk-ENGVYQPG.js → chunk-IA4D5XNT.js} +60 -10
- package/dist/chunk-IA4D5XNT.js.map +1 -0
- package/dist/{chunk-F4QMLOXJ.js → chunk-IAOAZUOO.js} +2 -2
- package/dist/{chunk-F4QMLOXJ.js.map → chunk-IAOAZUOO.js.map} +1 -1
- package/dist/{chunk-VCBTX62E.js → chunk-J3KGJ6P6.js} +2 -2
- package/dist/chunk-J3KGJ6P6.js.map +1 -0
- package/dist/{chunk-X6ADHJNI.js → chunk-KFYANKJI.js} +25 -6
- package/dist/chunk-KFYANKJI.js.map +1 -0
- package/dist/{chunk-A3CKOW2R.js → chunk-M5H2RMCH.js} +165 -26
- package/dist/chunk-M5H2RMCH.js.map +1 -0
- package/dist/chunk-MOSIE4Z2.js +51 -0
- package/dist/chunk-MOSIE4Z2.js.map +1 -0
- package/dist/{chunk-RRB26JRJ.js → chunk-NSVLUDUW.js} +19 -4
- package/dist/chunk-NSVLUDUW.js.map +1 -0
- package/dist/{chunk-7JUBXOIV.js → chunk-NXWE5S57.js} +25 -6
- package/dist/chunk-NXWE5S57.js.map +1 -0
- package/dist/chunk-RGS4WX2M.js +44 -0
- package/dist/chunk-RGS4WX2M.js.map +1 -0
- package/dist/chunk-SH6F3CCG.js +80 -0
- package/dist/chunk-SH6F3CCG.js.map +1 -0
- package/dist/{chunk-EAC4CDY7.js → chunk-SMZGAPCU.js} +15 -2
- package/dist/chunk-SMZGAPCU.js.map +1 -0
- package/dist/{chunk-NNMLEDMD.js → chunk-TJK44RQC.js} +64 -11
- package/dist/chunk-TJK44RQC.js.map +1 -0
- package/dist/{chunk-6ZXOQEAN.js → chunk-WF75U3V4.js} +7 -1
- package/dist/chunk-WF75U3V4.js.map +1 -0
- package/dist/collapsible-panel.d.ts +18 -7
- package/dist/collapsible-panel.js +19 -3
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +40 -5
- package/dist/content-item.js +1 -1
- package/dist/disclosure-arrow.js +2 -1
- package/dist/grid.d.ts +5 -1
- package/dist/grid.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +20 -20
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/lucide-icon.d.ts +5 -2
- package/dist/lucide-icon.js +2 -1
- package/dist/nav-stack.js +2 -1
- package/dist/pane.d.ts +2 -1
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-DqwtBxQL.d.ts → panel-toolbar-DDKh4uKd.d.ts} +11 -2
- package/dist/popup-menu-register.js +216 -3
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.d.ts +4 -3
- package/dist/popup-menu.js +1 -1
- package/dist/select.js +1 -1
- package/dist/split-view.js +2 -1
- package/dist/split-view.js.map +1 -1
- package/dist/styles/catalog/components/catalog-example.css +4 -0
- package/dist/styles/chip.css +14 -0
- package/dist/styles/content-item.css +45 -0
- package/dist/styles/grid.css +7 -0
- package/dist/styles/list-action-row.css +4 -3
- package/dist/styles/list-header.css +4 -3
- package/dist/styles/list-item.css +21 -11
- package/dist/styles/lucide-icon.css +5 -0
- package/dist/styles/pane.css +3 -2
- package/dist/styles/popup-menu.css +24 -10
- package/dist/styles/segmented-control.css +3 -0
- package/dist/styles/select.css +11 -0
- package/dist/styles/sunken-panel.css +7 -0
- package/dist/styles/text.css +29 -0
- package/dist/styles/token-search-field.css +51 -11
- package/dist/styles/toolbar-control-group.css +49 -0
- package/dist/styles/workbench.css +130 -2
- package/dist/sunken-panel.d.ts +6 -1
- package/dist/sunken-panel.js +1 -1
- package/dist/text.d.ts +14 -3
- package/dist/text.js +1 -1
- package/dist/{token-search-field-DvgFLhLL.d.ts → token-search-field-Xk8jiw8Y.d.ts} +18 -4
- package/dist/token-search-field.d.ts +1 -1
- package/dist/token-search-field.js +2 -1
- package/dist/token-search-model.d.ts +1 -1
- package/dist/toolbar-control-group.d.ts +5 -1
- package/dist/toolbar-control-group.js +2 -1
- package/dist/toolbar.d.ts +5 -2
- package/dist/toolbar.js +1 -1
- package/dist/wire-catalog.js +1 -1
- package/dist/wire-content-items.d.ts +9 -0
- package/dist/wire-content-items.js +66 -0
- package/dist/wire-content-items.js.map +1 -0
- package/dist/wire-token-search-fields.d.ts +1 -1
- package/dist/wire-token-search-fields.js +2 -1
- package/dist/wire-workbench.d.ts +7 -0
- package/dist/wire-workbench.js +1 -1
- package/dist/workbench.d.ts +24 -8
- package/dist/workbench.js +2 -1
- package/docs/accessibility.md +30 -6
- package/docs/catalog.md +42 -2
- package/docs/collapsible-panel.md +8 -1
- package/docs/component-contract.md +43 -5
- package/docs/component-selection.md +46 -8
- package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
- package/docs/design/templates/toolbar-dark.svg +1 -1
- package/docs/design/templates/toolbar.svg +1 -1
- package/docs/examples/component-catalog-extension.json +6 -0
- package/docs/layout.md +56 -9
- package/docs/sunken-panel.md +22 -0
- package/docs/surface-scaffold.md +6 -3
- package/docs/ui-analyzer.md +4 -0
- package/docs/ux-demo.md +1 -0
- package/docs/workbench.md +42 -4
- package/llms.txt +9 -5
- package/package.json +16 -2
- package/scripts/component-catalog-extension-validation.mjs +28 -0
- package/dist/chunk-4R777DUZ.js +0 -34
- package/dist/chunk-4R777DUZ.js.map +0 -1
- package/dist/chunk-6ZXOQEAN.js.map +0 -1
- package/dist/chunk-7JUBXOIV.js.map +0 -1
- package/dist/chunk-A3CKOW2R.js.map +0 -1
- package/dist/chunk-AUKT3KMG.js.map +0 -1
- package/dist/chunk-EAC4CDY7.js.map +0 -1
- package/dist/chunk-ENGVYQPG.js.map +0 -1
- package/dist/chunk-MA73TA6D.js +0 -42
- package/dist/chunk-MA73TA6D.js.map +0 -1
- package/dist/chunk-N2DRU35S.js +0 -45
- package/dist/chunk-N2DRU35S.js.map +0 -1
- package/dist/chunk-NNMLEDMD.js.map +0 -1
- package/dist/chunk-OD2VXAPL.js.map +0 -1
- package/dist/chunk-RRB26JRJ.js.map +0 -1
- package/dist/chunk-UCKKT6KO.js.map +0 -1
- package/dist/chunk-VCBTX62E.js.map +0 -1
- package/dist/chunk-X6ADHJNI.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readTokenSearchField, placeTokenSearchCaret } from './chunk-
|
|
1
|
+
import { readTokenSearchField, placeTokenSearchCaret } from './chunk-NSVLUDUW.js';
|
|
2
|
+
import { autoUpdate, computePosition, offset, flip, shift, size } from '@floating-ui/dom';
|
|
2
3
|
import { delegate, delegateCapture, signal } from 'kerfjs';
|
|
3
4
|
|
|
4
5
|
function editorFromEvent(root, event) {
|
|
@@ -87,14 +88,14 @@ function meaningfulSibling(block, direction) {
|
|
|
87
88
|
return sibling;
|
|
88
89
|
}
|
|
89
90
|
function caretSideNode(editor, range, direction) {
|
|
90
|
-
const { startContainer: container, startOffset:
|
|
91
|
+
const { startContainer: container, startOffset: offset2 } = range;
|
|
91
92
|
if (container.nodeType === Node.TEXT_NODE) {
|
|
92
93
|
const text = container.data;
|
|
93
|
-
const side = direction === "backward" ? text.slice(0,
|
|
94
|
+
const side = direction === "backward" ? text.slice(0, offset2) : text.slice(offset2);
|
|
94
95
|
if (stripZwsp(side).length > 0) return null;
|
|
95
96
|
return meaningfulSibling(topBlock(editor, container), direction);
|
|
96
97
|
}
|
|
97
|
-
const child = container.childNodes[direction === "backward" ?
|
|
98
|
+
const child = container.childNodes[direction === "backward" ? offset2 - 1 : offset2];
|
|
98
99
|
if (child) {
|
|
99
100
|
const block2 = topBlock(editor, child);
|
|
100
101
|
return isBlankText(child) ? meaningfulSibling(block2, direction) : block2;
|
|
@@ -143,19 +144,116 @@ function wireTokenSearchFields(root, {
|
|
|
143
144
|
const created = /* @__PURE__ */ new Map();
|
|
144
145
|
let disposed = false;
|
|
145
146
|
let pointerActivationTarget = null;
|
|
147
|
+
const pendingPointerBlurCollapses = /* @__PURE__ */ new Map();
|
|
148
|
+
let pointerReleaseTimer;
|
|
149
|
+
const positionedSuggestions = /* @__PURE__ */ new Map();
|
|
150
|
+
const syncSuggestions = () => {
|
|
151
|
+
const current = new Set(
|
|
152
|
+
root.querySelectorAll(".kui-token-search__suggestions")
|
|
153
|
+
);
|
|
154
|
+
for (const [popup, stop] of positionedSuggestions) {
|
|
155
|
+
if (current.has(popup)) continue;
|
|
156
|
+
stop();
|
|
157
|
+
positionedSuggestions.delete(popup);
|
|
158
|
+
}
|
|
159
|
+
for (const popup of current) {
|
|
160
|
+
if (positionedSuggestions.has(popup)) continue;
|
|
161
|
+
const field = popup.closest(
|
|
162
|
+
'[data-component="token-search-field"]'
|
|
163
|
+
);
|
|
164
|
+
if (!field) continue;
|
|
165
|
+
let active = true;
|
|
166
|
+
popup.style.position = "absolute";
|
|
167
|
+
popup.style.insetBlockStart = "auto";
|
|
168
|
+
popup.style.insetInlineStart = "auto";
|
|
169
|
+
popup.style.left = "0";
|
|
170
|
+
popup.style.top = "0";
|
|
171
|
+
popup.style.visibility = "hidden";
|
|
172
|
+
const update = async () => {
|
|
173
|
+
const width = Math.min(
|
|
174
|
+
Math.max(field.getBoundingClientRect().width, 240),
|
|
175
|
+
Math.max(0, field.ownerDocument.defaultView.innerWidth - 16)
|
|
176
|
+
);
|
|
177
|
+
popup.style.width = `${width}px`;
|
|
178
|
+
const position = await computePosition(field, popup, {
|
|
179
|
+
strategy: "absolute",
|
|
180
|
+
placement: "bottom-start",
|
|
181
|
+
middleware: [
|
|
182
|
+
offset(4),
|
|
183
|
+
flip({ padding: 8 }),
|
|
184
|
+
shift({ padding: 8 }),
|
|
185
|
+
size({
|
|
186
|
+
padding: 8,
|
|
187
|
+
apply({ availableHeight }) {
|
|
188
|
+
popup.style.maxHeight = `${Math.max(0, Math.min(240, availableHeight))}px`;
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
]
|
|
192
|
+
});
|
|
193
|
+
if (!active || disposed || !popup.isConnected) return;
|
|
194
|
+
popup.style.left = `${position.x}px`;
|
|
195
|
+
popup.style.top = `${position.y}px`;
|
|
196
|
+
popup.style.visibility = "visible";
|
|
197
|
+
};
|
|
198
|
+
const stopAutoUpdate = autoUpdate(field, popup, () => void update(), {
|
|
199
|
+
layoutShift: false
|
|
200
|
+
});
|
|
201
|
+
positionedSuggestions.set(popup, () => {
|
|
202
|
+
active = false;
|
|
203
|
+
stopAutoUpdate();
|
|
204
|
+
for (const property of [
|
|
205
|
+
"position",
|
|
206
|
+
"inset-block-start",
|
|
207
|
+
"inset-inline-start",
|
|
208
|
+
"left",
|
|
209
|
+
"top",
|
|
210
|
+
"visibility",
|
|
211
|
+
"width",
|
|
212
|
+
"max-height"
|
|
213
|
+
])
|
|
214
|
+
popup.style.removeProperty(property);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const suggestionsObserver = new MutationObserver(syncSuggestions);
|
|
219
|
+
suggestionsObserver.observe(root, { childList: true, subtree: true });
|
|
220
|
+
syncSuggestions();
|
|
146
221
|
const isExemptTarget = (element) => {
|
|
147
222
|
if (!element) return false;
|
|
148
223
|
if (element.closest("[data-token-search-keep-open]")) return true;
|
|
149
224
|
return keepOpenOn ? keepOpenOn(element) : false;
|
|
150
225
|
};
|
|
151
226
|
const trackPointerActivation = (event) => {
|
|
227
|
+
if (pointerReleaseTimer !== void 0)
|
|
228
|
+
view().clearTimeout(pointerReleaseTimer);
|
|
229
|
+
pointerReleaseTimer = void 0;
|
|
152
230
|
pointerActivationTarget = event.target instanceof Element ? event.target : null;
|
|
153
231
|
};
|
|
232
|
+
const flushPointerBlurCollapses = () => {
|
|
233
|
+
pointerReleaseTimer = void 0;
|
|
234
|
+
for (const collapse of pendingPointerBlurCollapses.values()) collapse();
|
|
235
|
+
pendingPointerBlurCollapses.clear();
|
|
236
|
+
};
|
|
237
|
+
const flushAfterPointerClick = () => {
|
|
238
|
+
if (pendingPointerBlurCollapses.size === 0) return;
|
|
239
|
+
if (pointerReleaseTimer !== void 0)
|
|
240
|
+
view().clearTimeout(pointerReleaseTimer);
|
|
241
|
+
pointerReleaseTimer = view().setTimeout(flushPointerBlurCollapses, 0);
|
|
242
|
+
};
|
|
154
243
|
const clearPointerActivation = () => {
|
|
155
244
|
pointerActivationTarget = null;
|
|
156
245
|
};
|
|
157
246
|
const clearPointerActivationAfterDefault = () => {
|
|
158
247
|
view().queueMicrotask(clearPointerActivation);
|
|
248
|
+
flushAfterPointerClick();
|
|
249
|
+
};
|
|
250
|
+
const clearPointerActivationAfterClick = () => {
|
|
251
|
+
clearPointerActivation();
|
|
252
|
+
flushAfterPointerClick();
|
|
253
|
+
};
|
|
254
|
+
const cancelPointerActivation = () => {
|
|
255
|
+
clearPointerActivation();
|
|
256
|
+
flushAfterPointerClick();
|
|
159
257
|
};
|
|
160
258
|
const signalFor = (id) => {
|
|
161
259
|
const own = adopted[id];
|
|
@@ -172,16 +270,38 @@ function wireTokenSearchFields(root, {
|
|
|
172
270
|
if (state.value !== next) state.value = next;
|
|
173
271
|
};
|
|
174
272
|
const view = () => root.ownerDocument.defaultView;
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
273
|
+
const focusing = /* @__PURE__ */ new Map();
|
|
274
|
+
const focusAfterRender = (id, selector, guardMovedFocus = false) => {
|
|
275
|
+
focusing.get(id)?.();
|
|
276
|
+
let frame;
|
|
277
|
+
const stop = () => {
|
|
278
|
+
observer.disconnect();
|
|
279
|
+
if (frame !== void 0) view().cancelAnimationFrame(frame);
|
|
280
|
+
if (focusing.get(id) === stop) focusing.delete(id);
|
|
281
|
+
};
|
|
282
|
+
const restore = () => {
|
|
283
|
+
if (disposed) return stop();
|
|
284
|
+
const field = root.querySelector(
|
|
285
|
+
`[data-component="token-search-field"][data-token-search-id="${CSS.escape(id)}"]`
|
|
180
286
|
);
|
|
181
|
-
|
|
287
|
+
const target = field?.querySelector(selector);
|
|
288
|
+
if (!field || !target) return;
|
|
289
|
+
const active = field.ownerDocument.activeElement;
|
|
290
|
+
if (guardMovedFocus && active !== field.ownerDocument.body && active !== target && !field.contains(active))
|
|
291
|
+
return stop();
|
|
292
|
+
stop();
|
|
182
293
|
if (target.matches("[data-token-search-editor]"))
|
|
183
294
|
placeTokenSearchCaret(target);
|
|
184
295
|
else target.focus();
|
|
296
|
+
};
|
|
297
|
+
const observer = new MutationObserver(restore);
|
|
298
|
+
observer.observe(root, { childList: true, subtree: true });
|
|
299
|
+
focusing.set(id, stop);
|
|
300
|
+
view().queueMicrotask(restore);
|
|
301
|
+
frame = view().requestAnimationFrame(() => {
|
|
302
|
+
frame = void 0;
|
|
303
|
+
restore();
|
|
304
|
+
stop();
|
|
185
305
|
});
|
|
186
306
|
};
|
|
187
307
|
const openField = (id) => {
|
|
@@ -203,12 +323,12 @@ function wireTokenSearchFields(root, {
|
|
|
203
323
|
'[data-component="token-search-field"]'
|
|
204
324
|
);
|
|
205
325
|
const id = field?.dataset.tokenSearchId;
|
|
206
|
-
const
|
|
207
|
-
if (!id ||
|
|
326
|
+
const offset2 = selectedAll ? 0 : caretQueryOffset(editor);
|
|
327
|
+
if (!id || offset2 === void 0 || field?.dataset.disabled === "true")
|
|
208
328
|
return;
|
|
209
329
|
pending.set(id, {
|
|
210
330
|
id,
|
|
211
|
-
offset,
|
|
331
|
+
offset: offset2,
|
|
212
332
|
tokenCount: editor.querySelectorAll(
|
|
213
333
|
'[data-component="token-search-token"]'
|
|
214
334
|
).length,
|
|
@@ -269,7 +389,7 @@ function wireTokenSearchFields(root, {
|
|
|
269
389
|
const commit = typeof input.data === "string" && /\s$/.test(input.data) || input.inputType === "insertFromPaste" && /\s$/.test(current.query);
|
|
270
390
|
model.edit(current, commit);
|
|
271
391
|
if (model.state.value.tokens.length > before)
|
|
272
|
-
focusAfterRender(id, "[data-token-search-editor]");
|
|
392
|
+
focusAfterRender(id, "[data-token-search-editor]", true);
|
|
273
393
|
}
|
|
274
394
|
if (onEdit) onEdit({ id, editor, event });
|
|
275
395
|
}
|
|
@@ -366,7 +486,11 @@ function wireTokenSearchFields(root, {
|
|
|
366
486
|
editor,
|
|
367
487
|
direction
|
|
368
488
|
};
|
|
369
|
-
models[id]
|
|
489
|
+
if (models[id]) {
|
|
490
|
+
const offset2 = caretQueryOffset(editor);
|
|
491
|
+
if (offset2 !== void 0) restoreDeletion(editor, { id, offset: offset2 });
|
|
492
|
+
models[id].remove(removal.value);
|
|
493
|
+
}
|
|
370
494
|
onRemoveToken?.(removal);
|
|
371
495
|
return;
|
|
372
496
|
}
|
|
@@ -422,7 +546,7 @@ function wireTokenSearchFields(root, {
|
|
|
422
546
|
const value = element.dataset.tokenSearchSuggestion;
|
|
423
547
|
if (!id || !value || field?.dataset.disabled === "true") return;
|
|
424
548
|
models[id]?.choose(value);
|
|
425
|
-
focusAfterRender(id, "[data-token-search-editor]");
|
|
549
|
+
focusAfterRender(id, "[data-token-search-editor]", true);
|
|
426
550
|
}
|
|
427
551
|
),
|
|
428
552
|
delegate(
|
|
@@ -438,7 +562,7 @@ function wireTokenSearchFields(root, {
|
|
|
438
562
|
if (!id || !value || field?.dataset.disabled === "true" || !models[id])
|
|
439
563
|
return;
|
|
440
564
|
models[id].expandToken(value);
|
|
441
|
-
focusAfterRender(id, "[data-token-search-editor]");
|
|
565
|
+
focusAfterRender(id, "[data-token-search-editor]", true);
|
|
442
566
|
}
|
|
443
567
|
),
|
|
444
568
|
delegate(
|
|
@@ -494,7 +618,7 @@ function wireTokenSearchFields(root, {
|
|
|
494
618
|
'[data-component="token-search-field"]'
|
|
495
619
|
);
|
|
496
620
|
const id = field?.dataset.tokenSearchId;
|
|
497
|
-
if (!id || field.dataset.collapsible !== "true" || field.dataset.disabled === "true")
|
|
621
|
+
if (!id || field.dataset.collapsible !== "true" && !models[id] || field.dataset.disabled === "true")
|
|
498
622
|
return;
|
|
499
623
|
const editor = replacementEditor(root, id);
|
|
500
624
|
clearing.get(id)?.();
|
|
@@ -516,7 +640,7 @@ function wireTokenSearchFields(root, {
|
|
|
516
640
|
observer.observe(root, { childList: true, subtree: true });
|
|
517
641
|
const timeout = view().setTimeout(stop, 0);
|
|
518
642
|
clearing.set(id, stop);
|
|
519
|
-
setExpanded(id, true);
|
|
643
|
+
if (field.dataset.collapsible === "true") setExpanded(id, true);
|
|
520
644
|
const current = replacementEditor(root, id);
|
|
521
645
|
if (current && ownsFocus(current)) placeTokenSearchCaret(current);
|
|
522
646
|
}
|
|
@@ -536,10 +660,14 @@ function wireTokenSearchFields(root, {
|
|
|
536
660
|
);
|
|
537
661
|
root.ownerDocument.addEventListener(
|
|
538
662
|
"pointercancel",
|
|
539
|
-
|
|
663
|
+
cancelPointerActivation,
|
|
664
|
+
true
|
|
665
|
+
);
|
|
666
|
+
root.ownerDocument.addEventListener(
|
|
667
|
+
"click",
|
|
668
|
+
clearPointerActivationAfterClick,
|
|
540
669
|
true
|
|
541
670
|
);
|
|
542
|
-
root.ownerDocument.addEventListener("click", clearPointerActivation, true);
|
|
543
671
|
disposers.push(
|
|
544
672
|
() => root.ownerDocument.removeEventListener(
|
|
545
673
|
"pointerdown",
|
|
@@ -553,12 +681,12 @@ function wireTokenSearchFields(root, {
|
|
|
553
681
|
),
|
|
554
682
|
() => root.ownerDocument.removeEventListener(
|
|
555
683
|
"pointercancel",
|
|
556
|
-
|
|
684
|
+
cancelPointerActivation,
|
|
557
685
|
true
|
|
558
686
|
),
|
|
559
687
|
() => root.ownerDocument.removeEventListener(
|
|
560
688
|
"click",
|
|
561
|
-
|
|
689
|
+
clearPointerActivationAfterClick,
|
|
562
690
|
true
|
|
563
691
|
)
|
|
564
692
|
);
|
|
@@ -592,17 +720,28 @@ function wireTokenSearchFields(root, {
|
|
|
592
720
|
if (next instanceof Node && field.contains(next)) return;
|
|
593
721
|
if (isExemptTarget(next instanceof Element ? next : null)) return;
|
|
594
722
|
if (!editorIsEmpty(editor)) return;
|
|
595
|
-
|
|
723
|
+
const collapseIfStillEmptyAndBlurred = () => {
|
|
724
|
+
if (disposed || !editorIsEmpty(editor)) return;
|
|
596
725
|
const active = field.ownerDocument.activeElement;
|
|
597
726
|
if (!field.contains(active) && !isExemptTarget(active))
|
|
598
727
|
setExpanded(id, false);
|
|
599
|
-
}
|
|
728
|
+
};
|
|
729
|
+
if (pointerActivationTarget)
|
|
730
|
+
pendingPointerBlurCollapses.set(id, collapseIfStillEmptyAndBlurred);
|
|
731
|
+
else view().queueMicrotask(collapseIfStillEmptyAndBlurred);
|
|
600
732
|
}
|
|
601
733
|
)
|
|
602
734
|
);
|
|
603
735
|
}
|
|
604
736
|
const dispose = () => {
|
|
605
737
|
disposed = true;
|
|
738
|
+
if (pointerReleaseTimer !== void 0)
|
|
739
|
+
view().clearTimeout(pointerReleaseTimer);
|
|
740
|
+
pendingPointerBlurCollapses.clear();
|
|
741
|
+
suggestionsObserver.disconnect();
|
|
742
|
+
for (const stop of positionedSuggestions.values()) stop();
|
|
743
|
+
positionedSuggestions.clear();
|
|
744
|
+
for (const stop of focusing.values()) stop();
|
|
606
745
|
for (const stop of disposers.splice(0)) stop();
|
|
607
746
|
};
|
|
608
747
|
const handle = (() => dispose());
|
|
@@ -619,4 +758,4 @@ function wireTokenSearchFields(root, {
|
|
|
619
758
|
|
|
620
759
|
export { wireTokenSearchFields };
|
|
621
760
|
|
|
622
|
-
//# sourceMappingURL=chunk-
|
|
761
|
+
//# sourceMappingURL=chunk-M5H2RMCH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/wire-token-search-fields.ts"],"names":["offset","block","keyboard"],"mappings":";;;;AAuIA,SAAS,eAAA,CACP,MACA,KAAA,EACyB;AACzB,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,EAAA,IAAI,EAAE,kBAAkB,OAAA,CAAA,EAAU;AAClC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,OAAA,CAAqB,4BAA4B,CAAA;AACvE,EAAA,OAAO,MAAA,IAAU,IAAA,CAAK,QAAA,CAAS,MAAM,IAAI,MAAA,GAAS,MAAA;AACpD;AAEA,SAAS,iBAAiB,MAAA,EAAyC;AACjE,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,aAAA,CAAc,YAAA,EAAa;AACpD,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,UAAA,KAAe,CAAA,EAAG;AAC9C,EAAA,MAAM,cAAA,GAAiB,SAAA,CAAU,UAAA,CAAW,CAAC,CAAA;AAC7C,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,cAAA,CAAe,cAAc,CAAA,EAAG;AACrD,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,aAAA,CAAc,WAAA,EAAY;AACrD,EAAA,WAAA,CAAY,mBAAmB,MAAM,CAAA;AACrC,EAAA,WAAA,CAAY,MAAA,CAAO,cAAA,CAAe,cAAA,EAAgB,cAAA,CAAe,WAAW,CAAA;AAC5E,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,aAAA,CAAc,aAAA,CAAc,KAAK,CAAA;AACvD,EAAA,MAAA,CAAO,MAAA,CAAO,WAAA,CAAY,aAAA,EAAe,CAAA;AACzC,EAAA,OAAO,oBAAA,CAAqB,MAAM,CAAA,CAAE,KAAA,CAAM,MAAA;AAC5C;AAEA,SAAS,iBAAA,CACP,MACA,EAAA,EACyB;AACzB,EAAA,OAAO;AAAA,IACL,GAAG,IAAA,CAAK,gBAAA,CAA8B,4BAA4B;AAAA,IAClE,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,OAAA,CAAQ,sBAAsB,EAAE,CAAA;AAC5D;AAEA,SAAS,cAAc,MAAA,EAA8B;AACnD,EAAA,MAAM,KAAA,GAAQ,qBAAqB,MAAM,CAAA;AACzC,EAAA,OAAO,MAAM,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,KAAA,CAAM,OAAO,MAAA,KAAW,CAAA;AAC7D;AAGA,SAAS,sBAAsB,MAAA,EAA8B;AAE3D,EAAA,MAAM,WAAW,MAAA,CAAO,aAAA,CAAc,YAAA,EAAa,CAAG,WAAW,CAAC,CAAA;AAClE,EAAA,IAAI,SAAS,SAAA,IAAa,CAAC,MAAA,CAAO,QAAA,CAAS,SAAS,uBAAuB,CAAA;AACzE,IAAA,OAAO,KAAA;AAIT,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,aAAA,CAAc,aAAA,CAAc,KAAK,CAAA;AAC7D,EAAA,YAAA,CAAa,MAAA,CAAO,QAAA,CAAS,aAAA,EAAe,CAAA;AAC5C,EAAA,MAAM,SAAA,GAAY,qBAAqB,MAAM,CAAA;AAC7C,EAAA,MAAM,aAAA,GAAgB,qBAAqB,YAAY,CAAA;AACvD,EAAA,OACE,aAAA,CAAc,KAAA,KAAU,SAAA,CAAU,KAAA,IAClC,aAAA,CAAc,MAAA,CAAO,MAAA,KAAW,SAAA,CAAU,MAAA,CAAO,MAAA,IACjD,aAAA,CAAc,MAAA,CAAO,KAAA;AAAA,IACnB,CAAC,OAAO,KAAA,KAAU,KAAA,CAAM,UAAU,SAAA,CAAU,MAAA,CAAO,KAAK,CAAA,EAAG;AAAA,GAC7D;AAEJ;AAEA,IAAM,cAAA,GAAiB,uCAAA;AACvB,IAAM,aAAA,GAAgB,0BAAA;AACtB,IAAM,YAAY,CAAC,IAAA,KAAyB,IAAA,CAAK,UAAA,CAAW,UAAK,EAAE,CAAA;AAUnE,SAAS,sBAAA,CACP,MAAA,EACA,WAAA,GAAc,KAAA,EACR;AACN,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,gBAAA,CAAiB,IAAI,CAAA;AAC/C,EAAA,IAAI,UAAA,CAAW,MAAA,KAAW,CAAA,IAAK,CAAC,WAAA,EAAa;AAC7C,EAAA,KAAA,MAAW,SAAA,IAAa,UAAA,EAAY,SAAA,CAAU,MAAA,EAAO;AACrD,EAAA,IAAI,CAAC,WAAA,IAAe,MAAA,CAAO,aAAA,CAAc,cAAc,CAAA,EAAG;AAC1D,EAAA,IAAI,CAAC,WAAA,IAAe,SAAA,CAAU,OAAO,WAAA,IAAe,EAAE,MAAM,EAAA,EAAI;AAChE,EAAA,MAAM,MAAM,MAAA,CAAO,aAAA;AACnB,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,aAAA,CAAc,MAAM,CAAA;AACrC,EAAA,IAAA,CAAK,YAAA,CAAa,0BAA0B,EAAE,CAAA;AAC9C,EAAA,IAAA,CAAK,YAAA,CAAa,cAAc,MAAM,CAAA;AACtC,EAAA,MAAA,CAAO,gBAAgB,IAAI,CAAA;AAC3B,EAAA,IAAI,GAAA,CAAI,kBAAkB,MAAA,EAAQ;AAElC,EAAA,MAAM,SAAA,GAAY,IAAI,YAAA,EAAa;AACnC,EAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY;AAC9B,EAAA,KAAA,CAAM,QAAA,CAAS,MAAM,CAAC,CAAA;AACtB,EAAA,KAAA,CAAM,SAAS,IAAI,CAAA;AACnB,EAAA,SAAA,CAAU,eAAA,EAAgB;AAC1B,EAAA,SAAA,CAAU,SAAS,KAAK,CAAA;AAC1B;AAGA,SAAS,eAAe,MAAA,EAAwC;AAC9D,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,aAAA,CAAc,YAAA,EAAa;AACpD,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,UAAA,KAAe,CAAA,EAAG;AAC9C,EAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,UAAA,CAAW,CAAC,CAAA;AACpC,EAAA,IAAI,CAAC,MAAM,SAAA,IAAa,CAAC,OAAO,QAAA,CAAS,KAAA,CAAM,cAAc,CAAA,EAAG;AAChE,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,QAAA,CAAS,QAAqB,IAAA,EAAyB;AAC9D,EAAA,IAAI,OAAA,GAAgB,IAAA;AACpB,EAAA,OAAO,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,UAAA,KAAe,MAAA;AAClD,IAAA,OAAA,GAAU,OAAA,CAAQ,UAAA;AACpB,EAAA,OAAO,OAAA,CAAQ,UAAA,KAAe,MAAA,GAAS,OAAA,GAAU,IAAA;AACnD;AAGA,SAAS,YAAY,IAAA,EAAqB;AACxC,EAAA,IAAI,IAAA,CAAK,aAAa,IAAA,CAAK,SAAA;AACzB,IAAA,OAAO,SAAA,CAAW,IAAA,CAAuB,IAAI,CAAA,KAAM,EAAA;AACrD,EAAA,OACE,IAAA,YAAgB,OAAA,IAChB,IAAA,CAAK,OAAA,CAAQ,aAAa,KAC1B,SAAA,CAAU,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA,KAAM,EAAA;AAE1C;AAGA,SAAS,iBAAA,CACP,OACA,SAAA,EACa;AACb,EAAA,IAAI,OAAA,GACF,SAAA,KAAc,UAAA,GAAa,KAAA,CAAM,kBAAkB,KAAA,CAAM,WAAA;AAC3D,EAAA,OAAO,OAAA,IAAW,YAAY,OAAO,CAAA;AACnC,IAAA,OAAA,GACE,SAAA,KAAc,UAAA,GAAa,OAAA,CAAQ,eAAA,GAAkB,OAAA,CAAQ,WAAA;AACjE,EAAA,OAAO,OAAA;AACT;AAGA,SAAS,aAAA,CACP,MAAA,EACA,KAAA,EACA,SAAA,EACa;AACb,EAAA,MAAM,EAAE,cAAA,EAAgB,SAAA,EAAW,WAAA,EAAaA,SAAO,GAAI,KAAA;AAC3D,EAAA,IAAI,SAAA,CAAU,QAAA,KAAa,IAAA,CAAK,SAAA,EAAW;AACzC,IAAA,MAAM,OAAQ,SAAA,CAA4B,IAAA;AAC1C,IAAA,MAAM,IAAA,GACJ,SAAA,KAAc,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,GAAGA,OAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAMA,OAAM,CAAA;AACtE,IAAA,IAAI,SAAA,CAAU,IAAI,CAAA,CAAE,MAAA,GAAS,GAAG,OAAO,IAAA;AAEvC,IAAA,OAAO,iBAAA,CAAkB,QAAA,CAAS,MAAA,EAAQ,SAAS,GAAI,SAAS,CAAA;AAAA,EAClE;AACA,EAAA,MAAM,QAAQ,SAAA,CAAU,UAAA,CACtB,cAAc,UAAA,GAAaA,OAAAA,GAAS,IAAIA,OAC1C,CAAA;AACA,EAAA,IAAI,KAAA,EAAO;AAET,IAAA,MAAMC,MAAAA,GAAQ,QAAA,CAAS,MAAA,EAAQ,KAAK,CAAA;AACpC,IAAA,OAAO,YAAY,KAAK,CAAA,GAAI,iBAAA,CAAkBA,MAAAA,EAAO,SAAS,CAAA,GAAIA,MAAAA;AAAA,EACpE;AACA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,MAAA,EAAQ,SAAS,CAAA;AACxC,EAAA,OAAO,KAAA,GAAQ,iBAAA,CAAkB,KAAA,EAAO,SAAS,CAAA,GAAI,IAAA;AACvD;AAGA,SAAS,aAAA,CACP,QACA,SAAA,EACyB;AACzB,EAAA,MAAM,KAAA,GAAQ,eAAe,MAAM,CAAA;AACnC,EAAA,IAAI,CAAC,KAAA,EAAO;AACZ,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAA,EAAQ,KAAA,EAAO,SAAS,CAAA;AACnD,EAAA,IAAI,CAAC,IAAA,EAAM;AACX,EAAA,MAAM,IAAA,GAAO,IAAA,YAAgB,OAAA,GAAU,IAAA,GAAO,IAAA,CAAK,aAAA;AACnD,EAAA,MAAM,IAAA,GAAO,IAAA,EAAM,OAAA,CAAqB,cAAc,CAAA,IAAK,IAAA;AAC3D,EAAA,OAAO,IAAA,IAAQ,MAAA,CAAO,QAAA,CAAS,IAAI,IAAI,IAAA,GAAO,MAAA;AAChD;AAKA,SAAS,oBAAA,CAAqB,QAAqB,IAAA,EAAyB;AAC1E,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,aAAA,CAAc,YAAA,EAAa;AACpD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,aAAA,CAAc,WAAA,EAAY;AAC/C,EAAA,KAAA,CAAM,aAAA,CAAc,QAAA,CAAS,MAAA,EAAQ,IAAI,CAAE,CAAA;AAC3C,EAAA,KAAA,CAAM,SAAS,IAAI,CAAA;AACnB,EAAA,SAAA,CAAU,eAAA,EAAgB;AAC1B,EAAA,SAAA,CAAU,SAAS,KAAK,CAAA;AACxB,EAAA,MAAA,CAAO,KAAA,CAAM,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA;AACtC;AAQO,SAAS,sBACd,IAAA,EACA;AAAA,EACE,SAAS,EAAC;AAAA,EACV,QAAA;AAAA,EACA,MAAA;AAAA,EACA,WAAA,GAAc,IAAA;AAAA,EACd,QAAA,GAAW;AACb,CAAA,GAAkC,EAAC,EACV;AACzB,EAAA,MAAM,UAAU,WAAA,KAAgB,KAAA;AAChC,EAAA,MAAM,MAAA,GAAS,OAAO,WAAA,KAAgB,QAAA,GAAW,cAAc,EAAC;AAChE,EAAA,MAAM,gBAAA,GAAmB,OAAA,KAAY,MAAA,CAAO,gBAAA,IAAoB,IAAA,CAAA;AAChE,EAAA,MAAM,mBAAA,GAAsB,OAAA,KAAY,MAAA,CAAO,mBAAA,IAAuB,IAAA,CAAA;AACtE,EAAA,MAAM,gBAAA,GAAmB,OAAA,KAAY,MAAA,CAAO,gBAAA,IAAoB,IAAA,CAAA;AAChE,EAAA,MAAM,WAAA,GAAc,OAAA,KAAY,MAAA,CAAO,WAAA,IAAe,IAAA,CAAA;AACtD,EAAA,MAAM,aAAa,MAAA,CAAO,UAAA;AAC1B,EAAA,MAAM,aAAa,QAAA,KAAa,KAAA,IAAS,OAAO,IAAA,CAAK,MAAM,EAAE,MAAA,GAAS,CAAA;AACtE,EAAA,MAAM,cAAA,GAAiB,OAAO,QAAA,KAAa,QAAA,GAAW,QAAA,GAAW,MAAA;AACjE,EAAA,MAAM,mBAAA,GACJ,UAAA,KAAe,cAAA,EAAgB,mBAAA,IAAuB,IAAA,CAAA;AACxD,EAAA,MAAM,kBAAA,GACJ,UAAA,KAAe,cAAA,EAAgB,kBAAA,IAAsB,IAAA,CAAA;AACvD,EAAA,MAAM,gBAAgB,cAAA,EAAgB,aAAA;AACtC,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,IAAW,EAAC;AACnC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAA6B;AACjD,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,IAAI,uBAAA,GAA0C,IAAA;AAC9C,EAAA,MAAM,2BAAA,uBAAkC,GAAA,EAAwB;AAChE,EAAA,IAAI,mBAAA;AACJ,EAAA,MAAM,qBAAA,uBAA4B,GAAA,EAA6B;AAE/D,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,MAAM,UAAU,IAAI,GAAA;AAAA,MAClB,IAAA,CAAK,iBAA8B,gCAAgC;AAAA,KACrE;AACA,IAAA,KAAA,MAAW,CAAC,KAAA,EAAO,IAAI,CAAA,IAAK,qBAAA,EAAuB;AACjD,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACxB,MAAA,IAAA,EAAK;AACL,MAAA,qBAAA,CAAsB,OAAO,KAAK,CAAA;AAAA,IACpC;AACA,IAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,KAAK,CAAA,EAAG;AACtC,MAAA,MAAM,QAAQ,KAAA,CAAM,OAAA;AAAA,QAClB;AAAA,OACF;AACA,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,IAAI,MAAA,GAAS,IAAA;AACb,MAAA,KAAA,CAAM,MAAM,QAAA,GAAW,UAAA;AACvB,MAAA,KAAA,CAAM,MAAM,eAAA,GAAkB,MAAA;AAC9B,MAAA,KAAA,CAAM,MAAM,gBAAA,GAAmB,MAAA;AAC/B,MAAA,KAAA,CAAM,MAAM,IAAA,GAAO,GAAA;AACnB,MAAA,KAAA,CAAM,MAAM,GAAA,GAAM,GAAA;AAClB,MAAA,KAAA,CAAM,MAAM,UAAA,GAAa,QAAA;AACzB,MAAA,MAAM,SAAS,YAAY;AACzB,QAAA,MAAM,QAAQ,IAAA,CAAK,GAAA;AAAA,UACjB,KAAK,GAAA,CAAI,KAAA,CAAM,qBAAA,EAAsB,CAAE,OAAO,GAAG,CAAA;AAAA,UACjD,KAAK,GAAA,CAAI,CAAA,EAAG,MAAM,aAAA,CAAc,WAAA,CAAa,aAAa,EAAE;AAAA,SAC9D;AACA,QAAA,KAAA,CAAM,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG,KAAK,CAAA,EAAA,CAAA;AAC5B,QAAA,MAAM,QAAA,GAAW,MAAM,eAAA,CAAgB,KAAA,EAAO,KAAA,EAAO;AAAA,UACnD,QAAA,EAAU,UAAA;AAAA,UACV,SAAA,EAAW,cAAA;AAAA,UACX,UAAA,EAAY;AAAA,YACV,OAAO,CAAC,CAAA;AAAA,YACR,IAAA,CAAK,EAAE,OAAA,EAAS,CAAA,EAAG,CAAA;AAAA,YACnB,KAAA,CAAM,EAAE,OAAA,EAAS,CAAA,EAAG,CAAA;AAAA,YACpB,IAAA,CAAK;AAAA,cACH,OAAA,EAAS,CAAA;AAAA,cACT,KAAA,CAAM,EAAE,eAAA,EAAgB,EAAG;AACzB,gBAAA,KAAA,CAAM,KAAA,CAAM,SAAA,GAAY,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,eAAe,CAAC,CAAC,CAAA,EAAA,CAAA;AAAA,cACxE;AAAA,aACD;AAAA;AACH,SACD,CAAA;AACD,QAAA,IAAI,CAAC,MAAA,IAAU,QAAA,IAAY,CAAC,MAAM,WAAA,EAAa;AAC/C,QAAA,KAAA,CAAM,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,QAAA,CAAS,CAAC,CAAA,EAAA,CAAA;AAChC,QAAA,KAAA,CAAM,KAAA,CAAM,GAAA,GAAM,CAAA,EAAG,QAAA,CAAS,CAAC,CAAA,EAAA,CAAA;AAC/B,QAAA,KAAA,CAAM,MAAM,UAAA,GAAa,SAAA;AAAA,MAC3B,CAAA;AACA,MAAA,MAAM,iBAAiB,UAAA,CAAW,KAAA,EAAO,OAAO,MAAM,KAAK,QAAO,EAAG;AAAA,QACnE,WAAA,EAAa;AAAA,OACd,CAAA;AACD,MAAA,qBAAA,CAAsB,GAAA,CAAI,OAAO,MAAM;AACrC,QAAA,MAAA,GAAS,KAAA;AACT,QAAA,cAAA,EAAe;AACf,QAAA,KAAA,MAAW,QAAA,IAAY;AAAA,UACrB,UAAA;AAAA,UACA,mBAAA;AAAA,UACA,oBAAA;AAAA,UACA,MAAA;AAAA,UACA,KAAA;AAAA,UACA,YAAA;AAAA,UACA,OAAA;AAAA,UACA;AAAA,SACF;AACE,UAAA,KAAA,CAAM,KAAA,CAAM,eAAe,QAAQ,CAAA;AAAA,MACvC,CAAC,CAAA;AAAA,IACH;AAAA,EACF,CAAA;AACA,EAAA,MAAM,mBAAA,GAAsB,IAAI,gBAAA,CAAiB,eAAe,CAAA;AAChE,EAAA,mBAAA,CAAoB,QAAQ,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AACpE,EAAA,eAAA,EAAgB;AAGhB,EAAA,MAAM,cAAA,GAAiB,CAAC,OAAA,KAAqC;AAC3D,IAAA,IAAI,CAAC,SAAS,OAAO,KAAA;AACrB,IAAA,IAAI,OAAA,CAAQ,OAAA,CAAQ,+BAA+B,CAAA,EAAG,OAAO,IAAA;AAC7D,IAAA,OAAO,UAAA,GAAa,UAAA,CAAW,OAAO,CAAA,GAAI,KAAA;AAAA,EAC5C,CAAA;AAMA,EAAA,MAAM,sBAAA,GAAyB,CAAC,KAAA,KAAiB;AAC/C,IAAA,IAAI,mBAAA,KAAwB,MAAA;AAC1B,MAAA,IAAA,EAAK,CAAE,aAAa,mBAAmB,CAAA;AACzC,IAAA,mBAAA,GAAsB,MAAA;AACtB,IAAA,uBAAA,GACE,KAAA,CAAM,MAAA,YAAkB,OAAA,GAAU,KAAA,CAAM,MAAA,GAAS,IAAA;AAAA,EACrD,CAAA;AACA,EAAA,MAAM,4BAA4B,MAAM;AACtC,IAAA,mBAAA,GAAsB,MAAA;AACtB,IAAA,KAAA,MAAW,QAAA,IAAY,2BAAA,CAA4B,MAAA,EAAO,EAAG,QAAA,EAAS;AACtE,IAAA,2BAAA,CAA4B,KAAA,EAAM;AAAA,EACpC,CAAA;AACA,EAAA,MAAM,yBAAyB,MAAM;AACnC,IAAA,IAAI,2BAAA,CAA4B,SAAS,CAAA,EAAG;AAC5C,IAAA,IAAI,mBAAA,KAAwB,MAAA;AAC1B,MAAA,IAAA,EAAK,CAAE,aAAa,mBAAmB,CAAA;AAGzC,IAAA,mBAAA,GAAsB,IAAA,EAAK,CAAE,UAAA,CAAW,yBAAA,EAA2B,CAAC,CAAA;AAAA,EACtE,CAAA;AACA,EAAA,MAAM,yBAAyB,MAAM;AACnC,IAAA,uBAAA,GAA0B,IAAA;AAAA,EAC5B,CAAA;AACA,EAAA,MAAM,qCAAqC,MAAM;AAC/C,IAAA,IAAA,EAAK,CAAE,eAAe,sBAAsB,CAAA;AAC5C,IAAA,sBAAA,EAAuB;AAAA,EACzB,CAAA;AACA,EAAA,MAAM,mCAAmC,MAAM;AAC7C,IAAA,sBAAA,EAAuB;AACvB,IAAA,sBAAA,EAAuB;AAAA,EACzB,CAAA;AACA,EAAA,MAAM,0BAA0B,MAAM;AACpC,IAAA,sBAAA,EAAuB;AACvB,IAAA,sBAAA,EAAuB;AAAA,EACzB,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,EAAA,KAAgC;AACjD,IAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,IAAA,IAAI,KAAK,OAAO,GAAA;AAChB,IAAA,IAAI,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAC1B,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,KAAA,GAAQ,OAAO,KAAK,CAAA;AACpB,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAI,KAAK,CAAA;AAAA,IACvB;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AACA,EAAA,MAAM,WAAA,GAAc,CAAC,EAAA,EAAY,IAAA,KAAkB;AACjD,IAAA,MAAM,KAAA,GAAQ,UAAU,EAAE,CAAA;AAC1B,IAAA,IAAI,KAAA,CAAM,KAAA,KAAU,IAAA,EAAM,KAAA,CAAM,KAAA,GAAQ,IAAA;AAAA,EAC1C,CAAA;AACA,EAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,WAAA;AACtC,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAwB;AAC7C,EAAA,MAAM,gBAAA,GAAmB,CACvB,EAAA,EACA,QAAA,EACA,kBAAkB,KAAA,KACf;AACH,IAAA,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA,IAAI;AACnB,IAAA,IAAI,KAAA;AACJ,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,IAAI,KAAA,KAAU,MAAA,EAAW,IAAA,EAAK,CAAE,qBAAqB,KAAK,CAAA;AAC1D,MAAA,IAAI,SAAS,GAAA,CAAI,EAAE,MAAM,IAAA,EAAM,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,IACnD,CAAA;AACA,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,IAAI,QAAA,SAAiB,IAAA,EAAK;AAC1B,MAAA,MAAM,QAAQ,IAAA,CAAK,aAAA;AAAA,QACjB,CAAA,4DAAA,EAA+D,GAAA,CAAI,MAAA,CAAO,EAAE,CAAC,CAAA,EAAA;AAAA,OAC/E;AACA,MAAA,MAAM,MAAA,GAAS,KAAA,EAAO,aAAA,CAA2B,QAAQ,CAAA;AACzD,MAAA,IAAI,CAAC,KAAA,IAAS,CAAC,MAAA,EAAQ;AACvB,MAAA,MAAM,MAAA,GAAS,MAAM,aAAA,CAAc,aAAA;AAInC,MAAA,IACE,eAAA,IACA,MAAA,KAAW,KAAA,CAAM,aAAA,CAAc,IAAA,IAC/B,WAAW,MAAA,IACX,CAAC,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AAEtB,QAAA,OAAO,IAAA,EAAK;AACd,MAAA,IAAA,EAAK;AACL,MAAA,IAAI,MAAA,CAAO,QAAQ,4BAA4B,CAAA;AAC7C,QAAA,qBAAA,CAAsB,MAAM,CAAA;AAAA,kBAClB,KAAA,EAAM;AAAA,IACpB,CAAA;AACA,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,OAAO,CAAA;AAC7C,IAAA,QAAA,CAAS,QAAQ,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AACzD,IAAA,QAAA,CAAS,GAAA,CAAI,IAAI,IAAI,CAAA;AACrB,IAAA,IAAA,EAAK,CAAE,eAAe,OAAO,CAAA;AAI7B,IAAA,KAAA,GAAQ,IAAA,EAAK,CAAE,qBAAA,CAAsB,MAAM;AACzC,MAAA,KAAA,GAAQ,MAAA;AACR,MAAA,OAAA,EAAQ;AACR,MAAA,IAAA,EAAK;AAAA,IACP,CAAC,CAAA;AAAA,EACH,CAAA;AACA,EAAA,MAAM,SAAA,GAAY,CAAC,EAAA,KAAe;AAChC,IAAA,WAAA,CAAY,IAAI,IAAI,CAAA;AACpB,IAAA,IAAI,WAAA,EAAa,gBAAA,CAAiB,EAAA,EAAI,4BAA4B,CAAA;AAAA,EACpE,CAAA;AACA,EAAA,MAAM,UAAA,GAAa,CAAC,EAAA,KAAe;AACjC,IAAA,WAAA,CAAY,IAAI,KAAK,CAAA;AACrB,IAAA,IAAI,WAAA,EAAa,gBAAA,CAAiB,EAAA,EAAI,2BAA2B,CAAA;AAAA,EACnE,CAAA;AAEA,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAwB;AAC7C,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAkC;AACtD,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAwB;AAC7C,EAAA,MAAM,gBAAA,uBAAuB,OAAA,EAAqB;AAElD,EAAA,MAAM,QAAA,GAAW,CAAC,MAAA,KAChB,MAAA,CAAO,OAAA,CAAQ,iBAAA;AACjB,EAAA,MAAM,eAAA,GAAkB,CAAC,MAAA,EAAqB,WAAA,KAA0B;AACtE,IAAA,IAAI,MAAA,CAAO,aAAA,CAAc,aAAA,KAAkB,MAAA,EAAQ;AACnD,IAAA,MAAM,QAAQ,MAAA,CAAO,OAAA;AAAA,MACnB;AAAA,KACF;AACA,IAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,IAAA,MAAMD,OAAAA,GAAS,WAAA,GAAc,CAAA,GAAI,gBAAA,CAAiB,MAAM,CAAA;AACxD,IAAA,IAAI,CAAC,EAAA,IAAMA,OAAAA,KAAW,MAAA,IAAa,KAAA,EAAO,QAAQ,QAAA,KAAa,MAAA;AAC7D,MAAA;AACF,IAAA,OAAA,CAAQ,IAAI,EAAA,EAAI;AAAA,MACd,EAAA;AAAA,MACA,MAAA,EAAAA,OAAAA;AAAA,MACA,YAAY,MAAA,CAAO,gBAAA;AAAA,QACjB;AAAA,OACF,CAAE,MAAA;AAAA,MACF,WAAA,EAAa,WAAA,IAAe,qBAAA,CAAsB,MAAM;AAAA,KACzD,CAAA;AAAA,EACH,CAAA;AACA,EAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAiB;AACtC,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,EAAM,KAAK,CAAA;AAC1C,IAAA,IAAI,MAAA,IAAW,KAAA,CAAqB,SAAA,CAAU,UAAA,CAAW,QAAQ,CAAA;AAC/D,MAAA,eAAA,CAAgB,MAAM,CAAA;AAAA,EAC1B,CAAA;AACA,EAAA,MAAM,eAAA,GAAkB,CACtB,MAAA,EACA,QAAA,KACG;AACH,IAAA,QAAA,CAAS,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA,IAAI;AAC5B,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,IAAA,EAAK,CAAE,aAAa,OAAO,CAAA;AAC3B,MAAA,QAAA,CAAS,MAAA,CAAO,SAAS,EAAE,CAAA;AAAA,IAC7B,CAAA;AACA,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,MAAM,WAAA,GAAc,iBAAA,CAAkB,IAAA,EAAM,QAAA,CAAS,EAAE,CAAA;AAGvD,MAAA,IAAI,CAAC,WAAA,IAAe,WAAA,KAAgB,MAAA,EAAQ;AAC5C,MAAA,IAAA,EAAK;AACL,MAAA,MAAM,MAAA,GAAS,YAAY,aAAA,CAAc,aAAA;AACzC,MAAA,IACE,WAAW,MAAA,IACX,MAAA,KAAW,WAAA,IACX,MAAA,KAAW,YAAY,aAAA,CAAc,IAAA;AAErC,QAAA;AACF,MAAA,qBAAA,CAAsB,WAAA,EAAa,SAAS,MAAM,CAAA;AAAA,IACpD,CAAA;AACA,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,OAAO,CAAA;AAC7C,IAAA,QAAA,CAAS,QAAQ,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAGzD,IAAA,MAAM,OAAA,GAAU,IAAA,EAAK,CAAE,UAAA,CAAW,MAAM,CAAC,CAAA;AACzC,IAAA,QAAA,CAAS,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,IAAI,CAAA;AAAA,EAChC,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAAiB;AAChC,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,EAAM,KAAK,CAAA;AAC1C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAM,QAAA,GAAW,SAAS,MAAM,CAAA;AAChC,IAAA,MAAM,YAAa,KAAA,CAAqB,SAAA;AACxC,IAAA,IAAI,CAAC,SAAA,CAAU,UAAA,CAAW,QAAQ,CAAA,EAAG,gBAAA,CAAiB,OAAO,MAAM,CAAA;AACnE,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACrC,IAAA,IAAI,SAAA,CAAU,WAAW,QAAQ,CAAA;AAC/B,MAAA,sBAAA,CAAuB,MAAA,EAAQ,UAAU,WAAW,CAAA;AACtD,IAAA,MAAM,OAAA,GACJ,aACC,QAAA,CAAS,WAAA,IACR,OAAO,gBAAA,CAAiB,cAAc,CAAA,CAAE,MAAA,GAAS,QAAA,CAAS,UAAA,CAAA;AAG9D,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,eAAA,CAAgB,QAAQ,QAAQ,CAAA;AAChC,MAAA,IACE,eACA,MAAA,CAAO,OAAA,CAAqB,uCAAuC,CAAA,EAC/D,QAAQ,WAAA,KAAgB,MAAA;AAE5B,QAAA,WAAA,CAAY,UAAU,IAAI,CAAA;AAAA,IAC9B;AACA,IAAA,MAAM,QAAQ,MAAA,CAAO,OAAA;AAAA,MACnB;AAAA,KACF;AACA,IAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,IAAA,IAAI,EAAA,IAAM,KAAA,EAAO,OAAA,CAAQ,QAAA,KAAa,MAAA,EAAQ;AAC5C,MAAA,MAAM,KAAA,GAAQ,OAAO,EAAE,CAAA;AACvB,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,gBAAA,CAAiB,cAAc,CAAA,CAAE,MAAA;AACvD,QAAA,MAAM,UAAU,oBAAA,CAAqB,MAAA,EAAQ,KAAA,CAAM,KAAA,CAAM,MAAM,MAAM,CAAA;AACrE,QAAA,MAAM,KAAA,GAAQ,KAAA;AACd,QAAA,MAAM,SACH,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,IAAY,MAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,IACvD,MAAM,SAAA,KAAc,iBAAA,IAAqB,KAAA,CAAM,IAAA,CAAK,QAAQ,KAAK,CAAA;AACpE,QAAA,KAAA,CAAM,IAAA,CAAK,SAAS,MAAM,CAAA;AAC1B,QAAA,IAAI,KAAA,CAAM,KAAA,CAAM,KAAA,CAAM,MAAA,CAAO,MAAA,GAAS,MAAA;AACpC,UAAA,gBAAA,CAAiB,EAAA,EAAI,8BAA8B,IAAI,CAAA;AAAA,MAC3D;AACA,MAAA,IAAI,QAAQ,MAAA,CAAO,EAAE,EAAA,EAAI,MAAA,EAAQ,OAA4B,CAAA;AAAA,IAC/D;AACA,IAAA,OAAA,CAAQ,OAAO,QAAQ,CAAA;AAAA,EACzB,CAAA;AACA,EAAA,IAAA,CAAK,gBAAA,CAAiB,aAAA,EAAe,aAAA,EAAe,IAAI,CAAA;AACxD,EAAA,IAAA,CAAK,gBAAA,CAAiB,OAAA,EAAS,OAAA,EAAS,IAAI,CAAA;AAE5C,EAAA,MAAM,oBAAA,GAAuB,CAAC,KAAA,KAAiB;AAC7C,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,EAAM,KAAK,CAAA;AAC1C,IAAA,IAAI,MAAA,EAAQ,gBAAA,CAAiB,MAAA,CAAO,MAAM,CAAA;AAAA,EAC5C,CAAA;AACA,EAAA,MAAM,oBAAA,GAAuB,CAAC,KAAA,KAAiB;AAC7C,IAAA,MAAM,aAAA,GAAgB,KAAA;AACtB,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,EAAM,KAAK,CAAA;AAC1C,IAAA,IAAI,CAAC,MAAA,IAAU,aAAA,CAAc,WAAA,EAAa;AAC1C,IAAA,MAAM,qBAAA,GACJ,cAAc,GAAA,KAAQ,WAAA,GAClB,0BACA,aAAA,CAAc,GAAA,KAAQ,WACpB,sBAAA,GACA,MAAA;AACR,IAAA,IACE,aAAA,CAAc,GAAA,CAAI,WAAA,EAAY,KAAM,QACnC,aAAA,CAAc,OAAA,IAAW,aAAA,CAAc,OAAA,CAAA,IACxC,CAAC,aAAA,CAAc,MAAA,IACf,CAAC,cAAc,QAAA,EACf;AAEA,MAAA,gBAAA,CAAiB,IAAI,MAAM,CAAA;AAC3B,MAAA;AAAA,IACF;AACA,IAAA,IAAI,qBAAA,IAAyB,gBAAA,CAAiB,MAAA,CAAO,MAAM,CAAA,EAAG;AAC5D,MAAA,IAAI,MAAA,CAAO,aAAA,EAAe,OAAA,CAAQ,QAAA,KAAa,MAAA,EAAQ;AAMvD,MAAA,aAAA,CAAc,cAAA,EAAe;AAC7B,MAAA,eAAA,CAAgB,QAAQ,IAAI,CAAA;AAC5B,MAAA,sBAAA,CAAuB,QAAQ,IAAI,CAAA;AACnC,MAAA,MAAA,CAAO,aAAA;AAAA,QACL,IAAI,WAAW,OAAA,EAAS;AAAA,UACtB,OAAA,EAAS,IAAA;AAAA,UACT,SAAA,EAAW;AAAA,SACZ;AAAA,OACH;AACA,MAAA;AAAA,IACF;AAIA,IAAA,IAAI,CAAC,qBAAA,EAAuB,gBAAA,CAAiB,MAAA,CAAO,MAAM,CAAA;AAAA,EAC5D,CAAA;AACA,EAAA,IAAA,CAAK,gBAAA,CAAiB,SAAA,EAAW,oBAAA,EAAsB,IAAI,CAAA;AAC3D,EAAA,IAAA,CAAK,gBAAA,CAAiB,aAAA,EAAe,oBAAA,EAAsB,IAAI,CAAA;AAC/D,EAAA,IAAA,CAAK,gBAAA,CAAiB,UAAA,EAAY,oBAAA,EAAsB,IAAI,CAAA;AAE5D,EAAA,MAAM,SAAA,GAA+B;AAAA,IACnC,MAAM;AACJ,MAAA,OAAA,CAAQ,KAAA,EAAM;AACd,MAAA,KAAA,MAAW,IAAA,IAAQ,QAAA,CAAS,MAAA,EAAO,EAAG,IAAA,EAAK;AAAA,IAC7C,CAAA;AAAA,IACA,MAAM,IAAA,CAAK,mBAAA,CAAoB,aAAA,EAAe,eAAe,IAAI,CAAA;AAAA,IACjE,MAAM,IAAA,CAAK,mBAAA,CAAoB,OAAA,EAAS,SAAS,IAAI,CAAA;AAAA,IACrD,MAAM,IAAA,CAAK,mBAAA,CAAoB,SAAA,EAAW,sBAAsB,IAAI,CAAA;AAAA,IACpE,MAAM,IAAA,CAAK,mBAAA,CAAoB,aAAA,EAAe,sBAAsB,IAAI,CAAA;AAAA,IACxE,MAAM,IAAA,CAAK,mBAAA,CAAoB,UAAA,EAAY,sBAAsB,IAAI;AAAA,GACvE;AAEA,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,QAAA;AAAA,MACE,IAAA;AAAA,MACA,SAAA;AAAA,MACA,4BAAA;AAAA,MACA,CAAC,OAAO,OAAA,KAAY;AAClB,QAAA,MAAM,aAAA,GAAgB,KAAA;AACtB,QAAA,MAAM,MAAA,GAAS,OAAA;AACf,QAAA,IAAI,cAAc,WAAA,EAAa;AAC/B,QAAA,MAAM,QAAQ,MAAA,CAAO,OAAA;AAAA,UACnB;AAAA,SACF;AACA,QAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,QAAA,IAAI,CAAC,EAAA,IAAM,KAAA,EAAO,OAAA,CAAQ,aAAa,MAAA,EAAQ;AAC/C,QAAA,MAAM,mBAAmB,QAAA,KAAa,KAAA,IAAS,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAC,CAAA;AACjE,QAAA,IAAI,aAAA,CAAc,QAAQ,OAAA,EAAS;AACjC,UAAA,aAAA,CAAc,cAAA,EAAe;AAC7B,UAAA,MAAM,KAAA,GAAQ,OAAO,EAAE,CAAA;AACvB,UAAA,IAAI,KAAA;AACF,YAAA,KAAA,CAAM,MAAA;AAAA,cACJ,oBAAA,CAAqB,MAAA,EAAQ,KAAA,CAAM,KAAA,CAAM,MAAM,MAAM;AAAA,aACvD;AACF,UAAA,QAAA,GAAW,EAAE,EAAA,EAAI,MAAA,EAAQ,CAAA;AACzB,UAAA;AAAA,QACF;AACA,QAAA,IAAI,MAAA,CAAO,EAAE,CAAA,IAAK,aAAA,CAAc,QAAQ,WAAA,EAAa;AACnD,UAAA,MAAM,QAAQ,KAAA,CAAM,aAAA;AAAA,YAClB;AAAA,WACF;AACA,UAAA,IAAI,KAAA,EAAO;AACT,YAAA,aAAA,CAAc,cAAA,EAAe;AAC7B,YAAA,KAAA,CAAM,KAAA,EAAM;AACZ,YAAA;AAAA,UACF;AAAA,QACF;AACA,QAAA,IAAI,MAAA,CAAO,EAAE,CAAA,IAAK,aAAA,CAAc,QAAQ,QAAA,EAAU,MAAA,CAAO,EAAE,CAAA,CAAE,OAAA,EAAQ;AACrE,QAAA,IACE,oBACA,mBAAA,KACC,aAAA,CAAc,QAAQ,WAAA,IAAe,aAAA,CAAc,QAAQ,QAAA,CAAA,EAC5D;AACA,UAAA,MAAM,SAAA,GACJ,aAAA,CAAc,GAAA,KAAQ,WAAA,GAAc,UAAA,GAAa,SAAA;AACnD,UAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAA,EAAQ,SAAS,CAAA;AAC5C,UAAA,IAAI,IAAA,EAAM;AACR,YAAA,aAAA,CAAc,cAAA,EAAe;AAC7B,YAAA,MAAM,OAAA,GAAmC;AAAA,cACvC,EAAA;AAAA,cACA,KAAA,EAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,IAAc,EAAA;AAAA,cAClC,MAAA;AAAA,cACA;AAAA,aACF;AACA,YAAA,IAAI,MAAA,CAAO,EAAE,CAAA,EAAG;AACd,cAAA,MAAMA,OAAAA,GAAS,iBAAiB,MAAM,CAAA;AACtC,cAAA,IAAIA,OAAAA,KAAW,QAAW,eAAA,CAAgB,MAAA,EAAQ,EAAE,EAAA,EAAI,MAAA,EAAAA,SAAQ,CAAA;AAChE,cAAA,MAAA,CAAO,EAAE,CAAA,CAAE,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,YACjC;AACA,YAAA,aAAA,GAAgB,OAAO,CAAA;AACvB,YAAA;AAAA,UACF;AAAA,QACF;AACA,QAAA,IACE,gBAAA,IACA,kBAAA,IACA,aAAA,CAAc,GAAA,KAAQ,YAAA,EACtB;AACA,UAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAA,EAAQ,SAAS,CAAA;AAC5C,UAAA,IAAI,IAAA,EAAM;AACR,YAAA,aAAA,CAAc,cAAA,EAAe;AAC7B,YAAA,oBAAA,CAAqB,QAAQ,IAAI,CAAA;AACjC,YAAA;AAAA,UACF;AAAA,QACF;AACA,QAAA,IACE,gBAAA,IACA,aAAA,CAAc,GAAA,KAAQ,QAAA,IACtB,KAAA,EAAO,QAAQ,WAAA,KAAgB,MAAA,IAC/B,aAAA,CAAc,MAAM,CAAA,EACpB;AACA,UAAA,aAAA,CAAc,cAAA,EAAe;AAC7B,UAAA,UAAA,CAAW,EAAE,CAAA;AAAA,QACf;AAAA,MACF;AAAA;AACF,GACF;AAEA,EAAA,IAAI,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAClC,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,QAAA;AAAA,QACE,IAAA;AAAA,QACA,SAAA;AAAA,QACA,gCAAA;AAAA,QACA,CAAC,OAAO,OAAA,KAAY;AAClB,UAAA,MAAME,SAAAA,GAAW,KAAA;AACjB,UAAA,MAAM,MAAA,GAAS,OAAA;AACf,UAAA,MAAM,OAAA,GAAU;AAAA,YACd,GAAG,OAAO,aAAA,CAAe,gBAAA;AAAA,cACvB;AAAA;AACF,WACF;AACA,UAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AACpC,UAAA,IAAIA,SAAAA,CAAS,QAAQ,QAAA,EAAU;AAC7B,YAAAA,UAAS,cAAA,EAAe;AACxB,YAAA,MAAA,CACG,QAAqB,uCAAuC,CAAA,EAC3D,aAAA,CAA2B,4BAA4B,GACvD,KAAA,EAAM;AAAA,UACZ,WACEA,SAAAA,CAAS,GAAA,KAAQ,WAAA,IACjBA,SAAAA,CAAS,QAAQ,SAAA,EACjB;AACA,YAAAA,UAAS,cAAA,EAAe;AACxB,YAAA,OAAA,CAAA,CACG,KAAA,IACEA,SAAAA,CAAS,GAAA,KAAQ,WAAA,GAAc,CAAA,GAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,CAAA,IACrD,OAAA,CAAQ,MACZ,CAAA,EAAG,KAAA,EAAM;AAAA,UACX;AAAA,QACF;AAAA,OACF;AAAA,MACA,QAAA;AAAA,QACE,IAAA;AAAA,QACA,OAAA;AAAA,QACA,gCAAA;AAAA,QACA,CAAC,QAAQ,OAAA,KAAY;AACnB,UAAA,MAAM,QAAQ,OAAA,CAAQ,OAAA;AAAA,YACpB;AAAA,WACF;AACA,UAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,UAAA,MAAM,KAAA,GAAS,QAAwB,OAAA,CAAQ,qBAAA;AAC/C,UAAA,IAAI,CAAC,EAAA,IAAM,CAAC,SAAS,KAAA,EAAO,OAAA,CAAQ,aAAa,MAAA,EAAQ;AACzD,UAAA,MAAA,CAAO,EAAE,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA;AACxB,UAAA,gBAAA,CAAiB,EAAA,EAAI,8BAA8B,IAAI,CAAA;AAAA,QACzD;AAAA,OACF;AAAA,MACA,QAAA;AAAA,QACE,IAAA;AAAA,QACA,OAAA;AAAA,QACA,+BAAA;AAAA,QACA,CAAC,QAAQ,OAAA,KAAY;AACnB,UAAA,MAAM,QAAQ,OAAA,CAAQ,OAAA;AAAA,YACpB;AAAA,WACF;AACA,UAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,UAAA,MAAM,KAAA,GAAS,QAAwB,OAAA,CAAQ,UAAA;AAC/C,UAAA,IACE,CAAC,EAAA,IACD,CAAC,KAAA,IACD,KAAA,EAAO,QAAQ,QAAA,KAAa,MAAA,IAC5B,CAAC,MAAA,CAAO,EAAE,CAAA;AAEV,YAAA;AACF,UAAA,MAAA,CAAO,EAAE,CAAA,CAAE,WAAA,CAAY,KAAK,CAAA;AAC5B,UAAA,gBAAA,CAAiB,EAAA,EAAI,8BAA8B,IAAI,CAAA;AAAA,QACzD;AAAA,OACF;AAAA,MACA,QAAA;AAAA,QACE,IAAA;AAAA,QACA,OAAA;AAAA,QACA,iCAAA;AAAA,QACA,CAAC,QAAQ,OAAA,KAAY;AACnB,UAAA,MAAM,QAAQ,OAAA,CAAQ,OAAA;AAAA,YACpB;AAAA,WACF;AACA,UAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,UAAA,MAAM,KAAA,GAAS,QAAwB,OAAA,CAAQ,UAAA;AAC/C,UAAA,IAAI,EAAA,IAAM,KAAA,IAAS,KAAA,EAAO,OAAA,CAAQ,QAAA,KAAa,MAAA;AAC7C,YAAA,MAAA,CAAO,EAAE,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA;AAAA,QAC5B;AAAA,OACF;AAAA,MACA,SAAS,IAAA,EAAM,OAAA,EAAS,0BAAA,EAA4B,CAAC,QAAQ,OAAA,KAAY;AACvE,QAAA,MAAM,QAAQ,OAAA,CAAQ,OAAA;AAAA,UACpB;AAAA,SACF;AACA,QAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,QAAA,IAAI,EAAA,IAAM,OAAO,OAAA,CAAQ,QAAA,KAAa,QAAQ,MAAA,CAAO,EAAE,GAAG,KAAA,EAAM;AAAA,MAClE,CAAC;AAAA,KACH;AAAA,EACF;AAEA,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,QAAA;AAAA,QACE,IAAA;AAAA,QACA,OAAA;AAAA,QACA,2BAAA;AAAA,QACA,CAAC,QAAQ,OAAA,KAAY;AAEnB,UAAA,MAAM,QAAS,OAAA,CAAwB,OAAA;AAAA,YACrC;AAAA,WACF;AACA,UAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,UAAA,IAAI,MAAM,KAAA,EAAO,OAAA,CAAQ,QAAA,KAAa,MAAA,YAAkB,EAAE,CAAA;AAAA,QAC5D;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,MAAM;AACJ,QAAA,KAAA,MAAW,IAAA,IAAQ,QAAA,CAAS,MAAA,EAAO,EAAG,IAAA,EAAK;AAAA,MAC7C,CAAA;AAAA,MACA,eAAA;AAAA,QACE,IAAA;AAAA,QACA,OAAA;AAAA,QACA,0BAAA;AAAA,QACA,CAAC,QAAQ,OAAA,KAAY;AACnB,UAAA,MAAM,QAAQ,OAAA,CAAQ,OAAA;AAAA,YACpB;AAAA,WACF;AACA,UAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,UAAA,IACE,CAAC,EAAA,IACA,KAAA,CAAM,OAAA,CAAQ,WAAA,KAAgB,MAAA,IAAU,CAAC,MAAA,CAAO,EAAE,CAAA,IACnD,KAAA,CAAM,OAAA,CAAQ,QAAA,KAAa,MAAA;AAE3B,YAAA;AACF,UAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,IAAA,EAAM,EAAE,CAAA;AACzC,UAAA,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA,IAAI;AACnB,UAAA,MAAM,OAAO,MAAM;AACjB,YAAA,QAAA,CAAS,UAAA,EAAW;AACpB,YAAA,IAAA,EAAK,CAAE,aAAa,OAAO,CAAA;AAC3B,YAAA,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,UACpB,CAAA;AACA,UAAA,MAAM,SAAA,GAAY,CAAC,WAAA,KAA6B;AAC9C,YAAA,MAAM,MAAA,GAAS,KAAK,aAAA,CAAc,aAAA;AAClC,YAAA,OACE,MAAA,KAAW,UACX,MAAA,KAAW,OAAA,IACX,WAAW,WAAA,IACX,MAAA,KAAW,KAAK,aAAA,CAAc,IAAA;AAAA,UAElC,CAAA;AACA,UAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM;AAC1C,YAAA,MAAM,WAAA,GAAc,iBAAA,CAAkB,IAAA,EAAM,EAAE,CAAA;AAC9C,YAAA,IAAI,CAAC,WAAA,IAAe,WAAA,KAAgB,MAAA,EAAQ;AAC5C,YAAA,IAAA,EAAK;AACL,YAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG,qBAAA,CAAsB,WAAW,CAAA;AAAA,UAC/D,CAAC,CAAA;AAID,UAAA,QAAA,CAAS,QAAQ,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AACzD,UAAA,MAAM,OAAA,GAAU,IAAA,EAAK,CAAE,UAAA,CAAW,MAAM,CAAC,CAAA;AACzC,UAAA,QAAA,CAAS,GAAA,CAAI,IAAI,IAAI,CAAA;AACrB,UAAA,IAAI,MAAM,OAAA,CAAQ,WAAA,KAAgB,MAAA,EAAQ,WAAA,CAAY,IAAI,IAAI,CAAA;AAC9D,UAAA,MAAM,OAAA,GAAU,iBAAA,CAAkB,IAAA,EAAM,EAAE,CAAA;AAI1C,UAAA,IAAI,OAAA,IAAW,SAAA,CAAU,OAAO,CAAA,wBAAyB,OAAO,CAAA;AAAA,QAClE;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,IAAI,mBAAA,EAAqB;AACvB,IAAA,IAAA,CAAK,aAAA,CAAc,gBAAA;AAAA,MACjB,aAAA;AAAA,MACA,sBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,aAAA,CAAc,gBAAA;AAAA,MACjB,WAAA;AAAA,MACA,kCAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,aAAA,CAAc,gBAAA;AAAA,MACjB,eAAA;AAAA,MACA,uBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,aAAA,CAAc,gBAAA;AAAA,MACjB,OAAA;AAAA,MACA,gCAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,MACE,KAAK,aAAA,CAAc,mBAAA;AAAA,QACjB,aAAA;AAAA,QACA,sBAAA;AAAA,QACA;AAAA,OACF;AAAA,MACF,MACE,KAAK,aAAA,CAAc,mBAAA;AAAA,QACjB,WAAA;AAAA,QACA,kCAAA;AAAA,QACA;AAAA,OACF;AAAA,MACF,MACE,KAAK,aAAA,CAAc,mBAAA;AAAA,QACjB,eAAA;AAAA,QACA,uBAAA;AAAA,QACA;AAAA,OACF;AAAA,MACF,MACE,KAAK,aAAA,CAAc,mBAAA;AAAA,QACjB,OAAA;AAAA,QACA,gCAAA;AAAA,QACA;AAAA;AACF,KACJ;AAIA,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,QAAA;AAAA,QACE,IAAA;AAAA,QACA,WAAA;AAAA,QACA,uEAAA;AAAA,QACA,CAAC,KAAA,KAAU;AACT,UAAA,KAAA,CAAM,cAAA,EAAe;AAAA,QACvB;AAAA;AACF,KACF;AACA,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,QAAA;AAAA,QACE,IAAA;AAAA,QACA,UAAA;AAAA,QACA,4BAAA;AAAA,QACA,CAAC,OAAO,OAAA,KAAY;AAClB,UAAA,MAAM,MAAA,GAAS,OAAA;AACf,UAAA,MAAM,QAAQ,MAAA,CAAO,OAAA;AAAA,YACnB;AAAA,WACF;AACA,UAAA,MAAM,EAAA,GAAK,OAAO,OAAA,CAAQ,aAAA;AAC1B,UAAA,IACE,CAAC,MACD,KAAA,EAAO,OAAA,CAAQ,gBAAgB,MAAA,IAC/B,KAAA,CAAM,QAAQ,QAAA,KAAa,MAAA;AAE3B,YAAA;AACF,UAAA,MAAM,gBAAiB,KAAA,CAAqB,aAAA;AAC5C,UAAA,MAAM,IAAA,GACJ,aAAA,YAAyB,OAAA,GACrB,aAAA,GACA,uBAAA;AACN,UAAA,IAAI,CAAC,SAAS,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA,IAAM,WAAA,IAAe,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA,CAAA;AAC/D,YAAA;AACF,UAAA,IAAI,IAAA,YAAgB,IAAA,IAAQ,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA,EAAG;AAClD,UAAA,IAAI,cAAA,CAAe,IAAA,YAAgB,OAAA,GAAU,IAAA,GAAO,IAAI,CAAA,EAAG;AAC3D,UAAA,IAAI,CAAC,aAAA,CAAc,MAAM,CAAA,EAAG;AAC5B,UAAA,MAAM,iCAAiC,MAAM;AAC3C,YAAA,IAAI,QAAA,IAAY,CAAC,aAAA,CAAc,MAAM,CAAA,EAAG;AACxC,YAAA,MAAM,MAAA,GAAS,MAAM,aAAA,CAAc,aAAA;AACnC,YAAA,IAAI,CAAC,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA,IAAK,CAAC,eAAe,MAAM,CAAA;AACnD,cAAA,WAAA,CAAY,IAAI,KAAK,CAAA;AAAA,UACzB,CAAA;AACA,UAAA,IAAI,uBAAA;AACF,YAAA,2BAAA,CAA4B,GAAA,CAAI,IAAI,8BAA8B,CAAA;AAAA,eAC/D,IAAA,EAAK,CAAE,cAAA,CAAe,8BAA8B,CAAA;AAAA,QAC3D;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,MAAM,UAAU,MAAM;AACpB,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,IAAI,mBAAA,KAAwB,MAAA;AAC1B,MAAA,IAAA,EAAK,CAAE,aAAa,mBAAmB,CAAA;AACzC,IAAA,2BAAA,CAA4B,KAAA,EAAM;AAClC,IAAA,mBAAA,CAAoB,UAAA,EAAW;AAC/B,IAAA,KAAA,MAAW,IAAA,IAAQ,qBAAA,CAAsB,MAAA,EAAO,EAAG,IAAA,EAAK;AACxD,IAAA,qBAAA,CAAsB,KAAA,EAAM;AAC5B,IAAA,KAAA,MAAW,IAAA,IAAQ,QAAA,CAAS,MAAA,EAAO,EAAG,IAAA,EAAK;AAC3C,IAAA,KAAA,MAAW,IAAA,IAAQ,SAAA,CAAU,MAAA,CAAO,CAAC,GAAG,IAAA,EAAK;AAAA,EAC/C,CAAA;AACA,EAAA,MAAM,MAAA,IAAU,MAAM,OAAA,EAAQ,CAAA;AAC9B,EAAA,MAAA,CAAO,OAAA,GAAU,OAAA;AACjB,EAAA,MAAA,CAAO,WAAW,CAAC,EAAA,KAAQ,OAAA,GAAU,SAAA,CAAU,EAAE,CAAA,GAAI,MAAA;AACrD,EAAA,MAAA,CAAO,IAAA,GAAO,CAAC,EAAA,KAAO;AACpB,IAAA,IAAI,OAAA,IAAW,CAAC,QAAA,EAAU,SAAA,CAAU,EAAE,CAAA;AAAA,EACxC,CAAA;AACA,EAAA,MAAA,CAAO,KAAA,GAAQ,CAAC,EAAA,KAAO;AACrB,IAAA,IAAI,OAAA,IAAW,CAAC,QAAA,EAAU,UAAA,CAAW,EAAE,CAAA;AAAA,EACzC,CAAA;AACA,EAAA,OAAO,MAAA;AACT","file":"chunk-M5H2RMCH.js","sourcesContent":["import {\n autoUpdate,\n computePosition,\n flip,\n offset,\n shift,\n size,\n} from '@floating-ui/dom';\nimport { delegate, delegateCapture, type Signal, signal } from 'kerfjs';\n\nimport {\n placeTokenSearchCaret,\n readTokenSearchField,\n} from './token-search-field.js';\nimport type { TokenSearchModel } from './token-search-model.js';\n\nexport interface TokenSearchSubmit {\n id: string;\n editor: HTMLElement;\n}\n\n/** Reported to {@link WireTokenSearchFieldsOptions.onEdit} on every editor input. */\nexport interface TokenSearchEdit extends TokenSearchSubmit {\n /**\n * The `InputEvent` that mutated the editor — read `event.inputType` / `event.data`\n * to gate commit behavior (e.g. only parse a chip on whitespace-terminated input)\n * without keeping a separate `input` listener.\n */\n event: InputEvent;\n}\n\n/** Reported when adjacent-token keyboard deletion asks the app to drop a chip. */\nexport interface TokenSearchTokenRemoval {\n id: string;\n /** The `data-token-value` of the token the app should remove from its state. */\n value: string;\n editor: HTMLElement;\n /** `'backward'` = the token before the caret (Backspace); `'forward'` = after (Delete). */\n direction: 'backward' | 'forward';\n}\n\n/**\n * Opt-in keyboard behavior for the atomic token chips. Off unless `keyboard` is\n * set; each piece defaults on once opted in. The helper never mutates app state:\n * a removal is reported through {@link TokenSearchKeyboardOptions.onRemoveToken}\n * for the caller to apply, while caret movement past a chip is a pure ephemeral\n * mechanic the helper performs itself.\n */\ninterface TokenSearchKeyboardBaseOptions {\n /**\n * From a collapsed caret with no selection, Backspace removes the token\n * immediately before it and Delete the token immediately after — reported via\n * `onRemoveToken` — instead of deleting a character. Default: true.\n */\n /**\n * ArrowRight moves the caret past a trailing atomic token so text typed next\n * lands after the chip. Default: true.\n */\n moveCaretPastToken?: boolean;\n /** Apply the reported removal to your controlled state, then re-render. */\n}\n\nexport type TokenSearchKeyboardOptions = TokenSearchKeyboardBaseOptions &\n (\n | {\n removeAdjacentToken?: true;\n /** Apply the reported removal to your controlled state, then re-render. */\n onRemoveToken: (removal: TokenSearchTokenRemoval) => void;\n }\n | { removeAdjacentToken: false; onRemoveToken?: never }\n );\n\n/**\n * Managed collapsible behavior for the iconic TokenSearchField. Every piece is on\n * by default; disable a specific one to own it in the app. Provide `signals` to\n * drive app-owned `expanded` signals per field id instead of helper-created ones.\n */\nexport interface TokenSearchCollapsibleOptions {\n /** Expand the field and focus its editor when the iconic trigger is activated. Default: true. */\n expandOnActivate?: boolean;\n /** Collapse the field when focus leaves it while it is empty. Default: true. */\n collapseOnEmptyBlur?: boolean;\n /** Collapse an empty field on Escape and restore focus to its trigger. Default: true. */\n collapseOnEscape?: boolean;\n /** Focus the editor on expand/controlled clear 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 /** Optional automatic grammar/suggestion models, keyed by TokenSearchField id. */\n models?: Readonly<Record<string, TokenSearchModel>>;\n onSubmit?: (submission: TokenSearchSubmit) => void;\n /** Fired on every editor `input`, after the browser mutates it, so a caller can drop its own `input` listener. */\n onEdit?: (edit: TokenSearchEdit) => void;\n /** Managed collapsible transient behavior. `true`/omitted = on with defaults; `false` = fully off. */\n collapsible?: boolean | TokenSearchCollapsibleOptions;\n /** Opt-in atomic-chip keyboard behavior (off by default). */\n keyboard?: false | TokenSearchKeyboardOptions;\n}\n\n/**\n * The value returned from {@link wireTokenSearchFields}: call it (or `dispose()`) to\n * tear down. When collapsible behavior is managed, it also exposes the transient\n * `expanded` state per field id so the app can read it in render, hand in its own\n * signal, or drive it imperatively.\n */\nexport interface TokenSearchFieldsHandle {\n (): void;\n dispose(): void;\n /** The managed `expanded` signal for a field id (adopted or helper-created); undefined when unmanaged. */\n expanded(id: string): Signal<boolean> | undefined;\n /** Expand the field (and, when focus is managed, focus its editor). */\n open(id: string): void;\n /** Collapse the field (and, when focus is managed, restore focus to its trigger). */\n close(id: string): void;\n}\n\ninterface PendingTokenDeletion {\n id: string;\n offset: number;\n tokenCount: number;\n selectedAll: boolean;\n}\n\nfunction editorFromEvent(\n root: HTMLElement,\n event: Event,\n): HTMLElement | undefined {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const editor = target.closest<HTMLElement>('[data-token-search-editor]');\n return editor && root.contains(editor) ? editor : undefined;\n}\n\nfunction caretQueryOffset(editor: HTMLElement): number | undefined {\n const selection = editor.ownerDocument.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const selectionRange = selection.getRangeAt(0);\n if (!editor.contains(selectionRange.startContainer)) return;\n const prefixRange = editor.ownerDocument.createRange();\n prefixRange.selectNodeContents(editor);\n prefixRange.setEnd(selectionRange.startContainer, selectionRange.startOffset);\n const prefix = editor.ownerDocument.createElement('div');\n prefix.append(prefixRange.cloneContents());\n return readTokenSearchField(prefix).query.length;\n}\n\nfunction replacementEditor(\n root: HTMLElement,\n id: string,\n): HTMLElement | undefined {\n return [\n ...root.querySelectorAll<HTMLElement>('[data-token-search-editor]'),\n ].find((editor) => editor.dataset.tokenSearchEditor === id);\n}\n\nfunction editorIsEmpty(editor: HTMLElement): boolean {\n const value = readTokenSearchField(editor);\n return value.query.length === 0 && value.tokens.length === 0;\n}\n\n/** Whether the active selection covers all logical text and tokens in the editor. */\nfunction selectionCoversEditor(editor: HTMLElement): boolean {\n // onBeforeInput calls this only after caretQueryOffset verified a live range.\n const selected = editor.ownerDocument.getSelection()!.getRangeAt(0);\n if (selected.collapsed || !editor.contains(selected.commonAncestorContainer))\n return false;\n // Browser select-all ranges are not structurally identical across platforms:\n // some use editor child offsets while others start/end inside the first/last\n // text nodes. Compare the selected logical value instead of DOM boundaries.\n const selectedHost = editor.ownerDocument.createElement('div');\n selectedHost.append(selected.cloneContents());\n const fullValue = readTokenSearchField(editor);\n const selectedValue = readTokenSearchField(selectedHost);\n return (\n selectedValue.query === fullValue.query &&\n selectedValue.tokens.length === fullValue.tokens.length &&\n selectedValue.tokens.every(\n (token, index) => token.value === fullValue.tokens[index]?.value,\n )\n );\n}\n\nconst TOKEN_SELECTOR = '[data-component=\"token-search-token\"]';\nconst TEXT_SELECTOR = '[data-token-search-text]';\nconst stripZwsp = (text: string): string => text.replaceAll('', '');\n\n/**\n * A `contenteditable` host emptied by select-all + Delete (or Backspace) leaves a\n * bogus `<br>` in every engine: it renders as a stray newline and `readTokenSearchField`\n * reads it back as a space. Strip those line breaks after a delete, and when the field\n * is otherwise empty (no chips, no visible text) restore the canonical empty text span\n * and place the caret in it so typing resumes cleanly. Called only after the browser has\n * applied the delete, so an ordinary partial delete is never touched.\n */\nfunction normalizeEmptiedEditor(\n editor: HTMLElement,\n selectedAll = false,\n): void {\n const lineBreaks = editor.querySelectorAll('br');\n if (lineBreaks.length === 0 && !selectedAll) return;\n for (const lineBreak of lineBreaks) lineBreak.remove();\n if (!selectedAll && editor.querySelector(TOKEN_SELECTOR)) return;\n if (!selectedAll && stripZwsp(editor.textContent ?? '') !== '') return;\n const doc = editor.ownerDocument;\n const span = doc.createElement('span');\n span.setAttribute('data-token-search-text', '');\n span.setAttribute('data-empty', 'true');\n editor.replaceChildren(span);\n if (doc.activeElement !== editor) return;\n // The editor is the focused, connected editing host, so a selection exists.\n const selection = doc.getSelection()!;\n const range = doc.createRange();\n range.setStart(span, 0);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n\n/** The collapsed, in-editor caret range, or undefined when there is a selection or none. */\nfunction collapsedCaret(editor: HTMLElement): Range | undefined {\n const selection = editor.ownerDocument.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (!range.collapsed || !editor.contains(range.startContainer)) return;\n return range;\n}\n\n/** The direct child of `editor` that contains `node` (or `node` itself), else null. */\nfunction topBlock(editor: HTMLElement, node: Node): Node | null {\n let current: Node = node;\n while (current.parentNode && current.parentNode !== editor)\n current = current.parentNode;\n return current.parentNode === editor ? current : null;\n}\n\n/** A text node or text span holding no visible character (only zero-width spacers). */\nfunction isBlankText(node: Node): boolean {\n if (node.nodeType === Node.TEXT_NODE)\n return stripZwsp((node as CharacterData).data) === '';\n return (\n node instanceof Element &&\n node.matches(TEXT_SELECTOR) &&\n stripZwsp(node.textContent ?? '') === ''\n );\n}\n\n/** The nearest sibling block on `direction`, skipping blank text spacers. */\nfunction meaningfulSibling(\n block: Node,\n direction: 'backward' | 'forward',\n): Node | null {\n let sibling =\n direction === 'backward' ? block.previousSibling : block.nextSibling;\n while (sibling && isBlankText(sibling))\n sibling =\n direction === 'backward' ? sibling.previousSibling : sibling.nextSibling;\n return sibling;\n}\n\n/** The node immediately on `direction` of the caret, only when no visible character separates them. */\nfunction caretSideNode(\n editor: HTMLElement,\n range: Range,\n direction: 'backward' | 'forward',\n): Node | null {\n const { startContainer: container, startOffset: offset } = range;\n if (container.nodeType === Node.TEXT_NODE) {\n const text = (container as CharacterData).data;\n const side =\n direction === 'backward' ? text.slice(0, offset) : text.slice(offset);\n if (stripZwsp(side).length > 0) return null;\n // An in-editor text node always has a top block (itself or its wrapping span).\n return meaningfulSibling(topBlock(editor, container)!, direction);\n }\n const child = container.childNodes[\n direction === 'backward' ? offset - 1 : offset\n ] as Node | undefined;\n if (child) {\n // `child` is a descendant of the in-editor caret container, so it has a top block.\n const block = topBlock(editor, child)!;\n return isBlankText(child) ? meaningfulSibling(block, direction) : block;\n }\n const block = topBlock(editor, container);\n return block ? meaningfulSibling(block, direction) : null;\n}\n\n/** The atomic token chip adjacent to a collapsed caret on `direction`, if any. */\nfunction adjacentToken(\n editor: HTMLElement,\n direction: 'backward' | 'forward',\n): HTMLElement | undefined {\n const range = collapsedCaret(editor);\n if (!range) return;\n const node = caretSideNode(editor, range, direction);\n if (!node) return;\n const base = node instanceof Element ? node : node.parentElement;\n const chip = base?.closest<HTMLElement>(TOKEN_SELECTOR) ?? null;\n return chip && editor.contains(chip) ? chip : undefined;\n}\n\n/** Move the caret to just after an atomic token chip so typed text lands after it.\n * Only reached after {@link collapsedCaret} already found a live selection, and the\n * chip is a direct block of the editor. */\nfunction placeCaretAfterToken(editor: HTMLElement, chip: HTMLElement): void {\n const selection = editor.ownerDocument.getSelection()!;\n const range = editor.ownerDocument.createRange();\n range.setStartAfter(topBlock(editor, chip)!);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n editor.focus({ preventScroll: true });\n}\n\n/**\n * Wire every TokenSearchField under `root`: submit on Enter, preserve the caret across\n * controlled token deletion, and (by default) manage the collapsible field's transient\n * expand/collapse/focus. Returns a {@link TokenSearchFieldsHandle} — a disposer that also\n * exposes the managed `expanded` state per field id.\n */\nexport function wireTokenSearchFields(\n root: HTMLElement,\n {\n models = {},\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 || Object.keys(models).length > 0;\n const keyboardConfig = typeof keyboard === 'object' ? keyboard : undefined;\n const removeAdjacentToken =\n keyboardOn && (keyboardConfig?.removeAdjacentToken ?? true);\n const moveCaretPastToken =\n keyboardOn && (keyboardConfig?.moveCaretPastToken ?? true);\n const onRemoveToken = keyboardConfig?.onRemoveToken;\n const adopted = config.signals ?? {};\n const created = new Map<string, Signal<boolean>>();\n let disposed = false;\n let pointerActivationTarget: Element | null = null;\n const pendingPointerBlurCollapses = new Map<string, () => void>();\n let pointerReleaseTimer: number | undefined;\n const positionedSuggestions = new Map<HTMLElement, () => void>();\n\n const syncSuggestions = () => {\n const current = new Set(\n root.querySelectorAll<HTMLElement>('.kui-token-search__suggestions'),\n );\n for (const [popup, stop] of positionedSuggestions) {\n if (current.has(popup)) continue;\n stop();\n positionedSuggestions.delete(popup);\n }\n for (const popup of current) {\n if (positionedSuggestions.has(popup)) continue;\n const field = popup.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n if (!field) continue;\n let active = true;\n popup.style.position = 'absolute';\n popup.style.insetBlockStart = 'auto';\n popup.style.insetInlineStart = 'auto';\n popup.style.left = '0';\n popup.style.top = '0';\n popup.style.visibility = 'hidden';\n const update = async () => {\n const width = Math.min(\n Math.max(field.getBoundingClientRect().width, 240),\n Math.max(0, field.ownerDocument.defaultView!.innerWidth - 16),\n );\n popup.style.width = `${width}px`;\n const position = await computePosition(field, popup, {\n strategy: 'absolute',\n placement: 'bottom-start',\n middleware: [\n offset(4),\n flip({ padding: 8 }),\n shift({ padding: 8 }),\n size({\n padding: 8,\n apply({ availableHeight }) {\n popup.style.maxHeight = `${Math.max(0, Math.min(240, availableHeight))}px`;\n },\n }),\n ],\n });\n if (!active || disposed || !popup.isConnected) return;\n popup.style.left = `${position.x}px`;\n popup.style.top = `${position.y}px`;\n popup.style.visibility = 'visible';\n };\n const stopAutoUpdate = autoUpdate(field, popup, () => void update(), {\n layoutShift: false,\n });\n positionedSuggestions.set(popup, () => {\n active = false;\n stopAutoUpdate();\n for (const property of [\n 'position',\n 'inset-block-start',\n 'inset-inline-start',\n 'left',\n 'top',\n 'visibility',\n 'width',\n 'max-height',\n ])\n popup.style.removeProperty(property);\n });\n }\n };\n const suggestionsObserver = new MutationObserver(syncSuggestions);\n suggestionsObserver.observe(root, { childList: true, subtree: true });\n syncSuggestions();\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 // WebKit can report `focusout.relatedTarget === null` while a pointer is\n // moving focus into a sibling button. Preserve the actual activation target\n // across that focus transition so a keep-open surface cannot be collapsed\n // (and removed) between pointerdown and click.\n const trackPointerActivation = (event: Event) => {\n if (pointerReleaseTimer !== undefined)\n view().clearTimeout(pointerReleaseTimer);\n pointerReleaseTimer = undefined;\n pointerActivationTarget =\n event.target instanceof Element ? event.target : null;\n };\n const flushPointerBlurCollapses = () => {\n pointerReleaseTimer = undefined;\n for (const collapse of pendingPointerBlurCollapses.values()) collapse();\n pendingPointerBlurCollapses.clear();\n };\n const flushAfterPointerClick = () => {\n if (pendingPointerBlurCollapses.size === 0) return;\n if (pointerReleaseTimer !== undefined)\n view().clearTimeout(pointerReleaseTimer);\n // A pointerup can have no click (drag/cancel); a click can run app handlers\n // after capture. A task after either event preserves the pressed target.\n pointerReleaseTimer = view().setTimeout(flushPointerBlurCollapses, 0);\n };\n const clearPointerActivation = () => {\n pointerActivationTarget = null;\n };\n const clearPointerActivationAfterDefault = () => {\n view().queueMicrotask(clearPointerActivation);\n flushAfterPointerClick();\n };\n const clearPointerActivationAfterClick = () => {\n clearPointerActivation();\n flushAfterPointerClick();\n };\n const cancelPointerActivation = () => {\n clearPointerActivation();\n flushAfterPointerClick();\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 focusing = new Map<string, () => void>();\n const focusAfterRender = (\n id: string,\n selector: string,\n guardMovedFocus = false,\n ) => {\n focusing.get(id)?.();\n let frame: number | undefined;\n const stop = () => {\n observer.disconnect();\n if (frame !== undefined) view().cancelAnimationFrame(frame);\n if (focusing.get(id) === stop) focusing.delete(id);\n };\n const restore = () => {\n if (disposed) return stop();\n const field = root.querySelector<HTMLElement>(\n `[data-component=\"token-search-field\"][data-token-search-id=\"${CSS.escape(id)}\"]`,\n );\n const target = field?.querySelector<HTMLElement>(selector);\n if (!field || !target) return;\n const active = field.ownerDocument.activeElement;\n // A later focus move to another control wins. The original editor may\n // have been replaced, leaving body active; controls of this field are\n // still part of the same interaction.\n if (\n guardMovedFocus &&\n active !== field.ownerDocument.body &&\n active !== target &&\n !field.contains(active)\n )\n return stop();\n stop();\n if (target.matches('[data-token-search-editor]'))\n placeTokenSearchCaret(target);\n else target.focus();\n };\n const observer = new MutationObserver(restore);\n observer.observe(root, { childList: true, subtree: true });\n focusing.set(id, stop);\n view().queueMicrotask(restore);\n // A collapsed field may reveal its editor in the next render frame.\n // The microtask/mutation path runs first; this bounded fallback keeps\n // opening reliable without reclaiming focus a user moved elsewhere.\n frame = view().requestAnimationFrame(() => {\n frame = undefined;\n restore();\n stop();\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 clearing = new Map<string, () => void>();\n const pending = new Map<string, PendingTokenDeletion>();\n const deleting = new Map<string, () => void>();\n const selectAllIntents = new WeakSet<HTMLElement>();\n // editorFromEvent's selector guarantees this data attribute is present.\n const intentId = (editor: HTMLElement): string =>\n editor.dataset.tokenSearchEditor!;\n const captureDeletion = (editor: HTMLElement, selectedAll?: boolean) => {\n if (editor.ownerDocument.activeElement !== editor) return;\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n const offset = selectedAll ? 0 : caretQueryOffset(editor);\n if (!id || offset === undefined || field?.dataset.disabled === 'true')\n return;\n pending.set(id, {\n id,\n offset,\n tokenCount: editor.querySelectorAll(\n '[data-component=\"token-search-token\"]',\n ).length,\n selectedAll: selectedAll ?? selectionCoversEditor(editor),\n });\n };\n const onBeforeInput = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (editor && (event as InputEvent).inputType.startsWith('delete'))\n captureDeletion(editor);\n };\n const restoreDeletion = (\n editor: HTMLElement,\n deletion: Pick<PendingTokenDeletion, 'id' | 'offset'>,\n ) => {\n deleting.get(deletion.id)?.();\n const stop = () => {\n observer.disconnect();\n view().clearTimeout(timeout);\n deleting.delete(deletion.id);\n };\n const restore = () => {\n const replacement = replacementEditor(root, deletion.id);\n // A native input can drain microtasks between capture and bubble listeners.\n // Wait for the actual replacement, including one rendered by a later listener.\n if (!replacement || replacement === editor) return;\n stop();\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 const observer = new MutationObserver(restore);\n observer.observe(root, { childList: true, subtree: true });\n // The input task owns synchronous controlled rendering. Expiration only\n // disconnects observation; it cannot move a later selection or steal focus.\n const timeout = view().setTimeout(stop, 0);\n deleting.set(deletion.id, stop);\n };\n const onInput = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (!editor) return;\n const editorId = intentId(editor);\n const inputType = (event as InputEvent).inputType;\n if (!inputType.startsWith('delete')) selectAllIntents.delete(editor);\n const deletion = pending.get(editorId);\n if (inputType.startsWith('delete'))\n normalizeEmptiedEditor(editor, deletion?.selectedAll);\n const restore =\n deletion &&\n (deletion.selectedAll ||\n editor.querySelectorAll(TOKEN_SELECTOR).length < deletion.tokenCount);\n // Own the replacement before application listeners synchronously render.\n // A populated field can be visually open while its adopted signal is false.\n if (restore) {\n restoreDeletion(editor, deletion);\n if (\n manageFocus &&\n editor.closest<HTMLElement>('[data-component=\"token-search-field\"]')\n ?.dataset.collapsible === 'true'\n )\n setExpanded(editorId, true);\n }\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 const model = models[id];\n if (model) {\n const before = editor.querySelectorAll(TOKEN_SELECTOR).length;\n const current = readTokenSearchField(editor, model.state.value.tokens);\n const input = event as InputEvent;\n const commit =\n (typeof input.data === 'string' && /\\s$/.test(input.data)) ||\n (input.inputType === 'insertFromPaste' && /\\s$/.test(current.query));\n model.edit(current, commit);\n if (model.state.value.tokens.length > before)\n focusAfterRender(id, '[data-token-search-editor]', true);\n }\n if (onEdit) onEdit({ id, editor, event: event as InputEvent });\n }\n pending.delete(editorId);\n };\n root.addEventListener('beforeinput', onBeforeInput, true);\n root.addEventListener('input', onInput, true);\n\n const clearSelectAllIntent = (event: Event) => {\n const editor = editorFromEvent(root, event);\n if (editor) selectAllIntents.delete(editor);\n };\n const trackSelectAllIntent = (event: Event) => {\n const keyboardEvent = event as KeyboardEvent;\n const editor = editorFromEvent(root, event);\n if (!editor || keyboardEvent.isComposing) return;\n const fullDeletionInputType =\n keyboardEvent.key === 'Backspace'\n ? 'deleteContentBackward'\n : keyboardEvent.key === 'Delete'\n ? 'deleteContentForward'\n : undefined;\n if (\n keyboardEvent.key.toLowerCase() === 'a' &&\n (keyboardEvent.ctrlKey || keyboardEvent.metaKey) &&\n !keyboardEvent.altKey &&\n !keyboardEvent.shiftKey\n ) {\n // Capture this before target/bubble handlers can stop propagation.\n selectAllIntents.add(editor);\n return;\n }\n if (fullDeletionInputType && selectAllIntents.delete(editor)) {\n if (editor.parentElement?.dataset.disabled === 'true') return;\n // Native mixed-contenteditable deletion is not reliable: Linux engines\n // can leave contenteditable=false chips behind, and a controlled render\n // then restores them from application state. The preceding shortcut is\n // an unambiguous full-delete request, so own that transition and publish\n // the same bubbling input contract the native edit would have produced.\n keyboardEvent.preventDefault();\n captureDeletion(editor, true);\n normalizeEmptiedEditor(editor, true);\n editor.dispatchEvent(\n new InputEvent('input', {\n bubbles: true,\n inputType: fullDeletionInputType,\n }),\n );\n return;\n }\n // Any intervening keyboard action consumes the shortcut intent. Printable\n // replacement typing clears it here before the browser's input event; the\n // input listener also covers paste, drop, and other non-keyboard edits.\n if (!fullDeletionInputType) selectAllIntents.delete(editor);\n };\n root.addEventListener('keydown', trackSelectAllIntent, true);\n root.addEventListener('pointerdown', clearSelectAllIntent, true);\n root.addEventListener('focusout', clearSelectAllIntent, true);\n\n const disposers: Array<() => void> = [\n () => {\n pending.clear();\n for (const stop of deleting.values()) stop();\n },\n () => root.removeEventListener('beforeinput', onBeforeInput, true),\n () => root.removeEventListener('input', onInput, true),\n () => root.removeEventListener('keydown', trackSelectAllIntent, true),\n () => root.removeEventListener('pointerdown', clearSelectAllIntent, true),\n () => root.removeEventListener('focusout', clearSelectAllIntent, true),\n ];\n\n disposers.push(\n delegate(\n root,\n 'keydown',\n '[data-token-search-editor]',\n (event, element) => {\n const keyboardEvent = event as KeyboardEvent;\n const editor = element as HTMLElement;\n if (keyboardEvent.isComposing) return;\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (!id || field?.dataset.disabled === 'true') return;\n const keyboardForField = keyboard !== false || Boolean(models[id]);\n if (keyboardEvent.key === 'Enter') {\n keyboardEvent.preventDefault();\n const model = models[id];\n if (model)\n model.submit(\n readTokenSearchField(editor, model.state.value.tokens),\n );\n onSubmit?.({ id, editor });\n return;\n }\n if (models[id] && keyboardEvent.key === 'ArrowDown') {\n const first = field.querySelector<HTMLButtonElement>(\n '[data-token-search-suggestion]',\n );\n if (first) {\n keyboardEvent.preventDefault();\n first.focus();\n return;\n }\n }\n if (models[id] && keyboardEvent.key === 'Escape') models[id].dismiss();\n if (\n keyboardForField &&\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 const removal: TokenSearchTokenRemoval = {\n id,\n value: chip.dataset.tokenValue ?? '',\n editor,\n direction,\n };\n if (models[id]) {\n const offset = caretQueryOffset(editor);\n if (offset !== undefined) restoreDeletion(editor, { id, offset });\n models[id].remove(removal.value);\n }\n onRemoveToken?.(removal);\n return;\n }\n }\n if (\n keyboardForField &&\n moveCaretPastToken &&\n keyboardEvent.key === 'ArrowRight'\n ) {\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 (Object.keys(models).length > 0) {\n disposers.push(\n delegate(\n root,\n 'keydown',\n '[data-token-search-suggestion]',\n (event, element) => {\n const keyboard = event as KeyboardEvent;\n const button = element as HTMLButtonElement;\n const buttons = [\n ...button.parentElement!.querySelectorAll<HTMLButtonElement>(\n '[data-token-search-suggestion]',\n ),\n ];\n const index = buttons.indexOf(button);\n if (keyboard.key === 'Escape') {\n keyboard.preventDefault();\n button\n .closest<HTMLElement>('[data-component=\"token-search-field\"]')\n ?.querySelector<HTMLElement>('[data-token-search-editor]')\n ?.focus();\n } else if (\n keyboard.key === 'ArrowDown' ||\n keyboard.key === 'ArrowUp'\n ) {\n keyboard.preventDefault();\n buttons[\n (index +\n (keyboard.key === 'ArrowDown' ? 1 : buttons.length - 1)) %\n buttons.length\n ]?.focus();\n }\n },\n ),\n delegate(\n root,\n 'click',\n '[data-token-search-suggestion]',\n (_event, element) => {\n const field = element.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n const value = (element as HTMLElement).dataset.tokenSearchSuggestion;\n if (!id || !value || field?.dataset.disabled === 'true') return;\n models[id]?.choose(value);\n focusAfterRender(id, '[data-token-search-editor]', true);\n },\n ),\n delegate(\n root,\n 'click',\n '.kui-token-search__token-edit',\n (_event, element) => {\n const field = element.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n const value = (element as HTMLElement).dataset.tokenValue;\n if (\n !id ||\n !value ||\n field?.dataset.disabled === 'true' ||\n !models[id]\n )\n return;\n models[id].expandToken(value);\n focusAfterRender(id, '[data-token-search-editor]', true);\n },\n ),\n delegate(\n root,\n 'click',\n '.kui-token-search__token-remove',\n (_event, element) => {\n const field = element.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n const value = (element as HTMLElement).dataset.tokenValue;\n if (id && value && field?.dataset.disabled !== 'true')\n models[id]?.remove(value);\n },\n ),\n delegate(root, 'click', '.kui-token-search__clear', (_event, element) => {\n const field = element.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (id && field?.dataset.disabled !== 'true') models[id]?.clear();\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 (manageFocus) {\n disposers.push(\n () => {\n for (const stop of clearing.values()) stop();\n },\n delegateCapture(\n root,\n 'click',\n '.kui-token-search__clear',\n (_event, element) => {\n const field = element.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n );\n const id = field?.dataset.tokenSearchId;\n if (\n !id ||\n (field.dataset.collapsible !== 'true' && !models[id]) ||\n field.dataset.disabled === 'true'\n )\n return;\n const editor = replacementEditor(root, id);\n clearing.get(id)?.();\n const stop = () => {\n observer.disconnect();\n view().clearTimeout(timeout);\n clearing.delete(id);\n };\n const ownsFocus = (replacement: HTMLElement) => {\n const active = root.ownerDocument.activeElement;\n return (\n active === editor ||\n active === element ||\n active === replacement ||\n active === root.ownerDocument.body\n );\n };\n const observer = new MutationObserver(() => {\n const replacement = replacementEditor(root, id);\n if (!replacement || replacement === editor) return;\n stop();\n if (ownsFocus(replacement)) placeTokenSearchCaret(replacement);\n });\n // Native clicks can drain microtasks between capture and bubble listeners.\n // Observe the actual controlled replacement before the app clears; a frame\n // is too late because the next shortcut-letter input may reach the page.\n observer.observe(root, { childList: true, subtree: true });\n const timeout = view().setTimeout(stop, 0);\n clearing.set(id, stop);\n if (field.dataset.collapsible === 'true') setExpanded(id, true);\n const current = replacementEditor(root, id);\n // Keyboard activation may start on the clear button. Own the current\n // editor now, and its replacement at the mutation checkpoint. Expiration\n // only disconnects observation; it never moves a later caret or focus.\n if (current && ownsFocus(current)) placeTokenSearchCaret(current);\n },\n ),\n );\n }\n\n if (collapseOnEmptyBlur) {\n root.ownerDocument.addEventListener(\n 'pointerdown',\n trackPointerActivation,\n true,\n );\n root.ownerDocument.addEventListener(\n 'pointerup',\n clearPointerActivationAfterDefault,\n true,\n );\n root.ownerDocument.addEventListener(\n 'pointercancel',\n cancelPointerActivation,\n true,\n );\n root.ownerDocument.addEventListener(\n 'click',\n clearPointerActivationAfterClick,\n true,\n );\n disposers.push(\n () =>\n root.ownerDocument.removeEventListener(\n 'pointerdown',\n trackPointerActivation,\n true,\n ),\n () =>\n root.ownerDocument.removeEventListener(\n 'pointerup',\n clearPointerActivationAfterDefault,\n true,\n ),\n () =>\n root.ownerDocument.removeEventListener(\n 'pointercancel',\n cancelPointerActivation,\n true,\n ),\n () =>\n root.ownerDocument.removeEventListener(\n 'click',\n clearPointerActivationAfterClick,\n true,\n ),\n );\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 relatedTarget = (event as FocusEvent).relatedTarget;\n const next =\n relatedTarget instanceof Element\n ? relatedTarget\n : pointerActivationTarget;\n if (!next && (clearing.has(id) || (manageFocus && deleting.has(id))))\n return;\n if (next instanceof Node && field.contains(next)) return;\n if (isExemptTarget(next instanceof Element ? next : null)) return;\n if (!editorIsEmpty(editor)) return;\n const collapseIfStillEmptyAndBlurred = () => {\n if (disposed || !editorIsEmpty(editor)) return;\n const active = field.ownerDocument.activeElement;\n if (!field.contains(active) && !isExemptTarget(active))\n setExpanded(id, false);\n };\n if (pointerActivationTarget)\n pendingPointerBlurCollapses.set(id, collapseIfStillEmptyAndBlurred);\n else view().queueMicrotask(collapseIfStillEmptyAndBlurred);\n },\n ),\n );\n }\n\n const dispose = () => {\n disposed = true;\n if (pointerReleaseTimer !== undefined)\n view().clearTimeout(pointerReleaseTimer);\n pendingPointerBlurCollapses.clear();\n suggestionsObserver.disconnect();\n for (const stop of positionedSuggestions.values()) stop();\n positionedSuggestions.clear();\n for (const stop of focusing.values()) stop();\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 && !disposed) openField(id);\n };\n handle.close = (id) => {\n if (managed && !disposed) closeField(id);\n };\n return handle;\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { remify } from './chunk-2G2ZJQYK.js';
|
|
2
|
+
import { jsx } from 'kerfjs/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
var lucideIconSizePixels = {
|
|
5
|
+
xs: 12,
|
|
6
|
+
s: 16,
|
|
7
|
+
m: 20,
|
|
8
|
+
l: 24,
|
|
9
|
+
xl: 32
|
|
10
|
+
};
|
|
11
|
+
function LucideIcon({
|
|
12
|
+
icon,
|
|
13
|
+
name,
|
|
14
|
+
className,
|
|
15
|
+
label,
|
|
16
|
+
size,
|
|
17
|
+
slot
|
|
18
|
+
}) {
|
|
19
|
+
if (typeof size === "number" && (!Number.isFinite(size) || size <= 0))
|
|
20
|
+
throw new RangeError(
|
|
21
|
+
"LucideIcon size must be a positive finite pixel value"
|
|
22
|
+
);
|
|
23
|
+
if (typeof size === "string" && !Object.hasOwn(lucideIconSizePixels, size))
|
|
24
|
+
throw new RangeError("LucideIcon size must use a named icon step");
|
|
25
|
+
const pixels = typeof size === "number" ? size : size && lucideIconSizePixels[size];
|
|
26
|
+
const slotAttribute = { slot };
|
|
27
|
+
return /* @__PURE__ */ jsx(
|
|
28
|
+
"svg",
|
|
29
|
+
{
|
|
30
|
+
...slotAttribute,
|
|
31
|
+
class: className,
|
|
32
|
+
"data-lucide": name,
|
|
33
|
+
"data-size": size === void 0 ? void 0 : String(size),
|
|
34
|
+
role: label ? "img" : void 0,
|
|
35
|
+
"aria-label": label,
|
|
36
|
+
"aria-hidden": label ? void 0 : "true",
|
|
37
|
+
viewBox: "0 0 24 24",
|
|
38
|
+
fill: "none",
|
|
39
|
+
stroke: "currentColor",
|
|
40
|
+
"stroke-width": "2",
|
|
41
|
+
"stroke-linecap": "round",
|
|
42
|
+
"stroke-linejoin": "round",
|
|
43
|
+
style: pixels === void 0 ? void 0 : `--_kui-lucide-size:${remify(pixels)}`,
|
|
44
|
+
children: icon.map(([tag, attrs]) => jsx(tag, attrs))
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { LucideIcon };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=chunk-MOSIE4Z2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lucide-icon.tsx"],"names":["jsx"],"mappings":";;;AAQA,IAAM,oBAAA,GAAuB;AAAA,EAC3B,EAAA,EAAI,EAAA;AAAA,EACJ,CAAA,EAAG,EAAA;AAAA,EACH,CAAA,EAAG,EAAA;AAAA,EACH,CAAA,EAAG,EAAA;AAAA,EACH,EAAA,EAAI;AACN,CAAA;AAcO,SAAS,UAAA,CAAW;AAAA,EACzB,IAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,IAAI,OAAO,SAAS,QAAA,KAAa,CAAC,OAAO,QAAA,CAAS,IAAI,KAAK,IAAA,IAAQ,CAAA,CAAA;AACjE,IAAA,MAAM,IAAI,UAAA;AAAA,MACR;AAAA,KACF;AACF,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,CAAC,MAAA,CAAO,MAAA,CAAO,sBAAsB,IAAI,CAAA;AACvE,IAAA,MAAM,IAAI,WAAW,4CAA4C,CAAA;AACnE,EAAA,MAAM,SACJ,OAAO,IAAA,KAAS,WAAW,IAAA,GAAO,IAAA,IAAQ,qBAAqB,IAAI,CAAA;AACrE,EAAA,MAAM,aAAA,GAAgB,EAAE,IAAA,EAAK;AAC7B,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,GAAG,aAAA;AAAA,MACJ,KAAA,EAAO,SAAA;AAAA,MACP,aAAA,EAAa,IAAA;AAAA,MACb,WAAA,EAAW,IAAA,KAAS,MAAA,GAAY,MAAA,GAAY,OAAO,IAAI,CAAA;AAAA,MACvD,IAAA,EAAM,QAAQ,KAAA,GAAQ,MAAA;AAAA,MACtB,YAAA,EAAY,KAAA;AAAA,MACZ,aAAA,EAAa,QAAQ,MAAA,GAAY,MAAA;AAAA,MACjC,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,MAAA,EAAO,cAAA;AAAA,MACP,cAAA,EAAa,GAAA;AAAA,MACb,gBAAA,EAAe,OAAA;AAAA,MACf,iBAAA,EAAgB,OAAA;AAAA,MAChB,OACE,MAAA,KAAW,MAAA,GACP,SACA,CAAA,mBAAA,EAAsB,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAAA,MAGzC,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC;AAAA;AAAA,GAC7C;AAEJ","file":"chunk-MOSIE4Z2.js","sourcesContent":["import { jsx } from 'kerfjs/jsx-runtime';\nimport type { IconNode } from 'lucide';\n\nimport { remify } from './css-values.js';\n\nexport type LucideNode = IconNode;\nexport type LucideIconSize = 'xs' | 's' | 'm' | 'l' | 'xl' | number;\n\nconst lucideIconSizePixels = {\n xs: 12,\n s: 16,\n m: 20,\n l: 24,\n xl: 32,\n} as const satisfies Record<Exclude<LucideIconSize, number>, number>;\n\nexport interface LucideIconProps {\n icon: LucideNode;\n name: string;\n className?: string;\n label?: string;\n /** Named icon scale or positive pixel size, converted to rem. Omit for 1em. */\n size?: LucideIconSize;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/** Render a Lucide-compatible icon node without copying icon SVG strings. */\nexport function LucideIcon({\n icon,\n name,\n className,\n label,\n size,\n slot,\n}: LucideIconProps) {\n if (typeof size === 'number' && (!Number.isFinite(size) || size <= 0))\n throw new RangeError(\n 'LucideIcon size must be a positive finite pixel value',\n );\n if (typeof size === 'string' && !Object.hasOwn(lucideIconSizePixels, size))\n throw new RangeError('LucideIcon size must use a named icon step');\n const pixels =\n typeof size === 'number' ? size : size && lucideIconSizePixels[size];\n const slotAttribute = { slot };\n return (\n <svg\n {...slotAttribute}\n class={className}\n data-lucide={name}\n data-size={size === undefined ? undefined : String(size)}\n role={label ? 'img' : undefined}\n aria-label={label}\n aria-hidden={label ? undefined : 'true'}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n style={\n pixels === undefined\n ? undefined\n : `--_kui-lucide-size:${remify(pixels)}`\n }\n >\n {icon.map(([tag, attrs]) => jsx(tag, attrs))}\n </svg>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LucideIcon } from './chunk-
|
|
1
|
+
import { LucideIcon } from './chunk-MOSIE4Z2.js';
|
|
2
2
|
import { Search, X } from 'lucide';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'kerfjs/jsx-runtime';
|
|
4
4
|
|
|
@@ -34,12 +34,14 @@ function TokenSearchField({
|
|
|
34
34
|
tokenPlaceholder = "Add search\u2026",
|
|
35
35
|
disabled = false,
|
|
36
36
|
autofocus = false,
|
|
37
|
+
fill = false,
|
|
37
38
|
collapsible = false,
|
|
38
39
|
expanded = false,
|
|
39
40
|
expandAction = "expand-token-search",
|
|
40
41
|
expandLabel,
|
|
41
42
|
leading,
|
|
42
43
|
trailing,
|
|
44
|
+
trailingAction,
|
|
43
45
|
presentation = "standalone",
|
|
44
46
|
editAction = "edit-search-token",
|
|
45
47
|
removeAction = "remove-search-token",
|
|
@@ -68,7 +70,8 @@ function TokenSearchField({
|
|
|
68
70
|
"data-disabled": String(disabled),
|
|
69
71
|
"data-collapsible": String(collapsible),
|
|
70
72
|
"data-expanded": String(resolvedExpanded),
|
|
71
|
-
"data-
|
|
73
|
+
"data-fill": String(fill),
|
|
74
|
+
"data-has-trailing": String(Boolean(trailing || trailingAction)),
|
|
72
75
|
"data-presentation": presentation,
|
|
73
76
|
slot,
|
|
74
77
|
children: !resolvedExpanded ? /* @__PURE__ */ jsx(
|
|
@@ -158,7 +161,19 @@ function TokenSearchField({
|
|
|
158
161
|
children: clearIcon ?? /* @__PURE__ */ jsx(CloseIcon, {})
|
|
159
162
|
}
|
|
160
163
|
),
|
|
161
|
-
|
|
164
|
+
trailingAction ? /* @__PURE__ */ jsx(
|
|
165
|
+
"button",
|
|
166
|
+
{
|
|
167
|
+
type: "button",
|
|
168
|
+
class: "kui-token-search__trailing-action",
|
|
169
|
+
id: trailingAction.id,
|
|
170
|
+
"data-action": trailingAction.action,
|
|
171
|
+
"aria-label": trailingAction.label,
|
|
172
|
+
title: trailingAction.label,
|
|
173
|
+
disabled,
|
|
174
|
+
children: trailingAction.icon
|
|
175
|
+
}
|
|
176
|
+
) : trailing ? /* @__PURE__ */ jsx("span", { class: "kui-token-search__trailing", children: trailing }) : null,
|
|
162
177
|
!disabled && suggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
163
178
|
"div",
|
|
164
179
|
{
|
|
@@ -244,4 +259,4 @@ function placeTokenSearchCaret(editor, offset) {
|
|
|
244
259
|
|
|
245
260
|
export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField };
|
|
246
261
|
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
262
|
+
//# sourceMappingURL=chunk-NSVLUDUW.js.map
|