vintage-frames 0.3.0 → 0.5.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 (45) hide show
  1. package/custom-elements.json +181 -32
  2. package/dist/components/vf-button.js +25 -25
  3. package/dist/components/vf-checkbox.js +15 -15
  4. package/dist/components/vf-container.d.ts +37 -3
  5. package/dist/components/vf-container.js +32 -10
  6. package/dist/components/vf-desktop.d.ts +103 -22
  7. package/dist/components/vf-desktop.js +100 -121
  8. package/dist/components/vf-dialog.d.ts +19 -15
  9. package/dist/components/vf-dialog.js +45 -53
  10. package/dist/components/vf-icon.js +56 -56
  11. package/dist/components/vf-list-item.js +16 -16
  12. package/dist/components/vf-list.js +26 -26
  13. package/dist/components/vf-menu-item.js +24 -24
  14. package/dist/components/vf-menu.js +27 -27
  15. package/dist/components/vf-number-field.js +17 -17
  16. package/dist/components/vf-progress-bar.js +3 -3
  17. package/dist/components/vf-radio-group.js +13 -13
  18. package/dist/components/vf-radio.js +16 -16
  19. package/dist/components/vf-select.js +27 -27
  20. package/dist/components/vf-slider.js +32 -32
  21. package/dist/components/vf-window.js +69 -69
  22. package/dist/index.d.ts +14 -0
  23. package/dist/index.js +73 -71
  24. package/dist/modal-dialog.js +21 -21
  25. package/dist/pattern-fill.d.ts +91 -0
  26. package/dist/pattern-fill.js +74 -0
  27. package/dist/patterns.d.ts +80 -0
  28. package/dist/patterns.js +477 -0
  29. package/dist/scroll-rail.js +37 -37
  30. package/dist/styles/recipes/pattern.d.ts +2 -12
  31. package/dist/styles/recipes/pattern.js +11 -15
  32. package/dist/styles/recipes/scroll-rail.d.ts +3 -12
  33. package/dist/styles/recipes/scroll-rail.js +7 -15
  34. package/dist/styles/recipes/surface.d.ts +18 -7
  35. package/dist/styles/recipes/surface.js +15 -0
  36. package/dist/text-control.js +11 -11
  37. package/dist/tile-grid.d.ts +4 -2
  38. package/dist/tile-grid.js +3 -3
  39. package/dist/toggle-control.js +5 -5
  40. package/dist/track-width.d.ts +7 -0
  41. package/dist/track-width.js +6 -3
  42. package/docs/SPEC.md +14 -10
  43. package/editor/vscode.html-custom-data.json +14 -4
  44. package/editor/web-types.json +46 -8
  45. package/package.json +3 -1
@@ -3,16 +3,29 @@ import { ScaleController as t } from "../scale.js";
3
3
  import n from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
4
  import { VfPositioned as r } from "../position.js";
5
5
  import { vfBase as i } from "../styles/recipes/host.js";
6
- import { GridSnapController as a } from "../grid-snap.js";
7
- import { VfSized as o } from "../size.js";
8
- import { LitElement as s, css as c, html as l } from "lit";
6
+ import { parsePattern as a } from "../patterns.js";
7
+ import { PatternFillController as o, vfPatternFill as s } from "../pattern-fill.js";
8
+ import { GridSnapController as c } from "../grid-snap.js";
9
+ import { VfSized as l } from "../size.js";
10
+ import { LitElement as u, css as d, html as f } from "lit";
11
+ import { property as p, query as m } from "lit/decorators.js";
9
12
  //#region src/components/vf-container.ts
10
- var u = class extends o(r(s)) {
13
+ var h = class extends l(r(u)) {
11
14
  constructor(...e) {
12
- super(...e), this.scale = new t(this), this.gridSnap = new a(this);
15
+ super(...e), this._pattern = null, this.#e = !1, this.scale = new t(this), this.gridSnap = new c(this), this.patternFill = new o(this, {
16
+ getBox: () => this.box,
17
+ getPattern: () => this._pattern,
18
+ getSize: () => ({
19
+ width: this.width,
20
+ height: this.height
21
+ })
22
+ });
13
23
  }
14
24
  static {
15
- this.styles = [i, c`
25
+ this.styles = [
26
+ i,
27
+ s,
28
+ d`
16
29
  :host {
17
30
  display: block;
18
31
  /* Shrink-wrap an undeclared axis rather than claim the parent's
@@ -75,12 +88,21 @@ var u = class extends o(r(s)) {
75
88
  ::slotted([fill-height]) {
76
89
  height: 100%;
77
90
  }
78
- `];
91
+ `
92
+ ];
93
+ }
94
+ #e;
95
+ willUpdate(e) {
96
+ super.willUpdate(e), e.has("pattern") && (this._pattern = a(this.pattern), this._pattern === null && this.pattern?.trim() && !this.#e && (this.#e = !0, console.warn(`vf-container: unknown pattern "${this.pattern}" — a library name (docs/PATTERNS.md) or sixteen hex digits. Painting nothing.`)));
79
97
  }
80
98
  render() {
81
- return l`<div class="vf-snap box"><slot></slot></div>`;
99
+ return f`<div
100
+ class="vf-snap box vf-pattern-fill${this._pattern ? " vf-patterned" : ""}"
101
+ >
102
+ <slot></slot>
103
+ </div>`;
82
104
  }
83
105
  };
84
- u = n([e("vf-container")], u);
106
+ n([p()], h.prototype, "pattern", void 0), n([m(".box")], h.prototype, "box", void 0), h = n([e("vf-container")], h);
85
107
  //#endregion
86
- export { u as VfContainer };
108
+ export { h as VfContainer };
@@ -3,8 +3,10 @@ declare const VfDesktop_base: (new (...args: any[]) => import("../position.js").
3
3
  /**
4
4
  * `<vf-desktop>` — the full-bleed classic desktop container.
5
5
  *
6
- * Renders the 50%-dither gray desktop pattern and manages the stacking order
7
- * and `active` state of slotted `vf-window` children: a `pointerdown` or
6
+ * Renders the desktop pattern the classic 50% dither by default, or any of
7
+ * the standard patterns by name (`pattern`, System 7's General Controls
8
+ * setting) — and manages the stacking order and `active` state of slotted
9
+ * `vf-window` children: a `pointerdown` or
8
10
  * `focusin` (keyboard focus) anywhere inside a window brings it to the front
9
11
  * and makes it the single active window. The windows' light-DOM order is kept
10
12
  * in step with the stacking order (bottom-most first, at pointer-gesture
@@ -17,6 +19,20 @@ declare const VfDesktop_base: (new (...args: any[]) => import("../position.js").
17
19
  * deactivates the active document window nor greys the palette, exactly as
18
20
  * System 7's floating windoids behaved while their application was frontmost.
19
21
  *
22
+ * **Deactivation.** On a real System 7 machine clicking the desktop clicked
23
+ * the *Finder* — the frontmost application's windows lost their stripes.
24
+ * {@link clearActive} is that gesture's handler: it clears `active` from
25
+ * the whole document tier, and **zero active windows is a legal state**,
26
+ * held until a press or keyboard focus re-enters a document window (or a
27
+ * new one is slotted, which activates it — opening a window brings its
28
+ * application forward). The desktop never takes this decision itself: its
29
+ * furniture is slotted light DOM (an icon layer, say), so only the page
30
+ * knows which of its children — or which presses on the bare dither — mean
31
+ * "the Finder", and it routes those through `clearActive()`. Left alone,
32
+ * the classic always-one-active behavior is unchanged. {@link activeWindow}
33
+ * reads the current holder, and every change of holder — including to and
34
+ * from none — fires `vf-activate`.
35
+ *
20
36
  * The desktop is a raster with an explicit size, always: **`width` and
21
37
  * `height`**, in system px, the way a WIND resource declared a window's —
22
38
  * the host box renders at the declared screen plus `2 × bezel` per axis, a
@@ -29,27 +45,41 @@ declare const VfDesktop_base: (new (...args: any[]) => import("../position.js").
29
45
  * the CRT's unlit margin — around the screen, rounding its top corners
30
46
  * with the classic corner mask.
31
47
  *
48
+ * **`pattern`** names the desktop pattern — `gray-50` (the dither) by
49
+ * default, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen
50
+ * hex digits stating a custom 8×8 pattern, as on `vf-container`. It is
51
+ * painted as the screen's own background: black ink on an opaque white
52
+ * paper, one whole-surface raster at one image px per system px, 1-bit at
53
+ * every density and zoom (src/pattern-fill.ts).
54
+ *
32
55
  * Custom properties:
33
- * - `--vf-desktop-pattern` — the dither's tile art (default a 1-bit 50%
34
- * checker, opaque black-on-white on a 30-system-px tile). Overriding it
35
- * renders the token as a placed tile grid at that same 30-px geometry
56
+ * - `--vf-desktop-pattern` — a consumer's own tile art in place of the
57
+ * pattern (the kit's default is a 1-bit 50% checker, opaque
58
+ * black-on-white on a 30-system-px tile). Set, it wins over `pattern` and
59
+ * renders as a placed tile grid at that same 30-px geometry
36
60
  * (src/tile-grid.ts); a token swapped at runtime without touching the
37
61
  * component wants a `requestUpdate()`.
38
- * - `--vf-desktop` — base color painted *under* the pattern layer (default
39
- * `#808080`). The default tile is opaque, so this only becomes visible when
40
- * `--vf-desktop-pattern` is overridden with a tile that has transparent
41
- * cells (or with `none`).
62
+ * - `--vf-desktop` — base color painted *under* the pattern (default
63
+ * `#808080`). The pattern's paper is opaque, so this only becomes visible
64
+ * when `--vf-desktop-pattern` is overridden with a tile that has
65
+ * transparent cells (or with `none`).
42
66
  *
43
67
  * @slot - Default slot: menu bar, windows, anything.
44
- * @csspart desktop - The dithered screen surface the whole-system-px
68
+ * @fires vf-activate - The active document-tier window changed. Detail
69
+ * `{ window: HTMLElement | null }` — the new holder, or `null` when the
70
+ * document tier deactivated (a {@link clearActive} call, or the active
71
+ * window leaving the DOM with none behind it). Fired once per change of
72
+ * holder, never for a re-assertion of the same one.
73
+ * @csspart desktop - The patterned screen surface — the whole-system-px
45
74
  * raster (inset by `bezel` when one is set).
46
- * @cssprop [--vf-desktop=#808080] - base color under the desktop dither
47
- * occluded by the default (opaque) tile, so it only shows through a custom
48
- * `--vf-desktop-pattern`
49
- * @cssprop --vf-desktop-pattern - the desktop dither's art a 50% checker
50
- * drawn as opaque black-on-white rects, on a 30-system-px tile. Override the
51
- * whole tile; consumer art renders as a placed tile grid at that same
52
- * geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom)
75
+ * @cssprop [--vf-desktop=#808080] - base color under the desktop pattern
76
+ * occluded by the pattern's opaque paper, so it only shows through a
77
+ * custom `--vf-desktop-pattern`
78
+ * @cssprop --vf-desktop-pattern - a consumer's own desktop tile, in place of
79
+ * `pattern` the kit's default is the 50% checker drawn as opaque
80
+ * black-on-white rects on a 30-system-px tile. Override the whole tile;
81
+ * consumer art renders as a placed tile grid at that same geometry (raster
82
+ * art magnifies nearest-neighbor, the `vf-img` idiom)
53
83
  */
54
84
  export declare class VfDesktop extends VfDesktop_base {
55
85
  #private;
@@ -79,6 +109,17 @@ export declare class VfDesktop extends VfDesktop_base {
79
109
  * the same pixels.
80
110
  */
81
111
  bezel: number;
112
+ /**
113
+ * The desktop pattern — System 7's General Controls setting. A library
114
+ * pattern by name (`gray-50`, the classic dither, by default; `gray-75`,
115
+ * `bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom
116
+ * 8×8 pattern, as on `vf-container`. Painted black on opaque white over
117
+ * the whole screen, 1-bit at every density and zoom. A
118
+ * `--vf-desktop-pattern` token override still wins and renders the
119
+ * consumer's tile as a placed grid; an unrecognized value warns once and
120
+ * keeps the dither.
121
+ */
122
+ pattern: string | null | undefined;
82
123
  /**
83
124
  * Size the screen to the largest whole-system-px raster whose host box —
84
125
  * bezel included — fits a CSS-px bound, and return what was set. The
@@ -101,13 +142,38 @@ export declare class VfDesktop extends VfDesktop_base {
101
142
  private readonly gridSnap;
102
143
  /**
103
144
  * The consumer's `--vf-desktop-pattern` override, or `''` for the kit
104
- * dither — which of the two exact-fill paths render() takes (see
145
+ * pattern — which of the two exact-fill paths render() takes (see
105
146
  * src/tile-grid.ts). Re-read every update; a token swapped at runtime
106
147
  * without touching the component wants a `requestUpdate()`.
107
148
  */
108
- private _pattern;
149
+ private _token;
150
+ /** `pattern`, resolved — the kit path's art; the dither when unset. */
151
+ private _desktopPattern;
152
+ /** The screen surface the pattern paints on; exists from the first render. */
153
+ private readonly screen;
154
+ /**
155
+ * The desktop pattern, painted as the screen's own background
156
+ * (src/pattern-fill.ts) from the declared raster — scale-independent, so
157
+ * density and zoom re-encode nothing — and silent while a consumer token
158
+ * owns the fill.
159
+ */
160
+ private readonly patternFill;
109
161
  /** Monotonic z-index counter for window stacking. */
110
162
  private _zCounter;
163
+ /**
164
+ * The active document-tier window, or null when the tier is deactivated
165
+ * (or empty). The single change-tracked truth behind {@link activeWindow}
166
+ * and the `vf-activate` event — written only by {@link _setActive}.
167
+ */
168
+ private _activeWindow;
169
+ /**
170
+ * Whether the document tier was *deliberately* deactivated (a
171
+ * {@link clearActive} call) — as opposed to `_activeWindow` being null
172
+ * because nothing has activated yet. Slot changes preserve a deliberate
173
+ * deactivation instead of promoting a survivor; a newly slotted document
174
+ * window still activates (opening a window brings its application forward).
175
+ */
176
+ private _deactivated;
111
177
  /** Whether a one-shot post-upgrade re-normalization is already pending. */
112
178
  private _awaitingUpgrade;
113
179
  /** Whether a pointer gesture that began on the desktop is still in flight. */
@@ -143,6 +209,18 @@ export declare class VfDesktop extends VfDesktop_base {
143
209
  * draggable in the same gesture that raises it.
144
210
  */
145
211
  bringToFront(win: HTMLElement): void;
212
+ /** The active document-tier window, or null while the tier is deactivated
213
+ * (or has no windows). Utility windows are never the holder. */
214
+ get activeWindow(): HTMLElement | null;
215
+ /**
216
+ * Deactivate the whole document tier — clear `active` from every document
217
+ * window, leaving none the holder. Pages route "the user clicked the
218
+ * Finder" presses — on the bare dither, on their own desktop furniture
219
+ * (an icon layer) — through here; the deactivated state holds until a
220
+ * document window is pressed, focused, brought to front, or newly
221
+ * slotted.
222
+ */
223
+ clearActive(): void;
146
224
  /** The z/active half of a raise, shared by every path. */
147
225
  private _restack;
148
226
  /** Sync the DOM order now, or at gesture end if a pointer is down. */
@@ -199,9 +277,12 @@ export declare class VfDesktop extends VfDesktop_base {
199
277
  */
200
278
  private _normalizeAfterUpgrade;
201
279
  /** 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). */
280
+ * window (`null` clears the whole tier — the deactivated state). Utility
281
+ * windows stand outside the invariant: a palette keeps whatever `active`
282
+ * state it has (true by default, so its dither and widgets stay drawn
283
+ * while document windows trade the highlight). The one write site of
284
+ * {@link _activeWindow}, so `vf-activate` fires exactly on a change of
285
+ * holder — re-asserting the current holder is silent. */
205
286
  private _setActive;
206
287
  /**
207
288
  * Set a window's `active` state. Prefers the property (the source of truth
@@ -1,41 +1,29 @@
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, tileRects as l, tileSpan as u } from "../styles/recipes/tile.js";
8
+ import { PATTERNS as d, parsePattern as f, patternMotif as p } from "../patterns.js";
9
+ import { patternOverride as m, tileGrid as h, vfTileGrid as g } from "../tile-grid.js";
10
+ import { PatternFillController as _, vfPatternFill as v } from "../pattern-fill.js";
11
+ import { GridSnapController as y } from "../grid-snap.js";
12
+ import { DocumentListenersController as b } from "../document-listeners.js";
13
+ import { SCREEN_CORNER as x, steppedCornerClip as S } from "../pixel-frame.js";
14
+ import { LitElement as C, css as w, html as T, unsafeCSS as E } from "lit";
15
+ import { property as D, query as O, queryAssignedElements as k } from "lit/decorators.js";
13
16
  //#region src/components/vf-desktop.ts
14
- var E = 1e6, D = 512, O = 342, k = 2, A = [
15
- [
16
- 0,
17
- 0,
18
- 2,
19
- 2,
20
- "#ffffff"
21
- ],
22
- [
23
- 0,
24
- 0,
25
- 1,
26
- 1,
27
- "#000000"
28
- ],
29
- [
30
- 1,
31
- 1,
32
- 1,
33
- 1,
34
- "#000000"
35
- ]
36
- ], j = s(k, k, l(A)), M = c(k, k, A), N = u(k), P = class extends a(b) {
17
+ var A = 1e6, j = 512, M = 342, N = "gray-50", P = p(d[N], "#000000", "#ffffff"), F = c(P.width, P.height, l(P.rects)), I = u(P.width), L = class extends o(C) {
37
18
  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, () => [[
19
+ super(...e), this.width = j, this.height = M, this.bezel = 0, this.pattern = N, this.scale = new n(this), this.gridSnap = new y(this), this._token = "", this._desktopPattern = d[N], this.#e = !1, this.patternFill = new _(this, {
20
+ getBox: () => this.screen,
21
+ getPattern: () => this._token ? null : this._desktopPattern,
22
+ getSize: () => ({
23
+ width: this.width ?? j,
24
+ height: this.height ?? M
25
+ })
26
+ }), this._zCounter = 0, this._activeWindow = null, this._deactivated = !1, this._awaitingUpgrade = !1, this._pointerGesture = !1, this._restoringFocus = !1, this._gestureEnd = new b(this, () => [[
39
27
  document,
40
28
  "pointerup",
41
29
  this._onGestureEnd,
@@ -59,9 +47,10 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
59
47
  }
60
48
  static {
61
49
  this.styles = [
62
- o,
63
- h,
64
- x`
50
+ s,
51
+ g,
52
+ v,
53
+ w`
65
54
  :host {
66
55
  display: block;
67
56
  position: relative;
@@ -87,69 +76,48 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
87
76
  raster's corrected edge, not the host's possibly-fractional one. */
88
77
  overflow: hidden;
89
78
  /* An isolated stacking context, so the tile grid's z-index: -1 below
90
- resolves HERE — above this element's own underlay background, under
91
- every slotted child. Without it the negative z-index would resolve
79
+ resolves HERE — above this element's own background, under every
80
+ slotted child. Without it the negative z-index would resolve
92
81
  against some ancestor stacking context and paint the tiles beneath
93
82
  this background. */
94
83
  isolation: isolate;
84
+ /* The base color. Under the kit pattern it is covered by the fill's
85
+ opaque white paper (vfPatternFill) — the authentic black-on-white
86
+ dither — and shows only through a consumer token's translucent
87
+ tile (see the --vf-desktop note in the class doc). The pattern
88
+ itself is this element's own background, written by the
89
+ PatternFillController: one whole-surface raster at one image px
90
+ per system px, magnified nearest-neighbor, which is what keeps it
91
+ 1-bit at the zoom-minted scales a repeating fill cannot hold
92
+ (src/tile-grid.ts, src/pattern-fill.ts). */
95
93
  background-color: var(--vf-desktop, #808080);
96
- /* Classic 50% checker dither as a crisp 1-bit SVG tile — a 2×2 motif
97
- painting an opaque white base with two black pixels on the diagonal.
98
- Black-on-white is the authentic System 7 dither, so the tile is
99
- deliberately opaque and covers the background-color above (see the
100
- --vf-desktop note in the class doc). Scaled with --vf-scale so each
101
- system pixel lands on whole device pixels; unlike a conic-gradient
102
- (whose hard stops the browser feathers into a blur), the SVG rects are
103
- pixel-exact.
104
-
105
- This CSS-repeated layer is the UNDERLAY: what actually shows is the
106
- whole-surface raster (or, under a consumer pattern token, the
107
- placed tile grid) rendered over it — see src/tile-grid.ts — which
108
- is what keeps the dither 1-bit at the zoom-minted scales a
109
- repeating fill cannot hold. The declaration stays as
110
- belt-and-braces paint beneath the (opaque) kit fill. Override the
111
- whole tile via --vf-desktop-pattern — the tile grid renders the
112
- same token at the same documented geometry. */
113
- background-image: var(--vf-desktop-pattern, ${C(j)});
114
- ${d(k)}
115
- /* Forced colors: the checker is opaque literal white-and-black (a
116
- preserved url() tile), which ignores a dark theme entirely. A
117
- backdrop is decoration, and high-contrast mode is a request for
118
- less of that — so the desktop goes flat Canvas (the forced
119
- background-color) rather than re-dithering in the user's pair.
120
- Deliberate; the windoid dot bar, which carries meaning, IS
121
- re-inked (see vfDots). */
94
+ /* Forced colors: the pattern is literal black ink on white, which
95
+ ignores a dark theme entirely. A backdrop is decoration, and
96
+ high-contrast mode is a request for less of that — so the desktop
97
+ goes flat Canvas (the forced background-color) rather than
98
+ re-dithering in the user's pair. Deliberate; the windoid dot bar,
99
+ which carries meaning, IS re-inked (see vfDots). The recipe drops
100
+ the image too; stated here as well so the posture lives with the
101
+ surface. */
122
102
  @media (forced-colors: active) {
123
103
  background-image: none;
124
104
  }
125
105
  }
126
- /* With a consumer pattern token in play the exact fill is the placed
127
- tile grid, and the CSS-repeated underlay must not paint: a
128
- translucent consumer tile would show the underlay's *drifting* copy
129
- of the same art through itself. The base color stays that is the
130
- layer translucent art composites over, as documented. */
131
- .screen.patterned {
132
- background-image: none;
133
- }
134
- /* The dither's exact fill — the whole-surface raster (kit art) or the
135
- placed tile grid (consumer art) — kept under every slotted child
136
- (menu bar, windows) by the negative z-index the .screen isolation
137
- scopes. The grid's tiles resolve the pattern token stated once here
138
- rather than per tile. */
139
- .screen > .vf-tile-grid,
140
- .screen > .vf-tile-raster {
106
+ /* A consumer token's exact fill the placed tile grid kept under
107
+ every slotted child (menu bar, windows) by the negative z-index the
108
+ .screen isolation scopes. The grid's tiles resolve the token stated
109
+ once here rather than per tile; the fallback is the kit dither for
110
+ the record, never reached (the grid renders only under a set token). */
111
+ .screen > .vf-tile-grid {
112
+ position: absolute;
113
+ inset: 0;
141
114
  z-index: -1;
142
- /* Forced colors: hidden with the underlay's tile, same posture — the
143
- desktop goes flat Canvas (a backdrop is decoration). */
115
+ --_vf-tile-image: var(--vf-desktop-pattern, ${E(F)});
116
+ /* Forced colors: hidden with the pattern, same posture. */
144
117
  @media (forced-colors: active) {
145
118
  display: none;
146
119
  }
147
120
  }
148
- .screen > .vf-tile-grid {
149
- position: absolute;
150
- inset: 0;
151
- --_vf-tile-image: var(--vf-desktop-pattern, ${C(M)});
152
- }
153
121
  /* Bezeled, the screen is inset by exactly one bezel width. The host
154
122
  is always the declared screen + 2×bezel (written in updated()), so
155
123
  this subtraction is exact and the raster is whole by construction —
@@ -175,25 +143,25 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
175
143
  .corner {
176
144
  position: absolute;
177
145
  top: 0;
178
- width: calc(var(--vf-scale, 1) * ${v[0]}px);
179
- height: calc(var(--vf-scale, 1) * ${v.length}px);
146
+ width: calc(var(--vf-scale, 1) * ${x[0]}px);
147
+ height: calc(var(--vf-scale, 1) * ${x.length}px);
180
148
  background: var(--vf-black, #000);
181
149
  pointer-events: none;
182
150
  z-index: 2147483647;
183
151
  }
184
152
  .corner.tl {
185
153
  left: 0;
186
- clip-path: ${C(y(v, "left"))};
154
+ clip-path: ${E(S(x, "left"))};
187
155
  }
188
156
  .corner.tr {
189
157
  right: 0;
190
- clip-path: ${C(y(v, "right"))};
158
+ clip-path: ${E(S(x, "right"))};
191
159
  }
192
160
  `
193
161
  ];
194
162
  }
195
163
  fitWithin(e, t) {
196
- let r = n(this), i = (e) => Math.max(0, Math.floor(e / r + 1e-6) - 2 * this.bezel);
164
+ let n = r(this), i = (e) => Math.max(0, Math.floor(e / n + 1e-6) - 2 * this.bezel);
197
165
  return this.width = i(e), this.height = i(t), {
198
166
  width: this.width,
199
167
  height: this.height
@@ -212,9 +180,15 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
212
180
  bringToFront(e) {
213
181
  this._restack(e), this._requestDomSync();
214
182
  }
183
+ get activeWindow() {
184
+ return this._activeWindow;
185
+ }
186
+ clearActive() {
187
+ this._deactivated = !0, this._setActive(null);
188
+ }
215
189
  _restack(e) {
216
190
  let t = this._isUtility(e);
217
- e.style.zIndex = String(++this._zCounter + (t ? E : 0)), t || this._setActive(e);
191
+ e.style.zIndex = String(++this._zCounter + (t ? A : 0)), t || this._setActive(e);
218
192
  }
219
193
  _requestDomSync() {
220
194
  this._pointerGesture || this._syncDomOrder();
@@ -231,20 +205,22 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
231
205
  let e = this._windows, t = null;
232
206
  for (let n of e) if (!n.style.zIndex) {
233
207
  let e = this._isUtility(n);
234
- n.style.zIndex = String(++this._zCounter + (e ? E : 0)), e || (t = n);
208
+ n.style.zIndex = String(++this._zCounter + (e ? A : 0)), e || (t = n);
235
209
  }
236
- let n = t ?? this._topmost(e.filter((e) => !this._isUtility(e)));
237
- n && this._setActive(n), customElements.get("vf-window") || this._normalizeAfterUpgrade();
210
+ let n = e.filter((e) => !this._isUtility(e)), r = this._activeWindow && n.includes(this._activeWindow) ? this._activeWindow : null;
211
+ this._setActive(t ?? r ?? (this._deactivated ? null : this._topmost(n))), customElements.get("vf-window") || this._normalizeAfterUpgrade();
238
212
  }
239
213
  _normalizeAfterUpgrade() {
240
214
  this._awaitingUpgrade || (this._awaitingUpgrade = !0, customElements.whenDefined("vf-window").then(() => {
241
215
  if (this._awaitingUpgrade = !1, !this.isConnected) return;
242
- let e = this._topmost(this._windows.filter((e) => !this._isUtility(e)));
243
- e && this._setActive(e);
216
+ let e = this._windows.filter((e) => !this._isUtility(e)), t = this._activeWindow && e.includes(this._activeWindow) ? this._activeWindow : null;
217
+ this._setActive(t ?? (this._deactivated ? null : this._topmost(e)));
244
218
  }));
245
219
  }
246
- _setActive(e) {
247
- for (let t of this._windows) this._isUtility(t) || this._setWindowActive(t, t === e);
220
+ _setActive(t) {
221
+ t && (this._deactivated = !1);
222
+ for (let e of this._windows) this._isUtility(e) || this._setWindowActive(e, e === t);
223
+ t !== this._activeWindow && (this._activeWindow = t, e(this, "vf-activate", { window: t }));
248
224
  }
249
225
  _setWindowActive(e, t) {
250
226
  if ("active" in e) {
@@ -274,37 +250,40 @@ var E = 1e6, D = 512, O = 342, k = 2, A = [
274
250
  r && n instanceof HTMLElement && n.isConnected && this._deepActiveElement() !== n && (this._restoringFocus = !0, n.focus({ preventScroll: !0 }), this._restoringFocus = !1);
275
251
  }
276
252
  willUpdate(e) {
277
- super.willUpdate(e), this._pattern = p(this, "--vf-desktop-pattern");
253
+ if (super.willUpdate(e), this._token = m(this, "--vf-desktop-pattern"), e.has("pattern")) {
254
+ let e = f(this.pattern);
255
+ e === null && this.pattern?.trim() && !this.#e && (this.#e = !0, console.warn(`vf-desktop: unknown pattern "${this.pattern}" — a library name (docs/PATTERNS.md) or sixteen hex digits. Keeping ${N}.`)), this._desktopPattern = e ?? d[N];
256
+ }
278
257
  }
279
258
  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);
259
+ 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")) {
260
+ let e = this.width ?? j, t = this.height ?? M;
261
+ this.style.width = i(e + 2 * this.bezel), this.style.height = i(t + 2 * this.bezel);
283
262
  }
284
263
  }
285
264
  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({
288
- cols: n,
289
- rows: i,
290
- tile: N
265
+ let e = this.width ?? j, t = this.height ?? M, n = this._token ? T`<div class="vf-tile-grid">
266
+ ${h({
267
+ cols: Math.ceil(e / I),
268
+ rows: Math.ceil(t / I),
269
+ tile: I
291
270
  })}
292
- </div>` : S`<div
293
- 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)}"
295
- ></div>`;
296
- return S`
271
+ </div>` : null;
272
+ return T`
297
273
  <div class=${this.bezel > 0 ? "desktop vf-snap bezeled" : "desktop vf-snap"}>
298
- <div class="screen${this._pattern ? " patterned" : ""}" part="desktop">
299
- ${a}
274
+ <div
275
+ class="screen vf-pattern-fill${this._token ? "" : " vf-patterned"}"
276
+ part="desktop"
277
+ >
278
+ ${n}
300
279
  <slot @slotchange=${this._onSlotChange}></slot>
301
- ${this.bezel > 0 ? S`<div class="corner tl"></div>
280
+ ${this.bezel > 0 ? T`<div class="corner tl"></div>
302
281
  <div class="corner tr"></div>` : null}
303
282
  </div>
304
283
  </div>
305
284
  `;
306
285
  }
307
286
  };
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);
287
+ a([D({ type: Number })], L.prototype, "width", void 0), a([D({ type: Number })], L.prototype, "height", void 0), a([D({ type: Number })], L.prototype, "bezel", void 0), a([D()], L.prototype, "pattern", void 0), a([k({ selector: "vf-window" })], L.prototype, "_windows", void 0), a([O(".screen")], L.prototype, "screen", void 0), L = a([t("vf-desktop")], L);
309
288
  //#endregion
310
- export { P as VfDesktop };
289
+ export { L as VfDesktop };
@@ -4,19 +4,21 @@ import './vf-button-group.js';
4
4
  * `<vf-dialog>` — the System 7 modal dialog shell.
5
5
  *
6
6
  * Two chromes, one modal lifecycle (native `<dialog>` for top-layer rendering
7
- * and focus trapping, with a fully transparent backdrop — no dimming):
7
+ * and focus trapping, with a fully transparent backdrop — no dimming). Both
8
+ * are the same dBoxProc double frame — 1px outer rule, 2px gap, 2px inner
9
+ * band, no shadow ({@link vfModalFrame}):
8
10
  *
9
- * - **Default:** a striped title bar with a centered title over a white body —
10
- * the movable-modal look. Drag the title bar to move it. `closable` adds the
11
- * standard close box (left of the bar) the HIG's own figures disagree on
12
- * whether a movable modal carries one (Figure 5-1 says yes, Figure 6-1 and
13
- * the Chapter 6 text say no), so the component enables either reading rather
14
- * than enforcing one.
15
- * - **`frame="plain"`:** the classic dBoxProc modal-dialog frame — 1px outer
16
- * border, 2px gap, 2px inner band, no shadow, no title bar — and immovable,
17
- * like the original. A `heading` renders as a centered display-face heading
18
- * at the top of the body (the reference art's "Dialog title"); `closable` is
19
- * ignored, there being no bar to carry the widget.
11
+ * - **Default:** the movable modal (movableDBoxProc) the striped title bar
12
+ * set into the top of that frame, with a centered title over a white body.
13
+ * Drag the title bar to move it. `closable` adds the standard close box
14
+ * (left of the bar) the HIG's own figures disagree on whether a movable
15
+ * modal carries one (Figure 5-1 says yes, Figure 6-1 and the Chapter 6 text
16
+ * say no), so the component enables either reading rather than enforcing
17
+ * one.
18
+ * - **`frame="plain"`:** the modal dialog box — the bare frame, no title bar —
19
+ * and immovable, like the original. A `heading` renders as a centered
20
+ * display-face heading at the top of the body (the reference art's "Dialog
21
+ * title"); `closable` is ignored, there being no bar to carry the widget.
20
22
  *
21
23
  * Open it with `show()` (or set the `open` attribute/property); close with
22
24
  * `close()`. Escape closes it and fires `vf-close` with
@@ -27,7 +29,8 @@ import './vf-button-group.js';
27
29
  * @slot buttons - Optional action buttons. Rendered as a bottom-right
28
30
  * `vf-button-group` (equal-width, faces aligned); the footer only takes
29
31
  * space when the slot is populated.
30
- * @csspart frame - The outer chrome frame (striped-bar or plain).
32
+ * @csspart frame - The outer frame (the double frame's 1px rule; the bar and
33
+ * the inner band sit inside it).
31
34
  * @csspart title-bar - The striped title bar (default chrome only).
32
35
  * @csspart title - The centered title patch (or the plain-frame heading).
33
36
  * @csspart close-box - The close widget (`closable`, default chrome only).
@@ -76,8 +79,9 @@ export declare class VfDialog extends VfModalDialog {
76
79
  */
77
80
  closable: boolean;
78
81
  /**
79
- * Frame chrome. Omit for the striped title bar (movable modal); `'plain'`
80
- * for the immovable dBoxProc double frame with no bar (modal dialog box).
82
+ * Frame chrome. Omit for the movable modal (the double frame with the
83
+ * striped title bar set into it); `'plain'` for the immovable modal dialog
84
+ * box (the bare double frame, no bar).
81
85
  */
82
86
  frame?: 'plain';
83
87
  /** Whether the `buttons` slot has assigned content (drives the footer). */