vintage-frames 0.6.1 → 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.
@@ -32,6 +32,12 @@ export declare const modalDialogStyles: import("lit").CSSResult;
32
32
  * event, an Escape-close no longer leaves a stale origin behind, so the next
33
33
  * open re-derives it.
34
34
  *
35
+ * It also owns the two keyboard rules every classic dialog followed (see
36
+ * {@link defaultButton} and {@link initialFocusTarget}): Return or Enter
37
+ * activates the default button from anywhere in the dialog, and the box opens
38
+ * with the insertion point in its first text field — or, with none, focus on
39
+ * the default button.
40
+ *
35
41
  * Removing an open modal from the DOM is a close path too. HTML's dialog
36
42
  * *removing steps* take the element out of the top layer **without** running
37
43
  * the close algorithm — no `close` event, no focus restoration — which is
@@ -124,6 +130,33 @@ export declare class VfModalDialog extends LitElement {
124
130
  * drag from squeezing the box.
125
131
  */
126
132
  protected get dialogSize(): Record<string, string | null>;
133
+ /**
134
+ * The dialog's default button — the one wearing the bold ring
135
+ * (`vf-button[variant="default"]`) — or null with none, or none enabled.
136
+ * Looked for among the slotted content first, then in the shadow tree, so a
137
+ * consumer's own modal that renders its buttons itself is covered too.
138
+ * Override to name it some other way.
139
+ */
140
+ protected get defaultButton(): HTMLElement | null;
141
+ /**
142
+ * Where focus lands on open. The classic Dialog Manager put the insertion
143
+ * point in the first editable text item and gave nothing else focus at all;
144
+ * the web needs a focused control for the keyboard to have anywhere to be,
145
+ * so with no text field the default button takes it (which is also what
146
+ * makes Return and Space work there without a Tab). In order:
147
+ *
148
+ * 1. a slotted control carrying `autofocus` — the author's say;
149
+ * 2. the first enabled text-entry control (`vf-text-field`,
150
+ * `vf-number-field`, `vf-text-area`, or a native text input/textarea);
151
+ * 3. the {@link defaultButton};
152
+ * 4. null — leave the browser's own choice alone.
153
+ *
154
+ * Left to itself, `showModal()` focuses the first focusable thing in flat
155
+ * tree order, which for a Cancel/OK row is Cancel, and for a body with a
156
+ * link in it is the link — so Return did the one thing a classic dialog's
157
+ * Return never did. Override to choose differently.
158
+ */
159
+ protected get initialFocusTarget(): HTMLElement | null;
127
160
  /** Open the modal (native `showModal()`), pinned onto the device grid. */
128
161
  show(): void;
129
162
  /** Close the modal. Fires `vf-close` with `{ reason: 'close' }`. */
@@ -4,7 +4,15 @@ import o from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js"
4
4
  import { DocumentListenersController as s } from "./document-listeners.js";
5
5
  import { LitElement as c, css as l } from "lit";
6
6
  import { property as u, query as d } from "lit/decorators.js";
7
- var f = 24, p = l`
7
+ var f = 24, p = /* @__PURE__ */ new Set([
8
+ "text",
9
+ "search",
10
+ "url",
11
+ "tel",
12
+ "email",
13
+ "password",
14
+ "number"
15
+ ]), m = (e) => e instanceof HTMLInputElement ? p.has(e.type) : !0, h = l`
8
16
  dialog {
9
17
  padding: 0;
10
18
  margin: auto;
@@ -43,32 +51,43 @@ var f = 24, p = l`
43
51
  the fallback is the arrow it always showed. */
44
52
  cursor: var(--vf-cursor, default);
45
53
  }
46
- `, m = class extends c {
54
+ `, g = class extends c {
47
55
  constructor(...e) {
48
56
  super(...e), this.scale = new t(this), this.open = !1, this.lightDismiss = !1, this.#e = !1, this.#n = null, this.#r = null, this.#i = new s(this, () => [
49
57
  [
50
58
  this._dialog,
51
59
  "pointerdown",
52
- this.#a
60
+ this.#s
53
61
  ],
54
62
  [
55
63
  this._dialog,
56
64
  "pointerup",
57
- this.#o
65
+ this.#c
58
66
  ],
59
67
  [
60
68
  this._dialog,
61
69
  "pointercancel",
62
- this.#s
70
+ this.#l
71
+ ],
72
+ [
73
+ this._dialog,
74
+ "keydown",
75
+ this.#o
63
76
  ]
64
- ]), this.#a = (e) => {
77
+ ]), this.#o = (e) => {
78
+ if (e.key !== "Enter" || e.defaultPrevented || e.isComposing || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
79
+ let t = e.composedPath();
80
+ if (t.some((e) => e instanceof HTMLAnchorElement && e.hasAttribute("href")) || t.some((e) => e instanceof HTMLTextAreaElement || e instanceof HTMLElement && e.isContentEditable) && e.code !== "NumpadEnter") return;
81
+ let n = this.defaultButton;
82
+ n && (e.preventDefault(), n.click());
83
+ }, this.#s = (e) => {
65
84
  this.#r = e.target === this._dialog ? e.pointerId : null;
66
- }, this.#o = (e) => {
85
+ }, this.#c = (e) => {
67
86
  let t = this.#r === e.pointerId;
68
87
  this.#r = null, !(!t || e.target !== this._dialog || !this.lightDismiss) && (this.#n = "outside", this.close());
69
- }, this.#s = () => {
88
+ }, this.#l = () => {
70
89
  this.#r = null;
71
- }, this.#c = null, this.#m = () => this.settle();
90
+ }, this.#u = null, this.#g = () => this.settle();
72
91
  }
73
92
  get dialogSize() {
74
93
  return {
@@ -88,42 +107,53 @@ var f = 24, p = l`
88
107
  #n;
89
108
  #r;
90
109
  #i;
91
- #a;
110
+ get defaultButton() {
111
+ let e = "vf-button[variant=\"default\"]";
112
+ return [...this.querySelectorAll(e), ...this.renderRoot.querySelectorAll(e)].find((e) => !e.matches(":disabled")) ?? null;
113
+ }
114
+ get initialFocusTarget() {
115
+ return this.querySelector("[autofocus]") || ([...this.querySelectorAll("vf-text-field, vf-number-field, vf-text-area, textarea, input")].find((e) => m(e) && !e.matches(":disabled")) ?? this.defaultButton);
116
+ }
117
+ #a() {
118
+ this.initialFocusTarget?.focus();
119
+ }
92
120
  #o;
93
121
  #s;
94
122
  #c;
123
+ #l;
124
+ #u;
95
125
  show() {
96
- this.open = !0, this.hasUpdated && this.#p();
126
+ this.open = !0, this.hasUpdated && this.#h();
97
127
  }
98
128
  close() {
99
- this.open = !1, this.hasUpdated && this.#p();
129
+ this.open = !1, this.hasUpdated && this.#h();
100
130
  }
101
131
  updated(e) {
102
- e.has("open") && this.#p(), (e.has("top") || e.has("left")) && this.settle(), this.#t();
132
+ e.has("open") && this.#h(), (e.has("top") || e.has("left")) && this.settle(), this.#t();
103
133
  }
104
- #l() {
134
+ #d() {
105
135
  let e = document.documentElement;
106
136
  return {
107
137
  width: a(e.clientWidth || window.innerWidth, this),
108
138
  height: a(e.clientHeight || window.innerHeight, this)
109
139
  };
110
140
  }
111
- #u(e, t) {
112
- let n = this.#l(), r = a(this._dialog?.offsetWidth ?? 0, this);
141
+ #f(e, t) {
142
+ let n = this.#d(), r = a(this._dialog?.offsetWidth ?? 0, this);
113
143
  return {
114
144
  x: Math.min(Math.max(e, f - r), n.width - f),
115
145
  y: Math.min(Math.max(t, 0), Math.max(0, n.height - f))
116
146
  };
117
147
  }
118
- #d() {
119
- let e = this.#l(), t = this._dialog?.getBoundingClientRect();
148
+ #p() {
149
+ let e = this.#d(), t = this._dialog?.getBoundingClientRect();
120
150
  return {
121
151
  x: (e.width - a(t?.width ?? 0, this)) / 2,
122
152
  y: (e.height - a(t?.height ?? 0, this)) / 2
123
153
  };
124
154
  }
125
155
  placeAt(e, t) {
126
- let n = this.#u(e, t);
156
+ let n = this.#f(e, t);
127
157
  this.left = r(n.x, this), this.top = r(n.y, this);
128
158
  }
129
159
  settle() {
@@ -132,10 +162,10 @@ var f = 24, p = l`
132
162
  let t = this.left != null || this.top != null ? {
133
163
  x: this.left ?? 0,
134
164
  y: this.top ?? 0
135
- } : this.#d(), n = this.#u(t.x, t.y);
165
+ } : this.#p(), n = this.#f(t.x, t.y);
136
166
  e.style.left = i(r(n.x, this)), e.style.top = i(r(n.y, this)), e.style.right = "auto", e.style.bottom = "auto", e.style.margin = "0";
137
167
  }
138
- #f() {
168
+ #m() {
139
169
  let e = this._dialog?.style;
140
170
  if (e) for (let t of [
141
171
  "left",
@@ -145,44 +175,44 @@ var f = 24, p = l`
145
175
  "margin"
146
176
  ]) e.removeProperty(t);
147
177
  }
148
- #p() {
178
+ #h() {
149
179
  let e = this._dialog;
150
- e && (this.open && !e.open ? (this.#c = document.activeElement, e.showModal(), this.settle(), this.#_(e), this.#i.attach()) : !this.open && e.open && e.close());
180
+ e && (this.open && !e.open ? (this.#u = document.activeElement, e.showModal(), this.#a(), this.settle(), this.#y(e), this.#i.attach()) : !this.open && e.open && e.close());
151
181
  }
152
- #m;
153
- #h;
154
182
  #g;
155
- #_(e) {
156
- typeof ResizeObserver < "u" && !this.#h && (this.#h = new ResizeObserver(this.#m), this.#h.observe(e)), window.addEventListener("resize", this.#m), this.#g ??= n(this.#m);
183
+ #_;
184
+ #v;
185
+ #y(e) {
186
+ typeof ResizeObserver < "u" && !this.#_ && (this.#_ = new ResizeObserver(this.#g), this.#_.observe(e)), window.addEventListener("resize", this.#g), this.#v ??= n(this.#g);
157
187
  }
158
- #v() {
159
- this.#h?.disconnect(), this.#h = void 0, window.removeEventListener("resize", this.#m), this.#g?.(), this.#g = void 0;
188
+ #b() {
189
+ this.#_?.disconnect(), this.#_ = void 0, window.removeEventListener("resize", this.#g), this.#v?.(), this.#v = void 0;
160
190
  }
161
191
  disconnectedCallback() {
162
- super.disconnectedCallback(), this.#v();
192
+ super.disconnectedCallback(), this.#b();
163
193
  let e = this._dialog;
164
194
  if (e?.open) {
165
195
  e.close();
166
- let t = this.#c, n = document.activeElement;
196
+ let t = this.#u, n = document.activeElement;
167
197
  t instanceof HTMLElement && t.isConnected && (n === null || n === document.body) && t.focus();
168
198
  }
169
- this.#c = null;
199
+ this.#u = null;
170
200
  }
171
201
  _onNativeCancel() {
172
202
  this.#n = "escape";
173
203
  }
174
204
  _onNativeClose() {
175
205
  let t = this.#n ?? "close";
176
- this.#n = null, this.#c = null, this.#r = null, this.#i.detach(), this.#v(), this.open = !1, this.#f(), e(this, "vf-close", { reason: t });
206
+ this.#n = null, this.#u = null, this.#r = null, this.#i.detach(), this.#b(), this.open = !1, this.#m(), e(this, "vf-close", { reason: t });
177
207
  }
178
208
  };
179
209
  o([u({
180
210
  type: Boolean,
181
211
  reflect: !0
182
- })], m.prototype, "open", void 0), o([u({ type: Number })], m.prototype, "width", void 0), o([u({ type: Number })], m.prototype, "height", void 0), o([u({ type: Number })], m.prototype, "top", void 0), o([u({ type: Number })], m.prototype, "left", void 0), o([u({
212
+ })], g.prototype, "open", void 0), o([u({ type: Number })], g.prototype, "width", void 0), o([u({ type: Number })], g.prototype, "height", void 0), o([u({ type: Number })], g.prototype, "top", void 0), o([u({ type: Number })], g.prototype, "left", void 0), o([u({
183
213
  type: Boolean,
184
214
  reflect: !0,
185
215
  attribute: "light-dismiss"
186
- })], m.prototype, "lightDismiss", void 0), o([d("dialog")], m.prototype, "_dialog", void 0);
216
+ })], g.prototype, "lightDismiss", void 0), o([d("dialog")], g.prototype, "_dialog", void 0);
187
217
  //#endregion
188
- export { m as VfModalDialog, p as modalDialogStyles };
218
+ export { g as VfModalDialog, h as modalDialogStyles };
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * The Finder "open" ghost — an icon's art redrawn as outline plus dither,
3
- * derived from the art itself in the client.
3
+ * derived from the art itself in the client — and, on the same terms, the
4
+ * dotted outline an icon drags as ({@link deriveDragOutline}).
4
5
  *
5
6
  * When a folder or application is open, the Finder redraws its icon as a
6
7
  * ghost: the outline stays, and everything inside it becomes pattern. The kit
@@ -38,3 +39,61 @@
38
39
  * an environment refusing a 2d context.
39
40
  */
40
41
  export declare function deriveOpenArt(art: HTMLImageElement | HTMLCanvasElement): HTMLCanvasElement | null;
42
+ /** A box inside an icon's frame, in system px. */
43
+ export interface DragOutlineBox {
44
+ x: number;
45
+ y: number;
46
+ width: number;
47
+ height: number;
48
+ }
49
+ /**
50
+ * Where an icon's parts sit inside its frame, in system px — measured by the
51
+ * icon, so the outline lands on the same pixels the frame paints.
52
+ */
53
+ export interface DragOutlineGeometry {
54
+ /** The frame. */
55
+ width: number;
56
+ height: number;
57
+ /**
58
+ * The art's own box, where it paints. Null when the pipeline has nothing
59
+ * to draw — nothing slotted, a failed load, an inline `<svg>` — and the
60
+ * cell's rectangle stands in.
61
+ */
62
+ art: DragOutlineBox | null;
63
+ /** The reserved art cell. */
64
+ cell: DragOutlineBox;
65
+ /** The name plate, or null with no name. */
66
+ plate: DragOutlineBox | null;
67
+ }
68
+ /**
69
+ * Derive the outline an icon drags as: the mask's boundary — the same
70
+ * one-pixel ring the open ghost finds, by the same erosion — and the name
71
+ * plate's rectangle, solid black on transparent, one canvas the size of the
72
+ * icon's frame at one image px per system px. Not yet dotted: the ring is
73
+ * derived once per drag, and {@link dotOutline} re-applies the checker at
74
+ * each step's phase.
75
+ *
76
+ * Art the pipeline cannot draw falls back to the cell's rectangle — the
77
+ * ghost's rule: never a blank where a state cannot show. Compositing only,
78
+ * never a readback, so cross-origin art derives too.
79
+ *
80
+ * Returns null for a frame with no size, or an environment refusing a 2d
81
+ * context.
82
+ */
83
+ export declare function deriveDragOutline(art: HTMLImageElement | HTMLCanvasElement | null, geometry: DragOutlineGeometry): HTMLCanvasElement | null;
84
+ /**
85
+ * Paint a selection rectangle — the rubber band `vf-icon-field` drags on its
86
+ * background — into `into`: a one-pixel outline `width` × `height` system px,
87
+ * dotted at `phase` the way the drag outline is. A degenerate axis paints as
88
+ * a one-pixel line rather than nothing.
89
+ */
90
+ export declare function paintSelectionRect(into: HTMLCanvasElement, width: number, height: number, phase: number): void;
91
+ /**
92
+ * Paint `ring` into `into` dotted with the checker at `phase` — 0 keeps the
93
+ * dots where `x + y` is even in the canvas's own coordinates, 1 where it is
94
+ * odd. The caller picks the phase from where the outline lands on screen,
95
+ * so the dots share the desktop dither's phase wherever the outline goes,
96
+ * as QuickDraw's screen-anchored pattern pen did. Sizing `into` to the ring
97
+ * clears it, so each step is a fresh paint.
98
+ */
99
+ export declare function dotOutline(ring: HTMLCanvasElement, into: HTMLCanvasElement, phase: number): void;
package/dist/open-art.js CHANGED
@@ -31,5 +31,51 @@ function r(t) {
31
31
  let c = o.ctx.createPattern(s, "repeat");
32
32
  return c && (o.ctx.globalCompositeOperation = "source-atop", o.ctx.fillStyle = c, o.ctx.fillRect(0, 0, r, i)), a.ctx.globalCompositeOperation = "source-over", a.ctx.drawImage(o.canvas, 0, 0), a.canvas;
33
33
  }
34
+ var i = null, a = () => {
35
+ if (!i) {
36
+ let t = e(2, 2);
37
+ if (!t) return null;
38
+ t.ctx.fillStyle = "#000", t.ctx.fillRect(0, 0, 1, 1), t.ctx.fillRect(1, 1, 1, 1), i = t.canvas;
39
+ }
40
+ return i;
41
+ }, o = (e, t) => {
42
+ t.width <= 0 || t.height <= 0 || (e.fillStyle = "#000", e.fillRect(t.x, t.y, t.width, t.height), t.width > 2 && t.height > 2 && e.clearRect(t.x + 1, t.y + 1, t.width - 2, t.height - 2));
43
+ };
44
+ function s(t, n) {
45
+ let { width: r, height: i } = n;
46
+ if (!r || !i) return null;
47
+ let a = e(r, i);
48
+ if (!a) return null;
49
+ let s = t ? n.art : null;
50
+ if (t && s && s.width > 0 && s.height > 0) {
51
+ let n = e(r, i), o = e(r, i);
52
+ if (!n || !o) return null;
53
+ n.ctx.drawImage(t, s.x, s.y, s.width, s.height), n.ctx.globalCompositeOperation = "source-in", n.ctx.fillStyle = "#000", n.ctx.fillRect(0, 0, r, i), o.ctx.drawImage(n.canvas, 0, 0), o.ctx.globalCompositeOperation = "destination-in";
54
+ for (let [e, t] of [
55
+ [1, 0],
56
+ [-1, 0],
57
+ [0, 1],
58
+ [0, -1]
59
+ ]) o.ctx.drawImage(n.canvas, e, t);
60
+ a.ctx.drawImage(n.canvas, 0, 0), a.ctx.globalCompositeOperation = "destination-out", a.ctx.drawImage(o.canvas, 0, 0), a.ctx.globalCompositeOperation = "source-over";
61
+ } else o(a.ctx, n.cell);
62
+ return n.plate && o(a.ctx, n.plate), a.canvas;
63
+ }
64
+ function c(t, n, r, i) {
65
+ let a = Math.max(1, Math.round(n)), s = Math.max(1, Math.round(r)), c = e(a, s);
66
+ c && (o(c.ctx, {
67
+ x: 0,
68
+ y: 0,
69
+ width: a,
70
+ height: s
71
+ }), l(c.canvas, t, i));
72
+ }
73
+ function l(e, t, n) {
74
+ let r = a(), i = t.getContext("2d");
75
+ if (!r || !i) return;
76
+ t.width = e.width, t.height = e.height, i.imageSmoothingEnabled = !1, i.drawImage(e, 0, 0);
77
+ let o = i.createPattern(r, "repeat");
78
+ o && (i.globalCompositeOperation = "destination-in", i.fillStyle = o, i.translate(n & 1, 0), i.fillRect(-2, 0, e.width + 2, e.height), i.setTransform(1, 0, 0, 1, 0, 0), i.globalCompositeOperation = "source-over");
79
+ }
34
80
  //#endregion
35
- export { r as deriveOpenArt };
81
+ export { s as deriveDragOutline, r as deriveOpenArt, l as dotOutline, c as paintSelectionRect };
@@ -84,6 +84,16 @@ type PositionedHost = HTMLElement & {
84
84
  * unrelated update — a heading change, a desktop toggling `active` — never
85
85
  * re-asserts a coordinate and costs nothing.
86
86
  *
87
+ * **Every write it makes is announced** as `vf-placement-change` (bubbles,
88
+ * `composed: false`, detail `{ left, top }` — nulls on a return to flow). It
89
+ * is an internal coordination event on the terms of the menu handshakes:
90
+ * parent and child share one light tree, and a kit protocol must not leak out
91
+ * of a consumer's shadow boundary. `vf-scroll-area` listens for it and
92
+ * re-measures, because a placed child moved through `top`/`left` changes the
93
+ * scroll range with no box changing anywhere a ResizeObserver can see — the
94
+ * plane's box is never grown by an absolutely positioned child. One funnel
95
+ * covers a drop, an arrow nudge and a page's own `icon.left = …` alike.
96
+ *
87
97
  * **`fixed`** holds the placement against the *visible* region of the nearest
88
98
  * scrolling ancestor instead of its scrolled plane — a tool strip over a
89
99
  * document, a column header over rows — and the flag alone places at (0,0).
@@ -103,6 +113,25 @@ type PositionedHost = HTMLElement & {
103
113
  * `overflow: hidden`) holds it exactly where placement would.
104
114
  */
105
115
  export declare const VfPositioned: <T extends Constructor<LitElement>>(Base: T) => Constructor<VfPositionedInterface> & T;
116
+ /**
117
+ * A viewport point as a placement in `anchor`'s coordinates: `{ left, top }`
118
+ * in whole system px on the placement lattice, measured from the anchor's
119
+ * box the way a placed child's `top`/`left` are — the unit and lattice a
120
+ * drag lands on, so the result can be written straight to a child's pair.
121
+ *
122
+ * The three containers whose anchor sits in shadow DOM (`vf-window`'s
123
+ * content region, `vf-desktop`'s screen, `vf-scroll-area`'s plane) expose it
124
+ * as `placementAt(clientX, clientY)`; everywhere else the anchor is the
125
+ * element's own padding box, and `toSysExact` against
126
+ * `getBoundingClientRect()` is the documented conversion. The anchor is
127
+ * expected to carry no border of its own (the three do not), so its border
128
+ * box is its padding box; `scaleAt` is the element whose `--vf-scale` the
129
+ * conversion reads — the component's host.
130
+ */
131
+ export declare function placementIn(anchor: Element, clientX: number, clientY: number, scaleAt?: Element): {
132
+ left: number;
133
+ top: number;
134
+ };
106
135
  /** The box a gesture is clamped into, in system px — see {@link PlacementClamp}. */
107
136
  export type PlacementBounds = {
108
137
  width: number;
@@ -155,6 +184,12 @@ export declare class PlacementController {
155
184
  constructor(host: PositionedHost, clamp: PlacementClamp);
156
185
  /** Whether a gesture has placed this host (as opposed to markup or CSS). */
157
186
  get placed(): boolean;
187
+ /**
188
+ * The box the gesture is clamped into, in system px: the one {@link seed}
189
+ * measured, or a fresh measurement before any gesture. A group drag reads
190
+ * it to clamp a whole selection's delta at once.
191
+ */
192
+ get bounds(): PlacementBounds;
158
193
  /**
159
194
  * The origin a move adds its delta to, in system px.
160
195
  *
package/dist/position.js CHANGED
@@ -1,24 +1,25 @@
1
- import { snapSys as e, sysLength as t, toSysExact as n } from "./scale.js";
2
- import r from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
3
- import { property as i } from "lit/decorators.js";
1
+ import { emit as e } from "./events.js";
2
+ import { snapSys as t, sysLength as n, toSysExact as r } from "./scale.js";
3
+ import i from "./_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.js";
4
+ import { property as a } from "lit/decorators.js";
4
5
  //#region src/position.ts
5
- var a = {
6
+ var o = {
6
7
  inline: "block",
7
8
  "inline-block": "block",
8
9
  "inline-flex": "flex",
9
10
  "inline-grid": "grid",
10
11
  "inline-table": "table"
11
- }, o = (e) => {
12
+ }, s = (e) => {
12
13
  class t extends e {
13
14
  constructor(...e) {
14
- super(...e), this.fixed = !1, new s(this);
15
+ super(...e), this.fixed = !1, new c(this);
15
16
  }
16
17
  }
17
- return r([i({ type: Number })], t.prototype, "top", void 0), r([i({ type: Number })], t.prototype, "left", void 0), r([i({
18
+ return i([a({ type: Number })], t.prototype, "top", void 0), i([a({ type: Number })], t.prototype, "left", void 0), i([a({
18
19
  type: Boolean,
19
20
  reflect: !0
20
21
  })], t.prototype, "fixed", void 0), t;
21
- }, s = class {
22
+ }, c = class {
22
23
  #e;
23
24
  #t = null;
24
25
  #n = null;
@@ -29,56 +30,70 @@ var a = {
29
30
  this.#e = e, e.addController(this);
30
31
  }
31
32
  hostConnected() {
32
- this.#i && this.#r && this.#c();
33
+ this.#i && this.#r && this.#l();
33
34
  }
34
35
  hostDisconnected() {
35
36
  this.#a?.disconnect(), this.#a = null;
36
37
  }
37
38
  hostUpdated() {
38
- let e = this.#e.top ?? null, n = this.#e.left ?? null, r = this.#e.fixed === !0, i = this.#e.style;
39
- if (e === null && n === null && !r) {
39
+ let e = this.#e.top ?? null, t = this.#e.left ?? null, r = this.#e.fixed === !0, i = this.#e.style;
40
+ if (e === null && t === null && !r) {
40
41
  if (!this.#i) return;
41
- this.#r && this.#s(), this.#i = !1, this.#r = !1, i.removeProperty("position"), i.removeProperty("top"), i.removeProperty("left"), i.removeProperty("right"), i.removeProperty("bottom"), i.removeProperty("margin");
42
+ this.#r && this.#c(), this.#i = !1, this.#r = !1, i.removeProperty("position"), i.removeProperty("top"), i.removeProperty("left"), i.removeProperty("right"), i.removeProperty("bottom"), i.removeProperty("margin"), this.#o(null, null);
42
43
  return;
43
44
  }
44
- if (this.#i && e === this.#t && n === this.#n && r === this.#r) return;
45
+ if (this.#i && e === this.#t && t === this.#n && r === this.#r) return;
45
46
  let a = this.#i && this.#r;
46
- this.#i = !0, this.#t = e, this.#n = n, this.#r = r, i.position = r ? "sticky" : "absolute", i.top = t(e ?? 0), i.left = t(n ?? 0), i.right = "auto", i.bottom = "auto", r ? a || this.#o() : (a && this.#s(), i.margin = "0");
47
+ this.#i = !0, this.#t = e, this.#n = t, this.#r = r, i.position = r ? "sticky" : "absolute", i.top = n(e ?? 0), i.left = n(t ?? 0), i.right = "auto", i.bottom = "auto", r ? a || this.#s() : (a && this.#c(), i.margin = "0"), this.#o(t ?? 0, e ?? 0);
48
+ }
49
+ #o(t, n) {
50
+ e(this.#e, "vf-placement-change", {
51
+ left: t,
52
+ top: n
53
+ }, { composed: !1 });
47
54
  }
48
- #o() {
55
+ #s() {
49
56
  let e = this.#e.style;
50
- e.maxWidth = "fit-content", e.zIndex = "1", this.#l = !1;
57
+ e.maxWidth = "fit-content", e.zIndex = "1", this.#u = !1;
51
58
  let t = this.#e.getBoundingClientRect();
52
- (t.width > 0 || t.height > 0) && this.#u(t.width, t.height), this.#c();
59
+ (t.width > 0 || t.height > 0) && this.#d(t.width, t.height), this.#l();
53
60
  }
54
- #s() {
55
- this.#a?.disconnect(), this.#a = null, this.#l = !1;
61
+ #c() {
62
+ this.#a?.disconnect(), this.#a = null, this.#u = !1;
56
63
  let e = this.#e.style;
57
64
  e.removeProperty("display"), e.removeProperty("max-width"), e.removeProperty("z-index");
58
65
  }
59
- #c() {
66
+ #l() {
60
67
  this.#a ??= new ResizeObserver((e) => {
61
68
  let t = e[e.length - 1]?.borderBoxSize?.[0];
62
- if (t) this.#u(t.inlineSize, t.blockSize);
69
+ if (t) this.#d(t.inlineSize, t.blockSize);
63
70
  else {
64
71
  let e = this.#e.getBoundingClientRect();
65
- this.#u(e.width, e.height);
72
+ this.#d(e.width, e.height);
66
73
  }
67
74
  }), this.#a.observe(this.#e);
68
75
  }
69
- #l = !1;
70
- #u(e, t) {
76
+ #u = !1;
77
+ #d(e, t) {
71
78
  let n = this.#e.style;
72
- if (!this.#l) {
79
+ if (!this.#u) {
73
80
  let e = getComputedStyle(this.#e).display;
74
81
  if (e) {
75
- let t = a[e];
76
- t && (n.display = t), this.#l = !0;
82
+ let t = o[e];
83
+ t && (n.display = t), this.#u = !0;
77
84
  }
78
85
  }
79
86
  n.margin = `0 ${-e}px ${-t}px 0`;
80
87
  }
81
- }, c = class {
88
+ };
89
+ function l(e, n, i, a = e) {
90
+ let o = e.getBoundingClientRect();
91
+ return {
92
+ left: t(r(n - o.left, a), a),
93
+ top: t(r(i - o.top, a), a)
94
+ };
95
+ }
96
+ var u = class {
82
97
  #e;
83
98
  #t;
84
99
  #n = !1;
@@ -89,36 +104,39 @@ var a = {
89
104
  get placed() {
90
105
  return this.#n;
91
106
  }
107
+ get bounds() {
108
+ return this.#r ?? this.#i();
109
+ }
92
110
  seed() {
93
- let t = this.#e;
94
- if (this.#r = this.#i(), t.left != null || t.top != null) return {
95
- x: t.left ?? 0,
96
- y: t.top ?? 0
111
+ let e = this.#e;
112
+ if (this.#r = this.#i(), e.left != null || e.top != null) return {
113
+ x: e.left ?? 0,
114
+ y: e.top ?? 0
97
115
  };
98
- let r = getComputedStyle(t), i = l.has(r.position), a = i ? parseFloat(r.left) || 0 : t.offsetLeft, o = i ? parseFloat(r.top) || 0 : t.offsetTop;
116
+ let n = getComputedStyle(e), i = d.has(n.position), a = i ? parseFloat(n.left) || 0 : e.offsetLeft, o = i ? parseFloat(n.top) || 0 : e.offsetTop;
99
117
  return {
100
- x: e(n(a, t), t),
101
- y: e(n(o, t), t)
118
+ x: t(r(a, e), e),
119
+ y: t(r(o, e), e)
102
120
  };
103
121
  }
104
- moveTo(t, n) {
105
- let r = this.#e, i = this.#t(t, n, this.#r ?? this.#i());
106
- r.left = e(i.x, r), r.top = e(i.y, r), this.#n = !0;
122
+ moveTo(e, n) {
123
+ let r = this.#e, i = this.#t(e, n, this.#r ?? this.#i());
124
+ r.left = t(i.x, r), r.top = t(i.y, r), this.#n = !0;
107
125
  }
108
126
  #i() {
109
- let e = this.#e, t = e.offsetParent, r = t && t.clientWidth > 0 && t.clientHeight > 0 ? t : null;
127
+ let e = this.#e, t = e.offsetParent, n = t && t.clientWidth > 0 && t.clientHeight > 0 ? t : null;
110
128
  return {
111
- width: n(r?.clientWidth ?? window.innerWidth, e),
112
- height: n(r?.clientHeight ?? window.innerHeight, e)
129
+ width: r(n?.clientWidth ?? window.innerWidth, e),
130
+ height: r(n?.clientHeight ?? window.innerHeight, e)
113
131
  };
114
132
  }
115
- }, l = /* @__PURE__ */ new Set([
133
+ }, d = /* @__PURE__ */ new Set([
116
134
  "absolute",
117
135
  "fixed",
118
136
  "sticky"
119
137
  ]);
120
- function u(e, t, n) {
121
- let r = e.top != null || e.left != null || e.fixed === !0, i = l.has(getComputedStyle(e).position), a = null;
138
+ function f(e, t, n) {
139
+ let r = e.top != null || e.left != null || e.fixed === !0, i = d.has(getComputedStyle(e).position), a = null;
122
140
  if (!r && !i) a = "unplaced";
123
141
  else {
124
142
  let t = e.offsetParent;
@@ -127,4 +145,4 @@ function u(e, t, n) {
127
145
  return a !== null && (console.warn(a === "unplaced" ? `${t}: movable, but in normal flow — so the first drag has to pull it out, reflowing everything after it on the page. State the origin in system px and it never was in flow: ${n}` : `${t}: the positioning parent has no box, so there is nowhere to drag to. Give it a size (and \`position: relative\`, if it is not a kit container) — the clamp is falling back to the viewport meanwhile.`), !0);
128
146
  }
129
147
  //#endregion
130
- export { c as PlacementController, o as VfPositioned, u as warnMovableContract };
148
+ export { u as PlacementController, s as VfPositioned, l as placementIn, f as warnMovableContract };
@@ -116,8 +116,15 @@ export declare class VfTextControlBase extends VfShadowRoleControl {
116
116
  * inner button, which runs the same transient-proxy path a pointer does. A
117
117
  * disabled default button means no submission at all, as in HTML; a form
118
118
  * with no submit button falls back to the bare call, also as in HTML.
119
+ *
120
+ * Returns whether a form owner took the press — true even when a disabled
121
+ * default button meant no submission, since HTML gave the press to the form
122
+ * either way. The callers cancel the keydown on true, so a modal shell
123
+ * (`VfModalDialog`) sees the press as spoken for and does not also route it
124
+ * to the dialog's default button; with no form the press goes on to the
125
+ * dialog untouched.
119
126
  */
120
- protected requestImplicitSubmit(): void;
127
+ protected requestImplicitSubmit(): boolean;
121
128
  /**
122
129
  * Dispatch a bubbling, composed value event (SPEC §4). Text fields use the
123
130
  * default `{ value }` detail; `vf-number-field` passes an enriched detail that
@@ -56,14 +56,9 @@ var l = class extends a {
56
56
  }
57
57
  requestImplicitSubmit() {
58
58
  let e = this.internals.form;
59
- if (!e) return;
59
+ if (!e) return !1;
60
60
  let t = [...e.elements].find((e) => e instanceof HTMLButtonElement && e.type === "submit" || e instanceof HTMLInputElement && (e.type === "submit" || e.type === "image") || e.localName === "vf-button" && e.type?.toLowerCase() === "submit");
61
- if (t) {
62
- if (t.matches(":disabled")) return;
63
- t.click();
64
- return;
65
- }
66
- e.requestSubmit();
61
+ return t ? (t.matches(":disabled") || t.click(), !0) : (e.requestSubmit(), !0);
67
62
  }
68
63
  emitValue(t, n = { value: this.value }) {
69
64
  e(this, t, n);