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,234 @@
1
+ /**
2
+ * The window manager. Applications make their windows; the manager places
3
+ * them, opens and closes them, follows the front application, carries them
4
+ * through a raster resize and arranges them.
5
+ *
6
+ * - `adopt()` takes a window an application made and appended: its
7
+ * application, the item it shows, how to place it, its resize policy, and
8
+ * what its close box means. `open()` raises the window for an item if one
9
+ * is open, and otherwise makes, appends, adopts and places one, and shows
10
+ * it out of `from`. `close()` hides a window into `to` — by default its
11
+ * home box, which the Finder provides: the item's icon, or the
12
+ * application's — then releases and removes it.
13
+ * - Placement, in order: this session's pin for the item, the saved pin,
14
+ * then the `place` policy — by default the first cascade slot no open
15
+ * window holds. The result is clamped into the desktop's window area.
16
+ * - The front application is the active window's, or the default one while
17
+ * none is active. `beforeFront` runs before a change, `onFront` reports it.
18
+ * - Palettes are an application's utility windows: shown while it is front
19
+ * and hidden otherwise, never closed or removed.
20
+ * - Opening a window moves keyboard focus into it; closing the active one
21
+ * moves focus to the window that becomes active, else to the closed
22
+ * window's icon, else to the desktop's icons. Focus left behind in a
23
+ * window that is no longer active — a title-bar press moves none — goes
24
+ * to the active window too.
25
+ * - `onWindows` reports a window opened or closed and a close's zoom rects
26
+ * landing, palettes aside; `isOpen()` and `hasWindows()` hold until they
27
+ * land, which is what the Finder's open ghost follows.
28
+ * - The resize rule re-pins every window with the nine-slice pin, re-reads a
29
+ * resizable window's pin when its size changed, floors it at the window's
30
+ * own size limits and caps it to the window area, so growing back restores
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.
35
+ */
36
+ import { VfWindow } from '../index.js';
37
+ import type { VfDesktop, VfViewportBox } from '../index.js';
38
+ import type { Bands, Box, Pin, Policy, Size } from './geometry.js';
39
+ /** A box to write, any edge optional. */
40
+ export interface BoxInput {
41
+ left?: number;
42
+ top?: number;
43
+ width?: number;
44
+ height?: number;
45
+ }
46
+ /** A placement: a position, and a size where one is stated. */
47
+ export interface Placed extends BoxInput {
48
+ left: number;
49
+ top: number;
50
+ }
51
+ /** How a window is placed: its box on the desktop's live window area. */
52
+ export type PlacePolicy = (area: Box) => BoxInput & Point;
53
+ type Point = {
54
+ left: number;
55
+ top: number;
56
+ };
57
+ /** What adopting a window declares. */
58
+ export interface AdoptOptions {
59
+ /** The application shown while the window is active. */
60
+ app: string;
61
+ /** The item it shows: a catalog id, or an application's own key. */
62
+ item?: string | null;
63
+ /** Its placement on the live window area; adopt() and arrange() apply it. Unset, the owner places it. */
64
+ place?: PlacePolicy | null;
65
+ /** A saved pin to open at instead. */
66
+ pin?: Pin | null;
67
+ /** Its resize policy for the re-pin. Default: a resizable window floored at its size limits, else fixed. */
68
+ policy?: ((cur: Box) => Policy) | null;
69
+ /** A box held across a raster resize while the window is near it. */
70
+ keep?: ((area: Box) => Box) | null;
71
+ /**
72
+ * A palette: shown while its application is front — and while the
73
+ * predicate holds, for one the application hides for its own reasons —
74
+ * and hidden otherwise. Never closed by the manager.
75
+ */
76
+ palette?: boolean | (() => boolean);
77
+ /**
78
+ * What the close box means. Unset, it closes the window. Set, the close box
79
+ * asks the application, which calls `close()` once it decides — after a
80
+ * Save prompt, say — or never.
81
+ */
82
+ close?: ((win: VfWindow) => void) | null;
83
+ }
84
+ /** What opening a window for an item declares. */
85
+ export interface OpenOptions extends Omit<AdoptOptions, 'pin' | 'palette'> {
86
+ /** Makes the window, not yet appended. */
87
+ create: () => VfWindow;
88
+ /** The box it opens out of, in viewport CSS px: an icon's `cellRect()`. */
89
+ from?: VfViewportBox | null;
90
+ }
91
+ /** An application's arrangement group, for windows it places itself. */
92
+ export interface ArrangeGroup {
93
+ arrange(): void;
94
+ arranged(): boolean;
95
+ }
96
+ /**
97
+ * The box a closing window shrinks into, in viewport CSS px: `item` is the
98
+ * window's item, or null, and `app` its application. The Finder answers with
99
+ * the item's icon, the nearest open folder around it, or the application's
100
+ * icon.
101
+ */
102
+ export type HomeBox = (item: string | null, app: string) => VfViewportBox | null;
103
+ /** Move the focus to the closed window's icon (`item` null: the desktop's first); resolves whether it moved. */
104
+ export type FocusHome = (item: string | null, app: string | null) => boolean;
105
+ export interface WindowManagerOptions {
106
+ /** The application front while no window is active. */
107
+ defaultApp: string;
108
+ /** A saved pin by item — the session the boot read. */
109
+ savedPin?: (item: string) => Pin | null;
110
+ }
111
+ /** The innermost focused element, through open shadow roots. */
112
+ export declare function deepActiveElement(): Element | null;
113
+ /**
114
+ * Move keyboard focus to the first thing in `win`'s content that takes it,
115
+ * once that content has rendered — and then only if `when`, read at that
116
+ * point, still holds. Resolves whether it did: a window with nothing
117
+ * focusable in its content keeps the focus where it was.
118
+ */
119
+ export declare function focusInto(win: Element, { when }?: {
120
+ when?: () => boolean;
121
+ }): Promise<boolean>;
122
+ /** The window manager over a desktop. */
123
+ export declare function createWindowManager(desktop: VfDesktop, options: WindowManagerOptions): {
124
+ /** The desktop's window area, system px. */
125
+ readonly area: Box;
126
+ /** The front application's id. */
127
+ readonly front: string;
128
+ /**
129
+ * Take a window an application made and appended (a slotted child of the
130
+ * desktop: the clamp reads its lattice). It opens at the saved `pin`, or
131
+ * at its `place`; without either the owner placed it.
132
+ */
133
+ adopt(win: VfWindow, opts: AdoptOptions): void;
134
+ /**
135
+ * Open the window for `item`: raise it if one is open, else make it,
136
+ * append it, adopt it and place it — this session's pin, then the saved
137
+ * one, then `place`, by default the first free cascade slot — and show it
138
+ * out of `from`. Keyboard focus moves into it. Returns the window.
139
+ */
140
+ open(opts: OpenOptions): VfWindow;
141
+ /**
142
+ * Close a window into `to` — by default its home box, the Finder's icon
143
+ * for it — then release and remove it. The item's box is remembered for
144
+ * the session. Resolves when the zoom rects have landed.
145
+ */
146
+ close(win: VfWindow, { to }?: {
147
+ to?: VfViewportBox | null;
148
+ }): Promise<boolean>;
149
+ /** The close box's route: the window's own close, or a plain close. */
150
+ requestClose(win: VfWindow): void;
151
+ /** The window showing `item`, or null. */
152
+ windowFor(item: string): VfWindow | null;
153
+ /** Every window of an application, back to front. */
154
+ windowsOf(app: string): VfWindow[];
155
+ /** A window's item, or null. */
156
+ itemOf(win: Element | null): string | null;
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;
173
+ /** Whether `win` is a palette. */
174
+ isPalette(win: Element | null): boolean;
175
+ /** Change the item a window shows: an untitled document's first save, say. */
176
+ setItem(win: VfWindow, item: string | null): void;
177
+ /** Whether a window shows `item`, or is still closing into its icon. */
178
+ isOpen(item: string): boolean;
179
+ /** Whether an application has a window open, palettes aside, or one still closing. */
180
+ hasWindows(app: string): boolean;
181
+ /** Re-read every palette's predicate: an application hid or showed one. */
182
+ palettesChanged(): void;
183
+ /** Write a box for a gesture the owner runs itself — a zoom, its group's arrange. */
184
+ write(win: VfWindow, box: Placed): void;
185
+ /** The box a placement would write, not written. */
186
+ clamped(win: VfWindow, box: BoxInput): Placed;
187
+ /** A window's `place` on the live area, clamped, or null. */
188
+ placed(win: VfWindow): Placed | null;
189
+ /** A window's pin on the current raster, for an owner that saves it. */
190
+ pinOf(win: VfWindow): Pin;
191
+ /** A pin on the live raster, clamped, under the window's policy or `policy`. */
192
+ fromPin(win: VfWindow, pin: Pin, policy?: Policy): Placed;
193
+ /** Widen the frame's bands, for an application whose windows dock along the edges. */
194
+ setFrameBands(next: Partial<Bands>): void;
195
+ /** Register an application's arrangement group. Returns the unregister. */
196
+ arrangeWith(app: string, group: ArrangeGroup): () => void;
197
+ /** View → Arrange Windows: every group's arrange, then every `place`. Nothing is raised. */
198
+ arrange(): void;
199
+ /** Whether every group is arranged and every shown window sits at its `place`. */
200
+ arranged(): boolean;
201
+ /**
202
+ * Carry every window from the `before` raster to the live one with the
203
+ * nine-slice pin, then tell the onRaster listeners. Nothing clamps a
204
+ * window's position, so growing back restores it.
205
+ */
206
+ resized(before: Size): void;
207
+ /** The windows' saved boxes: each open one with its depth, the palettes as boxes alone. */
208
+ snapshot(): Record<string, {
209
+ app: string;
210
+ pin: Pin;
211
+ z?: number;
212
+ }>;
213
+ /** This session's pin for an item whose window closed, or null. */
214
+ rememberedPin(item: string): Pin | null;
215
+ /** Notify layout of a change the owner made itself. */
216
+ layoutChanged(): void;
217
+ /** Set where a window closes into and where focus goes after it: the Finder's. */
218
+ setHome(box: HomeBox, focus: FocusHome): () => void;
219
+ /** The layout signal: any geometry write, drag, grow or arrange. Returns the unsubscribe. */
220
+ onLayout(fn: () => void): () => void;
221
+ /** A window opened or closed, or finished closing, palettes aside; a window's item changed. */
222
+ onWindows(fn: () => void): () => void;
223
+ /** A raster resize, after every window has re-pinned. */
224
+ onRaster(fn: (before: Size, after: Size) => void): () => void;
225
+ /** An activation, before the front application changes: `fn(win)`, the new active window or null. */
226
+ beforeFront(fn: (win: HTMLElement | null) => void): () => void;
227
+ /** The front application changed. */
228
+ onFront(fn: (app: string) => void): () => void;
229
+ /** A held dialog opened or closed, so `asking` may have changed. */
230
+ onDialogs(fn: () => void): () => void;
231
+ dispose(): void;
232
+ };
233
+ export type WindowManager = ReturnType<typeof createWindowManager>;
234
+ export {};
@@ -0,0 +1,387 @@
1
+ import { snapSys as e, systemPxQuantum as t } from "../scale.js";
2
+ import { VfWindow as n } from "../components/vf-window.js";
3
+ import "../index.js";
4
+ import { cascadeFrom as r, cascadedBox as i, frameOf as a, nearBox as o, pinOf as s, pinTo as c, windowOrigin as l } from "./geometry.js";
5
+ //#region src/shell/windows.ts
6
+ var u = (e, t) => e.set(t, (e.get(t) ?? 0) + 1), d = (e, t) => {
7
+ let n = e.get(t) ?? 1;
8
+ n > 1 ? e.set(t, n - 1) : e.delete(t);
9
+ }, f = (e, t, n) => Math.min(Math.max(e, t), n), p = (e) => ({
10
+ left: e.left ?? 0,
11
+ top: e.top ?? 0,
12
+ width: e.width ?? 0,
13
+ height: e.height ?? 0
14
+ });
15
+ function m() {
16
+ let e = document.activeElement;
17
+ for (; e?.shadowRoot?.activeElement;) e = e.shadowRoot.activeElement;
18
+ return e;
19
+ }
20
+ var h = (e) => {
21
+ let t = document.activeElement;
22
+ return !!t && (t === e || e.contains(t));
23
+ };
24
+ async function g(e, { when: t } = {}) {
25
+ let n = [...e.querySelectorAll("*")];
26
+ if (await Promise.all([e, ...n].map((e) => e.updateComplete)), !e.isConnected || t && !t()) return !1;
27
+ for (let t of n) if (!(t.closest("[hidden]") || !t.checkVisibility()) && !(t.tabIndex < 0 && !t.localName.startsWith("vf-")) && (t.focus({ preventScroll: !0 }), h(e))) return !0;
28
+ return !1;
29
+ }
30
+ function ee(m, ee) {
31
+ let { defaultApp: te, savedPin: ne = () => null } = ee, _ = [], v = (e, t, n) => {
32
+ e.addEventListener(t, n), _.push(() => e.removeEventListener(t, n));
33
+ }, y = () => ({
34
+ width: m.width,
35
+ height: m.height
36
+ }), b = () => m.windowArea, x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new WeakMap(), D = {}, O = () => a(b().top, D), k = /* @__PURE__ */ new Set(), A = !1, j = () => {
37
+ if (!A) for (let e of [...k]) e();
38
+ }, M = /* @__PURE__ */ new Set(), N = () => {
39
+ for (let e of [...M]) e();
40
+ }, P = /* @__PURE__ */ new Set(), F = /* @__PURE__ */ new Set(), I = /* @__PURE__ */ new Set(), L = /* @__PURE__ */ new Set(), R = /* @__PURE__ */ new Map(), z = [], re = (e) => {
41
+ for (let t = e; t; t = t.parentElement) if (R.has(t)) return t;
42
+ return null;
43
+ }, B = (e) => e.isConnected && (e.matches("vf-dialog[open]") || !!e.querySelector("vf-dialog[open]")), V = () => {
44
+ let e = z.filter((e) => R.has(e) && B(e));
45
+ for (let t of R.keys()) !e.includes(t) && B(t) && e.push(t);
46
+ if (!(e.length === z.length && e.every((e, t) => e === z[t]))) {
47
+ z = e;
48
+ for (let e of [...L]) e();
49
+ }
50
+ }, H = () => null, U = () => !1;
51
+ function W(n, r) {
52
+ let i = b(), a = t(n), o = (e) => Math.floor(e / a) * a, s = Math.ceil(i.top / a) * a, c = i.left + i.width, l = i.top + i.height, { width: u, height: d } = r;
53
+ n.resizable && (u != null && Number.isFinite(u) && (u = Math.min(u, o(i.width))), d != null && Number.isFinite(d) && (d = Math.min(d, o(Math.max(0, l - s)))));
54
+ let p = u ?? n.width ?? 0, m = d ?? n.height ?? 0;
55
+ return {
56
+ left: f(e(r.left ?? i.left, n), i.left, Math.max(i.left, o(c - p))),
57
+ top: f(e(r.top ?? s, n), s, Math.max(s, o(l - m))),
58
+ width: u,
59
+ height: d
60
+ };
61
+ }
62
+ let G = (t, n) => {
63
+ t.left = e(n.left, t), t.top = e(n.top, t), n.width != null && Number.isFinite(n.width) && (t.width = n.width), n.height != null && Number.isFinite(n.height) && (t.height = n.height), E.delete(t);
64
+ }, K = (e) => {
65
+ let t = x.get(e)?.place;
66
+ return t ? W(e, t(b())) : null;
67
+ }, q = (e, t) => {
68
+ let n = x.get(e)?.policy;
69
+ if (n) return n(t);
70
+ if (!e.resizable) return { size: {
71
+ width: t.width,
72
+ height: t.height
73
+ } };
74
+ let { minWidth: r, minHeight: i } = e.sizeLimits;
75
+ return { min: {
76
+ width: r,
77
+ height: i
78
+ } };
79
+ }, J = (e, t, n = q(e, p(e))) => W(e, c(t, y(), O(), n)), ie = (e, t) => {
80
+ let n = p(e);
81
+ return [
82
+ "left",
83
+ "top",
84
+ "width",
85
+ "height"
86
+ ].every((e) => {
87
+ let r = t[e];
88
+ return r == null || !Number.isFinite(r) || n[e] === r;
89
+ });
90
+ }, ae = (e) => {
91
+ let t = [...x].filter(([t, n]) => t !== e && !t.hidden && !n.palette).map(([e]) => p(e));
92
+ return r(l(b()), t).slot;
93
+ }, Y = te, X = (e) => e instanceof n && x.get(e)?.app || te;
94
+ function oe() {
95
+ let e = !1;
96
+ for (let [t, n] of x) {
97
+ if (!n.palette) continue;
98
+ let r = n.app === Y && n.palette();
99
+ t.hidden !== !r && (t.hidden = !r, r && m.bringToFront(t), e = !0);
100
+ }
101
+ e && j();
102
+ }
103
+ let se = (e) => {
104
+ let t = document.activeElement?.closest("vf-window");
105
+ !(t instanceof n) || t === e || !x.has(t) || x.get(t).palette || (e ? Z(e) : U(null, null));
106
+ }, Z = (e) => void g(e, { when: () => m.activeWindow === e }), ce = (e) => {
107
+ se(e);
108
+ for (let t of [...F]) t(e);
109
+ let t = X(e);
110
+ if (t !== Y) {
111
+ Y = t, oe();
112
+ for (let e of [...I]) e(Y);
113
+ }
114
+ };
115
+ v(m, "vf-activate", (e) => ce(e.detail.window)), v(m, "vf-close", (e) => {
116
+ let t = e.target;
117
+ t instanceof n && x.has(t) && $.requestClose(t);
118
+ });
119
+ let Q = 0, le = (e) => {
120
+ !(e.target instanceof n) || !x.has(e.target) || Q || (Q = window.setTimeout(() => {
121
+ Q = 0, j();
122
+ }, 0));
123
+ };
124
+ m.addEventListener("vf-placement-change", le), _.push(() => m.removeEventListener("vf-placement-change", le)), v(m, "vf-resize", (e) => {
125
+ e.detail?.commit && j();
126
+ });
127
+ let ue = (e) => {
128
+ let t = x.get(e);
129
+ t && (x.delete(e), E.delete(e), t.palette || N(), j());
130
+ }, de = (n, r, i, a) => {
131
+ let l = p(n), u = x.get(n);
132
+ if (u?.keep && o(l, u.keep(a))) {
133
+ G(n, W(n, u.keep(b())));
134
+ return;
135
+ }
136
+ let d = E.get(n), f = !!d && n.resizable && (d.width !== l.width || d.height !== l.height), m = !d || d.left !== l.left || d.top !== l.top || f || !d ? s(l, r, O()) : d.pin, h = c(m, i, O(), q(n, l));
137
+ if (n.left = e(h.left, n), n.top = e(h.top, n), n.resizable) {
138
+ let r = t(n), i = b(), a = Math.ceil(i.top / r) * r, o = Math.floor(i.width / r) * r, s = Math.floor(Math.max(0, i.top + i.height - a) / r) * r;
139
+ n.width = Math.min(e(h.width, n), o), n.height = Math.min(e(h.height, n), s);
140
+ }
141
+ E.set(n, {
142
+ pin: m,
143
+ ...p(n)
144
+ });
145
+ }, $ = {
146
+ get area() {
147
+ return b();
148
+ },
149
+ get front() {
150
+ return Y;
151
+ },
152
+ adopt(e, t) {
153
+ let n = t.palette;
154
+ if (x.set(e, {
155
+ app: t.app,
156
+ item: t.item ?? null,
157
+ place: t.place ?? null,
158
+ policy: t.policy ?? null,
159
+ keep: t.keep ?? null,
160
+ palette: n ? n === !0 ? () => !0 : n : null,
161
+ close: t.close ?? null
162
+ }), t.pin) G(e, J(e, t.pin));
163
+ else {
164
+ let t = K(e);
165
+ t && G(e, t);
166
+ }
167
+ if (n) {
168
+ let t = x.get(e);
169
+ e.hidden = !(t.app === Y && t.palette());
170
+ }
171
+ m.activeWindow === e && ce(e), n || N(), j();
172
+ },
173
+ open(e) {
174
+ let t = e.item == null ? null : $.windowFor(e.item);
175
+ if (t) return m.bringToFront(t), Z(t), t;
176
+ let n = e.create(), r = {
177
+ width: n.width ?? 0,
178
+ height: n.height ?? 0
179
+ }, a = ae();
180
+ m.append(n);
181
+ let o = e.item ?? null;
182
+ return $.adopt(n, {
183
+ app: e.app,
184
+ item: o,
185
+ place: e.place ?? ((e) => i(e, r, l(e), a)),
186
+ pin: o == null ? null : C.get(o)?.pin ?? ne(o),
187
+ policy: e.policy ?? null,
188
+ keep: e.keep ?? null,
189
+ close: e.close ?? null
190
+ }), o != null && C.delete(o), m.bringToFront(n), e.from && n.show({ from: e.from }), Z(n), n;
191
+ },
192
+ close(e, { to: t } = {}) {
193
+ let n = x.get(e), r = n?.item ?? null, i = n?.app ?? null, a = t === void 0 ? i == null ? null : H(r, i) : t, o = m.activeWindow === e || h(e);
194
+ r != null && i != null && C.set(r, {
195
+ app: i,
196
+ pin: s(p(e), y(), O())
197
+ });
198
+ let c = e.hide({ to: a });
199
+ r != null && u(w, r), i != null && !n?.palette && u(T, i);
200
+ let l = () => {
201
+ r != null && d(w, r), i != null && !n?.palette && d(T, i), N();
202
+ };
203
+ return c.then(l, l), ue(e), e.remove(), o && queueMicrotask(() => {
204
+ let e = m.activeWindow;
205
+ e ? Z(e) : U(r, i) || U(null, null);
206
+ }), c;
207
+ },
208
+ requestClose(e) {
209
+ let t = x.get(e)?.close;
210
+ t ? t(e) : $.close(e);
211
+ },
212
+ windowFor(e) {
213
+ for (let [t, n] of x) if (n.item === e) return t;
214
+ return null;
215
+ },
216
+ windowsOf(e) {
217
+ return m.stackingOrder.filter((t) => t instanceof n && x.get(t)?.app === e);
218
+ },
219
+ itemOf(e) {
220
+ return e instanceof n ? x.get(e)?.item ?? null : null;
221
+ },
222
+ appOf(e) {
223
+ if (e instanceof n) return x.get(e)?.app ?? null;
224
+ let t = re(e);
225
+ return t ? R.get(t).app : null;
226
+ },
227
+ holdDialog(e, { app: t }) {
228
+ let n = R.get(e);
229
+ if (n) n.app = t;
230
+ else {
231
+ let n = new MutationObserver(V);
232
+ n.observe(e, {
233
+ attributes: !0,
234
+ attributeFilter: ["open"],
235
+ subtree: !0
236
+ }), R.set(e, {
237
+ app: t,
238
+ observer: n
239
+ });
240
+ }
241
+ m.contains(e) || m.append(e), V();
242
+ },
243
+ releaseDialog(e) {
244
+ let t = R.get(e);
245
+ t && (t.observer.disconnect(), R.delete(e), V());
246
+ },
247
+ dialogsOf(e) {
248
+ return [...R].filter(([, t]) => t.app === e).map(([e]) => e);
249
+ },
250
+ get asking() {
251
+ let e = z[z.length - 1];
252
+ return e ? R.get(e).app : null;
253
+ },
254
+ isPalette(e) {
255
+ return e instanceof n && !!x.get(e)?.palette;
256
+ },
257
+ setItem(e, t) {
258
+ let n = x.get(e);
259
+ !n || n.item === t || (n.item = t, N());
260
+ },
261
+ isOpen(e) {
262
+ return w.has(e) || $.windowFor(e) !== null;
263
+ },
264
+ hasWindows(e) {
265
+ if (T.has(e)) return !0;
266
+ for (let [, t] of x) if (t.app === e && !t.palette) return !0;
267
+ return !1;
268
+ },
269
+ palettesChanged() {
270
+ oe();
271
+ },
272
+ write(e, t) {
273
+ G(e, t), j();
274
+ },
275
+ clamped(e, t) {
276
+ return W(e, t);
277
+ },
278
+ placed(e) {
279
+ return K(e);
280
+ },
281
+ pinOf(e) {
282
+ return s(p(e), y(), O());
283
+ },
284
+ fromPin(e, t, n) {
285
+ return J(e, t, n);
286
+ },
287
+ setFrameBands(e) {
288
+ D = { ...e }, E = /* @__PURE__ */ new WeakMap();
289
+ },
290
+ arrangeWith(e, t) {
291
+ return S.set(e, t), j(), () => {
292
+ S.get(e) === t && S.delete(e), j();
293
+ };
294
+ },
295
+ arrange() {
296
+ A = !0;
297
+ try {
298
+ for (let e of S.values()) e.arrange();
299
+ for (let e of x.keys()) {
300
+ let t = K(e);
301
+ t && G(e, t);
302
+ }
303
+ } finally {
304
+ A = !1;
305
+ }
306
+ j();
307
+ },
308
+ arranged() {
309
+ for (let e of S.values()) if (!e.arranged()) return !1;
310
+ for (let e of x.keys()) {
311
+ let t = K(e);
312
+ if (t && !e.hidden && !ie(e, t)) return !1;
313
+ }
314
+ return !0;
315
+ },
316
+ resized(e) {
317
+ let t = y();
318
+ if (e.width === t.width && e.height === t.height) return;
319
+ let n = b(), r = {
320
+ left: n.left,
321
+ top: n.top,
322
+ width: e.width - n.left,
323
+ height: Math.max(0, e.height - n.top)
324
+ };
325
+ for (let n of x.keys()) de(n, e, t, r);
326
+ for (let n of [...P]) n(e, t);
327
+ j();
328
+ },
329
+ snapshot() {
330
+ let e = {};
331
+ for (let [t, n] of C) e[t] = { ...n };
332
+ let t = m.stackingOrder;
333
+ for (let [n, r] of x) {
334
+ if (r.item == null) continue;
335
+ let i = s(p(n), y(), O());
336
+ e[r.item] = r.palette ? {
337
+ app: r.app,
338
+ pin: i
339
+ } : {
340
+ app: r.app,
341
+ pin: i,
342
+ z: t.indexOf(n)
343
+ };
344
+ }
345
+ return e;
346
+ },
347
+ rememberedPin(e) {
348
+ return C.get(e)?.pin ?? null;
349
+ },
350
+ layoutChanged() {
351
+ j();
352
+ },
353
+ setHome(e, t) {
354
+ return H = e, U = t, () => {
355
+ H = () => null, U = () => !1;
356
+ };
357
+ },
358
+ onLayout(e) {
359
+ return k.add(e), () => void k.delete(e);
360
+ },
361
+ onWindows(e) {
362
+ return M.add(e), () => void M.delete(e);
363
+ },
364
+ onRaster(e) {
365
+ return P.add(e), () => void P.delete(e);
366
+ },
367
+ beforeFront(e) {
368
+ return F.add(e), () => void F.delete(e);
369
+ },
370
+ onFront(e) {
371
+ return I.add(e), () => void I.delete(e);
372
+ },
373
+ onDialogs(e) {
374
+ return L.add(e), () => void L.delete(e);
375
+ },
376
+ dispose() {
377
+ clearTimeout(Q);
378
+ for (let e of _) e();
379
+ k.clear(), M.clear(), P.clear(), F.clear(), I.clear(), L.clear();
380
+ for (let { observer: e } of R.values()) e.disconnect();
381
+ R.clear(), z = [], S.clear(), x.clear();
382
+ }
383
+ };
384
+ return Y = X(m.activeWindow), $;
385
+ }
386
+ //#endregion
387
+ export { ee as createWindowManager, m as deepActiveElement, g as focusInto };
@@ -117,6 +117,12 @@ export declare class VfTextControlBase extends VfShadowRoleControl {
117
117
  * disabled default button means no submission at all, as in HTML; a form
118
118
  * with no submit button falls back to the bare call, also as in HTML.
119
119
  *
120
+ * One departure: a submit `vf-button variant="default"`, the button with
121
+ * the ring, is the default button when the form has one, ahead of the
122
+ * first in tree order. A Cancel/OK row puts Cancel first, and Return
123
+ * should press the button the ring marks — the one a modal's own Return
124
+ * rule presses (`VfModalDialog`).
125
+ *
120
126
  * Returns whether a form owner took the press — true even when a disabled
121
127
  * default button meant no submission, since HTML gave the press to the form
122
128
  * either way. The callers cancel the keydown on true, so a modal shell
@@ -57,8 +57,8 @@ var l = class extends a {
57
57
  requestImplicitSubmit() {
58
58
  let e = this.internals.form;
59
59
  if (!e) return !1;
60
- let t = [...e.elements].find((e) => e instanceof HTMLButtonElement && e.type === "submit" || e instanceof HTMLInputElement && (e.type === "submit" || e.type === "image") || e.localName === "vf-button" && !e.href && e.type?.toLowerCase() === "submit");
61
- return t ? (t.matches(":disabled") || t.click(), !0) : (e.requestSubmit(), !0);
60
+ let t = [...e.elements].filter((e) => e instanceof HTMLButtonElement && e.type === "submit" || e instanceof HTMLInputElement && (e.type === "submit" || e.type === "image") || e.localName === "vf-button" && !e.href && e.type?.toLowerCase() === "submit"), n = t.find((e) => e.localName === "vf-button" && e.variant === "default") ?? t[0];
61
+ return n ? (n.matches(":disabled") || n.click(), !0) : (e.requestSubmit(), !0);
62
62
  }
63
63
  emitValue(t, n = { value: this.value }) {
64
64
  e(this, t, n);
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A window's chrome as numbers: the insets between its outer box and the
3
+ * region its content lays out in, and the floor its grow box stops at.
4
+ *
5
+ * A page sizing a window to its content, or content to its window, needs the
6
+ * chrome between the two — a folder window's field sized to the scrolled
7
+ * plane, a palette sized to hold its cells exactly. Restating `1 + 18 + 20 +
8
+ * 15 + 1` in the page was the alternative, with a note to re-derive it if
9
+ * the kit's chrome ever changed.
10
+ */
11
+ /** The grow box's default floors, in system px: a window smaller than this can't be worked. */
12
+ export declare const WINDOW_MIN_WIDTH = 80;
13
+ export declare const WINDOW_MIN_HEIGHT = 54;
14
+ /** The declared options that decide a window's chrome — `vf-window`'s own. */
15
+ export interface VfWindowChromeOptions {
16
+ /** `'utility'` for the windoid's 12px bar; anything else is the 18px one. */
17
+ variant?: 'utility' | null;
18
+ /** The edge scroll rails, as on `vf-window`. */
19
+ scrollbars?: 'vertical' | 'horizontal' | 'both' | null;
20
+ /** The header's height, rule included, while the `header` slot is populated. */
21
+ headerHeight?: number | null;
22
+ /** Whether the `status` slot is populated. */
23
+ status?: boolean;
24
+ }
25
+ /** Four insets in system px. */
26
+ export interface VfInsets {
27
+ top: number;
28
+ right: number;
29
+ bottom: number;
30
+ left: number;
31
+ }
32
+ /**
33
+ * The insets, in system px, between a window's outer box (its `width` and
34
+ * `height`) and the region its content lays out in: the body, or under
35
+ * `scrollbars` the scrolled plane's viewport. They go both ways — the content
36
+ * of a window `W` wide is `W − left − right`, and a window that holds content
37
+ * `w` wide is `w + left + right`. The frame's 1px stroke on every side, the
38
+ * title bar (18, or 12 for a utility window) and the header above, the status
39
+ * strip (15) and a horizontal rail (15) below, a vertical rail (15) on the
40
+ * right. The numbers are the default tokens': a page that restyles
41
+ * `--vf-titlebar-height` or `--vf-status-bar-height` restates them.
42
+ */
43
+ export declare function windowChrome({ variant, scrollbars, headerHeight, status, }?: VfWindowChromeOptions): VfInsets;