vintage-frames 0.18.0 → 0.19.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.
- package/README.md +1 -1
- package/custom-elements.json +278 -51
- package/dist/build/app-file.d.ts +2 -2
- package/dist/build/app-file.js +1 -0
- package/dist/build/plugins.d.ts +2 -2
- package/dist/build/plugins.js +62 -59
- package/dist/components/vf-icon.d.ts +7 -0
- package/dist/components/vf-icon.js +101 -81
- package/dist/components/vf-menu-bar.d.ts +6 -4
- package/dist/components/vf-menu-bar.js +26 -56
- package/dist/components/vf-menu-item.d.ts +33 -5
- package/dist/components/vf-menu-item.js +128 -61
- package/dist/components/vf-menu.d.ts +35 -0
- package/dist/components/vf-menu.js +171 -111
- package/dist/glyphs.d.ts +6 -0
- package/dist/glyphs.js +18 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -14
- package/dist/menu-navigation.d.ts +34 -0
- package/dist/menu-navigation.js +53 -0
- package/dist/menu-press.d.ts +25 -7
- package/dist/menu-press.js +78 -44
- package/dist/motion.d.ts +10 -0
- package/dist/shell/app-file.d.ts +20 -4
- package/dist/shell/app-file.js +65 -53
- package/dist/shell/catalog.d.ts +79 -1
- package/dist/shell/catalog.js +206 -153
- package/dist/shell/finder.d.ts +28 -9
- package/dist/shell/finder.js +339 -267
- package/dist/shell/geometry.d.ts +7 -0
- package/dist/shell/geometry.js +19 -3
- package/dist/shell/index.d.ts +4 -4
- package/dist/shell/index.js +12 -12
- package/dist/shell/pure.d.ts +1 -1
- package/dist/shell/pure.js +6 -6
- package/dist/shell/shell.d.ts +14 -10
- package/dist/shell/shell.js +148 -116
- package/dist/shell/version.d.ts +1 -1
- package/dist/shell/version.js +1 -1
- package/dist/styles/body-italic-font.d.ts +2 -0
- package/dist/styles/body-italic-font.js +10 -0
- package/dist/styles/register-embedded-font.d.ts +5 -4
- package/dist/styles/register-embedded-font.js +11 -10
- package/docs/SPEC.md +11 -7
- package/editor/vscode.html-custom-data.json +15 -5
- package/editor/web-types.json +55 -9
- package/package.json +7 -3
package/dist/menu-press.d.ts
CHANGED
|
@@ -21,8 +21,7 @@ export interface MenuPressTarget {
|
|
|
21
21
|
* driven: **press a title, keep the button down, slide onto a command, release
|
|
22
22
|
* over it to run it.** Sliding sideways onto another title switches menus
|
|
23
23
|
* mid-press; releasing over a disabled row, a separator, the title, or off the
|
|
24
|
-
* menu entirely closes with nothing chosen (the classic "release outside"
|
|
25
|
-
* cancel).
|
|
24
|
+
* menu entirely closes with nothing chosen (the classic "release outside").
|
|
26
25
|
*
|
|
27
26
|
* The modern click-to-open style coexists, disambiguated by the gesture itself
|
|
28
27
|
* and resolved at the first release: a quick in-place tap on a title (under
|
|
@@ -31,15 +30,28 @@ export interface MenuPressTarget {
|
|
|
31
30
|
* in-place release — any press that travels to another title or row is a
|
|
32
31
|
* drag-pick however long it took.
|
|
33
32
|
*
|
|
33
|
+
* **One pointer model for both.** While a menu is open the pointer is tracked
|
|
34
|
+
* with or without a button down; the button only changes what a release
|
|
35
|
+
* means. Each open menu highlights the row under the pointer, or, with the
|
|
36
|
+
* pointer elsewhere, the item whose submenu is open. The pointer resting on
|
|
37
|
+
* an item for {@link SUBMENU_OPEN_MS} opens its submenu, and an open submenu
|
|
38
|
+
* stays {@link SUBMENU_CLOSE_MS} after the pointer moves onto another row of
|
|
39
|
+
* its menu, so a diagonal slide into it can cross the rows between. A release
|
|
40
|
+
* on an item that opens a submenu chooses nothing: the submenu opens now, and
|
|
41
|
+
* every menu stays dropped for clicking on.
|
|
42
|
+
*
|
|
34
43
|
* Everything is hit-tested by **coordinates**, not by event target, for the
|
|
35
44
|
* same reason `vf-select` is: under touch, the pointer is implicitly captured
|
|
36
45
|
* by the element the gesture started on, so every move and the release itself
|
|
37
46
|
* are delivered to the pressed title no matter what they are actually over.
|
|
47
|
+
* The open menus are tried deepest first, since a submenu is painted over its
|
|
48
|
+
* parent.
|
|
38
49
|
*
|
|
39
50
|
* The host binds {@link onPointerDown} to a `pointerdown` on itself — presses
|
|
40
|
-
* on titles and rows both bubble up composed —
|
|
41
|
-
* {@link MenuPressTarget}. Everything
|
|
42
|
-
* the page, the
|
|
51
|
+
* on titles and rows both bubble up composed — calls {@link track} as its
|
|
52
|
+
* menus open and close, and supplies a {@link MenuPressTarget}. Everything
|
|
53
|
+
* else (tracking to the release anywhere on the page, the highlight, the
|
|
54
|
+
* submenus, classification) lives here.
|
|
43
55
|
*/
|
|
44
56
|
export declare class MenuPressController implements ReactiveController {
|
|
45
57
|
#private;
|
|
@@ -47,10 +59,16 @@ export declare class MenuPressController implements ReactiveController {
|
|
|
47
59
|
constructor(host: ReactiveControllerHost, target: MenuPressTarget);
|
|
48
60
|
/**
|
|
49
61
|
* Host torn down mid-gesture. The listener controller detaches itself; drop
|
|
50
|
-
* the press
|
|
51
|
-
*
|
|
62
|
+
* the press and tracking state, which the normal close path is no longer
|
|
63
|
+
* going to run for.
|
|
52
64
|
*/
|
|
53
65
|
hostDisconnected(): void;
|
|
66
|
+
/**
|
|
67
|
+
* The host opened (`true`) or closed (`false`) its menus. While one is open
|
|
68
|
+
* the pointer is tracked with or without a button down, so a resting mouse
|
|
69
|
+
* highlights rows and opens submenus in the click-to-open style too.
|
|
70
|
+
*/
|
|
71
|
+
track(open: boolean): void;
|
|
54
72
|
/**
|
|
55
73
|
* Starts a press: drops the menu under the pointer if it isn't already, then
|
|
56
74
|
* tracks the press to its release. Both interaction styles begin here; the
|
package/dist/menu-press.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DocumentListenersController as e } from "./document-listeners.js";
|
|
2
2
|
import "./motion.js";
|
|
3
|
+
import { openPath as t } from "./menu-navigation.js";
|
|
3
4
|
//#region src/menu-press.ts
|
|
4
|
-
var
|
|
5
|
+
var n = class {
|
|
5
6
|
#e;
|
|
6
7
|
#t;
|
|
7
8
|
#n;
|
|
@@ -9,89 +10,122 @@ var t = class {
|
|
|
9
10
|
#i;
|
|
10
11
|
#a;
|
|
11
12
|
#o;
|
|
13
|
+
#s;
|
|
14
|
+
#c;
|
|
15
|
+
#l;
|
|
12
16
|
constructor(t, n) {
|
|
13
|
-
this.target = n, this.#e = !1, this.#t = !1, this.#n = !1, this.#r = null, this.#i = 0, this.#a = null, this.onPointerDown = (e) => {
|
|
17
|
+
this.target = n, this.#e = !1, this.#t = !1, this.#n = !1, this.#r = null, this.#i = 0, this.#a = !1, this.#o = !1, this.#s = null, this.onPointerDown = (e) => {
|
|
14
18
|
if (e.button > 0 || !e.isPrimary) return;
|
|
15
|
-
let t = this.#
|
|
16
|
-
if (t) {
|
|
17
|
-
if (e.preventDefault(), this.#e = !0, this.#n = !1, this.#r = t.item ?? t.menu, this.#i = e.timeStamp, this.#t = !t.menu.open, this.#
|
|
18
|
-
this.#
|
|
19
|
+
let t = this.#_(e.clientX, e.clientY);
|
|
20
|
+
if (!(!t || !t.title && !t.item)) {
|
|
21
|
+
if (e.preventDefault(), this.#e = !0, this.#n = !1, this.#r = t.item ?? t.menu, this.#i = e.timeStamp, this.#t = !t.menu.open, this.#l.attach(), t.item) {
|
|
22
|
+
this.#h(t);
|
|
19
23
|
return;
|
|
20
24
|
}
|
|
21
25
|
t.menu.focus(), this.#t && this.target.open(t.menu);
|
|
22
26
|
}
|
|
23
|
-
}, this.#
|
|
24
|
-
if (
|
|
25
|
-
e.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
}, this.#u = (e) => {
|
|
28
|
+
if (this.#o) return;
|
|
29
|
+
let t = this.#_(e.clientX, e.clientY);
|
|
30
|
+
if (this.#e) {
|
|
31
|
+
e.preventDefault();
|
|
32
|
+
let n = t ? t.item ?? (t.title ? t.menu : null) : null;
|
|
33
|
+
!this.#n && n !== this.#r && (this.#n = !0), t?.title && !t.menu.open && this.target.open(t.menu);
|
|
34
|
+
}
|
|
35
|
+
this.#h(t);
|
|
36
|
+
}, this.#d = (e) => {
|
|
29
37
|
if (!this.#e) return;
|
|
30
|
-
let t = this.#
|
|
31
|
-
this.#
|
|
32
|
-
}, this.#
|
|
33
|
-
this.#
|
|
34
|
-
}, t.addController(this), this.#
|
|
38
|
+
let t = this.#_(e.clientX, e.clientY), n = this.#t, r = !this.#n, i = e.timeStamp - this.#i < 200;
|
|
39
|
+
this.#p(), !(n && r && i) && this.#m(t && !t.title ? t : null);
|
|
40
|
+
}, this.#f = () => {
|
|
41
|
+
this.#p(), this.#h(null);
|
|
42
|
+
}, t.addController(this), this.#l = new e(t, () => [
|
|
35
43
|
[
|
|
36
44
|
document,
|
|
37
45
|
"pointermove",
|
|
38
|
-
this.#
|
|
46
|
+
this.#u,
|
|
39
47
|
!0
|
|
40
48
|
],
|
|
41
49
|
[
|
|
42
50
|
document,
|
|
43
51
|
"pointerup",
|
|
44
|
-
this.#
|
|
52
|
+
this.#d,
|
|
45
53
|
!0
|
|
46
54
|
],
|
|
47
55
|
[
|
|
48
56
|
document,
|
|
49
57
|
"pointercancel",
|
|
50
|
-
this.#
|
|
58
|
+
this.#f,
|
|
51
59
|
!0
|
|
52
60
|
]
|
|
53
61
|
]);
|
|
54
62
|
}
|
|
55
63
|
hostDisconnected() {
|
|
56
|
-
this.#
|
|
64
|
+
this.#p(), this.track(!1);
|
|
57
65
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
track(e) {
|
|
67
|
+
if (this.#a = e, e) {
|
|
68
|
+
this.#l.attach();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.#o = !1, this.#s = null, this.#g(), this.#e || this.#l.detach();
|
|
63
72
|
}
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
#u;
|
|
74
|
+
#d;
|
|
75
|
+
#f;
|
|
76
|
+
#p() {
|
|
77
|
+
this.#e && (this.#e = !1, this.#r = null, this.#a || this.#l.detach());
|
|
78
|
+
}
|
|
79
|
+
#m(e) {
|
|
80
|
+
let t = e?.item;
|
|
81
|
+
if (!e || !t || t.disabled) {
|
|
82
|
+
this.target.close();
|
|
67
83
|
return;
|
|
68
84
|
}
|
|
69
|
-
this.#
|
|
85
|
+
if (this.#g(), t.submenu) {
|
|
86
|
+
e.menu.expand(t);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.#h(e), this.#o = !0, t.activate();
|
|
90
|
+
}
|
|
91
|
+
#h(e) {
|
|
92
|
+
let n = e && !e.title ? {
|
|
93
|
+
menu: e.menu,
|
|
94
|
+
row: e.item && !e.item.disabled ? e.item : null
|
|
95
|
+
} : null, r = this.#s;
|
|
96
|
+
if (r?.menu === n?.menu && r?.row === n?.row) return;
|
|
97
|
+
this.#s = n;
|
|
98
|
+
for (let e of this.target.menus()) if (e.open) for (let r of t(e)) r.pointerOver(r === n?.menu ? n.row : void 0);
|
|
99
|
+
if (this.#g(), !n) return;
|
|
100
|
+
let { menu: i, row: a } = n, o = i.expandedItem;
|
|
101
|
+
(a === null || a !== o) && (o ? this.#c = window.setTimeout(() => i.expand(a?.submenu ? a : null), 300) : a?.submenu && (this.#c = window.setTimeout(() => i.expand(a), 150)));
|
|
70
102
|
}
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
t !== this.#a && (this.#a && (this.#a.active = !1), this.#a = t, t && (t.active = !0));
|
|
103
|
+
#g() {
|
|
104
|
+
this.#c !== void 0 && window.clearTimeout(this.#c), this.#c = void 0;
|
|
74
105
|
}
|
|
75
|
-
#
|
|
76
|
-
let
|
|
77
|
-
if (i) {
|
|
78
|
-
|
|
106
|
+
#_(e, n) {
|
|
107
|
+
let i = this.target.menus(), a = i.find((e) => e.open);
|
|
108
|
+
if (a) for (let i of t(a).reverse()) {
|
|
109
|
+
let t = i.panelRect;
|
|
110
|
+
if (!(!t || !r(t, e, n))) return {
|
|
79
111
|
menu: i,
|
|
80
|
-
|
|
112
|
+
title: !1,
|
|
113
|
+
item: i.allItems.find((t) => r(t.getBoundingClientRect(), e, n)) ?? null
|
|
81
114
|
};
|
|
82
115
|
}
|
|
83
|
-
for (let
|
|
84
|
-
let
|
|
85
|
-
if (
|
|
86
|
-
menu:
|
|
116
|
+
for (let t of i) {
|
|
117
|
+
let i = t.labelRect;
|
|
118
|
+
if (i && r(i, e, n)) return {
|
|
119
|
+
menu: t,
|
|
120
|
+
title: !0,
|
|
87
121
|
item: null
|
|
88
122
|
};
|
|
89
123
|
}
|
|
90
124
|
return null;
|
|
91
125
|
}
|
|
92
126
|
};
|
|
93
|
-
function
|
|
127
|
+
function r(e, t, n) {
|
|
94
128
|
return t >= e.left && t < e.right && n >= e.top && n < e.bottom;
|
|
95
129
|
}
|
|
96
130
|
//#endregion
|
|
97
|
-
export {
|
|
131
|
+
export { n as MenuPressController };
|
package/dist/motion.d.ts
CHANGED
|
@@ -19,6 +19,16 @@ export declare function prefersReducedMotion(): boolean;
|
|
|
19
19
|
* drag-pick regardless of duration.
|
|
20
20
|
*/
|
|
21
21
|
export declare const PRESS_HOLD_MS = 200;
|
|
22
|
+
/**
|
|
23
|
+
* How long (ms) the pointer rests on a menu item before its submenu opens,
|
|
24
|
+
* and how long it may stray onto another row of the same menu before an open
|
|
25
|
+
* submenu closes. The second is the longer, so a diagonal slide from an item
|
|
26
|
+
* into its submenu can cross the rows between. Not gated on
|
|
27
|
+
* `prefers-reduced-motion`: they are the interaction, not decoration, the
|
|
28
|
+
* reasoning {@link MENU_SCROLL_INTERVAL_MS} gives. Provisional, tuned by hand.
|
|
29
|
+
*/
|
|
30
|
+
export declare const SUBMENU_OPEN_MS = 150;
|
|
31
|
+
export declare const SUBMENU_CLOSE_MS = 300;
|
|
22
32
|
/**
|
|
23
33
|
* How long (ms) a press on a selected icon's name waits before it opens the
|
|
24
34
|
* rename box — long enough that a double-click has already declared itself.
|
package/dist/shell/app-file.d.ts
CHANGED
|
@@ -5,13 +5,21 @@
|
|
|
5
5
|
* the chunks and any decoder skips them.
|
|
6
6
|
*
|
|
7
7
|
* This is the reading half: the reader, checking a version against a range,
|
|
8
|
-
* putting versions in order,
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `vintage-frames/build`'s.
|
|
8
|
+
* putting versions in order, the app API levels and whether this kit runs an
|
|
9
|
+
* application, and the scale every box is drawn at. It is pure and runs the
|
|
10
|
+
* same under Node and in a page, through the platform's compression streams.
|
|
11
|
+
* Writing an app file, and the box, are `vintage-frames/build`'s.
|
|
12
12
|
*/
|
|
13
13
|
/** The app file format this kit reads and writes. */
|
|
14
14
|
export declare const APP_FILE_FORMAT = 1;
|
|
15
|
+
/**
|
|
16
|
+
* The app API this kit provides: the level of what a built application can
|
|
17
|
+
* use of it. It goes up when something in it changes or goes away, and never
|
|
18
|
+
* for an addition. app-api.json lists what it covers.
|
|
19
|
+
*/
|
|
20
|
+
export declare const APP_API = 2;
|
|
21
|
+
/** The oldest app API this kit still runs. */
|
|
22
|
+
export declare const APP_API_OLDEST = 2;
|
|
15
23
|
/**
|
|
16
24
|
* One system px of an app file's box, in its picture's px: every box of
|
|
17
25
|
* this format is drawn at 3×, each system px a 3 × 3 block.
|
|
@@ -29,6 +37,8 @@ export interface AppManifest {
|
|
|
29
37
|
version: string;
|
|
30
38
|
/** The kit range the code was built and checked against: `^0.17.0`. */
|
|
31
39
|
requires: string;
|
|
40
|
+
/** The app API the code was built against, {@link APP_API}. A file from before levels has none. */
|
|
41
|
+
api?: number;
|
|
32
42
|
author: string;
|
|
33
43
|
/** What the application is, in a sentence or two of plain text. */
|
|
34
44
|
description?: string;
|
|
@@ -97,3 +107,9 @@ export declare function compareVersions(a: string, b: string): number;
|
|
|
97
107
|
* false.
|
|
98
108
|
*/
|
|
99
109
|
export declare function satisfies(version: string, range: string): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Whether this kit runs the application a manifest describes: one built at
|
|
112
|
+
* an app API from {@link APP_API_OLDEST} to {@link APP_API}, or, for a file
|
|
113
|
+
* from before levels, one whose `requires` this kit's version meets.
|
|
114
|
+
*/
|
|
115
|
+
export declare function appRuns(manifest: Pick<AppManifest, 'requires' | 'api'>): boolean;
|
package/dist/shell/app-file.js
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
+
import { VERSION as e } from "./version.js";
|
|
1
2
|
//#region src/shell/app-file.ts
|
|
2
|
-
var
|
|
3
|
+
var t = 1, n = 2, r = 2, i = 3, a = "vintage-frames.app", o = "vintage-frames.code", s = [
|
|
3
4
|
"id",
|
|
4
5
|
"name",
|
|
5
6
|
"version",
|
|
6
7
|
"requires",
|
|
8
|
+
"api",
|
|
7
9
|
"author",
|
|
8
10
|
"description",
|
|
9
11
|
"icon"
|
|
10
|
-
],
|
|
12
|
+
], c = Uint8Array.of(137, 80, 78, 71, 13, 10, 26, 10), l = Uint32Array.from({ length: 256 }, (e, t) => {
|
|
11
13
|
let n = t;
|
|
12
14
|
for (let e = 0; e < 8; e++) n = n & 1 ? 3988292384 ^ n >>> 1 : n >>> 1;
|
|
13
15
|
return n >>> 0;
|
|
14
16
|
});
|
|
15
|
-
function
|
|
17
|
+
function u(e) {
|
|
16
18
|
let t = 4294967295;
|
|
17
|
-
for (let n of e) t =
|
|
19
|
+
for (let n of e) t = l[(t ^ n) & 255] ^ t >>> 8;
|
|
18
20
|
return (t ^ 4294967295) >>> 0;
|
|
19
21
|
}
|
|
20
|
-
function
|
|
21
|
-
if (e.length < 8 ||
|
|
22
|
+
function d(e) {
|
|
23
|
+
if (e.length < 8 || c.some((t, n) => e[n] !== t)) return null;
|
|
22
24
|
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = [], r = 8;
|
|
23
25
|
for (; r + 12 <= e.length;) {
|
|
24
26
|
let i = r + 12 + t.getUint32(r);
|
|
25
|
-
if (i > e.length ||
|
|
27
|
+
if (i > e.length || u(e.subarray(r + 4, i - 4)) !== t.getUint32(i - 4)) return null;
|
|
26
28
|
let a = String.fromCharCode(...e.subarray(r + 4, r + 8));
|
|
27
29
|
if (n.push({
|
|
28
30
|
type: a,
|
|
@@ -34,85 +36,91 @@ function c(e) {
|
|
|
34
36
|
}
|
|
35
37
|
return null;
|
|
36
38
|
}
|
|
37
|
-
function
|
|
39
|
+
function f(e) {
|
|
38
40
|
let t = e.indexOf(0);
|
|
39
41
|
return t > 0 ? String.fromCharCode(...e.subarray(0, t)) : "";
|
|
40
42
|
}
|
|
41
|
-
var
|
|
42
|
-
async function
|
|
43
|
+
var p = new TextDecoder("utf-8", { fatal: !0 });
|
|
44
|
+
async function m(e) {
|
|
43
45
|
let t = e.indexOf(0), n = e[t + 1], r = e[t + 2], i = e.indexOf(0, t + 3), a = i < 0 ? -1 : e.indexOf(0, i + 1);
|
|
44
46
|
if (t < 1 || a < 0 || n > 1 || r !== 0) throw Error("a broken iTXt chunk");
|
|
45
47
|
let o = e.subarray(a + 1);
|
|
46
|
-
return
|
|
48
|
+
return p.decode(n ? await h(o) : o);
|
|
47
49
|
}
|
|
48
|
-
async function
|
|
50
|
+
async function h(e) {
|
|
49
51
|
let t = new Blob([e.slice()]).stream().pipeThrough(new DecompressionStream("deflate"));
|
|
50
52
|
return new Uint8Array(await new Response(t).arrayBuffer());
|
|
51
53
|
}
|
|
52
|
-
async function
|
|
54
|
+
async function g(e) {
|
|
53
55
|
let t = new Blob([e.slice()]).stream().pipeThrough(new CompressionStream("deflate"));
|
|
54
56
|
return new Uint8Array(await new Response(t).arrayBuffer());
|
|
55
57
|
}
|
|
56
|
-
function
|
|
58
|
+
function _(e) {
|
|
57
59
|
if (!e || typeof e != "object") return "its manifest is not an object";
|
|
58
60
|
let t = e;
|
|
59
61
|
if (t.format !== 1) return typeof t.format == "number" ? `it is format ${t.format}, and this kit reads format 1` : "its manifest has no format";
|
|
60
62
|
let n = { format: 1 };
|
|
61
|
-
for (let e of
|
|
63
|
+
for (let e of s) {
|
|
62
64
|
let r = t[e];
|
|
65
|
+
if (e === "api") {
|
|
66
|
+
if (r === void 0) continue;
|
|
67
|
+
if (!Number.isInteger(r) || r < 1) return `its api, ${JSON.stringify(r)}, is not a level`;
|
|
68
|
+
n.api = r;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
63
71
|
if (e === "description") {
|
|
64
72
|
if (r !== void 0 && typeof r != "string") return "its description is not text";
|
|
65
73
|
typeof r == "string" && r.trim() && (n.description = r);
|
|
66
74
|
continue;
|
|
67
75
|
}
|
|
68
76
|
if (typeof r != "string" || !r) return `its manifest has no ${e}`;
|
|
69
|
-
if (e === "version" && !
|
|
70
|
-
if (e === "requires" && !
|
|
77
|
+
if (e === "version" && !S(r)) return `its version, ${r}, is not a version`;
|
|
78
|
+
if (e === "requires" && !C(r)) return `its requires, ${r}, is not a range`;
|
|
71
79
|
n[e] = r;
|
|
72
80
|
}
|
|
73
81
|
return n;
|
|
74
82
|
}
|
|
75
|
-
async function
|
|
76
|
-
let t =
|
|
83
|
+
async function v(e) {
|
|
84
|
+
let t = d(e);
|
|
77
85
|
if (!t) return "it is not a whole PNG";
|
|
78
|
-
let
|
|
79
|
-
for (let { type: e, data:
|
|
86
|
+
let n = /* @__PURE__ */ new Map();
|
|
87
|
+
for (let { type: e, data: r } of t) {
|
|
80
88
|
if (e !== "iTXt") continue;
|
|
81
|
-
let t =
|
|
89
|
+
let t = f(r);
|
|
82
90
|
if (t === "vintage-frames.app" || t === "vintage-frames.code") {
|
|
83
|
-
if (
|
|
84
|
-
|
|
91
|
+
if (n.has(t)) return `it has two ${t} chunks`;
|
|
92
|
+
n.set(t, r);
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
|
-
let
|
|
88
|
-
if (!
|
|
89
|
-
if (!
|
|
90
|
-
if (!
|
|
95
|
+
let r = n.get(a), i = n.get(o);
|
|
96
|
+
if (!r && !i) return "it carries no application";
|
|
97
|
+
if (!r) return "its manifest is missing";
|
|
98
|
+
if (!i) return "its code is missing";
|
|
91
99
|
let s;
|
|
92
100
|
try {
|
|
93
|
-
s = JSON.parse(await
|
|
101
|
+
s = JSON.parse(await m(r));
|
|
94
102
|
} catch {
|
|
95
103
|
return "its manifest does not read";
|
|
96
104
|
}
|
|
97
|
-
let
|
|
98
|
-
if (typeof
|
|
105
|
+
let c = _(s);
|
|
106
|
+
if (typeof c == "string") return c;
|
|
99
107
|
try {
|
|
100
108
|
return {
|
|
101
|
-
manifest:
|
|
102
|
-
code: await
|
|
109
|
+
manifest: c,
|
|
110
|
+
code: await m(i)
|
|
103
111
|
};
|
|
104
112
|
} catch {
|
|
105
113
|
return "its code does not inflate";
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
|
-
async function
|
|
109
|
-
let t = await
|
|
116
|
+
async function y(e) {
|
|
117
|
+
let t = await v(e);
|
|
110
118
|
return typeof t == "string" ? null : t;
|
|
111
119
|
}
|
|
112
|
-
var
|
|
113
|
-
function
|
|
120
|
+
var b = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
121
|
+
function x(e) {
|
|
114
122
|
if (typeof e != "string") return null;
|
|
115
|
-
let t =
|
|
123
|
+
let t = b.exec(e.trim().replace(/^v/, ""));
|
|
116
124
|
return t ? {
|
|
117
125
|
core: [
|
|
118
126
|
Number(t[1]),
|
|
@@ -122,18 +130,18 @@ function v(e) {
|
|
|
122
130
|
pre: t[4] ? t[4].split(".") : []
|
|
123
131
|
} : null;
|
|
124
132
|
}
|
|
125
|
-
function
|
|
126
|
-
return
|
|
133
|
+
function S(e) {
|
|
134
|
+
return b.test(e);
|
|
127
135
|
}
|
|
128
|
-
function
|
|
129
|
-
return
|
|
136
|
+
function C(e) {
|
|
137
|
+
return S(e.startsWith("^") ? e.slice(1) : e);
|
|
130
138
|
}
|
|
131
|
-
function
|
|
139
|
+
function w(e) {
|
|
132
140
|
if (typeof e != "string") return null;
|
|
133
141
|
let t = e.trim();
|
|
134
|
-
return
|
|
142
|
+
return x(t.startsWith("^") ? t.slice(1) : t);
|
|
135
143
|
}
|
|
136
|
-
function
|
|
144
|
+
function T(e, t) {
|
|
137
145
|
for (let n = 0; n < 3; n++) if (e.core[n] !== t.core[n]) return e.core[n] - t.core[n];
|
|
138
146
|
if (!e.pre.length || !t.pre.length) return t.pre.length - e.pre.length;
|
|
139
147
|
for (let n = 0; n < Math.max(e.pre.length, t.pre.length); n++) {
|
|
@@ -146,14 +154,14 @@ function S(e, t) {
|
|
|
146
154
|
}
|
|
147
155
|
return 0;
|
|
148
156
|
}
|
|
149
|
-
function
|
|
150
|
-
let n =
|
|
151
|
-
return n && r ?
|
|
157
|
+
function E(e, t) {
|
|
158
|
+
let n = x(e), r = x(t);
|
|
159
|
+
return n && r ? T(n, r) : !!n - +!!r;
|
|
152
160
|
}
|
|
153
|
-
function
|
|
154
|
-
let n =
|
|
161
|
+
function D(e, t) {
|
|
162
|
+
let n = x(e), r = w(t);
|
|
155
163
|
if (!n || !r) return !1;
|
|
156
|
-
if (!t.trim().startsWith("^")) return
|
|
164
|
+
if (!t.trim().startsWith("^")) return T(n, r) === 0;
|
|
157
165
|
if (n.pre.length && !(r.pre.length && n.core.every((e, t) => e === r.core[t]))) return !1;
|
|
158
166
|
let [i, a, o] = r.core, s = {
|
|
159
167
|
core: i ? [
|
|
@@ -171,7 +179,11 @@ function w(e, t) {
|
|
|
171
179
|
],
|
|
172
180
|
pre: []
|
|
173
181
|
};
|
|
174
|
-
return
|
|
182
|
+
return T(n, r) >= 0 && T(n, s) < 0;
|
|
183
|
+
}
|
|
184
|
+
function O(t) {
|
|
185
|
+
let { api: n } = t;
|
|
186
|
+
return n === void 0 ? D(e, t.requires) : Number.isInteger(n) && n >= 2 && n <= 2;
|
|
175
187
|
}
|
|
176
188
|
//#endregion
|
|
177
|
-
export {
|
|
189
|
+
export { n as APP_API, r as APP_API_OLDEST, t as APP_FILE_FORMAT, i as BOX_SCALE, o as CODE_KEYWORD, a as MANIFEST_KEYWORD, c as PNG_SIGNATURE, O as appRuns, E as compareVersions, u as crc32, g as deflate, h as inflate, v as inspectAppFile, S as isVersion, f as itxtKeyword, _ as manifestOf, d as pngChunks, y as readAppFile, D as satisfies };
|
package/dist/shell/catalog.d.ts
CHANGED
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
* never renamed, moved, copied or removed; nothing is made in the Trash.
|
|
14
14
|
* Deleting is a move into the Trash, and only Empty Trash removes. A
|
|
15
15
|
* volume's position is stored on a record of its own id.
|
|
16
|
+
* - The System Folder is kept the same way when the site names it: a folder
|
|
17
|
+
* on the startup disk (the desktop without one) holding Apple Menu Items
|
|
18
|
+
* and Startup Items, listed after the volumes. What they hold is anyone's,
|
|
19
|
+
* and the shell reads it: the Apple menu, and what opens at startup.
|
|
20
|
+
* - An alias stands for another item: its data names the original's id and
|
|
21
|
+
* kind, and `resolve` finds the original wherever it moved, until it is
|
|
22
|
+
* removed. An alias of a container takes a drop for its original, and
|
|
23
|
+
* keeps taking one, to say so, once the original is gone.
|
|
16
24
|
* - A folder never goes into itself or a folder inside it. A parent with no
|
|
17
25
|
* record reads as the desktop.
|
|
18
26
|
* - An item whose kind no application registers is left out of the listing
|
|
@@ -30,17 +38,25 @@ import type { Point } from './geometry.js';
|
|
|
30
38
|
export declare const TRASH = "trash";
|
|
31
39
|
/** The startup disk's id. */
|
|
32
40
|
export declare const DISK = "disk";
|
|
41
|
+
/** The System Folder's id: kept on the startup disk when the site names it. */
|
|
42
|
+
export declare const SYSTEM_FOLDER = "system-folder";
|
|
43
|
+
/** Apple Menu Items' id, in the System Folder: what it holds is the Apple menu. */
|
|
44
|
+
export declare const APPLE_MENU_ITEMS = "apple-menu-items";
|
|
45
|
+
/** Startup Items' id, in the System Folder: what it holds opens at startup. */
|
|
46
|
+
export declare const STARTUP_ITEMS = "startup-items";
|
|
33
47
|
/** A folder's kind. */
|
|
34
48
|
export declare const FOLDER = "folder";
|
|
35
49
|
/** An application's icon: the kind the shell registers, whose data names the application it opens. */
|
|
36
50
|
export declare const APP_KIND = "app";
|
|
51
|
+
/** An alias: the kind the shell registers, whose data names the item it stands for. */
|
|
52
|
+
export declare const ALIAS_KIND = "alias";
|
|
37
53
|
/** The name a new folder takes, counted up where it is taken. */
|
|
38
54
|
export declare const UNTITLED_FOLDER = "untitled folder";
|
|
39
55
|
/** One item of the catalog. */
|
|
40
56
|
export interface Item {
|
|
41
57
|
id: string;
|
|
42
58
|
name: string;
|
|
43
|
-
/** `folder`, a volume's (`trash`, `disk`), the shell's `app`, or a kind an application registers. */
|
|
59
|
+
/** `folder`, a volume's (`trash`, `disk`), the shell's `app` or `alias`, or a kind an application registers. */
|
|
44
60
|
kind: string;
|
|
45
61
|
/** A folder's id, a volume's, or null for the desktop. */
|
|
46
62
|
parent: string | null;
|
|
@@ -78,9 +94,17 @@ export interface Volumes {
|
|
|
78
94
|
trash?: string | false;
|
|
79
95
|
disk?: string | false;
|
|
80
96
|
}
|
|
97
|
+
/** The System Folder and its two folders, by name. A site that names them has them. */
|
|
98
|
+
export interface SystemFolders {
|
|
99
|
+
folder: string;
|
|
100
|
+
appleMenu: string;
|
|
101
|
+
startup: string;
|
|
102
|
+
}
|
|
81
103
|
export interface CatalogOptions {
|
|
82
104
|
storage: CatalogStorage | null;
|
|
83
105
|
volumes?: Volumes;
|
|
106
|
+
/** The System Folder, on the startup disk. Unset, none. */
|
|
107
|
+
system?: SystemFolders;
|
|
84
108
|
/** Whether an application registers `kind`. Folders are always listed. Default: every kind. */
|
|
85
109
|
listed?(kind: string): boolean;
|
|
86
110
|
/** A kind's payload hooks. */
|
|
@@ -109,10 +133,22 @@ export interface CatalogArchive {
|
|
|
109
133
|
export declare const isContainerKind: (kind: string) => boolean;
|
|
110
134
|
/** Whether `id` names a volume. */
|
|
111
135
|
export declare const isVolume: (id: string | null | undefined) => boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Whether `id` names a container the catalog keeps, never renamed, moved,
|
|
138
|
+
* copied or removed: a volume, the System Folder or a folder in it.
|
|
139
|
+
*/
|
|
140
|
+
export declare const isKept: (id: string | null | undefined) => boolean;
|
|
112
141
|
/** The application an `app` item stands for: its `data.app`, or null. */
|
|
113
142
|
export declare function appIdOf(item: Item): string | null;
|
|
143
|
+
/** The id of the item an alias stands for: its `data.original`, or null for anything but an alias. */
|
|
144
|
+
export declare function originalOf(item: Item): string | null;
|
|
114
145
|
/** The item with `id`, or null. */
|
|
115
146
|
export declare function itemOf(state: CatalogState, id: string | null | undefined): Item | null;
|
|
147
|
+
/**
|
|
148
|
+
* The item `id` names, or the original an alias stands for, through an alias
|
|
149
|
+
* of an alias too. Null once the original is gone, and for a chain that loops.
|
|
150
|
+
*/
|
|
151
|
+
export declare function resolve(state: CatalogState, id: string | null | undefined): Item | null;
|
|
116
152
|
/** The container `parent` resolves to: that container while it is listed, else the desktop (null). */
|
|
117
153
|
export declare function containerOf(state: CatalogState, parent: string | null | undefined): string | null;
|
|
118
154
|
/** The items directly in a container (null: the desktop), in listing order. */
|
|
@@ -132,6 +168,26 @@ export declare function isInside(state: CatalogState, id: string, ancestor: stri
|
|
|
132
168
|
export declare function enclosingFolders(state: CatalogState, id: string | null | undefined): string[];
|
|
133
169
|
/** Whether `id` is the Trash or anything inside it. */
|
|
134
170
|
export declare function isTrashed(state: CatalogState, id: string | null | undefined): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Whether Make Alias takes item `id`: an application, a document, a folder
|
|
173
|
+
* or the startup disk, or an alias of one, outside the Trash. Never the
|
|
174
|
+
* Trash itself, and never an alias whose original is gone.
|
|
175
|
+
*/
|
|
176
|
+
export declare function canAlias(state: CatalogState, id: string | null | undefined): boolean;
|
|
177
|
+
/** What a drop onto an item files into: a container's id, or the alias of a container whose original is gone. */
|
|
178
|
+
export type DropTarget = {
|
|
179
|
+
folder: string;
|
|
180
|
+
} | {
|
|
181
|
+
missing: Item;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* What a drop onto item `id` files into. A container takes it itself, and
|
|
185
|
+
* an alias of one passes it to the original, so filing judges the original:
|
|
186
|
+
* a folder never goes into itself through an alias either. An alias of a
|
|
187
|
+
* container whose original is gone still takes the drop and files nothing:
|
|
188
|
+
* `missing`, the alias. Anything else takes none: null.
|
|
189
|
+
*/
|
|
190
|
+
export declare function dropTargetOf(state: CatalogState, id: string | null | undefined): DropTarget | null;
|
|
135
191
|
/** Everything under a container, each container before what it holds; a loop is walked once. */
|
|
136
192
|
export declare function descendantsOf(state: CatalogState, parent: string | null): Item[];
|
|
137
193
|
/** The first free folder name in a container: "untitled folder", "untitled folder 2", … */
|
|
@@ -142,6 +198,28 @@ export declare function nextFolderName(state: CatalogState, parent: string | nul
|
|
|
142
198
|
* then " copy 2", " copy 3", …
|
|
143
199
|
*/
|
|
144
200
|
export declare function copyName(state: CatalogState, parent: string | null, name: string, kind: string): string;
|
|
201
|
+
/** The name for an alias of `name` in a container: "name alias", then "name alias 2", … while an alias there has it. */
|
|
202
|
+
export declare function aliasName(state: CatalogState, parent: string | null, name: string): string;
|
|
203
|
+
/** What Apple Menu Items holds, by name: the Apple menu's entries. None without the System Folder. */
|
|
204
|
+
export declare const appleMenuItemsOf: (state: CatalogState) => Item[];
|
|
205
|
+
/** What Startup Items holds, by name: what opens at startup. None without the System Folder. */
|
|
206
|
+
export declare const startupItemsOf: (state: CatalogState) => Item[];
|
|
207
|
+
/** One entry of the Apple menu, and what it holds when it is a folder's. */
|
|
208
|
+
export interface AppleMenuEntry {
|
|
209
|
+
/** The entry's own item: an alias stays the alias. */
|
|
210
|
+
item: Item;
|
|
211
|
+
/** What the folder holds, or the folder an alias stands for, by name. */
|
|
212
|
+
entries?: AppleMenuEntry[];
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* The Apple menu as a tree: what Apple Menu Items holds, by name, and for a
|
|
216
|
+
* folder in it, or an alias of one, what that folder holds, the same way,
|
|
217
|
+
* down to five levels below the menu. A folder already on the way down
|
|
218
|
+
* (Apple Menu Items starts it), an empty folder and a folder past the fifth
|
|
219
|
+
* level have no entries, so the tree never loops. None without the System
|
|
220
|
+
* Folder.
|
|
221
|
+
*/
|
|
222
|
+
export declare function appleMenuOf(state: CatalogState): AppleMenuEntry[];
|
|
145
223
|
/** The catalog's operations, over its listing. */
|
|
146
224
|
export interface Catalog {
|
|
147
225
|
get(): CatalogState;
|