vintage-frames 0.6.2 → 0.7.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.
@@ -29,8 +29,15 @@ declare const VfScrollArea_base: (new (...args: any[]) => import("../position.js
29
29
  * The scrolled plane sizes to its content — never narrower than the
30
30
  * viewport, as wide as content that cannot wrap — so the rails follow a row
31
31
  * that grows sideways the way they follow copy that grows down, and a
32
- * `slotchange` re-measures. {@link measure} covers a scroll range that
33
- * changes with no box changing (a placed child moved through `top`/`left`).
32
+ * `slotchange` re-measures. A placed child moved through `top`/`left` is
33
+ * heard too: every such write is announced as `vf-placement-change`
34
+ * (src/position.ts), and the area re-measures on it — a drop, an arrow
35
+ * nudge, a page's own `icon.left = …`, with no code on the page. {@link
36
+ * measure} covers a scroll range that changes with no box and no placement
37
+ * changing (a transform).
38
+ *
39
+ * {@link placementAt} converts a viewport point into the plane's own
40
+ * placement coordinates, for a drop that lands in this area from elsewhere.
34
41
  *
35
42
  * @slot - Scrollable content.
36
43
  * @csspart viewport - The inner scrolling container.
@@ -39,6 +46,7 @@ declare const VfScrollArea_base: (new (...args: any[]) => import("../position.js
39
46
  * dot-dither (white)
40
47
  */
41
48
  export declare class VfScrollArea extends VfScrollArea_base {
49
+ #private;
42
50
  private readonly scale;
43
51
  /** Device-pixel grid snapping; see src/grid-snap.ts. */
44
52
  private readonly gridSnap;
@@ -75,6 +83,18 @@ export declare class VfScrollArea extends VfScrollArea_base {
75
83
  private readonly rail;
76
84
  /** Whether the content actually overflows the viewport (either axis). */
77
85
  private _scrollable;
86
+ constructor();
87
+ /**
88
+ * A viewport point (CSS px) as a placement on the scrolled plane —
89
+ * `{ left, top }` in whole system px on the placement lattice, the pair a
90
+ * child dropped here is written with. The plane travels with the scroll,
91
+ * so its box already carries the scroll offset and the border-floor
92
+ * padding; nothing is left for the caller to add.
93
+ */
94
+ placementAt(clientX: number, clientY: number): {
95
+ left: number;
96
+ top: number;
97
+ };
78
98
  /**
79
99
  * Moves keyboard focus to the scrolling viewport — the focusable element
80
100
  * lives inside the shadow root, where the platform's `focus()` can't reach
@@ -84,10 +104,9 @@ export declare class VfScrollArea extends VfScrollArea_base {
84
104
  focus(options?: FocusOptions): void;
85
105
  /**
86
106
  * Re-measure overflow and re-sync the rails. The area tracks its content's
87
- * box and its slot by itself; call this for a scroll range that changes
88
- * with no box changing anywhere — a placed child moved through
89
- * `top`/`left`, a transform — the way the kit's own fields re-measure on
90
- * input.
107
+ * box, its slot and every placement write by itself; call this for a
108
+ * scroll range that changes with none of those — a transform — the way the
109
+ * kit's own fields re-measure on input.
91
110
  */
92
111
  measure(): void;
93
112
  /** Content added or removed under the fixed box — re-measure. */
@@ -1,24 +1,30 @@
1
1
  import { vfElement as e } from "../define.js";
2
2
  import { ScaleController as t } from "../scale.js";
3
3
  import n from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
- import { VfPositioned as r } from "../position.js";
5
- import { vfBase as i } from "../styles/recipes/host.js";
6
- import { vfFocusRing as a } from "../styles/recipes/focus.js";
7
- import { vfScrollRail as o } from "../styles/recipes/scroll-rail.js";
8
- import { GridSnapController as s } from "../grid-snap.js";
9
- import { ScrollStateController as c } from "../scroll-state.js";
10
- import { ScrollRailController as l, renderScrollRail as u } from "../scroll-rail.js";
11
- import { LitElement as d, css as f, html as p, nothing as m } from "lit";
12
- import { property as h, query as g, state as _ } from "lit/decorators.js";
4
+ import { VfPositioned as r, placementIn as i } from "../position.js";
5
+ import { vfBase as a } from "../styles/recipes/host.js";
6
+ import { vfFocusRing as o } from "../styles/recipes/focus.js";
7
+ import { vfScrollRail as s } from "../styles/recipes/scroll-rail.js";
8
+ import { GridSnapController as c } from "../grid-snap.js";
9
+ import { ScrollStateController as l } from "../scroll-state.js";
10
+ import { ScrollRailController as u, renderScrollRail as d } from "../scroll-rail.js";
11
+ import { LitElement as f, css as p, html as m, nothing as h } from "lit";
12
+ import { property as g, query as _, state as v } from "lit/decorators.js";
13
13
  //#region src/components/vf-scroll-area.ts
14
- var v = class extends r(d) {
15
- constructor(...e) {
16
- super(...e), this.scale = new t(this), this.gridSnap = new s(this), this.axis = "vertical", this.corner = !1, this.label = "", this.scrollState = new c(this, () => this.viewport, () => this.content, (e) => {
14
+ var y = class extends r(f) {
15
+ constructor() {
16
+ super(), this.scale = new t(this), this.gridSnap = new c(this), this.axis = "vertical", this.corner = !1, this.label = "", this.scrollState = new l(this, () => this.viewport, () => this.content, (e) => {
17
17
  this._scrollable = e.x || e.y;
18
- }), this.rail = new l(this, {
18
+ }), this.rail = new u(this, {
19
19
  getScroll: () => this.viewport,
20
20
  getContent: () => this.content
21
- }), this._scrollable = !1;
21
+ }), this._scrollable = !1, this.#e = () => {
22
+ this.measure();
23
+ }, this.addEventListener("vf-placement-change", this.#e);
24
+ }
25
+ #e;
26
+ placementAt(e, t) {
27
+ return i(this.content ?? this, e, t, this);
22
28
  }
23
29
  focus(e) {
24
30
  this.viewport?.focus(e);
@@ -31,9 +37,9 @@ var v = class extends r(d) {
31
37
  }
32
38
  static {
33
39
  this.styles = [
34
- i,
35
- o,
36
- f`
40
+ a,
41
+ s,
42
+ p`
37
43
  :host {
38
44
  display: block;
39
45
  }
@@ -132,36 +138,36 @@ var v = class extends r(d) {
132
138
  /* Focusable so keyboard users can scroll; inset ring to stay in-box. */
133
139
  .viewport:focus-visible {
134
140
  --vf-focus-offset: -2px;
135
- ${a}
141
+ ${o}
136
142
  }
137
143
  `
138
144
  ];
139
145
  }
140
146
  render() {
141
147
  let e = this.axis !== "horizontal", t = this.axis === "horizontal" || this.axis === "both", n = e && t || this.corner;
142
- return p`
148
+ return m`
143
149
  <div class="box vf-snap">
144
150
  <div
145
151
  class="viewport vf-scroll"
146
152
  part="viewport"
147
- tabindex=${this._scrollable ? "0" : m}
148
- role=${this.label ? "region" : this._scrollable ? "group" : m}
149
- aria-label=${this.label || m}
153
+ tabindex=${this._scrollable ? "0" : h}
154
+ role=${this.label ? "region" : this._scrollable ? "group" : h}
155
+ aria-label=${this.label || h}
150
156
  >
151
157
  <div class="content">
152
158
  <slot @slotchange=${this._onSlotChange}></slot>
153
159
  </div>
154
160
  </div>
155
- ${e ? u(this.rail, "vertical") : m}
156
- ${t ? u(this.rail, "horizontal") : m}
157
- ${n ? p`<div class="vf-rail-corner" aria-hidden="true"></div>` : m}
161
+ ${e ? d(this.rail, "vertical") : h}
162
+ ${t ? d(this.rail, "horizontal") : h}
163
+ ${n ? m`<div class="vf-rail-corner" aria-hidden="true"></div>` : h}
158
164
  </div>
159
165
  `;
160
166
  }
161
167
  };
162
- n([h({ reflect: !0 })], v.prototype, "axis", void 0), n([h({
168
+ n([g({ reflect: !0 })], y.prototype, "axis", void 0), n([g({
163
169
  type: Boolean,
164
170
  reflect: !0
165
- })], 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);
171
+ })], y.prototype, "corner", void 0), n([g()], y.prototype, "label", void 0), n([_(".viewport")], y.prototype, "viewport", void 0), n([_(".content")], y.prototype, "content", void 0), n([v()], y.prototype, "_scrollable", void 0), y = n([e("vf-scroll-area")], y);
166
172
  //#endregion
167
- export { v as VfScrollArea };
173
+ export { y as VfScrollArea };
@@ -154,6 +154,10 @@ export declare class VfWindow extends VfWindow_base {
154
154
  private _hasHeader;
155
155
  /** Whether the `status` slot has assigned content (drives the strip). */
156
156
  private _hasStatus;
157
+ /** The content region — the placed-child anchor; exists from the first render. */
158
+ private readonly body;
159
+ /** The built-in edge scroll area, while `scrollbars` is set. */
160
+ private readonly scrollArea;
157
161
  /** Default-on display scaling (true 72dpi size); see src/scale.ts. */
158
162
  private readonly scale;
159
163
  /** Device-pixel grid snapping; see src/grid-snap.ts. */
@@ -191,6 +195,26 @@ export declare class VfWindow extends VfWindow_base {
191
195
  */
192
196
  private readonly _drag;
193
197
  private _resizeState;
198
+ /**
199
+ * A viewport point (CSS px) as a placement in the window's content region
200
+ * — `{ left, top }` in whole system px on the placement lattice, the pair a
201
+ * child dropped into this window is written with: the body's corner, or
202
+ * under `scrollbars` the scrolled plane, scroll offset included. The anchor
203
+ * sits in the shadow tree, which is why the conversion is a method here
204
+ * rather than the page's own `toSysExact` against a rect.
205
+ */
206
+ placementAt(clientX: number, clientY: number): {
207
+ left: number;
208
+ top: number;
209
+ };
210
+ /**
211
+ * Re-measure the built-in scroll area's overflow and re-sync its rails —
212
+ * a no-op without `scrollbars`. The area re-measures by itself on its
213
+ * content's box, its slot and every placement write; this is the escape
214
+ * hatch for a scroll range that changes with none of those, the way
215
+ * `vf-scroll-area.measure()` is.
216
+ */
217
+ measure(): void;
194
218
  /**
195
219
  * Say something the first time a window is opened without a width. The size
196
220
  * itself is written by VfSized's controller, from `width`/`height` — which
@@ -2,52 +2,52 @@ import { emit as e } from "../events.js";
2
2
  import { vfElement as t } from "../define.js";
3
3
  import { ScaleController as n, snapSys as r, sysLength as i, toSysExact as a } from "../scale.js";
4
4
  import o from "../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
5
- import { PlacementController as s, VfPositioned as c, warnMovableContract as l } from "../position.js";
6
- import { vfBase as u } from "../styles/recipes/host.js";
7
- import { DOT_MOTIF as d, DOT_RECTS as f, DOT_SPAN as p, vfDots as m, vfStripes as h } from "../styles/recipes/pattern.js";
8
- import { vfChromeFrame as g } from "../styles/recipes/surface.js";
9
- import { vfRule as _ } from "../styles/recipes/rule.js";
10
- import { vfTitleBar as v, vfWindowWidgets as y } from "../styles/recipes/title-bar.js";
11
- import { vfFocus as b } from "../styles/recipes/focus.js";
12
- import { TileRasterCache as x, patternOverride as S, tileGrid as C, vfTileGrid as w } from "../tile-grid.js";
13
- import { GridSnapController as T } from "../grid-snap.js";
14
- import { VfSized as E } from "../size.js";
15
- import { DragController as D } from "../drag.js";
16
- import { TitleCenterController as O, chromeTitleBar as k, closeBox as A, widgetLabel as j, zoomBox as M } from "../chrome.js";
5
+ import { PlacementController as s, VfPositioned as c, placementIn as l, warnMovableContract as u } from "../position.js";
6
+ import { vfBase as d } from "../styles/recipes/host.js";
7
+ import { DOT_MOTIF as f, DOT_RECTS as p, DOT_SPAN as m, vfDots as h, vfStripes as g } from "../styles/recipes/pattern.js";
8
+ import { vfChromeFrame as _ } from "../styles/recipes/surface.js";
9
+ import { vfRule as v } from "../styles/recipes/rule.js";
10
+ import { vfTitleBar as y, vfWindowWidgets as b } from "../styles/recipes/title-bar.js";
11
+ import { vfFocus as x } from "../styles/recipes/focus.js";
12
+ import { TileRasterCache as S, patternOverride as C, tileGrid as w, vfTileGrid as T } from "../tile-grid.js";
13
+ import { GridSnapController as E } from "../grid-snap.js";
14
+ import { VfSized as D } from "../size.js";
15
+ import { DragController as O } from "../drag.js";
16
+ import { TitleCenterController as k, chromeTitleBar as A, closeBox as j, widgetLabel as M, zoomBox as N } from "../chrome.js";
17
17
  import "./vf-scroll-area.js";
18
- import { LitElement as N, css as P, html as F, nothing as I } from "lit";
19
- import { property as L, state as R } from "lit/decorators.js";
18
+ import { LitElement as P, css as F, html as I, nothing as L } from "lit";
19
+ import { property as R, query as z, state as B } from "lit/decorators.js";
20
20
  //#region src/components/vf-window.ts
21
- var z = 80, B = 54;
22
- function V(e, t, n) {
21
+ var V = 80, H = 54;
22
+ function U(e, t, n) {
23
23
  let r = Math.max(t, e);
24
24
  return n == null ? r : Math.min(n, r);
25
25
  }
26
- var H = 24, U = 8, W = class extends E(c(N)) {
26
+ var W = 24, G = 8, K = class extends D(c(P)) {
27
27
  constructor(...e) {
28
- super(...e), this.heading = "", this.active = !0, this.closable = !0, this.zoomable = !1, this.movable = !1, this.resizable = !1, this._hasHeader = !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) => {
28
+ super(...e), this.heading = "", this.active = !0, this.closable = !0, this.zoomable = !1, this.movable = !1, this.resizable = !1, this._hasHeader = !1, this._hasStatus = !1, this.scale = new n(this), this.gridSnap = new E(this), this.titleCenter = new k(this), this._dotsPattern = "", this.#e = new S(), this.#t = (e, t, n) => {
29
29
  let r = a(this.offsetWidth, this);
30
30
  return {
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))
31
+ x: Math.min(Math.max(e, W - r), n.width - W),
32
+ y: Math.min(Math.max(t, 0), Math.max(0, n.height - W))
33
33
  };
34
- }, this._placement = new s(this, (e, t, n) => this.#t(e, t, n)), this._drag = new D(this, {
34
+ }, this._placement = new s(this, (e, t, n) => this.#t(e, t, n)), this._drag = new O(this, {
35
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()),
36
36
  onDrag: (e, t) => this._placement.moveTo(e, t)
37
37
  }), this._resizeState = null, this.#n = !1, this.#r = !1;
38
38
  }
39
39
  static {
40
40
  this.styles = [
41
- u,
42
- h,
43
- m,
44
- w,
45
- b,
41
+ d,
46
42
  g,
43
+ h,
44
+ T,
45
+ x,
47
46
  _,
48
47
  v,
49
48
  y,
50
- P`
49
+ b,
50
+ F`
51
51
  :host {
52
52
  display: block;
53
53
  position: relative;
@@ -312,23 +312,30 @@ var H = 24, U = 8, W = class extends E(c(N)) {
312
312
  }
313
313
  #e;
314
314
  willUpdate(e) {
315
- super.willUpdate(e), this.variant === "utility" && (this._dotsPattern = S(this, "--vf-dots-pattern"));
315
+ super.willUpdate(e), this.variant === "utility" && (this._dotsPattern = C(this, "--vf-dots-pattern"));
316
316
  }
317
317
  _dotsTexture() {
318
318
  if (this.width == null) return;
319
319
  let e = Math.max(1, this.width - 2);
320
- if (this._dotsPattern) return C({
321
- cols: Math.ceil(e / p),
320
+ if (this._dotsPattern) return w({
321
+ cols: Math.ceil(e / m),
322
322
  rows: 1,
323
- tile: p
323
+ tile: m
324
324
  });
325
- let t = Math.ceil((e + d) / p) * p, n = U + d;
326
- return F`<div
325
+ let t = Math.ceil((e + f) / m) * m, n = G + f;
326
+ return I`<div
327
327
  class="vf-tile-raster"
328
- style="width:${i(t)};height:${i(n)};background-image:${this.#e.for(d, d, f, t, n)}"
328
+ style="width:${i(t)};height:${i(n)};background-image:${this.#e.for(f, f, p, t, n)}"
329
329
  ></div>`;
330
330
  }
331
331
  #t;
332
+ placementAt(e, t) {
333
+ let n = this.scrollArea;
334
+ return n ? n.placementAt(e, t) : l(this.body ?? this, e, t, this);
335
+ }
336
+ measure() {
337
+ this.scrollArea?.measure();
338
+ }
332
339
  updated() {
333
340
  this.#a();
334
341
  let t = this._resizeState;
@@ -341,7 +348,7 @@ var H = 24, U = 8, W = class extends E(c(N)) {
341
348
  #n;
342
349
  #r;
343
350
  #i() {
344
- this.#r ||= l(this, `vf-window${this.heading ? ` ("${this.heading}")` : ""}`, "<vf-window movable top=\"30\" left=\"40\" width=\"240\" height=\"176\">");
351
+ this.#r ||= u(this, `vf-window${this.heading ? ` ("${this.heading}")` : ""}`, "<vf-window movable top=\"30\" left=\"40\" width=\"240\" height=\"176\">");
345
352
  }
346
353
  #a() {
347
354
  if (this.#n) return;
@@ -381,7 +388,7 @@ var H = 24, U = 8, W = class extends E(c(N)) {
381
388
  _onGrowPointerMove(e) {
382
389
  let t = this._resizeState;
383
390
  if (!t || e.pointerId !== t.pointerId) return;
384
- 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);
391
+ let n = U(r(t.baseWidth + a(e.clientX - t.startX, this), this), this.minWidth ?? V, this.maxWidth), i = U(r(t.baseHeight + a(e.clientY - t.startY, this), this), this.minHeight ?? H, this.maxHeight);
385
392
  (n !== this.width || i !== this.height) && (t.emitPending = !0, t.resized = !0), this.width = n, this.height = i;
386
393
  }
387
394
  _onGrowPointerEnd(t) {
@@ -396,42 +403,42 @@ var H = 24, U = 8, W = class extends E(c(N)) {
396
403
  });
397
404
  }
398
405
  render() {
399
- return F`
406
+ return I`
400
407
  <div
401
408
  class="vf-frame vf-snap"
402
409
  part="frame"
403
410
  role="group"
404
- aria-labelledby=${this.heading ? "title" : I}
411
+ aria-labelledby=${this.heading ? "title" : L}
405
412
  >
406
- ${k(this._drag, F`
407
- ${this.closable ? A(j("Close", this.heading), this._onCloseClick) : I}
413
+ ${A(this._drag, I`
414
+ ${this.closable ? j(M("Close", this.heading), this._onCloseClick) : L}
408
415
  <span class="vf-title" part="title" id="title">${this.heading}</span>
409
- ${this.zoomable ? M(j("Zoom", this.heading), this._onZoomClick) : I}
416
+ ${this.zoomable ? N(M("Zoom", this.heading), this._onZoomClick) : L}
410
417
  `, this.variant === "utility" ? "vf-dots" : "vf-stripes", this.variant === "utility" ? this._dotsTexture() : void 0)}
411
418
  <div
412
419
  class="header vf-rule-bottom ${this._hasHeader ? "" : "empty"}"
413
420
  part="header"
414
- style=${this.headerHeight == null ? I : `height:${i(this.headerHeight)}`}
421
+ style=${this.headerHeight == null ? L : `height:${i(this.headerHeight)}`}
415
422
  >
416
423
  <slot name="header" @slotchange=${this._onHeaderSlotChange}></slot>
417
424
  </div>
418
425
  <div class="body" part="body">
419
- ${this.scrollbars ? F`
426
+ ${this.scrollbars ? I`
420
427
  <vf-scroll-area
421
428
  class="edge-scroll"
422
429
  axis=${this.scrollbars}
423
430
  ?corner=${this.resizable && !this._hasStatus}
424
- label=${this.heading || I}
431
+ label=${this.heading || L}
425
432
  exportparts="viewport"
426
433
  >
427
434
  <slot></slot>
428
435
  </vf-scroll-area>
429
- ` : F`<slot></slot>`}
436
+ ` : I`<slot></slot>`}
430
437
  </div>
431
438
  <div class="status vf-rule-top ${this._hasStatus ? "" : "empty"}" part="status-bar">
432
439
  <slot name="status" @slotchange=${this._onStatusSlotChange}></slot>
433
440
  </div>
434
- ${this.resizable ? F`
441
+ ${this.resizable ? I`
435
442
  <div
436
443
  class="grow"
437
444
  part="grow-box"
@@ -441,41 +448,41 @@ var H = 24, U = 8, W = class extends E(c(N)) {
441
448
  @pointercancel=${this._onGrowPointerEnd}
442
449
  @lostpointercapture=${this._onGrowPointerEnd}
443
450
  ></div>
444
- ` : I}
451
+ ` : L}
445
452
  </div>
446
453
  `;
447
454
  }
448
455
  };
449
- o([L({ reflect: !0 })], W.prototype, "variant", void 0), o([L()], W.prototype, "heading", void 0), o([L({
456
+ o([R({ reflect: !0 })], K.prototype, "variant", void 0), o([R()], K.prototype, "heading", void 0), o([R({
450
457
  type: Boolean,
451
458
  reflect: !0
452
- })], W.prototype, "active", void 0), o([L({
459
+ })], K.prototype, "active", void 0), o([R({
453
460
  type: Boolean,
454
461
  reflect: !0
455
- })], W.prototype, "closable", void 0), o([L({
462
+ })], K.prototype, "closable", void 0), o([R({
456
463
  type: Boolean,
457
464
  reflect: !0
458
- })], W.prototype, "zoomable", void 0), o([L({
465
+ })], K.prototype, "zoomable", void 0), o([R({
459
466
  type: Boolean,
460
467
  reflect: !0
461
- })], W.prototype, "movable", void 0), o([L({
468
+ })], K.prototype, "movable", void 0), o([R({
462
469
  type: Boolean,
463
470
  reflect: !0
464
- })], W.prototype, "resizable", void 0), o([L({
471
+ })], K.prototype, "resizable", void 0), o([R({
465
472
  type: Number,
466
473
  attribute: "min-width"
467
- })], W.prototype, "minWidth", void 0), o([L({
474
+ })], K.prototype, "minWidth", void 0), o([R({
468
475
  type: Number,
469
476
  attribute: "min-height"
470
- })], W.prototype, "minHeight", void 0), o([L({
477
+ })], K.prototype, "minHeight", void 0), o([R({
471
478
  type: Number,
472
479
  attribute: "max-width"
473
- })], W.prototype, "maxWidth", void 0), o([L({
480
+ })], K.prototype, "maxWidth", void 0), o([R({
474
481
  type: Number,
475
482
  attribute: "max-height"
476
- })], W.prototype, "maxHeight", void 0), o([L({ reflect: !0 })], W.prototype, "scrollbars", void 0), o([L({
483
+ })], K.prototype, "maxHeight", void 0), o([R({ reflect: !0 })], K.prototype, "scrollbars", void 0), o([R({
477
484
  type: Number,
478
485
  attribute: "header-height"
479
- })], W.prototype, "headerHeight", void 0), o([R()], W.prototype, "_hasHeader", void 0), o([R()], W.prototype, "_hasStatus", void 0), W = o([t("vf-window")], W);
486
+ })], K.prototype, "headerHeight", void 0), o([B()], K.prototype, "_hasHeader", void 0), o([B()], K.prototype, "_hasStatus", void 0), o([z(".body")], K.prototype, "body", void 0), o([z("vf-scroll-area")], K.prototype, "scrollArea", void 0), K = o([t("vf-window")], K);
480
487
  //#endregion
481
- export { W as VfWindow };
488
+ export { K as VfWindow };
package/dist/drag.d.ts CHANGED
@@ -9,6 +9,10 @@ import type { ReactiveController, ReactiveControllerHost } from 'lit';
9
9
  * a placement is stored in, so that a dropped host is still where it was
10
10
  * dropped after a zoom. The controller does the one conversion: pointer events
11
11
  * arrive in CSS px, and only the *delta* is converted.
12
+ *
13
+ * The trailing parameters on {@link onDrag} and {@link onDragEnd} are
14
+ * additive: a target that declares fewer (`vf-window`, `vf-dialog`) still
15
+ * conforms and simply ignores them.
12
16
  */
13
17
  export interface DragTarget {
14
18
  /**
@@ -21,10 +25,19 @@ export interface DragTarget {
21
25
  x: number;
22
26
  y: number;
23
27
  } | null;
24
- /** Apply a moved origin, in system px, already snapped onto the lattice. */
25
- onDrag(x: number, y: number): void;
26
- /** Optional: the drag ended (pointer released or cancelled). */
27
- onDragEnd?(): void;
28
+ /**
29
+ * Apply a moved origin, in system px, already snapped onto the lattice.
30
+ * `event` is the pointer move that produced it, for a target that reports
31
+ * the pointer itself (`vf-icon`'s drag events carry `clientX`/`clientY`).
32
+ */
33
+ onDrag(x: number, y: number, event: PointerEvent): void;
34
+ /**
35
+ * Optional: the drag ended. `cancelled` tells an abandoned gesture — a
36
+ * `pointercancel`, or {@link DragController.cancel} — from a release;
37
+ * `event` is the pointer event that ended it, `undefined` for a
38
+ * programmatic cancel.
39
+ */
40
+ onDragEnd?(event: PointerEvent | undefined, cancelled: boolean): void;
28
41
  }
29
42
  /**
30
43
  * Drag-to-move for 1-bit chrome. Bind {@link onPointerDown} / {@link onPointerMove}
@@ -45,5 +58,16 @@ export declare class DragController implements ReactiveController {
45
58
  hostDisconnected(): void;
46
59
  onPointerDown: (event: PointerEvent) => void;
47
60
  onPointerMove: (event: PointerEvent) => void;
61
+ /**
62
+ * The release — or, bound to `pointercancel` as every handle binds it, the
63
+ * platform abandoning the gesture (a touch the browser took for a scroll),
64
+ * which the target hears as a cancel.
65
+ */
48
66
  onPointerUp: (event: PointerEvent) => void;
67
+ /**
68
+ * Abandon the in-flight drag from code — an Escape mid-gesture. The capture
69
+ * is released and the target hears a cancel with no pointer event; the
70
+ * pointer's eventual release then belongs to nobody.
71
+ */
72
+ cancel(): void;
49
73
  }
package/dist/drag.js CHANGED
@@ -6,24 +6,33 @@ var n = class {
6
6
  #n;
7
7
  #r;
8
8
  #i;
9
+ #a;
9
10
  constructor(n, r) {
10
- this.host = n, this.target = r, this.#e = null, this.#t = 0, this.#n = 0, this.#r = 0, this.#i = 0, this.onPointerDown = (e) => {
11
+ this.host = n, this.target = r, this.#e = null, this.#t = null, this.#n = 0, this.#r = 0, this.#i = 0, this.#a = 0, this.onPointerDown = (e) => {
11
12
  if (this.#e !== null) return;
12
13
  let t = this.target.onDragStart(e);
13
- t && (this.#e = e.pointerId, this.#t = e.clientX, this.#n = e.clientY, this.#r = t.x, this.#i = t.y, e.currentTarget.setPointerCapture(e.pointerId), e.preventDefault());
14
+ if (!t) return;
15
+ this.#e = e.pointerId, this.#n = e.clientX, this.#r = e.clientY, this.#i = t.x, this.#a = t.y;
16
+ let n = e.currentTarget;
17
+ this.#t = n, n.setPointerCapture(e.pointerId), e.preventDefault();
14
18
  }, this.onPointerMove = (n) => {
15
19
  if (n.pointerId !== this.#e) return;
16
20
  let r = e(this.host);
17
- this.target.onDrag(t(this.#r + (n.clientX - this.#t) / r, this.host), t(this.#i + (n.clientY - this.#n) / r, this.host));
21
+ this.target.onDrag(t(this.#i + (n.clientX - this.#n) / r, this.host), t(this.#a + (n.clientY - this.#r) / r, this.host), n);
18
22
  }, this.onPointerUp = (e) => {
19
23
  if (e.pointerId !== this.#e) return;
20
- this.#e = null;
24
+ this.#e = null, this.#t = null;
21
25
  let t = e.currentTarget;
22
- t.hasPointerCapture(e.pointerId) && t.releasePointerCapture(e.pointerId), this.target.onDragEnd?.();
26
+ t.hasPointerCapture(e.pointerId) && t.releasePointerCapture(e.pointerId), this.target.onDragEnd?.(e, e.type === "pointercancel");
23
27
  }, n.addController(this);
24
28
  }
25
29
  hostDisconnected() {
26
- this.#e = null;
30
+ this.#e = null, this.#t = null;
31
+ }
32
+ cancel() {
33
+ if (this.#e === null) return;
34
+ let e = this.#e, t = this.#t;
35
+ this.#e = null, this.#t = null, t?.hasPointerCapture(e) && t.releasePointerCapture(e), this.target.onDragEnd?.(void 0, !0);
27
36
  }
28
37
  };
29
38
  //#endregion
package/dist/index.d.ts CHANGED
@@ -31,7 +31,8 @@ export { VfLabel } from './components/vf-label.js';
31
31
  export { VfParagraph } from './components/vf-paragraph.js';
32
32
  export { VfImg } from './components/vf-img.js';
33
33
  export { VfIcon } from './components/vf-icon.js';
34
- export type { VfIconSize } from './components/vf-icon.js';
34
+ export type { VfIconSize, VfIconDragDetail, VfIconDragFollower, } from './components/vf-icon.js';
35
+ export { VfIconField } from './components/vf-icon-field.js';
35
36
  export { VfMenuBar } from './components/vf-menu-bar.js';
36
37
  export { VfMenu } from './components/vf-menu.js';
37
38
  export { VfMenuItem } from './components/vf-menu-item.js';
package/dist/index.js CHANGED
@@ -60,15 +60,16 @@ import { VfLabel as jt } from "./components/vf-label.js";
60
60
  import { VfParagraph as Mt } from "./components/vf-paragraph.js";
61
61
  import { VfImg as Nt } from "./components/vf-img.js";
62
62
  import { VfIcon as Pt } from "./components/vf-icon.js";
63
- import { VfMenuBar as Ft } from "./components/vf-menu-bar.js";
64
- import { VfMenu as It } from "./components/vf-menu.js";
65
- import { VfMenuItem as Lt } from "./components/vf-menu-item.js";
66
- import { VfList as Rt } from "./components/vf-list.js";
67
- import { VfListItem as zt } from "./components/vf-list-item.js";
68
- import { VfFieldset as Bt } from "./components/vf-fieldset.js";
69
- import { VfGrid as Vt } from "./components/vf-grid.js";
70
- import { VfStack as Ht } from "./components/vf-stack.js";
71
- import { VfContainer as Ut } from "./components/vf-container.js";
72
- import { CURSOR_ARROW as Wt, CURSOR_CROSSHAIR as Gt, CURSOR_I_BEAM as Kt, CURSOR_WAIT as qt } from "./cursor-art.js";
73
- import { applyCursor as Jt } from "./cursor.js";
74
- export { ze as BLINK_FLIPS, Be as BLINK_INTERVAL_MS, Ee as BUTTON_FACE, De as BUTTON_FRAME, Ge as CARET_DOWN, Ke as CHECKBOX_X, qe as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, Wt as CURSOR_ARROW, Gt as CURSOR_CROSSHAIR, Kt as CURSOR_I_BEAM, qt as CURSOR_WAIT, Te as DocumentListenersController, Le as DragController, bt as FocusRuleController, Ce as GridSnapController, G as PATTERNS, K as PATTERN_NAMES, q as PATTERN_SIZE, D as PIXEL_GRID_METRICS, Ve as PRESS_HOLD_MS, xe as PatternFillController, T as PlacementController, Je as RADIO_DOT, Ye as RADIO_FACE, Xe as RADIO_RING, Ze as RADIO_RING_PRESSED, He as RENAME_DELAY_MS, Oe as RING_FRAME, ke as RING_HOLE, Ae as RING_INSET, ie as RULE_EDGES, je as SCREEN_CORNER, Qe as SLIDER_THUMB, $e as SLIDER_THUMB_FACE, et as STEPPER, tt as STEPPER_DOWN_FILL, nt as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, it as ScrollRailController, Re as ScrollStateController, R as TILE_LATTICE, ge as TileRasterCache, be as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, mt as VfButton, ut as VfButtonGroup, _t as VfCheckbox, Ut as VfContainer, Fe as VfDesktop, dt as VfDialog, Bt as VfFieldset, pt as VfFormControl, Vt as VfGrid, Pt as VfIcon, Nt as VfImg, jt as VfLabel, Rt as VfList, zt as VfListItem, It as VfMenu, Ft as VfMenuBar, Lt as VfMenuItem, ct as VfModalDialog, Et as VfNumberField, Dt as VfOption, Mt as VfParagraph, E as VfPositioned, kt as VfProgressBar, vt as VfRadio, yt as VfRadioGroup, ot as VfScrollArea, Ot as VfSelect, ft as VfSeparator, Ie as VfSized, At as VfSlider, Ht as VfStack, ht as VfSwatch, Tt as VfTextArea, Ct as VfTextControlBase, wt as VfTextField, gt as VfToggleControl, st as VfWindow, Jt as applyCursor, f as applyScale, t as defineElement, o as devicePxPerSystemPx, p as effectiveScale, e as emit, xt as focusModality, m as getScale, s as getZoom, rt as glyphSvg, lt as modalDialogStyles, h as onScaleChange, c as onZoomChange, J as parsePattern, ae as parseRule, Y as patternHex, X as patternMotif, _e as patternOverride, Z as patternRects, Ue as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, at as renderScrollRail, we as requestGridSnap, l as resetZoomBaseline, oe as ruleClasses, We as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, Me as steppedCornerClip, Ne as steppedRectClip, Pe as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, ve as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, St as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, te as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, Q as vfDots, n as vfElement, me as vfField, ue as vfFocus, de as vfFocusRing, fe as vfFocusUnderline, ee as vfHardShadowDecls, ne as vfModalFrame, re as vfPanel, Se as vfPatternFill, se as vfRule, he as vfScrollRail, L as vfStaticText, $ as vfStripes, ye as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, ce as vfTitleBar, pe as vfToggle, le as vfWindowWidgets };
63
+ import { VfIconField as Ft } from "./components/vf-icon-field.js";
64
+ import { VfMenuBar as It } from "./components/vf-menu-bar.js";
65
+ import { VfMenu as Lt } from "./components/vf-menu.js";
66
+ import { VfMenuItem as Rt } from "./components/vf-menu-item.js";
67
+ import { VfList as zt } from "./components/vf-list.js";
68
+ import { VfListItem as Bt } from "./components/vf-list-item.js";
69
+ import { VfFieldset as Vt } from "./components/vf-fieldset.js";
70
+ import { VfGrid as Ht } from "./components/vf-grid.js";
71
+ import { VfStack as Ut } from "./components/vf-stack.js";
72
+ import { VfContainer as Wt } from "./components/vf-container.js";
73
+ import { CURSOR_ARROW as Gt, CURSOR_CROSSHAIR as Kt, CURSOR_I_BEAM as qt, CURSOR_WAIT as Jt } from "./cursor-art.js";
74
+ import { applyCursor as Yt } from "./cursor.js";
75
+ export { ze as BLINK_FLIPS, Be as BLINK_INTERVAL_MS, Ee as BUTTON_FACE, De as BUTTON_FRAME, Ge as CARET_DOWN, Ke as CHECKBOX_X, qe as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, Gt as CURSOR_ARROW, Kt as CURSOR_CROSSHAIR, qt as CURSOR_I_BEAM, Jt as CURSOR_WAIT, Te as DocumentListenersController, Le as DragController, bt as FocusRuleController, Ce as GridSnapController, G as PATTERNS, K as PATTERN_NAMES, q as PATTERN_SIZE, D as PIXEL_GRID_METRICS, Ve as PRESS_HOLD_MS, xe as PatternFillController, T as PlacementController, Je as RADIO_DOT, Ye as RADIO_FACE, Xe as RADIO_RING, Ze as RADIO_RING_PRESSED, He as RENAME_DELAY_MS, Oe as RING_FRAME, ke as RING_HOLE, Ae as RING_INSET, ie as RULE_EDGES, je as SCREEN_CORNER, Qe as SLIDER_THUMB, $e as SLIDER_THUMB_FACE, et as STEPPER, tt as STEPPER_DOWN_FILL, nt as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, it as ScrollRailController, Re as ScrollStateController, R as TILE_LATTICE, ge as TileRasterCache, be as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, mt as VfButton, ut as VfButtonGroup, _t as VfCheckbox, Wt as VfContainer, Fe as VfDesktop, dt as VfDialog, Vt as VfFieldset, pt as VfFormControl, Ht as VfGrid, Pt as VfIcon, Ft as VfIconField, Nt as VfImg, jt as VfLabel, zt as VfList, Bt as VfListItem, Lt as VfMenu, It as VfMenuBar, Rt as VfMenuItem, ct as VfModalDialog, Et as VfNumberField, Dt as VfOption, Mt as VfParagraph, E as VfPositioned, kt as VfProgressBar, vt as VfRadio, yt as VfRadioGroup, ot as VfScrollArea, Ot as VfSelect, ft as VfSeparator, Ie as VfSized, At as VfSlider, Ut as VfStack, ht as VfSwatch, Tt as VfTextArea, Ct as VfTextControlBase, wt as VfTextField, gt as VfToggleControl, st as VfWindow, Yt as applyCursor, f as applyScale, t as defineElement, o as devicePxPerSystemPx, p as effectiveScale, e as emit, xt as focusModality, m as getScale, s as getZoom, rt as glyphSvg, lt as modalDialogStyles, h as onScaleChange, c as onZoomChange, J as parsePattern, ae as parseRule, Y as patternHex, X as patternMotif, _e as patternOverride, Z as patternRects, Ue as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, at as renderScrollRail, we as requestGridSnap, l as resetZoomBaseline, oe as ruleClasses, We as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, Me as steppedCornerClip, Ne as steppedRectClip, Pe as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, ve as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, St as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, te as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, Q as vfDots, n as vfElement, me as vfField, ue as vfFocus, de as vfFocusRing, fe as vfFocusUnderline, ee as vfHardShadowDecls, ne as vfModalFrame, re as vfPanel, Se as vfPatternFill, se as vfRule, he as vfScrollRail, L as vfStaticText, $ as vfStripes, ye as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, ce as vfTitleBar, pe as vfToggle, le as vfWindowWidgets };