vintage-frames 0.14.0 → 0.14.1

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