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.
package/dist/index.js CHANGED
@@ -1,31 +1,31 @@
1
- import { defineElement as e, vfElement as t } from "./define.js";
2
- import { CLASSIC_DPI as n, CSS_REFERENCE_DPI as r, SYSTEM_PX_IN_CSS_PX as i, devicePxPerSystemPx as a, getZoom as o, onZoomChange as s, resetZoomBaseline as c, truePixelRatio as l } from "./zoom.js";
3
- import { ScaleController as u, applyScale as d, effectiveScale as f, getScale as p, onScaleChange as m, snapSys as h, snapToDevicePx as g, snapToSystemPx as _, sys as v, sysLength as y, sysLengths as b, systemPxQuantum as x, toSys as S, toSysExact as C } from "./scale.js";
4
- import { PlacementController as w, VfPositioned as T } from "./position.js";
5
- import { PIXEL_GRID_METRICS as E, registerEmbeddedFont as D } from "./styles/register-embedded-font.js";
6
- import { VF_BODY_FAMILY as O, registerBodyFace as k } from "./styles/body-font.js";
7
- import { vfBodyDecls as A } from "./styles/recipes/body-face.js";
8
- import { VF_DISPLAY_FAMILY as j, registerDisplayFace as M } from "./styles/display-font.js";
9
- import { vfDisplay as N, vfDisplayDecls as P } from "./styles/recipes/display-face.js";
10
- import { vfBase as F } from "./styles/recipes/host.js";
11
- import { vfStaticText as I } from "./styles/recipes/static-text.js";
12
- import { TILE_LATTICE as L, tileImage as R, tileRaster as z, tileRects as B, tileSpan as V, vfTileMaskSize as H, vfTileSize as U } from "./styles/recipes/tile.js";
13
- import { vfDots as W, vfStripes as G } from "./styles/recipes/pattern.js";
14
- import { vfHardShadowDecls as K } from "./styles/recipes/shadow.js";
15
- import { vfChromeFrame as q, vfModalFrame as J, vfPanel as Y } from "./styles/recipes/surface.js";
16
- import { vfTitleBar as X, vfWindowWidgets as Z } from "./styles/recipes/title-bar.js";
17
- import { vfFocus as Q, vfFocusRing as $, vfFocusUnderline as ee } from "./styles/recipes/focus.js";
18
- import { vfToggle as te } from "./styles/recipes/toggle.js";
19
- import { vfField as ne } from "./styles/recipes/field.js";
20
- import { vfScrollRail as re } from "./styles/recipes/scroll-rail.js";
21
- import { TileRasterCache as ie, patternOverride as ae, tileGrid as oe, vfTileGrid as se } from "./tile-grid.js";
22
- import { GridSnapController as ce, requestGridSnap as le } from "./grid-snap.js";
23
- import { DocumentListenersController as ue } from "./document-listeners.js";
24
- import { BUTTON_FACE as de, BUTTON_FRAME as fe, RING_FRAME as pe, RING_HOLE as me, RING_INSET as he, SCREEN_CORNER as ge, steppedCornerClip as _e, steppedRectClip as ve, steppedRingClip as ye } from "./pixel-frame.js";
25
- import { VfDesktop as be } from "./components/vf-desktop.js";
26
- import { VfSized as xe } from "./size.js";
27
- import { DragController as Se } from "./drag.js";
28
- import { emit as Ce } from "./events.js";
1
+ import { emit as e } from "./events.js";
2
+ import { defineElement as t, vfElement as n } from "./define.js";
3
+ import { CLASSIC_DPI as r, CSS_REFERENCE_DPI as i, SYSTEM_PX_IN_CSS_PX as a, devicePxPerSystemPx as o, getZoom as s, onZoomChange as c, resetZoomBaseline as l, truePixelRatio as u } from "./zoom.js";
4
+ import { ScaleController as d, applyScale as f, effectiveScale as p, getScale as m, onScaleChange as h, snapSys as g, snapToDevicePx as _, snapToSystemPx as v, sys as y, sysLength as b, sysLengths as x, systemPxQuantum as S, toSys as C, toSysExact as w } from "./scale.js";
5
+ import { PlacementController as T, VfPositioned as E } from "./position.js";
6
+ import { PIXEL_GRID_METRICS as D, registerEmbeddedFont as O } from "./styles/register-embedded-font.js";
7
+ import { VF_BODY_FAMILY as k, registerBodyFace as A } from "./styles/body-font.js";
8
+ import { vfBodyDecls as j } from "./styles/recipes/body-face.js";
9
+ import { VF_DISPLAY_FAMILY as M, registerDisplayFace as N } from "./styles/display-font.js";
10
+ import { vfDisplay as P, vfDisplayDecls as F } from "./styles/recipes/display-face.js";
11
+ import { vfBase as I } from "./styles/recipes/host.js";
12
+ import { vfStaticText as L } from "./styles/recipes/static-text.js";
13
+ import { TILE_LATTICE as R, tileImage as z, tileRaster as B, tileRects as V, tileSpan as H, vfTileMaskSize as U, vfTileSize as W } from "./styles/recipes/tile.js";
14
+ import { vfDots as G, vfStripes as K } from "./styles/recipes/pattern.js";
15
+ import { vfHardShadowDecls as q } from "./styles/recipes/shadow.js";
16
+ import { vfChromeFrame as J, vfModalFrame as Y, vfPanel as X } from "./styles/recipes/surface.js";
17
+ import { vfTitleBar as Z, vfWindowWidgets as Q } from "./styles/recipes/title-bar.js";
18
+ import { vfFocus as $, vfFocusRing as ee, vfFocusUnderline as te } from "./styles/recipes/focus.js";
19
+ import { vfToggle as ne } from "./styles/recipes/toggle.js";
20
+ import { vfField as re } from "./styles/recipes/field.js";
21
+ import { vfScrollRail as ie } from "./styles/recipes/scroll-rail.js";
22
+ import { TileRasterCache as ae, patternOverride as oe, tileGrid as se, vfTileGrid as ce } from "./tile-grid.js";
23
+ import { GridSnapController as le, requestGridSnap as ue } from "./grid-snap.js";
24
+ import { DocumentListenersController as de } from "./document-listeners.js";
25
+ import { BUTTON_FACE as fe, BUTTON_FRAME as pe, RING_FRAME as me, RING_HOLE as he, RING_INSET as ge, SCREEN_CORNER as _e, steppedCornerClip as ve, steppedRectClip as ye, steppedRingClip as be } from "./pixel-frame.js";
26
+ import { VfDesktop as xe } from "./components/vf-desktop.js";
27
+ import { VfSized as Se } from "./size.js";
28
+ import { DragController as Ce } from "./drag.js";
29
29
  import { ScrollStateController as we } from "./scroll-state.js";
30
30
  import { BLINK_FLIPS as Te, BLINK_INTERVAL_MS as Ee, PRESS_HOLD_MS as De, RENAME_DELAY_MS as Oe, prefersReducedMotion as ke, runSelectionBlink as Ae } from "./motion.js";
31
31
  import { CARET_DOWN as je, CHECKBOX_X as Me, CHECKMARK as Ne, RADIO_DOT as Pe, RADIO_FACE as Fe, RADIO_RING as Ie, RADIO_RING_PRESSED as Le, SLIDER_THUMB as Re, SLIDER_THUMB_FACE as ze, STEPPER as Be, STEPPER_DOWN_FILL as Ve, STEPPER_UP_FILL as He, glyphSvg as Ue } from "./glyphs.js";
@@ -68,4 +68,4 @@ import { VfStack as kt } from "./components/vf-stack.js";
68
68
  import { VfContainer as At } from "./components/vf-container.js";
69
69
  import { CURSOR_ARROW as jt, CURSOR_CROSSHAIR as Mt, CURSOR_I_BEAM as Nt, CURSOR_WAIT as Pt } from "./cursor-art.js";
70
70
  import { applyCursor as Ft } from "./cursor.js";
71
- export { Te as BLINK_FLIPS, Ee as BLINK_INTERVAL_MS, de as BUTTON_FACE, fe as BUTTON_FRAME, je as CARET_DOWN, Me as CHECKBOX_X, Ne as CHECKMARK, n as CLASSIC_DPI, r as CSS_REFERENCE_DPI, jt as CURSOR_ARROW, Mt as CURSOR_CROSSHAIR, Nt as CURSOR_I_BEAM, Pt as CURSOR_WAIT, ue as DocumentListenersController, Se as DragController, ot as FocusRuleController, ce as GridSnapController, E as PIXEL_GRID_METRICS, De as PRESS_HOLD_MS, w as PlacementController, Pe as RADIO_DOT, Fe as RADIO_FACE, Ie as RADIO_RING, Le as RADIO_RING_PRESSED, Oe as RENAME_DELAY_MS, pe as RING_FRAME, me as RING_HOLE, he as RING_INSET, ge as SCREEN_CORNER, Re as SLIDER_THUMB, ze as SLIDER_THUMB_FACE, Be as STEPPER, Ve as STEPPER_DOWN_FILL, He as STEPPER_UP_FILL, i as SYSTEM_PX_IN_CSS_PX, u as ScaleController, We as ScrollRailController, we as ScrollStateController, L as TILE_LATTICE, ie as TileRasterCache, ht as TrackWidthController, O as VF_BODY_FAMILY, j as VF_DISPLAY_FAMILY, et as VfButton, Xe as VfButtonGroup, rt as VfCheckbox, At as VfContainer, be as VfDesktop, Ze as VfDialog, Dt as VfFieldset, $e as VfFormControl, Ot as VfGrid, xt as VfIcon, bt as VfImg, vt as VfLabel, Tt as VfList, Et as VfListItem, Ct as VfMenu, St as VfMenuBar, wt as VfMenuItem, Je as VfModalDialog, ft as VfNumberField, pt as VfOption, yt as VfParagraph, T as VfPositioned, gt as VfProgressBar, it as VfRadio, at as VfRadioGroup, Ke as VfScrollArea, mt as VfSelect, Qe as VfSeparator, xe as VfSized, _t as VfSlider, kt as VfStack, tt as VfSwatch, dt as VfTextArea, lt as VfTextControlBase, ut as VfTextField, nt as VfToggleControl, qe as VfWindow, Ft as applyCursor, d as applyScale, e as defineElement, a as devicePxPerSystemPx, f as effectiveScale, Ce as emit, st as focusModality, p as getScale, o as getZoom, Ue as glyphSvg, Ye as modalDialogStyles, m as onScaleChange, s as onZoomChange, ae as patternOverride, ke as prefersReducedMotion, k as registerBodyFace, M as registerDisplayFace, D as registerEmbeddedFont, Ge as renderScrollRail, le as requestGridSnap, c as resetZoomBaseline, Ae as runSelectionBlink, h as snapSys, g as snapToDevicePx, _ as snapToSystemPx, _e as steppedCornerClip, ve as steppedRectClip, ye as steppedRingClip, v as sys, y as sysLength, b as sysLengths, x as systemPxQuantum, oe as tileGrid, R as tileImage, z as tileRaster, B as tileRects, V as tileSpan, S as toSys, C as toSysExact, ct as trackFocusModality, l as truePixelRatio, F as vfBase, A as vfBodyDecls, q as vfChromeFrame, N as vfDisplay, P as vfDisplayDecls, W as vfDots, t as vfElement, ne as vfField, Q as vfFocus, $ as vfFocusRing, ee as vfFocusUnderline, K as vfHardShadowDecls, J as vfModalFrame, Y as vfPanel, re as vfScrollRail, I as vfStaticText, G as vfStripes, se as vfTileGrid, H as vfTileMaskSize, U as vfTileSize, X as vfTitleBar, te as vfToggle, Z as vfWindowWidgets };
71
+ export { Te as BLINK_FLIPS, Ee as BLINK_INTERVAL_MS, fe as BUTTON_FACE, pe as BUTTON_FRAME, je as CARET_DOWN, Me as CHECKBOX_X, Ne as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, jt as CURSOR_ARROW, Mt as CURSOR_CROSSHAIR, Nt as CURSOR_I_BEAM, Pt as CURSOR_WAIT, de as DocumentListenersController, Ce as DragController, ot as FocusRuleController, le as GridSnapController, D as PIXEL_GRID_METRICS, De as PRESS_HOLD_MS, T as PlacementController, Pe as RADIO_DOT, Fe as RADIO_FACE, Ie as RADIO_RING, Le as RADIO_RING_PRESSED, Oe as RENAME_DELAY_MS, me as RING_FRAME, he as RING_HOLE, ge as RING_INSET, _e as SCREEN_CORNER, Re as SLIDER_THUMB, ze as SLIDER_THUMB_FACE, Be as STEPPER, Ve as STEPPER_DOWN_FILL, He as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, We as ScrollRailController, we as ScrollStateController, R as TILE_LATTICE, ae as TileRasterCache, ht as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, et as VfButton, Xe as VfButtonGroup, rt as VfCheckbox, At as VfContainer, xe as VfDesktop, Ze as VfDialog, Dt as VfFieldset, $e as VfFormControl, Ot as VfGrid, xt as VfIcon, bt as VfImg, vt as VfLabel, Tt as VfList, Et as VfListItem, Ct as VfMenu, St as VfMenuBar, wt as VfMenuItem, Je as VfModalDialog, ft as VfNumberField, pt as VfOption, yt as VfParagraph, E as VfPositioned, gt as VfProgressBar, it as VfRadio, at as VfRadioGroup, Ke as VfScrollArea, mt as VfSelect, Qe as VfSeparator, Se as VfSized, _t as VfSlider, kt as VfStack, tt as VfSwatch, dt as VfTextArea, lt as VfTextControlBase, ut as VfTextField, nt as VfToggleControl, qe as VfWindow, Ft as applyCursor, f as applyScale, t as defineElement, o as devicePxPerSystemPx, p as effectiveScale, e as emit, st as focusModality, m as getScale, s as getZoom, Ue as glyphSvg, Ye as modalDialogStyles, h as onScaleChange, c as onZoomChange, oe as patternOverride, ke as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, Ge as renderScrollRail, ue as requestGridSnap, l as resetZoomBaseline, Ae as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, ve as steppedCornerClip, ye as steppedRectClip, be as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, se as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, ct as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, J as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, G as vfDots, n as vfElement, re as vfField, $ as vfFocus, ee as vfFocusRing, te as vfFocusUnderline, q as vfHardShadowDecls, Y as vfModalFrame, X as vfPanel, ie as vfScrollRail, L as vfStaticText, K as vfStripes, ce as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, Z as vfTitleBar, ne as vfToggle, Q as vfWindowWidgets };
@@ -1,6 +1,6 @@
1
- import { ScaleController as e, onScaleChange as t, snapSys as n, sysLength as r, toSysExact as i } from "./scale.js";
2
- import a from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
3
- import { emit as o } from "./events.js";
1
+ import { emit as e } from "./events.js";
2
+ import { ScaleController as t, onScaleChange as n, snapSys as r, sysLength as i, toSysExact as a } from "./scale.js";
3
+ import o from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
4
  import { LitElement as s, css as c } from "lit";
5
5
  import { property as l, query as u } from "lit/decorators.js";
6
6
  var d = 24, f = c`
@@ -43,13 +43,13 @@ var d = 24, f = c`
43
43
  cursor: var(--vf-cursor, default);
44
44
  }
45
45
  `, p = class extends s {
46
- constructor(...t) {
47
- super(...t), this.scale = new e(this), this.open = !1, this.#e = !1, this.#n = null, this.#r = null, this.#l = () => this.settle();
46
+ constructor(...e) {
47
+ super(...e), this.scale = new t(this), this.open = !1, this.#e = !1, this.#n = null, this.#r = null, this.#l = () => this.settle();
48
48
  }
49
49
  get dialogSize() {
50
50
  return {
51
- width: r(this.width ?? 260),
52
- height: this.height === void 0 ? null : r(this.height)
51
+ width: i(this.width ?? 260),
52
+ height: this.height === void 0 ? null : i(this.height)
53
53
  };
54
54
  }
55
55
  #e;
@@ -75,12 +75,12 @@ var d = 24, f = c`
75
75
  #i() {
76
76
  let e = document.documentElement;
77
77
  return {
78
- width: i(e.clientWidth || window.innerWidth, this),
79
- height: i(e.clientHeight || window.innerHeight, this)
78
+ width: a(e.clientWidth || window.innerWidth, this),
79
+ height: a(e.clientHeight || window.innerHeight, this)
80
80
  };
81
81
  }
82
82
  #a(e, t) {
83
- let n = this.#i(), r = i(this._dialog?.offsetWidth ?? 0, this);
83
+ let n = this.#i(), r = a(this._dialog?.offsetWidth ?? 0, this);
84
84
  return {
85
85
  x: Math.min(Math.max(e, d - r), n.width - d),
86
86
  y: Math.min(Math.max(t, 0), Math.max(0, n.height - d))
@@ -89,13 +89,13 @@ var d = 24, f = c`
89
89
  #o() {
90
90
  let e = this.#i(), t = this._dialog?.getBoundingClientRect();
91
91
  return {
92
- x: (e.width - i(t?.width ?? 0, this)) / 2,
93
- y: (e.height - i(t?.height ?? 0, this)) / 2
92
+ x: (e.width - a(t?.width ?? 0, this)) / 2,
93
+ y: (e.height - a(t?.height ?? 0, this)) / 2
94
94
  };
95
95
  }
96
96
  placeAt(e, t) {
97
- let r = this.#a(e, t);
98
- this.left = n(r.x, this), this.top = n(r.y, this);
97
+ let n = this.#a(e, t);
98
+ this.left = r(n.x, this), this.top = r(n.y, this);
99
99
  }
100
100
  settle() {
101
101
  let e = this._dialog;
@@ -103,8 +103,8 @@ var d = 24, f = c`
103
103
  let t = this.left != null || this.top != null ? {
104
104
  x: this.left ?? 0,
105
105
  y: this.top ?? 0
106
- } : this.#o(), i = this.#a(t.x, t.y);
107
- e.style.left = r(n(i.x, this)), e.style.top = r(n(i.y, this)), e.style.right = "auto", e.style.bottom = "auto", e.style.margin = "0";
106
+ } : this.#o(), n = this.#a(t.x, t.y);
107
+ e.style.left = i(r(n.x, this)), e.style.top = i(r(n.y, this)), e.style.right = "auto", e.style.bottom = "auto", e.style.margin = "0";
108
108
  }
109
109
  #s() {
110
110
  let e = this._dialog?.style;
@@ -124,7 +124,7 @@ var d = 24, f = c`
124
124
  #u;
125
125
  #d;
126
126
  #f(e) {
127
- typeof ResizeObserver < "u" && !this.#u && (this.#u = new ResizeObserver(this.#l), this.#u.observe(e)), window.addEventListener("resize", this.#l), this.#d ??= t(this.#l);
127
+ typeof ResizeObserver < "u" && !this.#u && (this.#u = new ResizeObserver(this.#l), this.#u.observe(e)), window.addEventListener("resize", this.#l), this.#d ??= n(this.#l);
128
128
  }
129
129
  #p() {
130
130
  this.#u?.disconnect(), this.#u = void 0, window.removeEventListener("resize", this.#l), this.#d?.(), this.#d = void 0;
@@ -143,13 +143,13 @@ var d = 24, f = c`
143
143
  this.#n = "escape";
144
144
  }
145
145
  _onNativeClose() {
146
- let e = this.#n ?? "close";
147
- this.#n = null, this.#r = null, this.#p(), this.open = !1, this.#s(), o(this, "vf-close", { reason: e });
146
+ let t = this.#n ?? "close";
147
+ this.#n = null, this.#r = null, this.#p(), this.open = !1, this.#s(), e(this, "vf-close", { reason: t });
148
148
  }
149
149
  };
150
- a([l({
150
+ o([l({
151
151
  type: Boolean,
152
152
  reflect: !0
153
- })], p.prototype, "open", void 0), a([l({ type: Number })], p.prototype, "width", void 0), a([l({ type: Number })], p.prototype, "height", void 0), a([l({ type: Number })], p.prototype, "top", void 0), a([l({ type: Number })], p.prototype, "left", void 0), a([u("dialog")], p.prototype, "_dialog", void 0);
153
+ })], p.prototype, "open", void 0), o([l({ type: Number })], p.prototype, "width", void 0), o([l({ type: Number })], p.prototype, "height", void 0), o([l({ type: Number })], p.prototype, "top", void 0), o([l({ type: Number })], p.prototype, "left", void 0), o([u("dialog")], p.prototype, "_dialog", void 0);
154
154
  //#endregion
155
155
  export { p as VfModalDialog, f as modalDialogStyles };
@@ -1,15 +1,15 @@
1
- import { ScaleController as e } from "./scale.js";
2
- import t from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
3
- import { GridSnapController as n } from "./grid-snap.js";
4
- import { emit as r, emitNative as i } from "./events.js";
1
+ import { emit as e, emitNative as t } from "./events.js";
2
+ import { ScaleController as n } from "./scale.js";
3
+ import r from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
+ import { GridSnapController as i } from "./grid-snap.js";
5
5
  import { VfShadowRoleControl as a } from "./form-control.js";
6
6
  import { FocusRuleController as o } from "./focus-modality.js";
7
7
  import { nothing as s } from "lit";
8
8
  import { property as c } from "lit/decorators.js";
9
9
  //#region src/text-control.ts
10
10
  var l = class extends a {
11
- constructor(...t) {
12
- super(...t), this.value = "", this.placeholder = "", this.readonly = !1, this.name = "", this.label = "", this.scale = new e(this), this.gridSnap = new n(this), this.focusRule = new o(this);
11
+ constructor(...e) {
12
+ super(...e), this.value = "", this.placeholder = "", this.readonly = !1, this.name = "", this.label = "", this.scale = new n(this), this.gridSnap = new i(this), this.focusRule = new o(this);
13
13
  }
14
14
  static {
15
15
  this.shadowRootOptions = {
@@ -65,19 +65,19 @@ var l = class extends a {
65
65
  }
66
66
  e.requestSubmit();
67
67
  }
68
- emitValue(e, t = { value: this.value }) {
69
- r(this, e, t);
68
+ emitValue(t, n = { value: this.value }) {
69
+ e(this, t, n);
70
70
  }
71
71
  handleInput(e) {
72
72
  this.value = e.target.value, this.emitValue("vf-input");
73
73
  }
74
74
  handleChange(e) {
75
- this.value = e.target.value, this.emitValue("vf-change"), i(this, "change");
75
+ this.value = e.target.value, this.emitValue("vf-change"), t(this, "change");
76
76
  }
77
77
  };
78
- t([c()], l.prototype, "value", void 0), t([c()], l.prototype, "placeholder", void 0), t([c({
78
+ r([c()], l.prototype, "value", void 0), r([c()], l.prototype, "placeholder", void 0), r([c({
79
79
  type: Boolean,
80
80
  reflect: !0
81
- })], l.prototype, "readonly", void 0), t([c({ reflect: !0 })], l.prototype, "name", void 0), t([c()], l.prototype, "label", void 0);
81
+ })], l.prototype, "readonly", void 0), r([c({ reflect: !0 })], l.prototype, "name", void 0), r([c()], l.prototype, "label", void 0);
82
82
  //#endregion
83
83
  export { l as VfTextControlBase };
@@ -1,6 +1,6 @@
1
- import { ScaleController as e } from "./scale.js";
2
- import { GridSnapController as t } from "./grid-snap.js";
3
- import { deferActivation as n } from "./events.js";
1
+ import { deferActivation as e } from "./events.js";
2
+ import { ScaleController as t } from "./scale.js";
3
+ import { GridSnapController as n } from "./grid-snap.js";
4
4
  //#region src/toggle-control.ts
5
5
  var r = (r) => {
6
6
  class i extends r {
@@ -9,8 +9,8 @@ var r = (r) => {
9
9
  }
10
10
  #e;
11
11
  constructor(...r) {
12
- super(...r), this.scale = new e(this), this.gridSnap = new t(this), this.#e = null, this.selfManagedTabIndex = !1, this.#n = (e) => {
13
- n(this, e, () => this.#t());
12
+ super(...r), this.scale = new t(this), this.gridSnap = new n(this), this.#e = null, this.selfManagedTabIndex = !1, this.#n = (t) => {
13
+ e(this, t, () => this.#t());
14
14
  }, this.#r = (e) => {
15
15
  e.key === " " && (e.preventDefault(), !e.repeat && this.dispatchEvent(new MouseEvent("click", {
16
16
  bubbles: !0,
package/docs/SPEC.md CHANGED
@@ -192,12 +192,14 @@ Every recipe also declares its size — `width`, and `height` where the window i
192
192
  #### `vf-desktop` (`VfDesktop`, vf-desktop.ts)
193
193
  Full-bleed classic desktop container.
194
194
  - **Attributes/props:** `width`, `height: number` (system px, defaults 512×342 — the compact Mac's raster) — the screen's own size, the way a WIND resource declared a window's. The host box renders at exactly `width + 2·bezel` per axis (a live `sysLength` written as host inline size on every update), always a whole number of system px. **Pure CSS sizing is not supported**: the inline size wins over any stylesheet, so the page sets the numbers — directly or via `fitWithin` — and positions the explicitly sized desktop with its own CSS, keeping any sub-system-pixel slack in the page's own layout. `bezel: number` (system px, default 0) — the black screen surround, the CRT's unlit margin between raster and case, added onto the declared screen on every side. The screen owns flow, an absolute window's containing block and the drag clip, so a dragged window crops at the raster's edge. Its two *top* corners wear the `SCREEN_CORNER` mask (the classic framebuffer rounded only the top pair; the raster's bottom corners ran square), painted above everything like the hardware mask — the masks land over a slotted menu bar's corners, so the bar needs no `rounded` of its own inside a bezeled desktop. The bezel width is written onto the host as `--vf-desktop-bezel` (self-set geometry, like `--vf-scale` — component-owned, not a theming token).
195
- - **Methods:** `fitWithin(maxWidth, maxHeight)` (CSS px) → sets `width`/ `height` to the largest whole-system-px raster whose host box — bezel included — fits the bound, per the current effective scale, and returns `{ width, height }`. The page's half of the sizing contract: call it on `resize` and `onScaleChange` (zoom and density moves change what a system px costs in CSS px), as a full-screen faux desktop does.
195
+ - **Methods:** `fitWithin(maxWidth, maxHeight)` (CSS px) → sets `width`/ `height` to the largest whole-system-px raster whose host box — bezel included — fits the bound, per the current effective scale, and returns `{ width, height }`. The page's half of the sizing contract: call it on `resize` and `onScaleChange` (zoom and density moves change what a system px costs in CSS px), as a full-screen faux desktop does. `clearActive()` → deactivate the whole document tier (see *Deactivation* under Behavior). `activeWindow: HTMLElement | null` (read-only) → the active document-tier window, or `null` while the tier is deactivated or empty; utility windows are never the holder.
196
196
  - **Visual:** `display: block; position: relative;` — the paint lives on an inner screen surface (part `desktop`, `overflow: hidden` — the whole-system-px raster, inset by `bezel` when one is set). Screen surface = classic 50% dither: a 2×2 motif with an opaque white base and two black pixels on the diagonal, rendered as the exact fill (one whole-surface raster; a consumer `--vf-desktop-pattern` renders as a placed tile grid on the token's 30-system-px tile — see *Tiled fills*) over a CSS-repeated underlay of the same art. The art is opaque black-on-white — the authentic System 7 dither — so it covers `var(--vf-desktop, #808080)` beneath it; that base color shows only under a custom pattern with transparent cells (or `none`).
197
197
  - **Slots:** default (menu bar, windows, anything).
198
198
  - **Behavior:** manages stacking of slotted `vf-window` children: `pointerdown` *or `focusin`* on a window brings it to front (incrementing z-index counter) and sets its `active` attribute, clearing `active` on the others — the `focusin` half is the keyboard route to activation: Tab landing anywhere in a background window (its undrawn-but-focusable widgets included) raises it. Listens via delegated pointerdown/focusin listeners + `slotchange`. Windows slotted before `vf-window` is defined are re-normalized once `customElements.whenDefined('vf-window')` settles, since the upgrade reflects each window's `active = true` default back out and upgrading a slotted node doesn't re-fire `slotchange`.
199
199
  - **DOM order follows z-order** (bottom-most first), so sequential focus order matches the visual stack and Shift+Tab mirrors Tab exactly. The sync runs at pointer-gesture end (a mid-gesture node move would clear the pointer capture a title-bar drag or grow-box resize holds) and on programmatic `bringToFront`, never from a focus-driven raise (moving the window focus just entered would re-order the tab sequence mid-traversal); focus surviving its own window's move is restored without re-raising that window. Non-window children (a menu bar, page content) keep their positions. `npm run verify:window-a11y`.
200
200
  - **Floating tier:** `vf-window[variant="utility"]` children stack in a z band `1_000_000` above the document tier (one shared monotonic counter, so a palette stays above every document window), restack only among themselves, and stand outside the single-active invariant both ways: clicking a palette doesn't deactivate the active document window, and activating a document window never clears a palette's `active` — System 7 windoid behavior while the app is frontmost. The tier test reads the `variant` *attribute*, so a not-yet-upgraded element still lands right.
201
+ - **Deactivation:** on a real System 7 machine clicking the desktop clicked the *Finder* — the frontmost application's windows lost their stripes. `clearActive()` is that gesture's handler: it clears `active` from the whole document tier, and **zero active windows is a legal state**, held until a press or `focusin` re-enters a document window or a new one is slotted (opening a window brings its application forward — a newly slotted window ends a deliberate deactivation, where a mere survivor never does: removing a *background* window while deactivated promotes nothing, while removing the holder outside a deactivation promotes the topmost survivor). The desktop never takes the decision itself — a press on its own bare dither changes nothing; desktop furniture is slotted light DOM, so only the page knows which of its children mean "the Finder". Utility windows keep their `active` through a deactivation (their dots stay drawn). Every change of holder — window to window, window to none, none to window — fires `vf-activate`, once per change; re-asserting the current holder is silent. `npm run verify:desktop-activate`.
202
+ - **Events:** `vf-activate` (detail `{ window: HTMLElement | null }` — the new holder, `null` on deactivation).
201
203
  - **Parts:** `desktop`.
202
204
 
203
205
  #### `vf-window` (`VfWindow`, vf-window.ts)
@@ -181,7 +181,7 @@
181
181
  },
182
182
  {
183
183
  "name": "vf-desktop",
184
- "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`).\n---\n\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop dither — occluded by the default (opaque) tile, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - the desktop dither's art — a 50% checker drawn as opaque black-on-white rects, on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The dithered screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
184
+ "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`).\n---\n\n\n### **Events:**\n - **vf-activate** - 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.\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop dither — occluded by the default (opaque) tile, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - the desktop dither's art — a 50% checker drawn as opaque black-on-white rects, on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The dithered screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
185
185
  "attributes": [
186
186
  {
187
187
  "name": "width",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
3
3
  "name": "vintage-frames",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -437,7 +437,7 @@
437
437
  },
438
438
  {
439
439
  "name": "vf-desktop",
440
- "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`).\n---\n\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop dither — occluded by the default (opaque) tile, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - the desktop dither's art — a 50% checker drawn as opaque black-on-white rects, on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The dithered screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
440
+ "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`).\n---\n\n\n### **Events:**\n - **vf-activate** - 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.\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop dither — occluded by the default (opaque) tile, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - the desktop dither's art — a 50% checker drawn as opaque black-on-white rects, on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The dithered screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
441
441
  "doc-url": "",
442
442
  "attributes": [
443
443
  {
@@ -472,7 +472,12 @@
472
472
  "description": "Default slot: menu bar, windows, anything."
473
473
  }
474
474
  ],
475
- "events": [],
475
+ "events": [
476
+ {
477
+ "name": "vf-activate",
478
+ "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."
479
+ }
480
+ ],
476
481
  "js": {
477
482
  "properties": [
478
483
  {
@@ -490,6 +495,11 @@
490
495
  "description": "Width of the black screen bezel, in system px (`0` = none), added onto\nthe declared screen on every side — a `width=\"502\" bezel=\"5\"` desktop\nrenders a 512-system-px host box. The compact Mac's CRT showed an\nunlit black margin between the desktop's raster and the case; `bezel`\ndraws it around the screen and puts the classic screen-corner mask on\nthe screen's two *top* corners — only the top pair was rounded in the\nframebuffer. Flow, window coordinates and the drag clip all belong to\nthe screen, so windows crop at its edge. Inside a bezeled desktop a\nmenu bar needs no `rounded` of its own — the desktop's mask lands on\nthe same pixels.",
491
496
  "type": "number"
492
497
  },
498
+ {
499
+ "name": "activeWindow",
500
+ "description": "The active document-tier window, or null while the tier is deactivated\n(or has no windows). Utility windows are never the holder.",
501
+ "type": "HTMLElement | null"
502
+ },
493
503
  {
494
504
  "name": "top",
495
505
  "description": "Offset from the top of the positioning parent, in whole system px.\nSetting this (or `left`) absolutely positions the element within its\nparent; the coordinate left unset is 0. Remove both to return the\nelement to normal flow.",
@@ -501,7 +511,12 @@
501
511
  "type": "number | null | undefined"
502
512
  }
503
513
  ],
504
- "events": []
514
+ "events": [
515
+ {
516
+ "name": "vf-activate",
517
+ "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."
518
+ }
519
+ ]
505
520
  }
506
521
  },
507
522
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vintage-frames",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Lit web components that emulate the look and feel of classic Mac OS System 7",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -71,6 +71,7 @@
71
71
  "measure:menus": "python3 scripts/measure-menu-render.py shots/menus.png",
72
72
  "probe:menus": "node scripts/probe-menu-scale.mjs",
73
73
  "verify:desktop": "node scripts/verify-desktop-upgrade.mjs",
74
+ "verify:desktop-activate": "node scripts/verify-desktop-activate.mjs",
74
75
  "verify:list-focus": "node scripts/verify-list-focus.mjs",
75
76
  "verify:control-heights": "node scripts/verify-control-heights.mjs",
76
77
  "verify:list-typeahead": "node scripts/verify-list-typeahead.mjs",