vintage-frames 0.3.0 → 0.4.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.
@@ -2145,7 +2145,7 @@
2145
2145
  "declarations": [
2146
2146
  {
2147
2147
  "kind": "class",
2148
- "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the 50%-dither gray desktop pattern and manages the stacking order\nand `active` state of slotted `vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, at pointer-gesture\nends), so tabbing walks the stack the way the eye does and Shift+Tab is\nits exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its top corners\nwith the classic corner mask.\n\nCustom properties:\n- `--vf-desktop-pattern` — the dither's tile art (default a 1-bit 50%\n checker, opaque black-on-white on a 30-system-px tile). Overriding it\n renders the token as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern layer (default\n `#808080`). The default tile is opaque, so this only becomes visible when\n `--vf-desktop-pattern` is overridden with a tile that has transparent\n cells (or with `none`).",
2148
+ "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the 50%-dither gray desktop pattern and manages the stacking order\nand `active` state of slotted `vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, at pointer-gesture\nends), so tabbing walks the stack the way the eye does and Shift+Tab is\nits exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its top corners\nwith the classic corner mask.\n\nCustom properties:\n- `--vf-desktop-pattern` — the dither's tile art (default a 1-bit 50%\n checker, opaque black-on-white on a 30-system-px tile). Overriding it\n renders the token as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern layer (default\n `#808080`). The default tile is opaque, so this only becomes visible when\n `--vf-desktop-pattern` is overridden with a tile that has transparent\n cells (or with `none`).",
2149
2149
  "name": "VfDesktop",
2150
2150
  "cssProperties": [
2151
2151
  {
@@ -2278,6 +2278,26 @@
2278
2278
  "default": "0",
2279
2279
  "description": "Monotonic z-index counter for window stacking."
2280
2280
  },
2281
+ {
2282
+ "kind": "field",
2283
+ "name": "_activeWindow",
2284
+ "type": {
2285
+ "text": "HTMLElement | null"
2286
+ },
2287
+ "privacy": "private",
2288
+ "default": "null",
2289
+ "description": "The active document-tier window, or null when the tier is deactivated\n(or empty). The single change-tracked truth behind activeWindow\nand the `vf-activate` event — written only by _setActive."
2290
+ },
2291
+ {
2292
+ "kind": "field",
2293
+ "name": "_deactivated",
2294
+ "type": {
2295
+ "text": "boolean"
2296
+ },
2297
+ "privacy": "private",
2298
+ "default": "false",
2299
+ "description": "Whether the document tier was *deliberately* deactivated (a\nclearActive call) — as opposed to `_activeWindow` being null\nbecause nothing has activated yet. Slot changes preserve a deliberate\ndeactivation instead of promoting a survivor; a newly slotted document\nwindow still activates (opening a window brings its application forward)."
2300
+ },
2281
2301
  {
2282
2302
  "kind": "field",
2283
2303
  "name": "_awaitingUpgrade",
@@ -2353,6 +2373,25 @@
2353
2373
  ],
2354
2374
  "description": "Bring a slotted window to the front of its tier. A document-tier window\nalso becomes the single active window (clearing `active` on the other\ndocument windows); a utility window restacks within the floating tier\nand leaves every `active` state alone.\n\nThe light-DOM order of the slotted windows follows (_syncDomOrder):\nvisual stacking and sequential focus order come from independent channels\n(z-index vs DOM position), and letting them drift apart is how a desktop\ntabs front-to-back one way and back-to-front the other, with widgets\nreachable only travelling backwards. Deferred to the end of any in-flight\npointer gesture — moving a node clears the pointer capture a title-bar\ndrag or grow-box resize holds on it, and a background window must stay\ndraggable in the same gesture that raises it."
2355
2375
  },
2376
+ {
2377
+ "kind": "field",
2378
+ "name": "activeWindow",
2379
+ "type": {
2380
+ "text": "HTMLElement | null"
2381
+ },
2382
+ "description": "The active document-tier window, or null while the tier is deactivated\n(or has no windows). Utility windows are never the holder.",
2383
+ "readonly": true
2384
+ },
2385
+ {
2386
+ "kind": "method",
2387
+ "name": "clearActive",
2388
+ "return": {
2389
+ "type": {
2390
+ "text": "void"
2391
+ }
2392
+ },
2393
+ "description": "Deactivate the whole document tier — clear `active` from every document\nwindow, leaving none the holder. Pages route \"the user clicked the\nFinder\" presses — on the bare dither, on their own desktop furniture\n(an icon layer) — through here; the deactivated state holds until a\ndocument window is pressed, focused, brought to front, or newly\nslotted."
2394
+ },
2356
2395
  {
2357
2396
  "kind": "method",
2358
2397
  "name": "_restack",
@@ -2474,11 +2513,11 @@
2474
2513
  {
2475
2514
  "name": "win",
2476
2515
  "type": {
2477
- "text": "HTMLElement"
2516
+ "text": "HTMLElement | null"
2478
2517
  }
2479
2518
  }
2480
2519
  ],
2481
- "description": "Set `active` on `win` only, clearing it on every other *document-tier*\nwindow. Utility windows stand outside the invariant: a palette keeps\nwhatever `active` state it has (true by default, so its dither and\nwidgets stay drawn while document windows trade the highlight)."
2520
+ "description": "Set `active` on `win` only, clearing it on every other *document-tier*\nwindow (`null` clears the whole tier — the deactivated state). Utility\nwindows stand outside the invariant: a palette keeps whatever `active`\nstate it has (true by default, so its dither and widgets stay drawn\nwhile document windows trade the highlight). The one write site of\n_activeWindow, so `vf-activate` fires exactly on a change of\nholder — re-asserting the current holder is silent."
2482
2521
  },
2483
2522
  {
2484
2523
  "kind": "method",
@@ -2573,6 +2612,12 @@
2573
2612
  }
2574
2613
  }
2575
2614
  ],
2615
+ "events": [
2616
+ {
2617
+ "description": "The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM with none behind it). Fired once per change of holder, never for a re-assertion of the same one.",
2618
+ "name": "vf-activate"
2619
+ }
2620
+ ],
2576
2621
  "attributes": [
2577
2622
  {
2578
2623
  "name": "width",
@@ -1,21 +1,21 @@
1
- import { vfElement as e } from "../define.js";
2
- import { ScaleController as t } from "../scale.js";
3
- import n from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
- import { VfPositioned as r } from "../position.js";
5
- import { vfDisplay as i } from "../styles/recipes/display-face.js";
6
- import { vfBase as a } from "../styles/recipes/host.js";
7
- import { vfFocusUnderline as o } from "../styles/recipes/focus.js";
8
- import { GridSnapController as s } from "../grid-snap.js";
9
- import { BUTTON_FACE as c, BUTTON_FRAME as l, RING_FRAME as u, RING_HOLE as d, steppedRectClip as f, steppedRingClip as p } from "../pixel-frame.js";
10
- import { deferActivation as m } from "../events.js";
1
+ import { deferActivation as e } from "../events.js";
2
+ import { vfElement as t } from "../define.js";
3
+ import { ScaleController as n } from "../scale.js";
4
+ import r from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
5
+ import { VfPositioned as i } from "../position.js";
6
+ import { vfDisplay as a } from "../styles/recipes/display-face.js";
7
+ import { vfBase as o } from "../styles/recipes/host.js";
8
+ import { vfFocusUnderline as s } from "../styles/recipes/focus.js";
9
+ import { GridSnapController as c } from "../grid-snap.js";
10
+ import { BUTTON_FACE as l, BUTTON_FRAME as u, RING_FRAME as d, RING_HOLE as f, steppedRectClip as p, steppedRingClip as m } from "../pixel-frame.js";
11
11
  import { VfShadowRoleControl as h } from "../form-control.js";
12
12
  import { css as g, html as _, nothing as v, unsafeCSS as y } from "lit";
13
13
  import { property as b, query as x } from "lit/decorators.js";
14
14
  //#region src/components/vf-button.ts
15
- var S = "vf-submitter", C = class extends r(h) {
16
- constructor(...e) {
17
- super(...e), this.type = "button", this.name = "", this.value = "", this.formAction = "", this.formEnctype = "", this.formMethod = "", this.formNoValidate = !1, this.formTarget = "", this.scale = new t(this), this.gridSnap = new s(this), this.#e = !1, this.handleClick = (e) => {
18
- this.isDisabled || this.#e || this.resolvedType !== "button" && m(this, e, () => this.activate());
15
+ var S = "vf-submitter", C = class extends i(h) {
16
+ constructor(...t) {
17
+ super(...t), this.type = "button", this.name = "", this.value = "", this.formAction = "", this.formEnctype = "", this.formMethod = "", this.formNoValidate = !1, this.formTarget = "", this.scale = new n(this), this.gridSnap = new c(this), this.#e = !1, this.handleClick = (t) => {
18
+ this.isDisabled || this.#e || this.resolvedType !== "button" && e(this, t, () => this.activate());
19
19
  };
20
20
  }
21
21
  static {
@@ -26,8 +26,8 @@ var S = "vf-submitter", C = class extends r(h) {
26
26
  }
27
27
  static {
28
28
  this.styles = [
29
+ o,
29
30
  a,
30
- i,
31
31
  g`
32
32
  :host {
33
33
  display: inline-flex;
@@ -61,7 +61,7 @@ var S = "vf-submitter", C = class extends r(h) {
61
61
  bottom: calc(var(--vf-scale, 1) * -${4}px - var(--vf-snap-dy, 0px));
62
62
  right: calc(var(--vf-scale, 1) * -${4}px - var(--vf-snap-dx, 0px));
63
63
  background: var(--vf-black, #000);
64
- clip-path: ${y(p(u, d))};
64
+ clip-path: ${y(m(d, f))};
65
65
  pointer-events: none;
66
66
  }
67
67
  /* Disabled default: the fat outer ring dims to gray; the inner button
@@ -131,12 +131,12 @@ var S = "vf-submitter", C = class extends r(h) {
131
131
  }
132
132
  button::before {
133
133
  background: var(--vf-black, #000);
134
- clip-path: ${y(f(l))};
134
+ clip-path: ${y(p(u))};
135
135
  }
136
136
  /* Face: white fill inset one pixel, with its own traced corner steps. */
137
137
  button::after {
138
138
  background: var(--vf-white, #fff);
139
- clip-path: ${y(f(c))};
139
+ clip-path: ${y(p(l))};
140
140
  }
141
141
  /* Pressed: instant white-on-black inversion. */
142
142
  button:active:not(:disabled) {
@@ -167,7 +167,7 @@ var S = "vf-submitter", C = class extends r(h) {
167
167
  outline: none;
168
168
  }
169
169
  button:focus-visible .label::after {
170
- ${o}
170
+ ${s}
171
171
  }
172
172
  /* Disabled: only the label dims to gray; the solid black border stays. */
173
173
  button:disabled {
@@ -213,22 +213,22 @@ var S = "vf-submitter", C = class extends r(h) {
213
213
  }
214
214
  }
215
215
  };
216
- n([b({ reflect: !0 })], C.prototype, "variant", void 0), n([b({ reflect: !0 })], C.prototype, "type", void 0), n([b({ reflect: !0 })], C.prototype, "name", void 0), n([b({ reflect: !0 })], C.prototype, "value", void 0), n([b({
216
+ r([b({ reflect: !0 })], C.prototype, "variant", void 0), r([b({ reflect: !0 })], C.prototype, "type", void 0), r([b({ reflect: !0 })], C.prototype, "name", void 0), r([b({ reflect: !0 })], C.prototype, "value", void 0), r([b({
217
217
  attribute: "formaction",
218
218
  reflect: !0
219
- })], C.prototype, "formAction", void 0), n([b({
219
+ })], C.prototype, "formAction", void 0), r([b({
220
220
  attribute: "formenctype",
221
221
  reflect: !0
222
- })], C.prototype, "formEnctype", void 0), n([b({
222
+ })], C.prototype, "formEnctype", void 0), r([b({
223
223
  attribute: "formmethod",
224
224
  reflect: !0
225
- })], C.prototype, "formMethod", void 0), n([b({
225
+ })], C.prototype, "formMethod", void 0), r([b({
226
226
  type: Boolean,
227
227
  attribute: "formnovalidate",
228
228
  reflect: !0
229
- })], C.prototype, "formNoValidate", void 0), n([b({
229
+ })], C.prototype, "formNoValidate", void 0), r([b({
230
230
  attribute: "formtarget",
231
231
  reflect: !0
232
- })], C.prototype, "formTarget", void 0), n([x("button")], C.prototype, "buttonEl", void 0), C = n([e("vf-button")], C);
232
+ })], C.prototype, "formTarget", void 0), r([x("button")], C.prototype, "buttonEl", void 0), C = r([t("vf-button")], C);
233
233
  //#endregion
234
234
  export { C as VfButton };
@@ -1,11 +1,11 @@
1
- import { vfElement as e } from "../define.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
3
- import { VfPositioned as n } from "../position.js";
4
- import { vfDisplay as r } from "../styles/recipes/display-face.js";
5
- import { vfBase as i } from "../styles/recipes/host.js";
6
- import { vfFocusUnderline as a } from "../styles/recipes/focus.js";
7
- import { vfToggle as o } from "../styles/recipes/toggle.js";
8
- import { emit as s, emitNative as c } from "../events.js";
1
+ import { emit as e, emitNative as t } from "../events.js";
2
+ import { vfElement as n } from "../define.js";
3
+ import r from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
+ import { VfPositioned as i } from "../position.js";
5
+ import { vfDisplay as a } from "../styles/recipes/display-face.js";
6
+ import { vfBase as o } from "../styles/recipes/host.js";
7
+ import { vfFocusUnderline as s } from "../styles/recipes/focus.js";
8
+ import { vfToggle as c } from "../styles/recipes/toggle.js";
9
9
  import { CHECKBOX_X as l, glyphSvg as u } from "../glyphs.js";
10
10
  import { VfFormControl as d } from "../form-control.js";
11
11
  import { VfToggleControl as f } from "../toggle-control.js";
@@ -13,12 +13,12 @@ import { css as p, html as m } from "lit";
13
13
  import { property as h, state as g } from "lit/decorators.js";
14
14
  import { classMap as _ } from "lit/directives/class-map.js";
15
15
  //#region src/components/vf-checkbox.ts
16
- var v = class extends n(f(d)) {
16
+ var v = class extends i(f(d)) {
17
17
  static {
18
18
  this.styles = [
19
- i,
20
- r,
21
19
  o,
20
+ a,
21
+ c,
22
22
  p`
23
23
  /* Keyboard focus underlines the box itself — not the label, and not a
24
24
  ring around either (see vfFocusUnderline). Both adjustments below are
@@ -28,7 +28,7 @@ var v = class extends n(f(d)) {
28
28
  blank row and the rule itself: −(1 + 1 + 1). */
29
29
  :host(:focus-visible) .box::after {
30
30
  --vf-focus-underline-offset: -3px;
31
- ${a}
31
+ ${s}
32
32
  left: calc(var(--vf-scale, 1) * -1px);
33
33
  right: calc(var(--vf-scale, 1) * -1px);
34
34
  }
@@ -132,12 +132,12 @@ var v = class extends n(f(d)) {
132
132
  this.checked = !0;
133
133
  }
134
134
  activate() {
135
- this.checked = !this.checked, this.focus(), s(this, "vf-change", { checked: this.checked }), c(this, "input"), c(this, "change");
135
+ this.checked = !this.checked, this.focus(), e(this, "vf-change", { checked: this.checked }), t(this, "input"), t(this, "change");
136
136
  }
137
137
  };
138
- t([h({
138
+ r([h({
139
139
  type: Boolean,
140
140
  reflect: !0
141
- })], v.prototype, "checked", void 0), t([h({ reflect: !0 })], v.prototype, "name", void 0), t([h()], v.prototype, "value", void 0), t([g()], v.prototype, "_hasLabel", void 0), v = t([e("vf-checkbox")], v);
141
+ })], v.prototype, "checked", void 0), r([h({ reflect: !0 })], v.prototype, "name", void 0), r([h()], v.prototype, "value", void 0), r([g()], v.prototype, "_hasLabel", void 0), v = r([n("vf-checkbox")], v);
142
142
  //#endregion
143
143
  export { v as VfCheckbox };
@@ -17,6 +17,20 @@ declare const VfDesktop_base: (new (...args: any[]) => import("../position.js").
17
17
  * deactivates the active document window nor greys the palette, exactly as
18
18
  * System 7's floating windoids behaved while their application was frontmost.
19
19
  *
20
+ * **Deactivation.** On a real System 7 machine clicking the desktop clicked
21
+ * the *Finder* — the frontmost application's windows lost their stripes.
22
+ * {@link clearActive} is that gesture's handler: it clears `active` from
23
+ * the whole document tier, and **zero active windows is a legal state**,
24
+ * held until a press or keyboard focus re-enters a document window (or a
25
+ * new one is slotted, which activates it — opening a window brings its
26
+ * application forward). The desktop never takes this decision itself: its
27
+ * furniture is slotted light DOM (an icon layer, say), so only the page
28
+ * knows which of its children — or which presses on the bare dither — mean
29
+ * "the Finder", and it routes those through `clearActive()`. Left alone,
30
+ * the classic always-one-active behavior is unchanged. {@link activeWindow}
31
+ * reads the current holder, and every change of holder — including to and
32
+ * from none — fires `vf-activate`.
33
+ *
20
34
  * The desktop is a raster with an explicit size, always: **`width` and
21
35
  * `height`**, in system px, the way a WIND resource declared a window's —
22
36
  * the host box renders at the declared screen plus `2 × bezel` per axis, a
@@ -41,6 +55,11 @@ declare const VfDesktop_base: (new (...args: any[]) => import("../position.js").
41
55
  * cells (or with `none`).
42
56
  *
43
57
  * @slot - Default slot: menu bar, windows, anything.
58
+ * @fires vf-activate - The active document-tier window changed. Detail
59
+ * `{ window: HTMLElement | null }` — the new holder, or `null` when the
60
+ * document tier deactivated (a {@link clearActive} call, or the active
61
+ * window leaving the DOM with none behind it). Fired once per change of
62
+ * holder, never for a re-assertion of the same one.
44
63
  * @csspart desktop - The dithered screen surface — the whole-system-px
45
64
  * raster (inset by `bezel` when one is set).
46
65
  * @cssprop [--vf-desktop=#808080] - base color under the desktop dither —
@@ -108,6 +127,20 @@ export declare class VfDesktop extends VfDesktop_base {
108
127
  private _pattern;
109
128
  /** Monotonic z-index counter for window stacking. */
110
129
  private _zCounter;
130
+ /**
131
+ * The active document-tier window, or null when the tier is deactivated
132
+ * (or empty). The single change-tracked truth behind {@link activeWindow}
133
+ * and the `vf-activate` event — written only by {@link _setActive}.
134
+ */
135
+ private _activeWindow;
136
+ /**
137
+ * Whether the document tier was *deliberately* deactivated (a
138
+ * {@link clearActive} call) — as opposed to `_activeWindow` being null
139
+ * because nothing has activated yet. Slot changes preserve a deliberate
140
+ * deactivation instead of promoting a survivor; a newly slotted document
141
+ * window still activates (opening a window brings its application forward).
142
+ */
143
+ private _deactivated;
111
144
  /** Whether a one-shot post-upgrade re-normalization is already pending. */
112
145
  private _awaitingUpgrade;
113
146
  /** Whether a pointer gesture that began on the desktop is still in flight. */
@@ -143,6 +176,18 @@ export declare class VfDesktop extends VfDesktop_base {
143
176
  * draggable in the same gesture that raises it.
144
177
  */
145
178
  bringToFront(win: HTMLElement): void;
179
+ /** The active document-tier window, or null while the tier is deactivated
180
+ * (or has no windows). Utility windows are never the holder. */
181
+ get activeWindow(): HTMLElement | null;
182
+ /**
183
+ * Deactivate the whole document tier — clear `active` from every document
184
+ * window, leaving none the holder. Pages route "the user clicked the
185
+ * Finder" presses — on the bare dither, on their own desktop furniture
186
+ * (an icon layer) — through here; the deactivated state holds until a
187
+ * document window is pressed, focused, brought to front, or newly
188
+ * slotted.
189
+ */
190
+ clearActive(): void;
146
191
  /** The z/active half of a raise, shared by every path. */
147
192
  private _restack;
148
193
  /** Sync the DOM order now, or at gesture end if a pointer is down. */
@@ -199,9 +244,12 @@ export declare class VfDesktop extends VfDesktop_base {
199
244
  */
200
245
  private _normalizeAfterUpgrade;
201
246
  /** Set `active` on `win` only, clearing it on every other *document-tier*
202
- * window. Utility windows stand outside the invariant: a palette keeps
203
- * whatever `active` state it has (true by default, so its dither and
204
- * widgets stay drawn while document windows trade the highlight). */
247
+ * window (`null` clears the whole tier — the deactivated state). Utility
248
+ * windows stand outside the invariant: a palette keeps whatever `active`
249
+ * state it has (true by default, so its dither and widgets stay drawn
250
+ * while document windows trade the highlight). The one write site of
251
+ * {@link _activeWindow}, so `vf-activate` fires exactly on a change of
252
+ * holder — re-asserting the current holder is silent. */
205
253
  private _setActive;
206
254
  /**
207
255
  * Set a window's `active` state. Prefers the property (the source of truth
@@ -1,17 +1,18 @@
1
- import { vfElement as e } from "../define.js";
2
- import { ScaleController as t, effectiveScale as n, sysLength as r } from "../scale.js";
3
- import i from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
- import { VfPositioned as a } from "../position.js";
5
- import { vfBase as o } from "../styles/recipes/host.js";
6
- import { tileImage as s, tileRaster as c, tileRects as l, tileSpan as u, vfTileSize as d } from "../styles/recipes/tile.js";
7
- import { TileRasterCache as f, patternOverride as p, tileGrid as m, vfTileGrid as h } from "../tile-grid.js";
8
- import { GridSnapController as g } from "../grid-snap.js";
9
- import { DocumentListenersController as _ } from "../document-listeners.js";
10
- import { SCREEN_CORNER as v, steppedCornerClip as y } from "../pixel-frame.js";
11
- import { LitElement as b, css as x, html as S, unsafeCSS as C } from "lit";
12
- import { property as w, queryAssignedElements as T } from "lit/decorators.js";
1
+ import { emit as e } from "../events.js";
2
+ import { vfElement as t } from "../define.js";
3
+ import { ScaleController as n, effectiveScale as r, sysLength as i } from "../scale.js";
4
+ import a from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
5
+ import { VfPositioned as o } from "../position.js";
6
+ import { vfBase as s } from "../styles/recipes/host.js";
7
+ import { tileImage as c, tileRaster as l, tileRects as u, tileSpan as d, vfTileSize as f } from "../styles/recipes/tile.js";
8
+ import { TileRasterCache as p, patternOverride as m, tileGrid as h, vfTileGrid as g } from "../tile-grid.js";
9
+ import { GridSnapController as _ } from "../grid-snap.js";
10
+ import { DocumentListenersController as v } from "../document-listeners.js";
11
+ import { SCREEN_CORNER as y, steppedCornerClip as b } from "../pixel-frame.js";
12
+ import { LitElement as x, css as S, html as C, unsafeCSS as w } from "lit";
13
+ import { property as T, queryAssignedElements as E } from "lit/decorators.js";
13
14
  //#region src/components/vf-desktop.ts
14
- var E = 1e6, D = 512, O = 342, k = 2, A = [
15
+ var D = 1e6, O = 512, k = 342, A = 2, j = [
15
16
  [
16
17
  0,
17
18
  0,
@@ -33,9 +34,9 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
33
34
  1,
34
35
  "#000000"
35
36
  ]
36
- ], j = s(k, k, l(A)), M = c(k, k, A), N = u(k), P = class extends a(b) {
37
+ ], M = c(A, A, u(j)), N = l(A, A, j), P = d(A), F = class extends o(x) {
37
38
  constructor(...e) {
38
- super(...e), this.width = D, this.height = O, this.bezel = 0, this.scale = new t(this), this.gridSnap = new g(this), this._pattern = "", this.#e = new f(), this._zCounter = 0, this._awaitingUpgrade = !1, this._pointerGesture = !1, this._restoringFocus = !1, this._gestureEnd = new _(this, () => [[
39
+ super(...e), this.width = O, this.height = k, this.bezel = 0, this.scale = new n(this), this.gridSnap = new _(this), this._pattern = "", this.#e = new p(), this._zCounter = 0, this._activeWindow = null, this._deactivated = !1, this._awaitingUpgrade = !1, this._pointerGesture = !1, this._restoringFocus = !1, this._gestureEnd = new v(this, () => [[
39
40
  document,
40
41
  "pointerup",
41
42
  this._onGestureEnd,
@@ -59,9 +60,9 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
59
60
  }
60
61
  static {
61
62
  this.styles = [
62
- o,
63
- h,
64
- x`
63
+ s,
64
+ g,
65
+ S`
65
66
  :host {
66
67
  display: block;
67
68
  position: relative;
@@ -110,8 +111,8 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
110
111
  belt-and-braces paint beneath the (opaque) kit fill. Override the
111
112
  whole tile via --vf-desktop-pattern — the tile grid renders the
112
113
  same token at the same documented geometry. */
113
- background-image: var(--vf-desktop-pattern, ${C(j)});
114
- ${d(k)}
114
+ background-image: var(--vf-desktop-pattern, ${w(M)});
115
+ ${f(A)}
115
116
  /* Forced colors: the checker is opaque literal white-and-black (a
116
117
  preserved url() tile), which ignores a dark theme entirely. A
117
118
  backdrop is decoration, and high-contrast mode is a request for
@@ -148,7 +149,7 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
148
149
  .screen > .vf-tile-grid {
149
150
  position: absolute;
150
151
  inset: 0;
151
- --_vf-tile-image: var(--vf-desktop-pattern, ${C(M)});
152
+ --_vf-tile-image: var(--vf-desktop-pattern, ${w(N)});
152
153
  }
153
154
  /* Bezeled, the screen is inset by exactly one bezel width. The host
154
155
  is always the declared screen + 2×bezel (written in updated()), so
@@ -175,25 +176,25 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
175
176
  .corner {
176
177
  position: absolute;
177
178
  top: 0;
178
- width: calc(var(--vf-scale, 1) * ${v[0]}px);
179
- height: calc(var(--vf-scale, 1) * ${v.length}px);
179
+ width: calc(var(--vf-scale, 1) * ${y[0]}px);
180
+ height: calc(var(--vf-scale, 1) * ${y.length}px);
180
181
  background: var(--vf-black, #000);
181
182
  pointer-events: none;
182
183
  z-index: 2147483647;
183
184
  }
184
185
  .corner.tl {
185
186
  left: 0;
186
- clip-path: ${C(y(v, "left"))};
187
+ clip-path: ${w(b(y, "left"))};
187
188
  }
188
189
  .corner.tr {
189
190
  right: 0;
190
- clip-path: ${C(y(v, "right"))};
191
+ clip-path: ${w(b(y, "right"))};
191
192
  }
192
193
  `
193
194
  ];
194
195
  }
195
196
  fitWithin(e, t) {
196
- let r = n(this), i = (e) => Math.max(0, Math.floor(e / r + 1e-6) - 2 * this.bezel);
197
+ let n = r(this), i = (e) => Math.max(0, Math.floor(e / n + 1e-6) - 2 * this.bezel);
197
198
  return this.width = i(e), this.height = i(t), {
198
199
  width: this.width,
199
200
  height: this.height
@@ -212,9 +213,15 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
212
213
  bringToFront(e) {
213
214
  this._restack(e), this._requestDomSync();
214
215
  }
216
+ get activeWindow() {
217
+ return this._activeWindow;
218
+ }
219
+ clearActive() {
220
+ this._deactivated = !0, this._setActive(null);
221
+ }
215
222
  _restack(e) {
216
223
  let t = this._isUtility(e);
217
- e.style.zIndex = String(++this._zCounter + (t ? E : 0)), t || this._setActive(e);
224
+ e.style.zIndex = String(++this._zCounter + (t ? D : 0)), t || this._setActive(e);
218
225
  }
219
226
  _requestDomSync() {
220
227
  this._pointerGesture || this._syncDomOrder();
@@ -231,20 +238,22 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
231
238
  let e = this._windows, t = null;
232
239
  for (let n of e) if (!n.style.zIndex) {
233
240
  let e = this._isUtility(n);
234
- n.style.zIndex = String(++this._zCounter + (e ? E : 0)), e || (t = n);
241
+ n.style.zIndex = String(++this._zCounter + (e ? D : 0)), e || (t = n);
235
242
  }
236
- let n = t ?? this._topmost(e.filter((e) => !this._isUtility(e)));
237
- n && this._setActive(n), customElements.get("vf-window") || this._normalizeAfterUpgrade();
243
+ let n = e.filter((e) => !this._isUtility(e)), r = this._activeWindow && n.includes(this._activeWindow) ? this._activeWindow : null;
244
+ this._setActive(t ?? r ?? (this._deactivated ? null : this._topmost(n))), customElements.get("vf-window") || this._normalizeAfterUpgrade();
238
245
  }
239
246
  _normalizeAfterUpgrade() {
240
247
  this._awaitingUpgrade || (this._awaitingUpgrade = !0, customElements.whenDefined("vf-window").then(() => {
241
248
  if (this._awaitingUpgrade = !1, !this.isConnected) return;
242
- let e = this._topmost(this._windows.filter((e) => !this._isUtility(e)));
243
- e && this._setActive(e);
249
+ let e = this._windows.filter((e) => !this._isUtility(e)), t = this._activeWindow && e.includes(this._activeWindow) ? this._activeWindow : null;
250
+ this._setActive(t ?? (this._deactivated ? null : this._topmost(e)));
244
251
  }));
245
252
  }
246
- _setActive(e) {
247
- for (let t of this._windows) this._isUtility(t) || this._setWindowActive(t, t === e);
253
+ _setActive(t) {
254
+ t && (this._deactivated = !1);
255
+ for (let e of this._windows) this._isUtility(e) || this._setWindowActive(e, e === t);
256
+ t !== this._activeWindow && (this._activeWindow = t, e(this, "vf-activate", { window: t }));
248
257
  }
249
258
  _setWindowActive(e, t) {
250
259
  if ("active" in e) {
@@ -274,37 +283,37 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
274
283
  r && n instanceof HTMLElement && n.isConnected && this._deepActiveElement() !== n && (this._restoringFocus = !0, n.focus({ preventScroll: !0 }), this._restoringFocus = !1);
275
284
  }
276
285
  willUpdate(e) {
277
- super.willUpdate(e), this._pattern = p(this, "--vf-desktop-pattern");
286
+ super.willUpdate(e), this._pattern = m(this, "--vf-desktop-pattern");
278
287
  }
279
288
  updated(e) {
280
- if (e.has("bezel") && (this.bezel > 0 ? this.style.setProperty("--vf-desktop-bezel", r(this.bezel)) : this.style.removeProperty("--vf-desktop-bezel")), e.has("width") || e.has("height") || e.has("bezel")) {
281
- let e = this.width ?? D, t = this.height ?? O;
282
- this.style.width = r(e + 2 * this.bezel), this.style.height = r(t + 2 * this.bezel);
289
+ if (e.has("bezel") && (this.bezel > 0 ? this.style.setProperty("--vf-desktop-bezel", i(this.bezel)) : this.style.removeProperty("--vf-desktop-bezel")), e.has("width") || e.has("height") || e.has("bezel")) {
290
+ let e = this.width ?? O, t = this.height ?? k;
291
+ this.style.width = i(e + 2 * this.bezel), this.style.height = i(t + 2 * this.bezel);
283
292
  }
284
293
  }
285
294
  render() {
286
- let e = this.width ?? D, t = this.height ?? O, n = Math.ceil(e / N), i = Math.ceil(t / N), a = this._pattern ? S`<div class="vf-tile-grid">
287
- ${m({
295
+ let e = this.width ?? O, t = this.height ?? k, n = Math.ceil(e / P), r = Math.ceil(t / P), a = this._pattern ? C`<div class="vf-tile-grid">
296
+ ${h({
288
297
  cols: n,
289
- rows: i,
290
- tile: N
298
+ rows: r,
299
+ tile: P
291
300
  })}
292
- </div>` : S`<div
301
+ </div>` : C`<div
293
302
  class="vf-tile-raster"
294
- style="width:${r(n * N)};height:${r(i * N)};background-image:${this.#e.for(k, k, A, n * N, i * N)}"
303
+ style="width:${i(n * P)};height:${i(r * P)};background-image:${this.#e.for(A, A, j, n * P, r * P)}"
295
304
  ></div>`;
296
- return S`
305
+ return C`
297
306
  <div class=${this.bezel > 0 ? "desktop vf-snap bezeled" : "desktop vf-snap"}>
298
307
  <div class="screen${this._pattern ? " patterned" : ""}" part="desktop">
299
308
  ${a}
300
309
  <slot @slotchange=${this._onSlotChange}></slot>
301
- ${this.bezel > 0 ? S`<div class="corner tl"></div>
310
+ ${this.bezel > 0 ? C`<div class="corner tl"></div>
302
311
  <div class="corner tr"></div>` : null}
303
312
  </div>
304
313
  </div>
305
314
  `;
306
315
  }
307
316
  };
308
- i([w({ type: Number })], P.prototype, "width", void 0), i([w({ type: Number })], P.prototype, "height", void 0), i([w({ type: Number })], P.prototype, "bezel", void 0), i([T({ selector: "vf-window" })], P.prototype, "_windows", void 0), P = i([e("vf-desktop")], P);
317
+ a([T({ type: Number })], F.prototype, "width", void 0), a([T({ type: Number })], F.prototype, "height", void 0), a([T({ type: Number })], F.prototype, "bezel", void 0), a([E({ selector: "vf-window" })], F.prototype, "_windows", void 0), F = a([t("vf-desktop")], F);
309
318
  //#endregion
310
- export { P as VfDesktop };
319
+ export { F as VfDesktop };