vintage-frames 0.14.1 → 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.
- package/custom-elements.json +94 -14
- package/dist/components/vf-button.d.ts +5 -1
- package/dist/components/vf-button.js +1 -1
- package/dist/components/vf-dialog.d.ts +7 -1
- package/dist/events.d.ts +3 -2
- package/dist/events.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/modal-dialog.d.ts +31 -4
- package/dist/modal-dialog.js +98 -82
- package/dist/position.js +25 -20
- package/dist/shell/alert.d.ts +17 -9
- package/dist/shell/alert.js +25 -28
- package/dist/shell/finder.d.ts +41 -1
- package/dist/shell/finder.js +212 -178
- package/dist/shell/index.d.ts +1 -3
- package/dist/shell/index.js +5 -6
- package/dist/shell/shell.d.ts +25 -11
- package/dist/shell/shell.js +143 -122
- package/dist/shell/windows.d.ts +21 -2
- package/dist/shell/windows.js +169 -125
- package/dist/text-control.d.ts +6 -0
- package/dist/text-control.js +2 -2
- package/docs/SPEC.md +5 -5
- package/editor/vscode.html-custom-data.json +2 -2
- package/editor/web-types.json +11 -6
- package/package.json +1 -1
package/dist/shell/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type { AppContext, AppDefinition, CatalogSetup, KindDefinition, Shell, Sh
|
|
|
14
14
|
export { createWindowManager, focusInto } from './windows.js';
|
|
15
15
|
export type { AdoptOptions, ArrangeGroup, BoxInput, FocusHome, HomeBox, OpenOptions, PlacePolicy, Placed, WindowManager, WindowManagerOptions, } from './windows.js';
|
|
16
16
|
export { finder, FINDER } from './finder.js';
|
|
17
|
-
export type { FinderApi, FinderArt, FinderCommand, FinderCommandSpec, FinderMenu, FinderOpen, FinderOptions, } from './finder.js';
|
|
17
|
+
export type { FinderAlert, FinderAlertHandler, FinderAlerts, FinderApi, FinderArt, FinderCommand, FinderCommandSpec, FinderFailedAction, FinderMenu, FinderOpen, FinderOptions, } from './finder.js';
|
|
18
18
|
export { fileByDrag } from './filing.js';
|
|
19
19
|
export type { FilingOptions } from './filing.js';
|
|
20
20
|
export { createCatalog, memoryStorage, childrenOf, containerOf, copyName, descendantsOf, enclosingFolders, isContainerKind, isInside, isTrashed, isVolume, itemCount, itemOf, nextFolderName, DISK, FOLDER, TRASH, UNTITLED_FOLDER, } from './catalog.js';
|
|
@@ -25,5 +25,3 @@ export type { LocalStorageStateOptions, SavedSession, SavedWindow, SessionSnapsh
|
|
|
25
25
|
export { BAND, CASCADE_SLOTS, CASCADE_STEP, ICON_CELL, ICON_COLUMN, ICON_INSET, ICON_ROW, NEAR, WINDOW_ORIGIN, cascadedBox, cascadeFrom, cascadeSlot, centeredBox, cleanUp, collisions, desktopLattice, fieldExtent, fillOrder, folderLattice, frameOf, isPin, latticeCell, latticeSlot, nearBox, nextFreeCell, pinOf, pinTo, trashCell, windowOrigin, } from './geometry.js';
|
|
26
26
|
export type { Bands, Box, CascadeOptions, EdgePin, Frame, Lattice, LatticeOptions, Pin, Point, Policy, Size, } from './geometry.js';
|
|
27
27
|
export { startClock, formatDate, formatTime, DATE_HOLD_MS } from './clock.js';
|
|
28
|
-
export { showAlert } from './alert.js';
|
|
29
|
-
export type { AlertButton, AlertOptions } from './alert.js';
|
package/dist/shell/index.js
CHANGED
|
@@ -3,9 +3,8 @@ import { BAND as v, CASCADE_SLOTS as y, CASCADE_STEP as b, ICON_CELL as x, ICON_
|
|
|
3
3
|
import { createWindowManager as q, focusInto as J } from "./windows.js";
|
|
4
4
|
import { localStorageState as Y, mergeSession as X, openWindowsOf as Z, readSession as Q } from "./state.js";
|
|
5
5
|
import { DATE_HOLD_MS as $, formatDate as ee, formatTime as te, startClock as ne } from "./clock.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
export { ie as APP_KIND, v as BAND, y as CASCADE_SLOTS, b as CASCADE_STEP, $ as DATE_HOLD_MS, e as DISK, le as FINDER, t as FOLDER, x as ICON_CELL, S as ICON_COLUMN, C as ICON_INSET, w as ICON_ROW, T as NEAR, n as TRASH, r as UNTITLED_FOLDER, E as WINDOW_ORIGIN, ae as appIdOf, D as cascadeFrom, O as cascadeSlot, k as cascadedBox, A as centeredBox, i as childrenOf, j as cleanUp, M as collisions, a as containerOf, o as copyName, s as createCatalog, oe as createShell, q as createWindowManager, se as defineApp, c as descendantsOf, N as desktopLattice, l as enclosingFolders, P as fieldExtent, ce as fileByDrag, F as fillOrder, ue as finder, J as focusInto, I as folderLattice, ee as formatDate, te as formatTime, L as frameOf, de as indexedDbStorage, u as isContainerKind, d as isInside, R as isPin, f as isTrashed, p as isVolume, m as itemCount, h as itemOf, z as latticeCell, B as latticeSlot, Y as localStorageState, g as memoryStorage, X as mergeSession, V as nearBox, _ as nextFolderName, H as nextFreeCell, Z as openWindowsOf, U as pinOf, W as pinTo, Q as readSession, re as showAlert, ne as startClock, G as trashCell, K as windowOrigin };
|
|
6
|
+
import { APP_KIND as re, appIdOf as ie, createShell as ae, defineApp as oe } from "./shell.js";
|
|
7
|
+
import { fileByDrag as se } from "./filing.js";
|
|
8
|
+
import { FINDER as ce, finder as le } from "./finder.js";
|
|
9
|
+
import { indexedDbStorage as ue } from "./storage.js";
|
|
10
|
+
export { re as APP_KIND, v as BAND, y as CASCADE_SLOTS, b as CASCADE_STEP, $ as DATE_HOLD_MS, e as DISK, ce as FINDER, t as FOLDER, x as ICON_CELL, S as ICON_COLUMN, C as ICON_INSET, w as ICON_ROW, T as NEAR, n as TRASH, r as UNTITLED_FOLDER, E as WINDOW_ORIGIN, ie as appIdOf, D as cascadeFrom, O as cascadeSlot, k as cascadedBox, A as centeredBox, i as childrenOf, j as cleanUp, M as collisions, a as containerOf, o as copyName, s as createCatalog, ae as createShell, q as createWindowManager, oe as defineApp, c as descendantsOf, N as desktopLattice, l as enclosingFolders, P as fieldExtent, se as fileByDrag, F as fillOrder, le as finder, J as focusInto, I as folderLattice, ee as formatDate, te as formatTime, L as frameOf, ue as indexedDbStorage, u as isContainerKind, d as isInside, R as isPin, f as isTrashed, p as isVolume, m as itemCount, h as itemOf, z as latticeCell, B as latticeSlot, Y as localStorageState, g as memoryStorage, X as mergeSession, V as nearBox, _ as nextFolderName, H as nextFreeCell, Z as openWindowsOf, U as pinOf, W as pinTo, Q as readSession, ne as startClock, G as trashCell, K as windowOrigin };
|
package/dist/shell/shell.d.ts
CHANGED
|
@@ -7,21 +7,23 @@
|
|
|
7
7
|
* nodes come back each time it is front, so items keep their state. A menu
|
|
8
8
|
* off the bar has no key equivalents, so only the front application's fire.
|
|
9
9
|
* The bar's label is the front application's name.
|
|
10
|
+
* - While an application's held dialog is open, the bar shows that
|
|
11
|
+
* application's name and menus instead; nothing else changes.
|
|
10
12
|
* - Each application's `init(ctx)` gets the desktop, the window manager, its
|
|
11
|
-
* own menus, the system menu, the other applications' actions
|
|
12
|
-
* call), the catalog when a Finder runs, the site's services,
|
|
13
|
-
* `gate()`, `onFront()` and `onDispose()`. Everything it sets up
|
|
14
|
-
* through `onDispose()`, so a hot
|
|
13
|
+
* own menus and dialogs, the system menu, the other applications' actions
|
|
14
|
+
* (read at the call), the catalog when a Finder runs, the site's services,
|
|
15
|
+
* `ask()`, `gate()`, `onFront()` and `onDispose()`. Everything it sets up
|
|
16
|
+
* comes down through `onDispose()`, and its dialogs with it, so a hot
|
|
17
|
+
* reload starts clean. The shell composes no UI of its own.
|
|
15
18
|
* - A window showing a catalog item follows it: its title follows a rename,
|
|
16
19
|
* and it closes when the item is removed.
|
|
17
20
|
* - The boot reads the catalog, seeds it once, reopens the last session's
|
|
18
21
|
* windows deepest first and the active one last, then starts saving.
|
|
19
22
|
*/
|
|
20
|
-
import type { VfDesktop, VfMenu, VfMenuItem, VfViewportBox } from '../index.js';
|
|
23
|
+
import type { VfDesktop, VfDialog, VfMenu, VfMenuItem, VfModalDialog, VfViewportBox } from '../index.js';
|
|
21
24
|
import type { Catalog, CatalogStorage, Item, Volumes } from './catalog.js';
|
|
22
25
|
import type { WindowManager } from './windows.js';
|
|
23
26
|
import type { ShellState } from './state.js';
|
|
24
|
-
import type { AlertOptions } from './alert.js';
|
|
25
27
|
/** A kind of catalog item an application registers: how it looks and opens. */
|
|
26
28
|
export interface KindDefinition {
|
|
27
29
|
/** Its 32×32 art: one URL, or one per item. */
|
|
@@ -57,6 +59,11 @@ export interface AppDefinition<Actions = unknown> {
|
|
|
57
59
|
icon?: string;
|
|
58
60
|
/** A fragment of `vf-menu` elements, each with a `data-menu` name. */
|
|
59
61
|
menus?: string;
|
|
62
|
+
/**
|
|
63
|
+
* A fragment of dialogs, each with a `data-dialog` name: a `vf-dialog`, or
|
|
64
|
+
* an element that renders one inside itself. Held under the application.
|
|
65
|
+
*/
|
|
66
|
+
dialogs?: string;
|
|
60
67
|
/** The catalog kinds it opens. */
|
|
61
68
|
kinds?: Record<string, KindDefinition>;
|
|
62
69
|
/** The Finder's: the catalog every application shares. */
|
|
@@ -98,8 +105,18 @@ export interface AppContext {
|
|
|
98
105
|
onMenu(fn: (value: string, item: VfMenuItem) => void): void;
|
|
99
106
|
/** Put an item in the system menu, which runs `fn` when picked. */
|
|
100
107
|
systemItem(value: string, label: string, fn: () => void): VfMenuItem;
|
|
101
|
-
/**
|
|
102
|
-
|
|
108
|
+
/** One of its dialogs by `data-dialog`; throws when the markup drifts. */
|
|
109
|
+
dialog<T extends HTMLElement = VfDialog>(name: string): T;
|
|
110
|
+
/** Hold a dialog it made in code: appended to the desktop, held under it, removed with it. Returns it. */
|
|
111
|
+
hold<T extends Element>(dialog: T): T;
|
|
112
|
+
/** Let a dialog it holds go, and remove it. */
|
|
113
|
+
release(dialog: Element): void;
|
|
114
|
+
/**
|
|
115
|
+
* Show a dialog it holds, and resolve its `returnValue`: the value of the
|
|
116
|
+
* button that submitted it, or null when it closed without one. Throws for
|
|
117
|
+
* a dialog it doesn't hold.
|
|
118
|
+
*/
|
|
119
|
+
ask(dialog: VfModalDialog): Promise<string | null>;
|
|
103
120
|
/** Keep `item` disabled while `test` is false: re-run on every press, key, selection change and activation. */
|
|
104
121
|
gate(item: VfMenuItem, test: () => boolean): void;
|
|
105
122
|
/** Whether a text field has keyboard focus, read through shadow roots at the call. */
|
|
@@ -128,8 +145,6 @@ export interface ShellOptions {
|
|
|
128
145
|
services?: Record<string, unknown>;
|
|
129
146
|
/** The clock in the menu bar's `end` slot. Default true. */
|
|
130
147
|
clock?: boolean;
|
|
131
|
-
/** The 32×32 caution art the alerts carry. */
|
|
132
|
-
caution?: string | null;
|
|
133
148
|
}
|
|
134
149
|
/** A running shell. */
|
|
135
150
|
export interface Shell {
|
|
@@ -139,7 +154,6 @@ export interface Shell {
|
|
|
139
154
|
readonly apps: Record<string, any>;
|
|
140
155
|
/** Settles once the boot has read the catalog and reopened the session. */
|
|
141
156
|
readonly ready: Promise<void>;
|
|
142
|
-
alert(message: string, options?: AlertOptions): Promise<string | null>;
|
|
143
157
|
dispose(): void;
|
|
144
158
|
}
|
|
145
159
|
/** The kind the shell registers: an application's icon, which opens it. */
|
package/dist/shell/shell.js
CHANGED
|
@@ -5,93 +5,96 @@ import { createCatalog as n } from "./catalog.js";
|
|
|
5
5
|
import { createWindowManager as r, deepActiveElement as i } from "./windows.js";
|
|
6
6
|
import { openWindowsOf as a } from "./state.js";
|
|
7
7
|
import { startClock as o } from "./clock.js";
|
|
8
|
-
import { showAlert as s } from "./alert.js";
|
|
9
8
|
//#region src/shell/shell.ts
|
|
10
|
-
function
|
|
9
|
+
function s(e) {
|
|
11
10
|
return e;
|
|
12
11
|
}
|
|
13
|
-
var
|
|
14
|
-
function
|
|
15
|
-
let
|
|
16
|
-
if (!
|
|
17
|
-
let
|
|
18
|
-
if (!
|
|
19
|
-
|
|
20
|
-
let
|
|
21
|
-
|
|
22
|
-
let
|
|
23
|
-
if (
|
|
12
|
+
var c = "app", l = (e) => e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e?.isContentEditable === !0;
|
|
13
|
+
function u(s, c) {
|
|
14
|
+
let u = c.apps, f = u.find((e) => e.catalog), p = c.defaultApp ?? f?.id ?? u[0]?.id ?? "", m = c.state ?? null, h = c.services ?? {}, g = [], _ = s.querySelector(":scope > vf-menu-bar");
|
|
15
|
+
if (!_) throw Error("vintage-frames/shell: the desktop has no vf-menu-bar");
|
|
16
|
+
let v = _.querySelector(":scope > vf-menu");
|
|
17
|
+
if (!v) throw Error("vintage-frames/shell: the menu bar has no system menu");
|
|
18
|
+
_.shortcuts = !0;
|
|
19
|
+
let y = m?.saved?.pattern;
|
|
20
|
+
y && (s.pattern = y);
|
|
21
|
+
let b = null;
|
|
22
|
+
if (c.fit === "viewport") {
|
|
24
23
|
let t = () => {
|
|
25
24
|
let e = {
|
|
26
|
-
width:
|
|
27
|
-
height:
|
|
25
|
+
width: s.width,
|
|
26
|
+
height: s.height
|
|
28
27
|
};
|
|
29
|
-
|
|
28
|
+
s.fitWithin(document.documentElement.clientWidth, document.documentElement.clientHeight), b?.resized(e);
|
|
30
29
|
};
|
|
31
30
|
t(), window.addEventListener("resize", t);
|
|
32
31
|
let n = e(t);
|
|
33
|
-
|
|
32
|
+
g.push(() => {
|
|
34
33
|
window.removeEventListener("resize", t), n();
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
|
-
let
|
|
38
|
-
defaultApp:
|
|
39
|
-
savedPin: (e) =>
|
|
36
|
+
let x = r(s, {
|
|
37
|
+
defaultApp: p,
|
|
38
|
+
savedPin: (e) => m?.pin(e) ?? null
|
|
40
39
|
});
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
e.target ===
|
|
40
|
+
b = x;
|
|
41
|
+
let S = (e) => {
|
|
42
|
+
e.target === s && s.clearActive();
|
|
44
43
|
};
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
art: (e) =>
|
|
49
|
-
open: (e, t) => void
|
|
44
|
+
s.addEventListener("pointerdown", S), g.push(() => s.removeEventListener("pointerdown", S));
|
|
45
|
+
let C = {}, w = /* @__PURE__ */ new Map();
|
|
46
|
+
w.set("app", {
|
|
47
|
+
art: (e) => u.find((t) => t.id === d(e))?.icon ?? "",
|
|
48
|
+
open: (e, t) => void C[d(e) ?? ""]?.open?.({ from: t }),
|
|
50
49
|
editable: !1
|
|
51
50
|
});
|
|
52
|
-
for (let e of
|
|
53
|
-
let
|
|
54
|
-
storage:
|
|
55
|
-
volumes:
|
|
56
|
-
listed: (e) =>
|
|
57
|
-
hooks: (e) =>
|
|
58
|
-
}) : null,
|
|
59
|
-
for (let [e, t] of
|
|
51
|
+
for (let e of u) for (let [t, n] of Object.entries(e.kinds ?? {})) w.set(t, n);
|
|
52
|
+
let T = f?.catalog ? n({
|
|
53
|
+
storage: f.catalog.storage,
|
|
54
|
+
volumes: f.catalog.volumes,
|
|
55
|
+
listed: (e) => w.has(e),
|
|
56
|
+
hooks: (e) => w.get(e)
|
|
57
|
+
}) : null, E = () => !!document.querySelector("vf-dialog[open]"), D = () => l(i()), O = /* @__PURE__ */ new Map(), k = () => {
|
|
58
|
+
for (let [e, t] of O) {
|
|
60
59
|
let n = !t();
|
|
61
60
|
e.disabled !== n && (e.disabled = n);
|
|
62
61
|
}
|
|
63
62
|
};
|
|
64
|
-
document.addEventListener("pointerdown",
|
|
65
|
-
let
|
|
66
|
-
art: l.caution ?? null,
|
|
67
|
-
...t
|
|
68
|
-
}), M = (e) => {
|
|
63
|
+
document.addEventListener("pointerdown", k, !0), document.addEventListener("keydown", k, !0), s.addEventListener("vf-select", k), s.addEventListener("vf-activate", k), g.push(() => document.removeEventListener("pointerdown", k, !0), () => document.removeEventListener("keydown", k, !0), () => s.removeEventListener("vf-select", k), () => s.removeEventListener("vf-activate", k), x.onWindows(k), x.onLayout(k)), T && g.push(T.subscribe(k));
|
|
64
|
+
let A = (e) => {
|
|
69
65
|
if (!e) return [];
|
|
70
66
|
let t = document.createElement("div");
|
|
71
67
|
t.innerHTML = e, customElements.upgrade(t);
|
|
72
|
-
let n = [...t.children].filter((e) => e
|
|
68
|
+
let n = [...t.children].filter((e) => e instanceof HTMLElement);
|
|
73
69
|
for (let e of n) e.remove();
|
|
74
70
|
return n;
|
|
75
|
-
},
|
|
71
|
+
}, j = u.map((e) => ({
|
|
76
72
|
def: e,
|
|
77
|
-
menus:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
menus: A(e.menus).filter((e) => e.localName === "vf-menu"),
|
|
74
|
+
dialogs: A(e.dialogs).filter((e) => e.dataset.dialog != null)
|
|
75
|
+
})), M = [];
|
|
76
|
+
for (let { def: e, menus: t, dialogs: n } of j) {
|
|
77
|
+
let r = [], i = `vintage-frames/shell (${e.id})`, a = /* @__PURE__ */ new Set();
|
|
78
|
+
for (let t of n) x.holdDialog(t, { app: e.id }), a.add(t);
|
|
79
|
+
r.push(() => {
|
|
80
|
+
for (let e of a) x.releaseDialog(e), e.remove();
|
|
81
|
+
a.clear();
|
|
82
|
+
});
|
|
83
|
+
let o = {
|
|
84
|
+
desktop: s,
|
|
85
|
+
windows: x,
|
|
83
86
|
menus: t,
|
|
84
|
-
systemMenu:
|
|
85
|
-
apps:
|
|
86
|
-
catalog:
|
|
87
|
-
services:
|
|
88
|
-
state:
|
|
89
|
-
kinds:
|
|
90
|
-
kind: (e) =>
|
|
91
|
-
app: (e) =>
|
|
87
|
+
systemMenu: v,
|
|
88
|
+
apps: C,
|
|
89
|
+
catalog: T,
|
|
90
|
+
services: h,
|
|
91
|
+
state: m,
|
|
92
|
+
kinds: w,
|
|
93
|
+
kind: (e) => w.get(e),
|
|
94
|
+
app: (e) => u.find((t) => t.id === e),
|
|
92
95
|
menu(e) {
|
|
93
96
|
let n = t.find((t) => t.dataset.menu === e);
|
|
94
|
-
if (!n) throw Error(`${
|
|
97
|
+
if (!n) throw Error(`${i}: missing menu ${e}`);
|
|
95
98
|
return n;
|
|
96
99
|
},
|
|
97
100
|
item(e) {
|
|
@@ -99,115 +102,133 @@ function d(c, l) {
|
|
|
99
102
|
let t = n.querySelector(`vf-menu-item[value="${CSS.escape(e)}"]`);
|
|
100
103
|
if (t) return t;
|
|
101
104
|
}
|
|
102
|
-
throw Error(`${
|
|
105
|
+
throw Error(`${i}: missing menu item ${e}`);
|
|
103
106
|
},
|
|
104
107
|
onMenu(e) {
|
|
105
|
-
for (let n of t)
|
|
106
|
-
if (
|
|
108
|
+
for (let n of t) o.on(n, "vf-menu-select", (t) => {
|
|
109
|
+
if (E()) return;
|
|
107
110
|
let { value: n, item: r } = t.detail;
|
|
108
111
|
e(n, r);
|
|
109
112
|
});
|
|
110
113
|
},
|
|
111
|
-
systemItem(e, t,
|
|
112
|
-
let
|
|
113
|
-
return
|
|
114
|
-
!
|
|
115
|
-
}),
|
|
114
|
+
systemItem(e, t, n) {
|
|
115
|
+
let i = document.createElement("vf-menu-item");
|
|
116
|
+
return i.setAttribute("value", e), i.textContent = t, v.append(i), o.on(v, "vf-menu-select", (t) => {
|
|
117
|
+
!E() && t.detail.value === e && n();
|
|
118
|
+
}), r.push(() => i.remove()), i;
|
|
119
|
+
},
|
|
120
|
+
dialog(e) {
|
|
121
|
+
let t = n.find((t) => t.dataset.dialog === e);
|
|
122
|
+
if (!t) throw Error(`${i}: missing dialog ${e}`);
|
|
123
|
+
return t;
|
|
124
|
+
},
|
|
125
|
+
hold(t) {
|
|
126
|
+
return x.holdDialog(t, { app: e.id }), a.add(t), t;
|
|
127
|
+
},
|
|
128
|
+
release(e) {
|
|
129
|
+
a.delete(e) && (x.releaseDialog(e), e.remove());
|
|
130
|
+
},
|
|
131
|
+
ask(t) {
|
|
132
|
+
if (x.appOf(t) !== e.id) throw Error(`${i}: ask() takes a dialog the application holds`);
|
|
133
|
+
return new Promise((e) => {
|
|
134
|
+
let n = (r) => {
|
|
135
|
+
r.target === t && (t.removeEventListener("vf-close", n), e(r.detail.returnValue));
|
|
136
|
+
};
|
|
137
|
+
t.addEventListener("vf-close", n), t.show();
|
|
138
|
+
});
|
|
116
139
|
},
|
|
117
|
-
alert: j,
|
|
118
140
|
gate(e, t) {
|
|
119
|
-
|
|
120
|
-
let
|
|
121
|
-
e.disabled !==
|
|
141
|
+
O.set(e, t), r.push(() => O.delete(e));
|
|
142
|
+
let n = !t();
|
|
143
|
+
e.disabled !== n && (e.disabled = n);
|
|
122
144
|
},
|
|
123
|
-
typing:
|
|
124
|
-
modalOpen:
|
|
145
|
+
typing: D,
|
|
146
|
+
modalOpen: E,
|
|
125
147
|
onFront(t) {
|
|
126
|
-
t(
|
|
148
|
+
t(x.front === e.id), r.push(x.onFront((n) => t(n === e.id)));
|
|
127
149
|
},
|
|
128
|
-
on(e, t,
|
|
129
|
-
e.addEventListener(t,
|
|
150
|
+
on(e, t, n, i) {
|
|
151
|
+
e.addEventListener(t, n, i), r.push(() => e.removeEventListener(t, n, i));
|
|
130
152
|
},
|
|
131
153
|
onDispose(e) {
|
|
132
|
-
|
|
154
|
+
r.push(e);
|
|
133
155
|
}
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
for (let e of
|
|
156
|
+
}, c = e.init(o);
|
|
157
|
+
c && (C[e.id] = c), M.push(() => {
|
|
158
|
+
for (let e of r.splice(0).reverse()) e();
|
|
137
159
|
});
|
|
138
160
|
}
|
|
139
|
-
let
|
|
140
|
-
let e =
|
|
141
|
-
if (!(!
|
|
142
|
-
if (
|
|
143
|
-
|
|
161
|
+
let N = null, P = () => {
|
|
162
|
+
let e = x.asking ?? x.front, t = j.find((t) => t.def.id === e) ?? j.find((e) => e.def.id === p) ?? null;
|
|
163
|
+
if (!(!t || t === N)) {
|
|
164
|
+
if (N) for (let e of N.menus) e.remove();
|
|
165
|
+
v.after(...t.menus), _.label = t.def.name, N = t, k();
|
|
144
166
|
}
|
|
145
167
|
};
|
|
146
|
-
if (
|
|
147
|
-
let e =
|
|
148
|
-
e || (e = document.createElement("vf-label"), e.slot = "end",
|
|
168
|
+
if (g.push(x.onFront(P), x.onDialogs(P)), P(), c.clock !== !1) {
|
|
169
|
+
let e = _.querySelector(":scope > [slot=\"end\"]"), t = !e;
|
|
170
|
+
e || (e = document.createElement("vf-label"), e.slot = "end", _.append(e));
|
|
149
171
|
let n = o(e);
|
|
150
|
-
|
|
172
|
+
g.push(() => {
|
|
151
173
|
n(), t && e.remove();
|
|
152
174
|
});
|
|
153
175
|
}
|
|
154
|
-
let
|
|
155
|
-
if (
|
|
176
|
+
let F = /* @__PURE__ */ new WeakSet(), I = () => {
|
|
177
|
+
if (T) for (let e of s.stackingOrder) {
|
|
156
178
|
if (!(e instanceof t)) continue;
|
|
157
|
-
let n =
|
|
179
|
+
let n = x.itemOf(e);
|
|
158
180
|
if (n == null) continue;
|
|
159
|
-
let r =
|
|
160
|
-
r ? (
|
|
181
|
+
let r = T.item(n);
|
|
182
|
+
r ? (F.add(e), e.heading !== r.name && (e.heading = r.name)) : F.has(e) && T.get().available && x.close(e, { to: null });
|
|
161
183
|
}
|
|
162
184
|
};
|
|
163
|
-
return
|
|
164
|
-
desktop:
|
|
165
|
-
windows:
|
|
166
|
-
catalog:
|
|
167
|
-
apps:
|
|
185
|
+
return T && g.push(T.subscribe(I), x.onWindows(I)), m?.hold(), {
|
|
186
|
+
desktop: s,
|
|
187
|
+
windows: x,
|
|
188
|
+
catalog: T,
|
|
189
|
+
apps: C,
|
|
168
190
|
ready: (async () => {
|
|
169
191
|
try {
|
|
170
|
-
|
|
171
|
-
for (let { item: e, app: t } of a(
|
|
172
|
-
let e =
|
|
192
|
+
T && (await T.refresh(), f?.catalog?.seed && await T.seed(f.catalog.seed));
|
|
193
|
+
for (let { item: e, app: t } of a(m?.saved ?? null)) await C[t]?.open?.({ item: e });
|
|
194
|
+
let e = m?.saved?.active;
|
|
173
195
|
if (e) {
|
|
174
|
-
let t =
|
|
175
|
-
t &&
|
|
196
|
+
let t = x.windowFor(e);
|
|
197
|
+
t && s.bringToFront(t);
|
|
176
198
|
}
|
|
177
199
|
} finally {
|
|
178
|
-
if (
|
|
179
|
-
let e =
|
|
180
|
-
windows:
|
|
181
|
-
active:
|
|
182
|
-
pattern:
|
|
200
|
+
if (m) {
|
|
201
|
+
let e = m.start(() => ({
|
|
202
|
+
windows: x.snapshot(),
|
|
203
|
+
active: x.itemOf(s.activeWindow),
|
|
204
|
+
pattern: s.pattern ?? null
|
|
183
205
|
}), (e) => {
|
|
184
206
|
let t = [
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
...
|
|
207
|
+
x.onLayout(e),
|
|
208
|
+
x.onWindows(e),
|
|
209
|
+
...T ? [T.subscribe(e)] : []
|
|
188
210
|
];
|
|
189
|
-
return
|
|
211
|
+
return s.addEventListener("vf-activate", e), () => {
|
|
190
212
|
for (let e of t) e();
|
|
191
|
-
|
|
213
|
+
s.removeEventListener("vf-activate", e);
|
|
192
214
|
};
|
|
193
215
|
});
|
|
194
|
-
|
|
216
|
+
g.push(e), m.release();
|
|
195
217
|
}
|
|
196
218
|
}
|
|
197
219
|
})(),
|
|
198
|
-
alert: j,
|
|
199
220
|
dispose() {
|
|
200
|
-
for (let e of
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
for (let e of
|
|
204
|
-
|
|
221
|
+
for (let e of M.splice(0).reverse()) e();
|
|
222
|
+
if (N) for (let e of N.menus) e.remove();
|
|
223
|
+
N = null;
|
|
224
|
+
for (let e of g.splice(0)) e();
|
|
225
|
+
x.dispose(), T?.dispose();
|
|
205
226
|
}
|
|
206
227
|
};
|
|
207
228
|
}
|
|
208
|
-
function
|
|
229
|
+
function d(e) {
|
|
209
230
|
let t = e.data;
|
|
210
231
|
return typeof t?.app == "string" ? t.app : null;
|
|
211
232
|
}
|
|
212
233
|
//#endregion
|
|
213
|
-
export {
|
|
234
|
+
export { c as APP_KIND, d as appIdOf, u as createShell, s as defineApp };
|
package/dist/shell/windows.d.ts
CHANGED
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
* resizable window's pin when its size changed, floors it at the window's
|
|
30
30
|
* own size limits and caps it to the window area, so growing back restores
|
|
31
31
|
* every place.
|
|
32
|
+
* - Dialogs: `holdDialog()` holds an application's dialog under it, in the
|
|
33
|
+
* desktop. The manager follows each held dialog's `open` attribute, and
|
|
34
|
+
* `asking` is the application of the one opened last and still open.
|
|
32
35
|
*/
|
|
33
36
|
import { VfWindow } from '../index.js';
|
|
34
37
|
import type { VfDesktop, VfViewportBox } from '../index.js';
|
|
@@ -151,8 +154,22 @@ export declare function createWindowManager(desktop: VfDesktop, options: WindowM
|
|
|
151
154
|
windowsOf(app: string): VfWindow[];
|
|
152
155
|
/** A window's item, or null. */
|
|
153
156
|
itemOf(win: Element | null): string | null;
|
|
154
|
-
/** A window's application, or null when the manager doesn't hold it. */
|
|
155
|
-
appOf(
|
|
157
|
+
/** A window's or a held dialog's application, or null when the manager doesn't hold it. */
|
|
158
|
+
appOf(el: Element | null): string | null;
|
|
159
|
+
/**
|
|
160
|
+
* Hold an application's dialog: a `vf-dialog`, or an element that renders
|
|
161
|
+
* one inside itself. It is appended to the desktop unless it is already
|
|
162
|
+
* in it, and its `open` is followed from then on.
|
|
163
|
+
*/
|
|
164
|
+
holdDialog(dialog: Element, { app }: {
|
|
165
|
+
app: string;
|
|
166
|
+
}): void;
|
|
167
|
+
/** Let a held dialog go. It stays where it is; the caller removes it. */
|
|
168
|
+
releaseDialog(dialog: Element): void;
|
|
169
|
+
/** An application's held dialogs. */
|
|
170
|
+
dialogsOf(app: string): Element[];
|
|
171
|
+
/** The application of the held dialog opened last and still open, or null. */
|
|
172
|
+
readonly asking: string | null;
|
|
156
173
|
/** Whether `win` is a palette. */
|
|
157
174
|
isPalette(win: Element | null): boolean;
|
|
158
175
|
/** Change the item a window shows: an untitled document's first save, say. */
|
|
@@ -209,6 +226,8 @@ export declare function createWindowManager(desktop: VfDesktop, options: WindowM
|
|
|
209
226
|
beforeFront(fn: (win: HTMLElement | null) => void): () => void;
|
|
210
227
|
/** The front application changed. */
|
|
211
228
|
onFront(fn: (app: string) => void): () => void;
|
|
229
|
+
/** A held dialog opened or closed, so `asking` may have changed. */
|
|
230
|
+
onDialogs(fn: () => void): () => void;
|
|
212
231
|
dispose(): void;
|
|
213
232
|
};
|
|
214
233
|
export type WindowManager = ReturnType<typeof createWindowManager>;
|