vintage-frames 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/custom-elements.json +8 -8
  2. package/dist/components/vf-checkbox.d.ts +6 -5
  3. package/dist/components/vf-checkbox.js +41 -37
  4. package/dist/components/vf-container.d.ts +11 -13
  5. package/dist/components/vf-container.js +24 -12
  6. package/dist/components/vf-fieldset.js +30 -22
  7. package/dist/components/vf-icon.js +55 -55
  8. package/dist/components/vf-list.js +30 -29
  9. package/dist/components/vf-menu.js +24 -22
  10. package/dist/components/vf-number-field.js +32 -30
  11. package/dist/components/vf-progress-bar.js +28 -29
  12. package/dist/components/vf-radio.js +3 -4
  13. package/dist/components/vf-scroll-area.js +27 -26
  14. package/dist/components/vf-select.js +108 -90
  15. package/dist/components/vf-separator.d.ts +5 -5
  16. package/dist/components/vf-separator.js +36 -10
  17. package/dist/components/vf-swatch.js +47 -45
  18. package/dist/components/vf-text-area.js +37 -35
  19. package/dist/components/vf-text-field.js +20 -18
  20. package/dist/components/vf-window.js +92 -72
  21. package/dist/index.d.ts +10 -1
  22. package/dist/index.js +60 -59
  23. package/dist/styles/base.d.ts +3 -1
  24. package/dist/styles/recipes/field.d.ts +10 -6
  25. package/dist/styles/recipes/field.js +8 -7
  26. package/dist/styles/recipes/focus.d.ts +7 -3
  27. package/dist/styles/recipes/rule.d.ts +11 -8
  28. package/dist/styles/recipes/rule.js +31 -13
  29. package/dist/styles/recipes/scroll-rail.d.ts +7 -6
  30. package/dist/styles/recipes/scroll-rail.js +18 -18
  31. package/dist/styles/recipes/shadow.d.ts +10 -6
  32. package/dist/styles/recipes/shadow.js +4 -2
  33. package/dist/styles/recipes/stroke.d.ts +85 -0
  34. package/dist/styles/recipes/stroke.js +53 -0
  35. package/dist/styles/recipes/surface.d.ts +8 -4
  36. package/dist/styles/recipes/surface.js +23 -17
  37. package/dist/styles/recipes/title-bar.d.ts +7 -0
  38. package/dist/styles/recipes/title-bar.js +25 -22
  39. package/dist/styles/recipes/toggle.js +3 -3
  40. package/dist/zoom.d.ts +9 -9
  41. package/docs/SPEC.md +23 -22
  42. package/editor/vscode.html-custom-data.json +4 -4
  43. package/editor/web-types.json +7 -7
  44. package/package.json +1 -1
@@ -6,39 +6,40 @@ import { PlacementController as c, VfPositioned as l, placementIn as u, warnMova
6
6
  import { vfBase as f } from "../styles/recipes/host.js";
7
7
  import { RepeatTileController as p, patternOverride as m, tileGrid as h, vfTileGrid as g } from "../tile-grid.js";
8
8
  import { DOTS as _, DOT_SPAN as v, vfDots as y, vfStripes as b } from "../styles/recipes/pattern.js";
9
- import { vfChromeFrame as x } from "../styles/recipes/surface.js";
10
- import { vfRule as S } from "../styles/recipes/rule.js";
11
- import { vfTitleBar as C, vfWindowWidgets as w } from "../styles/recipes/title-bar.js";
12
- import { vfFocus as T } from "../styles/recipes/focus.js";
13
- import { GridSnapController as E } from "../grid-snap.js";
14
- import { DocumentListenersController as D } from "../document-listeners.js";
15
- import { VfSized as O } from "../size.js";
16
- import { DragController as k } from "../drag.js";
17
- import { TitleCenterController as A, chromeTitleBar as j, closeBox as M, widgetLabel as N, zoomBox as P } from "../chrome.js";
18
- import { prefersReducedMotion as F, windowRectFraction as I } from "../motion.js";
19
- import { paintSelectionRect as L, penPhase as R, xorPenCanvas as z } from "../open-art.js";
9
+ import { vfStrokeDecls as x, vfStrokeInset as S } from "../styles/recipes/stroke.js";
10
+ import { vfChromeFrame as C } from "../styles/recipes/surface.js";
11
+ import { vfRule as w } from "../styles/recipes/rule.js";
12
+ import { vfTitleBar as T, vfWindowWidgets as E } from "../styles/recipes/title-bar.js";
13
+ import { vfFocus as D } from "../styles/recipes/focus.js";
14
+ import { GridSnapController as O } from "../grid-snap.js";
15
+ import { DocumentListenersController as k } from "../document-listeners.js";
16
+ import { VfSized as A } from "../size.js";
17
+ import { DragController as j } from "../drag.js";
18
+ import { TitleCenterController as M, chromeTitleBar as N, closeBox as P, widgetLabel as F, zoomBox as I } from "../chrome.js";
19
+ import { prefersReducedMotion as L, windowRectFraction as R } from "../motion.js";
20
+ import { paintSelectionRect as z, penPhase as B, xorPenCanvas as V } from "../open-art.js";
20
21
  import "./vf-scroll-area.js";
21
- import { LitElement as B, css as V, html as H, nothing as U } from "lit";
22
- import { property as W, query as G, state as K } from "lit/decorators.js";
22
+ import { LitElement as H, css as U, html as W, nothing as G } from "lit";
23
+ import { property as K, query as q, state as J } from "lit/decorators.js";
23
24
  //#region src/components/vf-window.ts
24
- var q = 80, J = 54;
25
- function Y(e, t, n) {
25
+ var Y = 80, X = 54;
26
+ function Z(e, t, n) {
26
27
  let r = Math.max(t, e);
27
28
  return n == null ? r : Math.min(n, r);
28
29
  }
29
- var X = 24, Z = class extends O(l(B)) {
30
+ var Q = 24, $ = class extends A(l(H)) {
30
31
  constructor(...e) {
31
- super(...e), this.heading = "", this.active = !0, this.closable = !0, this.zoomable = !1, this.movable = !1, this.outlineDrag = !1, this.resizable = !1, this._hasHeader = !1, this._hasStatus = !1, this.scale = new n(this), this.gridSnap = new E(this), this.titleCenter = new A(this), this._dotsPattern = "", this.#e = new p(this, {
32
+ super(...e), this.heading = "", this.active = !0, this.closable = !0, this.zoomable = !1, this.movable = !1, this.outlineDrag = !1, this.resizable = !1, this._hasHeader = !1, this._hasStatus = !1, this.scale = new n(this), this.gridSnap = new O(this), this.titleCenter = new M(this), this._dotsPattern = "", this.#e = new p(this, {
32
33
  getBox: () => this.renderRoot?.querySelector(".vf-dots"),
33
34
  getArt: () => this.variant === "utility" && !this._dotsPattern ? _ : null,
34
35
  property: "--_vf-dots-tile"
35
36
  }), this.#t = (e, t, n) => {
36
37
  let r = o(this.offsetWidth, this);
37
38
  return {
38
- x: Math.min(Math.max(e, X - r), n.width - X),
39
- y: Math.min(Math.max(t, 0), Math.max(0, n.height - X))
39
+ x: Math.min(Math.max(e, Q - r), n.width - Q),
40
+ y: Math.min(Math.max(t, 0), Math.max(0, n.height - Q))
40
41
  };
41
- }, this._placement = new c(this, (e, t, n) => this.#t(e, t, n)), this._drag = new k(this, {
42
+ }, this._placement = new c(this, (e, t, n) => this.#t(e, t, n)), this._drag = new j(this, {
42
43
  onDragStart: (e) => {
43
44
  if (!this.movable || e.button !== 0 || e.composedPath().some((e) => e instanceof HTMLElement && e.classList.contains("box"))) return null;
44
45
  this.#S();
@@ -51,7 +52,7 @@ var X = 24, Z = class extends O(l(B)) {
51
52
  onDragEnd: (e, t) => {
52
53
  this.#y(t);
53
54
  }
54
- }), this._resizeState = null, this.#n = this.attachInternals(), this.#r = null, this.#i = new D(this, () => [[
55
+ }), this._resizeState = null, this.#n = this.attachInternals(), this.#r = null, this.#i = new k(this, () => [[
55
56
  document,
56
57
  "pointerdown",
57
58
  this.#a,
@@ -65,7 +66,7 @@ var X = 24, Z = class extends O(l(B)) {
65
66
  this.#s("finish");
66
67
  }, this.#o = (e) => {
67
68
  e.key !== "Escape" || !this.#r || (e.preventDefault(), e.stopPropagation(), this.#s("finish"));
68
- }, this.#f = null, this.#p = new D(this, () => [[
69
+ }, this.#f = null, this.#p = new k(this, () => [[
69
70
  document,
70
71
  "keydown",
71
72
  this.#m,
@@ -80,12 +81,12 @@ var X = 24, Z = class extends O(l(B)) {
80
81
  b,
81
82
  y,
82
83
  g,
83
- T,
84
- x,
85
- S,
84
+ D,
86
85
  C,
87
86
  w,
88
- V`
87
+ T,
88
+ E,
89
+ U`
89
90
  :host {
90
91
  display: block;
91
92
  position: relative;
@@ -147,12 +148,12 @@ var X = 24, Z = class extends O(l(B)) {
147
148
  a focused widget out of the tree, so focus can't be dropped to
148
149
  <body> by a click on another window. */
149
150
  :host(:not([active])) .box {
150
- border-color: transparent;
151
+ --_vf-stroke-ink: transparent;
151
152
  background-color: transparent;
152
153
  box-shadow: none;
153
154
  }
154
155
  :host(:not([active])) .zoom::after {
155
- border-color: transparent;
156
+ --_vf-stroke-ink: transparent;
156
157
  }
157
158
 
158
159
  /* --- Utility (windoid) variant --------------------------------- */
@@ -195,7 +196,7 @@ var X = 24, Z = class extends O(l(B)) {
195
196
  a white (invisible, over the patch ring) borderline — rather than the
196
197
  big bar's 9×9 sunburst, which cannot land whole on a 5×5 interior. */
197
198
  :host([variant='utility']) .box:active {
198
- border-color: var(--vf-white, #ffffff);
199
+ --_vf-stroke-ink: var(--vf-white, #ffffff);
199
200
  background-color: var(--vf-black, #000000);
200
201
  background-image: none;
201
202
  }
@@ -272,11 +273,19 @@ var X = 24, Z = class extends O(l(B)) {
272
273
  vertical rail's arrows begin under it. Takes no space until the slot
273
274
  is populated. Clipped like the body; a drop-open panel still escapes
274
275
  (see the body's note). A div with a class, never a <header>: that
275
- element maps to a banner landmark (see render()). */
276
+ element maps to a banner landmark (see render()).
277
+
278
+ The rule is a stroke, so the header's own box runs under it: the
279
+ slot is the box content lays out, places and clips in, above the
280
+ rule. */
276
281
  .header {
277
- position: relative;
278
282
  flex: none;
279
283
  background: var(--vf-white, #ffffff);
284
+ }
285
+ .header > slot {
286
+ display: block;
287
+ position: relative;
288
+ height: 100%;
280
289
  overflow: hidden;
281
290
  }
282
291
  .header.empty {
@@ -296,7 +305,6 @@ var X = 24, Z = class extends O(l(B)) {
296
305
  .status {
297
306
  flex: none;
298
307
  display: flex;
299
- align-items: center;
300
308
  height: calc(var(--vf-scale, 1) * var(--vf-status-bar-height, 15px));
301
309
  /* The rule is vfRule's vf-rule-top on the element. */
302
310
  background: var(--vf-white, #ffffff);
@@ -305,6 +313,16 @@ var X = 24, Z = class extends O(l(B)) {
305
313
  white-space: nowrap;
306
314
  overflow: hidden;
307
315
  }
316
+ /* The rule is a stroke, so the strip's own box runs under it: the slot
317
+ centers the content in the 14px below the rule and clips it there.
318
+ Sideways it still runs to the strip's edges, as before. */
319
+ .status > slot {
320
+ display: flex;
321
+ align-items: center;
322
+ flex: 1 1 auto;
323
+ min-width: 0;
324
+ overflow-y: clip;
325
+ }
308
326
  /* Clear the grow box: its 15px cell plus the strip's own 6px inset. */
309
327
  :host([resizable]) .status {
310
328
  padding-inline-end: calc(var(--vf-scale, 1) * 21px);
@@ -314,18 +332,20 @@ var X = 24, Z = class extends O(l(B)) {
314
332
  }
315
333
 
316
334
  /* --- Grow box --------------------------------------------------- */
335
+ /* Flush inside the frame's stroke, which is padding (vfChromeFrame);
336
+ the two nested squares place against the box the same way, the
337
+ lower-right one clear of its top/left stroke. */
317
338
  .grow {
318
339
  position: absolute;
319
- right: 0;
320
- bottom: 0;
340
+ right: ${S(0)};
341
+ bottom: ${S(0)};
321
342
  z-index: 1;
322
343
  width: calc(var(--vf-scale, 1) * 15px);
323
344
  height: calc(var(--vf-scale, 1) * 15px);
324
- border-top: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000000);
325
- border-left: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000000);
326
345
  background: var(--vf-white, #ffffff);
327
346
  touch-action: none;
328
347
  cursor: var(--vf-cursor, default);
348
+ ${x({ edges: ["top", "left"] })}
329
349
  }
330
350
  .grow::before {
331
351
  content: '';
@@ -334,17 +354,17 @@ var X = 24, Z = class extends O(l(B)) {
334
354
  bottom: calc(var(--vf-scale, 1) * 1px);
335
355
  width: calc(var(--vf-scale, 1) * 9px);
336
356
  height: calc(var(--vf-scale, 1) * 9px);
337
- border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000000);
357
+ ${x()}
338
358
  }
339
359
  .grow::after {
340
360
  content: '';
341
361
  position: absolute;
342
- top: calc(var(--vf-scale, 1) * 2px);
343
- left: calc(var(--vf-scale, 1) * 2px);
362
+ top: ${S(2)};
363
+ left: ${S(2)};
344
364
  width: calc(var(--vf-scale, 1) * 7px);
345
365
  height: calc(var(--vf-scale, 1) * 7px);
346
- border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000000);
347
366
  background: var(--vf-white, #ffffff);
367
+ ${x()}
348
368
  }
349
369
  /* Inactive window: the size box empties with the scroll rails (the same
350
370
  HIG no-interactive-UX treatment ScrollStateController drives for the
@@ -380,7 +400,7 @@ var X = 24, Z = class extends O(l(B)) {
380
400
  async show(e = {}) {
381
401
  this.#s("finish"), this.hidden = !1;
382
402
  let t = e.from;
383
- if (!t || F()) return !1;
403
+ if (!t || L()) return !1;
384
404
  let n = {
385
405
  closing: !1,
386
406
  animations: []
@@ -396,7 +416,7 @@ var X = 24, Z = class extends O(l(B)) {
396
416
  async hide(e = {}) {
397
417
  let t = this.#r?.closing === !1, n = !this.hidden && !t;
398
418
  this.#s(t ? "cancel" : "finish");
399
- let r = e.to, i = r && n && this.isConnected && !F() ? this.#u(r, this.getBoundingClientRect(), !0) : null;
419
+ let r = e.to, i = r && n && this.isConnected && !L() ? this.#u(r, this.getBoundingClientRect(), !0) : null;
400
420
  if (this.hidden = !0, !i) return !1;
401
421
  let a = {
402
422
  closing: !0,
@@ -439,8 +459,8 @@ var X = 24, Z = class extends O(l(B)) {
439
459
  animations: []
440
460
  };
441
461
  for (let e = 0; e < 14; e++) {
442
- let t = I(e), r = (e, n) => e + Math.trunc((n - e) * t), o = r(l.left, u.left), s = r(l.top, u.top), c = Math.max(1, r(l.right, u.right) - o), f = Math.max(1, r(l.bottom, u.bottom) - s), p = z("window-rect"), m = p.style;
443
- m.position = "absolute", m.left = a(o), m.top = a(s), m.width = a(c), m.height = a(f), m.visibility = "hidden", L(p, c, f, R(o, s)), i.append(p), d.canvases.push(p);
462
+ let t = R(e), r = (e, n) => e + Math.trunc((n - e) * t), o = r(l.left, u.left), s = r(l.top, u.top), c = Math.max(1, r(l.right, u.right) - o), f = Math.max(1, r(l.bottom, u.bottom) - s), p = V("window-rect"), m = p.style;
463
+ m.position = "absolute", m.left = a(o), m.top = a(s), m.width = a(c), m.height = a(f), m.visibility = "hidden", z(p, c, f, B(o, s)), i.append(p), d.canvases.push(p);
444
464
  let h = n ? 13 - e : e;
445
465
  d.animations.push(p.animate([{ visibility: "visible" }, { visibility: "visible" }], {
446
466
  delay: h * 17,
@@ -475,13 +495,13 @@ var X = 24, Z = class extends O(l(B)) {
475
495
  #_(e, t, n) {
476
496
  let r = e.base.x + t, i = e.base.y + n;
477
497
  e.canvas.style.left = a(r), e.canvas.style.top = a(i);
478
- let o = R(r, i);
479
- o !== e.phase && (e.phase = o, L(e.canvas, e.width, e.height, o));
498
+ let o = B(r, i);
499
+ o !== e.phase && (e.phase = o, z(e.canvas, e.width, e.height, o));
480
500
  }
481
501
  #v(e) {
482
502
  let t = this.#d();
483
503
  if (!t) return null;
484
- let n = r(this), i = t.getBoundingClientRect(), o = Math.max(1, Math.round(e.width / n)), s = Math.max(1, Math.round(e.height / n)), c = z("drag-outline"), l = c.style;
504
+ let n = r(this), i = t.getBoundingClientRect(), o = Math.max(1, Math.round(e.width / n)), s = Math.max(1, Math.round(e.height / n)), c = V("drag-outline"), l = c.style;
485
505
  return l.position = "absolute", l.width = a(o), l.height = a(s), t.append(c), {
486
506
  canvas: c,
487
507
  base: {
@@ -554,7 +574,7 @@ var X = 24, Z = class extends O(l(B)) {
554
574
  _onGrowPointerMove(e) {
555
575
  let t = this._resizeState;
556
576
  if (!t || e.pointerId !== t.pointerId) return;
557
- let n = Y(i(t.baseWidth + o(e.clientX - t.startX, this), this), this.minWidth ?? q, this.maxWidth), r = Y(i(t.baseHeight + o(e.clientY - t.startY, this), this), this.minHeight ?? J, this.maxHeight);
577
+ let n = Z(i(t.baseWidth + o(e.clientX - t.startX, this), this), this.minWidth ?? Y, this.maxWidth), r = Z(i(t.baseHeight + o(e.clientY - t.startY, this), this), this.minHeight ?? X, this.maxHeight);
558
578
  (n !== this.width || r !== this.height) && (t.emitPending = !0, t.resized = !0), this.width = n, this.height = r;
559
579
  }
560
580
  _onGrowPointerEnd(t) {
@@ -569,42 +589,42 @@ var X = 24, Z = class extends O(l(B)) {
569
589
  });
570
590
  }
571
591
  render() {
572
- return H`
592
+ return W`
573
593
  <div
574
594
  class="vf-frame vf-snap"
575
595
  part="frame"
576
596
  role="group"
577
- aria-labelledby=${this.heading ? "title" : U}
597
+ aria-labelledby=${this.heading ? "title" : G}
578
598
  >
579
- ${j(this._drag, H`
580
- ${this.closable ? M(N("Close", this.heading), this._onCloseClick) : U}
599
+ ${N(this._drag, W`
600
+ ${this.closable ? P(F("Close", this.heading), this._onCloseClick) : G}
581
601
  <span class="vf-title" part="title" id="title">${this.heading}</span>
582
- ${this.zoomable ? P(N("Zoom", this.heading), this._onZoomClick) : U}
602
+ ${this.zoomable ? I(F("Zoom", this.heading), this._onZoomClick) : G}
583
603
  `, this.variant === "utility" ? this._dotsPattern ? "vf-dots vf-dots-token" : "vf-dots" : "vf-stripes", this.variant === "utility" ? this._dotsTexture() : void 0)}
584
604
  <div
585
605
  class="header vf-rule-bottom ${this._hasHeader ? "" : "empty"}"
586
606
  part="header"
587
- style=${this.headerHeight == null ? U : `height:${a(this.headerHeight)}`}
607
+ style=${this.headerHeight == null ? G : `height:${a(this.headerHeight)}`}
588
608
  >
589
609
  <slot name="header" @slotchange=${this._onHeaderSlotChange}></slot>
590
610
  </div>
591
611
  <div class="body" part="body">
592
- ${this.scrollbars ? H`
612
+ ${this.scrollbars ? W`
593
613
  <vf-scroll-area
594
614
  class="edge-scroll"
595
615
  axis=${this.scrollbars}
596
616
  ?corner=${this.resizable && !this._hasStatus}
597
- label=${this.heading || U}
617
+ label=${this.heading || G}
598
618
  exportparts="viewport"
599
619
  >
600
620
  <slot></slot>
601
621
  </vf-scroll-area>
602
- ` : H`<slot></slot>`}
622
+ ` : W`<slot></slot>`}
603
623
  </div>
604
624
  <div class="status vf-rule-top ${this._hasStatus ? "" : "empty"}" part="status-bar">
605
625
  <slot name="status" @slotchange=${this._onStatusSlotChange}></slot>
606
626
  </div>
607
- ${this.resizable ? H`
627
+ ${this.resizable ? W`
608
628
  <div
609
629
  class="grow"
610
630
  part="grow-box"
@@ -614,45 +634,45 @@ var X = 24, Z = class extends O(l(B)) {
614
634
  @pointercancel=${this._onGrowPointerEnd}
615
635
  @lostpointercapture=${this._onGrowPointerEnd}
616
636
  ></div>
617
- ` : U}
637
+ ` : G}
618
638
  </div>
619
639
  `;
620
640
  }
621
641
  };
622
- s([W({ reflect: !0 })], Z.prototype, "variant", void 0), s([W()], Z.prototype, "heading", void 0), s([W({
642
+ s([K({ reflect: !0 })], $.prototype, "variant", void 0), s([K()], $.prototype, "heading", void 0), s([K({
623
643
  type: Boolean,
624
644
  reflect: !0
625
- })], Z.prototype, "active", void 0), s([W({
645
+ })], $.prototype, "active", void 0), s([K({
626
646
  type: Boolean,
627
647
  reflect: !0
628
- })], Z.prototype, "closable", void 0), s([W({
648
+ })], $.prototype, "closable", void 0), s([K({
629
649
  type: Boolean,
630
650
  reflect: !0
631
- })], Z.prototype, "zoomable", void 0), s([W({
651
+ })], $.prototype, "zoomable", void 0), s([K({
632
652
  type: Boolean,
633
653
  reflect: !0
634
- })], Z.prototype, "movable", void 0), s([W({
654
+ })], $.prototype, "movable", void 0), s([K({
635
655
  type: Boolean,
636
656
  reflect: !0,
637
657
  attribute: "outline-drag"
638
- })], Z.prototype, "outlineDrag", void 0), s([W({
658
+ })], $.prototype, "outlineDrag", void 0), s([K({
639
659
  type: Boolean,
640
660
  reflect: !0
641
- })], Z.prototype, "resizable", void 0), s([W({
661
+ })], $.prototype, "resizable", void 0), s([K({
642
662
  type: Number,
643
663
  attribute: "min-width"
644
- })], Z.prototype, "minWidth", void 0), s([W({
664
+ })], $.prototype, "minWidth", void 0), s([K({
645
665
  type: Number,
646
666
  attribute: "min-height"
647
- })], Z.prototype, "minHeight", void 0), s([W({
667
+ })], $.prototype, "minHeight", void 0), s([K({
648
668
  type: Number,
649
669
  attribute: "max-width"
650
- })], Z.prototype, "maxWidth", void 0), s([W({
670
+ })], $.prototype, "maxWidth", void 0), s([K({
651
671
  type: Number,
652
672
  attribute: "max-height"
653
- })], Z.prototype, "maxHeight", void 0), s([W({ reflect: !0 })], Z.prototype, "scrollbars", void 0), s([W({
673
+ })], $.prototype, "maxHeight", void 0), s([K({ reflect: !0 })], $.prototype, "scrollbars", void 0), s([K({
654
674
  type: Number,
655
675
  attribute: "header-height"
656
- })], Z.prototype, "headerHeight", void 0), s([K()], Z.prototype, "_hasHeader", void 0), s([K()], Z.prototype, "_hasStatus", void 0), s([G(".body")], Z.prototype, "body", void 0), s([G("vf-scroll-area")], Z.prototype, "scrollArea", void 0), Z = s([t("vf-window")], Z);
676
+ })], $.prototype, "headerHeight", void 0), s([J()], $.prototype, "_hasHeader", void 0), s([J()], $.prototype, "_hasStatus", void 0), s([q(".body")], $.prototype, "body", void 0), s([q("vf-scroll-area")], $.prototype, "scrollArea", void 0), $ = s([t("vf-window")], $);
657
677
  //#endregion
658
- export { Z as VfWindow };
678
+ export { $ as VfWindow };
package/dist/index.d.ts CHANGED
@@ -92,7 +92,7 @@ export { CURSOR_ARROW, CURSOR_I_BEAM, CURSOR_CROSSHAIR, CURSOR_WAIT, } from './c
92
92
  * `static styles` to inherit the kit's type, panel frame, window chrome, focus
93
93
  * ring, field well and System 7 scroll-rail skin.
94
94
  */
95
- export { vfBase, vfBodyDecls, vfDisplay, vfDisplayDecls, vfStaticText, vfPanel, vfChromeFrame, vfModalFrame, vfRule, vfTitleBar, vfWindowWidgets, vfHardShadowDecls, vfStripes, vfDots, vfFocus, vfFocusRing, vfFocusUnderline, vfToggle, vfField, vfScrollRail, vfTileSize, vfTileMaskSize, tileImage, tileRaster, tileRects, tileSpan, TILE_LATTICE, } from './styles/base.js';
95
+ export { vfBase, vfBodyDecls, vfDisplay, vfDisplayDecls, vfStaticText, vfPanel, vfChromeFrame, vfModalFrame, vfRule, vfTitleBar, vfWindowWidgets, vfHardShadow, vfHardShadowDecls, vfStripes, vfDots, vfFocus, vfFocusRing, vfFocusUnderline, vfToggle, vfField, vfScrollRail, vfTileSize, vfTileMaskSize, tileImage, tileRaster, tileRects, tileSpan, TILE_LATTICE, } from './styles/base.js';
96
96
  export type { TileRect } from './styles/base.js';
97
97
  /**
98
98
  * The 1px rule's attribute grammar (`vf-container rule="top bottom"`): the
@@ -101,6 +101,15 @@ export type { TileRect } from './styles/base.js';
101
101
  */
102
102
  export { RULE_EDGES, parseRule, ruleClasses } from './styles/base.js';
103
103
  export type { RuleEdge } from './styles/base.js';
104
+ /**
105
+ * A 1-bit stroke for a box of your own: `vfStrokeDecls()` draws the line as
106
+ * padding plus an inset shadow, the way every kit frame is drawn, because a
107
+ * CSS `border` of `calc(var(--vf-scale, 1) * 1px)` renders thin under Safari's
108
+ * page zoom. `vfStrokeInset()` offsets a child placed against the box, and
109
+ * `vfStrokeShadow()` restates the painted width alone.
110
+ */
111
+ export { vfStrokeDecls, vfStrokeInset, vfStrokeShadow } from './styles/base.js';
112
+ export type { VfStrokeOptions } from './styles/base.js';
104
113
  /**
105
114
  * The exact tiled fill (src/tile-grid.ts): a surface's own art as a CSS
106
115
  * repeat of one tile drawn at the display's resolution — `repeatTile()` for
package/dist/index.js CHANGED
@@ -14,62 +14,63 @@ import { TILE_LATTICE as R, tileImage as z, tileRaster as B, tileRects as V, til
14
14
  import { REPEAT_TILE as G, RepeatTileController as K, devicePxAt as q, patternOverride as J, repeatTile as Y, tileGrid as X, vfRepeatTileSize as Z, vfTileGrid as Q } from "./tile-grid.js";
15
15
  import { PATTERNS as $, PATTERN_NAMES as ee, PATTERN_SIZE as te, parsePattern as ne, patternHex as re, patternMotif as ie, patternRects as ae } from "./patterns.js";
16
16
  import { vfDots as oe, vfStripes as se } from "./styles/recipes/pattern.js";
17
- import { vfHardShadowDecls as ce } from "./styles/recipes/shadow.js";
18
- import { vfChromeFrame as le, vfModalFrame as ue, vfPanel as de } from "./styles/recipes/surface.js";
19
- import { RULE_EDGES as fe, parseRule as pe, ruleClasses as me, vfRule as he } from "./styles/recipes/rule.js";
20
- import { vfTitleBar as ge, vfWindowWidgets as _e } from "./styles/recipes/title-bar.js";
21
- import { vfFocus as ve, vfFocusRing as ye, vfFocusUnderline as be } from "./styles/recipes/focus.js";
22
- import { vfToggle as xe } from "./styles/recipes/toggle.js";
23
- import { vfField as Se } from "./styles/recipes/field.js";
24
- import { vfScrollRail as Ce } from "./styles/recipes/scroll-rail.js";
25
- import { PatternFillController as we, vfPatternFill as Te } from "./pattern-fill.js";
26
- import { GridSnapController as Ee, requestGridSnap as De } from "./grid-snap.js";
27
- import { DocumentListenersController as Oe } from "./document-listeners.js";
28
- import { BUTTON_FACE as ke, BUTTON_FRAME as Ae, RING_FRAME as je, RING_HOLE as Me, RING_INSET as Ne, SCREEN_CORNER as Pe, steppedCornerClip as Fe, steppedRectClip as Ie, steppedRingClip as Le } from "./pixel-frame.js";
29
- import { VfDesktop as Re } from "./components/vf-desktop.js";
30
- import { VfSized as ze } from "./size.js";
31
- import { DragController as Be } from "./drag.js";
32
- import { BLINK_FLIPS as Ve, BLINK_INTERVAL_MS as He, DRAG_SLOP_COARSE_PX as Ue, DRAG_SLOP_PX as We, PRESS_HOLD_MS as Ge, RENAME_DELAY_MS as Ke, TAP_PAIR_MS as qe, TAP_PAIR_SLOP_PX as Je, WALK_BEAT_MS as Ye, WALK_STEP_MS as Xe, WALK_STEP_PX as Ze, WINDOW_RECTS_VISIBLE as Qe, WINDOW_RECT_RATIO as $e, WINDOW_RECT_STEPS as et, WINDOW_RECT_STEP_MS as tt, dragSlop as nt, prefersReducedMotion as rt, runOutlineTravel as it, runSelectionBlink as at, windowRectFraction as ot } from "./motion.js";
33
- import { ScrollStateController as st } from "./scroll-state.js";
34
- import { CARET_DOWN as ct, CARET_DOWN_SMALL as lt, CHECKBOX_X as ut, CHECKMARK as dt, RADIO_DOT as ft, RADIO_FACE as pt, RADIO_RING as mt, RADIO_RING_PRESSED as ht, SLIDER_THUMB as gt, SLIDER_THUMB_FACE as _t, STEPPER as vt, STEPPER_DOWN_FILL as yt, STEPPER_UP_FILL as bt, glyphSvg as xt } from "./glyphs.js";
35
- import { ScrollRailController as St, renderScrollRail as Ct } from "./scroll-rail.js";
36
- import { VfScrollArea as wt } from "./components/vf-scroll-area.js";
37
- import { VfWindow as Tt } from "./components/vf-window.js";
38
- import { VfModalDialog as Et, modalDialogStyles as Dt } from "./modal-dialog.js";
39
- import { VfDialog as Ot } from "./components/vf-dialog.js";
40
- import { VfSeparator as kt } from "./components/vf-separator.js";
41
- import { VfFormControl as At } from "./form-control.js";
42
- import { VfButton as jt } from "./components/vf-button.js";
43
- import { VfButtonGroup as Mt } from "./components/vf-button-group.js";
44
- import { VfSwatch as Nt } from "./components/vf-swatch.js";
45
- import { VfToggleControl as Pt } from "./toggle-control.js";
46
- import { VfCheckbox as Ft } from "./components/vf-checkbox.js";
47
- import { VfRadio as It } from "./components/vf-radio.js";
48
- import { VfRadioGroup as Lt } from "./components/vf-radio-group.js";
49
- import { FocusRuleController as Rt, focusModality as zt, trackFocusModality as Bt } from "./focus-modality.js";
50
- import { VfTextControlBase as Vt } from "./text-control.js";
51
- import { VfTextField as Ht } from "./components/vf-text-field.js";
52
- import { VfTextArea as Ut } from "./components/vf-text-area.js";
53
- import { VfNumberField as Wt } from "./components/vf-number-field.js";
54
- import { VfOption as Gt } from "./components/vf-option.js";
55
- import { VfSelect as Kt } from "./components/vf-select.js";
56
- import { TrackWidthController as qt } from "./track-width.js";
57
- import { VfProgressBar as Jt } from "./components/vf-progress-bar.js";
58
- import { VfSlider as Yt } from "./components/vf-slider.js";
59
- import { VfLabel as Xt } from "./components/vf-label.js";
60
- import { VfParagraph as Zt } from "./components/vf-paragraph.js";
61
- import { VfImg as Qt } from "./components/vf-img.js";
62
- import { VfIcon as $t } from "./components/vf-icon.js";
63
- import { VfIconField as en } from "./components/vf-icon-field.js";
64
- import { VfMenuBar as tn } from "./components/vf-menu-bar.js";
65
- import { VfMenu as nn } from "./components/vf-menu.js";
66
- import { VfMenuItem as rn } from "./components/vf-menu-item.js";
67
- import { VfList as an } from "./components/vf-list.js";
68
- import { VfListItem as on } from "./components/vf-list-item.js";
69
- import { VfFieldset as sn } from "./components/vf-fieldset.js";
70
- import { VfGrid as cn } from "./components/vf-grid.js";
71
- import { VfStack as ln } from "./components/vf-stack.js";
72
- import { VfContainer as un } from "./components/vf-container.js";
73
- import { CURSOR_ARROW as dn, CURSOR_CROSSHAIR as fn, CURSOR_I_BEAM as pn, CURSOR_WAIT as mn } from "./cursor-art.js";
74
- import { applyCursor as hn } from "./cursor.js";
75
- export { Ve as BLINK_FLIPS, He as BLINK_INTERVAL_MS, ke as BUTTON_FACE, Ae as BUTTON_FRAME, ct as CARET_DOWN, lt as CARET_DOWN_SMALL, ut as CHECKBOX_X, dt as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, dn as CURSOR_ARROW, fn as CURSOR_CROSSHAIR, pn as CURSOR_I_BEAM, mn as CURSOR_WAIT, Ue as DRAG_SLOP_COARSE_PX, We as DRAG_SLOP_PX, Oe as DocumentListenersController, Be as DragController, Rt as FocusRuleController, Ee as GridSnapController, $ as PATTERNS, ee as PATTERN_NAMES, te as PATTERN_SIZE, D as PIXEL_GRID_METRICS, Ge as PRESS_HOLD_MS, we as PatternFillController, T as PlacementController, ft as RADIO_DOT, pt as RADIO_FACE, mt as RADIO_RING, ht as RADIO_RING_PRESSED, Ke as RENAME_DELAY_MS, G as REPEAT_TILE, je as RING_FRAME, Me as RING_HOLE, Ne as RING_INSET, fe as RULE_EDGES, K as RepeatTileController, Pe as SCREEN_CORNER, gt as SLIDER_THUMB, _t as SLIDER_THUMB_FACE, vt as STEPPER, yt as STEPPER_DOWN_FILL, bt as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, St as ScrollRailController, st as ScrollStateController, qe as TAP_PAIR_MS, Je as TAP_PAIR_SLOP_PX, R as TILE_LATTICE, qt as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, jt as VfButton, Mt as VfButtonGroup, Ft as VfCheckbox, un as VfContainer, Re as VfDesktop, Ot as VfDialog, sn as VfFieldset, At as VfFormControl, cn as VfGrid, $t as VfIcon, en as VfIconField, Qt as VfImg, Xt as VfLabel, an as VfList, on as VfListItem, nn as VfMenu, tn as VfMenuBar, rn as VfMenuItem, Et as VfModalDialog, Wt as VfNumberField, Gt as VfOption, Zt as VfParagraph, E as VfPositioned, Jt as VfProgressBar, It as VfRadio, Lt as VfRadioGroup, wt as VfScrollArea, Kt as VfSelect, kt as VfSeparator, ze as VfSized, Yt as VfSlider, ln as VfStack, Nt as VfSwatch, Ut as VfTextArea, Vt as VfTextControlBase, Ht as VfTextField, Pt as VfToggleControl, Tt as VfWindow, Ye as WALK_BEAT_MS, Xe as WALK_STEP_MS, Ze as WALK_STEP_PX, Qe as WINDOW_RECTS_VISIBLE, $e as WINDOW_RECT_RATIO, et as WINDOW_RECT_STEPS, tt as WINDOW_RECT_STEP_MS, hn as applyCursor, f as applyScale, t as defineElement, q as devicePxAt, o as devicePxPerSystemPx, nt as dragSlop, p as effectiveScale, e as emit, zt as focusModality, m as getScale, s as getZoom, xt as glyphSvg, Dt as modalDialogStyles, h as onScaleChange, c as onZoomChange, ne as parsePattern, pe as parseRule, re as patternHex, ie as patternMotif, J as patternOverride, ae as patternRects, rt as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, Ct as renderScrollRail, Y as repeatTile, De as requestGridSnap, l as resetZoomBaseline, me as ruleClasses, it as runOutlineTravel, at as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, Fe as steppedCornerClip, Ie as steppedRectClip, Le as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, X as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, Bt as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, le as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, oe as vfDots, n as vfElement, Se as vfField, ve as vfFocus, ye as vfFocusRing, be as vfFocusUnderline, ce as vfHardShadowDecls, ue as vfModalFrame, de as vfPanel, Te as vfPatternFill, Z as vfRepeatTileSize, he as vfRule, Ce as vfScrollRail, L as vfStaticText, se as vfStripes, Q as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, ge as vfTitleBar, xe as vfToggle, _e as vfWindowWidgets, ot as windowRectFraction };
17
+ import { vfHardShadow as ce, vfHardShadowDecls as le } from "./styles/recipes/shadow.js";
18
+ import { vfStrokeDecls as ue, vfStrokeInset as de, vfStrokeShadow as fe } from "./styles/recipes/stroke.js";
19
+ import { vfChromeFrame as pe, vfModalFrame as me, vfPanel as he } from "./styles/recipes/surface.js";
20
+ import { RULE_EDGES as ge, parseRule as _e, ruleClasses as ve, vfRule as ye } from "./styles/recipes/rule.js";
21
+ import { vfTitleBar as be, vfWindowWidgets as xe } from "./styles/recipes/title-bar.js";
22
+ import { vfFocus as Se, vfFocusRing as Ce, vfFocusUnderline as we } from "./styles/recipes/focus.js";
23
+ import { vfToggle as Te } from "./styles/recipes/toggle.js";
24
+ import { vfField as Ee } from "./styles/recipes/field.js";
25
+ import { vfScrollRail as De } from "./styles/recipes/scroll-rail.js";
26
+ import { PatternFillController as Oe, vfPatternFill as ke } from "./pattern-fill.js";
27
+ import { GridSnapController as Ae, requestGridSnap as je } from "./grid-snap.js";
28
+ import { DocumentListenersController as Me } from "./document-listeners.js";
29
+ import { BUTTON_FACE as Ne, BUTTON_FRAME as Pe, RING_FRAME as Fe, RING_HOLE as Ie, RING_INSET as Le, SCREEN_CORNER as Re, steppedCornerClip as ze, steppedRectClip as Be, steppedRingClip as Ve } from "./pixel-frame.js";
30
+ import { VfDesktop as He } from "./components/vf-desktop.js";
31
+ import { VfSized as Ue } from "./size.js";
32
+ import { DragController as We } from "./drag.js";
33
+ import { BLINK_FLIPS as Ge, BLINK_INTERVAL_MS as Ke, DRAG_SLOP_COARSE_PX as qe, DRAG_SLOP_PX as Je, PRESS_HOLD_MS as Ye, RENAME_DELAY_MS as Xe, TAP_PAIR_MS as Ze, TAP_PAIR_SLOP_PX as Qe, WALK_BEAT_MS as $e, WALK_STEP_MS as et, WALK_STEP_PX as tt, WINDOW_RECTS_VISIBLE as nt, WINDOW_RECT_RATIO as rt, WINDOW_RECT_STEPS as it, WINDOW_RECT_STEP_MS as at, dragSlop as ot, prefersReducedMotion as st, runOutlineTravel as ct, runSelectionBlink as lt, windowRectFraction as ut } from "./motion.js";
34
+ import { ScrollStateController as dt } from "./scroll-state.js";
35
+ import { CARET_DOWN as ft, CARET_DOWN_SMALL as pt, CHECKBOX_X as mt, CHECKMARK as ht, RADIO_DOT as gt, RADIO_FACE as _t, RADIO_RING as vt, RADIO_RING_PRESSED as yt, SLIDER_THUMB as bt, SLIDER_THUMB_FACE as xt, STEPPER as St, STEPPER_DOWN_FILL as Ct, STEPPER_UP_FILL as wt, glyphSvg as Tt } from "./glyphs.js";
36
+ import { ScrollRailController as Et, renderScrollRail as Dt } from "./scroll-rail.js";
37
+ import { VfScrollArea as Ot } from "./components/vf-scroll-area.js";
38
+ import { VfWindow as kt } from "./components/vf-window.js";
39
+ import { VfModalDialog as At, modalDialogStyles as jt } from "./modal-dialog.js";
40
+ import { VfDialog as Mt } from "./components/vf-dialog.js";
41
+ import { VfSeparator as Nt } from "./components/vf-separator.js";
42
+ import { VfFormControl as Pt } from "./form-control.js";
43
+ import { VfButton as Ft } from "./components/vf-button.js";
44
+ import { VfButtonGroup as It } from "./components/vf-button-group.js";
45
+ import { VfSwatch as Lt } from "./components/vf-swatch.js";
46
+ import { VfToggleControl as Rt } from "./toggle-control.js";
47
+ import { VfCheckbox as zt } from "./components/vf-checkbox.js";
48
+ import { VfRadio as Bt } from "./components/vf-radio.js";
49
+ import { VfRadioGroup as Vt } from "./components/vf-radio-group.js";
50
+ import { FocusRuleController as Ht, focusModality as Ut, trackFocusModality as Wt } from "./focus-modality.js";
51
+ import { VfTextControlBase as Gt } from "./text-control.js";
52
+ import { VfTextField as Kt } from "./components/vf-text-field.js";
53
+ import { VfTextArea as qt } from "./components/vf-text-area.js";
54
+ import { VfNumberField as Jt } from "./components/vf-number-field.js";
55
+ import { VfOption as Yt } from "./components/vf-option.js";
56
+ import { VfSelect as Xt } from "./components/vf-select.js";
57
+ import { TrackWidthController as Zt } from "./track-width.js";
58
+ import { VfProgressBar as Qt } from "./components/vf-progress-bar.js";
59
+ import { VfSlider as $t } from "./components/vf-slider.js";
60
+ import { VfLabel as en } from "./components/vf-label.js";
61
+ import { VfParagraph as tn } from "./components/vf-paragraph.js";
62
+ import { VfImg as nn } from "./components/vf-img.js";
63
+ import { VfIcon as rn } from "./components/vf-icon.js";
64
+ import { VfIconField as an } from "./components/vf-icon-field.js";
65
+ import { VfMenuBar as on } from "./components/vf-menu-bar.js";
66
+ import { VfMenu as sn } from "./components/vf-menu.js";
67
+ import { VfMenuItem as cn } from "./components/vf-menu-item.js";
68
+ import { VfList as ln } from "./components/vf-list.js";
69
+ import { VfListItem as un } from "./components/vf-list-item.js";
70
+ import { VfFieldset as dn } from "./components/vf-fieldset.js";
71
+ import { VfGrid as fn } from "./components/vf-grid.js";
72
+ import { VfStack as pn } from "./components/vf-stack.js";
73
+ import { VfContainer as mn } from "./components/vf-container.js";
74
+ import { CURSOR_ARROW as hn, CURSOR_CROSSHAIR as gn, CURSOR_I_BEAM as _n, CURSOR_WAIT as vn } from "./cursor-art.js";
75
+ import { applyCursor as yn } from "./cursor.js";
76
+ export { Ge as BLINK_FLIPS, Ke as BLINK_INTERVAL_MS, Ne as BUTTON_FACE, Pe as BUTTON_FRAME, ft as CARET_DOWN, pt as CARET_DOWN_SMALL, mt as CHECKBOX_X, ht as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, hn as CURSOR_ARROW, gn as CURSOR_CROSSHAIR, _n as CURSOR_I_BEAM, vn as CURSOR_WAIT, qe as DRAG_SLOP_COARSE_PX, Je as DRAG_SLOP_PX, Me as DocumentListenersController, We as DragController, Ht as FocusRuleController, Ae as GridSnapController, $ as PATTERNS, ee as PATTERN_NAMES, te as PATTERN_SIZE, D as PIXEL_GRID_METRICS, Ye as PRESS_HOLD_MS, Oe as PatternFillController, T as PlacementController, gt as RADIO_DOT, _t as RADIO_FACE, vt as RADIO_RING, yt as RADIO_RING_PRESSED, Xe as RENAME_DELAY_MS, G as REPEAT_TILE, Fe as RING_FRAME, Ie as RING_HOLE, Le as RING_INSET, ge as RULE_EDGES, K as RepeatTileController, Re as SCREEN_CORNER, bt as SLIDER_THUMB, xt as SLIDER_THUMB_FACE, St as STEPPER, Ct as STEPPER_DOWN_FILL, wt as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, Et as ScrollRailController, dt as ScrollStateController, Ze as TAP_PAIR_MS, Qe as TAP_PAIR_SLOP_PX, R as TILE_LATTICE, Zt as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, Ft as VfButton, It as VfButtonGroup, zt as VfCheckbox, mn as VfContainer, He as VfDesktop, Mt as VfDialog, dn as VfFieldset, Pt as VfFormControl, fn as VfGrid, rn as VfIcon, an as VfIconField, nn as VfImg, en as VfLabel, ln as VfList, un as VfListItem, sn as VfMenu, on as VfMenuBar, cn as VfMenuItem, At as VfModalDialog, Jt as VfNumberField, Yt as VfOption, tn as VfParagraph, E as VfPositioned, Qt as VfProgressBar, Bt as VfRadio, Vt as VfRadioGroup, Ot as VfScrollArea, Xt as VfSelect, Nt as VfSeparator, Ue as VfSized, $t as VfSlider, pn as VfStack, Lt as VfSwatch, qt as VfTextArea, Gt as VfTextControlBase, Kt as VfTextField, Rt as VfToggleControl, kt as VfWindow, $e as WALK_BEAT_MS, et as WALK_STEP_MS, tt as WALK_STEP_PX, nt as WINDOW_RECTS_VISIBLE, rt as WINDOW_RECT_RATIO, it as WINDOW_RECT_STEPS, at as WINDOW_RECT_STEP_MS, yn as applyCursor, f as applyScale, t as defineElement, q as devicePxAt, o as devicePxPerSystemPx, ot as dragSlop, p as effectiveScale, e as emit, Ut as focusModality, m as getScale, s as getZoom, Tt as glyphSvg, jt as modalDialogStyles, h as onScaleChange, c as onZoomChange, ne as parsePattern, _e as parseRule, re as patternHex, ie as patternMotif, J as patternOverride, ae as patternRects, st as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, Dt as renderScrollRail, Y as repeatTile, je as requestGridSnap, l as resetZoomBaseline, ve as ruleClasses, ct as runOutlineTravel, lt as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, ze as steppedCornerClip, Be as steppedRectClip, Ve as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, X as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, Wt as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, pe as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, oe as vfDots, n as vfElement, Ee as vfField, Se as vfFocus, Ce as vfFocusRing, we as vfFocusUnderline, ce as vfHardShadow, le as vfHardShadowDecls, me as vfModalFrame, he as vfPanel, ke as vfPatternFill, Z as vfRepeatTileSize, ye as vfRule, De as vfScrollRail, L as vfStaticText, se as vfStripes, ue as vfStrokeDecls, de as vfStrokeInset, fe as vfStrokeShadow, Q as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, be as vfTitleBar, Te as vfToggle, xe as vfWindowWidgets, ut as windowRectFraction };
@@ -27,7 +27,9 @@ export { vfDisplay, vfDisplayDecls } from './recipes/display-face.js';
27
27
  export { vfBase } from './recipes/host.js';
28
28
  export { vfStaticText } from './recipes/static-text.js';
29
29
  export { vfDots, vfStripes } from './recipes/pattern.js';
30
- export { vfHardShadowDecls } from './recipes/shadow.js';
30
+ export { vfHardShadow, vfHardShadowDecls } from './recipes/shadow.js';
31
+ export { vfStrokeDecls, vfStrokeInset, vfStrokeShadow } from './recipes/stroke.js';
32
+ export type { VfStrokeOptions } from './recipes/stroke.js';
31
33
  export { vfChromeFrame, vfModalFrame, vfPanel } from './recipes/surface.js';
32
34
  export { RULE_EDGES, parseRule, ruleClasses, vfRule } from './recipes/rule.js';
33
35
  export type { RuleEdge } from './recipes/rule.js';
@@ -1,13 +1,17 @@
1
1
  /**
2
2
  * The System 7 editable-field skin (SPEC §1/§5): a white well with a 1px black
3
- * border, no corner radius, Chicago-style display type, and the kit's dashed
3
+ * frame, no corner radius, Chicago-style display type, and the kit's dashed
4
4
  * keyboard-focus rule under the well (no dotted ring). Add the `vf-field`
5
5
  * class to the inner native `<input>`/`<textarea>` and wrap it in a
6
- * `.vf-field-well` element; the host supplies layout (width, height, padding)
7
- * around it, and `VfTextControlBase` supplies the `.vf-focus-rule` class that
8
- * turns the rule on. Shared by vf-text-field, vf-text-area and
9
- * vf-number-field so the well, focus and disabled treatment stay identical
10
- * across all three.
6
+ * `.vf-field-well` element; the host supplies layout (width, height) around
7
+ * it, and `VfTextControlBase` supplies the `.vf-focus-rule` class that turns
8
+ * the rule on. Shared by vf-text-field, vf-text-area and vf-number-field so
9
+ * the well, focus and disabled treatment stay identical across all three.
10
+ *
11
+ * The frame is a stroke ({@link vfStrokeDecls}), so the recipe owns the
12
+ * input's padding and box-shadow: a host that insets the text restates the
13
+ * padding with `vfStrokeInset` (`padding: ${vfStrokeInset(0)}
14
+ * ${vfStrokeInset(6)}`) in a rule that outranks `.vf-field`.
11
15
  *
12
16
  * Why the wrapper: the rule is a pseudo-element, and a replaced element
13
17
  * generates none — neither `<input>` nor `<textarea>` can draw its own
@@ -1,11 +1,12 @@
1
1
  import { vfDisplayDecls as e } from "./display-face.js";
2
- import { vfFocusUnderline as t } from "./focus.js";
3
- import { css as n } from "lit";
2
+ import { vfStrokeDecls as t } from "./stroke.js";
3
+ import { vfFocusUnderline as n } from "./focus.js";
4
+ import { css as r } from "lit";
4
5
  //#region src/styles/recipes/field.ts
5
- var r = n`
6
+ var i = r`
6
7
  .vf-field {
7
8
  background: var(--vf-white, #fff);
8
- border: calc(var(--vf-scale, 1) * 1px) solid var(--vf-black, #000);
9
+ ${t()}
9
10
  border-radius: 0;
10
11
  /* Editable text is set in the Chicago-style display face. */
11
12
  ${e}
@@ -36,7 +37,7 @@ var r = n`
36
37
  VfTextControlBase adds .vf-focus-rule for a keyboard focus only. */
37
38
  .vf-field-well.vf-focus-rule::after {
38
39
  --vf-focus-underline-offset: -2px;
39
- ${t}
40
+ ${n}
40
41
  }
41
42
  /* Its own token, deliberately not --vf-disabled: the disabled rule below is
42
43
  an inactive control and exempt from contrast requirements, but a
@@ -50,7 +51,7 @@ var r = n`
50
51
  font-weight: inherit;
51
52
  opacity: 1;
52
53
  }
53
- /* Disabled: the text dims to gray; the solid black box border stays. The
54
+ /* Disabled: the text dims to gray; the solid black frame stays. The
54
55
  cursor returns to the arrow — a well that can't take input isn't text. */
55
56
  .vf-field:disabled {
56
57
  color: var(--vf-disabled, #c0c0c0);
@@ -65,4 +66,4 @@ var r = n`
65
66
  }
66
67
  `;
67
68
  //#endregion
68
- export { r as vfField };
69
+ export { i as vfField };