vintage-frames 0.5.4 → 0.5.6

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.
@@ -10756,7 +10756,7 @@
10756
10756
  "declarations": [
10757
10757
  {
10758
10758
  "kind": "class",
10759
- "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them.\n\nSize the host (width/height) from the outside; the viewport fills it.",
10759
+ "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them,\nand corner reserves that cell on a single-axis rail too — the\nrail stops 15px short of the frame, for a grow box to land in.\n\nSize the host (width/height) from the outside; the viewport fills it. The\nviewport insets its content 8px; flush drops that inset so content\nruns to the frame and the rails.",
10760
10760
  "name": "VfScrollArea",
10761
10761
  "cssProperties": [
10762
10762
  {
@@ -10807,6 +10807,28 @@
10807
10807
  "attribute": "axis",
10808
10808
  "reflects": true
10809
10809
  },
10810
+ {
10811
+ "kind": "field",
10812
+ "name": "flush",
10813
+ "type": {
10814
+ "text": "boolean"
10815
+ },
10816
+ "default": "false",
10817
+ "description": "Drop the viewport's 8px inset: slotted content and the (0,0) of placed\nchildren sit at the frame's inner edge, one system px from the frame\nbox (the border-floor compensation stays — see the viewport rule).\n`vf-window[scrollbars]` forwards its own `flush` here.",
10818
+ "attribute": "flush",
10819
+ "reflects": true
10820
+ },
10821
+ {
10822
+ "kind": "field",
10823
+ "name": "corner",
10824
+ "type": {
10825
+ "text": "boolean"
10826
+ },
10827
+ "default": "false",
10828
+ "description": "Reserve the bottom-right corner cell on a single-axis rail: the rail\nstops 15px short of the frame and the viewport spans the rest, leaving\nthe 15×15 cell — with the two dividers a `both` rail's corner carries —\nfor a grow box to land in. A `both` rail always has the cell, so the\nflag changes nothing there. `vf-window[scrollbars resizable]` sets it.",
10829
+ "attribute": "corner",
10830
+ "reflects": true
10831
+ },
10810
10832
  {
10811
10833
  "kind": "field",
10812
10834
  "name": "label",
@@ -10915,6 +10937,24 @@
10915
10937
  "description": "Which scroll rails to reserve as permanent placeholders: `vertical`\n(default), `horizontal`, or `both`. Each reserved rail shows an empty white\nchannel until its axis overflows; the unreserved axis still scrolls\nnatively (wheel, keyboard) but draws no rail.",
10916
10938
  "fieldName": "axis"
10917
10939
  },
10940
+ {
10941
+ "name": "flush",
10942
+ "type": {
10943
+ "text": "boolean"
10944
+ },
10945
+ "default": "false",
10946
+ "description": "Drop the viewport's 8px inset: slotted content and the (0,0) of placed\nchildren sit at the frame's inner edge, one system px from the frame\nbox (the border-floor compensation stays — see the viewport rule).\n`vf-window[scrollbars]` forwards its own `flush` here.",
10947
+ "fieldName": "flush"
10948
+ },
10949
+ {
10950
+ "name": "corner",
10951
+ "type": {
10952
+ "text": "boolean"
10953
+ },
10954
+ "default": "false",
10955
+ "description": "Reserve the bottom-right corner cell on a single-axis rail: the rail\nstops 15px short of the frame and the viewport spans the rest, leaving\nthe 15×15 cell — with the two dividers a `both` rail's corner carries —\nfor a grow box to land in. A `both` rail always has the cell, so the\nflag changes nothing there. `vf-window[scrollbars resizable]` sets it.",
10956
+ "fieldName": "corner"
10957
+ },
10918
10958
  {
10919
10959
  "name": "label",
10920
10960
  "type": {
@@ -17245,10 +17285,46 @@
17245
17285
  "text": "boolean"
17246
17286
  },
17247
17287
  "default": "false",
17248
- "description": "Show a grow box at the bottom-right corner for resizing.",
17288
+ "description": "Show a grow box at the bottom-right corner for resizing. The drag is\nbounded per axis by the sizeRect below.",
17249
17289
  "attribute": "resizable",
17250
17290
  "reflects": true
17251
17291
  },
17292
+ {
17293
+ "kind": "field",
17294
+ "name": "minWidth",
17295
+ "type": {
17296
+ "text": "number | null | undefined"
17297
+ },
17298
+ "description": "The sizeRect: the range of sizes the grow box can drag the window to,\nper axis, in whole system px — GrowWindow's, where the app stated the\nrectangle and the Window Manager clamped the drag to it. `minWidth` and\n`minHeight` default to the 80×54 floor a window can still be worked at;\nthe maxes are unbounded. A min equal to its max locks that axis —\n`min-height=\"67\" max-height=\"67\"` on a strip that scrolls sideways and\nnever grows taller, so the grow box changes the width alone.\n\nBounds the gesture only: an authored `width`/`height` outside the rect\nrenders as declared, and the first grow-box move brings it inside. The\nclamp runs after the drag's lattice snap, so a bound lands exactly the\nway an authored size does, even off the lattice (an odd height at 2×);\nwhere a min and max cross, the max wins, so a window held under the\nfloor stays put instead of jumping to it.",
17299
+ "attribute": "min-width"
17300
+ },
17301
+ {
17302
+ "kind": "field",
17303
+ "name": "minHeight",
17304
+ "type": {
17305
+ "text": "number | null | undefined"
17306
+ },
17307
+ "description": "See minWidth. Default 54.",
17308
+ "attribute": "min-height"
17309
+ },
17310
+ {
17311
+ "kind": "field",
17312
+ "name": "maxWidth",
17313
+ "type": {
17314
+ "text": "number | null | undefined"
17315
+ },
17316
+ "description": "See minWidth. Unbounded by default.",
17317
+ "attribute": "max-width"
17318
+ },
17319
+ {
17320
+ "kind": "field",
17321
+ "name": "maxHeight",
17322
+ "type": {
17323
+ "text": "number | null | undefined"
17324
+ },
17325
+ "description": "See minWidth. Unbounded by default.",
17326
+ "attribute": "max-height"
17327
+ },
17252
17328
  {
17253
17329
  "kind": "field",
17254
17330
  "name": "flush",
@@ -17256,7 +17332,7 @@
17256
17332
  "text": "boolean"
17257
17333
  },
17258
17334
  "default": "false",
17259
- "description": "Remove the default 12px body padding.",
17335
+ "description": "Remove the default 12px body padding. Under `scrollbars` the body has\nnone to remove, so the flag reaches the built-in scroll area instead\nand drops its viewport's 8px inset: content runs to the frame and the\nrails, and the (0,0) of placed children is the content region's corner.",
17260
17336
  "attribute": "flush",
17261
17337
  "reflects": true
17262
17338
  },
@@ -17266,7 +17342,7 @@
17266
17342
  "type": {
17267
17343
  "text": "'vertical' | 'horizontal' | 'both' | undefined"
17268
17344
  },
17269
- "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell. Values mirror `vf-scroll-area`'s `axis`; the `heading` names the\nscroll region; the viewport part is re-exported. Implies `flush` (the\nviewport carries its own padding). The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
17345
+ "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell — reserved on a single-axis rail too (the area's `corner`), unless\na populated status strip holds the grow box, when the rail runs edge to\nedge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the\n`heading` names the scroll region; the viewport part is re-exported.\nThe body's own padding goes; the viewport keeps its 8px inset unless\n`flush`, which passes through. The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
17270
17346
  "attribute": "scrollbars",
17271
17347
  "reflects": true
17272
17348
  },
@@ -17627,16 +17703,48 @@
17627
17703
  "text": "boolean"
17628
17704
  },
17629
17705
  "default": "false",
17630
- "description": "Show a grow box at the bottom-right corner for resizing.",
17706
+ "description": "Show a grow box at the bottom-right corner for resizing. The drag is\nbounded per axis by the sizeRect below.",
17631
17707
  "fieldName": "resizable"
17632
17708
  },
17709
+ {
17710
+ "name": "min-width",
17711
+ "type": {
17712
+ "text": "number | null | undefined"
17713
+ },
17714
+ "description": "The sizeRect: the range of sizes the grow box can drag the window to,\nper axis, in whole system px — GrowWindow's, where the app stated the\nrectangle and the Window Manager clamped the drag to it. `minWidth` and\n`minHeight` default to the 80×54 floor a window can still be worked at;\nthe maxes are unbounded. A min equal to its max locks that axis —\n`min-height=\"67\" max-height=\"67\"` on a strip that scrolls sideways and\nnever grows taller, so the grow box changes the width alone.\n\nBounds the gesture only: an authored `width`/`height` outside the rect\nrenders as declared, and the first grow-box move brings it inside. The\nclamp runs after the drag's lattice snap, so a bound lands exactly the\nway an authored size does, even off the lattice (an odd height at 2×);\nwhere a min and max cross, the max wins, so a window held under the\nfloor stays put instead of jumping to it.",
17715
+ "fieldName": "minWidth"
17716
+ },
17717
+ {
17718
+ "name": "min-height",
17719
+ "type": {
17720
+ "text": "number | null | undefined"
17721
+ },
17722
+ "description": "See minWidth. Default 54.",
17723
+ "fieldName": "minHeight"
17724
+ },
17725
+ {
17726
+ "name": "max-width",
17727
+ "type": {
17728
+ "text": "number | null | undefined"
17729
+ },
17730
+ "description": "See minWidth. Unbounded by default.",
17731
+ "fieldName": "maxWidth"
17732
+ },
17733
+ {
17734
+ "name": "max-height",
17735
+ "type": {
17736
+ "text": "number | null | undefined"
17737
+ },
17738
+ "description": "See minWidth. Unbounded by default.",
17739
+ "fieldName": "maxHeight"
17740
+ },
17633
17741
  {
17634
17742
  "name": "flush",
17635
17743
  "type": {
17636
17744
  "text": "boolean"
17637
17745
  },
17638
17746
  "default": "false",
17639
- "description": "Remove the default 12px body padding.",
17747
+ "description": "Remove the default 12px body padding. Under `scrollbars` the body has\nnone to remove, so the flag reaches the built-in scroll area instead\nand drops its viewport's 8px inset: content runs to the frame and the\nrails, and the (0,0) of placed children is the content region's corner.",
17640
17748
  "fieldName": "flush"
17641
17749
  },
17642
17750
  {
@@ -17644,7 +17752,7 @@
17644
17752
  "type": {
17645
17753
  "text": "'vertical' | 'horizontal' | 'both' | undefined"
17646
17754
  },
17647
- "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell. Values mirror `vf-scroll-area`'s `axis`; the `heading` names the\nscroll region; the viewport part is re-exported. Implies `flush` (the\nviewport carries its own padding). The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
17755
+ "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell — reserved on a single-axis rail too (the area's `corner`), unless\na populated status strip holds the grow box, when the rail runs edge to\nedge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the\n`heading` names the scroll region; the viewport part is re-exported.\nThe body's own padding goes; the viewport keeps its 8px inset unless\n`flush`, which passes through. The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
17648
17756
  "fieldName": "scrollbars"
17649
17757
  },
17650
17758
  {
@@ -18,9 +18,13 @@ declare const VfScrollArea_base: (new (...args: any[]) => import("../position.js
18
18
  * dither and thumb filling in only once that axis overflows (System 7 drew
19
19
  * an active window's no-overflow bar as arrows on a bare channel; driven
20
20
  * by {@link ScrollStateController}). Which rails are reserved is set by
21
- * {@link axis}; when both are reserved the bottom-right corner joins them.
21
+ * {@link axis}; when both are reserved the bottom-right corner joins them,
22
+ * and {@link corner} reserves that cell on a single-axis rail too — the
23
+ * rail stops 15px short of the frame, for a grow box to land in.
22
24
  *
23
- * Size the host (width/height) from the outside; the viewport fills it.
25
+ * Size the host (width/height) from the outside; the viewport fills it. The
26
+ * viewport insets its content 8px; {@link flush} drops that inset so content
27
+ * runs to the frame and the rails.
24
28
  *
25
29
  * @slot - Scrollable content.
26
30
  * @csspart viewport - The inner scrolling container.
@@ -39,6 +43,21 @@ export declare class VfScrollArea extends VfScrollArea_base {
39
43
  * natively (wheel, keyboard) but draws no rail.
40
44
  */
41
45
  axis: 'vertical' | 'horizontal' | 'both';
46
+ /**
47
+ * Drop the viewport's 8px inset: slotted content and the (0,0) of placed
48
+ * children sit at the frame's inner edge, one system px from the frame
49
+ * box (the border-floor compensation stays — see the viewport rule).
50
+ * `vf-window[scrollbars]` forwards its own `flush` here.
51
+ */
52
+ flush: boolean;
53
+ /**
54
+ * Reserve the bottom-right corner cell on a single-axis rail: the rail
55
+ * stops 15px short of the frame and the viewport spans the rest, leaving
56
+ * the 15×15 cell — with the two dividers a `both` rail's corner carries —
57
+ * for a grow box to land in. A `both` rail always has the cell, so the
58
+ * flag changes nothing there. `vf-window[scrollbars resizable]` sets it.
59
+ */
60
+ corner: boolean;
42
61
  /**
43
62
  * Accessible name for the scrolling viewport, applied as its `aria-label`
44
63
  * (an `aria-label` on the host would not reach into the shadow DOM). The
@@ -13,7 +13,7 @@ import { property as h, query as g, state as _ } from "lit/decorators.js";
13
13
  //#region src/components/vf-scroll-area.ts
14
14
  var v = class extends r(d) {
15
15
  constructor(...e) {
16
- super(...e), this.scale = new t(this), this.gridSnap = new s(this), this.axis = "vertical", this.label = "", this.scrollState = new c(this, () => this.viewport, () => this.content, (e) => {
16
+ super(...e), this.scale = new t(this), this.gridSnap = new s(this), this.axis = "vertical", this.flush = !1, this.corner = !1, this.label = "", this.scrollState = new c(this, () => this.viewport, () => this.content, (e) => {
17
17
  this._scrollable = e.x || e.y;
18
18
  }), this.rail = new l(this, {
19
19
  getScroll: () => this.viewport,
@@ -46,11 +46,13 @@ var v = class extends r(d) {
46
46
  }
47
47
  :host(:not([axis])) .box,
48
48
  :host([axis='vertical']) .box,
49
- :host([axis='both']) .box {
49
+ :host([axis='both']) .box,
50
+ :host([corner]) .box {
50
51
  grid-template-columns: 1fr auto;
51
52
  }
52
53
  :host([axis='horizontal']) .box,
53
- :host([axis='both']) .box {
54
+ :host([axis='both']) .box,
55
+ :host([corner]) .box {
54
56
  grid-template-rows: 1fr auto;
55
57
  }
56
58
  .viewport {
@@ -73,6 +75,23 @@ var v = class extends r(d) {
73
75
  var(--vf-scale, 1) * 8px + mod(var(--vf-scale, 1) * 1px, 1px)
74
76
  );
75
77
  }
78
+ /* flush: the inset goes, the border-floor term stays — content and the
79
+ (0,0) of placed children sit at the frame's inner edge, exactly one
80
+ system px from the frame box at every scale. */
81
+ :host([flush]) .viewport {
82
+ padding: mod(var(--vf-scale, 1) * 1px, 1px);
83
+ }
84
+ /* A single-axis rail with a reserved corner: the viewport spans the
85
+ track the missing rail would have taken, up to the corner cell, so
86
+ the rail stops 15px short of the frame. (A both-axes rail has no
87
+ missing track — the flag is inert there.) */
88
+ :host([corner][axis='horizontal']) .viewport {
89
+ grid-column: 1 / 3;
90
+ }
91
+ :host([corner]:not([axis])) .viewport,
92
+ :host([corner][axis='vertical']) .viewport {
93
+ grid-row: 1 / 3;
94
+ }
76
95
  .vf-rail--vertical {
77
96
  grid-area: 1 / 2;
78
97
  }
@@ -100,7 +119,7 @@ var v = class extends r(d) {
100
119
  ];
101
120
  }
102
121
  render() {
103
- let e = this.axis !== "horizontal", t = this.axis === "horizontal" || this.axis === "both";
122
+ let e = this.axis !== "horizontal", t = this.axis === "horizontal" || this.axis === "both", n = e && t || this.corner;
104
123
  return p`
105
124
  <div class="box vf-snap">
106
125
  <div
@@ -114,11 +133,17 @@ var v = class extends r(d) {
114
133
  </div>
115
134
  ${e ? u(this.rail, "vertical") : m}
116
135
  ${t ? u(this.rail, "horizontal") : m}
117
- ${e && t ? p`<div class="vf-rail-corner" aria-hidden="true"></div>` : m}
136
+ ${n ? p`<div class="vf-rail-corner" aria-hidden="true"></div>` : m}
118
137
  </div>
119
138
  `;
120
139
  }
121
140
  };
122
- n([h({ reflect: !0 })], v.prototype, "axis", void 0), n([h()], v.prototype, "label", void 0), n([g(".viewport")], v.prototype, "viewport", void 0), n([g(".content")], v.prototype, "content", void 0), n([_()], v.prototype, "_scrollable", void 0), v = n([e("vf-scroll-area")], v);
141
+ n([h({ reflect: !0 })], v.prototype, "axis", void 0), n([h({
142
+ type: Boolean,
143
+ reflect: !0
144
+ })], v.prototype, "flush", void 0), n([h({
145
+ type: Boolean,
146
+ reflect: !0
147
+ })], v.prototype, "corner", void 0), n([h()], v.prototype, "label", void 0), n([g(".viewport")], v.prototype, "viewport", void 0), n([g(".content")], v.prototype, "content", void 0), n([_()], v.prototype, "_scrollable", void 0), v = n([e("vf-scroll-area")], v);
123
148
  //#endregion
124
149
  export { v as VfScrollArea };
@@ -92,18 +92,52 @@ export declare class VfWindow extends VfWindow_base {
92
92
  zoomable: boolean;
93
93
  /** Allow dragging the window by its title bar. */
94
94
  movable: boolean;
95
- /** Show a grow box at the bottom-right corner for resizing. */
95
+ /**
96
+ * Show a grow box at the bottom-right corner for resizing. The drag is
97
+ * bounded per axis by the sizeRect below.
98
+ */
96
99
  resizable: boolean;
97
- /** Remove the default 12px body padding. */
100
+ /**
101
+ * The sizeRect: the range of sizes the grow box can drag the window to,
102
+ * per axis, in whole system px — GrowWindow's, where the app stated the
103
+ * rectangle and the Window Manager clamped the drag to it. `minWidth` and
104
+ * `minHeight` default to the 80×54 floor a window can still be worked at;
105
+ * the maxes are unbounded. A min equal to its max locks that axis —
106
+ * `min-height="67" max-height="67"` on a strip that scrolls sideways and
107
+ * never grows taller, so the grow box changes the width alone.
108
+ *
109
+ * Bounds the gesture only: an authored `width`/`height` outside the rect
110
+ * renders as declared, and the first grow-box move brings it inside. The
111
+ * clamp runs after the drag's lattice snap, so a bound lands exactly the
112
+ * way an authored size does, even off the lattice (an odd height at 2×);
113
+ * where a min and max cross, the max wins, so a window held under the
114
+ * floor stays put instead of jumping to it.
115
+ */
116
+ minWidth?: number | null;
117
+ /** See {@link minWidth}. Default 54. */
118
+ minHeight?: number | null;
119
+ /** See {@link minWidth}. Unbounded by default. */
120
+ maxWidth?: number | null;
121
+ /** See {@link minWidth}. Unbounded by default. */
122
+ maxHeight?: number | null;
123
+ /**
124
+ * Remove the default 12px body padding. Under `scrollbars` the body has
125
+ * none to remove, so the flag reaches the built-in scroll area instead
126
+ * and drops its viewport's 8px inset: content runs to the frame and the
127
+ * rails, and the (0,0) of placed children is the content region's corner.
128
+ */
98
129
  flush: boolean;
99
130
  /**
100
131
  * Put System 7 scroll rails on the window edge — the classic document
101
132
  * window. The body slot renders inside a built-in `vf-scroll-area` pulled
102
133
  * one system pixel under the frame on every side, so the rails repaint the
103
134
  * border lines and a `resizable` window's grow box lands in the corner
104
- * cell. Values mirror `vf-scroll-area`'s `axis`; the `heading` names the
105
- * scroll region; the viewport part is re-exported. Implies `flush` (the
106
- * viewport carries its own padding). The slotted composition (SPEC §5
135
+ * cell reserved on a single-axis rail too (the area's `corner`), unless
136
+ * a populated status strip holds the grow box, when the rail runs edge to
137
+ * edge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the
138
+ * `heading` names the scroll region; the viewport part is re-exported.
139
+ * The body's own padding goes; the viewport keeps its 8px inset unless
140
+ * `flush`, which passes through. The slotted composition (SPEC §5
107
141
  * vf-scroll-area) still works for windows that want an inset well instead.
108
142
  */
109
143
  scrollbars?: 'vertical' | 'horizontal' | 'both';
@@ -18,13 +18,18 @@ import "./vf-scroll-area.js";
18
18
  import { LitElement as N, css as P, html as F, nothing as I } from "lit";
19
19
  import { property as L, state as R } from "lit/decorators.js";
20
20
  //#region src/components/vf-window.ts
21
- var z = 80, B = 54, V = 24, H = 8, U = class extends E(c(N)) {
21
+ var z = 80, B = 54;
22
+ function V(e, t, n) {
23
+ let r = Math.max(t, e);
24
+ return n == null ? r : Math.min(n, r);
25
+ }
26
+ var H = 24, U = 8, W = class extends E(c(N)) {
22
27
  constructor(...e) {
23
28
  super(...e), this.heading = "", this.active = !0, this.closable = !0, this.zoomable = !1, this.movable = !1, this.resizable = !1, this.flush = !1, this._hasStatus = !1, this.scale = new n(this), this.gridSnap = new T(this), this.titleCenter = new O(this), this._dotsPattern = "", this.#e = new x(), this.#t = (e, t, n) => {
24
29
  let r = a(this.offsetWidth, this);
25
30
  return {
26
- x: Math.min(Math.max(e, V - r), n.width - V),
27
- y: Math.min(Math.max(t, 0), Math.max(0, n.height - V))
31
+ x: Math.min(Math.max(e, H - r), n.width - H),
32
+ y: Math.min(Math.max(t, 0), Math.max(0, n.height - H))
28
33
  };
29
34
  }, this._placement = new s(this, (e, t, n) => this.#t(e, t, n)), this._drag = new D(this, {
30
35
  onDragStart: (e) => !this.movable || e.button !== 0 || e.composedPath().some((e) => e instanceof HTMLElement && e.classList.contains("box")) ? null : (this.#i(), this._placement.seed()),
@@ -201,7 +206,9 @@ var z = 80, B = 54, V = 24, H = 8, U = class extends E(c(N)) {
201
206
  frame on every side, so its own frame border repaints the window's
202
207
  border lines exactly (no doubled frame), the rails run edge to edge,
203
208
  and a resizable window's grow box (z-index 1) lands over the rail
204
- corner cell. */
209
+ corner cell — which the render reserves on a single-axis rail too
210
+ (the area's corner flag), except when the status strip holds the
211
+ grow box instead. */
205
212
  .edge-scroll {
206
213
  width: calc(100% + var(--vf-scale, 1) * 2px);
207
214
  height: calc(100% + var(--vf-scale, 1) * 2px);
@@ -293,7 +300,7 @@ var z = 80, B = 54, V = 24, H = 8, U = class extends E(c(N)) {
293
300
  rows: 1,
294
301
  tile: p
295
302
  });
296
- let t = Math.ceil((e + d) / p) * p, n = H + d;
303
+ let t = Math.ceil((e + d) / p) * p, n = U + d;
297
304
  return F`<div
298
305
  class="vf-tile-raster"
299
306
  style="width:${i(t)};height:${i(n)};background-image:${this.#e.for(d, d, f, t, n)}"
@@ -348,7 +355,7 @@ var z = 80, B = 54, V = 24, H = 8, U = class extends E(c(N)) {
348
355
  _onGrowPointerMove(e) {
349
356
  let t = this._resizeState;
350
357
  if (!t || e.pointerId !== t.pointerId) return;
351
- let n = r(Math.max(z, t.baseWidth + a(e.clientX - t.startX, this)), this), i = r(Math.max(B, t.baseHeight + a(e.clientY - t.startY, this)), this);
358
+ let n = V(r(t.baseWidth + a(e.clientX - t.startX, this), this), this.minWidth ?? z, this.maxWidth), i = V(r(t.baseHeight + a(e.clientY - t.startY, this), this), this.minHeight ?? B, this.maxHeight);
352
359
  (n !== this.width || i !== this.height) && (t.emitPending = !0, t.resized = !0), this.width = n, this.height = i;
353
360
  }
354
361
  _onGrowPointerEnd(t) {
@@ -380,6 +387,8 @@ var z = 80, B = 54, V = 24, H = 8, U = class extends E(c(N)) {
380
387
  <vf-scroll-area
381
388
  class="edge-scroll"
382
389
  axis=${this.scrollbars}
390
+ ?flush=${this.flush}
391
+ ?corner=${this.resizable && !this._hasStatus}
383
392
  label=${this.heading || I}
384
393
  exportparts="viewport"
385
394
  >
@@ -405,24 +414,36 @@ var z = 80, B = 54, V = 24, H = 8, U = class extends E(c(N)) {
405
414
  `;
406
415
  }
407
416
  };
408
- o([L({ reflect: !0 })], U.prototype, "variant", void 0), o([L()], U.prototype, "heading", void 0), o([L({
417
+ o([L({ reflect: !0 })], W.prototype, "variant", void 0), o([L()], W.prototype, "heading", void 0), o([L({
409
418
  type: Boolean,
410
419
  reflect: !0
411
- })], U.prototype, "active", void 0), o([L({
420
+ })], W.prototype, "active", void 0), o([L({
412
421
  type: Boolean,
413
422
  reflect: !0
414
- })], U.prototype, "closable", void 0), o([L({
423
+ })], W.prototype, "closable", void 0), o([L({
415
424
  type: Boolean,
416
425
  reflect: !0
417
- })], U.prototype, "zoomable", void 0), o([L({
426
+ })], W.prototype, "zoomable", void 0), o([L({
418
427
  type: Boolean,
419
428
  reflect: !0
420
- })], U.prototype, "movable", void 0), o([L({
429
+ })], W.prototype, "movable", void 0), o([L({
421
430
  type: Boolean,
422
431
  reflect: !0
423
- })], U.prototype, "resizable", void 0), o([L({
432
+ })], W.prototype, "resizable", void 0), o([L({
433
+ type: Number,
434
+ attribute: "min-width"
435
+ })], W.prototype, "minWidth", void 0), o([L({
436
+ type: Number,
437
+ attribute: "min-height"
438
+ })], W.prototype, "minHeight", void 0), o([L({
439
+ type: Number,
440
+ attribute: "max-width"
441
+ })], W.prototype, "maxWidth", void 0), o([L({
442
+ type: Number,
443
+ attribute: "max-height"
444
+ })], W.prototype, "maxHeight", void 0), o([L({
424
445
  type: Boolean,
425
446
  reflect: !0
426
- })], U.prototype, "flush", void 0), o([L({ reflect: !0 })], U.prototype, "scrollbars", void 0), o([R()], U.prototype, "_hasStatus", void 0), U = o([t("vf-window")], U);
447
+ })], W.prototype, "flush", void 0), o([L({ reflect: !0 })], W.prototype, "scrollbars", void 0), o([R()], W.prototype, "_hasStatus", void 0), W = o([t("vf-window")], W);
427
448
  //#endregion
428
- export { U as VfWindow };
449
+ export { W as VfWindow };
@@ -150,11 +150,17 @@ var s = i(r["gray-25"]), c = s.width, l = s.height, u = s.rects, d = e(c, l, t(u
150
150
  width: calc(var(--vf-scale, 1) * 16px);
151
151
  }
152
152
 
153
- /* The both-axes corner cell. It supplies the two interior dividers
153
+ /* The corner cell: the rails' own 15px in both dimensions, so it sizes its
154
+ grid track even when only one rail is there to size it (vf-scroll-area's
155
+ corner flag on a single-axis rail). It supplies the two interior dividers
154
156
  (against the vertical increment arrow above and the horizontal one
155
- beside it) that those buttons leave to it; a resizable window's grow box
156
- lands exactly over it. */
157
+ beside it) that those buttons leave to it — on a single-axis rail the
158
+ other divider continues the rail's line across the cell, the way
159
+ DrawGrowIcon drew it; a resizable window's grow box lands exactly over
160
+ it. */
157
161
  .vf-rail-corner {
162
+ width: calc(var(--vf-scale, 1) * 15px);
163
+ height: calc(var(--vf-scale, 1) * 15px);
158
164
  background: var(--vf-white, #fff);
159
165
  border-top: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
160
166
  border-left: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
package/docs/SPEC.md CHANGED
@@ -208,7 +208,7 @@ Full-bleed classic desktop container.
208
208
 
209
209
  #### `vf-window` (`VfWindow`, vf-window.ts)
210
210
  The desktop-window shell: the classic document window (see DragThing screenshot), parameterized down to the windoid (see the Group A recipe table).
211
- - **Attributes/props:** `heading: string` (title text), `width: number` / `height: number` (**declare them both** — whole system px, so the window keeps its proportion to the chrome inside it at every density. A window is a fixed box in both axes, the way a WIND resource was: one that grows with its body is one the user can neither predict nor control via the grow box. Each missing dimension falls back to something different — width to block layout, height to the content — and the window names whichever are missing, once, in the console), `active: boolean` (default **true**; reflect), `closable: boolean` (default true), `zoomable: boolean` (default false), `movable: boolean` (default false), `resizable: boolean` (default false), `flush: boolean` (default false — removes body padding), `variant?: 'utility'` (the slim windoid chrome), `scrollbars?: 'vertical' | 'horizontal' | 'both'` (edge scroll rails).
211
+ - **Attributes/props:** `heading: string` (title text), `width: number` / `height: number` (**declare them both** — whole system px, so the window keeps its proportion to the chrome inside it at every density. A window is a fixed box in both axes, the way a WIND resource was: one that grows with its body is one the user can neither predict nor control via the grow box. Each missing dimension falls back to something different — width to block layout, height to the content — and the window names whichever are missing, once, in the console), `active: boolean` (default **true**; reflect), `closable: boolean` (default true), `zoomable: boolean` (default false), `movable: boolean` (default false), `resizable: boolean` (default false), `min-width` / `min-height: number` (default 80 / 54) and `max-width` / `max-height: number` (unbounded) — the grow box's sizeRect, whole system px (see Behavior), `flush: boolean` (default false — removes the body padding; under `scrollbars`, the built-in viewport's 8px inset instead), `variant?: 'utility'` (the slim windoid chrome), `scrollbars?: 'vertical' | 'horizontal' | 'both'` (edge scroll rails).
212
212
  - **Visual:** `vfChromeFrame` + `vfTitleBar` (§4), plus a full-size flex-column layout on the frame. `display: block`. Sets `--vf-surface: var(--vf-white, #fff)` on itself.
213
213
  - Title bar: from `vfTitleBar` — height `var(--vf-titlebar-height, 18px)`, white bg, bottom `1px solid black`, contains `.vf-stripes` layer (only when `active`). `touch-action: none` only when `[movable]`.
214
214
  - Title: centered, bold, on a white patch (`padding: 0 6px`; cap band on interior rows 4..12, 7px of white between ink and stripes — see §4 `vfTitleBar` for the traced geometry and the lattice hold) above the stripes, with `--vf-title-inset: 60px` of clearance so it ellipsizes before reaching the widgets. Inactive: no stripes, widgets undrawn (transparent ink — they keep their tab stops; see A11y below), the grow box's nested squares hidden, and every managed scroll rail inside the window blanked (see "always-a-rail" §5 vf-scroll-area) — but the title text stays black (System 7 never grayed the window title).
@@ -217,10 +217,10 @@ The desktop-window shell: the classic document window (see DragThing screenshot)
217
217
  - Body: `padding: 12px` (0 if `flush` or `scrollbars`), and `overflow: hidden` — the window being a fixed box, content taller than it is clipped at the frame the way the classic content region was, rather than painting out over the desktop; `scrollbars` is how the user reaches the rest. Two deliberate exemptions: `[scrollbars]` restores `overflow: visible`, because the edge-rail composition below pulls the scroll area one system px *outside* the body on every side and clipping would shave exactly that overhang off (the scroll area does its own clipping); and a control's drop-open panel is not clipped — `vf-select`'s list is `position: fixed` off the control's rect precisely to escape clipping ancestors (§5 vf-select), and it still escapes, because nothing between it and the viewport establishes a containing block for fixed descendants (the grid-snap correction is a `position: relative` left/top offset, never a transform — see §7). A `vf-menu` panel is anchored `position: absolute` and *would* clip, but a menu bar belongs to the desktop, not inside a window body.
218
218
  - Grow box (if `resizable`): 15×15 at bottom-right corner, white bg, 1px black top/left borders, containing two overlapping small square outlines. Inactive: the cell and its borders stay, the nested squares go — System 7 drew a deactivated window's size box hollow, with its blanked scroll rails.
219
219
  - Status bar (`status` slot): the classic bottom readout strip ("40px x 40px") — a 1px black rule (`vfRule`'s `.vf-rule-top`) over a white interior, `--vf-status-bar-height` (15px) in all, the grow box's own height, so a `resizable` window's grow box sits flush in the strip's right end (its top/left borders take over the rule there; the strip reserves 21px of right padding under `resizable` so text clears the cell). Slotted content rides the body face's native 12px line (`--vf-line-height`), whole-pixel centered in the 14px interior, `padding-inline: 6px`, nowrap + clipped. Takes **no space** until the slot is populated (the dialog-footer pattern), and collapses again when it empties. Composes with `scrollbars`: the edge rails' bottom overhang lands its frame line exactly on the strip's rule, so the two never double up — though the grow box then sits in the strip rather than the rail corner cell.
220
- - Edge scroll rails (if `scrollbars`): the body slot renders inside a shadow `vf-scroll-area` (its `axis` = the attribute's value, `label` = the heading, `viewport` part re-exported) carrying the TeachText composition internally — `calc(100% + 2px·scale)` with `margin: -1px·scale`, one system px under the frame on every side, so the area's own frame border repaints the window's border lines and a `resizable` window's grow box (z-index 1) lands exactly over the rail-corner cell. Same caveats as the slotted composition (see vf-scroll-area §5), which remains supported for inset wells.
220
+ - Edge scroll rails (if `scrollbars`): the body slot renders inside a shadow `vf-scroll-area` (its `axis` = the attribute's value, `label` = the heading, `viewport` part re-exported) carrying the TeachText composition internally — `calc(100% + 2px·scale)` with `margin: -1px·scale`, one system px under the frame on every side, so the area's own frame border repaints the window's border lines and a `resizable` window's grow box (z-index 1) lands exactly over the rail-corner cell. `flush` passes through to the area (its viewport drops the 8px inset, keeping the border-floor term, so content and the (0,0) of placed children sit at the content region's corner); a `resizable` window sets the area's `corner`, so a single-axis rail stops at the corner cell too — unless the status strip is populated, when the grow box sits in the strip and the rail runs edge to edge onto the strip's rule. Same caveats as the slotted composition (see vf-scroll-area §5), which remains supported for inset wells.
221
221
  - Utility variant (`variant="utility"`): the slim windoid bar traced from `Windows/utility-window.png` — `--vf-titlebar-height-utility` (12px = 11px interior + 1px rule), the `vfDots` dither instead of stripes (flush to the side borders — see §4 vfDots), 7×7 widgets (`top: 2px`; close `left: 7px`, zoom `right: 8px` — the art is asymmetric by that pixel) with a 2px patch ring where the striped bar's is 1px (`--vf-widget-ring`, internal geometry: the windoid sheet clears two px of dither beside its widgets), and the nested zoom square shrunk so its edges land at sprite col/row 3. No title patch: the display face's 16px line box can't sit in an 11px interior, so `.vf-title` is `display: none` under the variant (a retheming consumer can re-show it via `::part(title)`) and the heading names the widgets. A pressed windoid widget inverts whole — black interior under a white (invisible) borderline — rather than flashing the big bar's 9×9 sunburst, which can't land on a 5×5 interior.
222
222
  - **A11y:** the close/zoom `aria-label`s are qualified by the title when there is one (`Close ${heading}` / `Zoom ${heading}`, falling back to bare `Close` / `Zoom`) — several windows are open at once by design, so a bare repeated "Close" gives an AT user no way to tell which window a widget belongs to. The frame is `role="group"`, named by the title patch via `aria-labelledby` when there is a heading (the utility variant's hidden patch still names it — AccName resolves hidden labelledby targets) — `group` rather than `region` deliberately, so a desktop of windows doesn't pollute landmark navigation; the title bar is a `<div>`, never a `<header>`, which would map to an unnamed `banner` landmark even inside the shadow root. An inactive window's widgets stay in the tree and the tab order but paint no ink (transparent border/background/patch ring — the bare System 7 bar): a background window whose body holds nothing focusable is still reachable, activated by `vf-desktop`'s `focusin` raise the moment Tab lands on a widget, and never drops focus to `<body>` when it deactivates. `npm run verify:window-a11y`.
223
- - **Behavior:** close box click → `vf-close` (does NOT remove itself; consumer decides). Zoom box click → `vf-zoom`. If `movable`: dragging the title bar moves the window — the drag seeds its origin from the current offset position (once, converting to system px) and then states `left`/`top` via pointer capture, in whole system px like any authored placement. If `resizable`: dragging the grow box states `width`/`height` the same way, and fires `vf-resize` (detail `{ width, height, commit }`, sizes in whole system px) — one event per size the drag actually writes (`commit: false`), fired *after* the new box is applied so a handler that measures reads the resized layout, then a final `commit: true` as the gesture settles (release or cancel), only when it changed the size. Window content can follow the grow box from this event alone, no ResizeObserver. Fired by the gesture only: a programmatic `width`/`height` write fires nothing, the way a value set fires no `vf-change`.
223
+ - **Behavior:** close box click → `vf-close` (does NOT remove itself; consumer decides). Zoom box click → `vf-zoom`. If `movable`: dragging the title bar moves the window — the drag seeds its origin from the current offset position (once, converting to system px) and then states `left`/`top` via pointer capture, in whole system px like any authored placement. If `resizable`: dragging the grow box states `width`/`height` the same way, each axis clamped into the sizeRect (`min-width`/`max-width`, `min-height`/`max-height` — GrowWindow's: the app stated the rectangle of sizes and the Window Manager clamped the drag to it; the mins default to the 80×54 floor a window can still be worked at, the maxes are unbounded, and a min equal to its max locks the axis — the strip that scrolls sideways and never grows taller). The clamp runs after the lattice snap, so a bound lands exactly the way an authored size does even off the lattice (an odd height at 2×); where a min and max cross the max wins, so a window authored under the floor and held there never jumps to it. The rect bounds the gesture only: a size authored outside it renders as declared, and the first grow-box move brings it inside. The drag fires `vf-resize` (detail `{ width, height, commit }`, sizes in whole system px) — one event per size the drag actually writes (`commit: false`), fired *after* the new box is applied so a handler that measures reads the resized layout, then a final `commit: true` as the gesture settles (release or cancel), only when it changed the size. Window content can follow the grow box from this event alone, no ResizeObserver. Fired by the gesture only: a programmatic `width`/`height` write fires nothing, the way a value set fires no `vf-change`.
224
224
  - **Slots:** default (body content), `status` (the bottom status strip — see Visual).
225
225
  - **Parts:** `frame`, `title-bar`, `title`, `close-box`, `zoom-box`, `body`, `status-bar`, `grow-box`, plus `viewport` re-exported from the built-in scroll area when `scrollbars` is set.
226
226
  - **Events:** `vf-close`, `vf-zoom` (detail `{}`), `vf-resize` (detail `{ width, height, commit }`).
@@ -389,11 +389,11 @@ Classic list box.
389
389
 
390
390
  #### `vf-scroll-area` (`VfScrollArea`, vf-scroll-area.ts)
391
391
  A container whose scrollbars look like System 7.
392
- - **Attributes/props:** `axis: 'vertical' | 'horizontal' | 'both'` (default `'vertical'`, reflected) — which scroll rails to reserve as permanent placeholders (see "always-a-rail" below); `label: string` — accessible name for the viewport (`aria-label` on the viewport, since an `aria-label` on the host cannot reach into the shadow DOM). The viewport is a **Tab stop only while its content actually overflows** — the same state `ScrollStateController` measures for the rails; a fitting scroll area used to be a focusable stop with `role: generic` and no name, a dead Tab press. Whenever it is a stop it carries a role: `role="region"` when `label` names it (a named landmark), `role="group"` when not (an unnamed region is inert, so that role is reserved for the labelled case).
393
- - **Visual:** `display: block`; the snapped wrapper carries a real 1px black frame and a grid reserving each rail as its own edge column/row — `[viewport | vertical rail]` over `[horizontal rail | corner]` — with the white inner viewport padded `8px` plus the border-floor compensation (a `mod()` term restoring what engines floor off the fractional border-width, so slotted content and the (0,0) of placed children sit exactly 9 system px from the frame box at every scale). Consumer sets width/height on host. The rails are the drawn `vfScrollRail` subtree (§4 — the classic 16px cell counting the frame line: divider, 14px channel, 15px arrow cells, the fixed 16px thumb, the `tileRaster` dot-dither trough), rendered as later siblings of the viewport and synced to its native scrolling by `ScrollRailController`; the viewport carries the `vf-scroll` class, which hides the native bar without touching the native scrolling. When both rails are reserved, the corner cell joins them, supplying the interior dividers the adjacent arrow cells leave to it. Every engine renders the same rail; the old `::-webkit-scrollbar` skin, its `.vf-scroll-frame` overlay contortion (WebKit quantized native scrollbar rects to whole CSS px) and the Firefox `scrollbar-color` fallback are all retired.
392
+ - **Attributes/props:** `axis: 'vertical' | 'horizontal' | 'both'` (default `'vertical'`, reflected) — which scroll rails to reserve as permanent placeholders (see "always-a-rail" below); `flush: boolean` (default false, reflected) — drops the viewport's 8px inset, keeping the border-floor term, so content and the (0,0) of placed children sit at the frame's inner edge; `corner: boolean` (default false, reflected) — reserves the bottom-right corner cell on a single-axis rail (the rail stops 15px short of the frame, the viewport spans the rest), for a grow box to land in; inert on `both`, which always has the cell; `label: string` — accessible name for the viewport (`aria-label` on the viewport, since an `aria-label` on the host cannot reach into the shadow DOM). The viewport is a **Tab stop only while its content actually overflows** — the same state `ScrollStateController` measures for the rails; a fitting scroll area used to be a focusable stop with `role: generic` and no name, a dead Tab press. Whenever it is a stop it carries a role: `role="region"` when `label` names it (a named landmark), `role="group"` when not (an unnamed region is inert, so that role is reserved for the labelled case).
393
+ - **Visual:** `display: block`; the snapped wrapper carries a real 1px black frame and a grid reserving each rail as its own edge column/row — `[viewport | vertical rail]` over `[horizontal rail | corner]` — with the white inner viewport padded `8px` plus the border-floor compensation (a `mod()` term restoring what engines floor off the fractional border-width, so slotted content and the (0,0) of placed children sit exactly 9 system px from the frame box at every scale; `flush` keeps only the compensation, and they sit exactly 1). Consumer sets width/height on host. The rails are the drawn `vfScrollRail` subtree (§4 — the classic 16px cell counting the frame line: divider, 14px channel, 15px arrow cells, the fixed 16px thumb, the `tileRaster` dot-dither trough), rendered as later siblings of the viewport and synced to its native scrolling by `ScrollRailController`; the viewport carries the `vf-scroll` class, which hides the native bar without touching the native scrolling. When both rails are reserved, the corner cell joins them, supplying the interior dividers the adjacent arrow cells leave to it; `corner` reserves the same 15×15 cell beside a single rail, its other divider continuing the rail's line across the cell — DrawGrowIcon's form, for the grow box. Every engine renders the same rail; the old `::-webkit-scrollbar` skin, its `.vf-scroll-frame` overlay contortion (WebKit quantized native scrollbar rects to whole CSS px) and the Firefox `scrollbar-color` fallback are all retired.
394
394
  - **Always-a-rail behavior:** each *reserved* axis (per `axis`) renders its rail element as a permanent placeholder — arrow buttons on an empty white channel (dither off, no thumb; System 7 drew the arrows on any bar in an active window, and a scroller outside a window always counts as active) — until the content overflows that axis, when the dither and thumb fill in and the arrows go live (an idle axis's arrows are drawn but inert — the press guard in `ScrollRailController` skips them). `ScrollStateController` (`src/scroll-state.ts`) measures both axes and writes `data-overflow-x` / `data-overflow-y` (`"true"` / `"false"`) on the scroll element; the recipe keys the dither and thumb off those attributes. The unreserved axis still scrolls natively (wheel, keyboard) but draws no rail. Shared by vf-list and vf-text-area; a future `@container scroll-state(scrollable)` query could replace the JS for slotted-content components.
395
395
  - **Inactive-window blanking:** the HIG's non-frontmost window must not display interactive scroll UX, so the controller also finds the nearest `vf-window` up the composed tree (light-DOM ancestor for a slotted scroller, shadow ancestor for `vf-window[scrollbars]`'s own edge rails), watches its reflected `active` attribute, and toggles a presence-only `data-window-inactive` on the scroll element. While present, the recipe empties dither/thumb/arrows on BOTH axes regardless of overflow — the bare channel, arrows included (unlike the idle rail, which keeps them), exactly as System 7 blanked a deactivated window's bars (its List Manager/TextEdit deactivated in-window scrollbars too). No `vf-window` ancestor → the attribute never appears: dialogs have no inactive state and a bare scroll component always draws live. Like the overflow half, this signal could one day go declarative — a custom property cascaded under `vf-window:not([active])` gating the recipe via an `@container style()` query; the rails being ordinary DOM, that migration is a plain selector swap (see the FUTURE note in scroll-state.ts).
396
- - **Document-window (TeachText) composition:** to put the rails on a window's edge rather than inset in its body, slot the scroll area into a `vf-window[flush]` sized `calc(100% + 2px·scale)` with `margin: -1px·scale` — one system pixel under the window frame on every side. Its own frame border then repaints the window's border lines exactly (no doubled frame), and a resizable window's grow box lands exactly over the rail's corner cell, giving the classic System 7 document window. `vf-window[scrollbars]` renders exactly this composition from its own shadow tree, so the one-liner and the slotted form are geometrically identical; slot it yourself when the well should sit *inset* in the body instead (the installer's read-me well).
396
+ - **Document-window (TeachText) composition:** to put the rails on a window's edge rather than inset in its body, slot the scroll area into a `vf-window[flush]` sized `calc(100% + 2px·scale)` with `margin: -1px·scale` — one system pixel under the window frame on every side. Its own frame border then repaints the window's border lines exactly (no doubled frame), and a resizable window's grow box lands exactly over the rail's corner cell, giving the classic System 7 document window. `vf-window[scrollbars]` renders exactly this composition from its own shadow tree (forwarding its `flush`, and `corner` for a resizable window without a status strip), so the one-liner and the slotted form are geometrically identical; slot it yourself when the well should sit *inset* in the body instead (the installer's read-me well).
397
397
  - **Slots:** default. **Parts:** `viewport`.
398
398
 
399
399
  #### `vf-fieldset` (`VfFieldset`, vf-fieldset.ts)
@@ -932,7 +932,7 @@
932
932
  },
933
933
  {
934
934
  "name": "vf-scroll-area",
935
- "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them.\n\nSize the host (width/height) from the outside; the viewport fills it.\n---\n\n\n### **Slots:**\n - _default_ - Scrollable content.\n\n### **CSS Properties:**\n - **--vf-scrollbar-thumb** - scrollbar thumb/elevator (white) _(default: undefined)_\n- **--vf-scrollbar-track** - the scroll trough's base color under the dot-dither (white) _(default: undefined)_\n\n### **CSS Parts:**\n - **viewport** - The inner scrolling container.",
935
+ "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them,\nand corner reserves that cell on a single-axis rail too — the\nrail stops 15px short of the frame, for a grow box to land in.\n\nSize the host (width/height) from the outside; the viewport fills it. The\nviewport insets its content 8px; flush drops that inset so content\nruns to the frame and the rails.\n---\n\n\n### **Slots:**\n - _default_ - Scrollable content.\n\n### **CSS Properties:**\n - **--vf-scrollbar-thumb** - scrollbar thumb/elevator (white) _(default: undefined)_\n- **--vf-scrollbar-track** - the scroll trough's base color under the dot-dither (white) _(default: undefined)_\n\n### **CSS Parts:**\n - **viewport** - The inner scrolling container.",
936
936
  "attributes": [
937
937
  {
938
938
  "name": "axis",
@@ -943,6 +943,16 @@
943
943
  { "name": "both" }
944
944
  ]
945
945
  },
946
+ {
947
+ "name": "flush",
948
+ "description": "Drop the viewport's 8px inset: slotted content and the (0,0) of placed\nchildren sit at the frame's inner edge, one system px from the frame\nbox (the border-floor compensation stays — see the viewport rule).\n`vf-window[scrollbars]` forwards its own `flush` here.",
949
+ "values": []
950
+ },
951
+ {
952
+ "name": "corner",
953
+ "description": "Reserve the bottom-right corner cell on a single-axis rail: the rail\nstops 15px short of the frame and the viewport spans the rest, leaving\nthe 15×15 cell — with the two dividers a `both` rail's corner carries —\nfor a grow box to land in. A `both` rail always has the cell, so the\nflag changes nothing there. `vf-window[scrollbars resizable]` sets it.",
954
+ "values": []
955
+ },
946
956
  {
947
957
  "name": "label",
948
958
  "description": "Accessible name for the scrolling viewport, applied as its `aria-label`\n(an `aria-label` on the host would not reach into the shadow DOM). The\nviewport is keyboard-focusable while its content overflows, so without a\nname it is announced only as an anonymous scrollable group; setting\n`label` also promotes it to a named `role=\"region\"` landmark. While\n`label` is empty the viewport is a plain `group` when scrollable (an\nunnamed region is inert) and role-less when not.",
@@ -1351,17 +1361,37 @@
1351
1361
  },
1352
1362
  {
1353
1363
  "name": "resizable",
1354
- "description": "Show a grow box at the bottom-right corner for resizing.",
1364
+ "description": "Show a grow box at the bottom-right corner for resizing. The drag is\nbounded per axis by the sizeRect below.",
1365
+ "values": []
1366
+ },
1367
+ {
1368
+ "name": "min-width",
1369
+ "description": "The sizeRect: the range of sizes the grow box can drag the window to,\nper axis, in whole system px — GrowWindow's, where the app stated the\nrectangle and the Window Manager clamped the drag to it. `minWidth` and\n`minHeight` default to the 80×54 floor a window can still be worked at;\nthe maxes are unbounded. A min equal to its max locks that axis —\n`min-height=\"67\" max-height=\"67\"` on a strip that scrolls sideways and\nnever grows taller, so the grow box changes the width alone.\n\nBounds the gesture only: an authored `width`/`height` outside the rect\nrenders as declared, and the first grow-box move brings it inside. The\nclamp runs after the drag's lattice snap, so a bound lands exactly the\nway an authored size does, even off the lattice (an odd height at 2×);\nwhere a min and max cross, the max wins, so a window held under the\nfloor stays put instead of jumping to it.",
1370
+ "values": []
1371
+ },
1372
+ {
1373
+ "name": "min-height",
1374
+ "description": "See minWidth. Default 54.",
1375
+ "values": []
1376
+ },
1377
+ {
1378
+ "name": "max-width",
1379
+ "description": "See minWidth. Unbounded by default.",
1380
+ "values": []
1381
+ },
1382
+ {
1383
+ "name": "max-height",
1384
+ "description": "See minWidth. Unbounded by default.",
1355
1385
  "values": []
1356
1386
  },
1357
1387
  {
1358
1388
  "name": "flush",
1359
- "description": "Remove the default 12px body padding.",
1389
+ "description": "Remove the default 12px body padding. Under `scrollbars` the body has\nnone to remove, so the flag reaches the built-in scroll area instead\nand drops its viewport's 8px inset: content runs to the frame and the\nrails, and the (0,0) of placed children is the content region's corner.",
1360
1390
  "values": []
1361
1391
  },
1362
1392
  {
1363
1393
  "name": "scrollbars",
1364
- "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell. Values mirror `vf-scroll-area`'s `axis`; the `heading` names the\nscroll region; the viewport part is re-exported. Implies `flush` (the\nviewport carries its own padding). The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
1394
+ "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell — reserved on a single-axis rail too (the area's `corner`), unless\na populated status strip holds the grow box, when the rail runs edge to\nedge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the\n`heading` names the scroll region; the viewport part is re-exported.\nThe body's own padding goes; the viewport keeps its 8px inset unless\n`flush`, which passes through. The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
1365
1395
  "values": [
1366
1396
  { "name": "vertical" },
1367
1397
  { "name": "horizontal" },
@@ -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.5.4",
4
+ "version": "0.5.6",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -2239,7 +2239,7 @@
2239
2239
  },
2240
2240
  {
2241
2241
  "name": "vf-scroll-area",
2242
- "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them.\n\nSize the host (width/height) from the outside; the viewport fills it.\n---\n\n\n### **Slots:**\n - _default_ - Scrollable content.\n\n### **CSS Properties:**\n - **--vf-scrollbar-thumb** - scrollbar thumb/elevator (white) _(default: undefined)_\n- **--vf-scrollbar-track** - the scroll trough's base color under the dot-dither (white) _(default: undefined)_\n\n### **CSS Parts:**\n - **viewport** - The inner scrolling container.",
2242
+ "description": "`<vf-scroll-area>` — a container whose scrollbars look like System 7.\n\nWhite box with a 1px black frame, an inner scrolling viewport, and scroll\nrails the kit draws itself as shadow DOM (the shared `vfScrollRail` recipe):\nboxed arrow buttons at each end, a loose 1-bit dot-dither trough, and the\nclassic fixed 16px thumb. The native scrollbar is hidden, never the native\nscrolling — wheel, trackpad momentum, keyboard, touch and assistive-tech\nscrolling stay the platform's, and ScrollRailController keeps the\nrail in sync while driving the classic interactions (thumb drag, trough\npaging, arrow stepping with auto-repeat). Every engine renders the same\nrail — there is no Firefox fallback skin anymore.\n\nEach reserved scroll rail is a permanent placeholder: arrow buttons on an\nempty white channel sit in the gutter even when the content fits, the\ndither and thumb filling in only once that axis overflows (System 7 drew\nan active window's no-overflow bar as arrows on a bare channel; driven\nby ScrollStateController). Which rails are reserved is set by\naxis; when both are reserved the bottom-right corner joins them,\nand corner reserves that cell on a single-axis rail too — the\nrail stops 15px short of the frame, for a grow box to land in.\n\nSize the host (width/height) from the outside; the viewport fills it. The\nviewport insets its content 8px; flush drops that inset so content\nruns to the frame and the rails.\n---\n\n\n### **Slots:**\n - _default_ - Scrollable content.\n\n### **CSS Properties:**\n - **--vf-scrollbar-thumb** - scrollbar thumb/elevator (white) _(default: undefined)_\n- **--vf-scrollbar-track** - the scroll trough's base color under the dot-dither (white) _(default: undefined)_\n\n### **CSS Parts:**\n - **viewport** - The inner scrolling container.",
2243
2243
  "doc-url": "",
2244
2244
  "attributes": [
2245
2245
  {
@@ -2250,6 +2250,16 @@
2250
2250
  "default": "'vertical'"
2251
2251
  }
2252
2252
  },
2253
+ {
2254
+ "name": "flush",
2255
+ "description": "Drop the viewport's 8px inset: slotted content and the (0,0) of placed\nchildren sit at the frame's inner edge, one system px from the frame\nbox (the border-floor compensation stays — see the viewport rule).\n`vf-window[scrollbars]` forwards its own `flush` here.",
2256
+ "value": { "type": "boolean", "default": "false" }
2257
+ },
2258
+ {
2259
+ "name": "corner",
2260
+ "description": "Reserve the bottom-right corner cell on a single-axis rail: the rail\nstops 15px short of the frame and the viewport spans the rest, leaving\nthe 15×15 cell — with the two dividers a `both` rail's corner carries —\nfor a grow box to land in. A `both` rail always has the cell, so the\nflag changes nothing there. `vf-window[scrollbars resizable]` sets it.",
2261
+ "value": { "type": "boolean", "default": "false" }
2262
+ },
2253
2263
  {
2254
2264
  "name": "label",
2255
2265
  "description": "Accessible name for the scrolling viewport, applied as its `aria-label`\n(an `aria-label` on the host would not reach into the shadow DOM). The\nviewport is keyboard-focusable while its content overflows, so without a\nname it is announced only as an anonymous scrollable group; setting\n`label` also promotes it to a named `role=\"region\"` landmark. While\n`label` is empty the viewport is a plain `group` when scrollable (an\nunnamed region is inert) and role-less when not.",
@@ -2275,6 +2285,16 @@
2275
2285
  "description": "Which scroll rails to reserve as permanent placeholders: `vertical`\n(default), `horizontal`, or `both`. Each reserved rail shows an empty white\nchannel until its axis overflows; the unreserved axis still scrolls\nnatively (wheel, keyboard) but draws no rail.",
2276
2286
  "type": "'vertical' | 'horizontal' | 'both'"
2277
2287
  },
2288
+ {
2289
+ "name": "flush",
2290
+ "description": "Drop the viewport's 8px inset: slotted content and the (0,0) of placed\nchildren sit at the frame's inner edge, one system px from the frame\nbox (the border-floor compensation stays — see the viewport rule).\n`vf-window[scrollbars]` forwards its own `flush` here.",
2291
+ "type": "boolean"
2292
+ },
2293
+ {
2294
+ "name": "corner",
2295
+ "description": "Reserve the bottom-right corner cell on a single-axis rail: the rail\nstops 15px short of the frame and the viewport spans the rest, leaving\nthe 15×15 cell — with the two dividers a `both` rail's corner carries —\nfor a grow box to land in. A `both` rail always has the cell, so the\nflag changes nothing there. `vf-window[scrollbars resizable]` sets it.",
2296
+ "type": "boolean"
2297
+ },
2278
2298
  {
2279
2299
  "name": "label",
2280
2300
  "description": "Accessible name for the scrolling viewport, applied as its `aria-label`\n(an `aria-label` on the host would not reach into the shadow DOM). The\nviewport is keyboard-focusable while its content overflows, so without a\nname it is announced only as an anonymous scrollable group; setting\n`label` also promotes it to a named `role=\"region\"` landmark. While\n`label` is empty the viewport is a plain `group` when scrollable (an\nunnamed region is inert) and role-less when not.",
@@ -3270,17 +3290,37 @@
3270
3290
  },
3271
3291
  {
3272
3292
  "name": "resizable",
3273
- "description": "Show a grow box at the bottom-right corner for resizing.",
3293
+ "description": "Show a grow box at the bottom-right corner for resizing. The drag is\nbounded per axis by the sizeRect below.",
3274
3294
  "value": { "type": "boolean", "default": "false" }
3275
3295
  },
3296
+ {
3297
+ "name": "min-width",
3298
+ "description": "The sizeRect: the range of sizes the grow box can drag the window to,\nper axis, in whole system px — GrowWindow's, where the app stated the\nrectangle and the Window Manager clamped the drag to it. `minWidth` and\n`minHeight` default to the 80×54 floor a window can still be worked at;\nthe maxes are unbounded. A min equal to its max locks that axis —\n`min-height=\"67\" max-height=\"67\"` on a strip that scrolls sideways and\nnever grows taller, so the grow box changes the width alone.\n\nBounds the gesture only: an authored `width`/`height` outside the rect\nrenders as declared, and the first grow-box move brings it inside. The\nclamp runs after the drag's lattice snap, so a bound lands exactly the\nway an authored size does, even off the lattice (an odd height at 2×);\nwhere a min and max cross, the max wins, so a window held under the\nfloor stays put instead of jumping to it.",
3299
+ "value": { "type": "number | null | undefined" }
3300
+ },
3301
+ {
3302
+ "name": "min-height",
3303
+ "description": "See minWidth. Default 54.",
3304
+ "value": { "type": "number | null | undefined" }
3305
+ },
3306
+ {
3307
+ "name": "max-width",
3308
+ "description": "See minWidth. Unbounded by default.",
3309
+ "value": { "type": "number | null | undefined" }
3310
+ },
3311
+ {
3312
+ "name": "max-height",
3313
+ "description": "See minWidth. Unbounded by default.",
3314
+ "value": { "type": "number | null | undefined" }
3315
+ },
3276
3316
  {
3277
3317
  "name": "flush",
3278
- "description": "Remove the default 12px body padding.",
3318
+ "description": "Remove the default 12px body padding. Under `scrollbars` the body has\nnone to remove, so the flag reaches the built-in scroll area instead\nand drops its viewport's 8px inset: content runs to the frame and the\nrails, and the (0,0) of placed children is the content region's corner.",
3279
3319
  "value": { "type": "boolean", "default": "false" }
3280
3320
  },
3281
3321
  {
3282
3322
  "name": "scrollbars",
3283
- "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell. Values mirror `vf-scroll-area`'s `axis`; the `heading` names the\nscroll region; the viewport part is re-exported. Implies `flush` (the\nviewport carries its own padding). The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
3323
+ "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell — reserved on a single-axis rail too (the area's `corner`), unless\na populated status strip holds the grow box, when the rail runs edge to\nedge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the\n`heading` names the scroll region; the viewport part is re-exported.\nThe body's own padding goes; the viewport keeps its 8px inset unless\n`flush`, which passes through. The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
3284
3324
  "value": {
3285
3325
  "type": "'vertical' | 'horizontal' | 'both' | undefined"
3286
3326
  }
@@ -3361,17 +3401,37 @@
3361
3401
  },
3362
3402
  {
3363
3403
  "name": "resizable",
3364
- "description": "Show a grow box at the bottom-right corner for resizing.",
3404
+ "description": "Show a grow box at the bottom-right corner for resizing. The drag is\nbounded per axis by the sizeRect below.",
3365
3405
  "type": "boolean"
3366
3406
  },
3407
+ {
3408
+ "name": "minWidth",
3409
+ "description": "The sizeRect: the range of sizes the grow box can drag the window to,\nper axis, in whole system px — GrowWindow's, where the app stated the\nrectangle and the Window Manager clamped the drag to it. `minWidth` and\n`minHeight` default to the 80×54 floor a window can still be worked at;\nthe maxes are unbounded. A min equal to its max locks that axis —\n`min-height=\"67\" max-height=\"67\"` on a strip that scrolls sideways and\nnever grows taller, so the grow box changes the width alone.\n\nBounds the gesture only: an authored `width`/`height` outside the rect\nrenders as declared, and the first grow-box move brings it inside. The\nclamp runs after the drag's lattice snap, so a bound lands exactly the\nway an authored size does, even off the lattice (an odd height at 2×);\nwhere a min and max cross, the max wins, so a window held under the\nfloor stays put instead of jumping to it.",
3410
+ "type": "number | null | undefined"
3411
+ },
3412
+ {
3413
+ "name": "minHeight",
3414
+ "description": "See minWidth. Default 54.",
3415
+ "type": "number | null | undefined"
3416
+ },
3417
+ {
3418
+ "name": "maxWidth",
3419
+ "description": "See minWidth. Unbounded by default.",
3420
+ "type": "number | null | undefined"
3421
+ },
3422
+ {
3423
+ "name": "maxHeight",
3424
+ "description": "See minWidth. Unbounded by default.",
3425
+ "type": "number | null | undefined"
3426
+ },
3367
3427
  {
3368
3428
  "name": "flush",
3369
- "description": "Remove the default 12px body padding.",
3429
+ "description": "Remove the default 12px body padding. Under `scrollbars` the body has\nnone to remove, so the flag reaches the built-in scroll area instead\nand drops its viewport's 8px inset: content runs to the frame and the\nrails, and the (0,0) of placed children is the content region's corner.",
3370
3430
  "type": "boolean"
3371
3431
  },
3372
3432
  {
3373
3433
  "name": "scrollbars",
3374
- "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell. Values mirror `vf-scroll-area`'s `axis`; the `heading` names the\nscroll region; the viewport part is re-exported. Implies `flush` (the\nviewport carries its own padding). The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
3434
+ "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell — reserved on a single-axis rail too (the area's `corner`), unless\na populated status strip holds the grow box, when the rail runs edge to\nedge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the\n`heading` names the scroll region; the viewport part is re-exported.\nThe body's own padding goes; the viewport keeps its 8px inset unless\n`flush`, which passes through. The slotted composition (SPEC §5\nvf-scroll-area) still works for windows that want an inset well instead.",
3375
3435
  "type": "'vertical' | 'horizontal' | 'both' | undefined"
3376
3436
  },
3377
3437
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vintage-frames",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
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",