@stonecrop/desktop 0.35.0 → 0.38.0

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/dist/desktop.js CHANGED
@@ -1,72 +1,82 @@
1
- import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, guardReactiveProps, h, inject, markRaw, mergeProps, nextTick, normalizeClass, normalizeProps, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, resolveComponent, resolveDynamicComponent, shallowRef, toDisplayString, unref, useId, useTemplateRef, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
1
+ import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, customRef, defineComponent, guardReactiveProps, h, inject, isRef, markRaw, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, resolveComponent, resolveDynamicComponent, shallowRef, toDisplayString, toRefs, toValue, unref, useId, useTemplateRef, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
2
2
  import { DRAFT_RECORD_ID, isDraftRecordId, useStonecrop, useValidationStore } from "@stonecrop/stonecrop";
3
3
  import { AForm, resolvedFieldsToColumns } from "@stonecrop/aform";
4
- import './assets/index.css';//#region src/components/CommandPalette.vue?vue&type=script&setup=true&lang.ts
5
- var _hoisted_1$3 = { class: "command-palette-header" };
6
- var _hoisted_2$3 = ["placeholder", "aria-activedescendant"];
7
- var _hoisted_3$3 = {
4
+ import './assets/index.css';//#region src/components/CommandSearch.vue?vue&type=script&setup=true&lang.ts
5
+ var _hoisted_1$3 = [
6
+ "role",
7
+ "aria-modal",
8
+ "aria-label"
9
+ ];
10
+ var _hoisted_2$3 = { class: "command-search-header" };
11
+ var _hoisted_3$3 = ["placeholder", "aria-activedescendant"];
12
+ var _hoisted_4$3 = {
8
13
  key: 0,
9
- id: "command-palette-results",
10
- class: "command-palette-results",
14
+ id: "command-search-results",
15
+ class: "command-search-results",
11
16
  role: "listbox",
12
17
  "aria-label": "Command results"
13
18
  };
14
- var _hoisted_4$3 = [
19
+ var _hoisted_5$3 = [
15
20
  "id",
16
21
  "aria-selected",
17
22
  "onClick",
18
23
  "onMouseover"
19
24
  ];
20
- var _hoisted_5$3 = { class: "result-title" };
21
- var _hoisted_6$2 = { class: "result-content" };
22
- var _hoisted_7$1 = {
25
+ var _hoisted_6$2 = { class: "command-search-result-title" };
26
+ var _hoisted_7$1 = { class: "command-search-result-content" };
27
+ var _hoisted_8$1 = {
23
28
  key: 1,
24
- class: "command-palette-no-results",
29
+ class: "command-search-no-results",
25
30
  role: "status",
26
31
  "aria-live": "polite"
27
32
  };
28
- //#endregion
29
- //#region src/components/CommandPalette.vue
30
- var CommandPalette_default = /* @__PURE__ */ defineComponent({
31
- __name: "CommandPalette",
33
+ var CommandSearch_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
34
+ __name: "CommandSearch",
32
35
  props: {
33
36
  search: { type: Function },
34
- isOpen: {
37
+ placeholder: { default: "Type a command or search..." },
38
+ maxResults: { default: 10 },
39
+ embedded: {
35
40
  type: Boolean,
36
41
  default: false
37
42
  },
38
- placeholder: { default: "Type a command or search..." },
39
- maxResults: { default: 10 }
43
+ autofocus: {
44
+ type: Boolean,
45
+ default: false
46
+ }
40
47
  },
41
48
  emits: ["select", "close"],
42
- setup(__props, { emit: __emit }) {
49
+ setup(__props, { expose: __expose, emit: __emit }) {
43
50
  const emit = __emit;
44
51
  const listboxId = useId();
45
52
  const query = ref("");
46
53
  const selectedIndex = ref(0);
47
54
  const inputRef = useTemplateRef("input");
48
55
  const results = computed(() => {
49
- if (!query.value) return [];
50
56
  return __props.search(query.value).slice(0, __props.maxResults);
51
57
  });
52
- watch(() => __props.isOpen, async (open) => {
53
- if (open) {
54
- query.value = "";
55
- selectedIndex.value = 0;
56
- await nextTick();
57
- inputRef.value?.focus();
58
- }
59
- });
58
+ watch(() => __props.autofocus, async (shouldFocus) => {
59
+ if (!shouldFocus) return;
60
+ query.value = "";
61
+ selectedIndex.value = 0;
62
+ await nextTick();
63
+ inputRef.value?.focus();
64
+ }, { immediate: true });
60
65
  watch(results, () => {
61
66
  selectedIndex.value = 0;
62
67
  });
63
- const closeModal = () => {
64
- emit("close");
65
- };
68
+ function reset() {
69
+ query.value = "";
70
+ selectedIndex.value = 0;
71
+ }
72
+ __expose({
73
+ reset,
74
+ focus: () => inputRef.value?.focus()
75
+ });
66
76
  const handleKeydown = (e) => {
67
77
  switch (e.key) {
68
78
  case "Escape":
69
- closeModal();
79
+ if (!__props.embedded) emit("close");
70
80
  break;
71
81
  case "ArrowDown":
72
82
  e.preventDefault();
@@ -80,6 +90,69 @@ var CommandPalette_default = /* @__PURE__ */ defineComponent({
80
90
  }
81
91
  };
82
92
  const selectResult = (result) => {
93
+ emit("select", result);
94
+ if (!__props.embedded) emit("close");
95
+ };
96
+ return (_ctx, _cache) => {
97
+ return openBlock(), createElementBlock("div", {
98
+ class: normalizeClass(["command-search", { "command-search--embedded": __props.embedded }]),
99
+ role: __props.embedded ? void 0 : "dialog",
100
+ "aria-modal": __props.embedded ? void 0 : true,
101
+ "aria-label": __props.embedded ? void 0 : "Command palette"
102
+ }, [createElementVNode("div", _hoisted_2$3, [withDirectives(createElementVNode("input", {
103
+ ref: "input",
104
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
105
+ type: "text",
106
+ class: "command-search-input",
107
+ placeholder: __props.placeholder,
108
+ "aria-label": "Search commands",
109
+ "aria-activedescendant": results.value.length && selectedIndex.value >= 0 ? `${unref(listboxId)}-opt-${selectedIndex.value}` : void 0,
110
+ "aria-controls": "command-search-results",
111
+ onKeydown: handleKeydown
112
+ }, null, 40, _hoisted_3$3), [[vModelText, query.value]])]), results.value.length ? (openBlock(), createElementBlock("div", _hoisted_4$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(results.value, (result, index) => {
113
+ return openBlock(), createElementBlock("div", {
114
+ id: `${unref(listboxId)}-opt-${index}`,
115
+ key: index,
116
+ class: normalizeClass(["command-search-result", { selected: index === selectedIndex.value }]),
117
+ role: "option",
118
+ "aria-selected": index === selectedIndex.value,
119
+ onClick: ($event) => selectResult(result),
120
+ onMouseover: ($event) => selectedIndex.value = index
121
+ }, [createElementVNode("div", _hoisted_6$2, [renderSlot(_ctx.$slots, "title", { result }, void 0, true)]), createElementVNode("div", _hoisted_7$1, [renderSlot(_ctx.$slots, "content", { result }, void 0, true)])], 42, _hoisted_5$3);
122
+ }), 128))])) : query.value && !results.value.length ? (openBlock(), createElementBlock("div", _hoisted_8$1, [renderSlot(_ctx.$slots, "empty", {}, () => [createTextVNode(" No results found for \"" + toDisplayString(query.value) + "\" ", 1)], true)])) : createCommentVNode("", true)], 10, _hoisted_1$3);
123
+ };
124
+ }
125
+ });
126
+ //#endregion
127
+ //#region \0plugin-vue:export-helper
128
+ var _plugin_vue_export_helper_default = (sfc, props) => {
129
+ const target = sfc.__vccOpts || sfc;
130
+ for (const [key, val] of props) target[key] = val;
131
+ return target;
132
+ };
133
+ //#endregion
134
+ //#region src/components/CommandSearch.vue
135
+ var CommandSearch_default = /*#__PURE__*/ _plugin_vue_export_helper_default(CommandSearch_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-2ec3bd14"]]);
136
+ //#endregion
137
+ //#region src/components/CommandPalette.vue
138
+ var CommandPalette_default = /* @__PURE__ */ defineComponent({
139
+ __name: "CommandPalette",
140
+ props: {
141
+ search: { type: Function },
142
+ isOpen: {
143
+ type: Boolean,
144
+ default: false
145
+ },
146
+ placeholder: { default: "Type a command or search..." },
147
+ maxResults: { default: 10 }
148
+ },
149
+ emits: ["select", "close"],
150
+ setup(__props, { emit: __emit }) {
151
+ const emit = __emit;
152
+ const closeModal = () => {
153
+ emit("close");
154
+ };
155
+ const onSelect = (result) => {
83
156
  emit("select", result);
84
157
  closeModal();
85
158
  };
@@ -91,38 +164,352 @@ var CommandPalette_default = /* @__PURE__ */ defineComponent({
91
164
  onClick: closeModal
92
165
  }, [createElementVNode("div", {
93
166
  class: "command-palette",
94
- role: "dialog",
95
- "aria-modal": "true",
96
- "aria-label": "Command palette",
97
- onClick: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop"]))
98
- }, [createElementVNode("div", _hoisted_1$3, [withDirectives(createElementVNode("input", {
99
- ref: "input",
100
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
101
- type: "text",
102
- class: "command-palette-input",
167
+ onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"]))
168
+ }, [createVNode(CommandSearch_default, {
169
+ search: __props.search,
103
170
  placeholder: __props.placeholder,
104
- "aria-label": "Search commands",
105
- "aria-activedescendant": results.value.length && selectedIndex.value >= 0 ? `${unref(listboxId)}-opt-${selectedIndex.value}` : void 0,
106
- "aria-controls": "command-palette-results",
107
- autofocus: "",
108
- onKeydown: handleKeydown
109
- }, null, 40, _hoisted_2$3), [[vModelText, query.value]])]), results.value.length ? (openBlock(), createElementBlock("div", _hoisted_3$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(results.value, (result, index) => {
110
- return openBlock(), createElementBlock("div", {
111
- id: `${unref(listboxId)}-opt-${index}`,
112
- key: index,
113
- class: normalizeClass(["command-palette-result", { selected: index === selectedIndex.value }]),
114
- role: "option",
115
- "aria-selected": index === selectedIndex.value,
116
- onClick: ($event) => selectResult(result),
117
- onMouseover: ($event) => selectedIndex.value = index
118
- }, [createElementVNode("div", _hoisted_5$3, [renderSlot(_ctx.$slots, "title", { result })]), createElementVNode("div", _hoisted_6$2, [renderSlot(_ctx.$slots, "content", { result })])], 42, _hoisted_4$3);
119
- }), 128))])) : query.value && !results.value.length ? (openBlock(), createElementBlock("div", _hoisted_7$1, [renderSlot(_ctx.$slots, "empty", {}, () => [createTextVNode(" No results found for \"" + toDisplayString(query.value) + "\" ", 1)])])) : createCommentVNode("", true)])])) : createCommentVNode("", true)]),
171
+ "max-results": __props.maxResults,
172
+ autofocus: __props.isOpen,
173
+ onSelect,
174
+ onClose: closeModal
175
+ }, createSlots({
176
+ title: withCtx(({ result }) => [renderSlot(_ctx.$slots, "title", { result })]),
177
+ content: withCtx(({ result }) => [renderSlot(_ctx.$slots, "content", { result })]),
178
+ _: 2
179
+ }, [_ctx.$slots.empty ? {
180
+ name: "empty",
181
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "empty")]),
182
+ key: "0"
183
+ } : void 0]), 1032, [
184
+ "search",
185
+ "placeholder",
186
+ "max-results",
187
+ "autofocus"
188
+ ])])])) : createCommentVNode("", true)]),
120
189
  _: 3
121
190
  })]);
122
191
  };
123
192
  }
124
193
  });
125
194
  //#endregion
195
+ //#region ../node_modules/.pnpm/@vueuse+shared@14.4.0_vue@3.5.41_typescript@6.0.3_/node_modules/@vueuse/shared/dist/index.js
196
+ var isClient = typeof window !== "undefined" && typeof document !== "undefined";
197
+ typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope;
198
+ var toString = Object.prototype.toString;
199
+ var isObject = (val) => toString.call(val) === "[object Object]";
200
+ function toArray(value) {
201
+ return Array.isArray(value) ? value : [value];
202
+ }
203
+ /**
204
+ * Extended `toRefs` that also accepts refs of an object.
205
+ *
206
+ * @see https://vueuse.org/toRefs
207
+ * @param objectRef A ref or normal object or array.
208
+ * @param options Options
209
+ */
210
+ function toRefs$1(objectRef, options = {}) {
211
+ if (!isRef(objectRef)) return toRefs(objectRef);
212
+ const result = Array.isArray(objectRef.value) ? Array.from({ length: objectRef.value.length }) : {};
213
+ for (const key in objectRef.value) result[key] = customRef(() => ({
214
+ get() {
215
+ return objectRef.value[key];
216
+ },
217
+ set(v) {
218
+ var _toValue;
219
+ if ((_toValue = toValue(options.replaceRef)) !== null && _toValue !== void 0 ? _toValue : true) if (Array.isArray(objectRef.value)) {
220
+ const copy = [...objectRef.value];
221
+ copy[key] = v;
222
+ objectRef.value = copy;
223
+ } else {
224
+ const newObject = {
225
+ ...objectRef.value,
226
+ [key]: v
227
+ };
228
+ Object.setPrototypeOf(newObject, Object.getPrototypeOf(objectRef.value));
229
+ objectRef.value = newObject;
230
+ }
231
+ else objectRef.value[key] = v;
232
+ }
233
+ }));
234
+ return result;
235
+ }
236
+ /**
237
+ * Shorthand for watching value with {immediate: true}
238
+ *
239
+ * @see https://vueuse.org/watchImmediate
240
+ */
241
+ function watchImmediate(source, cb, options) {
242
+ return watch(source, cb, {
243
+ ...options,
244
+ immediate: true
245
+ });
246
+ }
247
+ //#endregion
248
+ //#region ../node_modules/.pnpm/@vueuse+core@14.4.0_vue@3.5.41_typescript@6.0.3_/node_modules/@vueuse/core/dist/index.js
249
+ var defaultWindow = isClient ? window : void 0;
250
+ isClient && window.document;
251
+ isClient && window.navigator;
252
+ isClient && window.location;
253
+ /**
254
+ * Get the dom element of a ref of element or Vue component instance
255
+ *
256
+ * @param elRef
257
+ */
258
+ function unrefElement(elRef) {
259
+ var _$el;
260
+ const plain = toValue(elRef);
261
+ return (_$el = plain === null || plain === void 0 ? void 0 : plain.$el) !== null && _$el !== void 0 ? _$el : plain;
262
+ }
263
+ function useEventListener(...args) {
264
+ const register = (el, event, listener, options) => {
265
+ el.addEventListener(event, listener, options);
266
+ return () => el.removeEventListener(event, listener, options);
267
+ };
268
+ const firstParamTargets = computed(() => {
269
+ const test = toArray(toValue(args[0])).filter((e) => e != null);
270
+ return test.every((e) => typeof e !== "string") ? test : void 0;
271
+ });
272
+ return watchImmediate(() => {
273
+ var _firstParamTargets$va, _firstParamTargets$va2;
274
+ return [
275
+ (_firstParamTargets$va = (_firstParamTargets$va2 = firstParamTargets.value) === null || _firstParamTargets$va2 === void 0 ? void 0 : _firstParamTargets$va2.map((e) => unrefElement(e))) !== null && _firstParamTargets$va !== void 0 ? _firstParamTargets$va : [defaultWindow].filter((e) => e != null),
276
+ toArray(toValue(firstParamTargets.value ? args[1] : args[0])),
277
+ toArray(unref(firstParamTargets.value ? args[2] : args[1])),
278
+ toValue(firstParamTargets.value ? args[3] : args[2])
279
+ ];
280
+ }, ([raw_targets, raw_events, raw_listeners, raw_options], _, onCleanup) => {
281
+ if (!(raw_targets === null || raw_targets === void 0 ? void 0 : raw_targets.length) || !(raw_events === null || raw_events === void 0 ? void 0 : raw_events.length) || !(raw_listeners === null || raw_listeners === void 0 ? void 0 : raw_listeners.length)) return;
282
+ const optionsClone = isObject(raw_options) ? { ...raw_options } : raw_options;
283
+ const cleanups = raw_targets.flatMap((el) => raw_events.flatMap((event) => raw_listeners.map((listener) => register(el, event, listener, optionsClone))));
284
+ onCleanup(() => {
285
+ cleanups.forEach((fn) => fn());
286
+ });
287
+ }, { flush: "post" });
288
+ }
289
+ var defaultScrollConfig = {
290
+ speed: 2,
291
+ margin: 30,
292
+ direction: "both"
293
+ };
294
+ function clampContainerScroll(container) {
295
+ if (container.scrollLeft > container.scrollWidth - container.clientWidth) container.scrollLeft = Math.max(0, container.scrollWidth - container.clientWidth);
296
+ if (container.scrollTop > container.scrollHeight - container.clientHeight) container.scrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
297
+ }
298
+ /**
299
+ * Make elements draggable.
300
+ *
301
+ * @see https://vueuse.org/useDraggable
302
+ * @param target
303
+ * @param options
304
+ */
305
+ function useDraggable(target, options = {}) {
306
+ var _toValue, _toValue2, _toValue3, _scrollConfig$directi;
307
+ const { pointerTypes, preventDefault, stopPropagation, exact, onMove, onEnd, onStart, initialValue, axis = "both", draggingElement = defaultWindow, containerElement, handle: draggingHandle = target, buttons = [0], restrictInView, autoScroll = false } = options;
308
+ const position = ref((_toValue = toValue(initialValue)) !== null && _toValue !== void 0 ? _toValue : {
309
+ x: 0,
310
+ y: 0
311
+ });
312
+ const pressedDelta = ref();
313
+ const filterEvent = (e) => {
314
+ if (pointerTypes) return pointerTypes.includes(e.pointerType);
315
+ return true;
316
+ };
317
+ const handleEvent = (e) => {
318
+ if (toValue(preventDefault)) e.preventDefault();
319
+ if (toValue(stopPropagation)) e.stopPropagation();
320
+ };
321
+ const scrollConfig = toValue(autoScroll);
322
+ const scrollSettings = typeof scrollConfig === "object" ? {
323
+ speed: (_toValue2 = toValue(scrollConfig.speed)) !== null && _toValue2 !== void 0 ? _toValue2 : defaultScrollConfig.speed,
324
+ margin: (_toValue3 = toValue(scrollConfig.margin)) !== null && _toValue3 !== void 0 ? _toValue3 : defaultScrollConfig.margin,
325
+ direction: (_scrollConfig$directi = scrollConfig.direction) !== null && _scrollConfig$directi !== void 0 ? _scrollConfig$directi : defaultScrollConfig.direction
326
+ } : defaultScrollConfig;
327
+ const getScrollAxisValues = (value) => typeof value === "number" ? [value, value] : [value.x, value.y];
328
+ const handleAutoScroll = (container, targetRect, position) => {
329
+ const { clientWidth, clientHeight, scrollLeft, scrollTop, scrollWidth, scrollHeight } = container;
330
+ const [marginX, marginY] = getScrollAxisValues(scrollSettings.margin);
331
+ const [speedX, speedY] = getScrollAxisValues(scrollSettings.speed);
332
+ let deltaX = 0;
333
+ let deltaY = 0;
334
+ if (scrollSettings.direction === "x" || scrollSettings.direction === "both") {
335
+ if (position.x < marginX && scrollLeft > 0) deltaX = -speedX;
336
+ else if (position.x + targetRect.width > clientWidth - marginX && scrollLeft < scrollWidth - clientWidth) deltaX = speedX;
337
+ }
338
+ if (scrollSettings.direction === "y" || scrollSettings.direction === "both") {
339
+ if (position.y < marginY && scrollTop > 0) deltaY = -speedY;
340
+ else if (position.y + targetRect.height > clientHeight - marginY && scrollTop < scrollHeight - clientHeight) deltaY = speedY;
341
+ }
342
+ if (deltaX || deltaY) container.scrollBy({
343
+ left: deltaX,
344
+ top: deltaY,
345
+ behavior: "auto"
346
+ });
347
+ };
348
+ let autoScrollInterval = null;
349
+ const startAutoScroll = () => {
350
+ const container = toValue(containerElement);
351
+ if (container && !autoScrollInterval) autoScrollInterval = setInterval(() => {
352
+ const targetRect = toValue(target).getBoundingClientRect();
353
+ const { x, y } = position.value;
354
+ const relativePosition = {
355
+ x: x - container.scrollLeft,
356
+ y: y - container.scrollTop
357
+ };
358
+ if (relativePosition.x >= 0 && relativePosition.y >= 0) {
359
+ handleAutoScroll(container, targetRect, relativePosition);
360
+ relativePosition.x += container.scrollLeft;
361
+ relativePosition.y += container.scrollTop;
362
+ position.value = relativePosition;
363
+ }
364
+ }, 1e3 / 60);
365
+ };
366
+ const stopAutoScroll = () => {
367
+ if (autoScrollInterval) {
368
+ clearInterval(autoScrollInterval);
369
+ autoScrollInterval = null;
370
+ }
371
+ };
372
+ const isPointerNearEdge = (pointer, container, margin, targetRect) => {
373
+ const [marginX, marginY] = typeof margin === "number" ? [margin, margin] : [margin.x, margin.y];
374
+ const { clientWidth, clientHeight } = container;
375
+ return pointer.x < marginX || pointer.x + targetRect.width > clientWidth - marginX || pointer.y < marginY || pointer.y + targetRect.height > clientHeight - marginY;
376
+ };
377
+ const checkAutoScroll = () => {
378
+ if (toValue(options.disabled) || !pressedDelta.value) return;
379
+ const container = toValue(containerElement);
380
+ if (!container) return;
381
+ const targetRect = toValue(target).getBoundingClientRect();
382
+ const { x, y } = position.value;
383
+ const relativePosition = {
384
+ x: x - container.scrollLeft,
385
+ y: y - container.scrollTop
386
+ };
387
+ if (isPointerNearEdge(relativePosition, container, scrollSettings.margin, targetRect)) startAutoScroll();
388
+ else stopAutoScroll();
389
+ };
390
+ if (toValue(autoScroll)) watch(position, checkAutoScroll);
391
+ const start = (e) => {
392
+ var _container$getBoundin;
393
+ if (!toValue(buttons).includes(e.button)) return;
394
+ if (toValue(options.disabled) || !filterEvent(e)) return;
395
+ if (toValue(exact) && e.target !== toValue(target)) return;
396
+ const container = toValue(containerElement);
397
+ const containerRect = container === null || container === void 0 || (_container$getBoundin = container.getBoundingClientRect) === null || _container$getBoundin === void 0 ? void 0 : _container$getBoundin.call(container);
398
+ const targetRect = toValue(target).getBoundingClientRect();
399
+ const pos = {
400
+ x: e.clientX - (container ? targetRect.left - containerRect.left + (autoScroll ? 0 : container.scrollLeft) : targetRect.left),
401
+ y: e.clientY - (container ? targetRect.top - containerRect.top + (autoScroll ? 0 : container.scrollTop) : targetRect.top)
402
+ };
403
+ if ((onStart === null || onStart === void 0 ? void 0 : onStart(pos, e)) === false) return;
404
+ pressedDelta.value = pos;
405
+ handleEvent(e);
406
+ };
407
+ const move = (e) => {
408
+ if (toValue(options.disabled) || !filterEvent(e)) return;
409
+ if (!pressedDelta.value) return;
410
+ const container = toValue(containerElement);
411
+ if (container instanceof HTMLElement) clampContainerScroll(container);
412
+ const targetRect = toValue(target).getBoundingClientRect();
413
+ let { x, y } = position.value;
414
+ if (axis === "x" || axis === "both") {
415
+ x = e.clientX - pressedDelta.value.x;
416
+ if (container) x = Math.min(Math.max(0, x), container.scrollWidth - targetRect.width);
417
+ }
418
+ if (axis === "y" || axis === "both") {
419
+ y = e.clientY - pressedDelta.value.y;
420
+ if (container) y = Math.min(Math.max(0, y), container.scrollHeight - targetRect.height);
421
+ }
422
+ if (toValue(autoScroll) && container) {
423
+ if (autoScrollInterval === null) handleAutoScroll(container, targetRect, {
424
+ x,
425
+ y
426
+ });
427
+ x += container.scrollLeft;
428
+ y += container.scrollTop;
429
+ }
430
+ if (container && (restrictInView || autoScroll)) {
431
+ if (axis !== "y") {
432
+ const relativeX = x - container.scrollLeft;
433
+ if (relativeX < 0) x = container.scrollLeft;
434
+ else if (relativeX > container.clientWidth - targetRect.width) x = container.clientWidth - targetRect.width + container.scrollLeft;
435
+ }
436
+ if (axis !== "x") {
437
+ const relativeY = y - container.scrollTop;
438
+ if (relativeY < 0) y = container.scrollTop;
439
+ else if (relativeY > container.clientHeight - targetRect.height) y = container.clientHeight - targetRect.height + container.scrollTop;
440
+ }
441
+ }
442
+ position.value = {
443
+ x,
444
+ y
445
+ };
446
+ onMove === null || onMove === void 0 || onMove(position.value, e);
447
+ handleEvent(e);
448
+ };
449
+ const end = (e) => {
450
+ if (toValue(options.disabled) || !filterEvent(e)) return;
451
+ if (!pressedDelta.value) return;
452
+ pressedDelta.value = void 0;
453
+ if (autoScroll) stopAutoScroll();
454
+ onEnd === null || onEnd === void 0 || onEnd(position.value, e);
455
+ handleEvent(e);
456
+ };
457
+ if (isClient) {
458
+ const config = () => {
459
+ var _options$capture;
460
+ return {
461
+ capture: (_options$capture = options.capture) !== null && _options$capture !== void 0 ? _options$capture : true,
462
+ passive: !toValue(preventDefault)
463
+ };
464
+ };
465
+ useEventListener(draggingHandle, "pointerdown", start, config);
466
+ useEventListener(draggingElement, "pointermove", move, config);
467
+ useEventListener(draggingElement, ["pointerup", "pointercancel"], end, config);
468
+ }
469
+ return {
470
+ ...toRefs$1(position),
471
+ position,
472
+ isDragging: computed(() => !!pressedDelta.value),
473
+ style: computed(() => `
474
+ left: ${position.value.x}px;
475
+ top: ${position.value.y}px;
476
+ ${autoScroll ? "text-wrap: nowrap;" : ""}
477
+ `)
478
+ };
479
+ }
480
+ Number.POSITIVE_INFINITY;
481
+ //#endregion
482
+ //#region src/action-set-layout.ts
483
+ /** SheetNav root is `<footer class="desktop__sheetnav">`; cluster holds tabs + toolbar. */
484
+ var SHEET_NAV_CLUSTER_SELECTOR = ".desktop__sheetnav .sheetnav-footer-cluster";
485
+ /** Maximum viewport Y for the bottom edge of the tile rail (above SheetNav). */
486
+ function maxRailBottomY(bounds) {
487
+ const { margin, innerHeight, sheetNavTop } = bounds;
488
+ if (sheetNavTop === null) return innerHeight - margin;
489
+ return sheetNavTop - margin;
490
+ }
491
+ function maxTopForRailHeight(railHeight, bounds) {
492
+ const margin = bounds.margin;
493
+ return Math.max(margin, maxRailBottomY(bounds) - railHeight);
494
+ }
495
+ function clampTileTop(top, railHeight, bounds) {
496
+ const margin = bounds.margin;
497
+ const maxTop = maxTopForRailHeight(railHeight, bounds);
498
+ return Math.min(Math.max(margin, top), maxTop);
499
+ }
500
+ function isAtLowerVerticalLimit(top, railHeight, bounds, epsilon = 1) {
501
+ return top >= maxTopForRailHeight(railHeight, bounds) - epsilon;
502
+ }
503
+ //#endregion
504
+ //#region src/action-set-layout-session.ts
505
+ var session = { tileTopPx: null };
506
+ function readActionSetLayoutSession() {
507
+ return session;
508
+ }
509
+ function writeActionSetLayoutSession(partial) {
510
+ if (partial.tileTopPx !== void 0) session.tileTopPx = partial.tileTopPx;
511
+ }
512
+ //#endregion
126
513
  //#region src/icons/index.ts
127
514
  /**
128
515
  * Shared 24×24 stroke chrome for ActionSet and shell icons.
@@ -235,68 +622,186 @@ var ActionSetIconHelp = actionSetIcon("ActionSetIconHelp", () => [
235
622
  ]);
236
623
  //#endregion
237
624
  //#region src/components/ActionSet.vue?vue&type=script&setup=true&lang.ts
238
- var _hoisted_1$2 = {
625
+ var _hoisted_1$2 = { class: "action-set" };
626
+ var _hoisted_2$2 = { class: "action-set__drawer-header" };
627
+ var _hoisted_3$2 = { class: "action-set__drawer-body" };
628
+ var _hoisted_4$2 = {
629
+ key: 1,
630
+ class: "action-set__actions-list"
631
+ };
632
+ var _hoisted_5$2 = ["aria-label"];
633
+ var _hoisted_6$1 = {
634
+ class: "action-set__actions-group-label",
635
+ "aria-hidden": "true"
636
+ };
637
+ var _hoisted_7 = ["onClick"];
638
+ var _hoisted_8 = ["href"];
639
+ var _hoisted_9 = ["href"];
640
+ var _hoisted_10 = ["disabled", "onClick"];
641
+ var _hoisted_11 = {
642
+ key: 0,
643
+ class: "action-set__actions-empty"
644
+ };
645
+ var _hoisted_12 = {
646
+ key: 1,
647
+ class: "action-set__drawer-empty"
648
+ };
649
+ var _hoisted_13 = ["aria-hidden"];
650
+ var _hoisted_14 = {
239
651
  class: "action-set__tile",
240
652
  role: "presentation"
241
653
  };
242
- var _hoisted_2$2 = ["aria-expanded"];
243
- var _hoisted_3$2 = [
654
+ var _hoisted_15 = ["aria-expanded"];
655
+ var _hoisted_16 = [
244
656
  "aria-label",
245
657
  "aria-current",
246
658
  "title",
247
659
  "onClick"
248
660
  ];
249
- var _hoisted_4$2 = {
661
+ var _hoisted_17 = {
250
662
  key: 1,
251
663
  class: "action-set__item-fallback",
252
664
  "aria-hidden": "true"
253
665
  };
254
- var _hoisted_5$2 = {
666
+ var _hoisted_18 = {
255
667
  key: 2,
256
668
  class: "action-set__item-badge"
257
669
  };
258
- var _hoisted_6$1 = { class: "action-set__drawer-header" };
259
- var _hoisted_7 = { class: "action-set__drawer-body" };
260
- var _hoisted_8 = {
261
- key: 0,
262
- class: "action-set__actions-list"
263
- };
264
- var _hoisted_9 = ["aria-label"];
265
- var _hoisted_10 = {
266
- class: "action-set__actions-group-label",
267
- "aria-hidden": "true"
268
- };
269
- var _hoisted_11 = ["onClick"];
270
- var _hoisted_12 = ["href"];
271
- var _hoisted_13 = ["href"];
272
- var _hoisted_14 = ["disabled", "onClick"];
273
- var _hoisted_15 = {
274
- key: 0,
275
- class: "action-set__actions-empty"
276
- };
277
- var _hoisted_16 = {
278
- key: 1,
279
- class: "action-set__drawer-empty"
280
- };
281
670
  var ACTIONS_TAB_ID = "__actions__";
282
671
  var SEARCH_TAB_ID = "__search__";
283
- var ActionSet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
672
+ //#endregion
673
+ //#region src/components/ActionSet.vue
674
+ var ActionSet_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
284
675
  __name: "ActionSet",
285
676
  props: {
286
677
  slots: { default: () => [] },
287
678
  elements: { default: () => [] },
288
- controller: {}
679
+ controller: {},
680
+ search: { type: Function },
681
+ searchPlaceholder: { default: "Type a command or search..." }
289
682
  },
290
- emits: ["actionClick", "search"],
683
+ emits: ["actionClick", "searchSelect"],
291
684
  setup(__props, { emit: __emit }) {
685
+ let tileGapProbe = null;
292
686
  const emit = __emit;
293
687
  const isExpanded = ref(true);
688
+ function readInitialTileTopPx() {
689
+ if (typeof window === "undefined") return 0;
690
+ const saved = readActionSetLayoutSession();
691
+ if (saved.tileTopPx !== null) return saved.tileTopPx;
692
+ return resolveOffsetTopPx();
693
+ }
694
+ const initialTileTopPx = readInitialTileTopPx();
695
+ const railLayoutReady = ref(false);
294
696
  const drawerEl = ref(null);
697
+ const searchEl = ref(null);
295
698
  const lastFocusedBeforeDrawer = ref(null);
296
699
  const activeSlot = computed(() => __props.slots.find((slot) => slot.id === __props.controller.activeSlotId.value) ?? null);
297
700
  const hasActions = computed(() => __props.elements.length > 0);
298
- const activeTabId = computed(() => __props.controller.isActionsOpen.value ? ACTIONS_TAB_ID : __props.controller.activeSlotId.value);
701
+ const activeTabId = computed(() => {
702
+ if (__props.controller.isSearchOpen.value) return SEARCH_TAB_ID;
703
+ if (__props.controller.isActionsOpen.value) return ACTIONS_TAB_ID;
704
+ return __props.controller.activeSlotId.value;
705
+ });
299
706
  const drawerOpen = computed(() => __props.controller.isDrawerOpen.value);
707
+ const tileRail = useTemplateRef("tileRail");
708
+ const dragHandle = useTemplateRef("dragHandle");
709
+ function resolveTileGapPx() {
710
+ if (typeof document === "undefined") return 4;
711
+ if (!tileGapProbe) {
712
+ tileGapProbe = document.createElement("div");
713
+ tileGapProbe.style.cssText = "position:absolute;visibility:hidden;pointer-events:none;height:0;width:var(--sc-action-set-tile-gap);";
714
+ document.body.append(tileGapProbe);
715
+ }
716
+ const px = Number.parseFloat(getComputedStyle(tileGapProbe).width);
717
+ return Number.isFinite(px) && px > 0 ? px : 4;
718
+ }
719
+ function resolveOffsetTopPx() {
720
+ if (typeof document === "undefined") return 0;
721
+ const raw = getComputedStyle(document.documentElement).getPropertyValue("--sc-action-set-offset-top").trim() || "35vh";
722
+ if (raw.endsWith("vh")) return Number.parseFloat(raw) / 100 * window.innerHeight;
723
+ if (raw.endsWith("px")) return Number.parseFloat(raw);
724
+ return window.innerHeight * .35;
725
+ }
726
+ function resolveSheetNavTopPx() {
727
+ if (typeof document === "undefined") return null;
728
+ const cluster = document.querySelector(SHEET_NAV_CLUSTER_SELECTOR);
729
+ if (!cluster) return null;
730
+ const top = cluster.getBoundingClientRect().top;
731
+ return Number.isFinite(top) ? top : null;
732
+ }
733
+ function layoutBounds() {
734
+ return {
735
+ margin: resolveTileGapPx(),
736
+ innerHeight: typeof window === "undefined" ? 0 : window.innerHeight,
737
+ sheetNavTop: resolveSheetNavTopPx()
738
+ };
739
+ }
740
+ function clampTileTop$1(top) {
741
+ if (typeof window === "undefined") return top;
742
+ return clampTileTop(top, tileRail.value?.offsetHeight ?? 0, layoutBounds());
743
+ }
744
+ function isAtLowerVerticalLimit$1() {
745
+ if (!tileRail.value) return false;
746
+ return isAtLowerVerticalLimit(tileTopPx.value, tileRail.value.offsetHeight, layoutBounds());
747
+ }
748
+ function applyVerticalLimits() {
749
+ tileTopPx.value = clampTileTop$1(tileTopPx.value);
750
+ }
751
+ function persistLayoutSession() {
752
+ writeActionSetLayoutSession({ tileTopPx: tileTopPx.value });
753
+ }
754
+ const { y: tileTopPx } = useDraggable(tileRail, {
755
+ axis: "y",
756
+ handle: dragHandle,
757
+ preventDefault: true,
758
+ initialValue: {
759
+ x: 0,
760
+ y: initialTileTopPx
761
+ },
762
+ onMove: (pos) => {
763
+ tileTopPx.value = clampTileTop$1(pos.y);
764
+ },
765
+ onEnd: () => {
766
+ applyVerticalLimits();
767
+ persistLayoutSession();
768
+ }
769
+ });
770
+ onMounted(() => {
771
+ nextTick(() => {
772
+ applyVerticalLimits();
773
+ persistLayoutSession();
774
+ requestAnimationFrame(() => {
775
+ applyVerticalLimits();
776
+ railLayoutReady.value = true;
777
+ });
778
+ });
779
+ });
780
+ watch(tileTopPx, () => {
781
+ persistLayoutSession();
782
+ });
783
+ watch(isExpanded, () => {
784
+ nextTick(() => {
785
+ applyVerticalLimits();
786
+ });
787
+ });
788
+ useEventListener(typeof window !== "undefined" ? window : null, "resize", () => {
789
+ applyVerticalLimits();
790
+ });
791
+ let sheetNavResizeObserver = null;
792
+ onMounted(() => {
793
+ const cluster = document.querySelector(SHEET_NAV_CLUSTER_SELECTOR);
794
+ if (!cluster || typeof ResizeObserver === "undefined") return;
795
+ sheetNavResizeObserver = new ResizeObserver(() => {
796
+ applyVerticalLimits();
797
+ });
798
+ sheetNavResizeObserver.observe(cluster);
799
+ });
800
+ onUnmounted(() => {
801
+ sheetNavResizeObserver?.disconnect();
802
+ sheetNavResizeObserver = null;
803
+ });
804
+ const tileRailStyle = computed(() => ({ top: `${tileTopPx.value}px` }));
300
805
  const allTabs = computed(() => {
301
806
  const tabs = [{
302
807
  id: SEARCH_TAB_ID,
@@ -329,12 +834,37 @@ var ActionSet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
329
834
  event.stopPropagation();
330
835
  __props.controller.close();
331
836
  }
332
- function onToggle() {
333
- isExpanded.value = !isExpanded.value;
837
+ async function onToggle() {
838
+ if (isExpanded.value) {
839
+ isExpanded.value = false;
840
+ await nextTick();
841
+ applyVerticalLimits();
842
+ return;
843
+ }
844
+ const atLowerLimit = isAtLowerVerticalLimit$1();
845
+ const heightBefore = tileRail.value?.offsetHeight ?? 0;
846
+ isExpanded.value = true;
847
+ await nextTick();
848
+ if (atLowerLimit && tileRail.value) {
849
+ const heightAfter = tileRail.value.offsetHeight;
850
+ tileTopPx.value -= heightAfter - heightBefore;
851
+ }
852
+ applyVerticalLimits();
853
+ }
854
+ function searchResultTitle(result) {
855
+ return typeof result === "object" && result !== null && "title" in result ? String(result.title) : "";
856
+ }
857
+ function searchResultDescription(result) {
858
+ return typeof result === "object" && result !== null && "description" in result ? String(result.description) : "";
859
+ }
860
+ function onSearchSelect(result) {
861
+ emit("searchSelect", result);
334
862
  }
335
863
  function onTileClick(tabId) {
336
- if (tabId === SEARCH_TAB_ID) emit("search");
337
- else if (drawerOpen.value && activeTabId.value === tabId) __props.controller.close();
864
+ if (tabId === SEARCH_TAB_ID) {
865
+ if (drawerOpen.value && activeTabId.value === SEARCH_TAB_ID) __props.controller.close();
866
+ else __props.controller.openSearch();
867
+ } else if (drawerOpen.value && activeTabId.value === tabId) __props.controller.close();
338
868
  else if (tabId === ACTIONS_TAB_ID) __props.controller.openActions();
339
869
  else __props.controller.openSlot(tabId);
340
870
  }
@@ -342,92 +872,119 @@ var ActionSet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
342
872
  if (action) emit("actionClick", label, action);
343
873
  }
344
874
  watch(drawerOpen, async (open) => {
875
+ if (typeof document === "undefined") return;
345
876
  if (open) {
346
877
  lastFocusedBeforeDrawer.value = document.activeElement instanceof HTMLElement ? document.activeElement : null;
347
878
  await nextTick();
879
+ if (__props.controller.isSearchOpen.value) {
880
+ searchEl.value?.focus();
881
+ return;
882
+ }
348
883
  drawerEl.value?.querySelector("button:not([disabled]), [href], input, select, textarea")?.focus();
349
884
  return;
350
885
  }
351
886
  lastFocusedBeforeDrawer.value?.focus();
352
887
  lastFocusedBeforeDrawer.value = null;
353
888
  });
889
+ watch(() => __props.controller.isSearchOpen.value, async (open) => {
890
+ if (!open) return;
891
+ await nextTick();
892
+ searchEl.value?.reset();
893
+ searchEl.value?.focus();
894
+ });
354
895
  return (_ctx, _cache) => {
355
- return openBlock(), createElementBlock("div", { class: normalizeClass(["action-set", {
356
- "action-set--expanded": isExpanded.value,
357
- "action-set--drawer-open": drawerOpen.value
358
- }]) }, [createElementVNode("div", _hoisted_1$2, [createElementVNode("button", {
359
- type: "button",
360
- class: normalizeClass(["action-set__toggle", { "action-set__toggle--expanded": isExpanded.value }]),
361
- "aria-label": "Toggle menu",
362
- "aria-expanded": isExpanded.value,
363
- onClick: onToggle
364
- }, " + ", 10, _hoisted_2$2), isExpanded.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(allTabs.value, (tab) => {
365
- return openBlock(), createElementBlock("button", {
366
- key: tab.id,
367
- type: "button",
368
- class: normalizeClass(["action-set__item", { "action-set__item--active": drawerOpen.value && activeTabId.value === tab.id }]),
369
- "aria-label": tab.label,
370
- "aria-current": drawerOpen.value && activeTabId.value === tab.id ? "page" : void 0,
371
- title: tab.label,
372
- onClick: ($event) => onTileClick(tab.id)
373
- }, [tab.icon ? (openBlock(), createBlock(resolveDynamicComponent(tab.icon), {
374
- key: 0,
375
- class: "action-set__item-icon"
376
- })) : (openBlock(), createElementBlock("span", _hoisted_4$2, toDisplayString(slotFallback(tab.label)), 1)), tabBadge(tab) > 0 ? (openBlock(), createElementBlock("span", _hoisted_5$2, toDisplayString(tabBadge(tab)), 1)) : createCommentVNode("", true)], 10, _hoisted_3$2);
377
- }), 128)) : createCommentVNode("", true)]), drawerOpen.value ? (openBlock(), createElementBlock("aside", {
896
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [drawerOpen.value ? (openBlock(), createElementBlock("aside", {
378
897
  key: 0,
379
898
  ref_key: "drawerEl",
380
899
  ref: drawerEl,
381
900
  class: "action-set__drawer",
382
901
  "aria-label": "Side panel",
383
902
  onKeydown: onDrawerKeydown
384
- }, [createElementVNode("header", _hoisted_6$1, [createElementVNode("button", {
903
+ }, [createElementVNode("header", _hoisted_2$2, [createElementVNode("button", {
385
904
  type: "button",
386
905
  class: "action-set__drawer-close",
387
906
  "aria-label": "Close panel",
388
907
  onClick: _cache[0] || (_cache[0] = ($event) => __props.controller.close())
389
- }, " × ")]), createElementVNode("div", _hoisted_7, [activeTabId.value === ACTIONS_TAB_ID ? (openBlock(), createElementBlock("div", _hoisted_8, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.elements, (el) => {
908
+ }, " × ")]), createElementVNode("div", _hoisted_3$2, [activeTabId.value === SEARCH_TAB_ID && __props.search ? (openBlock(), createBlock(CommandSearch_default, {
909
+ key: 0,
910
+ ref_key: "searchEl",
911
+ ref: searchEl,
912
+ search: __props.search,
913
+ placeholder: __props.searchPlaceholder,
914
+ embedded: "",
915
+ autofocus: "",
916
+ onSelect: onSearchSelect
917
+ }, {
918
+ title: withCtx(({ result }) => [renderSlot(_ctx.$slots, "search-title", { result }, () => [createTextVNode(toDisplayString(searchResultTitle(result)), 1)], true)]),
919
+ content: withCtx(({ result }) => [renderSlot(_ctx.$slots, "search-content", { result }, () => [createTextVNode(toDisplayString(searchResultDescription(result)), 1)], true)]),
920
+ _: 3
921
+ }, 8, ["search", "placeholder"])) : activeTabId.value === ACTIONS_TAB_ID ? (openBlock(), createElementBlock("div", _hoisted_4$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.elements, (el) => {
390
922
  return openBlock(), createElementBlock(Fragment, { key: el.label }, [el.type === "dropdown" ? (openBlock(), createElementBlock("div", {
391
923
  key: 0,
392
924
  class: "action-set__actions-group",
393
925
  role: "group",
394
926
  "aria-label": el.label
395
- }, [createElementVNode("p", _hoisted_10, toDisplayString(el.label), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(el.actions, (item) => {
927
+ }, [createElementVNode("p", _hoisted_6$1, toDisplayString(el.label), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(el.actions, (item) => {
396
928
  return openBlock(), createElementBlock(Fragment, { key: item.label }, [item.action ? (openBlock(), createElementBlock("button", {
397
929
  key: 0,
398
930
  type: "button",
399
931
  class: "action-set__actions-list-item action-set__actions-list-item--nested",
400
932
  onClick: ($event) => onActionClick(item.label, item.action)
401
- }, toDisplayString(item.label), 9, _hoisted_11)) : item.link ? (openBlock(), createElementBlock("a", {
933
+ }, toDisplayString(item.label), 9, _hoisted_7)) : item.link ? (openBlock(), createElementBlock("a", {
402
934
  key: 1,
403
935
  href: item.link,
404
936
  class: "action-set__actions-list-item action-set__actions-list-item--nested"
405
- }, toDisplayString(item.label), 9, _hoisted_12)) : createCommentVNode("", true)], 64);
406
- }), 128))], 8, _hoisted_9)) : !el.action && el.link ? (openBlock(), createElementBlock("a", {
937
+ }, toDisplayString(item.label), 9, _hoisted_8)) : createCommentVNode("", true)], 64);
938
+ }), 128))], 8, _hoisted_5$2)) : !el.action && el.link ? (openBlock(), createElementBlock("a", {
407
939
  key: 1,
408
940
  href: el.link,
409
941
  class: "action-set__actions-list-item"
410
- }, toDisplayString(el.label), 9, _hoisted_13)) : (openBlock(), createElementBlock("button", {
942
+ }, toDisplayString(el.label), 9, _hoisted_9)) : (openBlock(), createElementBlock("button", {
411
943
  key: 2,
412
944
  type: "button",
413
945
  class: "action-set__actions-list-item",
414
946
  disabled: el.disabled,
415
947
  onClick: ($event) => onActionClick(el.label, el.action)
416
- }, toDisplayString(el.label), 9, _hoisted_14))], 64);
417
- }), 128)), __props.elements.length === 0 ? (openBlock(), createElementBlock("p", _hoisted_15, "No actions available")) : createCommentVNode("", true)])) : activeSlot.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [activeSlot.value.component ? (openBlock(), createBlock(resolveDynamicComponent(activeSlot.value.component), { key: activeSlot.value.id })) : (openBlock(), createElementBlock("p", _hoisted_16, "No content"))], 64)) : createCommentVNode("", true)])], 544)) : createCommentVNode("", true)], 2);
948
+ }, toDisplayString(el.label), 9, _hoisted_10))], 64);
949
+ }), 128)), __props.elements.length === 0 ? (openBlock(), createElementBlock("p", _hoisted_11, "No actions available")) : createCommentVNode("", true)])) : activeSlot.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [activeSlot.value.component ? (openBlock(), createBlock(resolveDynamicComponent(activeSlot.value.component), { key: activeSlot.value.id })) : (openBlock(), createElementBlock("p", _hoisted_12, "No content"))], 64)) : createCommentVNode("", true)])], 544)) : createCommentVNode("", true), createElementVNode("div", {
950
+ ref_key: "tileRail",
951
+ ref: tileRail,
952
+ class: normalizeClass(["action-set__rail", {
953
+ "action-set__rail--drawer-open": drawerOpen.value,
954
+ "action-set__rail--layout-ready": railLayoutReady.value
955
+ }]),
956
+ style: normalizeStyle(tileRailStyle.value),
957
+ "aria-hidden": !railLayoutReady.value
958
+ }, [createElementVNode("button", {
959
+ ref_key: "dragHandle",
960
+ ref: dragHandle,
961
+ type: "button",
962
+ class: "action-set__drag-handle",
963
+ "aria-label": "Drag action set vertically",
964
+ title: "Drag vertically"
965
+ }, null, 512), createElementVNode("div", _hoisted_14, [createElementVNode("button", {
966
+ type: "button",
967
+ class: normalizeClass(["action-set__toggle", { "action-set__toggle--expanded": isExpanded.value }]),
968
+ "aria-label": "Toggle menu",
969
+ "aria-expanded": isExpanded.value,
970
+ onClick: onToggle
971
+ }, " + ", 10, _hoisted_15), isExpanded.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(allTabs.value, (tab) => {
972
+ return openBlock(), createElementBlock("button", {
973
+ key: tab.id,
974
+ type: "button",
975
+ class: normalizeClass(["action-set__item", { "action-set__item--active": drawerOpen.value && activeTabId.value === tab.id }]),
976
+ "aria-label": tab.label,
977
+ "aria-current": drawerOpen.value && activeTabId.value === tab.id ? "page" : void 0,
978
+ title: tab.label,
979
+ onClick: ($event) => onTileClick(tab.id)
980
+ }, [tab.icon ? (openBlock(), createBlock(resolveDynamicComponent(tab.icon), {
981
+ key: 0,
982
+ class: "action-set__item-icon"
983
+ })) : (openBlock(), createElementBlock("span", _hoisted_17, toDisplayString(slotFallback(tab.label)), 1)), tabBadge(tab) > 0 ? (openBlock(), createElementBlock("span", _hoisted_18, toDisplayString(tabBadge(tab)), 1)) : createCommentVNode("", true)], 10, _hoisted_16);
984
+ }), 128)) : createCommentVNode("", true)])], 14, _hoisted_13)]);
418
985
  };
419
986
  }
420
- });
421
- //#endregion
422
- //#region \0plugin-vue:export-helper
423
- var _plugin_vue_export_helper_default = (sfc, props) => {
424
- const target = sfc.__vccOpts || sfc;
425
- for (const [key, val] of props) target[key] = val;
426
- return target;
427
- };
428
- //#endregion
429
- //#region src/components/ActionSet.vue
430
- var ActionSet_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ActionSet_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-40295597"]]);
987
+ }), [["__scopeId", "data-v-8ca97265"]]);
431
988
  //#endregion
432
989
  //#region src/sheet-nav-toolbar.ts
433
990
  /** The id of the element SheetNav renders for footer controls, left of its tabs. */
@@ -515,15 +1072,24 @@ var actionSetKey = Symbol("actionSet");
515
1072
  function createActionSet(options) {
516
1073
  const activeSlotId = ref(null);
517
1074
  const actionsOpen = ref(false);
1075
+ const searchOpen = ref(false);
518
1076
  const previewSubject = shallowRef(null);
519
1077
  const previewId = ref(void 0);
520
1078
  function openActions() {
521
1079
  activeSlotId.value = null;
1080
+ searchOpen.value = false;
522
1081
  closePreview();
523
1082
  actionsOpen.value = true;
524
1083
  }
1084
+ function openSearch() {
1085
+ activeSlotId.value = null;
1086
+ actionsOpen.value = false;
1087
+ closePreview();
1088
+ searchOpen.value = true;
1089
+ }
525
1090
  function openSlot(slotId) {
526
1091
  actionsOpen.value = false;
1092
+ searchOpen.value = false;
527
1093
  if (activeSlotId.value === slotId) return;
528
1094
  activeSlotId.value = slotId;
529
1095
  closePreview();
@@ -543,6 +1109,7 @@ function createActionSet(options) {
543
1109
  function close() {
544
1110
  activeSlotId.value = null;
545
1111
  actionsOpen.value = false;
1112
+ searchOpen.value = false;
546
1113
  closePreview();
547
1114
  }
548
1115
  return {
@@ -552,11 +1119,13 @@ function createActionSet(options) {
552
1119
  previewSubject: computed(() => previewSubject.value),
553
1120
  isPreviewOpen: computed(() => previewSubject.value !== null),
554
1121
  isActionsOpen: computed(() => actionsOpen.value),
555
- isDrawerOpen: computed(() => actionsOpen.value || activeSlotId.value !== null),
1122
+ isSearchOpen: computed(() => searchOpen.value),
1123
+ isDrawerOpen: computed(() => actionsOpen.value || searchOpen.value || activeSlotId.value !== null),
556
1124
  present,
557
1125
  closePreview,
558
1126
  close,
559
1127
  openActions,
1128
+ openSearch,
560
1129
  openSlot
561
1130
  };
562
1131
  }
@@ -591,7 +1160,10 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
591
1160
  availableDoctypes: { default: () => [] },
592
1161
  routeAdapter: {},
593
1162
  actionSetSlots: {},
594
- hostActions: {}
1163
+ hostActions: {},
1164
+ breadcrumbs: {},
1165
+ commandSearch: { type: Function },
1166
+ commandSearchPlaceholder: { default: "Type a command or search..." }
595
1167
  },
596
1168
  emits: [
597
1169
  "action",
@@ -611,7 +1183,6 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
611
1183
  }
612
1184
  const fieldErrors = computed(() => currentView.value === "record" ? validationStore?.errorsByField ?? {} : {});
613
1185
  const loading = ref(false);
614
- const commandPaletteOpen = ref(false);
615
1186
  const draftRecord = ref({});
616
1187
  const currentViewData = computed({
617
1188
  get() {
@@ -827,15 +1398,23 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
827
1398
  }
828
1399
  return breadcrumbs;
829
1400
  });
1401
+ const sheetBreadcrumbs = computed(() => __props.breadcrumbs ?? navigationBreadcrumbs.value);
1402
+ const resolvedCommandSearch = (query) => {
1403
+ if (__props.commandSearch) return __props.commandSearch(query);
1404
+ return searchCommands(query);
1405
+ };
830
1406
  const searchCommands = (query) => {
831
1407
  const commands = [{
832
1408
  title: "Go Home",
833
1409
  description: "Navigate to the home page",
834
1410
  action: () => void doNavigate({ view: "doctypes" })
835
1411
  }, {
836
- title: "Toggle Command Palette",
837
- description: "Open/close the command palette",
838
- action: () => commandPaletteOpen.value = !commandPaletteOpen.value
1412
+ title: "Toggle Search",
1413
+ description: "Open/close the search panel",
1414
+ action: () => {
1415
+ if (actionSetController.isSearchOpen.value) actionSetController.close();
1416
+ else actionSetController.openSearch();
1417
+ }
839
1418
  }];
840
1419
  if (routeDoctype.value) {
841
1420
  commands.push({
@@ -867,7 +1446,10 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
867
1446
  };
868
1447
  const executeCommand = (command) => {
869
1448
  command.action();
870
- commandPaletteOpen.value = false;
1449
+ actionSetController.close();
1450
+ };
1451
+ const onSearchSelect = (result) => {
1452
+ executeCommand(result);
871
1453
  };
872
1454
  const listRecordsFetcher = (options) => {
873
1455
  if (!stonecrop.value || !currentDoctype.value) return Promise.resolve({
@@ -1146,13 +1728,9 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
1146
1728
  const handleKeydown = (event) => {
1147
1729
  if ((event.ctrlKey || event.metaKey) && event.key === "k") {
1148
1730
  event.preventDefault();
1149
- commandPaletteOpen.value = true;
1731
+ actionSetController.openSearch();
1150
1732
  }
1151
1733
  if (event.key === "Escape") {
1152
- if (commandPaletteOpen.value) {
1153
- commandPaletteOpen.value = false;
1154
- return;
1155
- }
1156
1734
  if (actionSetController.isPreviewOpen.value) {
1157
1735
  actionSetController.closePreview();
1158
1736
  return;
@@ -1202,7 +1780,7 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
1202
1780
  "data",
1203
1781
  "schema",
1204
1782
  "errors"
1205
- ])) : !unref(stonecrop) ? (openBlock(), createElementBlock("div", _hoisted_3, [..._cache[3] || (_cache[3] = [createElementVNode("p", null, "Initializing Stonecrop...", -1)])])) : (openBlock(), createElementBlock("div", _hoisted_4, [createElementVNode("p", null, "Loading " + toDisplayString(currentView.value) + " data...", 1)]))]), actionSetPreviewSubject.value ? (openBlock(), createElementBlock("aside", _hoisted_5, [createElementVNode("header", { class: "desktop__preview-header" }, [createElementVNode("button", {
1783
+ ])) : !unref(stonecrop) ? (openBlock(), createElementBlock("div", _hoisted_3, [..._cache[1] || (_cache[1] = [createElementVNode("p", null, "Initializing Stonecrop...", -1)])])) : (openBlock(), createElementBlock("div", _hoisted_4, [createElementVNode("p", null, "Loading " + toDisplayString(currentView.value) + " data...", 1)]))]), actionSetPreviewSubject.value ? (openBlock(), createElementBlock("aside", _hoisted_5, [createElementVNode("header", { class: "desktop__preview-header" }, [createElementVNode("button", {
1206
1784
  type: "button",
1207
1785
  class: "desktop__preview-close",
1208
1786
  "aria-label": "Close preview",
@@ -1212,35 +1790,31 @@ var Desktop_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
1212
1790
  slots: visibleActionSetSlots.value,
1213
1791
  elements: actionElements.value,
1214
1792
  controller: unref(actionSetController),
1793
+ search: resolvedCommandSearch,
1794
+ "search-placeholder": __props.commandSearchPlaceholder,
1215
1795
  onActionClick: handleActionClick,
1216
- onSearch: _cache[1] || (_cache[1] = ($event) => commandPaletteOpen.value = true)
1217
- }, null, 8, [
1796
+ onSearchSelect
1797
+ }, {
1798
+ "search-title": withCtx(({ result }) => [createTextVNode(toDisplayString(result.title), 1)]),
1799
+ "search-content": withCtx(({ result }) => [createTextVNode(toDisplayString(result.description), 1)]),
1800
+ _: 1
1801
+ }, 8, [
1218
1802
  "slots",
1219
1803
  "elements",
1220
- "controller"
1804
+ "controller",
1805
+ "search-placeholder"
1221
1806
  ]),
1222
1807
  createVNode(SheetNav_default, {
1223
1808
  class: "desktop__sheetnav",
1224
- breadcrumbs: navigationBreadcrumbs.value
1809
+ breadcrumbs: sheetBreadcrumbs.value
1225
1810
  }, {
1226
1811
  toolbar: withCtx(() => [renderSlot(_ctx.$slots, "sheetnav-toolbar", {}, void 0, true)]),
1227
1812
  _: 3
1228
- }, 8, ["breadcrumbs"]),
1229
- createVNode(CommandPalette_default, {
1230
- "is-open": commandPaletteOpen.value,
1231
- search: searchCommands,
1232
- placeholder: "Type a command or search...",
1233
- onSelect: executeCommand,
1234
- onClose: _cache[2] || (_cache[2] = ($event) => commandPaletteOpen.value = false)
1235
- }, {
1236
- title: withCtx(({ result }) => [createTextVNode(toDisplayString(result.title), 1)]),
1237
- content: withCtx(({ result }) => [createTextVNode(toDisplayString(result.description), 1)]),
1238
- _: 1
1239
- }, 8, ["is-open"])
1813
+ }, 8, ["breadcrumbs"])
1240
1814
  ], 2);
1241
1815
  };
1242
1816
  }
1243
- }), [["__scopeId", "data-v-378bae6b"]]);
1817
+ }), [["__scopeId", "data-v-9ccbbb36"]]);
1244
1818
  //#endregion
1245
1819
  //#region src/plugins/index.ts
1246
1820
  /**