vintage-frames 0.9.0 → 0.10.1

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.
@@ -6,6 +6,7 @@ import { VfPositioned as a } from "../position.js";
6
6
  import { vfBase as o } from "../styles/recipes/host.js";
7
7
  import { DocumentListenersController as s } from "../document-listeners.js";
8
8
  import { VfSized as c } from "../size.js";
9
+ import "../motion.js";
9
10
  import { paintSelectionRect as l, penPhase as u } from "../open-art.js";
10
11
  import { LitElement as d, css as f, html as p } from "lit";
11
12
  import { property as m } from "lit/decorators.js";
@@ -48,34 +49,52 @@ var h = (e, t, n) => Math.min(Math.max(e, t), n), g = class extends c(a(d)) {
48
49
  #e;
49
50
  #t;
50
51
  #n;
52
+ #r;
53
+ #i;
54
+ #a;
55
+ #o;
51
56
  constructor() {
52
57
  super(), this.label = "", this.scale = new n(this), this.#e = this.attachInternals(), this.#t = null, this.#n = new s(this, () => [[
53
58
  document,
54
59
  "keydown",
55
- this.#l,
60
+ this.#p,
61
+ !0
62
+ ]]), this.#r = null, this.#i = new s(this, () => [[
63
+ document,
64
+ "pointerdown",
65
+ this.#a,
66
+ !0
67
+ ], [
68
+ document,
69
+ "keydown",
70
+ this.#o,
56
71
  !0
57
- ]]), this.#r = () => {
58
- this.#i();
72
+ ]]), this.#a = () => {
73
+ this.#S();
59
74
  }, this.#o = (e) => {
75
+ e.key !== "Escape" || !this.#r || (e.preventDefault(), e.stopPropagation(), this.#S());
76
+ }, this.#s = () => {
77
+ this.#c();
78
+ }, this.#u = (e) => {
60
79
  if (this.#t || e.button !== 0 || e.target !== this) return;
61
80
  let t = this.getBoundingClientRect();
62
81
  if (t.width <= 0 || t.height <= 0) return;
63
- let n = r(this), i = this.#f(t, n);
82
+ let n = r(this), i = this.#g(t, n);
64
83
  this.#t = {
65
84
  pointerId: e.pointerId,
66
85
  box: t,
67
86
  reach: i,
68
- origin: this.#d(e, t, n, i),
69
- screen: this.#p(t, n),
70
- anchor: new Set(this.#a().filter((e) => e.selected)),
87
+ origin: this.#h(e, t, n, i),
88
+ screen: this.#_(t, n),
89
+ anchor: new Set(this.#l().filter((e) => e.selected)),
71
90
  rect: null,
72
91
  canvas: null,
73
92
  phase: -1
74
93
  }, this.setPointerCapture(e.pointerId), e.preventDefault();
75
- }, this.#s = (e) => {
94
+ }, this.#d = (e) => {
76
95
  let t = this.#t;
77
96
  if (!t || e.pointerId !== t.pointerId) return;
78
- let n = r(this), i = this.#d(e, t.box, n, t.reach);
97
+ let n = r(this), i = this.#h(e, t.box, n, t.reach);
79
98
  if (!t.rect && i.x === t.origin.x && i.y === t.origin.y) return;
80
99
  let a = {
81
100
  x: Math.min(t.origin.x, i.x),
@@ -83,46 +102,46 @@ var h = (e, t, n) => Math.min(Math.max(e, t), n), g = class extends c(a(d)) {
83
102
  width: Math.abs(i.x - t.origin.x),
84
103
  height: Math.abs(i.y - t.origin.y)
85
104
  }, o = t.rect;
86
- o && o.x === a.x && o.y === a.y && o.width === a.width && o.height === a.height || (o || (this.#n.attach(), t.canvas = this.#m(), this.renderRoot.append(t.canvas)), t.rect = a, this.#h(t, n), this.#g(t, n));
87
- }, this.#c = (e) => {
105
+ o && o.x === a.x && o.y === a.y && o.width === a.width && o.height === a.height || (o || (this.#n.attach(), t.canvas = this.#v(), this.renderRoot.append(t.canvas)), t.rect = a, this.#y(t, n), this.#b(t, n));
106
+ }, this.#f = (e) => {
88
107
  let t = this.#t;
89
- !t || e.pointerId !== t.pointerId || this.#u(e.type === "pointercancel");
90
- }, this.#l = (e) => {
91
- e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this.#u(!0));
92
- }, this.#e.role = "listbox", this.#e.ariaMultiSelectable = "true", this.addEventListener("pointerdown", this.#o), this.addEventListener("pointermove", this.#s), this.addEventListener("pointerup", this.#c), this.addEventListener("pointercancel", this.#c);
108
+ !t || e.pointerId !== t.pointerId || this.#m(e.type === "pointercancel");
109
+ }, this.#p = (e) => {
110
+ e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), this.#m(!0));
111
+ }, this.#e.role = "listbox", this.#e.ariaMultiSelectable = "true", this.addEventListener("pointerdown", this.#u), this.addEventListener("pointermove", this.#d), this.addEventListener("pointerup", this.#f), this.addEventListener("pointercancel", this.#f);
93
112
  }
94
113
  disconnectedCallback() {
95
- super.disconnectedCallback(), this.#t?.canvas?.remove(), this.#t = null;
114
+ super.disconnectedCallback(), this.#t?.canvas?.remove(), this.#t = null, this.#S();
96
115
  }
97
116
  updated(e) {
98
- e.has("label") && (this.#e.ariaLabel = this.label || null), e.has("size") && this.#i();
117
+ e.has("label") && (this.#e.ariaLabel = this.label || null), e.has("size") && this.#c();
99
118
  }
100
- #r;
101
- #i() {
119
+ #s;
120
+ #c() {
102
121
  let e = this.size;
103
122
  if (e != null) for (let t of this.querySelectorAll("vf-icon")) t.size !== e && (t.size = e);
104
123
  }
105
- #a() {
124
+ #l() {
106
125
  return [...this.querySelectorAll("vf-icon")].filter((e) => e.selectable);
107
126
  }
108
- #o;
109
- #s;
110
- #c;
111
- #l;
112
- #u(e) {
127
+ #u;
128
+ #d;
129
+ #f;
130
+ #p;
131
+ #m(e) {
113
132
  let t = this.#t;
114
- if (t && (this.#t = null, this.hasPointerCapture(t.pointerId) && this.releasePointerCapture(t.pointerId), t.rect && (this.#n.detach(), t.canvas?.remove(), e))) for (let e of this.#a()) {
133
+ if (t && (this.#t = null, this.hasPointerCapture(t.pointerId) && this.releasePointerCapture(t.pointerId), t.rect && (this.#n.detach(), t.canvas?.remove(), e))) for (let e of this.#l()) {
115
134
  let n = t.anchor.has(e);
116
135
  e.selected !== n && e.setSelected(n);
117
136
  }
118
137
  }
119
- #d(e, t, n, r) {
138
+ #h(e, t, n, r) {
120
139
  return {
121
140
  x: h(Math.round((e.clientX - t.left) / n), r.minX, r.maxX),
122
141
  y: h(Math.round((e.clientY - t.top) / n), r.minY, r.maxY)
123
142
  };
124
143
  }
125
- #f(e, t) {
144
+ #g(e, t) {
126
145
  let n = e.left, r = e.top, i = e.right, a = e.bottom, o = this.assignedSlot ?? this.parentNode;
127
146
  for (; o;) if (o instanceof Element) {
128
147
  let e = getComputedStyle(o);
@@ -140,7 +159,7 @@ var h = (e, t, n) => Math.min(Math.max(e, t), n), g = class extends c(a(d)) {
140
159
  maxY: Math.max(0, Math.floor(s((a - e.top) / t)))
141
160
  };
142
161
  }
143
- #p(t, n) {
162
+ #_(t, n) {
144
163
  let r = { surface: null };
145
164
  if (e(this, "vf-drag-surface-request", r, { composed: !1 }), !r.surface) return {
146
165
  x: 0,
@@ -152,19 +171,19 @@ var h = (e, t, n) => Math.min(Math.max(e, t), n), g = class extends c(a(d)) {
152
171
  y: Math.round((t.top - i.top) / n)
153
172
  };
154
173
  }
155
- #m() {
174
+ #v() {
156
175
  let e = document.createElement("canvas");
157
176
  e.className = "selection-rect";
158
177
  let t = e.style;
159
178
  return t.position = "fixed", t.display = "block", t.pointerEvents = "none", t.filter = "invert(1)", t.mixBlendMode = "difference", t.imageRendering = "pixelated", e;
160
179
  }
161
- #h(e, t) {
180
+ #y(e, t) {
162
181
  let { rect: n, canvas: r } = e;
163
182
  if (!n || !r) return;
164
183
  let i = Math.max(1, n.width), a = Math.max(1, n.height), o = u(e.screen.x + n.x, e.screen.y + n.y);
165
184
  l(r, i, a, o), e.phase = o, r.style.left = `${e.box.left + n.x * t}px`, r.style.top = `${e.box.top + n.y * t}px`, r.style.width = `${i * t}px`, r.style.height = `${a * t}px`;
166
185
  }
167
- #g(e, t) {
186
+ #b(e, t) {
168
187
  let { rect: n } = e;
169
188
  if (!n) return;
170
189
  let r = {
@@ -173,13 +192,53 @@ var h = (e, t, n) => Math.min(Math.max(e, t), n), g = class extends c(a(d)) {
173
192
  right: e.box.left + (n.x + Math.max(1, n.width)) * t,
174
193
  bottom: e.box.top + (n.y + Math.max(1, n.height)) * t
175
194
  };
176
- for (let t of this.#a()) {
195
+ for (let t of this.#l()) {
177
196
  let n = e.anchor.has(t) !== t.touches(r);
178
197
  t.selected !== n && t.setSelected(n);
179
198
  }
180
199
  }
200
+ dragIcons(e) {
201
+ this.#S();
202
+ let t = {
203
+ queue: [...e],
204
+ beat: null,
205
+ finished: !1,
206
+ settle: () => {}
207
+ }, n = new Promise((e) => {
208
+ t.settle = e;
209
+ });
210
+ return this.#r = t, this.#i.attach(), this.#x(t), n;
211
+ }
212
+ async #x(e) {
213
+ for (; !e.finished && e.queue.length > 0;) {
214
+ let t = e.queue[0];
215
+ if (!t) break;
216
+ let { icon: n, left: r, top: i } = t, a = n.isConnected ? await n.dragTo(r, i) : !1;
217
+ if (e.finished) return;
218
+ e.queue.shift(), !(!a || e.queue.length === 0) && await new Promise((t) => {
219
+ let n = window.setTimeout(() => {
220
+ e.beat = null, t();
221
+ }, 50);
222
+ e.beat = () => {
223
+ window.clearTimeout(n), e.beat = null, t();
224
+ };
225
+ });
226
+ }
227
+ this.#C(e);
228
+ }
229
+ #S() {
230
+ let e = this.#r;
231
+ if (e) {
232
+ e.beat?.();
233
+ for (let { icon: t, left: n, top: r } of e.queue) t.isConnected && t.moveTo(n, r);
234
+ e.queue.length = 0, this.#C(e);
235
+ }
236
+ }
237
+ #C(e) {
238
+ e.finished || (e.finished = !0, this.#r === e && (this.#r = null, this.#i.detach()), e.settle());
239
+ }
181
240
  render() {
182
- return p`<slot @slotchange=${this.#r}></slot>`;
241
+ return p`<slot @slotchange=${this.#s}></slot>`;
183
242
  }
184
243
  };
185
244
  i([m()], g.prototype, "label", void 0), i([m({ reflect: !0 })], g.prototype, "size", void 0), g = i([t("vf-icon-field")], g);
@@ -226,7 +226,8 @@ declare const VfIcon_base: (new (...args: any[]) => import("../position.js").VfP
226
226
  * changed the snapped proposal;
227
227
  * - `vf-drop`, the same shape at the release, **cancelable**: its default
228
228
  * action is the move, the proposal written through `left`/`top` and
229
- * clamped whole in the container measured at the press. `preventDefault()`
229
+ * clamped whole in the container measured at the press — held at the
230
+ * origin only in a scrolling plane, whose rails reach the rest. `preventDefault()`
230
231
  * writes nothing — the page re-parents or places the icon itself, the
231
232
  * outline's origin converted with the destination's `placementAt`;
232
233
  * - `vf-drag-cancel` `{}` on Escape or a `pointercancel`: nothing written.
@@ -270,6 +271,33 @@ declare const VfIcon_base: (new (...args: any[]) => import("../position.js").VfP
270
271
  * under `color` — with none of `selected`'s semantics: no event, no outside
271
272
  * listener, no `aria-selected`, the plate untouched.
272
273
  *
274
+ * ### The page drags it too
275
+ *
276
+ * The Finder's Clean Up walked a container's icons one at a time, each
277
+ * icon's outline travelling from where it sat to its cell and the icon
278
+ * landing when the outline arrived — the drag's own vocabulary, with the
279
+ * Finder for a hand. {@link dragTo} is that move for one icon: the outline
280
+ * built and placed as a drag's is, on the desktop's surface or in the frame,
281
+ * stepped to the landing at the walk's cadence ({@link runOutlineTravel},
282
+ * src/motion.ts — the kit's, no knobs), then the outline down and the icon
283
+ * written where a drop would write it. The landing is resolved before the
284
+ * outline sets off, so the outline goes where the icon will land rather
285
+ * than where a pair past the container's edge pointed. {@link moveTo} is
286
+ * that write alone: the drop's clamp and snap, one `vf-placement-change` —
287
+ * where a property set is the authored pair, unclamped. Neither fires a
288
+ * drag event (the page is the mover and already knows) and neither needs
289
+ * `movable`, which says the hand may drag: the page may always place its
290
+ * icon. `vf-icon-field.dragIcons` walks a set through `dragTo` with the
291
+ * Finder's beat between landings.
292
+ *
293
+ * A walk is finished, never cancelled: a press anywhere, or Escape, lands
294
+ * the icon at once — the user wants the machine back, and the move was the
295
+ * page's to make. A second `dragTo`, or a `moveTo`, finishes the one in
296
+ * flight the same way; leaving the DOM takes the outline down and writes
297
+ * nothing. Under `prefers-reduced-motion` the icon lands at once with no
298
+ * outline, the blink's posture — as does one being renamed, or one under
299
+ * the hand's own press.
300
+ *
273
301
  * Opening gets the same treatment. The double-click is the pointer gesture,
274
302
  * and its keyboard route is ⌘O / ⌘↓ — the System 7 Open shortcuts, with Ctrl
275
303
  * standing in for ⌘ off the Mac. Return is deliberately not one of them: the
@@ -564,6 +592,25 @@ export declare class VfIcon extends VfIcon_base {
564
592
  right: number;
565
593
  bottom: number;
566
594
  }): boolean;
595
+ /**
596
+ * Place the icon as a drop would: the stated pair — the origin point
597
+ * under an `origin`, the corner without one — clamped whole in the
598
+ * container measured now (held at the origin only in a scrolling plane),
599
+ * snapped onto the lattice, announced as one `vf-placement-change`. A
600
+ * `left`/`top` write is the authored pair, unclamped; this is the
601
+ * gesture's. Finishes a walk in flight first.
602
+ */
603
+ moveTo(left: number, top: number): void;
604
+ /**
605
+ * Move the icon the way a drag moves it (see the class doc): its outline
606
+ * travels from where it sits to where it will land, and the icon lands
607
+ * when the outline arrives, written as {@link moveTo} writes. Resolves
608
+ * once it has landed — to whether the outline travelled; false when the
609
+ * icon landed at once: already there, `prefers-reduced-motion`, nothing
610
+ * to draw the outline with, or not in the DOM (nothing written then).
611
+ * Fires no drag event. A walk already in flight here is finished first.
612
+ */
613
+ dragTo(left: number, top: number): Promise<boolean>;
567
614
  }
568
615
  declare global {
569
616
  interface HTMLElementTagNameMap {