vintage-frames 0.14.0 → 0.15.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.
Files changed (55) hide show
  1. package/README.md +16 -0
  2. package/custom-elements.json +271 -27
  3. package/dist/components/vf-button.d.ts +5 -1
  4. package/dist/components/vf-button.js +1 -1
  5. package/dist/components/vf-container.d.ts +3 -1
  6. package/dist/components/vf-container.js +34 -16
  7. package/dist/components/vf-desktop.d.ts +114 -12
  8. package/dist/components/vf-desktop.js +119 -58
  9. package/dist/components/vf-dialog.d.ts +7 -1
  10. package/dist/components/vf-icon-field.d.ts +1 -1
  11. package/dist/components/vf-icon.js +68 -61
  12. package/dist/components/vf-menu-bar.d.ts +5 -0
  13. package/dist/components/vf-menu-bar.js +67 -43
  14. package/dist/components/vf-window.d.ts +13 -0
  15. package/dist/components/vf-window.js +10 -1
  16. package/dist/events.d.ts +3 -2
  17. package/dist/events.js +3 -3
  18. package/dist/index.d.ts +3 -1
  19. package/dist/index.js +44 -43
  20. package/dist/modal-dialog.d.ts +31 -4
  21. package/dist/modal-dialog.js +98 -82
  22. package/dist/pattern-fill.d.ts +11 -8
  23. package/dist/pattern-fill.js +2 -4
  24. package/dist/position.d.ts +25 -7
  25. package/dist/position.js +31 -23
  26. package/dist/shell/alert.d.ts +40 -0
  27. package/dist/shell/alert.js +41 -0
  28. package/dist/shell/catalog.d.ts +168 -0
  29. package/dist/shell/catalog.js +278 -0
  30. package/dist/shell/clock.d.ts +16 -0
  31. package/dist/shell/clock.js +36 -0
  32. package/dist/shell/filing.d.ts +39 -0
  33. package/dist/shell/filing.js +68 -0
  34. package/dist/shell/finder.d.ts +156 -0
  35. package/dist/shell/finder.js +598 -0
  36. package/dist/shell/geometry.d.ts +196 -0
  37. package/dist/shell/geometry.js +241 -0
  38. package/dist/shell/index.d.ts +27 -0
  39. package/dist/shell/index.js +10 -0
  40. package/dist/shell/shell.d.ts +164 -0
  41. package/dist/shell/shell.js +234 -0
  42. package/dist/shell/state.d.ts +88 -0
  43. package/dist/shell/state.js +103 -0
  44. package/dist/shell/storage.d.ts +14 -0
  45. package/dist/shell/storage.js +41 -0
  46. package/dist/shell/windows.d.ts +234 -0
  47. package/dist/shell/windows.js +387 -0
  48. package/dist/text-control.d.ts +6 -0
  49. package/dist/text-control.js +2 -2
  50. package/dist/window-chrome.d.ts +43 -0
  51. package/dist/window-chrome.js +13 -0
  52. package/docs/SPEC.md +17 -16
  53. package/editor/vscode.html-custom-data.json +11 -6
  54. package/editor/web-types.json +55 -14
  55. package/package.json +10 -2
@@ -0,0 +1,598 @@
1
+ import { snapSys as e, systemPxQuantum as t } from "../scale.js";
2
+ import { prefersReducedMotion as n } from "../motion.js";
3
+ import { windowChrome as r } from "../window-chrome.js";
4
+ import "../index.js";
5
+ import { FOLDER as i, TRASH as a, childrenOf as o, enclosingFolders as s, isContainerKind as c, isInside as l, isTrashed as u, isVolume as d, itemCount as f } from "./catalog.js";
6
+ import { cleanUp as ee, collisions as te, desktopLattice as ne, fieldExtent as re, fillOrder as ie, folderLattice as ae, frameOf as oe, nextFreeCell as se, pinOf as ce, pinTo as le, trashCell as ue } from "./geometry.js";
7
+ import { appIdOf as de, defineApp as p } from "./shell.js";
8
+ import { fileByDrag as fe } from "./filing.js";
9
+ import { composeAlert as pe } from "./alert.js";
10
+ //#region src/shell/finder.ts
11
+ var m = "finder", me = 306, he = 300, ge = {
12
+ "new-folder": "New Folder",
13
+ "empty-trash": "Empty Trash",
14
+ paste: "Paste",
15
+ "add-file": "Adding the file"
16
+ }, _e = 20, ve = 18, h = {
17
+ left: 8,
18
+ top: 2
19
+ }, g = {
20
+ width: 12,
21
+ height: 12
22
+ }, _ = {
23
+ left: h.left - 1,
24
+ top: h.top
25
+ }, ye = {
26
+ left: _.left + g.width + 3,
27
+ top: h.top
28
+ }, v = [
29
+ {
30
+ menu: "file",
31
+ label: "File",
32
+ items: [
33
+ [
34
+ "open",
35
+ "Open",
36
+ "⌘O"
37
+ ],
38
+ ["new-folder", "New Folder"],
39
+ [
40
+ "close",
41
+ "Close",
42
+ "⌃W"
43
+ ]
44
+ ]
45
+ },
46
+ {
47
+ menu: "edit",
48
+ label: "Edit",
49
+ items: [
50
+ [
51
+ "copy",
52
+ "Copy",
53
+ "⌘C"
54
+ ],
55
+ [
56
+ "paste",
57
+ "Paste",
58
+ "⌘V"
59
+ ],
60
+ [
61
+ "select-all",
62
+ "Select All",
63
+ "⌘A"
64
+ ]
65
+ ]
66
+ },
67
+ {
68
+ menu: "view",
69
+ label: "View",
70
+ items: [[
71
+ "arrange",
72
+ "Arrange Windows",
73
+ "⌘J"
74
+ ]]
75
+ },
76
+ {
77
+ menu: "special",
78
+ label: "Special",
79
+ items: [["clean-up", "Clean Up Desktop"], ["empty-trash", "Empty Trash…"]]
80
+ }
81
+ ];
82
+ function y(e) {
83
+ return v.map(({ menu: t, label: n, items: r }) => {
84
+ let i = r.filter(([t]) => e(t)).map(([e, t, n], r) => `${e === "close" && r > 0 ? "<vf-separator></vf-separator>" : ""}<vf-menu-item value="${e}"${n ? ` shortcut="${n}"` : ""}>${t}</vf-menu-item>`);
85
+ return i.length ? `<vf-menu data-menu="${t}" label="${n}">${i.join("")}</vf-menu>` : "";
86
+ }).join("");
87
+ }
88
+ var be = (e) => e.localName === "vf-icon" && e.dataset.app != null || e instanceof HTMLTemplateElement && e.dataset.folder != null;
89
+ function xe(e) {
90
+ let t = (e, t) => e != null && t != null && Number.isFinite(+e) && Number.isFinite(+t) ? {
91
+ left: +e,
92
+ top: +t
93
+ } : void 0, n = [];
94
+ for (let r of [...e.children].filter(be)) r instanceof HTMLTemplateElement ? n.push({
95
+ kind: i,
96
+ name: r.dataset.folder ?? null,
97
+ at: t(r.dataset.left, r.dataset.top),
98
+ children: xe(r.content)
99
+ }) : n.push({
100
+ kind: "app",
101
+ name: r.getAttribute("label"),
102
+ app: r.dataset.app,
103
+ at: t(r.getAttribute("left"), r.getAttribute("top")),
104
+ children: []
105
+ });
106
+ return n;
107
+ }
108
+ function b(i) {
109
+ let b = i.volumes?.trash !== !1, x = (e) => i.commands?.[e] !== !1 && (e !== "empty-trash" || b), Se = [], Ce = (e) => e, S = i.seed === "markup" ? async (e) => {
110
+ let t = Date.now(), n = async (r, i) => {
111
+ for (let a of r) {
112
+ let r = await e.create({
113
+ kind: a.kind,
114
+ name: a.name ?? (a.app == null ? void 0 : Ce(a.app)),
115
+ parent: i,
116
+ ...a.at,
117
+ ...a.app == null ? {} : { data: { app: a.app } },
118
+ at: t++
119
+ });
120
+ r && a.children.length && await n(a.children, r.id);
121
+ }
122
+ };
123
+ await n(Se, null);
124
+ } : i.seed;
125
+ return p({
126
+ id: m,
127
+ name: "Finder",
128
+ menus: y(x),
129
+ dialogs: i.dialogs,
130
+ catalog: {
131
+ storage: i.storage,
132
+ volumes: i.volumes,
133
+ seed: S
134
+ },
135
+ init(p) {
136
+ let { desktop: y, windows: S } = p, C = p.catalog, w = i.art;
137
+ Ce = (e) => p.app(e)?.name ?? e;
138
+ let T = i.lattice?.desktop?.cell ?? 64, we = i.lattice?.folder?.cell ?? 64, Te = i.window ?? {
139
+ width: 320,
140
+ height: 223
141
+ }, E = r({
142
+ scrollbars: "both",
143
+ headerHeight: _e
144
+ }), Ee = /* @__PURE__ */ new Map();
145
+ async function D(e, t, n, r = {}) {
146
+ let i = Ee.get(e);
147
+ if (i) return i(t);
148
+ let a = pe(n, {
149
+ art: w.caution ?? null,
150
+ ...r
151
+ });
152
+ p.hold(a.dialog);
153
+ try {
154
+ await a.rendered();
155
+ let e = p.ask(a.dialog);
156
+ return a.fit(), await e;
157
+ } finally {
158
+ p.release(a.dialog);
159
+ }
160
+ }
161
+ let O = (e) => (t) => {
162
+ let n = t;
163
+ D("failed", {
164
+ action: e,
165
+ error: n
166
+ }, `${ge[e]} failed: ${n.message}.`);
167
+ }, k = y.querySelector(":scope > vf-icon-field"), De = !k;
168
+ if (!k) {
169
+ k = document.createElement("vf-icon-field"), k.label = "Desktop", k.toggleAttribute("fill-width", !0), k.toggleAttribute("fill-height", !0);
170
+ let e = y.querySelector(":scope > vf-menu-bar");
171
+ e ? e.after(k) : y.prepend(k);
172
+ }
173
+ let A = k, Oe = [...A.children].filter(be);
174
+ Se = xe(A);
175
+ for (let e of Oe) e.remove();
176
+ let j = () => S.windowsOf(m).map((e) => [S.itemOf(e), e]).filter((e) => e[0] != null), M = (e) => e.querySelector(":scope > vf-icon-field"), N = () => [[null, A], ...j().flatMap(([e, t]) => {
177
+ let n = M(t);
178
+ return n ? [[e, n]] : [];
179
+ })], ke = (e) => N().find(([t]) => t === e)?.[1] ?? null, P = (e) => [...e.querySelectorAll(":scope > vf-icon[data-id]")], F = () => N().flatMap(([, e]) => P(e)), I = (e) => e.dataset.id, L = (e) => F().find((t) => I(t) === e) ?? null, R = (e) => ({
180
+ left: e.left ?? 0,
181
+ top: e.top ?? 0
182
+ }), Ae = (e) => S.itemOf(e.closest("vf-window")), je = (e) => ({
183
+ width: Math.max(0, (e.width ?? 0) - E.left - E.right),
184
+ height: Math.max(0, (e.height ?? 0) - E.top - E.bottom)
185
+ }), Me = (e) => {
186
+ if (e == null) return ne(y.workArea, i.lattice?.desktop);
187
+ let t = S.windowFor(e);
188
+ return ae(t ? je(t).width : 0, i.lattice?.folder);
189
+ }, Ne = (e) => {
190
+ let t = S.windowFor(e), n = t && M(t);
191
+ if (!t || !n) return;
192
+ let r = re(P(n).map(R), je(t), { cell: we });
193
+ n.width !== r.width && (n.width = r.width), n.height !== r.height && (n.height = r.height);
194
+ }, Pe = (n, r, i) => {
195
+ if (r == null) {
196
+ let r = y.workArea, a = t(n), o = (e) => Math.floor(e / a) * a, s = Math.ceil(r.top / a) * a, c = Math.max(r.left, o(r.left + r.width - T)), l = Math.max(s, o(r.top + r.height - T));
197
+ n.left = Math.min(Math.max(e(i.left, n), r.left), c), n.top = Math.min(Math.max(e(i.top, n), s), l);
198
+ } else n.left = e(Math.max(0, i.left), n), n.top = e(Math.max(0, i.top), n);
199
+ }, Fe = (e) => {
200
+ if (e.kind === "folder") return w.folder;
201
+ if (e.kind === "trash") return f(C.get(), "trash") ? w.trashFull : w.trash;
202
+ if (e.kind === "disk") return w.disk ?? w.folder;
203
+ let t = p.kind(e.kind);
204
+ return (typeof t?.art == "function" ? t.art(e) : t?.art) || w.document;
205
+ };
206
+ function Ie(e, t) {
207
+ let n = e.querySelector(":scope > vf-img > img");
208
+ if (!n) {
209
+ let t = document.createElement("vf-img");
210
+ t.slot = "large", t.width = 32, t.height = 32, n = document.createElement("img"), n.alt = "", t.append(n), e.append(t);
211
+ }
212
+ n.getAttribute("src") !== t && (n.src = t);
213
+ }
214
+ function Le(e) {
215
+ let t = document.createElement("vf-icon");
216
+ return t.dataset.id = e.id, t.label = e.name, t.width = T, t.selectable = !0, t.movable = !0, c(e.kind) && (t.dataset.folder = e.id), t;
217
+ }
218
+ let z = /* @__PURE__ */ new Set(), B = /* @__PURE__ */ new WeakMap();
219
+ function Re(e, t, n, r) {
220
+ if (t.left != null && t.top != null) {
221
+ let r = `${t.left},${t.top}`;
222
+ if (B.get(e) === r) return;
223
+ B.set(e, r), (e.left !== t.left || e.top !== t.top) && Pe(e, n, {
224
+ left: t.left,
225
+ top: t.top
226
+ });
227
+ return;
228
+ }
229
+ let a = P(r).filter((t) => t !== e && t.left != null && t.top != null).map(R), o = n == null && t.id === "trash" ? ue(y.workArea, i.lattice?.desktop) : se(Me(n), a, n == null ? T : we);
230
+ Pe(e, n, o), z.add(e);
231
+ }
232
+ let V = !1;
233
+ function H() {
234
+ if (!V) {
235
+ V = !0;
236
+ try {
237
+ let e = C.get(), t = new Map(F().map((e) => [I(e), e])), n = /* @__PURE__ */ new Set(), r = [], i = [];
238
+ for (let [a, s] of N()) for (let c of o(e, a)) {
239
+ let e = t.get(c.id) ?? Le(c);
240
+ e.parentElement !== s && (s.append(e), e.left = void 0, e.top = void 0, B.delete(e)), n.add(e), e.label !== c.name && (e.label = c.name), e.editable = !d(c.id) && p.kind(c.kind)?.editable !== !1, Ie(e, Fe(c));
241
+ let o = c.kind === "app" ? S.hasWindows(de(c) ?? "") : S.isOpen(c.id);
242
+ e.open !== o && (e.open = o);
243
+ let l = () => Re(e, c, a, s);
244
+ c.left != null && c.top != null ? r.push(l) : i.push(l);
245
+ }
246
+ for (let e of t.values()) n.has(e) || e.remove();
247
+ for (let e of [...r, ...i]) e();
248
+ for (let [e, t] of j()) {
249
+ let n = M(t), r = C.item(e)?.name;
250
+ n && r != null && n.label !== r && (n.label = r), Ve(e), Ne(e);
251
+ }
252
+ } finally {
253
+ V = !1;
254
+ }
255
+ ze();
256
+ }
257
+ }
258
+ let U = !1;
259
+ function ze() {
260
+ if (U = !1, !z.size) return;
261
+ let e = /* @__PURE__ */ new Map();
262
+ for (let t of z) t.isConnected && t.left != null && t.top != null && e.set(I(t), R(t));
263
+ z.clear(), C.place(e);
264
+ }
265
+ p.on(y, "vf-placement-change", (e) => {
266
+ let t = e.target;
267
+ t.localName === "vf-icon" && t.dataset.id != null && (z.add(t), !U && (U = !0, queueMicrotask(ze)));
268
+ }), p.onDispose(C.subscribe(H)), p.onDispose(S.onWindows(H));
269
+ function Be() {
270
+ let e = document.createElement("vf-img");
271
+ e.dataset.trashMark = "", e.width = g.width, e.height = g.height, e.left = _.left, e.top = _.top;
272
+ let t = document.createElement("img");
273
+ return t.alt = "in the Trash", t.src = w.trashMark, e.append(t), e;
274
+ }
275
+ function Ve(e) {
276
+ let t = S.windowFor(e)?.querySelector(":scope > [slot=\"header\"]"), n = t?.querySelector(":scope > vf-label[data-count]");
277
+ if (!t || !n) return;
278
+ let r = C.get(), i = f(r, e), a = `${i} item${i === 1 ? "" : "s"}`;
279
+ n.textContent !== a && (n.textContent = a);
280
+ let o = !!w.trashMark && u(r, e), s = t.querySelector(":scope > vf-img[data-trash-mark]");
281
+ o && !s ? t.prepend(Be()) : !o && s && s.remove();
282
+ let c = o ? ye : h;
283
+ n.left !== c.left && (n.left = c.left);
284
+ }
285
+ function He(e) {
286
+ let t = C.item(e)?.name ?? "", n = document.createElement("vf-window");
287
+ n.heading = t, n.movable = !0, n.outlineDrag = !0, n.resizable = !0, n.scrollbars = "both", n.headerHeight = _e, n.width = Te.width, n.height = Te.height;
288
+ let r = document.createElement("vf-container");
289
+ r.slot = "header", r.toggleAttribute("fill-width", !0), r.height = ve, r.rule = "bottom";
290
+ let i = document.createElement("vf-label");
291
+ i.face = "body", i.dataset.count = "", i.left = h.left, i.top = h.top, r.append(i);
292
+ let a = document.createElement("vf-icon-field");
293
+ return a.label = t, a.left = 0, a.top = 0, n.append(r, a), n;
294
+ }
295
+ p.on(y, "vf-resize", (e) => {
296
+ if (!e.detail?.commit || S.appOf(e.target) !== "finder") return;
297
+ let t = S.itemOf(e.target);
298
+ t != null && Ne(t);
299
+ });
300
+ function W(e, t) {
301
+ let n = C.item(e);
302
+ n && (c(n.kind) ? S.open({
303
+ app: m,
304
+ item: e,
305
+ from: t,
306
+ create: () => He(e)
307
+ }) : p.kind(n.kind)?.open(n, t));
308
+ }
309
+ p.on(y, "vf-open", (e) => {
310
+ let t = e.target;
311
+ t.localName === "vf-icon" && t.dataset.id != null && (t.selected && J().length > 1 ? Ke() : W(I(t), t.cellRect()));
312
+ });
313
+ let Ue = (e) => {
314
+ let t = C.get().items.filter((t) => t.kind === "app" && de(t) === e);
315
+ return t.find((e) => L(e.id)) ?? t[0] ?? null;
316
+ }, We = (e, t) => C.item(e) ?? (t == null ? null : Ue(t));
317
+ p.onDispose(S.setHome((e, t) => {
318
+ let n = We(e, t);
319
+ if (!n) return null;
320
+ let r = L(n.id)?.cellRect();
321
+ if (r) return r;
322
+ for (let e of s(C.get(), n.parent)) {
323
+ let t = L(e)?.cellRect();
324
+ if (t) return t;
325
+ }
326
+ return null;
327
+ }, (e, t) => {
328
+ let n = e == null && t == null ? null : We(e, t), r = P(A), i = n ? L(n.id) : r.find((e) => e.selected) ?? r[0] ?? null;
329
+ return i?.checkVisibility() ? (i.focus({ preventScroll: !0 }), !0) : !1;
330
+ })), p.on(A, "pointerdown", () => y.clearActive());
331
+ let G = (e) => {
332
+ let t = e.target;
333
+ return t.localName === "vf-icon" && t.dataset.id != null;
334
+ };
335
+ p.on(y, "vf-change", (e) => {
336
+ if (!G(e)) return;
337
+ let t = e.target, { label: n, previous: r } = e.detail;
338
+ C.rename(I(t), n).catch(() => {
339
+ t.label = r;
340
+ });
341
+ });
342
+ let K = !1;
343
+ p.on(y, "vf-name-too-long", (e) => {
344
+ if (!G(e) || K) return;
345
+ K = !0;
346
+ let { limit: t } = e.detail;
347
+ D("name-too-long", { limit: t }, `That name is too long. A name can have up to ${t} characters.`).finally(() => {
348
+ K = !1;
349
+ });
350
+ }), p.on(y, "vf-name-rejected", (e) => {
351
+ G(e) && D("name-rejected", {}, "An item needs a name.");
352
+ }), p.onDispose(fe(y, {
353
+ folderOfWindow: (e) => S.appOf(e) === "finder" ? S.itemOf(e) ?? void 0 : void 0,
354
+ folderOfIcon: (e) => e.dataset.folder,
355
+ containerOf: (e) => e.dataset.id == null ? void 0 : Ae(e),
356
+ canFile: (e, t) => {
357
+ let n = C.get();
358
+ return e.every((e) => {
359
+ let r = e.dataset.id;
360
+ return r == null || d(r) ? !1 : t == null || e.dataset.folder == null || r !== t && !l(n, t, r);
361
+ });
362
+ },
363
+ file: (e, t, n) => {
364
+ let r = new Map([...n].map(([e, t]) => [I(e), t]));
365
+ C.move(e.map(I), t, r).catch((e) => {
366
+ D("move-failed", { error: e }, `The items couldn’t be moved: ${e.message}.`);
367
+ });
368
+ }
369
+ }));
370
+ let Ge = /* @__PURE__ */ new WeakMap(), q = 0;
371
+ p.onDispose(S.onRaster((t, n) => {
372
+ A.dragIcons([]);
373
+ let r = {
374
+ width: T,
375
+ height: T
376
+ }, a = oe(y.workArea.top);
377
+ for (let i of P(A)) {
378
+ let o = {
379
+ ...R(i),
380
+ ...r
381
+ }, s = Ge.get(i), c = !s || s.left !== o.left || s.top !== o.top ? ce(o, t, a) : s.pin, l = le(c, n, a, { size: r });
382
+ i.left = e(l.left, i), i.top = e(l.top, i), Ge.set(i, {
383
+ pin: c,
384
+ left: i.left,
385
+ top: i.top
386
+ });
387
+ }
388
+ i.cleanUpAfterResize && (window.clearTimeout(q), q = window.setTimeout(() => {
389
+ q = 0, te(P(A).map((e) => ({
390
+ ...R(e),
391
+ ...r
392
+ }))).size && Z(null);
393
+ }, he));
394
+ })), p.onDispose(() => window.clearTimeout(q));
395
+ let J = () => {
396
+ let e = new Set(F().filter((e) => e.selected).map(I));
397
+ return C.get().items.filter((t) => e.has(t.id));
398
+ }, Y = (e) => {
399
+ let t = new Set(e);
400
+ for (let e of F()) e.setSelected(t.has(I(e)));
401
+ }, X = () => {
402
+ let e = y.activeWindow;
403
+ return e && S.appOf(e) === "finder" ? S.itemOf(e) : null;
404
+ };
405
+ async function Z(e) {
406
+ let t = ke(e);
407
+ if (!t) return;
408
+ let n = Me(e), r = P(t), i = ee(n, r.map(R)), a = r.map((e, t) => ({
409
+ icon: e,
410
+ ...i[t]
411
+ })).sort((e, t) => ie(n, e, t));
412
+ await t.dragIcons(a);
413
+ }
414
+ async function Ke() {
415
+ let e = n() ? 0 : me;
416
+ for (let [t, n] of J().entries()) t && e && await new Promise((t) => setTimeout(t, e)), W(n.id, L(n.id)?.cellRect() ?? null);
417
+ }
418
+ async function qe(e) {
419
+ let t = L(e);
420
+ t && (Y([e]), await t.updateComplete, t.startEditing());
421
+ }
422
+ let Je = () => C.get().available ? !0 : (D("storage-unavailable", {}, "Files can’t be saved in this browser session. A private window, perhaps.", { label: "Storage Unavailable" }), !1);
423
+ async function Ye() {
424
+ if (!Je()) return;
425
+ let e = await C.create({ parent: X() }).catch(O("new-folder"));
426
+ e && await qe(e.id);
427
+ }
428
+ async function Xe() {
429
+ let e = f(C.get(), a);
430
+ if (!b || !e) return;
431
+ let t = C.trashSize(), n = Math.ceil(t / 1024), r = e === 1 ? `The Trash contains 1 item, which uses ${n}K of disk space. Are you sure you want to permanently remove it?` : `The Trash contains ${e} items, which use ${n}K of disk space. Are you sure you want to permanently remove these items?`;
432
+ await D("empty-trash", {
433
+ count: e,
434
+ bytes: t
435
+ }, r, {
436
+ label: "Empty Trash",
437
+ buttons: [{
438
+ label: "Cancel",
439
+ value: "cancel"
440
+ }, {
441
+ label: "OK",
442
+ value: "ok",
443
+ default: !0
444
+ }]
445
+ }) === "ok" && await C.emptyTrash().catch(O("empty-trash"));
446
+ }
447
+ let Q = {
448
+ ids: [],
449
+ text: ""
450
+ }, Ze = (e) => e.replace(/\r\n?/g, "\n").trimEnd();
451
+ async function Qe() {
452
+ let e = J().filter((e) => !d(e.id));
453
+ if (!e.length) return;
454
+ let t = e.map((e) => e.name).join("\n");
455
+ Q = {
456
+ ids: e.map((e) => e.id),
457
+ text: t
458
+ };
459
+ let n = e.find((e) => p.kind(e.kind)?.export);
460
+ try {
461
+ let e = n ? await p.kind(n.kind).export(n) : null;
462
+ if (e?.type && e.type !== "text/plain" && typeof ClipboardItem < "u") {
463
+ await navigator.clipboard.write([new ClipboardItem({
464
+ "text/plain": new Blob([t], { type: "text/plain" }),
465
+ [e.type]: e
466
+ })]);
467
+ return;
468
+ }
469
+ } catch {}
470
+ try {
471
+ await navigator.clipboard?.writeText(t);
472
+ } catch {}
473
+ }
474
+ async function $e(e, t) {
475
+ for (let n of p.kinds.values()) if (n.claim && await n.claim(e, t)) return !0;
476
+ return !1;
477
+ }
478
+ let et = () => [...p.kinds.values()].some((e) => e.claim);
479
+ async function tt() {
480
+ try {
481
+ if (navigator.clipboard?.read) {
482
+ let e = null, t = [];
483
+ for (let n of await navigator.clipboard.read()) for (let r of n.types) {
484
+ let i = await n.getType(r);
485
+ r === "text/plain" ? e ??= await i.text() : t.push(i);
486
+ }
487
+ return {
488
+ text: e,
489
+ files: t
490
+ };
491
+ }
492
+ if (navigator.clipboard?.readText) return {
493
+ text: await navigator.clipboard.readText(),
494
+ files: []
495
+ };
496
+ } catch {}
497
+ return null;
498
+ }
499
+ async function nt(e) {
500
+ if (!Je()) return;
501
+ let t = X();
502
+ if (u(C.get(), t)) return;
503
+ let n = e === void 0 ? await tt() : e, r = Q.ids.length > 0 && (n == null || n.text != null && Ze(n.text) === Ze(Q.text));
504
+ try {
505
+ if (r) {
506
+ let e = await C.copy(Q.ids, t);
507
+ e.length && Y(e.map((e) => e.id));
508
+ } else for (let e of n?.files ?? []) await $e(e, t);
509
+ } catch (e) {
510
+ O("paste")(e);
511
+ }
512
+ }
513
+ p.on(document, "paste", (e) => {
514
+ if (!x("paste") || S.front !== "finder" || p.modalOpen() || p.typing()) return;
515
+ let t = e.clipboardData;
516
+ t && (e.preventDefault(), nt({
517
+ text: t.getData("text/plain") || null,
518
+ files: [...t.files]
519
+ }));
520
+ });
521
+ let rt = (e) => [...e.dataTransfer?.types ?? []].includes("Files");
522
+ p.on(y, "dragover", (e) => {
523
+ rt(e) && et() && e.preventDefault();
524
+ }), p.on(y, "drop", (e) => {
525
+ if (!rt(e) || !et()) return;
526
+ e.preventDefault();
527
+ let t = e, n = [...t.dataTransfer?.files ?? []], r = document.elementsFromPoint(t.clientX, t.clientY).find((e) => e.localName === "vf-window");
528
+ if (r && S.appOf(r) !== "finder" || (r ? y.bringToFront(r) : y.clearActive(), !Je())) return;
529
+ let i = r ? S.itemOf(r) : null;
530
+ u(C.get(), i) || (async () => {
531
+ for (let e of n) await $e(e, i);
532
+ })().catch(O("add-file"));
533
+ });
534
+ let it = {
535
+ open: () => void Ke(),
536
+ "new-folder": () => void Ye(),
537
+ close: () => {
538
+ let e = X(), t = e == null ? null : S.windowFor(e);
539
+ t && S.requestClose(t);
540
+ },
541
+ copy: () => void Qe(),
542
+ paste: () => void nt(),
543
+ "select-all": () => {
544
+ let e = ke(X());
545
+ e && Y(P(e).map(I));
546
+ },
547
+ arrange: () => S.arrange(),
548
+ "clean-up": () => void Z(X()),
549
+ "empty-trash": () => void Xe()
550
+ }, $ = (e, t) => {
551
+ x(e) && p.gate(p.item(e), t);
552
+ };
553
+ if ($("open", () => !p.typing() && J().length > 0), $("new-folder", () => !u(C.get(), X())), $("close", () => X() != null), $("copy", () => !p.typing() && J().some((e) => !d(e.id))), $("paste", () => !p.typing() && !u(C.get(), X())), $("select-all", () => !p.typing()), $("arrange", () => !S.arranged()), $("empty-trash", () => f(C.get(), a) > 0), x("clean-up")) {
554
+ let e = p.item("clean-up");
555
+ p.gate(e, () => {
556
+ let t = X() == null ? "Clean Up Desktop" : "Clean Up Window";
557
+ return e.textContent !== t && (e.textContent = t), !0;
558
+ });
559
+ }
560
+ let at = !0, ot = (e) => {
561
+ let t = p.menus.find((t) => t.dataset.menu === e);
562
+ if (t) return t;
563
+ if (!at) throw Error(`vintage-frames/shell (finder): no ${e} menu; add to it from extend`);
564
+ let n = document.createElement("vf-menu");
565
+ n.dataset.menu = e, n.label = v.find((t) => t.menu === e).label;
566
+ let r = v.map((e) => e.menu), i = p.menus.findIndex((t) => r.indexOf(t.dataset.menu) > r.indexOf(e));
567
+ return p.menus.splice(i < 0 ? p.menus.length : i, 0, n), n;
568
+ }, st = {
569
+ catalog: C,
570
+ selection: J,
571
+ select: Y,
572
+ activeFolder: X,
573
+ open: ({ item: e, from: t = null } = {}) => {
574
+ e != null && W(e, t);
575
+ },
576
+ rename: qe,
577
+ cleanUp: Z,
578
+ iconFor: L,
579
+ addCommand(e) {
580
+ let t = ot(e.menu);
581
+ e.separator && t.append(document.createElement("vf-separator"));
582
+ let n = document.createElement("vf-menu-item");
583
+ return n.setAttribute("value", e.value), e.shortcut && n.setAttribute("shortcut", e.shortcut), n.textContent = e.label, t.append(n), it[e.value] = e.run, e.enabled && p.gate(n, e.enabled), n;
584
+ },
585
+ alertWith(e, t) {
586
+ Ee.set(e, t);
587
+ }
588
+ };
589
+ return i.extend?.(st, p), at = !1, p.onMenu((e) => it[e]?.()), p.onDispose(() => {
590
+ for (let [, e] of j()) e.remove();
591
+ for (let e of P(A)) e.remove();
592
+ De ? A.remove() : A.append(...Oe);
593
+ }), H(), st;
594
+ }
595
+ });
596
+ }
597
+ //#endregion
598
+ export { m as FINDER, b as finder };