@stonecrop/desktop 0.31.0 → 0.33.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,835 +1,952 @@
1
- import { defineComponent as q, ref as _, onMounted as le, openBlock as h, createElementBlock as g, normalizeClass as O, createElementVNode as i, Fragment as H, renderList as U, toDisplayString as N, createCommentVNode as P, withDirectives as z, vShow as Y, useTemplateRef as se, computed as R, watch as K, nextTick as ce, createBlock as ie, Teleport as _e, createVNode as B, Transition as xe, withCtx as j, withModifiers as ue, vModelText as de, renderSlot as G, createTextVNode as W, resolveComponent as Ne, withKeys as F, normalizeStyle as J, unref as Q, provide as X, onUnmounted as Me } from "vue";
2
- import { useStonecrop as Te, useValidationStore as Ve, isDraftRecordId as Ee, DRAFT_RECORD_ID as Oe } from "@stonecrop/stonecrop";
3
- import { AForm as Be, resolvedFieldsToColumns as Fe } from "@stonecrop/aform";
4
- const Pe = { class: "action-menu-icon" }, Ke = { class: "action-element-header" }, je = ["disabled", "onClick"], Le = { key: 0 }, He = { class: "dropdown-header" }, Ue = ["onClick"], ze = ["onClick"], We = { class: "dropdown-container" }, qe = { class: "dropdown" }, Ge = ["onClick"], Je = ["href"], Qe = { class: "dropdown-item" }, Xe = /* @__PURE__ */ q({
5
- __name: "ActionSet",
6
- props: {
7
- elements: { default: () => [] }
8
- },
9
- emits: ["actionClick"],
10
- setup(c, { emit: A }) {
11
- const y = A, a = _({}), u = _(!0), x = _([]);
12
- le(() => {
13
- w();
14
- });
15
- const w = () => {
16
- a.value = {}, x.value = [];
17
- }, b = () => {
18
- u.value = !u.value;
19
- }, S = (v) => {
20
- const r = !a.value[v];
21
- w(), r && (a.value[v] = !0, x.value[v] = !0);
22
- }, D = (v, r) => {
23
- y("actionClick", r, v);
24
- };
25
- return (v, r) => (h(), g("div", {
26
- class: O([{ collapsed: !u.value }, "action-set"])
27
- }, [
28
- i("div", Pe, [
29
- i("div", {
30
- id: "cross",
31
- class: O({ rotated: u.value }),
32
- onClick: b
33
- }, "×", 2)
34
- ]),
35
- r[0] || (r[0] = i("div", { style: { "margin-right": "30px" } }, null, -1)),
36
- (h(!0), g(H, null, U(c.elements, (s, o) => (h(), g("div", {
37
- key: s.label,
38
- class: "action-element"
39
- }, [
40
- i("div", Ke, [
41
- s.type == "button" ? (h(), g("button", {
42
- key: 0,
43
- disabled: s.disabled,
44
- class: "button-default",
45
- onClick: (n) => D(s.action, s.label)
46
- }, N(s.label), 9, je)) : P("", !0)
47
- ]),
48
- s.type == "dropdown" ? (h(), g("div", Le, [
49
- i("div", He, [
50
- i("div", {
51
- class: O(["cross", { rotated: x.value[o] }]),
52
- onClick: (n) => S(o)
53
- }, "×", 10, Ue),
54
- i("button", {
55
- class: "button-default dropdown-title",
56
- onClick: (n) => S(o)
57
- }, N(s.label), 9, ze)
58
- ]),
59
- z(i("div", We, [
60
- i("div", qe, [
61
- (h(!0), g(H, null, U(s.actions, (n) => (h(), g("div", {
62
- key: n.label
63
- }, [
64
- n.action != null ? (h(), g("button", {
65
- key: 0,
66
- class: "dropdown-item",
67
- onClick: (m) => D(n.action, n.label)
68
- }, N(n.label), 9, Ge)) : n.link != null ? (h(), g("a", {
69
- key: 1,
70
- href: n.link
71
- }, [
72
- i("button", Qe, N(n.label), 1)
73
- ], 8, Je)) : P("", !0)
74
- ]))), 128))
75
- ])
76
- ], 512), [
77
- [Y, a.value[o]]
78
- ])
79
- ])) : P("", !0)
80
- ]))), 128))
81
- ], 2));
82
- }
83
- }), ve = (c, A) => {
84
- const y = c.__vccOpts || c;
85
- for (const [a, u] of A)
86
- y[a] = u;
87
- return y;
88
- }, pe = /* @__PURE__ */ ve(Xe, [["__scopeId", "data-v-8e18f635"]]), Ye = { class: "command-palette-header" }, Ze = ["placeholder"], et = {
89
- key: 0,
90
- class: "command-palette-results"
91
- }, tt = ["onClick", "onMouseover"], at = { class: "result-title" }, ot = { class: "result-content" }, rt = {
92
- key: 1,
93
- class: "command-palette-no-results"
94
- }, fe = /* @__PURE__ */ q({
95
- __name: "CommandPalette",
96
- props: {
97
- search: { type: Function },
98
- isOpen: { type: Boolean, default: !1 },
99
- placeholder: { default: "Type a command or search..." },
100
- maxResults: { default: 10 }
101
- },
102
- emits: ["select", "close"],
103
- setup(c, { emit: A }) {
104
- const y = A, a = _(""), u = _(0), x = se("input"), w = R(() => a.value ? c.search(a.value).slice(0, c.maxResults) : []);
105
- K(
106
- () => c.isOpen,
107
- async (v) => {
108
- v && (a.value = "", u.value = 0, await ce(), x.value?.focus());
109
- }
110
- ), K(w, () => {
111
- u.value = 0;
112
- });
113
- const b = () => {
114
- y("close");
115
- }, S = (v) => {
116
- switch (v.key) {
117
- case "Escape":
118
- b();
119
- break;
120
- case "ArrowDown":
121
- v.preventDefault(), w.value.length && (u.value = (u.value + 1) % w.value.length);
122
- break;
123
- case "ArrowUp":
124
- v.preventDefault(), w.value.length && (u.value = (u.value - 1 + w.value.length) % w.value.length);
125
- break;
126
- case "Enter":
127
- w.value.length && u.value >= 0 && D(w.value[u.value]);
128
- break;
129
- }
130
- }, D = (v) => {
131
- y("select", v), b();
132
- };
133
- return (v, r) => (h(), ie(_e, { to: "body" }, [
134
- B(xe, { name: "fade" }, {
135
- default: j(() => [
136
- c.isOpen ? (h(), g("div", {
137
- key: 0,
138
- class: "command-palette-overlay",
139
- onClick: b
140
- }, [
141
- i("div", {
142
- class: "command-palette",
143
- onClick: r[1] || (r[1] = ue(() => {
144
- }, ["stop"]))
145
- }, [
146
- i("div", Ye, [
147
- z(i("input", {
148
- ref: "input",
149
- "onUpdate:modelValue": r[0] || (r[0] = (s) => a.value = s),
150
- type: "text",
151
- class: "command-palette-input",
152
- placeholder: c.placeholder,
153
- autofocus: "",
154
- onKeydown: S
155
- }, null, 40, Ze), [
156
- [de, a.value]
157
- ])
158
- ]),
159
- w.value.length ? (h(), g("div", et, [
160
- (h(!0), g(H, null, U(w.value, (s, o) => (h(), g("div", {
161
- key: o,
162
- class: O(["command-palette-result", { selected: o === u.value }]),
163
- onClick: (n) => D(s),
164
- onMouseover: (n) => u.value = o
165
- }, [
166
- i("div", at, [
167
- G(v.$slots, "title", { result: s })
168
- ]),
169
- i("div", ot, [
170
- G(v.$slots, "content", { result: s })
171
- ])
172
- ], 42, tt))), 128))
173
- ])) : a.value && !w.value.length ? (h(), g("div", rt, [
174
- G(v.$slots, "empty", {}, () => [
175
- W(' No results found for "' + N(a.value) + '" ', 1)
176
- ])
177
- ])) : P("", !0)
178
- ])
179
- ])) : P("", !0)
180
- ]),
181
- _: 3
182
- })
183
- ]));
184
- }
185
- }), nt = { class: "tabs" }, lt = { tabindex: "0" }, st = { tabindex: "0" }, ct = /* @__PURE__ */ q({
186
- __name: "SheetNav",
187
- props: {
188
- breadcrumbs: { default: () => [] }
189
- },
190
- setup(c) {
191
- const A = _(!0), y = _(!1), a = _(""), u = se("searchinput"), x = R(() => A.value ? "unrotated" : "rotated"), w = () => {
192
- A.value = !A.value;
193
- }, b = async () => {
194
- y.value = !y.value, await ce(() => {
195
- u.value?.focus();
196
- });
197
- }, S = (r) => {
198
- r.preventDefault(), r.stopPropagation();
199
- }, D = async (r) => {
200
- r.preventDefault(), r.stopPropagation(), await b();
201
- }, v = () => {
202
- };
203
- return (r, s) => {
204
- const o = Ne("router-link");
205
- return h(), g("footer", null, [
206
- i("ul", nt, [
207
- i("li", {
208
- class: "hidebreadcrumbs",
209
- onClick: w,
210
- onKeydown: F(w, ["enter"])
211
- }, [
212
- i("a", lt, [
213
- i("div", {
214
- class: O(x.value)
215
- }, "×", 2)
216
- ])
217
- ], 32),
218
- i("li", {
219
- class: "hometab",
220
- style: J({ display: A.value ? "block" : "none" }),
221
- onClick: v,
222
- onKeydown: F(v, ["enter"])
223
- }, [
224
- B(o, {
225
- to: "/",
226
- tabindex: "0"
227
- }, {
228
- default: j(() => [...s[5] || (s[5] = [
229
- i("svg", {
230
- class: "icon",
231
- "aria-label": "Home",
232
- viewBox: "0 0 24 24",
233
- fill: "none",
234
- stroke: "currentColor",
235
- "stroke-width": "2"
236
- }, [
237
- i("path", { d: "M3 12l9-9 9 9" }),
238
- i("path", { d: "M9 21V12h6v9" })
239
- ], -1)
240
- ])]),
241
- _: 1
242
- })
243
- ], 36),
244
- i("li", {
245
- class: O(["searchtab", { "search-active": y.value }]),
246
- style: J({ display: A.value ? "block" : "none" })
247
- }, [
248
- i("a", st, [
249
- z((h(), g("svg", {
250
- class: "icon search-icon",
251
- role: "button",
252
- "aria-label": "Search",
253
- viewBox: "0 0 24 24",
254
- fill: "none",
255
- stroke: "currentColor",
256
- "stroke-width": "2",
257
- onClick: b,
258
- onKeydown: F(b, ["enter"])
259
- }, [...s[6] || (s[6] = [
260
- i("circle", {
261
- cx: "11",
262
- cy: "11",
263
- r: "7"
264
- }, null, -1),
265
- i("path", { d: "M21 21l-4.35-4.35" }, null, -1)
266
- ])], 544)), [
267
- [Y, !y.value]
268
- ]),
269
- z(i("input", {
270
- ref: "searchinput",
271
- "onUpdate:modelValue": s[0] || (s[0] = (n) => a.value = n),
272
- type: "text",
273
- placeholder: "Search...",
274
- onClick: s[1] || (s[1] = ue(() => {
275
- }, ["stop"])),
276
- onInput: s[2] || (s[2] = (n) => S(n)),
277
- onBlur: s[3] || (s[3] = (n) => D(n)),
278
- onKeydown: [
279
- s[4] || (s[4] = F((n) => D(n), ["enter"])),
280
- F(b, ["escape"])
281
- ]
282
- }, null, 544), [
283
- [Y, y.value],
284
- [de, a.value]
285
- ])
286
- ])
287
- ], 6),
288
- (h(!0), g(H, null, U(c.breadcrumbs, (n) => (h(), g("li", {
289
- key: n.title,
290
- style: J({ display: A.value ? "block" : "none" })
291
- }, [
292
- B(o, {
293
- tabindex: "0",
294
- to: n.to
295
- }, {
296
- default: j(() => [
297
- W(N(n.title), 1)
298
- ]),
299
- _: 2
300
- }, 1032, ["to"])
301
- ], 4))), 128))
302
- ])
303
- ]);
304
- };
305
- }
306
- }), me = /* @__PURE__ */ ve(ct, [["__scopeId", "data-v-cd118b06"]]), it = {
307
- key: 1,
308
- class: "loading"
309
- }, ut = {
310
- key: 2,
311
- class: "loading"
312
- }, dt = /* @__PURE__ */ q({
313
- __name: "Desktop",
314
- props: {
315
- availableDoctypes: { default: () => [] },
316
- routeAdapter: {}
317
- },
318
- emits: ["action", "navigate", "record:open", "load-records", "load-record"],
319
- setup(c, { emit: A }) {
320
- const y = A, { stonecrop: a } = Te();
321
- let u = null;
322
- try {
323
- u = Ve();
324
- } catch {
325
- u = null;
326
- }
327
- const x = R(
328
- () => I.value === "record" ? u?.errorsByField ?? {} : {}
329
- ), w = _(!1), b = _(!1), S = _({}), D = R({
330
- get() {
331
- if (I.value === "doctypes")
332
- return {
333
- doctypes_table: c.availableDoctypes?.map((e) => ({
334
- id: e,
335
- doctype: e,
336
- display_name: E(e),
337
- actions: "View Records"
338
- })) ?? []
339
- };
340
- if (I.value === "records")
341
- return {
342
- records_table: ae().map(
343
- (e) => Object.assign({}, e, {
344
- id: re(e) ?? "",
345
- // A list row is navigation. Actions live on the record view, where the Actions
346
- // dropdown is built from what the doctype declares and what the record's
347
- // current state allows. This cell used to also offer Delete, which dispatched
348
- // an action named `DELETE` that Desktop invented — no doctype in a
349
- // WorkflowMeta app declares it, so it failed on every click. Removal is a
350
- // workflow outcome (`archive`, `cancel`) and belongs in the doctype.
351
- actions: "Edit"
352
- })
353
- )
354
- };
355
- if (!a.value || !o.value || !m.value)
356
- return {};
357
- try {
358
- const t = { ...V.value ? S.value : a.value.getRecordById(o.value, m.value)?.get("") }, l = a.value.registry.registry[o.value];
359
- if (l) {
360
- for (const d of l.getSchemaArray())
361
- if (d.kind === "fieldset") {
362
- const p = {};
363
- for (const k of d.schema)
364
- k.fieldname && (p[k.fieldname] = t[k.fieldname]);
365
- t[d.fieldname] = p;
366
- }
367
- }
368
- return t;
369
- } catch {
370
- return {};
371
- }
372
- },
373
- set(e) {
374
- if (I.value === "record" && !(!a.value || !o.value || !m.value))
375
- try {
376
- const t = a.value.registry.registry[o.value], l = /* @__PURE__ */ new Set();
377
- if (t)
378
- for (const f of t.getSchemaArray())
379
- f.kind === "fieldset" && l.add(f.fieldname);
380
- const d = {}, p = [];
381
- for (const [f, C] of Object.entries(e))
382
- l.has(f) && C && typeof C == "object" && !Array.isArray(C) ? p.push(C) : d[f] = C;
383
- for (const f of p)
384
- Object.assign(d, f);
385
- const k = [];
386
- if (V.value) {
387
- const f = { ...S.value };
388
- for (const [C, $] of Object.entries(d))
389
- $ !== void 0 && f[C] !== $ && (f[C] = $, k.push(C));
390
- S.value = f;
391
- } else {
392
- const f = a.value.getStore();
393
- for (const [C, $] of Object.entries(d)) {
394
- if ($ === void 0) continue;
395
- const T = `${o.value}.${m.value}.${C}`;
396
- (f.has(T) ? f.get(T) : void 0) !== $ && (f.set(T, $), k.push(C));
397
- }
398
- }
399
- k.length > 0 && v(k);
400
- } catch (t) {
401
- console.warn("HST update failed:", t);
402
- }
403
- }
404
- });
405
- function v(e) {
406
- if (!u || !a.value || !o.value || !m.value) return;
407
- const l = a.value.registry.getDoctype(o.value)?.getTriggers();
408
- if (!l || Object.keys(l).length === 0) return;
409
- const d = V.value ? { ...S.value } : {
410
- ...a.value.getRecordById(o.value, m.value)?.get("")
411
- };
412
- for (const p of e)
413
- u.validateField(l, p, d);
414
- }
415
- const r = R(() => c.routeAdapter ? null : Q(a.value?.registry.router?.currentRoute)), s = R(() => c.routeAdapter ? null : a.value?.registry.router), o = R(() => {
416
- if (c.routeAdapter) return c.routeAdapter.getCurrentDoctype();
417
- if (!r.value) return "";
418
- if (r.value.meta?.actualDoctype)
419
- return r.value.meta.actualDoctype;
420
- if (r.value.params.doctype)
421
- return r.value.params.doctype.toString();
422
- const e = r.value.params.pathMatch;
423
- return e && e.length > 0 ? e[0] : "";
424
- }), n = R(() => {
425
- if (c.routeAdapter) return c.routeAdapter.getCurrentDoctype();
426
- if (!r.value) return "";
427
- if (r.value.meta?.doctype)
428
- return r.value.meta.doctype;
429
- if (r.value.params.doctype)
430
- return r.value.params.doctype.toString();
431
- const e = r.value.params.pathMatch;
432
- return e && e.length > 0 ? e[0] : "";
433
- }), m = R(() => {
434
- if (c.routeAdapter) return c.routeAdapter.getCurrentRecordId();
435
- if (!r.value) return "";
436
- if (r.value.params.recordId)
437
- return r.value.params.recordId.toString();
438
- const e = r.value.params.pathMatch;
439
- return e && e.length > 1 ? e[1] : "";
440
- }), V = R(() => Ee(m.value)), I = R(() => {
441
- if (c.routeAdapter) return c.routeAdapter.getCurrentView();
442
- if (!r.value || r.value.name === "home" || r.value.path === "/")
443
- return "doctypes";
444
- if (r.value.name && r.value.name !== "catch-all") {
445
- const t = r.value.name;
446
- if (t.includes("form") || r.value.params.recordId)
447
- return "record";
448
- if (t.includes("list") || r.value.params.doctype)
449
- return "records";
450
- }
451
- const e = r.value.params.pathMatch;
452
- return e && e.length > 0 ? e.length === 1 ? "records" : "record" : "doctypes";
453
- }), he = () => {
454
- if (!a.value || !o.value || !m.value)
455
- return [];
456
- try {
457
- const e = a.value.registry.getDoctype(o.value);
458
- if (!e?.workflow) return [];
459
- const t = a.value.getRecordState(o.value, m.value), l = e.getAvailableTransitions(t), d = D.value || {};
460
- return l.map(({ name: p }) => ({
461
- // Prefer the workflow action's human-readable label (WorkflowMeta format);
462
- // fall back to the raw transition name for XState workflows with no action meta.
463
- label: e.getActionMeta(p)?.label ?? p,
464
- action: () => {
465
- y("action", {
466
- name: p,
467
- doctype: o.value,
468
- recordId: m.value,
469
- data: d
470
- });
471
- }
472
- }));
473
- } catch (e) {
474
- return console.warn("Error getting available transitions:", e), [];
475
- }
476
- }, ye = () => {
477
- if (!a.value || !o.value || !m.value)
478
- return [];
479
- try {
480
- const e = a.value.registry.getDoctype(o.value);
481
- if (!e?.workflow) return [];
482
- const t = a.value.getRecordState(o.value, m.value), l = e.getAvailableCommands(t), d = D.value || {};
483
- return l.map(({ name: p }) => ({
484
- label: e.getActionMeta(p)?.label ?? p,
485
- action: () => {
486
- y("action", {
487
- name: p,
488
- doctype: o.value,
489
- recordId: m.value,
490
- data: d
491
- });
492
- }
493
- }));
494
- } catch (e) {
495
- return console.warn("Error getting available commands:", e), [];
496
- }
497
- }, ge = R(() => {
498
- const e = [];
499
- switch (I.value) {
500
- case "records":
501
- e.push({
502
- type: "button",
503
- label: "New Record",
504
- action: () => {
505
- L();
506
- }
507
- });
508
- break;
509
- case "record": {
510
- const t = [...he(), ...ye()];
511
- t.length > 0 && e.push({
512
- type: "dropdown",
513
- label: "Actions",
514
- actions: t
515
- });
516
- break;
517
- }
518
- }
519
- return e;
520
- }), we = R(() => {
521
- const e = [];
522
- if (I.value === "records" && n.value)
523
- e.push(
524
- { title: "Home", to: "/" },
525
- { title: E(n.value), to: `/${n.value}` }
526
- );
527
- else if (I.value === "record" && n.value) {
528
- const t = m.value ? `/${n.value}/${m.value}` : r.value?.fullPath ?? "";
529
- e.push(
530
- { title: "Home", to: "/" },
531
- { title: E(n.value), to: `/${n.value}` },
532
- { title: V.value ? "New Record" : "Edit Record", to: t }
533
- );
534
- }
535
- return e;
536
- }), be = (e) => {
537
- const t = [
538
- {
539
- title: "Go Home",
540
- description: "Navigate to the home page",
541
- action: () => {
542
- M({ view: "doctypes" });
543
- }
544
- },
545
- {
546
- title: "Toggle Command Palette",
547
- description: "Open/close the command palette",
548
- action: () => b.value = !b.value
549
- }
550
- ];
551
- return n.value && (t.push({
552
- title: `View ${E(n.value)} Records`,
553
- description: `Navigate to ${n.value} list`,
554
- action: () => {
555
- M({ view: "records", doctype: n.value });
556
- }
557
- }), t.push({
558
- title: `Create New ${E(n.value)}`,
559
- description: `Create a new ${n.value} record`,
560
- action: () => {
561
- L();
562
- }
563
- })), c.availableDoctypes.forEach((l) => {
564
- t.push({
565
- title: `View ${E(l)}`,
566
- description: `Navigate to ${l} list`,
567
- action: () => {
568
- M({ view: "records", doctype: l });
569
- }
570
- });
571
- }), e ? t.filter(
572
- (l) => l.title.toLowerCase().includes(e.toLowerCase()) || l.description.toLowerCase().includes(e.toLowerCase())
573
- ) : t;
574
- }, ke = (e) => {
575
- e.action(), b.value = !1;
576
- }, Ce = (e) => {
577
- if (!a.value || !o.value)
578
- return Promise.resolve({ data: [], hasMore: !1 });
579
- const t = a.value.registry.getDoctype(o.value);
580
- return t ? a.value.getRecords(t, e) : Promise.resolve({ data: [], hasMore: !1 });
581
- }, E = (e) => e.split("-").map((t) => t.charAt(0).toUpperCase() + t.slice(1)).join(" "), M = async (e) => {
582
- y("navigate", e), c.routeAdapter ? await c.routeAdapter.navigate(e) : e.view === "doctypes" ? await s.value?.push("/") : e.view === "records" && e.doctype ? await s.value?.push(`/${e.doctype}`) : e.view === "record" && e.doctype && e.recordId && await s.value?.push(`/${e.doctype}/${e.recordId}`);
583
- }, Z = async (e) => {
584
- await M({ view: "records", doctype: e });
585
- }, ee = async (e) => {
586
- const t = n.value;
587
- y("record:open", { doctype: t, recordId: e }), await M({ view: "record", doctype: t, recordId: e });
588
- }, L = async () => {
589
- await M({ view: "record", doctype: n.value, recordId: Oe });
590
- }, Ae = () => c.availableDoctypes?.length ? [
591
- {
592
- kind: "table",
593
- fieldname: "doctypes_table",
594
- component: "ATable",
595
- label: "Doctypes",
596
- schema: [
597
- {
598
- fieldname: "doctype",
599
- label: "Doctype",
600
- component: "ATextInput",
601
- align: "left",
602
- edit: !1,
603
- width: "20ch"
604
- },
605
- {
606
- fieldname: "display_name",
607
- label: "Name",
608
- component: "ATextInput",
609
- align: "left",
610
- edit: !1,
611
- width: "30ch"
612
- },
613
- // No record count column. It read `getRecordIds(doctype).length`, which is how many
614
- // records HST happens to hold — zero for a doctype never opened, and the page size
615
- // for one that was. The real total belongs to the backend and Desktop never asks
616
- // for it, so this shell cannot answer it. Same reason the `recordIdField` prop went.
617
- {
618
- fieldname: "actions",
619
- label: "Actions",
620
- component: "ATextInput",
621
- align: "center",
622
- edit: !1,
623
- width: "20ch"
624
- }
625
- ],
626
- config: { view: "list", fullWidth: !0 }
627
- }
628
- ] : [], De = () => {
629
- if (!o.value) return [];
630
- if (!a.value) return [];
631
- const e = a.value.registry, t = e.registry[o.value];
632
- if (!t) return [];
633
- const l = e.resolveSchema(t);
634
- if (l.length === 0) return [];
635
- const d = o.value, p = !!a.value.getClient();
636
- return [
637
- {
638
- kind: "table",
639
- fieldname: "records_table",
640
- component: "ATable",
641
- // Which resolved fields a cell can render is answered once, in @stonecrop/aform, and
642
- // called by the child-table builder too. Flattening alone is not the rule: it kept the
643
- // expanding links, whose value is a nested record or an array of them.
644
- schema: [...Fe(l), { fieldname: "actions", label: "Actions", component: "ATextInput" }],
645
- config: { view: "list", fullWidth: !0 },
646
- ...p ? { getRecords: Ce, sourceKey: d } : {}
647
- }
648
- ];
649
- }, te = () => {
650
- if (!o.value) return [];
651
- if (!a.value) return [];
652
- try {
653
- const e = a.value?.registry, t = e?.registry[o.value];
654
- return t?.schema ? e.resolveSchema(t) : [];
655
- } catch {
656
- return [];
657
- }
658
- }, ae = () => {
659
- if (!a.value || !o.value)
660
- return [];
661
- const t = a.value.records(o.value)?.get("");
662
- return t && typeof t == "object" && !Array.isArray(t) ? Object.values(t) : [];
663
- }, oe = R(() => {
664
- switch (I.value) {
665
- case "doctypes":
666
- return Ae();
667
- case "records":
668
- return De();
669
- case "record":
670
- return te();
671
- default:
672
- return [];
673
- }
674
- }), Re = (e, t) => {
675
- t && t();
676
- }, re = (e) => {
677
- if (!(!a.value || !o.value))
678
- return a.value.registry.registry[o.value]?.getRecordId(e);
679
- }, Se = (e) => {
680
- const t = e.querySelector("td[data-rowindex]");
681
- if (!t) return null;
682
- const l = t.getAttribute("data-rowindex");
683
- if (l === null) return null;
684
- const d = parseInt(l, 10);
685
- if (isNaN(d)) return null;
686
- const k = ae()[d];
687
- return k ? re(k) ?? null : null;
688
- }, $e = async (e) => {
689
- const t = e.target;
690
- t.getAttribute("data-action") === "create" && await L();
691
- const d = t.closest("td, th");
692
- if (d) {
693
- const p = d.textContent?.trim(), k = d.closest("tr");
694
- if (p === "View Records" && k) {
695
- const f = k.querySelectorAll("td");
696
- if (f.length > 0) {
697
- const $ = f[1].textContent?.trim();
698
- $ && await Z($);
699
- }
700
- } else if (p === "Edit" && k) {
701
- const f = Se(k);
702
- f && await ee(f);
703
- }
704
- }
705
- }, Ie = async () => {
706
- if (!(!a.value || !o.value || !a.value.getClient())) {
707
- w.value = !0;
708
- try {
709
- await a.value.getRecord(o.value, m.value);
710
- } catch (e) {
711
- console.warn("Error fetching record:", e);
712
- } finally {
713
- w.value = !1;
714
- }
715
- }
716
- };
717
- K(
718
- [I, o, m],
719
- () => {
720
- if (I.value === "records" && o.value)
721
- y("load-records", { doctype: o.value });
722
- else if (I.value === "record" && o.value && m.value) {
723
- if (V.value) return;
724
- y("load-record", { doctype: o.value, recordId: m.value }), Ie();
725
- }
726
- },
727
- { immediate: !0 }
728
- ), K([o, m], () => {
729
- u?.clearAll();
730
- }), K(
731
- [o, m],
732
- () => {
733
- if (!V.value) {
734
- S.value = {};
735
- return;
736
- }
737
- const e = a.value?.registry;
738
- S.value = e ? e.initializeRecord(te()) : {};
739
- },
740
- { immediate: !0 }
741
- ), X("desktopMethods", {
742
- navigateToDoctype: Z,
743
- openRecord: ee,
744
- createNewRecord: L,
745
- /**
746
- * Convenience wrapper so child components (e.g. slot content) can emit
747
- * an action event without needing a direct reference to the emit function.
748
- */
749
- emitAction: (e, t) => {
750
- y("action", {
751
- name: e,
752
- doctype: o.value,
753
- recordId: m.value,
754
- data: t ?? D.value ?? {}
755
- });
756
- }
757
- }), X("aformLinkNavigator", {
758
- navigate: (e, t) => {
759
- M({ view: "record", doctype: e, recordId: String(t) });
760
- }
761
- }), X("aformLinkResolver", async (e, t) => {
762
- if (a.value)
763
- try {
764
- const d = (await a.value.getMeta({ path: `/${e}`, segments: [e] }))?.displayField;
765
- if (!d) return;
766
- const p = ($) => {
767
- if (!$) return;
768
- const T = $[d];
769
- return typeof T == "string" || typeof T == "number" ? String(T) : void 0;
770
- }, k = a.value.getRecordById(e, t)?.get(""), f = p(k);
771
- if (f != null) return f;
772
- await a.value.getRecord(e, t);
773
- const C = a.value.getRecordById(e, t)?.get("");
774
- return p(C);
775
- } catch {
776
- return;
777
- }
778
- });
779
- const ne = (e) => {
780
- (e.ctrlKey || e.metaKey) && e.key === "k" && (e.preventDefault(), b.value = !0), e.key === "Escape" && b.value && (b.value = !1);
781
- };
782
- return le(() => {
783
- document.addEventListener("keydown", ne);
784
- }), Me(() => {
785
- document.removeEventListener("keydown", ne);
786
- }), (e, t) => (h(), g("div", {
787
- class: "desktop",
788
- onClick: $e
789
- }, [
790
- B(pe, {
791
- elements: ge.value,
792
- onActionClick: Re
793
- }, null, 8, ["elements"]),
794
- oe.value.length > 0 ? (h(), ie(Q(Be), {
795
- key: 0,
796
- data: D.value,
797
- "onUpdate:data": t[0] || (t[0] = (l) => D.value = l),
798
- schema: oe.value,
799
- errors: x.value
800
- }, null, 8, ["data", "schema", "errors"])) : Q(a) ? (h(), g("div", ut, [
801
- i("p", null, "Loading " + N(I.value) + " data...", 1)
802
- ])) : (h(), g("div", it, [...t[2] || (t[2] = [
803
- i("p", null, "Initializing Stonecrop...", -1)
804
- ])])),
805
- B(me, { breadcrumbs: we.value }, null, 8, ["breadcrumbs"]),
806
- B(fe, {
807
- "is-open": b.value,
808
- search: be,
809
- placeholder: "Type a command or search...",
810
- onSelect: ke,
811
- onClose: t[1] || (t[1] = (l) => b.value = !1)
812
- }, {
813
- title: j(({ result: l }) => [
814
- W(N(l.title), 1)
815
- ]),
816
- content: j(({ result: l }) => [
817
- W(N(l.description), 1)
818
- ]),
819
- _: 1
820
- }, 8, ["is-open"])
821
- ]));
822
- }
823
- }), yt = {
824
- install: (c) => {
825
- c.component("ActionSet", pe), c.component("CommandPalette", fe), c.component("Desktop", dt), c.component("SheetNav", me);
826
- }
1
+ import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, resolveComponent, toDisplayString, unref, useTemplateRef, vModelText, vShow, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
2
+ import { DRAFT_RECORD_ID, isDraftRecordId, useStonecrop, useValidationStore } from "@stonecrop/stonecrop";
3
+ import { AForm, resolvedFieldsToColumns } from "@stonecrop/aform";
4
+ import './assets/index.css';//#region src/components/ActionSet.vue?vue&type=script&setup=true&lang.ts
5
+ var _hoisted_1$3 = { class: "action-menu-icon" };
6
+ var _hoisted_2$3 = { class: "action-element-header" };
7
+ var _hoisted_3$2 = ["disabled", "onClick"];
8
+ var _hoisted_4$2 = { key: 0 };
9
+ var _hoisted_5$2 = { class: "dropdown-header" };
10
+ var _hoisted_6$1 = ["onClick"];
11
+ var _hoisted_7$1 = ["onClick"];
12
+ var _hoisted_8 = { class: "dropdown-container" };
13
+ var _hoisted_9 = { class: "dropdown" };
14
+ var _hoisted_10 = ["onClick"];
15
+ var _hoisted_11 = ["href"];
16
+ var _hoisted_12 = { class: "dropdown-item" };
17
+ var ActionSet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
18
+ __name: "ActionSet",
19
+ props: { elements: { default: () => [] } },
20
+ emits: ["actionClick"],
21
+ setup(__props, { emit: __emit }) {
22
+ const emit = __emit;
23
+ const dropdownStates = ref({});
24
+ const isOpen = ref(true);
25
+ const dropdownOpen = ref([]);
26
+ onMounted(() => {
27
+ closeDropdowns();
28
+ });
29
+ const closeDropdowns = () => {
30
+ dropdownStates.value = {};
31
+ dropdownOpen.value = [];
32
+ };
33
+ const onClick = () => {
34
+ isOpen.value = !isOpen.value;
35
+ };
36
+ const toggleDropdown = (index) => {
37
+ const showDropdown = !dropdownStates.value[index];
38
+ closeDropdowns();
39
+ if (showDropdown) {
40
+ dropdownStates.value[index] = true;
41
+ dropdownOpen.value[index] = true;
42
+ }
43
+ };
44
+ const handleClick = (action, label) => {
45
+ emit("actionClick", label, action);
46
+ };
47
+ return (_ctx, _cache) => {
48
+ return openBlock(), createElementBlock("div", { class: normalizeClass([{ collapsed: !isOpen.value }, "action-set"]) }, [
49
+ createElementVNode("div", _hoisted_1$3, [createElementVNode("div", {
50
+ id: "cross",
51
+ class: normalizeClass({ rotated: isOpen.value }),
52
+ onClick
53
+ }, "×", 2)]),
54
+ _cache[0] || (_cache[0] = createElementVNode("div", { style: { "margin-right": "30px" } }, null, -1)),
55
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.elements, (el, index) => {
56
+ return openBlock(), createElementBlock("div", {
57
+ key: el.label,
58
+ class: "action-element"
59
+ }, [createElementVNode("div", _hoisted_2$3, [el.type == "button" ? (openBlock(), createElementBlock("button", {
60
+ key: 0,
61
+ disabled: el.disabled,
62
+ class: "button-default",
63
+ onClick: ($event) => handleClick(el.action, el.label)
64
+ }, toDisplayString(el.label), 9, _hoisted_3$2)) : createCommentVNode("", true)]), el.type == "dropdown" ? (openBlock(), createElementBlock("div", _hoisted_4$2, [createElementVNode("div", _hoisted_5$2, [createElementVNode("div", {
65
+ class: normalizeClass(["cross", { rotated: dropdownOpen.value[index] }]),
66
+ onClick: ($event) => toggleDropdown(index)
67
+ }, "×", 10, _hoisted_6$1), createElementVNode("button", {
68
+ class: "button-default dropdown-title",
69
+ onClick: ($event) => toggleDropdown(index)
70
+ }, toDisplayString(el.label), 9, _hoisted_7$1)]), withDirectives(createElementVNode("div", _hoisted_8, [createElementVNode("div", _hoisted_9, [(openBlock(true), createElementBlock(Fragment, null, renderList(el.actions, (item) => {
71
+ return openBlock(), createElementBlock("div", { key: item.label }, [item.action != null ? (openBlock(), createElementBlock("button", {
72
+ key: 0,
73
+ class: "dropdown-item",
74
+ onClick: ($event) => handleClick(item.action, item.label)
75
+ }, toDisplayString(item.label), 9, _hoisted_10)) : item.link != null ? (openBlock(), createElementBlock("a", {
76
+ key: 1,
77
+ href: item.link
78
+ }, [createElementVNode("button", _hoisted_12, toDisplayString(item.label), 1)], 8, _hoisted_11)) : createCommentVNode("", true)]);
79
+ }), 128))])], 512), [[vShow, dropdownStates.value[index]]])])) : createCommentVNode("", true)]);
80
+ }), 128))
81
+ ], 2);
82
+ };
83
+ }
84
+ });
85
+ //#endregion
86
+ //#region \0plugin-vue:export-helper
87
+ var _plugin_vue_export_helper_default = (sfc, props) => {
88
+ const target = sfc.__vccOpts || sfc;
89
+ for (const [key, val] of props) target[key] = val;
90
+ return target;
827
91
  };
828
- export {
829
- pe as ActionSet,
830
- fe as CommandPalette,
831
- dt as Desktop,
832
- me as SheetNav,
833
- yt as StonecropDesktop
92
+ //#endregion
93
+ //#region src/components/ActionSet.vue
94
+ var ActionSet_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ActionSet_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-8e18f635"]]);
95
+ //#endregion
96
+ //#region src/components/CommandPalette.vue?vue&type=script&setup=true&lang.ts
97
+ var _hoisted_1$2 = { class: "command-palette-header" };
98
+ var _hoisted_2$2 = ["placeholder"];
99
+ var _hoisted_3$1 = {
100
+ key: 0,
101
+ class: "command-palette-results"
834
102
  };
835
- //# sourceMappingURL=desktop.js.map
103
+ var _hoisted_4$1 = ["onClick", "onMouseover"];
104
+ var _hoisted_5$1 = { class: "result-title" };
105
+ var _hoisted_6 = { class: "result-content" };
106
+ var _hoisted_7 = {
107
+ key: 1,
108
+ class: "command-palette-no-results"
109
+ };
110
+ //#endregion
111
+ //#region src/components/CommandPalette.vue
112
+ var CommandPalette_default = /* @__PURE__ */ defineComponent({
113
+ __name: "CommandPalette",
114
+ props: {
115
+ search: { type: Function },
116
+ isOpen: {
117
+ type: Boolean,
118
+ default: false
119
+ },
120
+ placeholder: { default: "Type a command or search..." },
121
+ maxResults: { default: 10 }
122
+ },
123
+ emits: ["select", "close"],
124
+ setup(__props, { emit: __emit }) {
125
+ const emit = __emit;
126
+ const query = ref("");
127
+ const selectedIndex = ref(0);
128
+ const inputRef = useTemplateRef("input");
129
+ const results = computed(() => {
130
+ if (!query.value) return [];
131
+ return __props.search(query.value).slice(0, __props.maxResults);
132
+ });
133
+ watch(() => __props.isOpen, async (open) => {
134
+ if (open) {
135
+ query.value = "";
136
+ selectedIndex.value = 0;
137
+ await nextTick();
138
+ inputRef.value?.focus();
139
+ }
140
+ });
141
+ watch(results, () => {
142
+ selectedIndex.value = 0;
143
+ });
144
+ const closeModal = () => {
145
+ emit("close");
146
+ };
147
+ const handleKeydown = (e) => {
148
+ switch (e.key) {
149
+ case "Escape":
150
+ closeModal();
151
+ break;
152
+ case "ArrowDown":
153
+ e.preventDefault();
154
+ if (results.value.length) selectedIndex.value = (selectedIndex.value + 1) % results.value.length;
155
+ break;
156
+ case "ArrowUp":
157
+ e.preventDefault();
158
+ if (results.value.length) selectedIndex.value = (selectedIndex.value - 1 + results.value.length) % results.value.length;
159
+ break;
160
+ case "Enter": if (results.value.length && selectedIndex.value >= 0) selectResult(results.value[selectedIndex.value]);
161
+ }
162
+ };
163
+ const selectResult = (result) => {
164
+ emit("select", result);
165
+ closeModal();
166
+ };
167
+ return (_ctx, _cache) => {
168
+ return openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: "fade" }, {
169
+ default: withCtx(() => [__props.isOpen ? (openBlock(), createElementBlock("div", {
170
+ key: 0,
171
+ class: "command-palette-overlay",
172
+ onClick: closeModal
173
+ }, [createElementVNode("div", {
174
+ class: "command-palette",
175
+ onClick: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop"]))
176
+ }, [createElementVNode("div", _hoisted_1$2, [withDirectives(createElementVNode("input", {
177
+ ref: "input",
178
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
179
+ type: "text",
180
+ class: "command-palette-input",
181
+ placeholder: __props.placeholder,
182
+ autofocus: "",
183
+ onKeydown: handleKeydown
184
+ }, null, 40, _hoisted_2$2), [[vModelText, query.value]])]), results.value.length ? (openBlock(), createElementBlock("div", _hoisted_3$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(results.value, (result, index) => {
185
+ return openBlock(), createElementBlock("div", {
186
+ key: index,
187
+ class: normalizeClass(["command-palette-result", { selected: index === selectedIndex.value }]),
188
+ onClick: ($event) => selectResult(result),
189
+ onMouseover: ($event) => selectedIndex.value = index
190
+ }, [createElementVNode("div", _hoisted_5$1, [renderSlot(_ctx.$slots, "title", { result })]), createElementVNode("div", _hoisted_6, [renderSlot(_ctx.$slots, "content", { result })])], 42, _hoisted_4$1);
191
+ }), 128))])) : query.value && !results.value.length ? (openBlock(), createElementBlock("div", _hoisted_7, [renderSlot(_ctx.$slots, "empty", {}, () => [createTextVNode(" No results found for \"" + toDisplayString(query.value) + "\" ", 1)])])) : createCommentVNode("", true)])])) : createCommentVNode("", true)]),
192
+ _: 3
193
+ })]);
194
+ };
195
+ }
196
+ });
197
+ //#endregion
198
+ //#region src/sheet-nav-toolbar.ts
199
+ /** The id of the element SheetNav renders for footer controls, left of its tabs. */
200
+ var SHEET_NAV_TOOLBAR_ID = "sheetnav-toolbar";
201
+ /** Teleport target for footer controls rendered anywhere on the page: `<Teleport :to="SHEET_NAV_TOOLBAR_SELECTOR">`. */
202
+ var SHEET_NAV_TOOLBAR_SELECTOR = `#${SHEET_NAV_TOOLBAR_ID}`;
203
+ //#endregion
204
+ //#region src/components/SheetNav.vue?vue&type=script&setup=true&lang.ts
205
+ var _hoisted_1$1 = { class: "sheetnav-footer-cluster" };
206
+ var _hoisted_2$1 = ["id"];
207
+ var _hoisted_3 = { class: "tabs" };
208
+ var _hoisted_4 = { tabindex: "0" };
209
+ var _hoisted_5 = { tabindex: "0" };
210
+ //#endregion
211
+ //#region src/components/SheetNav.vue
212
+ var SheetNav_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
213
+ __name: "SheetNav",
214
+ props: { breadcrumbs: { default: () => [] } },
215
+ setup(__props) {
216
+ onMounted(() => {
217
+ if (document.querySelectorAll(SHEET_NAV_TOOLBAR_SELECTOR).length > 1) console.warn(`More than one SheetNav is mounted: content teleported to ${SHEET_NAV_TOOLBAR_SELECTOR} lands in the first one only.`);
218
+ });
219
+ const breadcrumbsVisibile = ref(true);
220
+ const searchVisible = ref(false);
221
+ const searchText = ref("");
222
+ const inputRef = useTemplateRef("searchinput");
223
+ const rotateHideTabIcon = computed(() => {
224
+ return breadcrumbsVisibile.value ? "unrotated" : "rotated";
225
+ });
226
+ const toggleBreadcrumbs = () => {
227
+ breadcrumbsVisibile.value = !breadcrumbsVisibile.value;
228
+ };
229
+ const toggleSearch = async () => {
230
+ searchVisible.value = !searchVisible.value;
231
+ await nextTick(() => {
232
+ inputRef.value?.focus();
233
+ });
234
+ };
235
+ const handleSearchInput = (event) => {
236
+ event.preventDefault();
237
+ event.stopPropagation();
238
+ };
239
+ const handleSearch = async (event) => {
240
+ event.preventDefault();
241
+ event.stopPropagation();
242
+ await toggleSearch();
243
+ };
244
+ const navigateHome = () => {};
245
+ return (_ctx, _cache) => {
246
+ const _component_router_link = resolveComponent("router-link");
247
+ return openBlock(), createElementBlock("footer", null, [createElementVNode("div", _hoisted_1$1, [createElementVNode("div", {
248
+ id: unref(SHEET_NAV_TOOLBAR_ID),
249
+ class: "sheetnav-toolbar"
250
+ }, [renderSlot(_ctx.$slots, "toolbar", {}, void 0, true)], 8, _hoisted_2$1), createElementVNode("ul", _hoisted_3, [
251
+ createElementVNode("li", {
252
+ class: "hidebreadcrumbs",
253
+ onClick: toggleBreadcrumbs,
254
+ onKeydown: withKeys(toggleBreadcrumbs, ["enter"])
255
+ }, [createElementVNode("a", _hoisted_4, [createElementVNode("div", { class: normalizeClass(rotateHideTabIcon.value) }, "×", 2)])], 32),
256
+ createElementVNode("li", {
257
+ class: "hometab",
258
+ style: normalizeStyle({ display: breadcrumbsVisibile.value ? "flex" : "none" }),
259
+ onClick: navigateHome,
260
+ onKeydown: withKeys(navigateHome, ["enter"])
261
+ }, [createVNode(_component_router_link, {
262
+ to: "/",
263
+ tabindex: "0"
264
+ }, {
265
+ default: withCtx(() => [..._cache[5] || (_cache[5] = [createElementVNode("svg", {
266
+ class: "icon",
267
+ "aria-label": "Home",
268
+ viewBox: "0 0 24 24",
269
+ fill: "none",
270
+ stroke: "currentColor",
271
+ "stroke-width": "2"
272
+ }, [createElementVNode("path", { d: "M3 12l9-9 9 9" }), createElementVNode("path", { d: "M9 21V12h6v9" })], -1)])]),
273
+ _: 1
274
+ })], 36),
275
+ createElementVNode("li", {
276
+ class: normalizeClass(["searchtab", { "search-active": searchVisible.value }]),
277
+ style: normalizeStyle({ display: breadcrumbsVisibile.value ? "flex" : "none" })
278
+ }, [createElementVNode("a", _hoisted_5, [withDirectives((openBlock(), createElementBlock("svg", {
279
+ class: "icon search-icon",
280
+ role: "button",
281
+ "aria-label": "Search",
282
+ viewBox: "0 0 24 24",
283
+ fill: "none",
284
+ stroke: "currentColor",
285
+ "stroke-width": "2",
286
+ onClick: toggleSearch,
287
+ onKeydown: withKeys(toggleSearch, ["enter"])
288
+ }, [..._cache[6] || (_cache[6] = [createElementVNode("circle", {
289
+ cx: "11",
290
+ cy: "11",
291
+ r: "7"
292
+ }, null, -1), createElementVNode("path", { d: "M21 21l-4.35-4.35" }, null, -1)])], 544)), [[vShow, !searchVisible.value]]), withDirectives(createElementVNode("input", {
293
+ ref: "searchinput",
294
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchText.value = $event),
295
+ type: "text",
296
+ placeholder: "Search...",
297
+ onClick: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop"])),
298
+ onInput: _cache[2] || (_cache[2] = ($event) => handleSearchInput($event)),
299
+ onBlur: _cache[3] || (_cache[3] = ($event) => handleSearch($event)),
300
+ onKeydown: [_cache[4] || (_cache[4] = withKeys(($event) => handleSearch($event), ["enter"])), withKeys(toggleSearch, ["escape"])]
301
+ }, null, 544), [[vShow, searchVisible.value], [vModelText, searchText.value]])])], 6),
302
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.breadcrumbs, (breadcrumb) => {
303
+ return openBlock(), createElementBlock("li", {
304
+ key: breadcrumb.title,
305
+ style: normalizeStyle({ display: breadcrumbsVisibile.value ? "flex" : "none" })
306
+ }, [createVNode(_component_router_link, {
307
+ tabindex: "0",
308
+ to: breadcrumb.to
309
+ }, {
310
+ default: withCtx(() => [createTextVNode(toDisplayString(breadcrumb.title), 1)]),
311
+ _: 2
312
+ }, 1032, ["to"])], 4);
313
+ }), 128))
314
+ ])])]);
315
+ };
316
+ }
317
+ }), [["__scopeId", "data-v-7c905747"]]);
318
+ //#endregion
319
+ //#region src/components/Desktop.vue?vue&type=script&setup=true&lang.ts
320
+ var _hoisted_1 = {
321
+ key: 1,
322
+ class: "loading"
323
+ };
324
+ var _hoisted_2 = {
325
+ key: 2,
326
+ class: "loading"
327
+ };
328
+ //#endregion
329
+ //#region src/components/Desktop.vue
330
+ var Desktop_default = /* @__PURE__ */ defineComponent({
331
+ __name: "Desktop",
332
+ props: {
333
+ availableDoctypes: { default: () => [] },
334
+ routeAdapter: {}
335
+ },
336
+ emits: [
337
+ "action",
338
+ "navigate",
339
+ "record:open",
340
+ "load-records",
341
+ "load-record"
342
+ ],
343
+ setup(__props, { emit: __emit }) {
344
+ const emit = __emit;
345
+ const { stonecrop } = useStonecrop();
346
+ let validationStore = null;
347
+ try {
348
+ validationStore = useValidationStore();
349
+ } catch {
350
+ validationStore = null;
351
+ }
352
+ const fieldErrors = computed(() => currentView.value === "record" ? validationStore?.errorsByField ?? {} : {});
353
+ const loading = ref(false);
354
+ const commandPaletteOpen = ref(false);
355
+ const draftRecord = ref({});
356
+ const currentViewData = computed({
357
+ get() {
358
+ if (currentView.value === "doctypes") return { doctypes_table: __props.availableDoctypes?.map((doctype) => ({
359
+ id: doctype,
360
+ doctype,
361
+ display_name: formatDoctypeName(doctype),
362
+ actions: "View Records"
363
+ })) ?? [] };
364
+ if (currentView.value === "records") return { records_table: getRecords().map((record) => Object.assign({}, record, {
365
+ id: resolveRecordId(record) ?? "",
366
+ actions: "Edit"
367
+ })) };
368
+ if (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) return {};
369
+ try {
370
+ const flat = { ...isNewRecord.value ? draftRecord.value : stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)?.get("") };
371
+ const doctype = stonecrop.value.registry.registry[currentDoctype.value];
372
+ if (doctype) {
373
+ for (const field of doctype.getSchemaArray()) if (field.kind === "fieldset") {
374
+ const nested = {};
375
+ for (const child of field.schema) if (child.fieldname) nested[child.fieldname] = flat[child.fieldname];
376
+ flat[field.fieldname] = nested;
377
+ }
378
+ }
379
+ return flat;
380
+ } catch {
381
+ return {};
382
+ }
383
+ },
384
+ set(newData) {
385
+ if (currentView.value !== "record") return;
386
+ if (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) return;
387
+ try {
388
+ const doctype = stonecrop.value.registry.registry[currentDoctype.value];
389
+ const fieldsetNames = /* @__PURE__ */ new Set();
390
+ if (doctype) {
391
+ for (const field of doctype.getSchemaArray()) if (field.kind === "fieldset") fieldsetNames.add(field.fieldname);
392
+ }
393
+ const flatData = {};
394
+ const fieldsetValues = [];
395
+ for (const [key, value] of Object.entries(newData)) if (fieldsetNames.has(key) && value && typeof value === "object" && !Array.isArray(value)) fieldsetValues.push(value);
396
+ else flatData[key] = value;
397
+ for (const nestedValue of fieldsetValues) Object.assign(flatData, nestedValue);
398
+ const changedFields = [];
399
+ if (isNewRecord.value) {
400
+ const next = { ...draftRecord.value };
401
+ for (const [fieldname, value] of Object.entries(flatData)) {
402
+ if (value === void 0) continue;
403
+ if (next[fieldname] !== value) {
404
+ next[fieldname] = value;
405
+ changedFields.push(fieldname);
406
+ }
407
+ }
408
+ draftRecord.value = next;
409
+ } else {
410
+ const hstStore = stonecrop.value.getStore();
411
+ for (const [fieldname, value] of Object.entries(flatData)) {
412
+ if (value === void 0) continue;
413
+ const fieldPath = `${currentDoctype.value}.${currentRecordId.value}.${fieldname}`;
414
+ if ((hstStore.has(fieldPath) ? hstStore.get(fieldPath) : void 0) !== value) {
415
+ hstStore.set(fieldPath, value);
416
+ changedFields.push(fieldname);
417
+ }
418
+ }
419
+ }
420
+ if (changedFields.length > 0) driveFieldValidation(changedFields);
421
+ } catch (error) {
422
+ console.warn("HST update failed:", error);
423
+ }
424
+ }
425
+ });
426
+ function driveFieldValidation(changedFields) {
427
+ if (!validationStore || !stonecrop.value || !currentDoctype.value || !currentRecordId.value) return;
428
+ const triggers = stonecrop.value.registry.getDoctype(currentDoctype.value)?.getTriggers();
429
+ if (!triggers || Object.keys(triggers).length === 0) return;
430
+ const record = isNewRecord.value ? { ...draftRecord.value } : { ...stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)?.get("") };
431
+ for (const field of changedFields) validationStore.validateField(triggers, field, record);
432
+ }
433
+ const route = computed(() => __props.routeAdapter ? null : unref(stonecrop.value?.registry.router?.currentRoute));
434
+ const router = computed(() => __props.routeAdapter ? null : stonecrop.value?.registry.router);
435
+ const currentDoctype = computed(() => {
436
+ if (__props.routeAdapter) return __props.routeAdapter.getCurrentDoctype();
437
+ if (!route.value) return "";
438
+ if (route.value.meta?.actualDoctype) return route.value.meta.actualDoctype;
439
+ if (route.value.params.doctype) return route.value.params.doctype.toString();
440
+ const pathMatch = route.value.params.pathMatch;
441
+ if (pathMatch && pathMatch.length > 0) return pathMatch[0];
442
+ return "";
443
+ });
444
+ const routeDoctype = computed(() => {
445
+ if (__props.routeAdapter) return __props.routeAdapter.getCurrentDoctype();
446
+ if (!route.value) return "";
447
+ if (route.value.meta?.doctype) return route.value.meta.doctype;
448
+ if (route.value.params.doctype) return route.value.params.doctype.toString();
449
+ const pathMatch = route.value.params.pathMatch;
450
+ if (pathMatch && pathMatch.length > 0) return pathMatch[0];
451
+ return "";
452
+ });
453
+ const currentRecordId = computed(() => {
454
+ if (__props.routeAdapter) return __props.routeAdapter.getCurrentRecordId();
455
+ if (!route.value) return "";
456
+ if (route.value.params.recordId) return route.value.params.recordId.toString();
457
+ const pathMatch = route.value.params.pathMatch;
458
+ if (pathMatch && pathMatch.length > 1) return pathMatch[1];
459
+ return "";
460
+ });
461
+ const isNewRecord = computed(() => isDraftRecordId(currentRecordId.value));
462
+ const currentView = computed(() => {
463
+ if (__props.routeAdapter) return __props.routeAdapter.getCurrentView();
464
+ if (!route.value) return "doctypes";
465
+ if (route.value.name === "home" || route.value.path === "/") return "doctypes";
466
+ if (route.value.name && route.value.name !== "catch-all") {
467
+ const routeName = route.value.name;
468
+ if (routeName.includes("form") || route.value.params.recordId) return "record";
469
+ else if (routeName.includes("list") || route.value.params.doctype) return "records";
470
+ }
471
+ const pathMatch = route.value.params.pathMatch;
472
+ if (pathMatch && pathMatch.length > 0) return pathMatch.length === 1 ? "records" : "record";
473
+ return "doctypes";
474
+ });
475
+ const getAvailableTransitions = () => {
476
+ if (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) return [];
477
+ try {
478
+ const doctype = stonecrop.value.registry.getDoctype(currentDoctype.value);
479
+ if (!doctype?.workflow) return [];
480
+ const currentState = stonecrop.value.getRecordState(currentDoctype.value, currentRecordId.value);
481
+ const transitions = doctype.getAvailableTransitions(currentState);
482
+ const recordData = currentViewData.value || {};
483
+ return transitions.map(({ name }) => ({
484
+ label: doctype.getActionMeta(name)?.label ?? name,
485
+ action: () => {
486
+ emit("action", {
487
+ name,
488
+ doctype: currentDoctype.value,
489
+ recordId: currentRecordId.value,
490
+ data: recordData
491
+ });
492
+ }
493
+ }));
494
+ } catch (error) {
495
+ console.warn("Error getting available transitions:", error);
496
+ return [];
497
+ }
498
+ };
499
+ const getAvailableCommands = () => {
500
+ if (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) return [];
501
+ try {
502
+ const doctype = stonecrop.value.registry.getDoctype(currentDoctype.value);
503
+ if (!doctype?.workflow) return [];
504
+ const currentState = stonecrop.value.getRecordState(currentDoctype.value, currentRecordId.value);
505
+ const commands = doctype.getAvailableCommands(currentState);
506
+ const recordData = currentViewData.value || {};
507
+ return commands.map(({ name }) => ({
508
+ label: doctype.getActionMeta(name)?.label ?? name,
509
+ action: () => {
510
+ emit("action", {
511
+ name,
512
+ doctype: currentDoctype.value,
513
+ recordId: currentRecordId.value,
514
+ data: recordData
515
+ });
516
+ }
517
+ }));
518
+ } catch (error) {
519
+ console.warn("Error getting available commands:", error);
520
+ return [];
521
+ }
522
+ };
523
+ const actionElements = computed(() => {
524
+ const elements = [];
525
+ switch (currentView.value) {
526
+ case "records":
527
+ elements.push({
528
+ type: "button",
529
+ label: "New Record",
530
+ action: () => void createNewRecord()
531
+ });
532
+ break;
533
+ case "record": {
534
+ const recordActions = [...getAvailableTransitions(), ...getAvailableCommands()];
535
+ if (recordActions.length > 0) elements.push({
536
+ type: "dropdown",
537
+ label: "Actions",
538
+ actions: recordActions
539
+ });
540
+ break;
541
+ }
542
+ }
543
+ return elements;
544
+ });
545
+ const navigationBreadcrumbs = computed(() => {
546
+ const breadcrumbs = [];
547
+ if (currentView.value === "records" && routeDoctype.value) breadcrumbs.push({
548
+ title: "Home",
549
+ to: "/"
550
+ }, {
551
+ title: formatDoctypeName(routeDoctype.value),
552
+ to: `/${routeDoctype.value}`
553
+ });
554
+ else if (currentView.value === "record" && routeDoctype.value) {
555
+ const recordPath = currentRecordId.value ? `/${routeDoctype.value}/${currentRecordId.value}` : route.value?.fullPath ?? "";
556
+ breadcrumbs.push({
557
+ title: "Home",
558
+ to: "/"
559
+ }, {
560
+ title: formatDoctypeName(routeDoctype.value),
561
+ to: `/${routeDoctype.value}`
562
+ }, {
563
+ title: isNewRecord.value ? "New Record" : "Edit Record",
564
+ to: recordPath
565
+ });
566
+ }
567
+ return breadcrumbs;
568
+ });
569
+ const searchCommands = (query) => {
570
+ const commands = [{
571
+ title: "Go Home",
572
+ description: "Navigate to the home page",
573
+ action: () => void doNavigate({ view: "doctypes" })
574
+ }, {
575
+ title: "Toggle Command Palette",
576
+ description: "Open/close the command palette",
577
+ action: () => commandPaletteOpen.value = !commandPaletteOpen.value
578
+ }];
579
+ if (routeDoctype.value) {
580
+ commands.push({
581
+ title: `View ${formatDoctypeName(routeDoctype.value)} Records`,
582
+ description: `Navigate to ${routeDoctype.value} list`,
583
+ action: () => void doNavigate({
584
+ view: "records",
585
+ doctype: routeDoctype.value
586
+ })
587
+ });
588
+ commands.push({
589
+ title: `Create New ${formatDoctypeName(routeDoctype.value)}`,
590
+ description: `Create a new ${routeDoctype.value} record`,
591
+ action: () => void createNewRecord()
592
+ });
593
+ }
594
+ __props.availableDoctypes.forEach((doctype) => {
595
+ commands.push({
596
+ title: `View ${formatDoctypeName(doctype)}`,
597
+ description: `Navigate to ${doctype} list`,
598
+ action: () => void doNavigate({
599
+ view: "records",
600
+ doctype
601
+ })
602
+ });
603
+ });
604
+ if (!query) return commands;
605
+ return commands.filter((cmd) => cmd.title.toLowerCase().includes(query.toLowerCase()) || cmd.description.toLowerCase().includes(query.toLowerCase()));
606
+ };
607
+ const executeCommand = (command) => {
608
+ command.action();
609
+ commandPaletteOpen.value = false;
610
+ };
611
+ const listRecordsFetcher = (options) => {
612
+ if (!stonecrop.value || !currentDoctype.value) return Promise.resolve({
613
+ data: [],
614
+ hasMore: false
615
+ });
616
+ const doctype = stonecrop.value.registry.getDoctype(currentDoctype.value);
617
+ if (!doctype) return Promise.resolve({
618
+ data: [],
619
+ hasMore: false
620
+ });
621
+ return stonecrop.value.getRecords(doctype, options);
622
+ };
623
+ const formatDoctypeName = (doctype) => {
624
+ return doctype.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
625
+ };
626
+ const doNavigate = async (target) => {
627
+ emit("navigate", target);
628
+ if (__props.routeAdapter) await __props.routeAdapter.navigate(target);
629
+ else if (target.view === "doctypes") await router.value?.push("/");
630
+ else if (target.view === "records" && target.doctype) await router.value?.push(`/${target.doctype}`);
631
+ else if (target.view === "record" && target.doctype && target.recordId) await router.value?.push(`/${target.doctype}/${target.recordId}`);
632
+ };
633
+ const navigateToDoctype = async (doctype) => {
634
+ await doNavigate({
635
+ view: "records",
636
+ doctype
637
+ });
638
+ };
639
+ const openRecord = async (recordId) => {
640
+ const doctype = routeDoctype.value;
641
+ emit("record:open", {
642
+ doctype,
643
+ recordId
644
+ });
645
+ await doNavigate({
646
+ view: "record",
647
+ doctype,
648
+ recordId
649
+ });
650
+ };
651
+ const createNewRecord = async () => {
652
+ await doNavigate({
653
+ view: "record",
654
+ doctype: routeDoctype.value,
655
+ recordId: DRAFT_RECORD_ID
656
+ });
657
+ };
658
+ const getDoctypesSchema = () => {
659
+ if (!__props.availableDoctypes?.length) return [];
660
+ return [{
661
+ kind: "table",
662
+ fieldname: "doctypes_table",
663
+ component: "ATable",
664
+ label: "Doctypes",
665
+ schema: [
666
+ {
667
+ fieldname: "doctype",
668
+ label: "Doctype",
669
+ component: "ATextInput",
670
+ align: "left",
671
+ edit: false,
672
+ width: "20ch"
673
+ },
674
+ {
675
+ fieldname: "display_name",
676
+ label: "Name",
677
+ component: "ATextInput",
678
+ align: "left",
679
+ edit: false,
680
+ width: "30ch"
681
+ },
682
+ {
683
+ fieldname: "actions",
684
+ label: "Actions",
685
+ component: "ATextInput",
686
+ align: "center",
687
+ edit: false,
688
+ width: "20ch"
689
+ }
690
+ ],
691
+ config: {
692
+ view: "list",
693
+ fullWidth: true
694
+ }
695
+ }];
696
+ };
697
+ const getRecordsSchema = () => {
698
+ if (!currentDoctype.value) return [];
699
+ if (!stonecrop.value) return [];
700
+ const registry = stonecrop.value.registry;
701
+ const doctype = registry.registry[currentDoctype.value];
702
+ if (!doctype) return [];
703
+ const schema = registry.resolveSchema(doctype);
704
+ if (schema.length === 0) return [];
705
+ const doctypeSlug = currentDoctype.value;
706
+ const clientConfigured = Boolean(stonecrop.value.getClient());
707
+ return [{
708
+ kind: "table",
709
+ fieldname: "records_table",
710
+ component: "ATable",
711
+ schema: [...resolvedFieldsToColumns(schema), {
712
+ fieldname: "actions",
713
+ label: "Actions",
714
+ component: "ATextInput"
715
+ }],
716
+ config: {
717
+ view: "list",
718
+ fullWidth: true
719
+ },
720
+ ...clientConfigured ? {
721
+ getRecords: listRecordsFetcher,
722
+ sourceKey: doctypeSlug
723
+ } : {}
724
+ }];
725
+ };
726
+ const getRecordFormSchema = () => {
727
+ if (!currentDoctype.value) return [];
728
+ if (!stonecrop.value) return [];
729
+ try {
730
+ const registry = stonecrop.value?.registry;
731
+ const doctype = registry?.registry[currentDoctype.value];
732
+ if (!doctype?.schema) return [];
733
+ return registry.resolveSchema(doctype);
734
+ } catch {
735
+ return [];
736
+ }
737
+ };
738
+ const getRecords = () => {
739
+ if (!stonecrop.value || !currentDoctype.value) return [];
740
+ const recordsData = stonecrop.value.records(currentDoctype.value)?.get("");
741
+ if (recordsData && typeof recordsData === "object" && !Array.isArray(recordsData)) return Object.values(recordsData);
742
+ return [];
743
+ };
744
+ const currentViewSchema = computed(() => {
745
+ switch (currentView.value) {
746
+ case "doctypes": return getDoctypesSchema();
747
+ case "records": return getRecordsSchema();
748
+ case "record": return getRecordFormSchema();
749
+ default: return [];
750
+ }
751
+ });
752
+ const handleActionClick = (_label, action) => {
753
+ if (action) action();
754
+ };
755
+ /**
756
+ * Resolve a record's identity for links and navigation.
757
+ *
758
+ * Identity is declared once, on the doctype: `primaryKey`, or `id` when nothing is declared.
759
+ * Delegating to `Doctype.getRecordId` is what guarantees this matches the key
760
+ * `Stonecrop.getRecords` stored the record under — resolving it independently here would let a
761
+ * row render a link to an HST path that does not exist.
762
+ *
763
+ * There is deliberately no per-shell override. Identity is a per-doctype fact and one shell
764
+ * renders many doctypes, so a single prop cannot answer it; a shell that named a field would
765
+ * also be overriding the very declaration the store keyed on, which is the bug above.
766
+ */
767
+ const resolveRecordId = (record) => {
768
+ if (!stonecrop.value || !currentDoctype.value) return void 0;
769
+ return stonecrop.value.registry.registry[currentDoctype.value]?.getRecordId(record);
770
+ };
771
+ const getRecordIdFromRow = (rowElement) => {
772
+ const cell = rowElement.querySelector("td[data-rowindex]");
773
+ if (!cell) return null;
774
+ const rowIndexAttr = cell.getAttribute("data-rowindex");
775
+ if (rowIndexAttr === null) return null;
776
+ const rowIndex = parseInt(rowIndexAttr, 10);
777
+ if (isNaN(rowIndex)) return null;
778
+ const record = getRecords()[rowIndex];
779
+ if (!record) return null;
780
+ return resolveRecordId(record) ?? null;
781
+ };
782
+ const handleClick = async (event) => {
783
+ const target = event.target;
784
+ if (target.getAttribute("data-action") === "create") await createNewRecord();
785
+ const cell = target.closest("td, th");
786
+ if (cell) {
787
+ const cellText = cell.textContent?.trim();
788
+ const row = cell.closest("tr");
789
+ if (cellText === "View Records" && row) {
790
+ const cells = row.querySelectorAll("td");
791
+ if (cells.length > 0) {
792
+ const doctype = cells[1].textContent?.trim();
793
+ if (doctype) await navigateToDoctype(doctype);
794
+ }
795
+ } else if (cellText === "Edit" && row) {
796
+ const recordId = getRecordIdFromRow(row);
797
+ if (recordId) await openRecord(recordId);
798
+ }
799
+ }
800
+ };
801
+ const loadRecordData = async () => {
802
+ if (!stonecrop.value || !currentDoctype.value || !stonecrop.value.getClient()) return;
803
+ loading.value = true;
804
+ try {
805
+ await stonecrop.value.getRecord(currentDoctype.value, currentRecordId.value);
806
+ } catch (error) {
807
+ console.warn("Error fetching record:", error);
808
+ } finally {
809
+ loading.value = false;
810
+ }
811
+ };
812
+ watch([
813
+ currentView,
814
+ currentDoctype,
815
+ currentRecordId
816
+ ], () => {
817
+ if (currentView.value === "records" && currentDoctype.value) emit("load-records", { doctype: currentDoctype.value });
818
+ else if (currentView.value === "record" && currentDoctype.value && currentRecordId.value) {
819
+ if (isNewRecord.value) return;
820
+ emit("load-record", {
821
+ doctype: currentDoctype.value,
822
+ recordId: currentRecordId.value
823
+ });
824
+ loadRecordData();
825
+ }
826
+ }, { immediate: true });
827
+ watch([currentDoctype, currentRecordId], () => {
828
+ validationStore?.clearAll();
829
+ });
830
+ watch([currentDoctype, currentRecordId], () => {
831
+ if (!isNewRecord.value) {
832
+ draftRecord.value = {};
833
+ return;
834
+ }
835
+ const registry = stonecrop.value?.registry;
836
+ draftRecord.value = registry ? registry.initializeRecord(getRecordFormSchema()) : {};
837
+ }, { immediate: true });
838
+ provide("desktopMethods", {
839
+ navigateToDoctype,
840
+ openRecord,
841
+ createNewRecord,
842
+ /**
843
+ * Convenience wrapper so child components (e.g. slot content) can emit
844
+ * an action event without needing a direct reference to the emit function.
845
+ */
846
+ emitAction: (name, data) => {
847
+ emit("action", {
848
+ name,
849
+ doctype: currentDoctype.value,
850
+ recordId: currentRecordId.value,
851
+ data: data ?? currentViewData.value ?? {}
852
+ });
853
+ }
854
+ });
855
+ provide("aformLinkNavigator", { navigate: (doctype, id) => {
856
+ doNavigate({
857
+ view: "record",
858
+ doctype,
859
+ recordId: String(id)
860
+ });
861
+ } });
862
+ provide("aformLinkResolver", async (doctypeSlug, id) => {
863
+ if (!stonecrop.value) return void 0;
864
+ try {
865
+ const displayField = (await stonecrop.value.getMeta({
866
+ path: `/${doctypeSlug}`,
867
+ segments: [doctypeSlug]
868
+ }))?.displayField;
869
+ if (!displayField) return void 0;
870
+ const readDisplay = (rec) => {
871
+ if (!rec) return void 0;
872
+ const val = rec[displayField];
873
+ return typeof val === "string" || typeof val === "number" ? String(val) : void 0;
874
+ };
875
+ const cached = stonecrop.value.getRecordById(doctypeSlug, id)?.get("");
876
+ const cachedDisplay = readDisplay(cached);
877
+ if (cachedDisplay != null) return cachedDisplay;
878
+ await stonecrop.value.getRecord(doctypeSlug, id);
879
+ const fetched = stonecrop.value.getRecordById(doctypeSlug, id)?.get("");
880
+ return readDisplay(fetched);
881
+ } catch {
882
+ return;
883
+ }
884
+ });
885
+ const handleKeydown = (event) => {
886
+ if ((event.ctrlKey || event.metaKey) && event.key === "k") {
887
+ event.preventDefault();
888
+ commandPaletteOpen.value = true;
889
+ }
890
+ if (event.key === "Escape" && commandPaletteOpen.value) commandPaletteOpen.value = false;
891
+ };
892
+ onMounted(() => {
893
+ document.addEventListener("keydown", handleKeydown);
894
+ });
895
+ onUnmounted(() => {
896
+ document.removeEventListener("keydown", handleKeydown);
897
+ });
898
+ return (_ctx, _cache) => {
899
+ return openBlock(), createElementBlock("div", {
900
+ class: "desktop",
901
+ onClick: handleClick
902
+ }, [
903
+ createVNode(ActionSet_default, {
904
+ elements: actionElements.value,
905
+ onActionClick: handleActionClick
906
+ }, null, 8, ["elements"]),
907
+ currentViewSchema.value.length > 0 ? (openBlock(), createBlock(unref(AForm), {
908
+ key: 0,
909
+ data: currentViewData.value,
910
+ "onUpdate:data": _cache[0] || (_cache[0] = ($event) => currentViewData.value = $event),
911
+ schema: currentViewSchema.value,
912
+ errors: fieldErrors.value
913
+ }, null, 8, [
914
+ "data",
915
+ "schema",
916
+ "errors"
917
+ ])) : !unref(stonecrop) ? (openBlock(), createElementBlock("div", _hoisted_1, [..._cache[2] || (_cache[2] = [createElementVNode("p", null, "Initializing Stonecrop...", -1)])])) : (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("p", null, "Loading " + toDisplayString(currentView.value) + " data...", 1)])),
918
+ createVNode(SheetNav_default, { breadcrumbs: navigationBreadcrumbs.value }, {
919
+ toolbar: withCtx(() => [renderSlot(_ctx.$slots, "sheetnav-toolbar")]),
920
+ _: 3
921
+ }, 8, ["breadcrumbs"]),
922
+ createVNode(CommandPalette_default, {
923
+ "is-open": commandPaletteOpen.value,
924
+ search: searchCommands,
925
+ placeholder: "Type a command or search...",
926
+ onSelect: executeCommand,
927
+ onClose: _cache[1] || (_cache[1] = ($event) => commandPaletteOpen.value = false)
928
+ }, {
929
+ title: withCtx(({ result }) => [createTextVNode(toDisplayString(result.title), 1)]),
930
+ content: withCtx(({ result }) => [createTextVNode(toDisplayString(result.description), 1)]),
931
+ _: 1
932
+ }, 8, ["is-open"])
933
+ ]);
934
+ };
935
+ }
936
+ });
937
+ //#endregion
938
+ //#region src/plugins/index.ts
939
+ /**
940
+ * This is the main plugin that will be used to register all the desktop components.
941
+ * @public
942
+ */
943
+ var plugin = { install: (app) => {
944
+ app.component("ActionSet", ActionSet_default);
945
+ app.component("CommandPalette", CommandPalette_default);
946
+ app.component("Desktop", Desktop_default);
947
+ app.component("SheetNav", SheetNav_default);
948
+ } };
949
+ //#endregion
950
+ export { ActionSet_default as ActionSet, CommandPalette_default as CommandPalette, Desktop_default as Desktop, SHEET_NAV_TOOLBAR_SELECTOR, SheetNav_default as SheetNav, plugin as StonecropDesktop };
951
+
952
+ //# sourceMappingURL=desktop.js.map