beam-alpha 0.1.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.
- package/README.md +114 -0
- package/bin/blueprint.mjs +7 -0
- package/dist/beam.js +3272 -0
- package/dist/canvas/assets/AzeretMono-C5fM7CrN.woff2 +0 -0
- package/dist/canvas/assets/OpenRunde-Bold-DS-_1xH5.woff2 +0 -0
- package/dist/canvas/assets/OpenRunde-Medium-Krf-ZDqK.woff2 +0 -0
- package/dist/canvas/assets/OpenRunde-Regular-BZVnpUN1.woff2 +0 -0
- package/dist/canvas/assets/OpenRunde-Semibold-Nru5tuSm.woff2 +0 -0
- package/dist/canvas/assets/index-BIsbDeNY.css +1 -0
- package/dist/canvas/assets/index.embed-CE8oqNgH.js +230 -0
- package/dist/canvas/index.html +16 -0
- package/dist/cli.js +678 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +8663 -0
- package/dist/next/pin-loader.cjs +120 -0
- package/dist/next/source-loader.cjs +137 -0
- package/dist/next.d.ts +60 -0
- package/dist/next.js +8896 -0
- package/dist/overlay/overlay.css +1 -0
- package/dist/overlay/overlay.js +219 -0
- package/dist/probe.js +3084 -0
- package/dist/runtime/core.d.ts +43 -0
- package/dist/runtime/core.js +36 -0
- package/dist/runtime/core.prod.js +19 -0
- package/dist/runtime/react.d.ts +16 -0
- package/dist/runtime/react.js +48 -0
- package/dist/runtime/react.prod.js +17 -0
- package/package.json +67 -0
package/dist/probe.js
ADDED
|
@@ -0,0 +1,3084 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
// ../../node_modules/torph/dist/index.mjs
|
|
4
|
+
var _t = { locale: "en", duration: 400, ease: "cubic-bezier(0.19, 1, 0.22, 1)", disabled: false, respectReducedMotion: true };
|
|
5
|
+
function Dt(e, t, n) {
|
|
6
|
+
if (n < 1) {
|
|
7
|
+
let u = t * Math.sqrt(1 - n * n);
|
|
8
|
+
return 1 - Math.exp(-n * t * e) * (Math.cos(u * e) + n * t / u * Math.sin(u * e));
|
|
9
|
+
}
|
|
10
|
+
let i = Math.sqrt(n * n - 1), r = -t * (n + i), s = -t * (n - i), o = -r / (s - r);
|
|
11
|
+
return 1 - (1 - o) * Math.exp(r * e) - o * Math.exp(s * e);
|
|
12
|
+
}
|
|
13
|
+
function Ie(e, t, n) {
|
|
14
|
+
let s = 0;
|
|
15
|
+
for (let o = 0; o < 10; o += 1e-3) if (Math.abs(Dt(o, e, t) - 1) > n) s = 0;
|
|
16
|
+
else if (s += 1e-3, s > 0.1) return Math.ceil((o - s + 1e-3) * 1e3);
|
|
17
|
+
return Math.ceil(10 * 1e3);
|
|
18
|
+
}
|
|
19
|
+
function Ft(e, t) {
|
|
20
|
+
if (typeof e == "object") {
|
|
21
|
+
let n = Le(e);
|
|
22
|
+
return { ease: n.easing, duration: n.duration };
|
|
23
|
+
}
|
|
24
|
+
return { ease: e, duration: t };
|
|
25
|
+
}
|
|
26
|
+
var $t = /* @__PURE__ */ new Map();
|
|
27
|
+
function Le(e) {
|
|
28
|
+
let { stiffness: t = 100, damping: n = 10, mass: i = 1, precision: r = 1e-3 } = e ?? {}, s = `${t}:${n}:${i}:${r}`, o = $t.get(s);
|
|
29
|
+
if (o) return o;
|
|
30
|
+
let a = Math.sqrt(t / i), u = n / (2 * Math.sqrt(t * i)), c = Ie(a, u, r), f = Math.min(100, Math.max(32, Math.round(c / 15))), l = [];
|
|
31
|
+
for (let d = 0; d < f; d++) {
|
|
32
|
+
let h = d / (f - 1) * (c / 1e3), M = d === f - 1 ? 1 : Dt(h, a, u);
|
|
33
|
+
l.push(Math.round(M * 1e4) / 1e4 + "");
|
|
34
|
+
}
|
|
35
|
+
for (; l.length > 2 && l[l.length - 2] === "1"; ) l.splice(l.length - 2, 1);
|
|
36
|
+
let m = { easing: `linear(${l.join(", ")})`, duration: c };
|
|
37
|
+
return $t.set(s, m), m;
|
|
38
|
+
}
|
|
39
|
+
function G(e, t) {
|
|
40
|
+
let n = e.length, i = t.length, r = Array.from({ length: n + 1 }, () => Array(i + 1).fill(0));
|
|
41
|
+
for (let c = n - 1; c >= 0; c--) for (let f = i - 1; f >= 0; f--) r[c][f] = e[c] === t[f] ? r[c + 1][f + 1] + 1 : Math.max(r[c + 1][f], r[c][f + 1]);
|
|
42
|
+
let s = [], o = [], a = 0, u = 0;
|
|
43
|
+
for (; a < n && u < i; ) e[a] === t[u] ? (s.push(a), o.push(u), a++, u++) : r[a + 1][u] >= r[a][u + 1] ? a++ : u++;
|
|
44
|
+
return [s, o];
|
|
45
|
+
}
|
|
46
|
+
var Ne = "\0n";
|
|
47
|
+
var ke = 0;
|
|
48
|
+
function ht() {
|
|
49
|
+
return `${Ne}${ke++}`;
|
|
50
|
+
}
|
|
51
|
+
function k(e) {
|
|
52
|
+
return e >= "0" && e <= "9";
|
|
53
|
+
}
|
|
54
|
+
function q(e) {
|
|
55
|
+
for (let t of e) if (k(t)) return true;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function gt(e) {
|
|
59
|
+
let t = "";
|
|
60
|
+
for (let n of e) !k(n) && !bt.includes(n) && (t += n);
|
|
61
|
+
return t;
|
|
62
|
+
}
|
|
63
|
+
var bt = ".,'\xA0\u202F\u2009\u2007";
|
|
64
|
+
var He = "+-\u2212(#";
|
|
65
|
+
var Oe = `%.,!?:;)"'\u201D\u2019`;
|
|
66
|
+
var _e = new RegExp("\\p{Sc}", "u");
|
|
67
|
+
function Pt(e, t) {
|
|
68
|
+
return t.includes(e) || _e.test(e);
|
|
69
|
+
}
|
|
70
|
+
function J(e) {
|
|
71
|
+
let t = 0, n = e.length;
|
|
72
|
+
for (; t < n && Pt(e[t], He); ) t++;
|
|
73
|
+
for (; n > t && Pt(e[n - 1], Oe); ) n--;
|
|
74
|
+
if (t >= n || !k(e[t]) || !k(e[n - 1])) return false;
|
|
75
|
+
for (let i = t; i < n; i++) {
|
|
76
|
+
let r = e[i];
|
|
77
|
+
if (!k(r) && !bt.includes(r)) return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
function at(e) {
|
|
82
|
+
return k(e) ? "digit" : "symbol";
|
|
83
|
+
}
|
|
84
|
+
var Ct = /* @__PURE__ */ new Map();
|
|
85
|
+
function xt(e) {
|
|
86
|
+
let t = String(e), n = Ct.get(t);
|
|
87
|
+
if (n) return n;
|
|
88
|
+
let i = ".";
|
|
89
|
+
try {
|
|
90
|
+
i = new Intl.NumberFormat(e).formatToParts(1.1).find((r) => r.type === "decimal")?.value ?? ".";
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
return Ct.set(t, i), i;
|
|
94
|
+
}
|
|
95
|
+
function U(e, t, n, i = ".") {
|
|
96
|
+
let r = e.split("");
|
|
97
|
+
if (!t || t.length === 0) return $e(r);
|
|
98
|
+
let s = t.map((c) => c.string === "\xA0" ? " " : c.string), o = n != null ? De(s, r, n, i) : Fe(s, r, i), a = /* @__PURE__ */ new Set();
|
|
99
|
+
for (let [, c] of o) a.add(t[c].id);
|
|
100
|
+
let u = [];
|
|
101
|
+
for (let c = 0; c < r.length; c++) {
|
|
102
|
+
let f = r[c], l = at(f), m = f === " " ? "\xA0" : f;
|
|
103
|
+
if (o.has(c)) {
|
|
104
|
+
let d = o.get(c);
|
|
105
|
+
u.push({ id: t[d].id, string: m, kind: l });
|
|
106
|
+
} else {
|
|
107
|
+
let d = ht();
|
|
108
|
+
for (; a.has(d); ) d = ht();
|
|
109
|
+
a.add(d), u.push({ id: d, string: m, kind: l });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return u;
|
|
113
|
+
}
|
|
114
|
+
function $e(e) {
|
|
115
|
+
return e.map((t) => ({ id: ht(), string: t === " " ? "\xA0" : t, kind: at(t) }));
|
|
116
|
+
}
|
|
117
|
+
function De(e, t, n, i) {
|
|
118
|
+
let r = /* @__PURE__ */ new Map(), s = Xt(e, i), o = Xt(t, i), a = (m, d) => r.set(o[m], s[d]), u = 0;
|
|
119
|
+
for (; u < o.length && o[u] < n; ) u++;
|
|
120
|
+
let c = o.length - s.length;
|
|
121
|
+
if (c > 0) {
|
|
122
|
+
let m = u - c;
|
|
123
|
+
for (let d = 0; d < m && d < s.length; d++) a(d, d);
|
|
124
|
+
for (let d = u; d < o.length; d++) {
|
|
125
|
+
let h = d - c;
|
|
126
|
+
h >= 0 && h < s.length && a(d, h);
|
|
127
|
+
}
|
|
128
|
+
} else if (c < 0) {
|
|
129
|
+
for (let m = 0; m < u && m < o.length; m++) a(m, m);
|
|
130
|
+
for (let m = u; m < o.length; m++) {
|
|
131
|
+
let d = m - c;
|
|
132
|
+
d >= 0 && d < s.length && a(m, d);
|
|
133
|
+
}
|
|
134
|
+
} else for (let m = 0; m < o.length; m++) t[o[m]] === e[s[m]] && a(m, m);
|
|
135
|
+
let f = Bt(e, i), l = Bt(t, i);
|
|
136
|
+
for (let m = 1; m <= f.length && m <= l.length; m++) {
|
|
137
|
+
let d = f[f.length - m], h = l[l.length - m];
|
|
138
|
+
e[d] === t[h] && r.set(h, d);
|
|
139
|
+
}
|
|
140
|
+
return r;
|
|
141
|
+
}
|
|
142
|
+
function Kt(e, t) {
|
|
143
|
+
return e !== t && bt.includes(e);
|
|
144
|
+
}
|
|
145
|
+
function Xt(e, t) {
|
|
146
|
+
let n = [];
|
|
147
|
+
for (let i = 0; i < e.length; i++) Kt(e[i], t) || n.push(i);
|
|
148
|
+
return n;
|
|
149
|
+
}
|
|
150
|
+
function Bt(e, t) {
|
|
151
|
+
let n = [];
|
|
152
|
+
for (let i = 0; i < e.length; i++) Kt(e[i], t) && n.push(i);
|
|
153
|
+
return n;
|
|
154
|
+
}
|
|
155
|
+
function Fe(e, t, n) {
|
|
156
|
+
let i = /* @__PURE__ */ new Map(), r = 0;
|
|
157
|
+
for (; r < e.length && r < t.length && e[r] === t[r] && !k(e[r]); ) i.set(r, r), r++;
|
|
158
|
+
let s = e.length, o = t.length;
|
|
159
|
+
for (; s > r && o > r && e[s - 1] === t[o - 1] && !k(e[s - 1]); ) i.set(o - 1, s - 1), s--, o--;
|
|
160
|
+
let a = Ut(e, r, s, n), u = Ut(t, r, o, n), c = Gt(e, r, a), f = Gt(t, r, u);
|
|
161
|
+
if (c > 0 && f > 0 && Math.abs(c - f) >= Pe) return i;
|
|
162
|
+
if (!d(r, a, r, u, true)) for (let h = 1; a - h >= r && u - h >= r; h++) m(a - h, u - h);
|
|
163
|
+
if (a < s && u < o) {
|
|
164
|
+
i.set(u, a);
|
|
165
|
+
for (let h = 1; a + h < s && u + h < o; h++) m(a + h, u + h);
|
|
166
|
+
d(a + 1, s, u + 1, o, false);
|
|
167
|
+
}
|
|
168
|
+
function m(h, M) {
|
|
169
|
+
let x = e[h];
|
|
170
|
+
k(x) || x === t[M] && i.set(M, h);
|
|
171
|
+
}
|
|
172
|
+
function d(h, M, x, T, L) {
|
|
173
|
+
let E = Wt(e, h, M), N = Wt(t, x, T);
|
|
174
|
+
if (E.length === N.length || !L) {
|
|
175
|
+
let A = Math.min(E.length, N.length);
|
|
176
|
+
for (let _ = 0; _ < A; _++) {
|
|
177
|
+
let B = E[_], rt = N[_];
|
|
178
|
+
e[B] === t[rt] && i.set(rt, B);
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
let g = E.map((A) => e[A]).reverse(), v = N.map((A) => t[A]).reverse(), [R, O] = G(g, v);
|
|
183
|
+
for (let A = 0; A < R.length; A++) {
|
|
184
|
+
let _ = E[E.length - 1 - R[A]], B = N[N.length - 1 - O[A]];
|
|
185
|
+
i.set(B, _);
|
|
186
|
+
}
|
|
187
|
+
return R.length > 0;
|
|
188
|
+
}
|
|
189
|
+
return i;
|
|
190
|
+
}
|
|
191
|
+
function Wt(e, t, n) {
|
|
192
|
+
let i = [];
|
|
193
|
+
for (let r = t; r < n; r++) k(e[r]) && i.push(r);
|
|
194
|
+
return i;
|
|
195
|
+
}
|
|
196
|
+
var Pe = 3;
|
|
197
|
+
function Gt(e, t, n) {
|
|
198
|
+
let i = 0;
|
|
199
|
+
for (let r = t; r < n; r++) k(e[r]) && i++;
|
|
200
|
+
return i;
|
|
201
|
+
}
|
|
202
|
+
function Ut(e, t, n, i) {
|
|
203
|
+
for (let r = n - 1; r >= t; r--) if (e[r] === i) return r;
|
|
204
|
+
return n;
|
|
205
|
+
}
|
|
206
|
+
function yt() {
|
|
207
|
+
let e = /* @__PURE__ */ new Set();
|
|
208
|
+
return { reserve(t) {
|
|
209
|
+
e.add(t);
|
|
210
|
+
}, has(t) {
|
|
211
|
+
return e.has(t);
|
|
212
|
+
}, take(t) {
|
|
213
|
+
if (!e.has(t)) return e.add(t), t;
|
|
214
|
+
let n = 1;
|
|
215
|
+
for (; e.has(`${t}~${n}`); ) n++;
|
|
216
|
+
let i = `${t}~${n}`;
|
|
217
|
+
return e.add(i), i;
|
|
218
|
+
} };
|
|
219
|
+
}
|
|
220
|
+
function zt(e) {
|
|
221
|
+
let t = [], n = [], i = () => {
|
|
222
|
+
n.length !== 0 && (t.push({ word: n.map((r) => r.string).join(""), segments: n }), n = []);
|
|
223
|
+
};
|
|
224
|
+
for (let r of e) r.string === "\xA0" || r.string === `
|
|
225
|
+
` ? i() : n.push(r);
|
|
226
|
+
return i(), t;
|
|
227
|
+
}
|
|
228
|
+
function Yt(e) {
|
|
229
|
+
let t = [], n = [], i = () => {
|
|
230
|
+
if (n.length === 0) return;
|
|
231
|
+
let r = n.map((s) => s.string).join("");
|
|
232
|
+
J(r) ? t.push(...U(r)) : t.push(...n), n = [];
|
|
233
|
+
};
|
|
234
|
+
for (let r of e) r.string === "\xA0" || r.string === `
|
|
235
|
+
` ? (i(), t.push(r)) : n.push(r);
|
|
236
|
+
return i(), t;
|
|
237
|
+
}
|
|
238
|
+
function K(e, t, n = true) {
|
|
239
|
+
let i = e.includes(`
|
|
240
|
+
`), r = e.includes(" ") || i, s = yt();
|
|
241
|
+
if (i) {
|
|
242
|
+
let a = e.split(`
|
|
243
|
+
`), u = [], c = 0;
|
|
244
|
+
return a.forEach((f, l) => {
|
|
245
|
+
l > 0 && (u.push({ id: s.take(`newline-${c}`), string: `
|
|
246
|
+
` }), c += 1), f.length > 0 && u.push(...jt(f, t, true, c, s)), c += f.length;
|
|
247
|
+
}), n ? Yt(u) : u;
|
|
248
|
+
}
|
|
249
|
+
let o = jt(e, t, r, 0, s);
|
|
250
|
+
return n ? Yt(o) : o;
|
|
251
|
+
}
|
|
252
|
+
function jt(e, t, n, i, r) {
|
|
253
|
+
if (typeof Intl.Segmenter < "u") {
|
|
254
|
+
let s = new Intl.Segmenter(t, { granularity: n ? "word" : "grapheme" });
|
|
255
|
+
return Ce(s.segment(e)[Symbol.iterator](), i, r);
|
|
256
|
+
}
|
|
257
|
+
return Xe(e, n, i, r);
|
|
258
|
+
}
|
|
259
|
+
function Ce(e, t, n) {
|
|
260
|
+
let i = [];
|
|
261
|
+
for (let r of Array.from(e)) {
|
|
262
|
+
let s = t + r.index;
|
|
263
|
+
r.segment === " " ? i.push({ id: n.take(`space-${s}`), string: "\xA0" }) : i.push({ id: qt(r.segment, s, n), string: r.segment });
|
|
264
|
+
}
|
|
265
|
+
return i;
|
|
266
|
+
}
|
|
267
|
+
function qt(e, t, n) {
|
|
268
|
+
return n.has(e) ? n.take(`${e}-${t}`) : n.take(e);
|
|
269
|
+
}
|
|
270
|
+
function Xe(e, t, n, i) {
|
|
271
|
+
let r = t ? e.split(" ") : e.split(""), s = [], o = n;
|
|
272
|
+
return r.forEach((a, u) => {
|
|
273
|
+
t && u > 0 && (s.push({ id: i.take(`space-${o}`), string: "\xA0" }), o += 1), s.push({ id: qt(a, o, i), string: a }), o += a.length;
|
|
274
|
+
}), s;
|
|
275
|
+
}
|
|
276
|
+
var Y = "torph-root";
|
|
277
|
+
var Q = "torph-item";
|
|
278
|
+
var w = "torph-id";
|
|
279
|
+
var V = "torph-kind";
|
|
280
|
+
var F = "torph-slot";
|
|
281
|
+
var H = "torph-exiting";
|
|
282
|
+
var P = "torph-sr";
|
|
283
|
+
var Z = "torph-debug";
|
|
284
|
+
var tt = "empty";
|
|
285
|
+
var Be = { linear: [0, 0, 1, 1], ease: [0.25, 0.1, 0.25, 1], "ease-in": [0.42, 0, 1, 1], "ease-out": [0, 0, 0.58, 1], "ease-in-out": [0.42, 0, 0.58, 1] };
|
|
286
|
+
var Jt = (e, t, n) => {
|
|
287
|
+
let i = 1 - n;
|
|
288
|
+
return 3 * i * i * n * e + 3 * i * n * n * t + n * n * n;
|
|
289
|
+
};
|
|
290
|
+
function Qt(e, t, n, i) {
|
|
291
|
+
return (r) => {
|
|
292
|
+
if (r <= 0) return 0;
|
|
293
|
+
if (r >= 1) return 1;
|
|
294
|
+
let s = 0, o = 1;
|
|
295
|
+
for (let a = 0; a < 24; a += 1) {
|
|
296
|
+
let u = (s + o) / 2;
|
|
297
|
+
Jt(e, n, u) < r ? s = u : o = u;
|
|
298
|
+
}
|
|
299
|
+
return Jt(t, i, (s + o) / 2);
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function We(e) {
|
|
303
|
+
let t = [...e];
|
|
304
|
+
(t[0] === null || t[0] === void 0) && (t[0] = 0), t[t.length - 1] === null && (t[t.length - 1] = 1);
|
|
305
|
+
for (let n = 1; n < t.length; n += 1) {
|
|
306
|
+
if (t[n] !== null) continue;
|
|
307
|
+
let i = n;
|
|
308
|
+
for (; t[i] === null; ) i += 1;
|
|
309
|
+
let r = t[n - 1], s = (t[i] - r) / (i - n + 1);
|
|
310
|
+
for (let o = n; o < i; o += 1) t[o] = r + s * (o - n + 1);
|
|
311
|
+
}
|
|
312
|
+
return t.map((n, i, r) => i === 0 ? n : Math.max(n, r[i - 1]));
|
|
313
|
+
}
|
|
314
|
+
function Ge(e) {
|
|
315
|
+
let t = [], n = [];
|
|
316
|
+
for (let r of e.split(",")) {
|
|
317
|
+
let s = r.trim().split(/\s+/).filter(Boolean), o = Number(s[0]);
|
|
318
|
+
if (!Number.isFinite(o)) return null;
|
|
319
|
+
let a = s.slice(1);
|
|
320
|
+
if (a.length > 2) return null;
|
|
321
|
+
if (a.length === 0) {
|
|
322
|
+
t.push(o), n.push(null);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
for (let u of a) {
|
|
326
|
+
if (!u.endsWith("%")) return null;
|
|
327
|
+
let c = Number(u.slice(0, -1));
|
|
328
|
+
if (!Number.isFinite(c)) return null;
|
|
329
|
+
t.push(o), n.push(c / 100);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (t.length < 2) return null;
|
|
333
|
+
let i = We(n);
|
|
334
|
+
return (r) => {
|
|
335
|
+
if (r <= i[0]) return t[0];
|
|
336
|
+
let s = i.length - 1;
|
|
337
|
+
if (r >= i[s]) return t[s];
|
|
338
|
+
let o = 0;
|
|
339
|
+
for (; o < s && i[o + 1] < r; ) o += 1;
|
|
340
|
+
let a = i[o + 1] - i[o];
|
|
341
|
+
return a === 0 ? t[o + 1] : t[o] + (t[o + 1] - t[o]) * (r - i[o]) / a;
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function Vt(e) {
|
|
345
|
+
let t = e.trim().toLowerCase(), n = Be[t];
|
|
346
|
+
if (n) return Qt(...n);
|
|
347
|
+
let i = /^cubic-bezier\(([^)]*)\)$/.exec(t);
|
|
348
|
+
if (i) {
|
|
349
|
+
let s = i[1].split(",").map((o) => Number(o.trim()));
|
|
350
|
+
return s.length !== 4 || s.some((o) => !Number.isFinite(o)) ? null : Qt(s[0], s[1], s[2], s[3]);
|
|
351
|
+
}
|
|
352
|
+
let r = /^linear\(([^)]*)\)$/.exec(t);
|
|
353
|
+
return r ? Ge(r[1]) : null;
|
|
354
|
+
}
|
|
355
|
+
var St = 1e-4;
|
|
356
|
+
function Mt(e, t) {
|
|
357
|
+
let n = Math.min(Math.max(t, 0), 1 - St);
|
|
358
|
+
return (e(n + St) - e(n)) / St;
|
|
359
|
+
}
|
|
360
|
+
function lt(e, t) {
|
|
361
|
+
return e * t;
|
|
362
|
+
}
|
|
363
|
+
function X(e) {
|
|
364
|
+
let t = getComputedStyle(e).transform;
|
|
365
|
+
if (!t || t === "none") return { tx: 0, ty: 0 };
|
|
366
|
+
let n = t.match(/matrix\(([^)]+)\)/);
|
|
367
|
+
if (!n) return { tx: 0, ty: 0 };
|
|
368
|
+
let i = n[1].split(",").map(Number);
|
|
369
|
+
return { tx: i[4] || 0, ty: i[5] || 0 };
|
|
370
|
+
}
|
|
371
|
+
function et(e) {
|
|
372
|
+
let t = getComputedStyle(e), n = parseFloat(t.width), i = parseFloat(t.height);
|
|
373
|
+
if (Number.isNaN(n) || Number.isNaN(i)) {
|
|
374
|
+
let r = e.getBoundingClientRect();
|
|
375
|
+
return { width: r.width, height: r.height };
|
|
376
|
+
}
|
|
377
|
+
return { width: n, height: i };
|
|
378
|
+
}
|
|
379
|
+
function j(e) {
|
|
380
|
+
let { tx: t, ty: n } = X(e), i = Number(getComputedStyle(e).opacity) || 1;
|
|
381
|
+
return e.getAnimations().forEach((r) => r.cancel()), { tx: t, ty: n, opacity: i };
|
|
382
|
+
}
|
|
383
|
+
var Ue = 8;
|
|
384
|
+
var Ke = 0.1;
|
|
385
|
+
var Ye = 0.5;
|
|
386
|
+
var je = 0.5;
|
|
387
|
+
var ee = () => performance.now();
|
|
388
|
+
function ze(e, t) {
|
|
389
|
+
let n = Math.max(0, Math.min(Ue, t) - Mt(e, 0));
|
|
390
|
+
if (!(n > 0)) return { curve: e, k: 0 };
|
|
391
|
+
let i = Math.max(3, Math.ceil(n / (Math.E * Ke)) - 1);
|
|
392
|
+
return { curve: (r) => r >= 1 ? 1 : e(r) + n * r * Math.pow(1 - r, i), k: n };
|
|
393
|
+
}
|
|
394
|
+
function qe(e, t) {
|
|
395
|
+
let n = Math.min(120, Math.max(32, Math.round(t / 8))), i = [];
|
|
396
|
+
for (let r = 0; r < n; r += 1) {
|
|
397
|
+
let s = r / (n - 1), o = r === n - 1 ? 1 : e(s);
|
|
398
|
+
i.push(`${Math.round(o * 1e4) / 1e4}`);
|
|
399
|
+
}
|
|
400
|
+
return `linear(${i.join(", ")})`;
|
|
401
|
+
}
|
|
402
|
+
function Zt(e, t, n, i, r, s, o, a) {
|
|
403
|
+
let u = (m, d, h, M, x) => {
|
|
404
|
+
let T = e.animate([{ [t]: `${m}px` }, { [t]: `${d}px` }], { duration: s, easing: h, fill: "both" });
|
|
405
|
+
return x !== void 0 && (T.currentTime = x), { anim: T, from: m, to: d, easing: h, curve: M, startedAt: ee() - (x ?? 0) };
|
|
406
|
+
};
|
|
407
|
+
if (r && r.elapsed !== null && Math.abs(r.to - i) < je) return u(r.from, r.to, r.easing, r.curve, r.elapsed);
|
|
408
|
+
let c = i - n, f = o, l = a;
|
|
409
|
+
if (a && Math.abs(c) > Ye) {
|
|
410
|
+
let m = ze(a, (r?.velocity ?? 0) * s / c);
|
|
411
|
+
m.k > 0 && (l = m.curve, f = qe(m.curve, s));
|
|
412
|
+
}
|
|
413
|
+
return u(n, i, f, l);
|
|
414
|
+
}
|
|
415
|
+
function te(e, t) {
|
|
416
|
+
let n = e.anim.currentTime === null, i = ee() - e.startedAt, s = n || !Number.isFinite(i) || i >= t || i < 0 ? null : i;
|
|
417
|
+
return { from: e.from, to: e.to, easing: e.easing, curve: e.curve, elapsed: s, velocity: s === null || !e.curve ? 0 : (e.to - e.from) * Mt(e.curve, s / t) / t };
|
|
418
|
+
}
|
|
419
|
+
var D = /* @__PURE__ */ new WeakMap();
|
|
420
|
+
function Je(e) {
|
|
421
|
+
return D.get(e)?.snapshot();
|
|
422
|
+
}
|
|
423
|
+
function ut(e) {
|
|
424
|
+
e.style.width = "", e.style.height = "", e.style.transitionProperty = "";
|
|
425
|
+
}
|
|
426
|
+
function ne(e) {
|
|
427
|
+
let t = D.get(e);
|
|
428
|
+
t && (D.delete(e), t.stop(), t.onCancel?.());
|
|
429
|
+
}
|
|
430
|
+
function re(e) {
|
|
431
|
+
let t = D.get(e);
|
|
432
|
+
t && (D.delete(e), t.stop()), ut(e);
|
|
433
|
+
}
|
|
434
|
+
function ie(e, t, n, i, r, s, o) {
|
|
435
|
+
let a = Je(e);
|
|
436
|
+
if (ne(e), t === 0 || n === 0) {
|
|
437
|
+
ut(e), o?.();
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
e.style.transitionProperty = "none", e.style.width = "", e.style.height = "", e.offsetWidth;
|
|
441
|
+
let { width: u, height: c } = et(e), f = Vt(r), l = Zt(e, "width", t, u, a?.width, i, r, f), m = Zt(e, "height", n, c, a?.height, i, r, f), d = () => {
|
|
442
|
+
l.anim.cancel(), m.anim.cancel();
|
|
443
|
+
};
|
|
444
|
+
l.anim.onfinish = () => {
|
|
445
|
+
D.delete(e), d(), ut(e), s?.();
|
|
446
|
+
}, D.set(e, { stop: d, onCancel: o, snapshot: () => ({ width: te(l, i), height: te(m, i) }) });
|
|
447
|
+
}
|
|
448
|
+
function se(e, t, n, i, r, s) {
|
|
449
|
+
ne(e), e.style.transitionProperty = "none", e.style.width = `${t}px`, e.style.height = `${n}px`;
|
|
450
|
+
let o = setTimeout(() => {
|
|
451
|
+
D.delete(e), ut(e), r?.();
|
|
452
|
+
}, i), a = (u) => ({ from: u, to: u, easing: "linear", curve: null, elapsed: null, velocity: 0 });
|
|
453
|
+
D.set(e, { stop: () => clearTimeout(o), onCancel: s, snapshot: () => ({ width: a(t), height: a(n) }) });
|
|
454
|
+
}
|
|
455
|
+
function ct(e) {
|
|
456
|
+
let t = Array.from(e.children), n = {}, i = e.getBoundingClientRect();
|
|
457
|
+
return t.forEach((r, s) => {
|
|
458
|
+
if (r.hasAttribute(H) || r.hasAttribute(P) || r.tagName === "BR") return;
|
|
459
|
+
let o = r.getAttribute(w) || `child-${s}`, a = r.getBoundingClientRect(), { tx: u, ty: c } = X(r);
|
|
460
|
+
n[o] = { x: a.left - i.left - u, y: a.top - i.top - c };
|
|
461
|
+
}), n;
|
|
462
|
+
}
|
|
463
|
+
function Tt(e, t, n) {
|
|
464
|
+
let i = e[n], r = t[n];
|
|
465
|
+
return !i || !r ? { dx: 0, dy: 0 } : { dx: i.x - r.x, dy: i.y - r.y };
|
|
466
|
+
}
|
|
467
|
+
function Et(e, t, n, i = "backward-first") {
|
|
468
|
+
let [r, s] = i === "backward-first" ? ["backward", "forward"] : ["forward", "backward"], o = (a) => {
|
|
469
|
+
if (a === "backward") {
|
|
470
|
+
for (let u = e - 1; u >= 0; u--) if (n.has(t[u])) return t[u];
|
|
471
|
+
} else for (let u = e + 1; u < t.length; u++) if (n.has(t[u])) return t[u];
|
|
472
|
+
return null;
|
|
473
|
+
};
|
|
474
|
+
return o(r) ?? o(s);
|
|
475
|
+
}
|
|
476
|
+
function oe(e, t, n, i) {
|
|
477
|
+
let r = new Set(n.filter((o, a) => i.has(o) && !t.has(e[a]))), s = /* @__PURE__ */ new Map();
|
|
478
|
+
for (let o = 0; o < e.length; o++) {
|
|
479
|
+
let a = e[o];
|
|
480
|
+
t.has(a) && s.set(a, Et(o, n, r, "forward-first"));
|
|
481
|
+
}
|
|
482
|
+
return s;
|
|
483
|
+
}
|
|
484
|
+
function ae(e, t) {
|
|
485
|
+
let { dx: n, dy: i, duration: r, ease: s, scale: o } = t;
|
|
486
|
+
e.animate({ transform: o ? `translate(${n}px, ${i}px) scale(0.95)` : `translate(${n}px, ${i}px)`, offset: 1 }, { duration: r, easing: s, fill: "both" });
|
|
487
|
+
let a = e.animate({ opacity: 0, offset: 1 }, { duration: lt(r, 0.25), easing: "linear", fill: "both" });
|
|
488
|
+
a.onfinish = () => e.remove();
|
|
489
|
+
}
|
|
490
|
+
function ue(e, t) {
|
|
491
|
+
let { deltaX: n, deltaY: i, isNew: r, duration: s, ease: o } = t, a = j(e), u = n + a.tx, c = i + a.ty, f = r && a.opacity >= 1 ? 0 : a.opacity;
|
|
492
|
+
e.animate([{ transform: `translate(${u}px, ${c}px) scale(${r ? 0.95 : 1})` }, { transform: "none" }], { duration: s, easing: o, fill: "both" }), f < 1 && e.animate([{ opacity: f }, { opacity: 1 }], { duration: lt(s, r ? 0.5 : 0.25), delay: r ? lt(s, 0.25) : 0, easing: "linear", fill: "both" });
|
|
493
|
+
}
|
|
494
|
+
function Qe(e, t) {
|
|
495
|
+
let n = 0, i = 0;
|
|
496
|
+
for (let r = e; r && r !== t; r = r.offsetParent) n += r.offsetLeft, i += r.offsetTop;
|
|
497
|
+
return { x: n, y: i };
|
|
498
|
+
}
|
|
499
|
+
function At(e, t) {
|
|
500
|
+
let n = document.createElement(e);
|
|
501
|
+
return n.setAttribute(Q, ""), n.setAttribute(w, t), n.setAttribute("aria-hidden", "true"), n;
|
|
502
|
+
}
|
|
503
|
+
function le(e, t) {
|
|
504
|
+
let n = /* @__PURE__ */ new Map();
|
|
505
|
+
for (let i of t) {
|
|
506
|
+
if (i.tagName === "BR") continue;
|
|
507
|
+
let { x: r, y: s } = Qe(i, e), { tx: o, ty: a } = X(i), { width: u, height: c } = et(i), f = Number(getComputedStyle(i).opacity) || 1;
|
|
508
|
+
i.getAnimations().forEach((l) => l.cancel()), n.set(i, { left: r + o, top: s + a, width: u, height: c, opacity: f });
|
|
509
|
+
}
|
|
510
|
+
for (let i = t.length - 1; i >= 0; i--) t[i].tagName === "BR" && (t[i].remove(), t.splice(i, 1));
|
|
511
|
+
t.forEach((i) => {
|
|
512
|
+
let r = n.get(i);
|
|
513
|
+
i.setAttribute(H, ""), i.style.position = "absolute", i.style.pointerEvents = "none", i.style.left = `${r.left}px`, i.style.top = `${r.top}px`, i.style.width = `${r.width}px`, i.style.height = `${r.height}px`, i.style.opacity = String(r.opacity);
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
function ce(e, t) {
|
|
517
|
+
if (t.size === 0) return;
|
|
518
|
+
let n = Array.from(e.children), i = /* @__PURE__ */ new Set();
|
|
519
|
+
for (let r of n) {
|
|
520
|
+
if (r.hasAttribute(H)) continue;
|
|
521
|
+
let s = r.getAttribute(w);
|
|
522
|
+
if (!s || i.has(s)) continue;
|
|
523
|
+
let o = t.get(s);
|
|
524
|
+
if (o) {
|
|
525
|
+
i.add(s);
|
|
526
|
+
for (let a of o) {
|
|
527
|
+
let u = At("span", a.id);
|
|
528
|
+
wt(u, a), r.before(u);
|
|
529
|
+
}
|
|
530
|
+
r.remove();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function wt(e, t) {
|
|
535
|
+
if (!t.kind) {
|
|
536
|
+
e.removeAttribute(V), e.removeAttribute(F), e.textContent = t.string;
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
e.setAttribute(V, t.kind), e.setAttribute(F, "");
|
|
540
|
+
let n = e.firstElementChild;
|
|
541
|
+
n || (e.textContent = "", n = document.createElement("span"), e.appendChild(n)), n.textContent = t.string;
|
|
542
|
+
}
|
|
543
|
+
function vt(e) {
|
|
544
|
+
return e.hasAttribute(F) ? e.firstElementChild ?? e : e;
|
|
545
|
+
}
|
|
546
|
+
function me(e, t, n, i) {
|
|
547
|
+
let r = /* @__PURE__ */ new Map();
|
|
548
|
+
t.forEach((s) => {
|
|
549
|
+
let o = s.getAttribute(w);
|
|
550
|
+
n.has(o) && !s.hasAttribute(H) && (r.set(o, s), s.remove());
|
|
551
|
+
}), Array.from(e.childNodes).forEach((s) => {
|
|
552
|
+
s.nodeType === Node.TEXT_NODE && s.remove();
|
|
553
|
+
}), i.forEach((s) => {
|
|
554
|
+
let o = r.get(s.id);
|
|
555
|
+
if (o && r.delete(s.id), s.string === `
|
|
556
|
+
`) {
|
|
557
|
+
o && o.tagName === "BR" ? e.appendChild(o) : e.appendChild(At("br", s.id));
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
if (o && o.tagName !== "BR") o.style.transformOrigin = "", wt(o, s), e.appendChild(o);
|
|
561
|
+
else {
|
|
562
|
+
let a = At("span", s.id);
|
|
563
|
+
wt(a, s), e.appendChild(a);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
var Ve = 0.45;
|
|
568
|
+
var Ze = 0.25;
|
|
569
|
+
function pe(e, t) {
|
|
570
|
+
let { dx: n, dy: i, slideDistance: r, duration: s, ease: o } = t, a = vt(e);
|
|
571
|
+
e.animate({ transform: `translate(${n}px, ${i}px)`, offset: 1 }, { duration: s, easing: o, fill: "both" }), a.animate({ transform: `translate(0px, ${r}px)`, offset: 1 }, { duration: s, easing: o, fill: "both" });
|
|
572
|
+
let u = a.animate({ opacity: 0, offset: 1 }, { duration: s * Ve, easing: "linear", fill: "both" });
|
|
573
|
+
u.onfinish = () => e.remove();
|
|
574
|
+
}
|
|
575
|
+
function fe(e, t) {
|
|
576
|
+
let { deltaX: n, deltaY: i, slideDistance: r, kind: s, duration: o, ease: a } = t;
|
|
577
|
+
Rt(e, { deltaX: n, deltaY: i, duration: o, ease: a });
|
|
578
|
+
let u = vt(e), c = j(u), f = s === "digit" ? -r : r;
|
|
579
|
+
u.animate({ transform: `translate(0px, ${c.ty + f}px)`, offset: 0 }, { duration: o, easing: a, fill: "both" });
|
|
580
|
+
let l = c.opacity >= 1 ? 0 : c.opacity;
|
|
581
|
+
l < 1 && u.animate([{ opacity: l }, { opacity: 1 }], { duration: o * Ze, easing: "linear", fill: "both" });
|
|
582
|
+
}
|
|
583
|
+
function Rt(e, t) {
|
|
584
|
+
let { deltaX: n, deltaY: i, duration: r, ease: s } = t, { tx: o, ty: a } = X(e);
|
|
585
|
+
e.getAnimations().forEach((f) => f.cancel());
|
|
586
|
+
let u = n + o, c = i + a;
|
|
587
|
+
u === 0 && c === 0 || e.animate({ transform: `translate(${u}px, ${c}px)`, offset: 0 }, { duration: r, easing: s, fill: "both" });
|
|
588
|
+
}
|
|
589
|
+
var tn = 6;
|
|
590
|
+
var de = 0.8;
|
|
591
|
+
var en = 0.45;
|
|
592
|
+
var nn = 0.35;
|
|
593
|
+
function he(e) {
|
|
594
|
+
let t = e.map((u) => u.getBoundingClientRect()), n = Math.min(...t.map((u) => u.left)), i = Math.max(...t.map((u) => u.right)), r = Math.min(...t.map((u) => u.top)), s = Math.max(...t.map((u) => u.bottom)), o = (n + i) / 2, a = (r + s) / 2;
|
|
595
|
+
return t.map((u) => `${o - u.left}px ${a - u.top}px`);
|
|
596
|
+
}
|
|
597
|
+
function ge(e, t) {
|
|
598
|
+
let { duration: n, ease: i } = t, r = he(e);
|
|
599
|
+
e.forEach((s, o) => {
|
|
600
|
+
s.getAnimations().forEach((u) => u.cancel()), s.style.transformOrigin = r[o], s.animate({ transform: `scale(${de})`, offset: 1 }, { duration: n, easing: i, fill: "both" });
|
|
601
|
+
let a = s.animate({ opacity: 0, offset: 1 }, { duration: n * en, easing: "linear", fill: "both" });
|
|
602
|
+
a.onfinish = () => s.remove();
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
function be(e, t) {
|
|
606
|
+
let { duration: n, ease: i } = t, r = he(e);
|
|
607
|
+
e.forEach((s, o) => {
|
|
608
|
+
let a = j(s);
|
|
609
|
+
s.style.transformOrigin = r[o], s.animate({ transform: `scale(${de})`, offset: 0 }, { duration: n, easing: i, fill: "both" });
|
|
610
|
+
let u = a.opacity >= 1 ? 0 : a.opacity;
|
|
611
|
+
s.animate([{ opacity: u }, { opacity: 1 }], { duration: n * nn, easing: "linear", fill: "both" });
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
function It(e, t) {
|
|
615
|
+
let n = [], i = [], r = () => {
|
|
616
|
+
i.length >= tn && n.push(i), i = [];
|
|
617
|
+
};
|
|
618
|
+
for (let s of e) t.has(s) ? i.push(s) : r();
|
|
619
|
+
return r(), n;
|
|
620
|
+
}
|
|
621
|
+
var rn = "\0#";
|
|
622
|
+
function xe(e, t) {
|
|
623
|
+
if (e.segments.length !== 1 || e.word.length <= 1) return e.segments;
|
|
624
|
+
let n = e.segments[0], i = e.word.split("").map((r, s) => ({ id: `${n.id}:${s}`, string: r }));
|
|
625
|
+
return t.set(n.id, i), i;
|
|
626
|
+
}
|
|
627
|
+
function sn(e) {
|
|
628
|
+
return e.map((t) => ({ ...t, kind: t.kind ?? at(t.string) }));
|
|
629
|
+
}
|
|
630
|
+
function on(e, t) {
|
|
631
|
+
if (e.length === 0 || t.length === 0) return 0;
|
|
632
|
+
let [n] = G(e.split(""), t.split(""));
|
|
633
|
+
return n.length / Math.max(e.length, t.length);
|
|
634
|
+
}
|
|
635
|
+
function ye(e, t) {
|
|
636
|
+
let n = [], i = 0;
|
|
637
|
+
for (let r = 0; r < e; r++) n.push(i), t.has(r) && i++;
|
|
638
|
+
return n;
|
|
639
|
+
}
|
|
640
|
+
var an = 0.4;
|
|
641
|
+
function un(e, t) {
|
|
642
|
+
return (q(e) || q(t)) && gt(e) === gt(t) ? 1 : on(e, t);
|
|
643
|
+
}
|
|
644
|
+
var ln = 2500;
|
|
645
|
+
var cn = 1e6;
|
|
646
|
+
function Lt(e, t, n, i = {}) {
|
|
647
|
+
let r = t.includes(" "), s = t.includes(`
|
|
648
|
+
`), o = zt(e), a = i.numbers !== false, u = (p) => a && J(p), c = (p) => u(p) ? rn : p, f = a && (q(t) || o.some((p) => q(p.word)));
|
|
649
|
+
if (o.length <= 1 && !r && !s && !f) return { segments: K(t, n, a), splits: /* @__PURE__ */ new Map() };
|
|
650
|
+
let l = [], m = [], d = t.split(/( |\n)/), h = [];
|
|
651
|
+
for (let p of d) p === " " || p === `
|
|
652
|
+
` ? h.push(p) : p.length > 0 && (m.push(h), l.push(p), h = []);
|
|
653
|
+
let M = h, x = o.map((p) => p.word);
|
|
654
|
+
if (x.length * l.length > cn) return { segments: K(t, n, a), splits: /* @__PURE__ */ new Map() };
|
|
655
|
+
let [T, L] = G(x.map(c), l.map(c)), E = new Set(T), N = new Set(L), g = /* @__PURE__ */ new Map();
|
|
656
|
+
for (let p = 0; p < L.length; p++) g.set(L[p], T[p]);
|
|
657
|
+
let v = x.map((p, b) => b).filter((p) => !E.has(p)), R = l.map((p, b) => b).filter((p) => !N.has(p)), O = /* @__PURE__ */ new Set();
|
|
658
|
+
for (let p of R) for (let b of v) if (!O.has(b) && c(l[p]) === c(x[b])) {
|
|
659
|
+
g.set(p, b), O.add(b);
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
O.size > 0 && (v = v.filter((p) => !O.has(p)), R = R.filter((p) => !g.has(p)));
|
|
663
|
+
let A = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Set(), B = ye(x.length, E), rt = ye(l.length, N);
|
|
664
|
+
if (v.length * R.length <= ln) for (let p of R) {
|
|
665
|
+
let b = -1, S = an;
|
|
666
|
+
for (let y of v) {
|
|
667
|
+
if (_.has(y) || B[y] !== rt[p]) continue;
|
|
668
|
+
let it = un(x[y], l[p]);
|
|
669
|
+
it > S && (S = it, b = y);
|
|
670
|
+
}
|
|
671
|
+
b >= 0 && (A.set(p, b), _.add(b));
|
|
672
|
+
}
|
|
673
|
+
let pt = l.map((p, b) => {
|
|
674
|
+
let S = g.get(b), y = S ?? A.get(b);
|
|
675
|
+
return y === void 0 ? { mode: "fresh" } : u(p) ? { mode: "number", oi: y } : S !== void 0 ? { mode: "reuse", oi: y } : { mode: "morph", oi: y };
|
|
676
|
+
}), kt = pt.filter((p) => p.mode === "number").length === 1 ? i.cursorIndex : void 0, Ae = xt(n), W = yt();
|
|
677
|
+
for (let p of pt) {
|
|
678
|
+
if (p.mode === "fresh") continue;
|
|
679
|
+
let b = o[p.oi];
|
|
680
|
+
if (p.mode !== "reuse" && b.segments.length === 1) {
|
|
681
|
+
let S = b.segments[0];
|
|
682
|
+
for (let y = 0; y < b.word.length; y++) W.reserve(`${S.id}:${y}`);
|
|
683
|
+
} else for (let S of b.segments) W.reserve(S.id);
|
|
684
|
+
}
|
|
685
|
+
let $ = [], ft = /* @__PURE__ */ new Map(), z = 0;
|
|
686
|
+
function Ht(p) {
|
|
687
|
+
for (let b of p) b === `
|
|
688
|
+
` ? $.push({ id: W.take(`newline-${z}`), string: `
|
|
689
|
+
` }) : $.push({ id: W.take(`space-${z}`), string: "\xA0" }), z++;
|
|
690
|
+
}
|
|
691
|
+
for (let p = 0; p < l.length; p++) {
|
|
692
|
+
Ht(m[p] ?? (p > 0 ? [" "] : []));
|
|
693
|
+
let b = pt[p], S = l[p];
|
|
694
|
+
if (b.mode === "reuse") for (let y of o[b.oi].segments) $.push(y);
|
|
695
|
+
else if (b.mode === "number") {
|
|
696
|
+
let y = o[b.oi];
|
|
697
|
+
$.push(...U(S, sn(xe(y, ft)), kt === void 0 ? void 0 : kt - z, Ae));
|
|
698
|
+
} else if (b.mode === "morph") {
|
|
699
|
+
let y = o[b.oi], it = y.word, we = xe(y, ft), ve = it.split(""), st = S.split(""), [Re, Ot] = G(ve, st), dt = /* @__PURE__ */ new Map();
|
|
700
|
+
for (let I = 0; I < Ot.length; I++) {
|
|
701
|
+
let ot = we[Re[I]];
|
|
702
|
+
ot && dt.set(Ot[I], ot);
|
|
703
|
+
}
|
|
704
|
+
for (let I = 0; I < st.length; I++) if (dt.has(I)) {
|
|
705
|
+
let ot = dt.get(I);
|
|
706
|
+
$.push({ id: ot.id, string: st[I] });
|
|
707
|
+
} else $.push({ id: W.take(`${S}~${I}`), string: st[I] });
|
|
708
|
+
} else u(S) ? $.push(...U(S)) : $.push({ id: W.take(S), string: S });
|
|
709
|
+
z += S.length;
|
|
710
|
+
}
|
|
711
|
+
return Ht(M), { segments: $, splits: ft };
|
|
712
|
+
}
|
|
713
|
+
var mn = `
|
|
714
|
+
[${Y}] {
|
|
715
|
+
display: inline-block;
|
|
716
|
+
position: relative;
|
|
717
|
+
vertical-align: top;
|
|
718
|
+
will-change: width, height;
|
|
719
|
+
white-space: nowrap;
|
|
720
|
+
text-align: inherit;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
[${Q}]:not(br) {
|
|
724
|
+
display: inline-block;
|
|
725
|
+
position: relative;
|
|
726
|
+
will-change: opacity, transform;
|
|
727
|
+
transform: none;
|
|
728
|
+
opacity: 1;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/*
|
|
732
|
+
* The value once as plain text \u2014 every other child is an aria-hidden fragment.
|
|
733
|
+
* Out of flow, because the engine measures every child of the root. Clipped
|
|
734
|
+
* rather than display: none, which would take it out of the a11y tree as well.
|
|
735
|
+
* user-select: none, or a copied selection pastes the value twice.
|
|
736
|
+
*/
|
|
737
|
+
[${P}] {
|
|
738
|
+
position: absolute;
|
|
739
|
+
width: 1px;
|
|
740
|
+
height: 1px;
|
|
741
|
+
margin: -1px;
|
|
742
|
+
padding: 0;
|
|
743
|
+
border: 0;
|
|
744
|
+
overflow: hidden;
|
|
745
|
+
clip-path: inset(50%);
|
|
746
|
+
white-space: pre;
|
|
747
|
+
-webkit-user-select: none;
|
|
748
|
+
user-select: none;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/*
|
|
752
|
+
* A digit slides a whole line box to arrive, so it needs its own box to hide
|
|
753
|
+
* behind. Not the root: that spans every line, so clipping there leaves a digit
|
|
754
|
+
* on a middle line sliding over its neighbour in view. The transform sits on the
|
|
755
|
+
* child, so the slide never touches the slot's rect and the FLIP pass stays
|
|
756
|
+
* oblivious. clip-path, not overflow \u2014 an inline-block whose overflow is
|
|
757
|
+
* anything but visible has its baseline synthesized to the bottom margin edge
|
|
758
|
+
* (CSS 2.1 \xA710.8.1), and engines disagree on whether overflow: clip counts.
|
|
759
|
+
* The inline axis stays open so glyph overhang is not shaved.
|
|
760
|
+
*/
|
|
761
|
+
[${F}] {
|
|
762
|
+
clip-path: inset(0 -100vw);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
[${F}] > span {
|
|
766
|
+
display: inline-block;
|
|
767
|
+
will-change: opacity, transform;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/*
|
|
771
|
+
* Softens the clip above into a gradient, positionally rather than on a timer, so
|
|
772
|
+
* it stays in step with the slide at any duration. The band (--torph-fade, 0 for a
|
|
773
|
+
* hard edge) must eat into the box: the clip trims at the border box, so a ramp
|
|
774
|
+
* reaching past it sits in territory already removed and is never seen. no-clip
|
|
775
|
+
* plus repeat-x is what carries the profile across glyph overhang.
|
|
776
|
+
*/
|
|
777
|
+
@supports (mask-clip: no-clip) or (-webkit-mask-clip: no-clip) {
|
|
778
|
+
[${F}] {
|
|
779
|
+
--torph-mask: linear-gradient(
|
|
780
|
+
to bottom,
|
|
781
|
+
transparent,
|
|
782
|
+
#000 var(--torph-fade, 0.15em),
|
|
783
|
+
#000 calc(100% - var(--torph-fade, 0.15em)),
|
|
784
|
+
transparent
|
|
785
|
+
);
|
|
786
|
+
-webkit-mask-image: var(--torph-mask);
|
|
787
|
+
mask-image: var(--torph-mask);
|
|
788
|
+
-webkit-mask-repeat: repeat-x;
|
|
789
|
+
mask-repeat: repeat-x;
|
|
790
|
+
-webkit-mask-clip: no-clip;
|
|
791
|
+
mask-clip: no-clip;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
[${Y}][${Z}] {
|
|
796
|
+
outline: 2px solid magenta;
|
|
797
|
+
[${Q}] {
|
|
798
|
+
outline: 2px solid cyan;
|
|
799
|
+
outline-offset: -4px;
|
|
800
|
+
}
|
|
801
|
+
}`;
|
|
802
|
+
var C = null;
|
|
803
|
+
var Nt = 0;
|
|
804
|
+
function Se() {
|
|
805
|
+
Nt++, !C && (C = document.createElement("style"), C.dataset.torph = "true", C.textContent = mn, document.head.appendChild(C));
|
|
806
|
+
}
|
|
807
|
+
function Me() {
|
|
808
|
+
Nt--, !(Nt > 0 || !C) && (C.remove(), C = null);
|
|
809
|
+
}
|
|
810
|
+
function Te() {
|
|
811
|
+
if (typeof window > "u") return { prefersReducedMotion: false, destroy: () => {
|
|
812
|
+
} };
|
|
813
|
+
let e = window.matchMedia("(prefers-reduced-motion: reduce)"), t = { prefersReducedMotion: e.matches, destroy: i };
|
|
814
|
+
function n(r) {
|
|
815
|
+
t.prefersReducedMotion = r.matches;
|
|
816
|
+
}
|
|
817
|
+
function i() {
|
|
818
|
+
e.removeEventListener("change", n);
|
|
819
|
+
}
|
|
820
|
+
return e.addEventListener("change", n), t;
|
|
821
|
+
}
|
|
822
|
+
var Ee = { ..._t, debug: false, scale: true, numbers: true };
|
|
823
|
+
var nt = class {
|
|
824
|
+
element;
|
|
825
|
+
options = {};
|
|
826
|
+
data;
|
|
827
|
+
currentMeasures = {};
|
|
828
|
+
prevMeasures = {};
|
|
829
|
+
previousSegments = [];
|
|
830
|
+
isInitialRender = true;
|
|
831
|
+
reducedMotion = null;
|
|
832
|
+
srNode = null;
|
|
833
|
+
hasSetup = false;
|
|
834
|
+
constructor(t) {
|
|
835
|
+
let n = Object.fromEntries(Object.entries(t).filter(([, a]) => a !== void 0)), { ease: i, ...r } = { ...Ee, ...n }, { ease: s, duration: o } = Ft(i, r.duration);
|
|
836
|
+
this.options = { ...r, ease: s, duration: o }, this.element = t.element, this.options.respectReducedMotion && (this.reducedMotion = Te()), this.data = "", this.isDisabled() || this.setup();
|
|
837
|
+
}
|
|
838
|
+
setup() {
|
|
839
|
+
this.hasSetup || (this.hasSetup = true, this.element.setAttribute(Y, ""), this.options.debug && this.element.setAttribute(Z, ""), Se());
|
|
840
|
+
}
|
|
841
|
+
destroy() {
|
|
842
|
+
this.reducedMotion?.destroy(), re(this.element), this.element.getAnimations().forEach((t) => t.cancel()), this.srNode?.remove(), this.srNode = null, this.element.removeAttribute(Y), this.element.removeAttribute(Z), this.hasSetup && (this.hasSetup = false, Me());
|
|
843
|
+
}
|
|
844
|
+
isDisabled() {
|
|
845
|
+
return !!(this.options.disabled || this.reducedMotion?.prefersReducedMotion);
|
|
846
|
+
}
|
|
847
|
+
update(t, n) {
|
|
848
|
+
let i = typeof t == "number" ? t.toLocaleString(this.options.locale, { minimumFractionDigits: this.options.decimals, maximumFractionDigits: this.options.decimals }) : t;
|
|
849
|
+
if (i !== this.data) {
|
|
850
|
+
if (this.data = i, this.isDisabled()) {
|
|
851
|
+
typeof i == "string" && (this.srNode = null, this.element.textContent = i, this.previousSegments = [], this.isInitialRender = true);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
if (this.setup(), this.data instanceof HTMLElement) throw new Error("HTMLElement not yet supported");
|
|
855
|
+
this.options.onAnimationStart && !this.isInitialRender && this.options.onAnimationStart(), this.createTextGroup(this.data, this.element, n);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
createTextGroup(t, n, i) {
|
|
859
|
+
let { width: r, height: s } = et(n), o = this.options.numbers !== false;
|
|
860
|
+
this.syncAccessibleText(t);
|
|
861
|
+
let a, u;
|
|
862
|
+
if (this.previousSegments.length > 0) {
|
|
863
|
+
let g = Lt(this.previousSegments, t, this.options.locale, { numbers: o, cursorIndex: i });
|
|
864
|
+
a = g.segments, u = g.splits;
|
|
865
|
+
} else a = K(t, this.options.locale, o), u = /* @__PURE__ */ new Map();
|
|
866
|
+
let c = a.length === 0;
|
|
867
|
+
c && (a = [{ id: tt, string: "\u200B" }]), ce(n, u), this.prevMeasures = ct(this.element);
|
|
868
|
+
let f = Array.from(n.children).filter((g) => !g.hasAttribute(P)), l = new Set(a.map((g) => g.id)), m = f.filter((g) => !l.has(g.getAttribute(w)) && !g.hasAttribute(H)), d = new Set(m), h = f.map((g) => g.getAttribute(w)), M = oe(f, d, h, l);
|
|
869
|
+
le(n, m), me(n, f, l, a), this.currentMeasures = ct(this.element);
|
|
870
|
+
let x = a.reduce((g, v) => v.string === `
|
|
871
|
+
` ? g + 1 : g, 1), T = (n.offsetHeight || 20 * x) / x;
|
|
872
|
+
n.style.width = `${r}px`, n.offsetWidth;
|
|
873
|
+
let L = ct(this.element);
|
|
874
|
+
n.style.width = "", this.updateStyles(a, L, T);
|
|
875
|
+
let E = this.isInitialRender ? [] : It(f, new Set(m)), N = new Set(E.flat());
|
|
876
|
+
for (let g of E) ge(g, { duration: this.options.duration, ease: this.options.ease });
|
|
877
|
+
if (m.forEach((g) => {
|
|
878
|
+
if (this.isInitialRender || g.getAttribute(w) === tt) {
|
|
879
|
+
g.remove();
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (N.has(g)) return;
|
|
883
|
+
let v = M.get(g), { dx: R, dy: O } = v ? Tt(this.currentMeasures, this.prevMeasures, v) : { dx: 0, dy: 0 };
|
|
884
|
+
g.hasAttribute(V) ? pe(g, { dx: R, dy: O, slideDistance: T, duration: this.options.duration, ease: this.options.ease }) : ae(g, { dx: R, dy: O, duration: this.options.duration, ease: this.options.ease, scale: this.options.scale });
|
|
885
|
+
}), this.previousSegments = a, this.isInitialRender) {
|
|
886
|
+
this.isInitialRender = false, n.style.width = "", n.style.height = "";
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
c ? se(n, r, s, this.options.duration, this.options.onAnimationComplete, this.options.onAnimationCancel) : ie(n, r, s, this.options.duration, this.options.ease, this.options.onAnimationComplete, this.options.onAnimationCancel);
|
|
890
|
+
}
|
|
891
|
+
updateStyles(t, n, i) {
|
|
892
|
+
if (this.isInitialRender) return;
|
|
893
|
+
let r = Array.from(this.element.children).filter((l) => !l.hasAttribute(P)), s = t.map((l) => l.id), o = new Map(t.map((l) => [l.id, l.kind])), a = r.filter((l) => !l.hasAttribute(H) && l.tagName !== "BR" && l.getAttribute(w) !== tt), u = new Set(a.filter((l) => !this.prevMeasures[l.getAttribute(w)])), c = /* @__PURE__ */ new Set();
|
|
894
|
+
for (let l of It(a, u)) l.forEach((m) => c.add(m)), be(l, { duration: this.options.duration, ease: this.options.ease });
|
|
895
|
+
let f = new Set(s.filter((l) => this.prevMeasures[l]));
|
|
896
|
+
r.forEach((l, m) => {
|
|
897
|
+
if (l.hasAttribute(H) || l.tagName === "BR" || c.has(l)) return;
|
|
898
|
+
let d = l.getAttribute(w) || `child-${m}`;
|
|
899
|
+
if (d === tt) return;
|
|
900
|
+
let h = !this.prevMeasures[d], M = h ? Et(t.findIndex((E) => E.id === d), s, f) : d, { dx: x, dy: T } = M ? Tt(this.prevMeasures, n, M) : { dx: 0, dy: 0 }, L = o.get(d);
|
|
901
|
+
L && h ? fe(l, { deltaX: x, deltaY: T, slideDistance: i, kind: L, duration: this.options.duration, ease: this.options.ease }) : L ? Rt(l, { deltaX: x, deltaY: T, duration: this.options.duration, ease: this.options.ease }) : ue(l, { deltaX: x, deltaY: T, isNew: h, duration: this.options.duration, ease: this.options.ease });
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
syncAccessibleText(t) {
|
|
905
|
+
if (!this.srNode || this.srNode.parentNode !== this.element) {
|
|
906
|
+
let n = document.createElement("span");
|
|
907
|
+
n.setAttribute(P, ""), this.element.prepend(n), this.srNode = n;
|
|
908
|
+
}
|
|
909
|
+
this.srNode.textContent = t;
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
// ../probe/src/index.ts
|
|
914
|
+
var MAX_CANDIDATES = 4;
|
|
915
|
+
var SEL_ATTR = "data-bp-sel";
|
|
916
|
+
var OVERLAY_ID = "__bp_overlay__";
|
|
917
|
+
var SPOT_ATTR = "data-bp-spot";
|
|
918
|
+
var SPOT_STYLE_ID = "__bp_spotlight__";
|
|
919
|
+
var NON_VISUAL = /* @__PURE__ */ new Set(["head", "script", "style", "link", "meta", "title", "template", "noscript", "base"]);
|
|
920
|
+
var MAX_FIBER_WALK = 500;
|
|
921
|
+
var PORTAL_SCAN = 200;
|
|
922
|
+
var MAX_SCAN = 6e3;
|
|
923
|
+
var MAX_TREE = 800;
|
|
924
|
+
function emit(type, payload) {
|
|
925
|
+
try {
|
|
926
|
+
window.__bpEmit?.(JSON.stringify({ type, payload, t: performance.now() }));
|
|
927
|
+
} catch {
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
function mountRoot() {
|
|
931
|
+
return document.body ?? document.documentElement;
|
|
932
|
+
}
|
|
933
|
+
function pathOf(el) {
|
|
934
|
+
const mount = mountRoot();
|
|
935
|
+
const segments = [];
|
|
936
|
+
let node = el;
|
|
937
|
+
while (node && node !== mount) {
|
|
938
|
+
const parent = node.parentElement;
|
|
939
|
+
if (!parent) return null;
|
|
940
|
+
segments.unshift(Array.prototype.indexOf.call(parent.children, node));
|
|
941
|
+
node = parent;
|
|
942
|
+
}
|
|
943
|
+
return node === mount ? segments.join("/") : null;
|
|
944
|
+
}
|
|
945
|
+
function hasOwnText(el) {
|
|
946
|
+
for (const node of Array.from(el.childNodes)) {
|
|
947
|
+
if (node.nodeType === 3 && (node.nodeValue ?? "").trim() !== "") return true;
|
|
948
|
+
}
|
|
949
|
+
return false;
|
|
950
|
+
}
|
|
951
|
+
function elementAt(path) {
|
|
952
|
+
const mount = mountRoot();
|
|
953
|
+
if (path === "") return mount;
|
|
954
|
+
let node = mount;
|
|
955
|
+
for (const seg of path.split("/")) {
|
|
956
|
+
const next = node.children[Number(seg)];
|
|
957
|
+
if (!next) return null;
|
|
958
|
+
node = next;
|
|
959
|
+
}
|
|
960
|
+
return node;
|
|
961
|
+
}
|
|
962
|
+
function rectOf(el) {
|
|
963
|
+
const b = el.getBoundingClientRect();
|
|
964
|
+
return { x: b.left, y: b.top, w: b.width, h: b.height };
|
|
965
|
+
}
|
|
966
|
+
var RADIUS_PROPS = [
|
|
967
|
+
"borderTopLeftRadius",
|
|
968
|
+
"borderTopRightRadius",
|
|
969
|
+
"borderBottomRightRadius",
|
|
970
|
+
"borderBottomLeftRadius"
|
|
971
|
+
];
|
|
972
|
+
function radiiOf(el, rect) {
|
|
973
|
+
if (!(el instanceof HTMLElement) || !el.isConnected) return [0, 0, 0, 0];
|
|
974
|
+
const cs = getComputedStyle(el);
|
|
975
|
+
const w2 = el.offsetWidth;
|
|
976
|
+
const h = el.offsetHeight;
|
|
977
|
+
if (w2 <= 0 || h <= 0) return [0, 0, 0, 0];
|
|
978
|
+
const r = RADIUS_PROPS.map((prop) => {
|
|
979
|
+
const v = cs[prop].split(" ")[0];
|
|
980
|
+
const n = parseFloat(v);
|
|
981
|
+
if (!(n > 0)) return 0;
|
|
982
|
+
return v.endsWith("%") ? n / 100 * w2 : n;
|
|
983
|
+
});
|
|
984
|
+
const [tl, tr, br, bl] = r;
|
|
985
|
+
const f = Math.min(1, w2 / (tl + tr || 1), w2 / (bl + br || 1), h / (tl + bl || 1), h / (tr + br || 1));
|
|
986
|
+
const k2 = rect.w / w2;
|
|
987
|
+
return r.map((v) => v * f * k2);
|
|
988
|
+
}
|
|
989
|
+
function targetOf(el) {
|
|
990
|
+
const rect = rectOf(el);
|
|
991
|
+
return { rect, radii: radiiOf(el, rect) };
|
|
992
|
+
}
|
|
993
|
+
var fiberKey = null;
|
|
994
|
+
function fiberOf(el) {
|
|
995
|
+
if (fiberKey !== null) {
|
|
996
|
+
const hit = el[fiberKey];
|
|
997
|
+
if (hit) return hit;
|
|
998
|
+
}
|
|
999
|
+
for (const key of Object.keys(el)) {
|
|
1000
|
+
if (key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")) {
|
|
1001
|
+
fiberKey = key;
|
|
1002
|
+
return el[key];
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
function fiberName(type) {
|
|
1008
|
+
if (typeof type === "function") {
|
|
1009
|
+
const fn = type;
|
|
1010
|
+
const name = fn.displayName || fn.name;
|
|
1011
|
+
if (!name || name === "_c" || name.includes(".")) return null;
|
|
1012
|
+
return name;
|
|
1013
|
+
}
|
|
1014
|
+
if (type && typeof type === "object") {
|
|
1015
|
+
const o = type;
|
|
1016
|
+
if (o.displayName && !o.displayName.includes(".")) return o.displayName;
|
|
1017
|
+
if (o.render) return fiberName(o.render);
|
|
1018
|
+
if (o.type) return fiberName(o.type);
|
|
1019
|
+
if (o.displayName) return null;
|
|
1020
|
+
}
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
function nearestComponent(el) {
|
|
1024
|
+
let f = fiberOf(el);
|
|
1025
|
+
while (f) {
|
|
1026
|
+
const name = fiberName(f.type);
|
|
1027
|
+
if (name) return { fiber: f, name };
|
|
1028
|
+
f = f.return;
|
|
1029
|
+
}
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
function componentFiber(el) {
|
|
1033
|
+
let f = fiberOf(el);
|
|
1034
|
+
while (f) {
|
|
1035
|
+
if (fiberName(f.type)) return f;
|
|
1036
|
+
f = f.return;
|
|
1037
|
+
}
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
function componentRoot(el) {
|
|
1041
|
+
const f = componentFiber(el);
|
|
1042
|
+
if (!f) return null;
|
|
1043
|
+
const mount = mountRoot();
|
|
1044
|
+
let root = el;
|
|
1045
|
+
while (root.parentElement && root.parentElement !== mount && componentFiber(root.parentElement) === f) {
|
|
1046
|
+
root = root.parentElement;
|
|
1047
|
+
}
|
|
1048
|
+
return root;
|
|
1049
|
+
}
|
|
1050
|
+
function componentNameOf(el) {
|
|
1051
|
+
return nearestComponent(el)?.name ?? void 0;
|
|
1052
|
+
}
|
|
1053
|
+
function identityOf(el) {
|
|
1054
|
+
const near = nearestComponent(el);
|
|
1055
|
+
if (!near) return void 0;
|
|
1056
|
+
const root = componentRoot(el);
|
|
1057
|
+
if (!root) return void 0;
|
|
1058
|
+
const rootPath = pathOf(root);
|
|
1059
|
+
if (rootPath === null) return void 0;
|
|
1060
|
+
const owner = root.parentElement && mountRoot().contains(root.parentElement) ? root.parentElement : mountRoot();
|
|
1061
|
+
const peers = [];
|
|
1062
|
+
let ambiguous = false;
|
|
1063
|
+
const firstType = componentFiber(root)?.type;
|
|
1064
|
+
let scanned = 0;
|
|
1065
|
+
const all = owner.querySelectorAll("*");
|
|
1066
|
+
for (const node of Array.from(all)) {
|
|
1067
|
+
if (++scanned > MAX_SCAN) break;
|
|
1068
|
+
const nc = nearestComponent(node);
|
|
1069
|
+
if (!nc || nc.name !== near.name) continue;
|
|
1070
|
+
if (componentRoot(node) !== node) continue;
|
|
1071
|
+
if (componentFiber(node)?.type !== firstType) ambiguous = true;
|
|
1072
|
+
peers.push(node);
|
|
1073
|
+
}
|
|
1074
|
+
if (!peers.includes(root)) peers.push(root);
|
|
1075
|
+
peers.sort((a, b) => comparePaths(pathOf(a) ?? "", pathOf(b) ?? ""));
|
|
1076
|
+
const discriminant = discriminantOf(peers, root);
|
|
1077
|
+
return {
|
|
1078
|
+
key: `${near.name}@${pathOf(owner) ?? ""}`,
|
|
1079
|
+
name: near.name,
|
|
1080
|
+
kind: "component",
|
|
1081
|
+
index: peers.indexOf(root),
|
|
1082
|
+
count: peers.length,
|
|
1083
|
+
rootPath,
|
|
1084
|
+
...ambiguous ? { ambiguous: true } : {},
|
|
1085
|
+
...discriminant ? { variant: discriminant.variant, variantCount: discriminant.count } : {}
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
var VARIANT_SKIP = ["children", "className", "class", "style", "key", "ref", "id"];
|
|
1089
|
+
var VARIANT_PREFERRED = ["variant", "kind", "type", "mode", "appearance", "intent", "tone", "status", "state", "size", "color"];
|
|
1090
|
+
function variantValue(v) {
|
|
1091
|
+
if (typeof v === "string") return v.length > 0 && v.length <= 32 ? v : null;
|
|
1092
|
+
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
1093
|
+
return null;
|
|
1094
|
+
}
|
|
1095
|
+
function propsOf(el) {
|
|
1096
|
+
const props = componentFiber(el)?.memoizedProps;
|
|
1097
|
+
return props && typeof props === "object" ? props : {};
|
|
1098
|
+
}
|
|
1099
|
+
function matchesVariant(root, variant) {
|
|
1100
|
+
return variantValue(propsOf(root)[variant.prop]) === variant.value;
|
|
1101
|
+
}
|
|
1102
|
+
function discriminantOf(peers, root) {
|
|
1103
|
+
if (peers.length < 2) return void 0;
|
|
1104
|
+
const props = peers.map(propsOf);
|
|
1105
|
+
const mine = props[peers.indexOf(root)];
|
|
1106
|
+
if (!mine) return void 0;
|
|
1107
|
+
const candidates = [];
|
|
1108
|
+
for (const prop of Object.keys(mine)) {
|
|
1109
|
+
if (VARIANT_SKIP.indexOf(prop) !== -1 || prop.slice(0, 2) === "on") continue;
|
|
1110
|
+
const own = variantValue(mine[prop]);
|
|
1111
|
+
if (own === null) continue;
|
|
1112
|
+
const values = props.map((p) => variantValue(p[prop]));
|
|
1113
|
+
if (values.some((v) => v === null)) continue;
|
|
1114
|
+
const distinct = [];
|
|
1115
|
+
for (const v of values) if (v !== null && distinct.indexOf(v) === -1) distinct.push(v);
|
|
1116
|
+
if (distinct.length < 2) continue;
|
|
1117
|
+
candidates.push({ prop, value: own });
|
|
1118
|
+
}
|
|
1119
|
+
if (candidates.length === 0) return void 0;
|
|
1120
|
+
const rank = (prop) => {
|
|
1121
|
+
const at2 = VARIANT_PREFERRED.indexOf(prop);
|
|
1122
|
+
return at2 === -1 ? VARIANT_PREFERRED.length : at2;
|
|
1123
|
+
};
|
|
1124
|
+
candidates.sort((a, b) => rank(a.prop) - rank(b.prop) || (a.prop < b.prop ? -1 : 1));
|
|
1125
|
+
const best = candidates[0];
|
|
1126
|
+
let count = 0;
|
|
1127
|
+
for (const p of props) if (variantValue(p[best.prop]) === best.value) count++;
|
|
1128
|
+
return { variant: { prop: best.prop, value: best.value }, count };
|
|
1129
|
+
}
|
|
1130
|
+
function comparePaths(a, b) {
|
|
1131
|
+
const l = a === "" ? [] : a.split("/").map(Number);
|
|
1132
|
+
const r = b === "" ? [] : b.split("/").map(Number);
|
|
1133
|
+
for (let i = 0; i < Math.max(l.length, r.length); i++) {
|
|
1134
|
+
const x = l[i] ?? -1;
|
|
1135
|
+
const y = r[i] ?? -1;
|
|
1136
|
+
if (x !== y) return x - y;
|
|
1137
|
+
}
|
|
1138
|
+
return 0;
|
|
1139
|
+
}
|
|
1140
|
+
function describeValue(v) {
|
|
1141
|
+
if (v === null) return "null";
|
|
1142
|
+
if (Array.isArray(v)) return `[${v.length} items]`;
|
|
1143
|
+
switch (typeof v) {
|
|
1144
|
+
case "string":
|
|
1145
|
+
return JSON.stringify(v.length > 60 ? `${v.slice(0, 60)}\u2026` : v);
|
|
1146
|
+
case "number":
|
|
1147
|
+
case "boolean":
|
|
1148
|
+
case "undefined":
|
|
1149
|
+
return String(v);
|
|
1150
|
+
case "function":
|
|
1151
|
+
return "fn";
|
|
1152
|
+
case "object": {
|
|
1153
|
+
const o = v;
|
|
1154
|
+
if (o["$$typeof"]) return "<element>";
|
|
1155
|
+
try {
|
|
1156
|
+
const json = JSON.stringify(v);
|
|
1157
|
+
return json && json.length <= 80 ? json : "{\u2026}";
|
|
1158
|
+
} catch {
|
|
1159
|
+
return "{\u2026}";
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
default:
|
|
1163
|
+
return typeof v;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
function summariseProps(props) {
|
|
1167
|
+
const out = {};
|
|
1168
|
+
if (!props || typeof props !== "object") return out;
|
|
1169
|
+
let taken = 0;
|
|
1170
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1171
|
+
if (taken >= 16) break;
|
|
1172
|
+
if (key === "children" && typeof value !== "string") continue;
|
|
1173
|
+
out[key] = describeValue(value);
|
|
1174
|
+
taken++;
|
|
1175
|
+
}
|
|
1176
|
+
return out;
|
|
1177
|
+
}
|
|
1178
|
+
function labelParts(el) {
|
|
1179
|
+
const comp = componentNameOf(el);
|
|
1180
|
+
if (comp && componentRoot(el) === el) return { label: comp, componentName: comp };
|
|
1181
|
+
const aria = el.getAttribute("aria-label");
|
|
1182
|
+
if (aria) return { label: aria, componentName: comp };
|
|
1183
|
+
const text = el.children.length === 0 ? (el.textContent ?? "").trim() : "";
|
|
1184
|
+
if (text && text.length <= 24) return { label: text, componentName: comp };
|
|
1185
|
+
if (comp) return { label: comp, componentName: comp };
|
|
1186
|
+
const role = el.getAttribute("role");
|
|
1187
|
+
return { label: role || el.tagName.toLowerCase(), componentName: comp };
|
|
1188
|
+
}
|
|
1189
|
+
function labelOf(el) {
|
|
1190
|
+
return labelParts(el).label;
|
|
1191
|
+
}
|
|
1192
|
+
function crumbLite(el) {
|
|
1193
|
+
const elementPath = pathOf(el);
|
|
1194
|
+
if (elementPath === null) return null;
|
|
1195
|
+
const source = el.getAttribute("data-bp-source");
|
|
1196
|
+
const { label, componentName } = labelParts(el);
|
|
1197
|
+
return {
|
|
1198
|
+
elementPath,
|
|
1199
|
+
tag: el.tagName.toLowerCase(),
|
|
1200
|
+
classes: Array.from(el.classList),
|
|
1201
|
+
label,
|
|
1202
|
+
componentName,
|
|
1203
|
+
...source ? { source } : {},
|
|
1204
|
+
rect: rectOf(el)
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function crumbOf(el) {
|
|
1208
|
+
const lite = crumbLite(el);
|
|
1209
|
+
if (!lite) return null;
|
|
1210
|
+
return { ...lite, identity: identityOf(el) };
|
|
1211
|
+
}
|
|
1212
|
+
function refOf(el) {
|
|
1213
|
+
const self = crumbOf(el);
|
|
1214
|
+
if (!self) return null;
|
|
1215
|
+
const mount = mountRoot();
|
|
1216
|
+
const ancestors = [];
|
|
1217
|
+
let node = el.parentElement;
|
|
1218
|
+
while (node && node !== mount) {
|
|
1219
|
+
const crumb = crumbOf(node);
|
|
1220
|
+
if (crumb) ancestors.unshift(crumb);
|
|
1221
|
+
node = node.parentElement;
|
|
1222
|
+
}
|
|
1223
|
+
const rootCrumb = crumbOf(mount);
|
|
1224
|
+
if (rootCrumb) ancestors.unshift(rootCrumb);
|
|
1225
|
+
return { ...self, ancestors };
|
|
1226
|
+
}
|
|
1227
|
+
function elementAtPoint(x, y) {
|
|
1228
|
+
const mount = mountRoot();
|
|
1229
|
+
const stack = document.elementsFromPoint(x, y);
|
|
1230
|
+
for (const el of stack) {
|
|
1231
|
+
if (el.id === OVERLAY_ID || el.closest(`#${OVERLAY_ID}`)) continue;
|
|
1232
|
+
if (el === mount || mount.contains(el)) return el;
|
|
1233
|
+
}
|
|
1234
|
+
return null;
|
|
1235
|
+
}
|
|
1236
|
+
var SELECTOR_MAX_DEPTH = 12;
|
|
1237
|
+
var STABLE_ATTRS = ["data-testid", "data-test-id", "data-test", "data-cy", "data-qa", "data-component", "name"];
|
|
1238
|
+
var OUR_ATTRS = /* @__PURE__ */ new Set([SEL_ATTR, SPOT_ATTR, "data-bp-source"]);
|
|
1239
|
+
var PLAIN_NAME = /^[A-Za-z_-][-A-Za-z0-9_]*$/;
|
|
1240
|
+
function quoteValue(value) {
|
|
1241
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1242
|
+
}
|
|
1243
|
+
function resolvesTo(selector, el) {
|
|
1244
|
+
try {
|
|
1245
|
+
const found = mountRoot().querySelectorAll(selector);
|
|
1246
|
+
return found.length === 1 && found[0] === el;
|
|
1247
|
+
} catch {
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function anchorFor(el) {
|
|
1252
|
+
const id = el.getAttribute("id");
|
|
1253
|
+
if (id && PLAIN_NAME.test(id) && resolvesTo(`#${id}`, el)) return `#${id}`;
|
|
1254
|
+
const tried = [];
|
|
1255
|
+
for (const attr of STABLE_ATTRS) {
|
|
1256
|
+
const value = el.getAttribute(attr);
|
|
1257
|
+
if (value !== null && value.length <= 80) tried.push(`[${attr}=${quoteValue(value)}]`);
|
|
1258
|
+
}
|
|
1259
|
+
for (const attr of Array.from(el.attributes)) {
|
|
1260
|
+
if (!attr.name.startsWith("data-") || OUR_ATTRS.has(attr.name)) continue;
|
|
1261
|
+
if (STABLE_ATTRS.indexOf(attr.name) !== -1) continue;
|
|
1262
|
+
if (attr.value.length > 80) continue;
|
|
1263
|
+
tried.push(attr.value === "" ? `[${attr.name}]` : `[${attr.name}=${quoteValue(attr.value)}]`);
|
|
1264
|
+
}
|
|
1265
|
+
for (const selector of tried) if (resolvesTo(selector, el)) return selector;
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
function compoundFor(el) {
|
|
1269
|
+
const tag = el.tagName.toLowerCase();
|
|
1270
|
+
const classes = Array.from(el.classList).filter((c) => PLAIN_NAME.test(c)).slice(0, 3);
|
|
1271
|
+
const base = tag + classes.map((c) => `.${c}`).join("");
|
|
1272
|
+
const parent = el.parentElement;
|
|
1273
|
+
if (!parent) return base;
|
|
1274
|
+
const siblings = Array.from(parent.children);
|
|
1275
|
+
let matches = 0;
|
|
1276
|
+
for (const sibling of siblings) {
|
|
1277
|
+
try {
|
|
1278
|
+
if (sibling.matches(base)) matches++;
|
|
1279
|
+
} catch {
|
|
1280
|
+
matches = 2;
|
|
1281
|
+
break;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
if (matches === 1) return base;
|
|
1285
|
+
return `${base}:nth-child(${siblings.indexOf(el) + 1})`;
|
|
1286
|
+
}
|
|
1287
|
+
function printSelector(el) {
|
|
1288
|
+
const mount = mountRoot();
|
|
1289
|
+
if (el === mount || !mount.contains(el) && el !== mount) return null;
|
|
1290
|
+
const own = anchorFor(el);
|
|
1291
|
+
if (own) return own;
|
|
1292
|
+
const parts = [];
|
|
1293
|
+
let node = el;
|
|
1294
|
+
for (let depth = 0; node && node !== mount && depth < SELECTOR_MAX_DEPTH; depth++) {
|
|
1295
|
+
const anchor = depth === 0 ? null : anchorFor(node);
|
|
1296
|
+
parts.unshift(anchor ?? compoundFor(node));
|
|
1297
|
+
const candidate = parts.join(" > ");
|
|
1298
|
+
if (resolvesTo(candidate, el)) return candidate;
|
|
1299
|
+
if (anchor) break;
|
|
1300
|
+
node = node.parentElement;
|
|
1301
|
+
}
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1304
|
+
var RING_STROKE = 2;
|
|
1305
|
+
var TAB_RADIUS = 6;
|
|
1306
|
+
var JOIN_RADIUS = 4;
|
|
1307
|
+
var INNER_RADIUS = 4;
|
|
1308
|
+
var BADGE_RADIUS = 6;
|
|
1309
|
+
var MARKER_SIZE = 18;
|
|
1310
|
+
var TAB_HEIGHT = 17;
|
|
1311
|
+
var CHROME_FONT = "-apple-system,BlinkMacSystemFont,system-ui,sans-serif";
|
|
1312
|
+
var POP_EASE = "cubic-bezier(0.34,1.45,0.64,1)";
|
|
1313
|
+
var MARKER_MORPH_MS = 180;
|
|
1314
|
+
var CURSOR_DX = 6;
|
|
1315
|
+
var CURSOR_DY = 23;
|
|
1316
|
+
var CURSOR_FLIP_DY = 6;
|
|
1317
|
+
var CURSOR_FADE_MS = 140;
|
|
1318
|
+
var POINTING_CSS = "*{cursor:crosshair!important}[data-bp-marker]{cursor:pointer!important}";
|
|
1319
|
+
var POINTING_STYLE_ID = "__bp_cursor__";
|
|
1320
|
+
var TAB_INTRO_MS = 240;
|
|
1321
|
+
var TAB_INTRO_DELAY_MS = 60;
|
|
1322
|
+
var TAB_BLEED = 6;
|
|
1323
|
+
var DETACH_SETTLE_MS = 1200;
|
|
1324
|
+
var MORPH_SPRING = { stiffness: 345, damping: 32, mass: 1.2, precision: 7e-3 };
|
|
1325
|
+
var RING_COLOR_VAR = "--bp-ring-c";
|
|
1326
|
+
var RING_JOIN_VAR = "--bp-ring-j";
|
|
1327
|
+
var RECOLOR_MS = 320;
|
|
1328
|
+
var RECOLOR_EASE = "cubic-bezier(0.23, 1, 0.32, 1)";
|
|
1329
|
+
var colorPropsRegistered = false;
|
|
1330
|
+
function registerRingColors() {
|
|
1331
|
+
if (colorPropsRegistered) return;
|
|
1332
|
+
colorPropsRegistered = true;
|
|
1333
|
+
for (const name of [RING_COLOR_VAR, RING_JOIN_VAR]) {
|
|
1334
|
+
try {
|
|
1335
|
+
CSS.registerProperty({ name, syntax: "<color>", inherits: true, initialValue: "transparent" });
|
|
1336
|
+
} catch {
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
var GLYPH_SIZE = 8;
|
|
1341
|
+
var SPIN_MS = 900;
|
|
1342
|
+
var GLYPH_TURN_MS = 200;
|
|
1343
|
+
var SPIN_GLYPH = `<svg width="${GLYPH_SIZE}" height="${GLYPH_SIZE}" viewBox="0 0 8 8" fill="none" style="display:block"><path d="M8 4C8 6.20914 6.20914 8 4 8C1.79086 8 0 6.20914 0 4C0 1.79086 1.79086 0 4 0C6.20914 0 8 1.79086 8 4ZM1.69306 4C1.69306 5.27409 2.72591 6.30694 4 6.30694C5.27409 6.30694 6.30694 5.27409 6.30694 4C6.30694 2.72591 5.27409 1.69306 4 1.69306C2.72591 1.69306 1.69306 2.72591 1.69306 4Z" fill="currentColor" fill-opacity="0.4"/><path d="M7.15347 4C7.621 4 8.00896 3.61686 7.91076 3.15977C7.82445 2.75808 7.67642 2.37042 7.47045 2.01104C7.12346 1.40559 6.62412 0.901459 6.02202 0.548704C5.41991 0.195949 4.736 0.00684783 4.03821 0.000182513C3.624 -0.00377393 3.21346 0.0566317 2.82087 0.177743C2.37412 0.31556 2.22958 0.841322 2.45817 1.24915C2.68676 1.65699 3.20646 1.78396 3.66915 1.7169C3.78559 1.70003 3.90355 1.69203 4.02203 1.69316C4.42448 1.69701 4.81892 1.80607 5.16617 2.00951C5.51342 2.21296 5.80141 2.50371 6.00153 2.8529C6.06045 2.9557 6.11115 3.06251 6.15336 3.17233C6.32109 3.60873 6.68595 4 7.15347 4Z" fill="currentColor"/></svg>`;
|
|
1344
|
+
var STROKE_GLYPH = (d) => `<svg width="${GLYPH_SIZE}" height="${GLYPH_SIZE}" viewBox="0 0 8 8" fill="none" style="display:block">${d}</svg>`;
|
|
1345
|
+
var PAUSE_GLYPH = STROKE_GLYPH(
|
|
1346
|
+
'<path d="M2 1.5V6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 1.5V6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
|
|
1347
|
+
);
|
|
1348
|
+
var ALERT_GLYPH = STROKE_GLYPH(
|
|
1349
|
+
'<path d="M4 1.25V3.75" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 6.75V6.7501" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
|
|
1350
|
+
);
|
|
1351
|
+
var AGENT_TAB = {
|
|
1352
|
+
working: { text: "Working...", glyph: SPIN_GLYPH, spin: true },
|
|
1353
|
+
approval: { text: "Needs Approval", glyph: PAUSE_GLYPH, spin: false },
|
|
1354
|
+
failed: { text: "Failed", glyph: ALERT_GLYPH, spin: false }
|
|
1355
|
+
};
|
|
1356
|
+
var AGENT_FALLBACK = {
|
|
1357
|
+
working: "#f87bdf",
|
|
1358
|
+
approval: "#fd8a44",
|
|
1359
|
+
failed: "#e5484d"
|
|
1360
|
+
};
|
|
1361
|
+
var RESOLVED_FALLBACK = "#1d9c00";
|
|
1362
|
+
var CHECK_GLYPH = '<svg width="10" height="10" viewBox="0 0 10 10" fill="none" style="display:block"><path d="M2.1 5.25L4.05 7.2L7.9 3" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
1363
|
+
function turnOver(el, html) {
|
|
1364
|
+
if (typeof el.animate !== "function") {
|
|
1365
|
+
el.innerHTML = html;
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
for (const a of el.getAnimations?.() ?? []) {
|
|
1369
|
+
if (a.id === "turn") a.cancel();
|
|
1370
|
+
}
|
|
1371
|
+
const half = GLYPH_TURN_MS / 2;
|
|
1372
|
+
const out = el.animate([{ opacity: 1, scale: "1" }, { opacity: 0, scale: "0.4" }], {
|
|
1373
|
+
duration: half,
|
|
1374
|
+
easing: "ease-in",
|
|
1375
|
+
id: "turn"
|
|
1376
|
+
});
|
|
1377
|
+
out.onfinish = () => {
|
|
1378
|
+
el.innerHTML = html;
|
|
1379
|
+
el.animate([{ opacity: 0, scale: "0.4" }, { opacity: 1, scale: "1" }], {
|
|
1380
|
+
duration: half,
|
|
1381
|
+
easing: POP_EASE,
|
|
1382
|
+
fill: "backwards",
|
|
1383
|
+
id: "turn"
|
|
1384
|
+
});
|
|
1385
|
+
};
|
|
1386
|
+
out.oncancel = () => {
|
|
1387
|
+
el.innerHTML = html;
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
var FRAME_PATH = "";
|
|
1391
|
+
function frameBox() {
|
|
1392
|
+
const s = RING_STROKE;
|
|
1393
|
+
return { x: s, y: s, w: Math.max(0, window.innerWidth - 2 * s), h: Math.max(0, window.innerHeight - 2 * s) };
|
|
1394
|
+
}
|
|
1395
|
+
function markRect(path, el) {
|
|
1396
|
+
return path === FRAME_PATH ? frameBox() : rectOf(el);
|
|
1397
|
+
}
|
|
1398
|
+
function markTarget(path, el) {
|
|
1399
|
+
return path === FRAME_PATH ? { rect: frameBox(), radii: [0, 0, 0, 0] } : targetOf(el);
|
|
1400
|
+
}
|
|
1401
|
+
function filletBox(r) {
|
|
1402
|
+
return `width:${r}px;height:${r}px;overflow:hidden;`;
|
|
1403
|
+
}
|
|
1404
|
+
function filletArc(r, hole, color) {
|
|
1405
|
+
const left = hole === "tr" || hole === "br" ? 0 : -r;
|
|
1406
|
+
const top = hole === "bl" || hole === "br" ? 0 : -r;
|
|
1407
|
+
return `position:absolute;left:${left}px;top:${top}px;width:${2 * r}px;height:${2 * r}px;border-radius:50%;box-shadow:0 0 0 ${r}px ${color};`;
|
|
1408
|
+
}
|
|
1409
|
+
function dressFillet(f, position, r, hole, color) {
|
|
1410
|
+
f.square.style.cssText = position + filletBox(r);
|
|
1411
|
+
f.arc.style.cssText = filletArc(r, hole, color);
|
|
1412
|
+
}
|
|
1413
|
+
var Ring = class {
|
|
1414
|
+
constructor(parent, fill, morphing = false) {
|
|
1415
|
+
/** Styling caches — rewritten on change, never per frame. */
|
|
1416
|
+
this.color = "";
|
|
1417
|
+
this.textColor = "#ffffff";
|
|
1418
|
+
this.joinColor = "";
|
|
1419
|
+
this.label = "";
|
|
1420
|
+
this.morph = null;
|
|
1421
|
+
this.glyph = null;
|
|
1422
|
+
this.spinning = false;
|
|
1423
|
+
this.tabW = 0;
|
|
1424
|
+
this.radius = "";
|
|
1425
|
+
this.tucked = false;
|
|
1426
|
+
this.tabShift = 0;
|
|
1427
|
+
this.tabDress = "";
|
|
1428
|
+
this.dropR = -1;
|
|
1429
|
+
this.tabHidden = false;
|
|
1430
|
+
this.hasTab = true;
|
|
1431
|
+
this.geom = "";
|
|
1432
|
+
this.fused = false;
|
|
1433
|
+
this.shown = false;
|
|
1434
|
+
this.rect = null;
|
|
1435
|
+
this.fill = fill;
|
|
1436
|
+
this.morphing = morphing;
|
|
1437
|
+
const div = (css, into) => {
|
|
1438
|
+
const d = document.createElement("div");
|
|
1439
|
+
d.style.cssText = css;
|
|
1440
|
+
into.appendChild(d);
|
|
1441
|
+
return d;
|
|
1442
|
+
};
|
|
1443
|
+
registerRingColors();
|
|
1444
|
+
this.rootEl = div(
|
|
1445
|
+
"position:fixed;left:0;top:0;pointer-events:none;display:none;will-change:transform,width,height;",
|
|
1446
|
+
parent
|
|
1447
|
+
);
|
|
1448
|
+
const fillet = (css, into) => {
|
|
1449
|
+
const square = div(css, into);
|
|
1450
|
+
return { square, arc: div("", square) };
|
|
1451
|
+
};
|
|
1452
|
+
this.box = div("position:absolute;inset:0;box-sizing:border-box;", this.rootEl);
|
|
1453
|
+
this.inTL = fillet("position:absolute;left:0;top:0;", this.box);
|
|
1454
|
+
this.inTR = fillet("position:absolute;right:0;top:0;display:none;", this.box);
|
|
1455
|
+
this.inBR = fillet("position:absolute;right:0;bottom:0;display:none;", this.box);
|
|
1456
|
+
this.tabRow = div("position:absolute;bottom:100%;left:0;overflow:hidden;white-space:nowrap;", this.rootEl);
|
|
1457
|
+
this.tabSlide = div("position:relative;display:flex;align-items:flex-end;", this.tabRow);
|
|
1458
|
+
this.tab = div(
|
|
1459
|
+
`display:flex;align-items:center;gap:4px;padding:2px 6px 1px;font:600 11px/14px ${CHROME_FONT};letter-spacing:-0.08px;border-radius:${TAB_RADIUS}px ${TAB_RADIUS}px 0 0;`,
|
|
1460
|
+
this.tabSlide
|
|
1461
|
+
);
|
|
1462
|
+
this.tabGlyph = div(`display:none;flex:none;width:${GLYPH_SIZE}px;height:${GLYPH_SIZE}px;`, this.tab);
|
|
1463
|
+
this.tabText = div("", this.tab);
|
|
1464
|
+
this.tabJoin = fillet("", this.tabSlide);
|
|
1465
|
+
this.tabBleed = div(`position:absolute;left:0;right:0;top:100%;height:${TAB_BLEED}px;`, this.tabSlide);
|
|
1466
|
+
this.tabDrop = fillet("position:absolute;left:100%;top:0;display:none;", this.rootEl);
|
|
1467
|
+
this.markJoin = fillet(`position:absolute;top:100%;right:${MARKER_SIZE}px;display:none;`, this.rootEl);
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Everything that only changes with color or fusion.
|
|
1471
|
+
*
|
|
1472
|
+
* The pieces are written once, against `var(--bp-ring-c)` (and the join's
|
|
1473
|
+
* own variable), and the container holds the values. So a ring that
|
|
1474
|
+
* *changes* color — an agent ring going from working to needs-approval —
|
|
1475
|
+
* writes one property and the stroke, the tab, the bleed and every join
|
|
1476
|
+
* fillet travel together, interpolated in oklab by the registered
|
|
1477
|
+
* property. The very first color is written without the transition: a new
|
|
1478
|
+
* ring appears in its color, it does not fade up out of transparent.
|
|
1479
|
+
*/
|
|
1480
|
+
style(color, textColor, joinColor) {
|
|
1481
|
+
if (color === this.color && textColor === this.textColor && joinColor === this.joinColor) return;
|
|
1482
|
+
const first = this.color === "";
|
|
1483
|
+
this.color = color;
|
|
1484
|
+
this.textColor = textColor;
|
|
1485
|
+
this.joinColor = joinColor;
|
|
1486
|
+
if (first) {
|
|
1487
|
+
const c2 = `var(${RING_COLOR_VAR})`;
|
|
1488
|
+
this.box.style.border = `${RING_STROKE}px solid ${c2}`;
|
|
1489
|
+
this.box.style.background = this.fill ? colorMix(c2, 0.08) : "transparent";
|
|
1490
|
+
this.tab.style.background = c2;
|
|
1491
|
+
this.tabBleed.style.background = c2;
|
|
1492
|
+
dressFillet(this.tabJoin, "position:relative;", JOIN_RADIUS, "tr", c2);
|
|
1493
|
+
}
|
|
1494
|
+
this.tab.style.color = textColor;
|
|
1495
|
+
this.rootEl.style.setProperty(RING_COLOR_VAR, color);
|
|
1496
|
+
this.rootEl.style.setProperty(RING_JOIN_VAR, joinColor);
|
|
1497
|
+
if (first) {
|
|
1498
|
+
requestAnimationFrame(() => {
|
|
1499
|
+
this.rootEl.style.transition = `${RING_COLOR_VAR} ${RECOLOR_MS}ms ${RECOLOR_EASE},${RING_JOIN_VAR} ${RECOLOR_MS}ms ${RECOLOR_EASE}`;
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
const c = `var(${RING_COLOR_VAR})`;
|
|
1503
|
+
dressFillet(this.inTL, `position:absolute;left:0;top:0;display:${this.hasTab ? "block" : "none"};`, INNER_RADIUS, "br", c);
|
|
1504
|
+
dressFillet(this.inBR, `position:absolute;right:0;bottom:0;display:${this.fused ? "block" : "none"};`, INNER_RADIUS, "tl", c);
|
|
1505
|
+
dressFillet(
|
|
1506
|
+
this.markJoin,
|
|
1507
|
+
`position:absolute;top:100%;right:${MARKER_SIZE}px;display:${this.fused ? "block" : "none"};`,
|
|
1508
|
+
JOIN_RADIUS,
|
|
1509
|
+
"bl",
|
|
1510
|
+
`var(${RING_JOIN_VAR})`
|
|
1511
|
+
);
|
|
1512
|
+
this.dropFillets(this.dropR, true);
|
|
1513
|
+
this.radius = "";
|
|
1514
|
+
}
|
|
1515
|
+
/**
|
|
1516
|
+
* The overhang's two fillets, sized to the room the tab actually leaves.
|
|
1517
|
+
*
|
|
1518
|
+
* `r` is the drop's radius — zero when the tab clears the box's right edge
|
|
1519
|
+
* by less than the corner it is already rounding, in which case the tab's
|
|
1520
|
+
* own curve lands on that edge and there is nothing left to round. The
|
|
1521
|
+
* inner one is the box's, so it keeps the inner radius whenever the
|
|
1522
|
+
* corner is squared at all.
|
|
1523
|
+
*/
|
|
1524
|
+
dropFillets(r, force = false) {
|
|
1525
|
+
if (r === this.dropR && !force) return;
|
|
1526
|
+
this.dropR = r;
|
|
1527
|
+
const c = `var(${RING_COLOR_VAR})`;
|
|
1528
|
+
const drop = Math.max(r, 0);
|
|
1529
|
+
dressFillet(this.tabDrop, `position:absolute;left:100%;top:0;display:${drop > 0 ? "block" : "none"};`, drop, "br", c);
|
|
1530
|
+
dressFillet(this.inTR, `position:absolute;right:0;top:0;display:${r >= 0 ? "block" : "none"};`, INNER_RADIUS, "bl", c);
|
|
1531
|
+
}
|
|
1532
|
+
/** The tab's text — measured only when it changes (the old chip's trick). */
|
|
1533
|
+
setLabel(label) {
|
|
1534
|
+
if (label === this.label) return;
|
|
1535
|
+
this.label = label;
|
|
1536
|
+
if (this.morphing) {
|
|
1537
|
+
if (!this.morph) {
|
|
1538
|
+
this.morph = new nt({
|
|
1539
|
+
element: this.tabText,
|
|
1540
|
+
ease: MORPH_SPRING,
|
|
1541
|
+
onAnimationComplete: () => {
|
|
1542
|
+
if (this.hasTab) this.tabW = this.tab.offsetWidth;
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
this.morph.update(label);
|
|
1547
|
+
if (this.hasTab) this.tabW = this.tab.offsetWidth;
|
|
1548
|
+
} else {
|
|
1549
|
+
this.tabText.textContent = label;
|
|
1550
|
+
}
|
|
1551
|
+
if (this.hasTab && !this.morphing) this.tabW = this.tab.offsetWidth;
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* The tab's leading glyph — the agent rings' spinner, pause and alert
|
|
1555
|
+
* (`AGENT_TAB`); `null` for every other ring, which is the default. Only a
|
|
1556
|
+
* change in *presence* re-measures the tab: the three glyphs are one size,
|
|
1557
|
+
* so swapping one for another moves nothing.
|
|
1558
|
+
*
|
|
1559
|
+
* `spin` turns the glyph, which is the whole of what "Working…" claims —
|
|
1560
|
+
* a partial ring standing still reads as broken, not busy. WAAPI so it
|
|
1561
|
+
* survives the page's own stylesheets, and reduced motion leaves it still:
|
|
1562
|
+
* the word beside it already says the fact.
|
|
1563
|
+
*/
|
|
1564
|
+
setGlyph(svg, spin = false) {
|
|
1565
|
+
if (svg !== this.glyph) {
|
|
1566
|
+
const swap = svg !== null && this.glyph !== null;
|
|
1567
|
+
const appeared = svg !== null !== (this.glyph !== null);
|
|
1568
|
+
this.glyph = svg;
|
|
1569
|
+
if (swap && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
1570
|
+
this.turnOver(svg);
|
|
1571
|
+
} else {
|
|
1572
|
+
this.tabGlyph.innerHTML = svg ?? "";
|
|
1573
|
+
}
|
|
1574
|
+
this.tabGlyph.style.display = svg === null ? "none" : "block";
|
|
1575
|
+
if (appeared && this.hasTab) this.tabW = this.tab.offsetWidth;
|
|
1576
|
+
}
|
|
1577
|
+
if (spin === this.spinning) return;
|
|
1578
|
+
this.spinning = spin;
|
|
1579
|
+
for (const a of this.tabGlyph.getAnimations?.() ?? []) if (a.id === "spin") a.cancel();
|
|
1580
|
+
if (!spin || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
1581
|
+
this.tabGlyph.animate?.([{ rotate: "0deg" }, { rotate: "360deg" }], {
|
|
1582
|
+
duration: SPIN_MS,
|
|
1583
|
+
iterations: Infinity,
|
|
1584
|
+
easing: "linear",
|
|
1585
|
+
id: "spin"
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
/** Half out, swap, half back — the glyph's own state change. */
|
|
1589
|
+
turnOver(svg) {
|
|
1590
|
+
turnOver(this.tabGlyph, svg);
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Take the whole construction out of the page — a status ring whose turn
|
|
1594
|
+
* ended. The pooled rings (hover, selection) never call it.
|
|
1595
|
+
*
|
|
1596
|
+
* It leaves rather than vanishing: the fused chip under it is already
|
|
1597
|
+
* traveling back to annotate purple on the recolor clock, and a ring that
|
|
1598
|
+
* cut out from around a chip mid-transition would read as two events. The
|
|
1599
|
+
* caller has already dropped this ring, so a fading one is never redrawn.
|
|
1600
|
+
*/
|
|
1601
|
+
destroy() {
|
|
1602
|
+
for (const a of this.tabGlyph.getAnimations?.() ?? []) a.cancel();
|
|
1603
|
+
this.morph?.destroy();
|
|
1604
|
+
this.morph = null;
|
|
1605
|
+
if (!this.shown || typeof this.rootEl.animate !== "function") {
|
|
1606
|
+
this.rootEl.remove();
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
const out = this.rootEl.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
1610
|
+
duration: RECOLOR_MS,
|
|
1611
|
+
easing: RECOLOR_EASE
|
|
1612
|
+
});
|
|
1613
|
+
out.onfinish = () => this.rootEl.remove();
|
|
1614
|
+
out.oncancel = () => this.rootEl.remove();
|
|
1615
|
+
}
|
|
1616
|
+
/** Whether the construction carries its label tab at all. Pointer hover
|
|
1617
|
+
* hands the name to the cursor label, so its ring drops the tab and gets
|
|
1618
|
+
* all four corners back; path-driven hovers (the layers preview, a
|
|
1619
|
+
* hovered marker) keep it — there is no cursor there to follow. */
|
|
1620
|
+
setTab(show) {
|
|
1621
|
+
if (show === this.hasTab) return;
|
|
1622
|
+
this.hasTab = show;
|
|
1623
|
+
this.tabRow.style.display = show ? "block" : "none";
|
|
1624
|
+
this.inTL.square.style.display = show ? "block" : "none";
|
|
1625
|
+
if (show && this.label) this.tabW = this.tab.offsetWidth;
|
|
1626
|
+
this.radius = "";
|
|
1627
|
+
}
|
|
1628
|
+
/** The select hand-off's second half: the tab pushes out of the box's
|
|
1629
|
+
* top-left edge (down out of it when tucked), clipped by `tabRow` so it
|
|
1630
|
+
* emerges from behind the ring rather than sliding over it. WAAPI so a
|
|
1631
|
+
* quick re-select restarts cleanly; the caller gates reduced motion. */
|
|
1632
|
+
intro() {
|
|
1633
|
+
if (!this.hasTab || typeof this.tabSlide.animate !== "function") return;
|
|
1634
|
+
for (const a of this.tabSlide.getAnimations?.() ?? []) a.cancel();
|
|
1635
|
+
this.tabSlide.animate(
|
|
1636
|
+
[{ transform: this.tucked ? "translateY(-100%)" : "translateY(100%)" }, { transform: "translateY(0)" }],
|
|
1637
|
+
{ duration: TAB_INTRO_MS, delay: TAB_INTRO_DELAY_MS, easing: POP_EASE, fill: "backwards" }
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
/** During a parameter drag the label gets out of the way — the old chip's
|
|
1641
|
+
* suppression, inherited by the tab. The box stays, so the drag keeps its
|
|
1642
|
+
* bearings. */
|
|
1643
|
+
setTabHidden(hidden) {
|
|
1644
|
+
if (hidden === this.tabHidden) return;
|
|
1645
|
+
this.tabHidden = hidden;
|
|
1646
|
+
this.tabRow.style.visibility = hidden ? "hidden" : "visible";
|
|
1647
|
+
}
|
|
1648
|
+
/** A marker is fused at the box's bottom-right: that corner squares off,
|
|
1649
|
+
* the inner fillet rounds it from inside, and the join appears. */
|
|
1650
|
+
setFused(fused) {
|
|
1651
|
+
if (fused === this.fused) return;
|
|
1652
|
+
this.fused = fused;
|
|
1653
|
+
this.inBR.square.style.display = fused ? "block" : "none";
|
|
1654
|
+
this.markJoin.square.style.display = fused ? "block" : "none";
|
|
1655
|
+
this.radius = "";
|
|
1656
|
+
}
|
|
1657
|
+
/** Returns whether the ring's geometry actually changed this call — the
|
|
1658
|
+
* draw loop's own motion signal, free because the cache is already here. */
|
|
1659
|
+
draw(target) {
|
|
1660
|
+
if (!target) {
|
|
1661
|
+
const moved2 = this.shown;
|
|
1662
|
+
if (this.shown) this.rootEl.style.display = "none";
|
|
1663
|
+
this.shown = false;
|
|
1664
|
+
this.rect = null;
|
|
1665
|
+
this.geom = "";
|
|
1666
|
+
return moved2;
|
|
1667
|
+
}
|
|
1668
|
+
const { rect, radii } = target;
|
|
1669
|
+
const s = RING_STROKE;
|
|
1670
|
+
const geom = `${rect.x}|${rect.y}|${rect.w}|${rect.h}`;
|
|
1671
|
+
const moved = geom !== this.geom;
|
|
1672
|
+
if (moved) {
|
|
1673
|
+
this.geom = geom;
|
|
1674
|
+
this.rootEl.style.display = "block";
|
|
1675
|
+
this.rootEl.style.transform = `translate(${rect.x - s}px,${rect.y - s}px)`;
|
|
1676
|
+
this.rootEl.style.width = `${rect.w + 2 * s}px`;
|
|
1677
|
+
this.rootEl.style.height = `${rect.h + 2 * s}px`;
|
|
1678
|
+
}
|
|
1679
|
+
this.shown = true;
|
|
1680
|
+
this.rect = rect;
|
|
1681
|
+
const tucked = rect.y - s < TAB_HEIGHT;
|
|
1682
|
+
if (tucked !== this.tucked) {
|
|
1683
|
+
this.tucked = tucked;
|
|
1684
|
+
this.tabRow.style.bottom = tucked ? "auto" : "100%";
|
|
1685
|
+
this.tabRow.style.top = tucked ? `${RING_STROKE}px` : "auto";
|
|
1686
|
+
this.tabBleed.style.top = tucked ? "auto" : "100%";
|
|
1687
|
+
this.tabBleed.style.bottom = tucked ? "100%" : "auto";
|
|
1688
|
+
}
|
|
1689
|
+
const past = rect.x - s + this.tabW + JOIN_RADIUS - window.innerWidth;
|
|
1690
|
+
const shift = past > 0 ? -Math.min(past, Math.max(0, rect.x - s)) : 0;
|
|
1691
|
+
if (shift !== this.tabShift) {
|
|
1692
|
+
this.tabShift = shift;
|
|
1693
|
+
this.tabRow.style.transform = shift === 0 ? "" : `translateX(${shift}px)`;
|
|
1694
|
+
}
|
|
1695
|
+
const width = rect.w + 2 * s;
|
|
1696
|
+
const clear = this.hasTab && !tucked ? this.tabW + shift - width : -1;
|
|
1697
|
+
const overhang = clear >= 0;
|
|
1698
|
+
const tabR = overhang ? Math.min(TAB_RADIUS, clear) : 0;
|
|
1699
|
+
this.dropFillets(overhang ? Math.min(JOIN_RADIUS, clear - tabR) : -1);
|
|
1700
|
+
const joinFits = !tucked && clear + JOIN_RADIUS <= 0;
|
|
1701
|
+
const dress = `${tucked ? "tucked" : tabR}|${joinFits}`;
|
|
1702
|
+
if (dress !== this.tabDress) {
|
|
1703
|
+
this.tabDress = dress;
|
|
1704
|
+
this.tab.style.borderRadius = tucked ? `0 0 ${TAB_RADIUS}px ${TAB_RADIUS}px` : `${TAB_RADIUS}px ${TAB_RADIUS}px ${tabR}px 0`;
|
|
1705
|
+
this.tabJoin.square.style.visibility = joinFits ? "visible" : "hidden";
|
|
1706
|
+
}
|
|
1707
|
+
const [tl, tr, br, bl] = radii;
|
|
1708
|
+
const outer = (r) => `${Math.round((r + s) * 100) / 100}px`;
|
|
1709
|
+
const radius = `${this.hasTab ? "0px" : outer(tl)} ${overhang ? "0px" : outer(tr)} ${this.fused ? "0px" : outer(br)} ${outer(bl)}`;
|
|
1710
|
+
if (radius !== this.radius) {
|
|
1711
|
+
this.radius = radius;
|
|
1712
|
+
this.box.style.borderRadius = radius;
|
|
1713
|
+
}
|
|
1714
|
+
return moved;
|
|
1715
|
+
}
|
|
1716
|
+
tabState() {
|
|
1717
|
+
if (!this.shown || this.tabHidden || !this.hasTab) return null;
|
|
1718
|
+
const b = this.tab.getBoundingClientRect();
|
|
1719
|
+
return { rect: { x: b.left, y: b.top, w: b.width, h: b.height }, text: this.label };
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
var Overlay = class {
|
|
1723
|
+
constructor() {
|
|
1724
|
+
this.root = null;
|
|
1725
|
+
/** The cursor label: pointer hover's name, riding the pointer. */
|
|
1726
|
+
this.cursorEl = null;
|
|
1727
|
+
this.cursorLabel = "";
|
|
1728
|
+
this.cursorW = 0;
|
|
1729
|
+
this.cursorShown = false;
|
|
1730
|
+
/** Standing ordinal markers, keyed by element path. */
|
|
1731
|
+
this.markerEls = /* @__PURE__ */ new Map();
|
|
1732
|
+
this.markerStyle = /* @__PURE__ */ new Map();
|
|
1733
|
+
this.markerPos = /* @__PURE__ */ new Map();
|
|
1734
|
+
/** Drawn marker geometry, for synthetic pointing — a wire host forwards
|
|
1735
|
+
* coordinates instead of real events, so the probe answers "was that a
|
|
1736
|
+
* marker?" itself and every host gets Beam's native behavior. */
|
|
1737
|
+
this.markerXY = /* @__PURE__ */ new Map();
|
|
1738
|
+
this.markersHidden = false;
|
|
1739
|
+
this.lastMarkers = [];
|
|
1740
|
+
/** The standing agent rings, one construction per decorated element path —
|
|
1741
|
+
* the markers' lifecycle, applied to a ring. */
|
|
1742
|
+
this.statusRings = /* @__PURE__ */ new Map();
|
|
1743
|
+
this.statusDress = /* @__PURE__ */ new Map();
|
|
1744
|
+
this.lastStatus = [];
|
|
1745
|
+
/** Hovering a marker points at its annotation: the hover construction
|
|
1746
|
+
* draws on its element in annotate's color, fused to the chip. */
|
|
1747
|
+
this.hoverAnnotate = false;
|
|
1748
|
+
/** Whether the annotation each ring is fused to is resolved — the one fact
|
|
1749
|
+
* that recolors the whole construction green, chip and ring together. */
|
|
1750
|
+
this.hoverResolved = false;
|
|
1751
|
+
this.selResolved = false;
|
|
1752
|
+
this.markerHandler = null;
|
|
1753
|
+
this.markerHover = null;
|
|
1754
|
+
this.colors = { hover: "#32b2ed", selection: "#32b2ed", chipText: "#ffffff", annotate: "#bc5cf3" };
|
|
1755
|
+
this.visible = false;
|
|
1756
|
+
/** A pointing mode is up: the page wears the crosshair. Separate from
|
|
1757
|
+
* `visible` because interact keeps the rings while giving the page its
|
|
1758
|
+
* cursor back. */
|
|
1759
|
+
this.pointing = false;
|
|
1760
|
+
this.pointingStyle = null;
|
|
1761
|
+
/** A parameter drag is in flight: the selection ring gets out of the way
|
|
1762
|
+
* so the change is readable. Hover stays live — this is not `visible`. */
|
|
1763
|
+
this.suppressSelection = false;
|
|
1764
|
+
}
|
|
1765
|
+
ensure() {
|
|
1766
|
+
if (this.root && this.root.isConnected) return true;
|
|
1767
|
+
const host = document.documentElement;
|
|
1768
|
+
if (!host) return false;
|
|
1769
|
+
const root = document.createElement("div");
|
|
1770
|
+
root.id = OVERLAY_ID;
|
|
1771
|
+
root.setAttribute("aria-hidden", "true");
|
|
1772
|
+
root.style.cssText = "position:fixed;inset:0;z-index:2147483646;pointer-events:none;contain:strict;";
|
|
1773
|
+
this.hoverRing = new Ring(root, true);
|
|
1774
|
+
this.selRing = new Ring(root, false);
|
|
1775
|
+
const cursor = document.createElement("div");
|
|
1776
|
+
cursor.style.cssText = `position:fixed;left:0;top:0;pointer-events:none;display:none;will-change:transform;padding:2px 6px 1px;font:600 11px/14px ${CHROME_FONT};letter-spacing:-0.08px;white-space:nowrap;border-radius:${BADGE_RADIUS}px;box-shadow:0 3px 8px rgba(0,0,0,0.18);opacity:0;transition:opacity ${CURSOR_FADE_MS}ms ease;`;
|
|
1777
|
+
root.appendChild(cursor);
|
|
1778
|
+
this.cursorEl = cursor;
|
|
1779
|
+
host.appendChild(root);
|
|
1780
|
+
this.root = root;
|
|
1781
|
+
this.restyle();
|
|
1782
|
+
return true;
|
|
1783
|
+
}
|
|
1784
|
+
setColors(c) {
|
|
1785
|
+
this.colors = { ...this.colors, ...c };
|
|
1786
|
+
if (!this.root) return;
|
|
1787
|
+
this.restyle();
|
|
1788
|
+
this.markerStyle.clear();
|
|
1789
|
+
this.statusDress.clear();
|
|
1790
|
+
}
|
|
1791
|
+
/** The color one agent state paints with — the host's, else the token's
|
|
1792
|
+
* literal (`AGENT_FALLBACK`). */
|
|
1793
|
+
statusColor(state) {
|
|
1794
|
+
return this.colors[state] ?? AGENT_FALLBACK[state];
|
|
1795
|
+
}
|
|
1796
|
+
annotateColor() {
|
|
1797
|
+
return this.colors.annotate ?? this.colors.selection;
|
|
1798
|
+
}
|
|
1799
|
+
resolvedColor() {
|
|
1800
|
+
return this.colors.resolved ?? RESOLVED_FALLBACK;
|
|
1801
|
+
}
|
|
1802
|
+
/** What an annotation's construction paints with: purple while it is still
|
|
1803
|
+
* asking, green once it has been answered. One function, because the chip
|
|
1804
|
+
* and every ring that fuses to it must never disagree. */
|
|
1805
|
+
annColor(resolved) {
|
|
1806
|
+
return resolved ? this.resolvedColor() : this.annotateColor();
|
|
1807
|
+
}
|
|
1808
|
+
restyle() {
|
|
1809
|
+
const hoverAnn = this.annColor(this.hoverResolved);
|
|
1810
|
+
this.hoverRing.style(this.hoverAnnotate ? hoverAnn : this.colors.hover, this.colors.chipText, hoverAnn);
|
|
1811
|
+
const selAnn = this.annColor(this.selResolved);
|
|
1812
|
+
this.selRing.style(this.selRing.fused ? selAnn : this.colors.selection, this.colors.chipText, selAnn);
|
|
1813
|
+
if (this.cursorEl) {
|
|
1814
|
+
this.cursorEl.style.background = this.colors.hover;
|
|
1815
|
+
this.cursorEl.style.color = this.colors.chipText;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
/** Marker hover recolors the hover construction to the annotation's own
|
|
1819
|
+
* color — purple while it is still asking, the resolved green once it has
|
|
1820
|
+
* been answered. */
|
|
1821
|
+
setHoverAccent(annotate, resolved = false) {
|
|
1822
|
+
if (!this.ensure()) return;
|
|
1823
|
+
if (annotate === this.hoverAnnotate && resolved === this.hoverResolved) return;
|
|
1824
|
+
this.hoverAnnotate = annotate;
|
|
1825
|
+
this.hoverResolved = resolved;
|
|
1826
|
+
this.restyle();
|
|
1827
|
+
}
|
|
1828
|
+
setHoverFused(fused) {
|
|
1829
|
+
if (this.ensure()) this.hoverRing.setFused(fused);
|
|
1830
|
+
}
|
|
1831
|
+
setSelectionLabel(label) {
|
|
1832
|
+
if (this.ensure()) this.selRing.setLabel(label);
|
|
1833
|
+
}
|
|
1834
|
+
/** `resolved` is the fused mark's own state, not the selection's: a request
|
|
1835
|
+
* answered while its ring is standing recolors in place, on the same
|
|
1836
|
+
* clock the chip below it recolors on. */
|
|
1837
|
+
setSelectionFused(fused, resolved = false) {
|
|
1838
|
+
if (!this.ensure()) return;
|
|
1839
|
+
const next = fused && !this.suppressSelection;
|
|
1840
|
+
const done = next && resolved;
|
|
1841
|
+
if (next === this.selRing.fused && done === this.selResolved) return;
|
|
1842
|
+
this.selResolved = done;
|
|
1843
|
+
this.selRing.setFused(next);
|
|
1844
|
+
this.restyle();
|
|
1845
|
+
}
|
|
1846
|
+
drawHover(target, label) {
|
|
1847
|
+
if (!this.ensure()) return false;
|
|
1848
|
+
if (target && label !== null) this.hoverRing.setLabel(label);
|
|
1849
|
+
this.hoverRing.setTabHidden(this.suppressSelection);
|
|
1850
|
+
return this.hoverRing.draw(this.visible ? target : null);
|
|
1851
|
+
}
|
|
1852
|
+
/** Whether the hover construction carries its tab — off for pointer hover
|
|
1853
|
+
* (the cursor label owns the name), on for path-driven hovers. */
|
|
1854
|
+
setHoverTab(show) {
|
|
1855
|
+
if (this.ensure()) this.hoverRing.setTab(show);
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* The cursor label follows the pointer at its top-right — flipped below
|
|
1859
|
+
* near the viewport top, pulled left of the pointer at the right edge, so
|
|
1860
|
+
* the name is always beside the cursor and never clipped. Text is measured
|
|
1861
|
+
* only when it changes; a move writes one transform.
|
|
1862
|
+
*/
|
|
1863
|
+
drawCursor(x, y, label) {
|
|
1864
|
+
if (!this.ensure() || !this.visible) return;
|
|
1865
|
+
const el = this.cursorEl;
|
|
1866
|
+
const showing = this.cursorShown;
|
|
1867
|
+
if (!showing) {
|
|
1868
|
+
this.cursorShown = true;
|
|
1869
|
+
el.style.display = "block";
|
|
1870
|
+
}
|
|
1871
|
+
if (label !== this.cursorLabel) {
|
|
1872
|
+
this.cursorLabel = label;
|
|
1873
|
+
el.textContent = label;
|
|
1874
|
+
this.cursorW = el.offsetWidth;
|
|
1875
|
+
} else if (!showing) {
|
|
1876
|
+
void el.offsetWidth;
|
|
1877
|
+
}
|
|
1878
|
+
let cx = x + CURSOR_DX;
|
|
1879
|
+
if (cx + this.cursorW + 4 > window.innerWidth) cx = Math.max(4, x - CURSOR_DX - this.cursorW);
|
|
1880
|
+
let cy = y - CURSOR_DY;
|
|
1881
|
+
if (cy < 4) cy = y + CURSOR_FLIP_DY;
|
|
1882
|
+
el.style.transform = `translate(${cx}px,${cy}px)`;
|
|
1883
|
+
if (!showing) el.style.opacity = "1";
|
|
1884
|
+
}
|
|
1885
|
+
/** Take the cursor label down — fading in place (a click, the pointer
|
|
1886
|
+
* leaving) or instantly (scroll, teardown: a stale position must not
|
|
1887
|
+
* linger where the content used to be). */
|
|
1888
|
+
hideCursor(fade) {
|
|
1889
|
+
const el = this.cursorEl;
|
|
1890
|
+
if (!el || !this.cursorShown) return;
|
|
1891
|
+
this.cursorShown = false;
|
|
1892
|
+
el.style.opacity = "0";
|
|
1893
|
+
if (!fade) el.style.display = "none";
|
|
1894
|
+
}
|
|
1895
|
+
/** The crosshair sheet follows `pointing && visible` — installed under the
|
|
1896
|
+
* document root (the spotlight's pattern, page CSS can't outrank it),
|
|
1897
|
+
* removed the moment pointing ends so the page's own cursors return. */
|
|
1898
|
+
syncCursorStyle() {
|
|
1899
|
+
const want = this.pointing && this.visible;
|
|
1900
|
+
if (want) {
|
|
1901
|
+
if (this.pointingStyle && this.pointingStyle.isConnected) return;
|
|
1902
|
+
const host = document.documentElement;
|
|
1903
|
+
if (!host) return;
|
|
1904
|
+
const style = document.createElement("style");
|
|
1905
|
+
style.id = POINTING_STYLE_ID;
|
|
1906
|
+
style.textContent = POINTING_CSS;
|
|
1907
|
+
host.appendChild(style);
|
|
1908
|
+
this.pointingStyle = style;
|
|
1909
|
+
} else if (this.pointingStyle) {
|
|
1910
|
+
this.pointingStyle.remove();
|
|
1911
|
+
this.pointingStyle = null;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
/** The click hand-off: the cursor label freezes and fades while the new
|
|
1915
|
+
* selection's tab pushes out of the ring — one name changing owners.
|
|
1916
|
+
* Reduced motion keeps the fade (it is one) and skips the push. */
|
|
1917
|
+
handOff() {
|
|
1918
|
+
if (!this.ensure()) return;
|
|
1919
|
+
this.hideCursor(true);
|
|
1920
|
+
if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
1921
|
+
this.selRing.intro();
|
|
1922
|
+
}
|
|
1923
|
+
drawSelection(target) {
|
|
1924
|
+
if (!this.ensure()) return false;
|
|
1925
|
+
return this.selRing.draw(this.visible && !this.suppressSelection ? target : null);
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* The standing agent rings — the full construction on every element a
|
|
1929
|
+
* managed turn is live on, redrawn every frame like the markers so they
|
|
1930
|
+
* can't lag a scroll. Standing chrome: this draws with no selection, and
|
|
1931
|
+
* only the host clears it.
|
|
1932
|
+
*
|
|
1933
|
+
* One ring per element and no more: the caller stands the selection and
|
|
1934
|
+
* hover constructions down on these elements, because two rings on one
|
|
1935
|
+
* element read as a bug rather than as two facts.
|
|
1936
|
+
*/
|
|
1937
|
+
drawStatus(draws) {
|
|
1938
|
+
if (!this.ensure()) return false;
|
|
1939
|
+
this.lastStatus = draws;
|
|
1940
|
+
let moved = false;
|
|
1941
|
+
const keep = new Set(draws.map((d) => d.key));
|
|
1942
|
+
for (const [key, ring] of this.statusRings) {
|
|
1943
|
+
if (keep.has(key)) continue;
|
|
1944
|
+
ring.destroy();
|
|
1945
|
+
this.statusRings.delete(key);
|
|
1946
|
+
this.statusDress.delete(key);
|
|
1947
|
+
moved = true;
|
|
1948
|
+
}
|
|
1949
|
+
for (const d of draws) {
|
|
1950
|
+
let ring = this.statusRings.get(d.key);
|
|
1951
|
+
if (!ring) {
|
|
1952
|
+
ring = new Ring(this.root, false, true);
|
|
1953
|
+
this.statusRings.set(d.key, ring);
|
|
1954
|
+
moved = true;
|
|
1955
|
+
}
|
|
1956
|
+
const dress = `${d.state}|${this.colors.chipText}|${this.statusColor(d.state)}`;
|
|
1957
|
+
if (this.statusDress.get(d.key) !== dress) {
|
|
1958
|
+
this.statusDress.set(d.key, dress);
|
|
1959
|
+
const color = this.statusColor(d.state);
|
|
1960
|
+
const tab = AGENT_TAB[d.state];
|
|
1961
|
+
ring.style(color, this.colors.chipText, color);
|
|
1962
|
+
ring.setLabel(tab.text);
|
|
1963
|
+
ring.setGlyph(tab.glyph, tab.spin);
|
|
1964
|
+
}
|
|
1965
|
+
ring.setFused(d.fused);
|
|
1966
|
+
if (ring.draw(d.target)) moved = true;
|
|
1967
|
+
}
|
|
1968
|
+
return moved;
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* The standing ordinal markers — annotation numbers at their elements'
|
|
1972
|
+
* bottom-right, redrawn every frame like the rings so they can't lag a
|
|
1973
|
+
* scroll. A marker on the selected element draws fused (square top, the
|
|
1974
|
+
* ring's join beside it); the CSS transition is what makes ring dismissal
|
|
1975
|
+
* a morph instead of a jump. Markers are the one pointer-active chrome:
|
|
1976
|
+
* a click answers the host, never the page.
|
|
1977
|
+
*/
|
|
1978
|
+
drawMarkers(draws) {
|
|
1979
|
+
if (!this.ensure()) return false;
|
|
1980
|
+
this.lastMarkers = draws;
|
|
1981
|
+
let moved = false;
|
|
1982
|
+
const born = [];
|
|
1983
|
+
const keep = new Set(draws.map((d) => d.key));
|
|
1984
|
+
for (const [key, el] of this.markerEls) {
|
|
1985
|
+
if (!keep.has(key)) {
|
|
1986
|
+
el.remove();
|
|
1987
|
+
this.markerEls.delete(key);
|
|
1988
|
+
this.markerStyle.delete(key);
|
|
1989
|
+
this.markerPos.delete(key);
|
|
1990
|
+
this.markerXY.delete(key);
|
|
1991
|
+
moved = true;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
for (const d of draws) {
|
|
1995
|
+
let el = this.markerEls.get(d.key);
|
|
1996
|
+
if (!el) {
|
|
1997
|
+
el = document.createElement("div");
|
|
1998
|
+
el.setAttribute("data-bp-marker", "");
|
|
1999
|
+
el.style.cssText = `position:fixed;left:0;top:0;display:flex;align-items:center;justify-content:center;pointer-events:auto;cursor:pointer;z-index:1;width:${MARKER_SIZE}px;height:${MARKER_SIZE}px;box-sizing:border-box;font:600 11px/1 ${CHROME_FONT};letter-spacing:-0.4px;font-variant-numeric:tabular-nums;will-change:translate;border-radius:${BADGE_RADIUS}px;transition:border-radius ${MARKER_MORPH_MS}ms ${POP_EASE},box-shadow ${MARKER_MORPH_MS}ms ease,opacity 200ms ease,background-color ${RECOLOR_MS}ms ${RECOLOR_EASE};`;
|
|
2000
|
+
const key = d.key;
|
|
2001
|
+
const marker = el;
|
|
2002
|
+
el.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
2003
|
+
el.addEventListener("click", (e) => {
|
|
2004
|
+
e.preventDefault();
|
|
2005
|
+
e.stopPropagation();
|
|
2006
|
+
const ordinal = Number(marker.dataset.ordinal ?? "0");
|
|
2007
|
+
this.markerHandler?.(key, ordinal);
|
|
2008
|
+
emit("markerClick", { path: key, ordinal });
|
|
2009
|
+
});
|
|
2010
|
+
el.addEventListener("pointerenter", () => this.markerHover?.(key));
|
|
2011
|
+
el.addEventListener("pointerleave", () => this.markerHover?.(null));
|
|
2012
|
+
this.root.appendChild(el);
|
|
2013
|
+
this.markerEls.set(d.key, el);
|
|
2014
|
+
born.push({ el, ordinal: d.ordinal });
|
|
2015
|
+
moved = true;
|
|
2016
|
+
}
|
|
2017
|
+
if (this.markersHidden) el.style.display = "flex";
|
|
2018
|
+
const s = RING_STROKE;
|
|
2019
|
+
let x = d.rect.x + d.rect.w + s - MARKER_SIZE;
|
|
2020
|
+
let y = d.rect.y + d.rect.h + s;
|
|
2021
|
+
if (y + MARKER_SIZE > window.innerHeight) y = d.rect.y + d.rect.h - s - MARKER_SIZE;
|
|
2022
|
+
x = Math.max(0, Math.min(x, window.innerWidth - MARKER_SIZE));
|
|
2023
|
+
this.markerXY.set(d.key, { x, y, ordinal: d.ordinal });
|
|
2024
|
+
const pos = `${x}px ${y}px`;
|
|
2025
|
+
if (this.markerPos.get(d.key) !== pos) {
|
|
2026
|
+
this.markerPos.set(d.key, pos);
|
|
2027
|
+
el.style.translate = pos;
|
|
2028
|
+
moved = true;
|
|
2029
|
+
}
|
|
2030
|
+
const style = `${d.ordinal}|${d.fused}|${d.status}|${d.detached}|${d.agent ?? ""}`;
|
|
2031
|
+
const was = this.markerStyle.get(d.key);
|
|
2032
|
+
if (was !== style) {
|
|
2033
|
+
this.markerStyle.set(d.key, style);
|
|
2034
|
+
const done = d.status === "resolved";
|
|
2035
|
+
const mark = done ? CHECK_GLYPH : String(d.ordinal);
|
|
2036
|
+
const turning = was !== void 0 && was.split("|")[2] !== d.status && !matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
2037
|
+
if (turning) turnOver(el, mark);
|
|
2038
|
+
else if (done) el.innerHTML = mark;
|
|
2039
|
+
else el.textContent = mark;
|
|
2040
|
+
el.dataset.ordinal = String(d.ordinal);
|
|
2041
|
+
el.style.background = d.detached ? "#a9adb1" : d.agent ? this.statusColor(d.agent) : done ? this.resolvedColor() : this.annotateColor();
|
|
2042
|
+
el.style.color = this.colors.chipText;
|
|
2043
|
+
el.style.border = "none";
|
|
2044
|
+
el.style.opacity = "1";
|
|
2045
|
+
el.style.borderRadius = d.fused ? `0 0 ${BADGE_RADIUS}px ${BADGE_RADIUS}px` : `${BADGE_RADIUS}px`;
|
|
2046
|
+
el.style.boxShadow = d.fused ? "0 1px 3px rgba(0,0,0,0.06)" : "0 3px 8px rgba(0,0,0,0.15)";
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
if (born.length > 0 && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
2050
|
+
born.sort((a, b) => a.ordinal - b.ordinal);
|
|
2051
|
+
born.forEach(
|
|
2052
|
+
(b, i) => b.el.animate([{ opacity: 0, scale: "0.25", offset: 0 }], {
|
|
2053
|
+
duration: 280,
|
|
2054
|
+
delay: Math.min(i * 45, 400),
|
|
2055
|
+
easing: POP_EASE,
|
|
2056
|
+
fill: "backwards"
|
|
2057
|
+
})
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
this.markersHidden = false;
|
|
2061
|
+
return moved;
|
|
2062
|
+
}
|
|
2063
|
+
/** The marker under a viewport point, for synthetic pointing. Only markers
|
|
2064
|
+
* actually drawn this session answer — hidden overlays have none. */
|
|
2065
|
+
markerAtPoint(x, y) {
|
|
2066
|
+
if (!this.visible || this.markersHidden) return null;
|
|
2067
|
+
for (const [path, m] of this.markerXY) {
|
|
2068
|
+
if (x >= m.x && x <= m.x + MARKER_SIZE && y >= m.y && y <= m.y + MARKER_SIZE)
|
|
2069
|
+
return { path, ordinal: m.ordinal };
|
|
2070
|
+
}
|
|
2071
|
+
return null;
|
|
2072
|
+
}
|
|
2073
|
+
hideAll() {
|
|
2074
|
+
if (!this.root) return;
|
|
2075
|
+
this.hoverRing.draw(null);
|
|
2076
|
+
this.selRing.draw(null);
|
|
2077
|
+
for (const ring of this.statusRings.values()) ring.draw(null);
|
|
2078
|
+
this.hideCursor(false);
|
|
2079
|
+
for (const el of this.markerEls.values()) el.style.display = "none";
|
|
2080
|
+
this.markersHidden = true;
|
|
2081
|
+
}
|
|
2082
|
+
/** What is actually painted right now — the conformance suite's read.
|
|
2083
|
+
* `hover` and `selection` stay the element rects (the construction paints
|
|
2084
|
+
* the stroke outside them); `hoverTab`, `cursorChip`, `tab`, `badge` and
|
|
2085
|
+
* `markers` are the chrome. Pointer hover names through `cursorChip`;
|
|
2086
|
+
* `hoverTab` stands only for path-driven hovers (layers preview, a
|
|
2087
|
+
* hovered marker). */
|
|
2088
|
+
state() {
|
|
2089
|
+
if (!this.root)
|
|
2090
|
+
return {
|
|
2091
|
+
hover: null,
|
|
2092
|
+
hoverTab: null,
|
|
2093
|
+
cursorChip: null,
|
|
2094
|
+
selection: null,
|
|
2095
|
+
tab: null,
|
|
2096
|
+
badge: null,
|
|
2097
|
+
markers: [],
|
|
2098
|
+
status: []
|
|
2099
|
+
};
|
|
2100
|
+
const rect = (el) => {
|
|
2101
|
+
const b = el.getBoundingClientRect();
|
|
2102
|
+
return { x: b.left, y: b.top, w: b.width, h: b.height };
|
|
2103
|
+
};
|
|
2104
|
+
const markers = this.markersHidden ? [] : this.lastMarkers.map((d) => {
|
|
2105
|
+
const el = this.markerEls.get(d.key);
|
|
2106
|
+
return el ? { rect: rect(el), text: String(d.ordinal), fused: d.fused } : null;
|
|
2107
|
+
}).filter((m) => m !== null);
|
|
2108
|
+
const fused = markers.find((m) => m.fused);
|
|
2109
|
+
return {
|
|
2110
|
+
hover: this.hoverRing.shown ? this.hoverRing.rect : null,
|
|
2111
|
+
hoverTab: this.hoverRing.tabState(),
|
|
2112
|
+
cursorChip: this.cursorShown && this.cursorEl ? { rect: rect(this.cursorEl), text: this.cursorLabel } : null,
|
|
2113
|
+
selection: this.selRing.shown ? this.selRing.rect : null,
|
|
2114
|
+
tab: this.selRing.tabState(),
|
|
2115
|
+
badge: fused ? { rect: fused.rect, text: fused.text } : null,
|
|
2116
|
+
markers: markers.map((m) => ({ rect: m.rect, text: m.text })),
|
|
2117
|
+
// Element rects, like `hover` and `selection`: the construction paints
|
|
2118
|
+
// its stroke outside them. `text` is what the tab says.
|
|
2119
|
+
status: this.lastStatus.map((d) => {
|
|
2120
|
+
const ring = this.statusRings.get(d.key);
|
|
2121
|
+
if (!ring?.shown || !ring.rect) return null;
|
|
2122
|
+
return { rect: ring.rect, text: AGENT_TAB[d.state].text, state: d.state };
|
|
2123
|
+
}).filter((r) => r !== null)
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
function colorMix(color, alpha) {
|
|
2128
|
+
return `color-mix(in srgb, ${color} ${Math.round(alpha * 100)}%, transparent)`;
|
|
2129
|
+
}
|
|
2130
|
+
var SPOT_CSS = `[${SPOT_ATTR}="0"]{visibility:hidden!important}[${SPOT_ATTR}="1"]{visibility:visible!important}`;
|
|
2131
|
+
var ARMED_CSS = `body{visibility:hidden!important}${SPOT_CSS}`;
|
|
2132
|
+
var Spotlight = class {
|
|
2133
|
+
constructor() {
|
|
2134
|
+
this.style = null;
|
|
2135
|
+
this.text = "";
|
|
2136
|
+
this.path = null;
|
|
2137
|
+
this.applied = false;
|
|
2138
|
+
this.marked = /* @__PURE__ */ new Set();
|
|
2139
|
+
/** `<body>`'s children the first time the element resolved. Without React
|
|
2140
|
+
* this is the only clue a node is a portal: it wasn't there before. */
|
|
2141
|
+
this.baseline = null;
|
|
2142
|
+
this.rootWatch = null;
|
|
2143
|
+
}
|
|
2144
|
+
/** Spotlight the element at `path`; `null` turns it off. */
|
|
2145
|
+
set(path) {
|
|
2146
|
+
if (path === this.path) return;
|
|
2147
|
+
this.path = path;
|
|
2148
|
+
this.applied = false;
|
|
2149
|
+
this.baseline = null;
|
|
2150
|
+
this.clearMarks();
|
|
2151
|
+
if (path === null) {
|
|
2152
|
+
this.write("");
|
|
2153
|
+
this.emitState();
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
this.write(ARMED_CSS);
|
|
2157
|
+
this.emitState();
|
|
2158
|
+
this.refresh();
|
|
2159
|
+
}
|
|
2160
|
+
/** Re-measure the kept set. Called on every coalesced content change. */
|
|
2161
|
+
refresh() {
|
|
2162
|
+
if (this.path === null) return;
|
|
2163
|
+
if (!document.body) return;
|
|
2164
|
+
const el = elementAt(this.path);
|
|
2165
|
+
if (!el || !el.isConnected) {
|
|
2166
|
+
if (!this.applied) return;
|
|
2167
|
+
this.applied = false;
|
|
2168
|
+
this.clearMarks();
|
|
2169
|
+
this.write(ARMED_CSS);
|
|
2170
|
+
this.emitState();
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
const { hide, show } = this.compute(el);
|
|
2174
|
+
this.mark(hide, show);
|
|
2175
|
+
this.write(SPOT_CSS);
|
|
2176
|
+
if (!this.applied) {
|
|
2177
|
+
this.applied = true;
|
|
2178
|
+
this.emitState();
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
state() {
|
|
2182
|
+
let kept = 0;
|
|
2183
|
+
for (const el of this.marked) if (el.getAttribute(SPOT_ATTR) === "1") kept++;
|
|
2184
|
+
return { path: this.path, applied: this.applied, hidden: this.marked.size - kept, kept };
|
|
2185
|
+
}
|
|
2186
|
+
/** Is `el` marked hidden right now? Used by the tag/selection paths so the
|
|
2187
|
+
* spotlight and the overlay can't argue about one element. */
|
|
2188
|
+
hidden(el) {
|
|
2189
|
+
return el.getAttribute(SPOT_ATTR) === "0";
|
|
2190
|
+
}
|
|
2191
|
+
compute(el) {
|
|
2192
|
+
const hide = [];
|
|
2193
|
+
const show = [];
|
|
2194
|
+
const body = document.body;
|
|
2195
|
+
if (body && this.baseline === null) this.baseline = new Set(Array.from(body.children));
|
|
2196
|
+
const chain = [];
|
|
2197
|
+
for (let node = el; node; node = node.parentElement) chain.unshift(node);
|
|
2198
|
+
const fiber = fiberOf(el);
|
|
2199
|
+
const rect = el.getBoundingClientRect();
|
|
2200
|
+
for (let i = 0; i < chain.length - 1; i++) {
|
|
2201
|
+
for (const child of Array.from(chain[i].children)) {
|
|
2202
|
+
if (child === chain[i + 1] || child.id === OVERLAY_ID) continue;
|
|
2203
|
+
if (NON_VISUAL.has(child.tagName.toLowerCase())) continue;
|
|
2204
|
+
if (this.owned(child, fiber, rect)) show.push(child);
|
|
2205
|
+
else hide.push(child);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
return { hide, show };
|
|
2209
|
+
}
|
|
2210
|
+
/** Did the focused element put this node on screen? */
|
|
2211
|
+
owned(child, focus, rect) {
|
|
2212
|
+
if (focus) {
|
|
2213
|
+
if (this.ownedFiber(child, focus)) return true;
|
|
2214
|
+
if (fiberOf(child) === null) {
|
|
2215
|
+
let scanned = 0;
|
|
2216
|
+
for (const node of Array.from(child.querySelectorAll("*"))) {
|
|
2217
|
+
if (++scanned > PORTAL_SCAN) break;
|
|
2218
|
+
if (this.ownedFiber(node, focus)) return true;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
return false;
|
|
2222
|
+
}
|
|
2223
|
+
if (!this.baseline || child.parentElement !== document.body || this.baseline.has(child)) return false;
|
|
2224
|
+
const b = child.getBoundingClientRect();
|
|
2225
|
+
return b.width > 0 && b.height > 0 && b.left < rect.right && b.right > rect.left && b.top < rect.bottom && b.bottom > rect.top;
|
|
2226
|
+
}
|
|
2227
|
+
/** Does `node`'s fiber ancestry pass through the focused element's fiber? */
|
|
2228
|
+
ownedFiber(node, focus) {
|
|
2229
|
+
let f = fiberOf(node);
|
|
2230
|
+
const alt = focus.alternate ?? null;
|
|
2231
|
+
for (let steps = 0; f && steps < MAX_FIBER_WALK; steps++, f = f.return) {
|
|
2232
|
+
if (f === focus || f === alt || (f.alternate ?? null) === focus) return true;
|
|
2233
|
+
}
|
|
2234
|
+
return false;
|
|
2235
|
+
}
|
|
2236
|
+
mark(hide, show) {
|
|
2237
|
+
const next = new Set(hide);
|
|
2238
|
+
for (const el of show) next.add(el);
|
|
2239
|
+
for (const el of this.marked) if (!next.has(el)) el.removeAttribute(SPOT_ATTR);
|
|
2240
|
+
for (const el of hide) if (el.getAttribute(SPOT_ATTR) !== "0") el.setAttribute(SPOT_ATTR, "0");
|
|
2241
|
+
for (const el of show) if (el.getAttribute(SPOT_ATTR) !== "1") el.setAttribute(SPOT_ATTR, "1");
|
|
2242
|
+
this.marked = next;
|
|
2243
|
+
}
|
|
2244
|
+
clearMarks() {
|
|
2245
|
+
for (const el of this.marked) el.removeAttribute(SPOT_ATTR);
|
|
2246
|
+
this.marked = /* @__PURE__ */ new Set();
|
|
2247
|
+
}
|
|
2248
|
+
write(text) {
|
|
2249
|
+
this.text = text;
|
|
2250
|
+
if (!this.ensureStyle()) return;
|
|
2251
|
+
if (this.style.textContent !== text) this.style.textContent = text;
|
|
2252
|
+
}
|
|
2253
|
+
/**
|
|
2254
|
+
* The sheet lives on `<html>`, not in the override stylesheet, so the two
|
|
2255
|
+
* can never fight — and it has to exist before the document has a `<body>`,
|
|
2256
|
+
* which is the whole point of arming.
|
|
2257
|
+
*/
|
|
2258
|
+
ensureStyle() {
|
|
2259
|
+
if (this.style && this.style.isConnected) return true;
|
|
2260
|
+
const host = document.documentElement;
|
|
2261
|
+
if (!host) {
|
|
2262
|
+
this.waitForRoot();
|
|
2263
|
+
return false;
|
|
2264
|
+
}
|
|
2265
|
+
const style = document.createElement("style");
|
|
2266
|
+
style.id = SPOT_STYLE_ID;
|
|
2267
|
+
style.textContent = this.text;
|
|
2268
|
+
host.appendChild(style);
|
|
2269
|
+
this.style = style;
|
|
2270
|
+
return true;
|
|
2271
|
+
}
|
|
2272
|
+
waitForRoot() {
|
|
2273
|
+
if (this.rootWatch || typeof MutationObserver === "undefined") return;
|
|
2274
|
+
this.rootWatch = new MutationObserver(() => {
|
|
2275
|
+
if (!document.documentElement) return;
|
|
2276
|
+
this.rootWatch?.disconnect();
|
|
2277
|
+
this.rootWatch = null;
|
|
2278
|
+
this.write(this.text);
|
|
2279
|
+
this.refresh();
|
|
2280
|
+
});
|
|
2281
|
+
this.rootWatch.observe(document, { childList: true, subtree: true });
|
|
2282
|
+
}
|
|
2283
|
+
emitState() {
|
|
2284
|
+
emit("spotlight", this.state());
|
|
2285
|
+
}
|
|
2286
|
+
};
|
|
2287
|
+
var RuntimeParams = class {
|
|
2288
|
+
constructor() {
|
|
2289
|
+
this.values = {};
|
|
2290
|
+
this.subs = /* @__PURE__ */ new Set();
|
|
2291
|
+
/** Channels the page has read at least once, this document. */
|
|
2292
|
+
this.claimed = /* @__PURE__ */ new Set();
|
|
2293
|
+
/** Before/after: suspended, every read falls through to the page's own value. */
|
|
2294
|
+
this.enabled = true;
|
|
2295
|
+
}
|
|
2296
|
+
api() {
|
|
2297
|
+
return {
|
|
2298
|
+
get: (name, fallback) => {
|
|
2299
|
+
if (!this.claimed.has(name)) {
|
|
2300
|
+
this.claimed.add(name);
|
|
2301
|
+
emit("claims", { channels: Array.from(this.claimed) });
|
|
2302
|
+
}
|
|
2303
|
+
if (!this.enabled) return fallback;
|
|
2304
|
+
const v = this.values[name];
|
|
2305
|
+
return v === void 0 ? fallback : v;
|
|
2306
|
+
},
|
|
2307
|
+
all: () => ({ ...this.values }),
|
|
2308
|
+
subscribe: (fn) => {
|
|
2309
|
+
this.subs.add(fn);
|
|
2310
|
+
return () => this.subs.delete(fn);
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
set(values, enabled) {
|
|
2315
|
+
this.values = values;
|
|
2316
|
+
this.enabled = enabled;
|
|
2317
|
+
this.notify();
|
|
2318
|
+
}
|
|
2319
|
+
claims() {
|
|
2320
|
+
return Array.from(this.claimed);
|
|
2321
|
+
}
|
|
2322
|
+
// A page that reads parameters in render needs a nudge to render again, and
|
|
2323
|
+
// there is no general way to ask a framework for one. So: tell subscribers,
|
|
2324
|
+
// and dispatch a DOM event for anything that would rather listen than
|
|
2325
|
+
// subscribe. Both carry the values, so neither has to read back.
|
|
2326
|
+
notify() {
|
|
2327
|
+
const snapshot = { ...this.values };
|
|
2328
|
+
for (const fn of this.subs) {
|
|
2329
|
+
try {
|
|
2330
|
+
fn(snapshot);
|
|
2331
|
+
} catch {
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
try {
|
|
2335
|
+
window.dispatchEvent(new CustomEvent("bp:params", { detail: snapshot }));
|
|
2336
|
+
} catch {
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
};
|
|
2340
|
+
var SCROLL_SETTLE_MS = 150;
|
|
2341
|
+
var LOOP_ACTIVE_MS = 500;
|
|
2342
|
+
var LOOP_IDLE_MS = 250;
|
|
2343
|
+
var Probe = class {
|
|
2344
|
+
constructor() {
|
|
2345
|
+
this.overlay = new Overlay();
|
|
2346
|
+
this.params = new RuntimeParams();
|
|
2347
|
+
this.spot = new Spotlight();
|
|
2348
|
+
this.tagSeq = 0;
|
|
2349
|
+
this.hoverEl = null;
|
|
2350
|
+
this.hoverLabel = null;
|
|
2351
|
+
/** How the hover landed: the pointer carries the cursor label, a path
|
|
2352
|
+
* (layers preview) keeps the ring's own tab — no cursor to follow. */
|
|
2353
|
+
this.hoverVia = "pointer";
|
|
2354
|
+
this.selEl = null;
|
|
2355
|
+
this.rafId = null;
|
|
2356
|
+
/** Standing annotation markers the host asked for — see `decorate`. */
|
|
2357
|
+
this.decorations = [];
|
|
2358
|
+
/** When each mark's path first failed to resolve — a mark only falls back
|
|
2359
|
+
* to its stored snapshot after a settle, so a booting document (elements
|
|
2360
|
+
* three renders away) never flashes gray markers at stale positions. */
|
|
2361
|
+
this.unresolvedSince = /* @__PURE__ */ new Map();
|
|
2362
|
+
/** The marker under the pointer, owning the hover construction. */
|
|
2363
|
+
this.markerHoverPath = null;
|
|
2364
|
+
this.mutationRaf = null;
|
|
2365
|
+
this.declRaf = null;
|
|
2366
|
+
/** When the last activity signal landed — the loop's full-rate window. */
|
|
2367
|
+
this.lastActivityAt = 0;
|
|
2368
|
+
/** Hover suppression window while the page scrolls. */
|
|
2369
|
+
this.scrollingUntil = 0;
|
|
2370
|
+
this.idleTimer = null;
|
|
2371
|
+
this.activityAttached = false;
|
|
2372
|
+
/**
|
|
2373
|
+
* Tags someone *else* owns — an override stylesheet, a pin.
|
|
2374
|
+
*
|
|
2375
|
+
* The selection hands its tag back when it moves on; a held one never does,
|
|
2376
|
+
* because the rule addressing it outlives the pick that wrote it. Without
|
|
2377
|
+
* this, the tweak you just tuned came undone the moment you inspected the
|
|
2378
|
+
* next element: `[data-bp-sel="7"]` stopped matching anything.
|
|
2379
|
+
*
|
|
2380
|
+
* Tag values, not elements: a page that re-renders the node away leaves a
|
|
2381
|
+
* short dead string here rather than a detached `Element` this set would
|
|
2382
|
+
* otherwise keep alive for the session.
|
|
2383
|
+
*/
|
|
2384
|
+
this.heldTags = /* @__PURE__ */ new Set();
|
|
2385
|
+
this.onScroll = () => {
|
|
2386
|
+
this.scrollingUntil = performance.now() + SCROLL_SETTLE_MS;
|
|
2387
|
+
if (this.hoverEl) {
|
|
2388
|
+
this.hoverEl = null;
|
|
2389
|
+
this.hoverLabel = null;
|
|
2390
|
+
this.overlay.hideCursor(false);
|
|
2391
|
+
this.overlay.drawHover(null, null);
|
|
2392
|
+
}
|
|
2393
|
+
this.wake();
|
|
2394
|
+
};
|
|
2395
|
+
this.onResize = () => this.wake();
|
|
2396
|
+
this.onMotion = () => this.wake();
|
|
2397
|
+
this.watch();
|
|
2398
|
+
this.tick = this.tick.bind(this);
|
|
2399
|
+
this.overlay.markerHover = (path) => {
|
|
2400
|
+
this.markerHoverPath = path;
|
|
2401
|
+
this.wake();
|
|
2402
|
+
};
|
|
2403
|
+
window.__bpParams = this.params.api();
|
|
2404
|
+
if (typeof window.__bpSpot === "string") this.spot.set(window.__bpSpot);
|
|
2405
|
+
window.addEventListener("bp:declare", () => this.emitDeclarations());
|
|
2406
|
+
if (window.__bpDecl && window.__bpDecl.rev > 0) this.emitDeclarations();
|
|
2407
|
+
emit("ready", { url: location.href });
|
|
2408
|
+
const painted = () => {
|
|
2409
|
+
requestAnimationFrame(
|
|
2410
|
+
() => requestAnimationFrame(() => emit("painted", { url: location.href }))
|
|
2411
|
+
);
|
|
2412
|
+
};
|
|
2413
|
+
if (document.readyState === "complete") painted();
|
|
2414
|
+
else window.addEventListener("load", painted, { once: true });
|
|
2415
|
+
}
|
|
2416
|
+
/** The page's declared parameters, in registration order. */
|
|
2417
|
+
declared() {
|
|
2418
|
+
const reg = window.__bpDecl;
|
|
2419
|
+
return reg ? Object.values(reg.params) : [];
|
|
2420
|
+
}
|
|
2421
|
+
// Coalesced to a frame: HMR replaces a module and every `useParam` in it
|
|
2422
|
+
// re-registers in one burst, which must land as one event, not a storm.
|
|
2423
|
+
emitDeclarations() {
|
|
2424
|
+
if (this.declRaf !== null) return;
|
|
2425
|
+
this.declRaf = requestAnimationFrame(() => {
|
|
2426
|
+
this.declRaf = null;
|
|
2427
|
+
emit("declarations", { params: this.declared() });
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
/** Push the card's runtime parameters. `enabled` is the before/after gate. */
|
|
2431
|
+
setParams(values, enabled) {
|
|
2432
|
+
this.params.set(values, enabled);
|
|
2433
|
+
}
|
|
2434
|
+
/** Which channels the page has read, this document. */
|
|
2435
|
+
claimedChannels() {
|
|
2436
|
+
return this.params.claims();
|
|
2437
|
+
}
|
|
2438
|
+
setOverlay(config) {
|
|
2439
|
+
if (config.colors) this.overlay.setColors(config.colors);
|
|
2440
|
+
if (config.suppressSelection !== void 0) {
|
|
2441
|
+
this.overlay.suppressSelection = config.suppressSelection;
|
|
2442
|
+
if (config.suppressSelection) this.overlay.drawSelection(null);
|
|
2443
|
+
}
|
|
2444
|
+
if (config.pointing !== void 0) this.overlay.pointing = config.pointing;
|
|
2445
|
+
if (config.visible !== void 0) {
|
|
2446
|
+
this.overlay.visible = config.visible;
|
|
2447
|
+
if (!config.visible) {
|
|
2448
|
+
this.hoverEl = null;
|
|
2449
|
+
this.hoverLabel = null;
|
|
2450
|
+
this.overlay.hideAll();
|
|
2451
|
+
this.stopLoop();
|
|
2452
|
+
this.detachActivity();
|
|
2453
|
+
} else {
|
|
2454
|
+
this.attachActivity();
|
|
2455
|
+
this.wake();
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
if (config.pointing !== void 0 || config.visible !== void 0) this.overlay.syncCursorStyle();
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Standing annotation markers: the ordinals the host says stand on these
|
|
2462
|
+
* elements. Standing chrome — redrawn every frame with the rings, cleared
|
|
2463
|
+
* only by the host (never by `clearSelection`), and the one pointer-active
|
|
2464
|
+
* piece of the overlay: a marker click answers the host, not the page
|
|
2465
|
+
* (`markerClick` emit for wire hosts, `onMarkerClick` for in-page ones).
|
|
2466
|
+
*/
|
|
2467
|
+
decorate(marks) {
|
|
2468
|
+
this.decorations = marks;
|
|
2469
|
+
this.wake();
|
|
2470
|
+
}
|
|
2471
|
+
onMarkerClick(handler) {
|
|
2472
|
+
this.overlay.markerHandler = handler;
|
|
2473
|
+
}
|
|
2474
|
+
hover(x, y) {
|
|
2475
|
+
const mark = this.overlay.markerAtPoint(x, y);
|
|
2476
|
+
if (mark) {
|
|
2477
|
+
if (this.markerHoverPath !== mark.path) {
|
|
2478
|
+
this.markerHoverPath = mark.path;
|
|
2479
|
+
this.wake();
|
|
2480
|
+
}
|
|
2481
|
+
this.hoverEl = null;
|
|
2482
|
+
this.hoverLabel = null;
|
|
2483
|
+
this.overlay.hideCursor(false);
|
|
2484
|
+
this.overlay.drawHover(null, null);
|
|
2485
|
+
emit("hover", null);
|
|
2486
|
+
return null;
|
|
2487
|
+
}
|
|
2488
|
+
if (this.markerHoverPath !== null) {
|
|
2489
|
+
this.markerHoverPath = null;
|
|
2490
|
+
this.wake();
|
|
2491
|
+
}
|
|
2492
|
+
const el = elementAtPoint(x, y);
|
|
2493
|
+
this.hoverEl = el;
|
|
2494
|
+
this.hoverVia = "pointer";
|
|
2495
|
+
const crumb = el ? crumbLite(el) : null;
|
|
2496
|
+
this.hoverLabel = crumb?.label ?? null;
|
|
2497
|
+
const suppressed = performance.now() < this.scrollingUntil;
|
|
2498
|
+
const shown = !suppressed && el !== null && el !== this.selEl;
|
|
2499
|
+
this.overlay.setHoverTab(false);
|
|
2500
|
+
this.overlay.drawHover(shown && el ? targetOf(el) : null, this.hoverLabel);
|
|
2501
|
+
if (shown && this.hoverLabel) this.overlay.drawCursor(x, y, this.hoverLabel);
|
|
2502
|
+
else this.overlay.hideCursor(!suppressed);
|
|
2503
|
+
this.wake();
|
|
2504
|
+
emit("hover", crumb);
|
|
2505
|
+
return crumb;
|
|
2506
|
+
}
|
|
2507
|
+
hoverOff() {
|
|
2508
|
+
this.hoverEl = null;
|
|
2509
|
+
this.hoverLabel = null;
|
|
2510
|
+
this.overlay.hideCursor(true);
|
|
2511
|
+
this.overlay.drawHover(null, null);
|
|
2512
|
+
emit("hover", null);
|
|
2513
|
+
}
|
|
2514
|
+
/** Draw the hover construction on the element at `path` — the layers
|
|
2515
|
+
* list's row preview. Draw-only: no `hover` emission, so the last pointer
|
|
2516
|
+
* crumb (what an annotate click places a pin from) is untouched. */
|
|
2517
|
+
hoverPath(path) {
|
|
2518
|
+
const el = elementAt(path);
|
|
2519
|
+
this.hoverEl = el;
|
|
2520
|
+
this.hoverVia = "path";
|
|
2521
|
+
this.hoverLabel = el ? labelOf(el) : null;
|
|
2522
|
+
this.overlay.hideCursor(false);
|
|
2523
|
+
this.overlay.setHoverTab(true);
|
|
2524
|
+
this.overlay.drawHover(el && el !== this.selEl ? targetOf(el) : null, this.hoverLabel);
|
|
2525
|
+
this.wake();
|
|
2526
|
+
}
|
|
2527
|
+
select(x, y) {
|
|
2528
|
+
const mark = this.overlay.markerAtPoint(x, y);
|
|
2529
|
+
if (mark) {
|
|
2530
|
+
this.overlay.markerHandler?.(mark.path, mark.ordinal);
|
|
2531
|
+
emit("markerClick", { path: mark.path, ordinal: mark.ordinal });
|
|
2532
|
+
return null;
|
|
2533
|
+
}
|
|
2534
|
+
const el = elementAtPoint(x, y);
|
|
2535
|
+
if (!el) return null;
|
|
2536
|
+
return this.commitSelection(el, true);
|
|
2537
|
+
}
|
|
2538
|
+
selectPath(path) {
|
|
2539
|
+
const el = elementAt(path);
|
|
2540
|
+
return el ? this.commitSelection(el) : null;
|
|
2541
|
+
}
|
|
2542
|
+
/** A stable, unique tag for an element, so `[data-bp-sel="v"]` matches
|
|
2543
|
+
* exactly one node — pins and the selection can coexist without collision. */
|
|
2544
|
+
tag(el) {
|
|
2545
|
+
const existing = el.getAttribute(SEL_ATTR);
|
|
2546
|
+
if (existing) return existing;
|
|
2547
|
+
const v = String(++this.tagSeq);
|
|
2548
|
+
el.setAttribute(SEL_ATTR, v);
|
|
2549
|
+
return v;
|
|
2550
|
+
}
|
|
2551
|
+
/** Whether the selection may reclaim this element's tag. */
|
|
2552
|
+
tagHeld(el) {
|
|
2553
|
+
const tag = el.getAttribute(SEL_ATTR);
|
|
2554
|
+
return tag !== null && this.heldTags.has(tag);
|
|
2555
|
+
}
|
|
2556
|
+
commitSelection(el, viaPointer = false) {
|
|
2557
|
+
const fresh = el !== this.selEl;
|
|
2558
|
+
if (this.selEl && this.selEl !== el && this.selEl.getAttribute(SEL_ATTR) && !this.tagHeld(this.selEl)) {
|
|
2559
|
+
this.selEl.removeAttribute(SEL_ATTR);
|
|
2560
|
+
}
|
|
2561
|
+
this.selEl = el;
|
|
2562
|
+
this.tag(el);
|
|
2563
|
+
const ref = refOf(el);
|
|
2564
|
+
this.overlay.setSelectionLabel(labelOf(el));
|
|
2565
|
+
this.overlay.drawSelection(targetOf(el));
|
|
2566
|
+
this.overlay.drawHover(null, null);
|
|
2567
|
+
if (viaPointer && fresh) this.overlay.handOff();
|
|
2568
|
+
else this.overlay.hideCursor(viaPointer);
|
|
2569
|
+
this.wake();
|
|
2570
|
+
return ref;
|
|
2571
|
+
}
|
|
2572
|
+
clearSelection() {
|
|
2573
|
+
if (this.selEl && !this.tagHeld(this.selEl)) this.selEl.removeAttribute(SEL_ATTR);
|
|
2574
|
+
this.selEl = null;
|
|
2575
|
+
this.overlay.drawSelection(null);
|
|
2576
|
+
this.wake();
|
|
2577
|
+
}
|
|
2578
|
+
describe(path) {
|
|
2579
|
+
const el = elementAt(path);
|
|
2580
|
+
return el ? refOf(el) : null;
|
|
2581
|
+
}
|
|
2582
|
+
rects(paths) {
|
|
2583
|
+
return paths.map((p) => {
|
|
2584
|
+
const el = elementAt(p);
|
|
2585
|
+
return el ? markRect(p, el) : null;
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
scope(scope) {
|
|
2589
|
+
if (!scope.componentKey) return elementAt(scope.elementPath) ? [scope.elementPath] : [];
|
|
2590
|
+
const [name, ownerPath = ""] = scope.componentKey.split("@");
|
|
2591
|
+
const variant = scope.variant;
|
|
2592
|
+
const find = (owner2) => {
|
|
2593
|
+
const found = [];
|
|
2594
|
+
let scanned = 0;
|
|
2595
|
+
for (const node of Array.from(owner2.querySelectorAll("*"))) {
|
|
2596
|
+
if (++scanned > MAX_SCAN) break;
|
|
2597
|
+
const nc = nearestComponent(node);
|
|
2598
|
+
if (nc?.name !== name || componentRoot(node) !== node) continue;
|
|
2599
|
+
if (variant && !matchesVariant(node, variant)) continue;
|
|
2600
|
+
found.push(node);
|
|
2601
|
+
}
|
|
2602
|
+
return found;
|
|
2603
|
+
};
|
|
2604
|
+
const mount = mountRoot();
|
|
2605
|
+
const owner = elementAt(ownerPath) ?? mount;
|
|
2606
|
+
let roots = find(owner);
|
|
2607
|
+
if (roots.length === 0 && owner !== mount) roots = find(mount);
|
|
2608
|
+
roots.sort((a, b) => comparePaths(pathOf(a) ?? "", pathOf(b) ?? ""));
|
|
2609
|
+
const chosen = scope.instanceIndex === void 0 ? roots : roots.filter((_, i) => i === scope.instanceIndex);
|
|
2610
|
+
const inner = scope.innerPath ?? "";
|
|
2611
|
+
return chosen.map((root) => {
|
|
2612
|
+
const rp = pathOf(root);
|
|
2613
|
+
if (rp === null) return null;
|
|
2614
|
+
const full = inner === "" ? rp : rp === "" ? inner : `${rp}/${inner}`;
|
|
2615
|
+
return elementAt(full) ? full : null;
|
|
2616
|
+
}).filter((p) => p !== null);
|
|
2617
|
+
}
|
|
2618
|
+
/** Ensure the element at `path` carries `data-bp-sel` so main can find its
|
|
2619
|
+
* CDP nodeId for pinning. Returns the selector value, or null. */
|
|
2620
|
+
ensureTag(path) {
|
|
2621
|
+
const el = elementAt(path);
|
|
2622
|
+
if (!el) return null;
|
|
2623
|
+
const tag = this.tag(el);
|
|
2624
|
+
this.heldTags.add(tag);
|
|
2625
|
+
return tag;
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* Hand held tags back — `null` releases every one (Reset, a host dropping
|
|
2629
|
+
* its whole override sheet). The element the selection is still on keeps its
|
|
2630
|
+
* attribute; every other loses it, so the page is left carrying nothing
|
|
2631
|
+
* Blueprint put there.
|
|
2632
|
+
*/
|
|
2633
|
+
releaseTags(paths) {
|
|
2634
|
+
const tags = paths === null ? [...this.heldTags] : paths.map((p) => elementAt(p)?.getAttribute(SEL_ATTR) ?? null).filter((tag) => tag !== null);
|
|
2635
|
+
for (const tag of tags) {
|
|
2636
|
+
this.heldTags.delete(tag);
|
|
2637
|
+
const el = document.querySelector(`[${SEL_ATTR}="${CSS.escape(tag)}"]`);
|
|
2638
|
+
if (el && el !== this.selEl) el.removeAttribute(SEL_ATTR);
|
|
2639
|
+
}
|
|
2640
|
+
if (paths === null) this.heldTags.clear();
|
|
2641
|
+
}
|
|
2642
|
+
/** Computed style values for the element at `path` — the pin test reads the
|
|
2643
|
+
* forced :hover background here, and phase 3 derives parameters from it. */
|
|
2644
|
+
/**
|
|
2645
|
+
* A durable CSS selector for the element at `path` — the beam's own address.
|
|
2646
|
+
*
|
|
2647
|
+
* The inverse of `query`, and the reason a capture can cross a process
|
|
2648
|
+
* boundary at all: a path is measured against one render, a selector is
|
|
2649
|
+
* re-resolved against every later one. See `printSelector`.
|
|
2650
|
+
*/
|
|
2651
|
+
selectorFor(path) {
|
|
2652
|
+
const el = elementAt(path);
|
|
2653
|
+
return el ? printSelector(el) : null;
|
|
2654
|
+
}
|
|
2655
|
+
/** Child-index path of the first element matching a CSS selector, or null.
|
|
2656
|
+
* Provenance (phase 3) and the conformance suite both address by selector. */
|
|
2657
|
+
query(selector) {
|
|
2658
|
+
let el = null;
|
|
2659
|
+
try {
|
|
2660
|
+
el = mountRoot().querySelector(selector);
|
|
2661
|
+
} catch {
|
|
2662
|
+
return null;
|
|
2663
|
+
}
|
|
2664
|
+
return el ? pathOf(el) : null;
|
|
2665
|
+
}
|
|
2666
|
+
computed(path, props) {
|
|
2667
|
+
const el = elementAt(path);
|
|
2668
|
+
if (!el) return null;
|
|
2669
|
+
const cs = getComputedStyle(el);
|
|
2670
|
+
const out = {};
|
|
2671
|
+
for (const prop of props) out[prop] = cs.getPropertyValue(prop);
|
|
2672
|
+
return out;
|
|
2673
|
+
}
|
|
2674
|
+
/** `computed`, for a whole subtree at once — see `PageProbe.sample`. */
|
|
2675
|
+
sample(paths, props) {
|
|
2676
|
+
return paths.map((path) => this.computed(path, props));
|
|
2677
|
+
}
|
|
2678
|
+
/**
|
|
2679
|
+
* The page's color variables (mirrors `PageColorVariable`): every custom
|
|
2680
|
+
* property declared on the root by the page's own stylesheets — Tailwind
|
|
2681
|
+
* v4's `@theme` lands as `:root, :host { --color-…}` inside `@layer
|
|
2682
|
+
* theme`, so grouping rules are walked — resolved off the root and kept
|
|
2683
|
+
* where the value is a color. Cross-origin sheets can't be read and are
|
|
2684
|
+
* skipped; a sheet Blueprint injected is the page's too, and harmless.
|
|
2685
|
+
*/
|
|
2686
|
+
colorVariables() {
|
|
2687
|
+
const names = /* @__PURE__ */ new Set();
|
|
2688
|
+
const rootish = /(^|[\s,])(:root|html|:host)(\b|[\s,:])/;
|
|
2689
|
+
const walk = (rules) => {
|
|
2690
|
+
for (const rule of Array.from(rules)) {
|
|
2691
|
+
if (rule instanceof CSSStyleRule) {
|
|
2692
|
+
if (!rootish.test(rule.selectorText)) continue;
|
|
2693
|
+
for (let i = 0; i < rule.style.length; i++) {
|
|
2694
|
+
const prop = rule.style[i];
|
|
2695
|
+
if (prop && prop.startsWith("--")) names.add(prop);
|
|
2696
|
+
}
|
|
2697
|
+
} else if ("cssRules" in rule) {
|
|
2698
|
+
walk(rule.cssRules);
|
|
2699
|
+
}
|
|
2700
|
+
if (names.size > 600) return;
|
|
2701
|
+
}
|
|
2702
|
+
};
|
|
2703
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
2704
|
+
try {
|
|
2705
|
+
walk(sheet.cssRules);
|
|
2706
|
+
} catch {
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
const cs = getComputedStyle(document.documentElement);
|
|
2710
|
+
const out = [];
|
|
2711
|
+
for (const name of [...names].sort()) {
|
|
2712
|
+
const value = cs.getPropertyValue(name).trim();
|
|
2713
|
+
if (value && CSS.supports("color", value)) out.push({ name, value });
|
|
2714
|
+
}
|
|
2715
|
+
return out;
|
|
2716
|
+
}
|
|
2717
|
+
/** What the overlay is drawing right now — a test/debug read, so the suite
|
|
2718
|
+
* can assert against the painted chrome rather than the element rects. */
|
|
2719
|
+
overlayState() {
|
|
2720
|
+
return this.overlay.state();
|
|
2721
|
+
}
|
|
2722
|
+
/**
|
|
2723
|
+
* The component behind an element, described for a sandbox request: what
|
|
2724
|
+
* it was rendered *with*, and what it was rendered *inside*.
|
|
2725
|
+
*
|
|
2726
|
+
* `wrappedBy` is every named component up the fiber tree, outermost first —
|
|
2727
|
+
* the provider chain as Blueprint can see it. Blueprint doesn't try to guess
|
|
2728
|
+
* which of them are providers; the agent knows the codebase and can.
|
|
2729
|
+
*/
|
|
2730
|
+
describeComponent(path) {
|
|
2731
|
+
const el = elementAt(path);
|
|
2732
|
+
if (!el) return null;
|
|
2733
|
+
const near = nearestComponent(el);
|
|
2734
|
+
if (!near) return null;
|
|
2735
|
+
const wrappedBy = [];
|
|
2736
|
+
let f = near.fiber.return;
|
|
2737
|
+
for (let i = 0; f && i < MAX_FIBER_WALK && wrappedBy.length < 12; i++, f = f.return) {
|
|
2738
|
+
const name = fiberName(f.type);
|
|
2739
|
+
if (name && wrappedBy[0] !== name) wrappedBy.unshift(name);
|
|
2740
|
+
}
|
|
2741
|
+
return { name: near.name, props: summariseProps(near.fiber.memoizedProps), wrappedBy };
|
|
2742
|
+
}
|
|
2743
|
+
/** What a sandbox page says about itself, or null on any other page.
|
|
2744
|
+
* The entry owns the fact; Blueprint owns the state drawn over the card. */
|
|
2745
|
+
sandbox() {
|
|
2746
|
+
return window.__bpSandbox ?? null;
|
|
2747
|
+
}
|
|
2748
|
+
/** Show only the element at `path`, its ancestors and what it opened;
|
|
2749
|
+
* `null` lifts it. See `Spotlight`. */
|
|
2750
|
+
spotlight(path) {
|
|
2751
|
+
this.spot.set(path);
|
|
2752
|
+
}
|
|
2753
|
+
/** Whether the spotlight is armed or applied, and how much it is hiding. */
|
|
2754
|
+
spotlightState() {
|
|
2755
|
+
return this.spot.state();
|
|
2756
|
+
}
|
|
2757
|
+
/**
|
|
2758
|
+
* The element tree in document order, for the layers list. Depth-first from
|
|
2759
|
+
* the mount root, capped at `maxNodes` with the cut declared — never silent.
|
|
2760
|
+
* `name` is the component where the element is a component root (the unit a
|
|
2761
|
+
* person thinks in), the DOM tag otherwise.
|
|
2762
|
+
*/
|
|
2763
|
+
tree(maxNodes = MAX_TREE) {
|
|
2764
|
+
const nodes = [];
|
|
2765
|
+
let truncated = false;
|
|
2766
|
+
const walk = (el, depth) => {
|
|
2767
|
+
for (const child of Array.from(el.children)) {
|
|
2768
|
+
if (child.id === OVERLAY_ID) continue;
|
|
2769
|
+
if (nodes.length >= maxNodes) {
|
|
2770
|
+
truncated = true;
|
|
2771
|
+
return false;
|
|
2772
|
+
}
|
|
2773
|
+
const path = pathOf(child);
|
|
2774
|
+
if (path === null) continue;
|
|
2775
|
+
const comp = componentRoot(child) === child ? componentNameOf(child) : void 0;
|
|
2776
|
+
nodes.push({
|
|
2777
|
+
path,
|
|
2778
|
+
tag: child.tagName.toLowerCase(),
|
|
2779
|
+
name: comp ?? child.tagName.toLowerCase(),
|
|
2780
|
+
component: comp !== void 0,
|
|
2781
|
+
depth,
|
|
2782
|
+
text: hasOwnText(child)
|
|
2783
|
+
});
|
|
2784
|
+
if (!walk(child, depth + 1)) return false;
|
|
2785
|
+
}
|
|
2786
|
+
return true;
|
|
2787
|
+
};
|
|
2788
|
+
walk(mountRoot(), 0);
|
|
2789
|
+
return { nodes, truncated };
|
|
2790
|
+
}
|
|
2791
|
+
/**
|
|
2792
|
+
* The element at `path`, as a live handle.
|
|
2793
|
+
*
|
|
2794
|
+
* Only ever useful to an **in-page** host: over CDP a DOM node cannot cross
|
|
2795
|
+
* the wire, which is why every other method here answers in paths and rects.
|
|
2796
|
+
* Beam's driver runs in the same document as the probe, so it can ask
|
|
2797
|
+
* directly rather than re-implementing the walk — one addressing scheme, not
|
|
2798
|
+
* two (`packages/probe/src/beam.ts`).
|
|
2799
|
+
*/
|
|
2800
|
+
nodeAt(path) {
|
|
2801
|
+
return elementAt(path);
|
|
2802
|
+
}
|
|
2803
|
+
/** Path for a live element handle — main resolves an animation's target
|
|
2804
|
+
* (`DOM.resolveNode` → `Runtime.callFunctionOn`) through this, so the
|
|
2805
|
+
* Live motion strip can scope itself with the same addressing scheme
|
|
2806
|
+
* selection uses. */
|
|
2807
|
+
pathForElement(el) {
|
|
2808
|
+
return el instanceof Element ? pathOf(el) : null;
|
|
2809
|
+
}
|
|
2810
|
+
/**
|
|
2811
|
+
* The pseudo-states that are *live* around the element at `path` right now
|
|
2812
|
+
* — candidates, not conclusions.
|
|
2813
|
+
*
|
|
2814
|
+
* A capture leaving this page (Beam's crossing, the beam driver) carries
|
|
2815
|
+
* them so the card can try them once resolving the selector bare has
|
|
2816
|
+
* failed; the cost of over-guessing is one retry rather than a static
|
|
2817
|
+
* element arriving pinned. What earns a place is a signal that something is
|
|
2818
|
+
* *held open*: an expanded trigger, a focused control, or the immediate
|
|
2819
|
+
* ancestors the pointer is on (which is how `.parent:hover .child` and
|
|
2820
|
+
* `group-hover` work). Deliberately short — a card wearing four pins that
|
|
2821
|
+
* changed nothing is a lie about why it looks the way it does.
|
|
2822
|
+
*/
|
|
2823
|
+
candidatePins(path) {
|
|
2824
|
+
const el = elementAt(path);
|
|
2825
|
+
const out = [];
|
|
2826
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2827
|
+
const add = (node, states) => {
|
|
2828
|
+
if (!node || out.length >= MAX_CANDIDATES || node === document.body || node === document.documentElement) return;
|
|
2829
|
+
const selector = printSelector(node);
|
|
2830
|
+
if (!selector || seen.has(selector)) return;
|
|
2831
|
+
seen.add(selector);
|
|
2832
|
+
out.push({ selector, states });
|
|
2833
|
+
};
|
|
2834
|
+
let expanded = 0;
|
|
2835
|
+
for (const node of Array.from(document.querySelectorAll('[aria-expanded="true"]'))) {
|
|
2836
|
+
if (++expanded > 2) break;
|
|
2837
|
+
add(node, ["hover", "focus"]);
|
|
2838
|
+
}
|
|
2839
|
+
if (el) {
|
|
2840
|
+
let node = el.parentElement;
|
|
2841
|
+
for (let i = 0; node && i < 2; i++, node = node.parentElement) {
|
|
2842
|
+
if (node.matches(":hover")) add(node, ["hover"]);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
const active = document.activeElement;
|
|
2846
|
+
if (active && active !== document.body && !(el && el.contains(active))) add(active, ["focus"]);
|
|
2847
|
+
return out;
|
|
2848
|
+
}
|
|
2849
|
+
pauseAnimations() {
|
|
2850
|
+
for (const anim of document.getAnimations?.() ?? []) anim.pause();
|
|
2851
|
+
}
|
|
2852
|
+
resumeAnimations() {
|
|
2853
|
+
for (const anim of document.getAnimations?.() ?? []) anim.play();
|
|
2854
|
+
}
|
|
2855
|
+
// Re-measure while visible: the whole reason the rings live in the page.
|
|
2856
|
+
// Frame rate while anything moves; `LOOP_IDLE_MS` sampling once everything
|
|
2857
|
+
// drawn has held still past `LOOP_ACTIVE_MS`; parked outright with nothing
|
|
2858
|
+
// drawn. Any activity signal (`wake`) restores frame rate.
|
|
2859
|
+
startLoop() {
|
|
2860
|
+
if (this.idleTimer !== null) {
|
|
2861
|
+
clearTimeout(this.idleTimer);
|
|
2862
|
+
this.idleTimer = null;
|
|
2863
|
+
}
|
|
2864
|
+
if (this.rafId === null) this.rafId = requestAnimationFrame(this.tick);
|
|
2865
|
+
}
|
|
2866
|
+
stopLoop() {
|
|
2867
|
+
if (this.rafId !== null) cancelAnimationFrame(this.rafId);
|
|
2868
|
+
this.rafId = null;
|
|
2869
|
+
if (this.idleTimer !== null) clearTimeout(this.idleTimer);
|
|
2870
|
+
this.idleTimer = null;
|
|
2871
|
+
}
|
|
2872
|
+
wake() {
|
|
2873
|
+
this.lastActivityAt = performance.now();
|
|
2874
|
+
if (this.overlay.visible) this.startLoop();
|
|
2875
|
+
}
|
|
2876
|
+
/** Scroll and resize can move what the rings track without a single DOM
|
|
2877
|
+
* mutation — listened only while the overlay is up. Capture, because
|
|
2878
|
+
* `scroll` doesn't bubble but does capture through the light tree. */
|
|
2879
|
+
attachActivity() {
|
|
2880
|
+
if (this.activityAttached) return;
|
|
2881
|
+
this.activityAttached = true;
|
|
2882
|
+
window.addEventListener("scroll", this.onScroll, { capture: true, passive: true });
|
|
2883
|
+
window.addEventListener("resize", this.onResize, { passive: true });
|
|
2884
|
+
window.addEventListener("animationstart", this.onMotion, { capture: true, passive: true });
|
|
2885
|
+
window.addEventListener("transitionrun", this.onMotion, { capture: true, passive: true });
|
|
2886
|
+
}
|
|
2887
|
+
detachActivity() {
|
|
2888
|
+
if (!this.activityAttached) return;
|
|
2889
|
+
this.activityAttached = false;
|
|
2890
|
+
window.removeEventListener("scroll", this.onScroll, true);
|
|
2891
|
+
window.removeEventListener("resize", this.onResize);
|
|
2892
|
+
window.removeEventListener("animationstart", this.onMotion, true);
|
|
2893
|
+
window.removeEventListener("transitionrun", this.onMotion, true);
|
|
2894
|
+
}
|
|
2895
|
+
tick() {
|
|
2896
|
+
this.rafId = null;
|
|
2897
|
+
if (!this.overlay.visible) return;
|
|
2898
|
+
const now = performance.now();
|
|
2899
|
+
const scrolling = now < this.scrollingUntil;
|
|
2900
|
+
const hoverMark = this.markerHoverPath;
|
|
2901
|
+
const draws = [];
|
|
2902
|
+
const status = [];
|
|
2903
|
+
const ringed = /* @__PURE__ */ new Set();
|
|
2904
|
+
let fused = false;
|
|
2905
|
+
let fusedResolved = false;
|
|
2906
|
+
let settling = false;
|
|
2907
|
+
for (const d of this.decorations) {
|
|
2908
|
+
const el = elementAt(d.path);
|
|
2909
|
+
const alive = el !== null && el.isConnected;
|
|
2910
|
+
if (alive) this.unresolvedSince.delete(d.path);
|
|
2911
|
+
else {
|
|
2912
|
+
const since = this.unresolvedSince.get(d.path) ?? now;
|
|
2913
|
+
if (this.unresolvedSince.get(d.path) === void 0) this.unresolvedSince.set(d.path, now);
|
|
2914
|
+
if (now - since < DETACH_SETTLE_MS) {
|
|
2915
|
+
settling = true;
|
|
2916
|
+
continue;
|
|
2917
|
+
}
|
|
2918
|
+
if (!d.fallbackRect) continue;
|
|
2919
|
+
}
|
|
2920
|
+
const onSelection = alive && el === this.selEl;
|
|
2921
|
+
if (onSelection) {
|
|
2922
|
+
fused = true;
|
|
2923
|
+
fusedResolved = d.status === "resolved";
|
|
2924
|
+
}
|
|
2925
|
+
const agent = alive ? d.agent : void 0;
|
|
2926
|
+
if (agent && el) {
|
|
2927
|
+
ringed.add(el);
|
|
2928
|
+
status.push({ key: d.path, state: agent, target: markTarget(d.path, el), fused: true });
|
|
2929
|
+
}
|
|
2930
|
+
draws.push({
|
|
2931
|
+
key: d.path,
|
|
2932
|
+
ordinal: d.ordinal,
|
|
2933
|
+
rect: alive ? markRect(d.path, el) : d.fallbackRect,
|
|
2934
|
+
fused: onSelection || agent !== void 0 || alive && d.path === hoverMark,
|
|
2935
|
+
status: d.status ?? "sent",
|
|
2936
|
+
detached: !alive,
|
|
2937
|
+
...agent ? { agent } : {}
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
const selTarget = this.selEl && this.selEl.isConnected ? targetOf(this.selEl) : null;
|
|
2941
|
+
let hoverLost = false;
|
|
2942
|
+
if (this.hoverEl && !this.hoverEl.isConnected) {
|
|
2943
|
+
this.hoverEl = null;
|
|
2944
|
+
this.hoverLabel = null;
|
|
2945
|
+
hoverLost = true;
|
|
2946
|
+
}
|
|
2947
|
+
const hoverMarkEl = hoverMark ? elementAt(hoverMark) : null;
|
|
2948
|
+
const markHover = hoverMark !== null && hoverMarkEl && hoverMarkEl.isConnected && !ringed.has(hoverMarkEl) ? {
|
|
2949
|
+
target: hoverMarkEl !== this.selEl ? markTarget(hoverMark, hoverMarkEl) : null,
|
|
2950
|
+
label: labelOf(hoverMarkEl),
|
|
2951
|
+
resolved: draws.some((d) => d.key === hoverMark && d.status === "resolved")
|
|
2952
|
+
} : null;
|
|
2953
|
+
const hoverTarget = !markHover && this.hoverEl && this.hoverEl !== this.selEl && !ringed.has(this.hoverEl) ? targetOf(this.hoverEl) : null;
|
|
2954
|
+
let movedAny = false;
|
|
2955
|
+
if (this.overlay.drawStatus(status)) movedAny = true;
|
|
2956
|
+
this.overlay.setSelectionFused(fused, fusedResolved);
|
|
2957
|
+
if (this.selEl) {
|
|
2958
|
+
if (selTarget) {
|
|
2959
|
+
const standDown = ringed.has(this.selEl);
|
|
2960
|
+
if (this.overlay.drawSelection(standDown ? null : selTarget)) movedAny = true;
|
|
2961
|
+
} else {
|
|
2962
|
+
this.clearSelection();
|
|
2963
|
+
movedAny = true;
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
if (markHover) {
|
|
2967
|
+
this.overlay.setHoverTab(true);
|
|
2968
|
+
this.overlay.hideCursor(true);
|
|
2969
|
+
this.overlay.setHoverAccent(true, markHover.resolved);
|
|
2970
|
+
this.overlay.setHoverFused(true);
|
|
2971
|
+
if (this.overlay.drawHover(scrolling ? null : markHover.target, markHover.label)) movedAny = true;
|
|
2972
|
+
} else {
|
|
2973
|
+
this.overlay.setHoverAccent(false);
|
|
2974
|
+
this.overlay.setHoverFused(false);
|
|
2975
|
+
this.overlay.setHoverTab(this.hoverVia === "path");
|
|
2976
|
+
if (this.hoverEl) {
|
|
2977
|
+
if (this.overlay.drawHover(scrolling ? null : hoverTarget, this.hoverLabel)) movedAny = true;
|
|
2978
|
+
} else if (hoverMark || hoverLost) {
|
|
2979
|
+
if (hoverLost) this.overlay.hideCursor(false);
|
|
2980
|
+
if (this.overlay.drawHover(null, null)) movedAny = true;
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
if (this.overlay.drawMarkers(draws)) movedAny = true;
|
|
2984
|
+
if (movedAny) this.lastActivityAt = now;
|
|
2985
|
+
const nothingShown = draws.length === 0 && status.length === 0 && !settling && !this.selEl && !this.hoverEl && !hoverMark;
|
|
2986
|
+
if (nothingShown) return;
|
|
2987
|
+
if (scrolling || now - this.lastActivityAt < LOOP_ACTIVE_MS) {
|
|
2988
|
+
this.startLoop();
|
|
2989
|
+
} else {
|
|
2990
|
+
this.idleTimer = setTimeout(() => {
|
|
2991
|
+
this.idleTimer = null;
|
|
2992
|
+
this.startLoop();
|
|
2993
|
+
}, LOOP_IDLE_MS);
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
// Content shape changes re-anchor scoped params and pins on the host side.
|
|
2997
|
+
watch() {
|
|
2998
|
+
const ping = () => {
|
|
2999
|
+
this.wake();
|
|
3000
|
+
if (this.mutationRaf !== null) return;
|
|
3001
|
+
this.mutationRaf = requestAnimationFrame(() => {
|
|
3002
|
+
this.mutationRaf = null;
|
|
3003
|
+
this.spot.refresh();
|
|
3004
|
+
emit("contentChanged");
|
|
3005
|
+
});
|
|
3006
|
+
};
|
|
3007
|
+
const ours = (r) => r.type === "attributes" && (r.attributeName === SPOT_ATTR || r.attributeName === SEL_ATTR);
|
|
3008
|
+
const start = () => {
|
|
3009
|
+
const mount = mountRoot();
|
|
3010
|
+
const mo = new MutationObserver((records) => {
|
|
3011
|
+
if (records.every(ours)) return;
|
|
3012
|
+
ping();
|
|
3013
|
+
});
|
|
3014
|
+
mo.observe(mount, { childList: true, subtree: true, attributes: true, characterData: true });
|
|
3015
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
3016
|
+
const ro = new ResizeObserver(ping);
|
|
3017
|
+
ro.observe(mount);
|
|
3018
|
+
}
|
|
3019
|
+
};
|
|
3020
|
+
if (document.body) start();
|
|
3021
|
+
else document.addEventListener("DOMContentLoaded", start, { once: true });
|
|
3022
|
+
}
|
|
3023
|
+
};
|
|
3024
|
+
var HOLD_KEYS = /* @__PURE__ */ new Set(["Meta", "Alt", "Shift", "Control"]);
|
|
3025
|
+
var PRINTABLE_HOLDS = /* @__PURE__ */ new Set(["c", "`"]);
|
|
3026
|
+
function typingHere(e) {
|
|
3027
|
+
const target = e.composedPath()[0];
|
|
3028
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
3029
|
+
return target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable;
|
|
3030
|
+
}
|
|
3031
|
+
function forwardHolds() {
|
|
3032
|
+
const send = (kind, e, key) => {
|
|
3033
|
+
emit("keyHold", { kind, key, meta: e.metaKey, alt: e.altKey, ctrl: e.ctrlKey });
|
|
3034
|
+
};
|
|
3035
|
+
window.addEventListener(
|
|
3036
|
+
"keydown",
|
|
3037
|
+
(e) => {
|
|
3038
|
+
if (!window.__bpEmit || e.repeat) return;
|
|
3039
|
+
if (HOLD_KEYS.has(e.key)) {
|
|
3040
|
+
send("down", e, e.key);
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
if (e.metaKey || e.altKey) {
|
|
3044
|
+
send("chord", e);
|
|
3045
|
+
return;
|
|
3046
|
+
}
|
|
3047
|
+
const key = e.key.toLowerCase();
|
|
3048
|
+
if (PRINTABLE_HOLDS.has(key) && !e.ctrlKey && !typingHere(e)) send("down", e, key);
|
|
3049
|
+
},
|
|
3050
|
+
true
|
|
3051
|
+
);
|
|
3052
|
+
window.addEventListener(
|
|
3053
|
+
"keyup",
|
|
3054
|
+
(e) => {
|
|
3055
|
+
if (!window.__bpEmit) return;
|
|
3056
|
+
const key = HOLD_KEYS.has(e.key) ? e.key : e.key.toLowerCase();
|
|
3057
|
+
if (HOLD_KEYS.has(key) || PRINTABLE_HOLDS.has(key)) send("up", e, key);
|
|
3058
|
+
},
|
|
3059
|
+
true
|
|
3060
|
+
);
|
|
3061
|
+
}
|
|
3062
|
+
function forwardZoom() {
|
|
3063
|
+
window.addEventListener(
|
|
3064
|
+
"wheel",
|
|
3065
|
+
(e) => {
|
|
3066
|
+
if (!window.__bpEmit || !window.__bpZoomToHost) return;
|
|
3067
|
+
if (!e.ctrlKey && !e.metaKey) return;
|
|
3068
|
+
e.preventDefault();
|
|
3069
|
+
emit("wheelZoom", { deltaY: e.deltaY, deltaMode: e.deltaMode, x: e.clientX, y: e.clientY });
|
|
3070
|
+
},
|
|
3071
|
+
// Non-passive, or `preventDefault` is a no-op and the browser zooms
|
|
3072
|
+
// anyway — the same lesson the canvas root's listener carries.
|
|
3073
|
+
{ passive: false, capture: true }
|
|
3074
|
+
);
|
|
3075
|
+
}
|
|
3076
|
+
function install() {
|
|
3077
|
+
if (window.__bp) return;
|
|
3078
|
+
window.__bp = new Probe();
|
|
3079
|
+
forwardHolds();
|
|
3080
|
+
forwardZoom();
|
|
3081
|
+
}
|
|
3082
|
+
if (window.__bpDeferInstall) window.__bpInstall = install;
|
|
3083
|
+
else install();
|
|
3084
|
+
})();
|