unfold-nav 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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +421 -0
- package/dist/element.d.cts +37 -0
- package/dist/element.d.ts +37 -0
- package/dist/icons.d.cts +12 -0
- package/dist/icons.d.ts +12 -0
- package/dist/index.d.cts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/insets.d.cts +4 -0
- package/dist/insets.d.ts +4 -0
- package/dist/layout.d.cts +197 -0
- package/dist/layout.d.ts +197 -0
- package/dist/navigation.d.cts +2 -0
- package/dist/navigation.d.ts +2 -0
- package/dist/options.d.cts +6 -0
- package/dist/options.d.ts +6 -0
- package/dist/styles.d.cts +1 -0
- package/dist/styles.d.ts +1 -0
- package/dist/tree.d.cts +22 -0
- package/dist/tree.d.ts +22 -0
- package/dist/types.d.cts +108 -0
- package/dist/types.d.ts +108 -0
- package/dist/unfold-nav.js +2211 -0
- package/dist/unfold-nav.js.map +1 -0
- package/dist/unfold-nav.umd.cjs +446 -0
- package/dist/unfold-nav.umd.cjs.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,2211 @@
|
|
|
1
|
+
//#region src/icons.ts
|
|
2
|
+
var e = /^(https?:|data:|blob:|\/|\.\.?\/)|\.(svg|png|jpe?g|gif|webp|avif)(\?.*)?$/i, t = /^[a-z][\w-]{2,}$/i;
|
|
3
|
+
function n(r, i, a, o = 0) {
|
|
4
|
+
if (r == null || r === "" || o > 3) return null;
|
|
5
|
+
if (typeof r == "function") return n(r(), i, a, o + 1);
|
|
6
|
+
if (typeof r != "string") return r.cloneNode(!0);
|
|
7
|
+
let s = r.trim();
|
|
8
|
+
if (s.startsWith("<")) {
|
|
9
|
+
let e = document.createElement("template");
|
|
10
|
+
return e.innerHTML = s, e.content;
|
|
11
|
+
}
|
|
12
|
+
if (e.test(s)) {
|
|
13
|
+
let e = document.createElement("img");
|
|
14
|
+
return e.src = s, e.alt = "", e.decoding = "async", e.draggable = !1, e;
|
|
15
|
+
}
|
|
16
|
+
if (t.test(s)) {
|
|
17
|
+
let e = i?.(s, a);
|
|
18
|
+
return e == null || e === s ? null : n(e, void 0, a, o + 1);
|
|
19
|
+
}
|
|
20
|
+
let c = document.createElement("span");
|
|
21
|
+
return c.className = "glyph", c.textContent = s, c;
|
|
22
|
+
}
|
|
23
|
+
function r(e) {
|
|
24
|
+
let t = document.createElement("span");
|
|
25
|
+
return t.className = "mono", t.textContent = Array.from(e.trim())[0]?.toUpperCase() ?? "•", t;
|
|
26
|
+
}
|
|
27
|
+
var i = (e) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${e}</svg>`, a = i("<path d=\"M12 17.5 6 8.6M12 17.5V6.2M12 17.5l6-8.9\"/><circle cx=\"12\" cy=\"18.2\" r=\"2.5\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"5.6\" cy=\"8\" r=\"2\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"12\" cy=\"5.4\" r=\"2\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"18.4\" cy=\"8\" r=\"2\" fill=\"currentColor\" stroke=\"none\"/>"), o = i("<path d=\"M6.5 6.5l11 11M17.5 6.5l-11 11\"/>"), s = i("<path d=\"M19 12H5.5M11 6l-6 6 6 6\"/>"), c = (e) => Array.isArray(e) ? e : [e], l = Math.PI * 2, u = Math.PI / 180, d = 4;
|
|
28
|
+
function f(e, t) {
|
|
29
|
+
let n = Math.max(t.x - e.x, 0, e.x - (t.x + t.w)), r = Math.max(t.y - e.y, 0, e.y - (t.y + t.h));
|
|
30
|
+
return Math.hypot(n, r);
|
|
31
|
+
}
|
|
32
|
+
function p(e, t, n = 0) {
|
|
33
|
+
return e.x < t.x + t.w + n && t.x < e.x + e.w + n && e.y < t.y + t.h + n && t.y < e.y + e.h + n;
|
|
34
|
+
}
|
|
35
|
+
var m = (e, t) => t.x >= e.x && t.x <= e.x + e.w && t.y >= e.y && t.y <= e.y + e.h, h = (e, t) => t.x >= e.x - .5 && t.y >= e.y - .5 && t.x + t.w <= e.x + e.w + .5 && t.y + t.h <= e.y + e.h + .5, g = (e, t) => ({
|
|
36
|
+
x: e.x - t,
|
|
37
|
+
y: e.y - t,
|
|
38
|
+
w: e.w + t * 2,
|
|
39
|
+
h: e.h + t * 2
|
|
40
|
+
});
|
|
41
|
+
function _(e, t, n) {
|
|
42
|
+
let r = n.x - t.x, i = n.y - t.y, a = r * r + i * i, o = a ? Math.max(0, Math.min(1, ((e.x - t.x) * r + (e.y - t.y) * i) / a)) : 0;
|
|
43
|
+
return Math.hypot(e.x - (t.x + o * r), e.y - (t.y + o * i));
|
|
44
|
+
}
|
|
45
|
+
function v(e, t) {
|
|
46
|
+
let n = Infinity;
|
|
47
|
+
for (let r = 0; r < t.length - 1; r++) n = Math.min(n, _(e, t[r], t[r + 1]));
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
function ee(e, t, n) {
|
|
51
|
+
let r = 0, i = 1, a = t.x - e.x, o = t.y - e.y, s = [
|
|
52
|
+
-a,
|
|
53
|
+
a,
|
|
54
|
+
-o,
|
|
55
|
+
o
|
|
56
|
+
], c = [
|
|
57
|
+
e.x - n.x,
|
|
58
|
+
n.x + n.w - e.x,
|
|
59
|
+
e.y - n.y,
|
|
60
|
+
n.y + n.h - e.y
|
|
61
|
+
];
|
|
62
|
+
for (let e = 0; e < 4; e++) if (s[e] === 0) {
|
|
63
|
+
if (c[e] < 0) return !1;
|
|
64
|
+
} else {
|
|
65
|
+
let t = c[e] / s[e];
|
|
66
|
+
if (s[e] < 0) {
|
|
67
|
+
if (t > i) return !1;
|
|
68
|
+
t > r && (r = t);
|
|
69
|
+
} else {
|
|
70
|
+
if (t < r) return !1;
|
|
71
|
+
t < i && (i = t);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return !0;
|
|
75
|
+
}
|
|
76
|
+
function y(e, t) {
|
|
77
|
+
for (let n = 0; n < e.length - 1; n++) if (ee(e[n], e[n + 1], t)) return !0;
|
|
78
|
+
return !1;
|
|
79
|
+
}
|
|
80
|
+
function b(e, t, n) {
|
|
81
|
+
let r = t.x - e.x, i = t.y - e.y, a = Math.hypot(r, i) || 1;
|
|
82
|
+
return {
|
|
83
|
+
x: e.x + r / a * n,
|
|
84
|
+
y: e.y + i / a * n
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
var x = (e) => e.toFixed(1);
|
|
88
|
+
function S(e, t, n, r) {
|
|
89
|
+
let i = () => {
|
|
90
|
+
let n = b(e, t, e.r), r = b(t, e, t.r);
|
|
91
|
+
return {
|
|
92
|
+
d: `M${x(n.x)} ${x(n.y)}L${x(r.x)} ${x(r.y)}`,
|
|
93
|
+
points: [n, r]
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
if (n === "step") {
|
|
97
|
+
let n = b(e, t, e.r), r = b(t, e, t.r);
|
|
98
|
+
if (Math.min(Math.abs(r.x - n.x), Math.abs(r.y - n.y)) < 1 || Math.hypot(t.x - e.x, t.y - e.y) <= e.r + t.r) return i();
|
|
99
|
+
let a = Math.abs(t.x - e.x) >= Math.abs(t.y - e.y), o = a ? (n.x + r.x) / 2 : (n.y + r.y) / 2, s = a ? [{
|
|
100
|
+
x: o,
|
|
101
|
+
y: n.y
|
|
102
|
+
}, {
|
|
103
|
+
x: o,
|
|
104
|
+
y: r.y
|
|
105
|
+
}] : [{
|
|
106
|
+
x: n.x,
|
|
107
|
+
y: o
|
|
108
|
+
}, {
|
|
109
|
+
x: r.x,
|
|
110
|
+
y: o
|
|
111
|
+
}], c = [
|
|
112
|
+
n,
|
|
113
|
+
...s,
|
|
114
|
+
r
|
|
115
|
+
], l = [n], u = `M${x(n.x)} ${x(n.y)}`;
|
|
116
|
+
return s.forEach((e, t) => {
|
|
117
|
+
let n = c[t], r = c[t + 2], i = Math.min(10, Math.hypot(e.x - n.x, e.y - n.y) / 2, Math.hypot(r.x - e.x, r.y - e.y) / 2), a = b(e, n, i), o = b(e, r, i);
|
|
118
|
+
u += `L${x(a.x)} ${x(a.y)}Q${x(e.x)} ${x(e.y)} ${x(o.x)} ${x(o.y)}`, l.push(a);
|
|
119
|
+
for (let t = 1; t <= 4; t++) {
|
|
120
|
+
let n = t / 4, r = 1 - n;
|
|
121
|
+
l.push({
|
|
122
|
+
x: r * r * a.x + 2 * r * n * e.x + n * n * o.x,
|
|
123
|
+
y: r * r * a.y + 2 * r * n * e.y + n * n * o.y
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}), l.push(r), {
|
|
127
|
+
d: `${u}L${x(r.x)} ${x(r.y)}`,
|
|
128
|
+
points: l
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (n !== "curved" || r == null) return i();
|
|
132
|
+
let a = Math.hypot(t.x - e.x, t.y - e.y) || 1, o = {
|
|
133
|
+
x: e.x + Math.cos(r) * a * .5,
|
|
134
|
+
y: e.y + Math.sin(r) * a * .5
|
|
135
|
+
}, s = b(e, o, e.r), c = b(t, o, t.r), l = [];
|
|
136
|
+
for (let e = 0; e <= 6; e++) {
|
|
137
|
+
let t = e / 6, n = 1 - t;
|
|
138
|
+
l.push({
|
|
139
|
+
x: n * n * s.x + 2 * n * t * o.x + t * t * c.x,
|
|
140
|
+
y: n * n * s.y + 2 * n * t * o.y + t * t * c.y
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
d: `M${x(s.x)} ${x(s.y)}Q${x(o.x)} ${x(o.y)} ${x(c.x)} ${x(c.y)}`,
|
|
145
|
+
points: l
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
var C = [
|
|
149
|
+
0,
|
|
150
|
+
...Array.from({ length: 7 }, (e, t) => [(t + 1) * 22.5, -(t + 1) * 22.5]).flat(),
|
|
151
|
+
180
|
|
152
|
+
].map((e) => e * u), w = [
|
|
153
|
+
0,
|
|
154
|
+
12,
|
|
155
|
+
28
|
|
156
|
+
], T = [
|
|
157
|
+
0,
|
|
158
|
+
12,
|
|
159
|
+
28,
|
|
160
|
+
48
|
|
161
|
+
];
|
|
162
|
+
function E(e, t, n, r, i, a) {
|
|
163
|
+
let o = Math.cos(i), s = Math.sin(i), c = 0, l = a + n + r;
|
|
164
|
+
for (let i = 0; i < 14; i++) {
|
|
165
|
+
let i = (c + l) / 2;
|
|
166
|
+
f({
|
|
167
|
+
x: e,
|
|
168
|
+
y: t
|
|
169
|
+
}, {
|
|
170
|
+
x: e + o * i - n / 2,
|
|
171
|
+
y: t + s * i - r / 2,
|
|
172
|
+
w: n,
|
|
173
|
+
h: r
|
|
174
|
+
}) >= a ? l = i : c = i;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
x: e + o * l - n / 2,
|
|
178
|
+
y: t + s * l - r / 2,
|
|
179
|
+
w: n,
|
|
180
|
+
h: r
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function D(e, t, n) {
|
|
184
|
+
for (let r of n.circles) if (r !== t && f(r, e) < r.r + n.pad) return !0;
|
|
185
|
+
for (let t of n.taken) if (p(e, t, d)) return !0;
|
|
186
|
+
if (n.edges.length) {
|
|
187
|
+
let t = g(e, 2);
|
|
188
|
+
for (let e of n.edges) if (y(e, t)) return !0;
|
|
189
|
+
}
|
|
190
|
+
return !1;
|
|
191
|
+
}
|
|
192
|
+
function te(e, t, n, r) {
|
|
193
|
+
let i = c(t)[0], a = 0;
|
|
194
|
+
for (let t of w) for (let o of C) {
|
|
195
|
+
let s = E(e.x, e.y, i.w, i.h, n + o, e.r + (r.ownPad ?? r.pad) + t);
|
|
196
|
+
h(r.bounds, s) && !D(s, e, r) && a++;
|
|
197
|
+
}
|
|
198
|
+
return a;
|
|
199
|
+
}
|
|
200
|
+
function O(e, t, n = (e, t) => k(e.node, e.size, e.angle, t)) {
|
|
201
|
+
let r = (r) => {
|
|
202
|
+
let i = e.map(() => null), a = {
|
|
203
|
+
...t,
|
|
204
|
+
taken: [...t.taken]
|
|
205
|
+
}, o = 0;
|
|
206
|
+
for (let t of r) {
|
|
207
|
+
let r = n(e[t], a);
|
|
208
|
+
r ? a.taken.push(r) : o++, i[t] = r;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
out: i,
|
|
212
|
+
missing: o
|
|
213
|
+
};
|
|
214
|
+
}, i = e.map((e, t) => t), a = r(i);
|
|
215
|
+
if (a.missing === 0 || e.length < 2) return a.out;
|
|
216
|
+
let o = e.map((e) => te(e.node, e.size, e.angle, t));
|
|
217
|
+
for (let e of [[...i].sort((e, t) => o[e] - o[t]), [...i].reverse()]) {
|
|
218
|
+
let t = r(e);
|
|
219
|
+
if (t.missing < a.missing && (a = t), a.missing === 0) break;
|
|
220
|
+
}
|
|
221
|
+
return a.out;
|
|
222
|
+
}
|
|
223
|
+
function k(e, t, n, r) {
|
|
224
|
+
for (let i of c(t)) {
|
|
225
|
+
let t = ne(e, i, n, r);
|
|
226
|
+
if (t) return t;
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
function ne(e, t, n, r) {
|
|
231
|
+
for (let i of r.rings ?? w) for (let a of C) {
|
|
232
|
+
let o = E(e.x, e.y, t.w, t.h, n + a, e.r + (r.ownPad ?? r.pad) + i);
|
|
233
|
+
if (h(r.bounds, o) && !D(o, e, r)) return o;
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
var re = Array.from({ length: 41 }, (e, t) => 1 + t * .06), ie = [
|
|
238
|
+
1,
|
|
239
|
+
1.15,
|
|
240
|
+
1.3,
|
|
241
|
+
1.5,
|
|
242
|
+
1.75,
|
|
243
|
+
2,
|
|
244
|
+
2.3
|
|
245
|
+
], A = 5 * u, ae = 200;
|
|
246
|
+
function j(e, t, n, r, i) {
|
|
247
|
+
let a = r - i * (n - 1) / 2;
|
|
248
|
+
return Array.from({ length: n }, (n, r) => {
|
|
249
|
+
let o = a + r * i;
|
|
250
|
+
return {
|
|
251
|
+
x: e.x + t * Math.cos(o),
|
|
252
|
+
y: e.y + t * Math.sin(o)
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function M(e, t, n, r) {
|
|
257
|
+
return Array.from({ length: n }, (i, a) => {
|
|
258
|
+
let o = r + a * l / n;
|
|
259
|
+
return {
|
|
260
|
+
x: e.x + t * Math.cos(o),
|
|
261
|
+
y: e.y + t * Math.sin(o)
|
|
262
|
+
};
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function oe(e, t, n, r = !1) {
|
|
266
|
+
let { bounds: i, radius: a } = t, o = t.labelPad ?? 8, s = 0, c = 0;
|
|
267
|
+
for (let n of e) {
|
|
268
|
+
s += Math.max(0, i.x + a - n.x) + Math.max(0, n.x + a - (i.x + i.w)), s += Math.max(0, i.y + a - n.y) + Math.max(0, n.y + a - (i.y + i.h));
|
|
269
|
+
for (let e of t.obstacles) {
|
|
270
|
+
let r = a + e.r + t.gap * .75, i = Math.hypot(n.x - e.x, n.y - e.y);
|
|
271
|
+
i < r && (s += r - i);
|
|
272
|
+
}
|
|
273
|
+
if (!r) for (let e of t.blocked ?? []) {
|
|
274
|
+
let t = f(n, e);
|
|
275
|
+
t < a + o && (s += a + o - t);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (n && t.edgeStyle !== "none" && s === 0) {
|
|
279
|
+
let n = t.edgeStyle ?? "straight";
|
|
280
|
+
for (let n of e) for (let e of t.edges ?? []) {
|
|
281
|
+
let t = v(n, e);
|
|
282
|
+
t < a + 4 && (c += a + 4 - t);
|
|
283
|
+
}
|
|
284
|
+
e.forEach((r, i) => {
|
|
285
|
+
let o = S(t.origin, {
|
|
286
|
+
...r,
|
|
287
|
+
r: a
|
|
288
|
+
}, n, t.parentAngle).points;
|
|
289
|
+
for (let e of t.obstacles) {
|
|
290
|
+
let t = v(e, o);
|
|
291
|
+
t < e.r + 4 && (c += e.r + 4 - t);
|
|
292
|
+
}
|
|
293
|
+
e.forEach((e, t) => {
|
|
294
|
+
if (t === i) return;
|
|
295
|
+
let n = v(e, o);
|
|
296
|
+
n < a + 4 && (c += a + 4 - n);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
base: s,
|
|
302
|
+
edges: c
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function N(e, t, n, r, i = "optional") {
|
|
306
|
+
if (!t.labels?.some(Boolean) && !t.originLabel) return {
|
|
307
|
+
labels: e.map(() => null),
|
|
308
|
+
originLabel: null
|
|
309
|
+
};
|
|
310
|
+
let a = t.radius, o = t.edgeStyle ?? "straight", s = e.map((e) => ({
|
|
311
|
+
x: e.x,
|
|
312
|
+
y: e.y,
|
|
313
|
+
r: a
|
|
314
|
+
})), c = o === "none" ? [] : s.map((e) => S(t.origin, e, o, t.parentAngle).points), l = o === "none" ? [] : [...t.edges ?? [], ...c], u = {
|
|
315
|
+
bounds: t.bounds,
|
|
316
|
+
circles: [
|
|
317
|
+
...t.obstacles,
|
|
318
|
+
t.origin,
|
|
319
|
+
...s
|
|
320
|
+
],
|
|
321
|
+
taken: [...t.blocked ?? []],
|
|
322
|
+
edges: l,
|
|
323
|
+
pad: t.labelPad ?? 8
|
|
324
|
+
}, d = s.map((e, n) => ({
|
|
325
|
+
i: n,
|
|
326
|
+
node: e,
|
|
327
|
+
size: t.labels?.[n] ?? null,
|
|
328
|
+
angle: Math.atan2(e.y - t.origin.y, e.x - t.origin.x)
|
|
329
|
+
})).filter((e) => !!e.size), f = O(d, u, (e, t) => {
|
|
330
|
+
let r = e.i;
|
|
331
|
+
return k(e.node, e.size, e.angle, t) ?? (n === "strict" ? null : k(e.node, e.size, e.angle, {
|
|
332
|
+
...t,
|
|
333
|
+
edges: c
|
|
334
|
+
})) ?? (n === "loose" ? k(e.node, e.size, e.angle, {
|
|
335
|
+
...t,
|
|
336
|
+
edges: c.length ? [c[r]] : []
|
|
337
|
+
}) : null);
|
|
338
|
+
}), p = s.map(() => null);
|
|
339
|
+
if (d.forEach((e, t) => p[e.i] = f[t]), !r && d.some((e, t) => !f[t])) return null;
|
|
340
|
+
let m = null;
|
|
341
|
+
if (t.originLabel) {
|
|
342
|
+
let e = {
|
|
343
|
+
...u,
|
|
344
|
+
taken: [...u.taken, ...p.filter((e) => !!e)],
|
|
345
|
+
rings: T
|
|
346
|
+
}, n = t.parentEdge ? [t.parentEdge] : [];
|
|
347
|
+
if (m = k(t.origin, t.originLabel, t.direction, {
|
|
348
|
+
...e,
|
|
349
|
+
edges: [...e.edges, ...n]
|
|
350
|
+
}), !m && i !== "clean" && (m = k(t.origin, t.originLabel, t.direction + Math.PI, {
|
|
351
|
+
...e,
|
|
352
|
+
edges: e.edges.filter((e) => e !== t.parentEdge)
|
|
353
|
+
})), !m && i !== "optional" && !r) return null;
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
labels: p,
|
|
357
|
+
originLabel: m
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function P(e) {
|
|
361
|
+
let { origin: t, count: n, radius: r, gap: i } = e;
|
|
362
|
+
if (n <= 0) return {
|
|
363
|
+
points: [],
|
|
364
|
+
labels: []
|
|
365
|
+
};
|
|
366
|
+
let a = 2 * r + i, o = null, s = (t, n, r, i) => {
|
|
367
|
+
let a = oe(t, e, n);
|
|
368
|
+
if ((!o || a.base < o.penalty) && (o = {
|
|
369
|
+
points: t,
|
|
370
|
+
penalty: a.base
|
|
371
|
+
}), a.base > 0 || n && a.edges > 0 || r.left <= 0) return null;
|
|
372
|
+
r.left--;
|
|
373
|
+
let s = N(t, e, n ? "strict" : "relaxed", !1, i);
|
|
374
|
+
return s ? {
|
|
375
|
+
points: t,
|
|
376
|
+
...s
|
|
377
|
+
} : null;
|
|
378
|
+
}, c = re.map((t) => e.distance * t);
|
|
379
|
+
if (n > 1 && e.maxSpread != null) {
|
|
380
|
+
let t = a / (2 * Math.sin(e.maxSpread / (2 * (n - 1)))) + .5;
|
|
381
|
+
t > e.distance && c.push(t);
|
|
382
|
+
}
|
|
383
|
+
c.sort((e, t) => e - t);
|
|
384
|
+
let l = Math.min(e.maxDeviation ?? Math.PI, Math.PI), u = e.maxSpread != null && !e.ring ? Math.min(e.maxSpread * 1.5, 1.4 * Math.PI) : e.maxSpread, d = [
|
|
385
|
+
{
|
|
386
|
+
dev: l,
|
|
387
|
+
strict: !0,
|
|
388
|
+
spread: e.maxSpread
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
dev: Math.PI,
|
|
392
|
+
strict: !0,
|
|
393
|
+
spread: u
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
dev: Math.PI,
|
|
397
|
+
strict: !1,
|
|
398
|
+
spread: u
|
|
399
|
+
}
|
|
400
|
+
], f = (e.originLabel ? [
|
|
401
|
+
"clean",
|
|
402
|
+
"breadcrumb",
|
|
403
|
+
"optional"
|
|
404
|
+
] : ["optional"]).flatMap((e) => d.map((t) => ({
|
|
405
|
+
...t,
|
|
406
|
+
needOrigin: e
|
|
407
|
+
})));
|
|
408
|
+
for (let r of f) {
|
|
409
|
+
if (e.ring && n >= 3) {
|
|
410
|
+
let i = Math.max(e.distance, a / (2 * Math.sin(Math.PI / n)));
|
|
411
|
+
for (let a of ie) {
|
|
412
|
+
let o = s(M(t, i * a, n, e.direction), r.strict, { left: 1 }, r.needOrigin);
|
|
413
|
+
if (o) return o;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
for (let i of c) {
|
|
417
|
+
if (a >= 2 * i) continue;
|
|
418
|
+
let o = 2 * Math.asin(a / (2 * i)), c = Math.max(o, e.preferredStep ?? 0), l = c > o + 1e-9 ? [c, o] : [o], u = [];
|
|
419
|
+
for (let t of l) {
|
|
420
|
+
if (n > 1 && r.spread != null && t * (n - 1) > r.spread + 1e-9) continue;
|
|
421
|
+
let i = t === c ? 0 : .15;
|
|
422
|
+
for (let n = 0; n * A <= r.dev + 1e-9; n++) for (let r of n === 0 ? [0] : [1, -1]) {
|
|
423
|
+
let a = r * n * A;
|
|
424
|
+
u.push({
|
|
425
|
+
dir: e.direction + a,
|
|
426
|
+
step: t,
|
|
427
|
+
cost: Math.abs(a) + i
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
u.sort((e, t) => e.cost - t.cost);
|
|
432
|
+
let d = { left: ae };
|
|
433
|
+
for (let e of u) {
|
|
434
|
+
let a = s(j(t, i, n, e.dir, e.step), r.strict, d, r.needOrigin);
|
|
435
|
+
if (a) return a;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
let p = null, m = -1, h = 0, g = e.edgeStyle ?? "straight", _ = (t) => {
|
|
440
|
+
if (oe(t, e, !1, !0).base > 0) return;
|
|
441
|
+
h++;
|
|
442
|
+
let i = N(t, e, "loose", !0), a = i.labels, o = g === "none" ? [] : [...e.edges ?? [], ...t.map((t) => S(e.origin, {
|
|
443
|
+
...t,
|
|
444
|
+
r
|
|
445
|
+
}, g, e.parentAngle).points)], s = a.filter(Boolean).length + +!!i.originLabel, c = a.filter((e) => e && !o.some((t) => y(t, e))).length, l = s * (n + 2) + c;
|
|
446
|
+
l > m && (p = {
|
|
447
|
+
points: t,
|
|
448
|
+
...i
|
|
449
|
+
}, m = l);
|
|
450
|
+
};
|
|
451
|
+
if (e.ring && n >= 3) {
|
|
452
|
+
let r = Math.max(e.distance, a / (2 * Math.sin(Math.PI / n)));
|
|
453
|
+
for (let i of ie) _(M(t, r * i, n, e.direction));
|
|
454
|
+
}
|
|
455
|
+
for (let r of c) {
|
|
456
|
+
let i = (n + +!!e.originLabel) * (n + 2) + n;
|
|
457
|
+
if (h >= 160 || m === i || a >= 2 * r) continue;
|
|
458
|
+
let o = 2 * Math.asin(a / (2 * r));
|
|
459
|
+
for (let a = 0; a * A <= Math.PI && h < 160 && m < i; a++) for (let i of a === 0 ? [0] : [1, -1]) _(j(t, r, n, e.direction + i * a * A, o));
|
|
460
|
+
}
|
|
461
|
+
if (p) return p;
|
|
462
|
+
let v = o?.points ?? j(t, e.distance, n, e.direction, a / e.distance);
|
|
463
|
+
return {
|
|
464
|
+
points: v,
|
|
465
|
+
...N(v, e, "loose", !0)
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function F(e, t = /* @__PURE__ */ new Map()) {
|
|
469
|
+
let n = /* @__PURE__ */ new Map(), r = e.edgeStyle ?? "straight", i = e.nodeRadius, a = [e.hub], o = [], s = [], c = /* @__PURE__ */ new Set(), l = {
|
|
470
|
+
x: e.bounds.x + e.bounds.w / 2,
|
|
471
|
+
y: e.bounds.y + e.bounds.h / 2
|
|
472
|
+
};
|
|
473
|
+
for (let d of e.levels) {
|
|
474
|
+
let p = d.parentId == null ? null : n.get(d.parentId);
|
|
475
|
+
if (d.parentId != null && !p) continue;
|
|
476
|
+
d.parentId != null && c.add(d.parentId);
|
|
477
|
+
let m = p ? {
|
|
478
|
+
x: p.x,
|
|
479
|
+
y: p.y,
|
|
480
|
+
r: i
|
|
481
|
+
} : e.hub, h = t.get(d.key);
|
|
482
|
+
if (!h || h.points.length !== d.childIds.length) {
|
|
483
|
+
let n = Math.atan2(l.y - e.hub.y, l.x - e.hub.x), f = Math.hypot(l.x - e.hub.x, l.y - e.hub.y) < 1;
|
|
484
|
+
h = P({
|
|
485
|
+
origin: m,
|
|
486
|
+
parentAngle: p ? p.angle : null,
|
|
487
|
+
count: d.childIds.length,
|
|
488
|
+
direction: p ? p.angle : f ? -Math.PI / 2 : n,
|
|
489
|
+
radius: i,
|
|
490
|
+
distance: e.distance,
|
|
491
|
+
gap: e.gap,
|
|
492
|
+
bounds: e.bounds,
|
|
493
|
+
obstacles: a.filter((e) => e.x !== m.x || e.y !== m.y),
|
|
494
|
+
blocked: s.filter((e) => !c.has(e.id)).map((e) => e.rect),
|
|
495
|
+
edges: o,
|
|
496
|
+
edgeStyle: r,
|
|
497
|
+
labels: d.childIds.map((t) => e.labelSize?.(t) ?? null),
|
|
498
|
+
originLabel: p && d.parentId ? (e.branchLabelSize ?? e.labelSize)?.(d.parentId) ?? null : null,
|
|
499
|
+
parentEdge: p ? p.edge : null,
|
|
500
|
+
labelPad: e.labelPad,
|
|
501
|
+
...p ? {
|
|
502
|
+
maxSpread: 150 * u,
|
|
503
|
+
maxDeviation: 110 * u
|
|
504
|
+
} : {
|
|
505
|
+
ring: !0,
|
|
506
|
+
preferredStep: 50 * u,
|
|
507
|
+
maxSpread: Math.PI
|
|
508
|
+
}
|
|
509
|
+
}), t.set(d.key, h);
|
|
510
|
+
}
|
|
511
|
+
p && (p.pathLabel = h.originLabel ?? null, p.pathLabel && s.push({
|
|
512
|
+
id: `${d.parentId}\u0000open`,
|
|
513
|
+
rect: p.pathLabel
|
|
514
|
+
}));
|
|
515
|
+
let g = e.labelPad ?? 8;
|
|
516
|
+
for (let e of s) {
|
|
517
|
+
if (c.has(e.id) || !h.points.some((t) => f(t, e.rect) < i + g - .5)) continue;
|
|
518
|
+
let [t, r] = e.id.split("\0"), a = n.get(t);
|
|
519
|
+
a && (r ? a.pathLabel = null : a.label = null);
|
|
520
|
+
}
|
|
521
|
+
d.childIds.forEach((e, t) => {
|
|
522
|
+
let c = h.points[t], l = {
|
|
523
|
+
x: c.x,
|
|
524
|
+
y: c.y,
|
|
525
|
+
r: i
|
|
526
|
+
}, u = p ? p.angle : null, d = S(m, l, r, u).points;
|
|
527
|
+
n.set(e, {
|
|
528
|
+
x: c.x,
|
|
529
|
+
y: c.y,
|
|
530
|
+
from: {
|
|
531
|
+
x: m.x,
|
|
532
|
+
y: m.y
|
|
533
|
+
},
|
|
534
|
+
angle: Math.atan2(c.y - m.y, c.x - m.x),
|
|
535
|
+
parentAngle: u,
|
|
536
|
+
label: h.labels[t] ?? null,
|
|
537
|
+
edge: d
|
|
538
|
+
}), a.push(l), r !== "none" && o.push(d);
|
|
539
|
+
let f = h.labels[t];
|
|
540
|
+
f && s.push({
|
|
541
|
+
id: e,
|
|
542
|
+
rect: f
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
let d = e.levels[e.levels.length - 1];
|
|
547
|
+
if (d && e.labelSize) {
|
|
548
|
+
let t = e.labelPad ?? 8, a = /* @__PURE__ */ new Map();
|
|
549
|
+
for (let [e, t] of n) a.set(e, {
|
|
550
|
+
x: t.x,
|
|
551
|
+
y: t.y,
|
|
552
|
+
r: i
|
|
553
|
+
});
|
|
554
|
+
let s = d.childIds.filter((e) => n.has(e)), c = (e) => o.some((t) => y(t, e)), l = s.filter((t) => {
|
|
555
|
+
let r = n.get(t).label;
|
|
556
|
+
return e.labelSize(t) && (!r || c(r));
|
|
557
|
+
});
|
|
558
|
+
if (l.length) {
|
|
559
|
+
let i = {
|
|
560
|
+
bounds: e.bounds,
|
|
561
|
+
circles: [e.hub, ...a.values()],
|
|
562
|
+
taken: s.filter((e) => !l.includes(e)).map((e) => n.get(e).label).filter((e) => !!e),
|
|
563
|
+
edges: o,
|
|
564
|
+
pad: t
|
|
565
|
+
}, c = l.map((t) => ({
|
|
566
|
+
id: t,
|
|
567
|
+
node: a.get(t),
|
|
568
|
+
size: e.labelSize(t),
|
|
569
|
+
angle: n.get(t).angle
|
|
570
|
+
})), u = O(c, i, (e, t) => {
|
|
571
|
+
let i = n.get(e.id);
|
|
572
|
+
return k(e.node, e.size, e.angle, t) ?? i.label ?? k(e.node, e.size, e.angle, {
|
|
573
|
+
...t,
|
|
574
|
+
edges: r === "none" ? [] : [i.edge]
|
|
575
|
+
});
|
|
576
|
+
});
|
|
577
|
+
c.forEach((e, t) => {
|
|
578
|
+
let r = n.get(e.id);
|
|
579
|
+
u[t] && u[t] !== r.label && (r.label = u[t], r.borrowed = !0);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (r === "step" && d && e.labelSize) {
|
|
584
|
+
let t = new Set(e.levels.flatMap((e) => e.parentId == null ? [] : [e.parentId])), r = [.../* @__PURE__ */ new Set([...t, ...d.childIds])].filter((e) => n.has(e)), a = (e) => t.has(e) ? n.get(e).pathLabel : n.get(e).label;
|
|
585
|
+
for (let s of r) {
|
|
586
|
+
let c = n.get(s), l = a(s), u = t.has(s) ? o.filter((e) => e !== c.edge) : o;
|
|
587
|
+
if (l && !u.some((e) => y(e, l))) continue;
|
|
588
|
+
let d = (t.has(s) ? e.branchLabelSize ?? e.labelSize : e.labelSize)(s);
|
|
589
|
+
if (!d) continue;
|
|
590
|
+
let f = {
|
|
591
|
+
x: c.x,
|
|
592
|
+
y: c.y,
|
|
593
|
+
r: i
|
|
594
|
+
}, p = {
|
|
595
|
+
bounds: e.bounds,
|
|
596
|
+
circles: [e.hub, ...[...n.values()].map((e) => ({
|
|
597
|
+
x: e.x,
|
|
598
|
+
y: e.y,
|
|
599
|
+
r: i
|
|
600
|
+
}))],
|
|
601
|
+
taken: r.filter((e) => e !== s).map(a).filter((e) => !!e),
|
|
602
|
+
edges: u,
|
|
603
|
+
pad: e.labelPad ?? 8,
|
|
604
|
+
rings: [
|
|
605
|
+
...T,
|
|
606
|
+
64,
|
|
607
|
+
80
|
|
608
|
+
]
|
|
609
|
+
}, m = k(f, d, c.angle, p);
|
|
610
|
+
t.has(s) ? c.pathLabel = m : c.label = m, m && (c.borrowed = !0);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return n;
|
|
614
|
+
}
|
|
615
|
+
function se(e, t, n) {
|
|
616
|
+
let r = -1, i = Infinity;
|
|
617
|
+
return t.forEach((t, a) => {
|
|
618
|
+
let o = Math.hypot(e.x - t.x, e.y - t.y);
|
|
619
|
+
o <= t.r + n && o < i && (r = a, i = o);
|
|
620
|
+
}), r;
|
|
621
|
+
}
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/styles.ts
|
|
624
|
+
var ce = "\n --_fg: var(--unfold-fg, #17171c);\n --_muted: var(--unfold-muted, rgb(23 23 28 / .68));\n --_surface: var(--unfold-surface, rgb(255 255 255 / .78));\n --_surface-active: var(--unfold-surface-active, rgb(255 255 255 / .96));\n --_border: var(--unfold-border, rgb(255 255 255 / .7));\n --_outline: var(--unfold-outline, rgb(15 15 30 / .09));\n --_shadow: var(--unfold-shadow, 0 1px 2px rgb(15 15 30 / .08), 0 10px 28px -8px rgb(15 15 30 / .28));\n --_edge: var(--unfold-edge, rgb(23 23 28 / .2));\n --_label-bg: var(--unfold-label-bg, rgb(255 255 255 / .9));\n --_label-fg: var(--unfold-label-fg, var(--_fg));\n --_backdrop: var(--unfold-backdrop, rgb(244 244 248 / .42));\n", I = "\n --_fg: var(--unfold-fg, #f3f3f6);\n --_muted: var(--unfold-muted, rgb(243 243 246 / .7));\n --_surface: var(--unfold-surface, rgb(38 38 44 / .72));\n --_surface-active: var(--unfold-surface-active, rgb(56 56 64 / .92));\n --_border: var(--unfold-border, rgb(255 255 255 / .12));\n --_outline: var(--unfold-outline, rgb(0 0 0 / .4));\n --_shadow: var(--unfold-shadow, 0 1px 2px rgb(0 0 0 / .3), 0 12px 30px -8px rgb(0 0 0 / .6));\n --_edge: var(--unfold-edge, rgb(243 243 246 / .22));\n --_label-bg: var(--unfold-label-bg, rgb(30 30 36 / .9));\n --_label-fg: var(--unfold-label-fg, var(--_fg));\n --_backdrop: var(--unfold-backdrop, rgb(8 8 12 / .45));\n", le = `
|
|
625
|
+
:host {
|
|
626
|
+
display: inline-block;
|
|
627
|
+
vertical-align: middle;
|
|
628
|
+
}
|
|
629
|
+
:host([hidden]) { display: none; }
|
|
630
|
+
|
|
631
|
+
.root {
|
|
632
|
+
--_accent: var(--unfold-accent, #5b5bf0);
|
|
633
|
+
--_accent-fg: var(--unfold-accent-fg, #fff);
|
|
634
|
+
--_blur: var(--unfold-blur, 18px);
|
|
635
|
+
--_backdrop-blur: var(--unfold-backdrop-blur, 6px);
|
|
636
|
+
--_edge-width: var(--unfold-edge-width, 1.5px);
|
|
637
|
+
--_icon-size: var(--unfold-icon-size, 22px);
|
|
638
|
+
--_dur: var(--unfold-duration, 340ms);
|
|
639
|
+
--_spring: var(--unfold-easing, cubic-bezier(.22, 1.2, .36, 1));
|
|
640
|
+
--_ease: cubic-bezier(.3, .7, .2, 1);
|
|
641
|
+
--_z: var(--unfold-z-index, 2147483000);
|
|
642
|
+
--_node-radius: var(--unfold-node-radius, 50%);
|
|
643
|
+
--_trigger-radius: var(--unfold-trigger-radius, 50%);
|
|
644
|
+
--_border-width: var(--unfold-border-width, 1px);
|
|
645
|
+
--_active-scale: var(--unfold-active-scale, 1.14);
|
|
646
|
+
--_dim-opacity: var(--unfold-dim-opacity, .7);
|
|
647
|
+
--_dim-scale: var(--unfold-dim-scale, .86);
|
|
648
|
+
--_label-radius: var(--unfold-label-radius, 9px);
|
|
649
|
+
/* Follows the reader's font-size preference, never smaller than 13px. */
|
|
650
|
+
--_label-size: var(--unfold-label-size, max(13px, .8125rem));
|
|
651
|
+
--_desc-size: var(--unfold-description-size, max(12px, .75rem));
|
|
652
|
+
--_dock-bg: var(--unfold-dock-bg, color-mix(in srgb, var(--_surface-active) 88%, transparent));
|
|
653
|
+
--_dock-border: var(--unfold-dock-border, var(--_outline));
|
|
654
|
+
--_dock-blur: var(--unfold-dock-blur, 16px);
|
|
655
|
+
--_label-weight: var(--unfold-label-weight, 600);
|
|
656
|
+
--_label-tracking: var(--unfold-label-tracking, normal);
|
|
657
|
+
--_label-case: var(--unfold-label-case, none);
|
|
658
|
+
${ce}
|
|
659
|
+
/* Longhands on purpose: with no --unfold-font the family declaration is invalid and simply inherits the
|
|
660
|
+
page's font, while size and weight stay ours. (A shorthand with an inherited part would be dropped.) */
|
|
661
|
+
font-family: var(--unfold-font);
|
|
662
|
+
font-size: 13px;
|
|
663
|
+
font-weight: 500;
|
|
664
|
+
line-height: 1.25;
|
|
665
|
+
color: var(--_fg);
|
|
666
|
+
}
|
|
667
|
+
.root[data-theme="dark"] { ${I} }
|
|
668
|
+
@media (prefers-color-scheme: dark) {
|
|
669
|
+
.root[data-theme="auto"] { ${I} }
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/* ---------------------------------------------------------------- button */
|
|
673
|
+
|
|
674
|
+
/* dock="bar": a strip along the button's edge, so page content never sits under the button. */
|
|
675
|
+
.dock-bar {
|
|
676
|
+
display: none;
|
|
677
|
+
position: fixed;
|
|
678
|
+
z-index: calc(var(--_z) - 1);
|
|
679
|
+
background: var(--_dock-bg);
|
|
680
|
+
border: 0 solid var(--_dock-border);
|
|
681
|
+
-webkit-backdrop-filter: blur(var(--_dock-blur)) saturate(1.4);
|
|
682
|
+
backdrop-filter: blur(var(--_dock-blur)) saturate(1.4);
|
|
683
|
+
}
|
|
684
|
+
.root[data-dock="bar"] .dock-bar[data-edge] { display: block; }
|
|
685
|
+
.dock-bar[data-edge="top"], .dock-bar[data-edge="bottom"] { left: 0; right: 0; }
|
|
686
|
+
.dock-bar[data-edge="left"], .dock-bar[data-edge="right"] { top: 0; bottom: 0; }
|
|
687
|
+
.dock-bar[data-edge="top"] { top: 0; height: calc(var(--_trigger-size) + var(--_offset-y) * 2 + env(safe-area-inset-top, 0px)); border-bottom-width: 1px; }
|
|
688
|
+
.dock-bar[data-edge="bottom"] { bottom: 0; height: calc(var(--_trigger-size) + var(--_offset-y) * 2 + env(safe-area-inset-bottom, 0px)); border-top-width: 1px; }
|
|
689
|
+
.dock-bar[data-edge="left"] { left: 0; width: calc(var(--_trigger-size) + var(--_offset-x) * 2 + env(safe-area-inset-left, 0px)); border-right-width: 1px; }
|
|
690
|
+
.dock-bar[data-edge="right"] { right: 0; width: calc(var(--_trigger-size) + var(--_offset-x) * 2 + env(safe-area-inset-right, 0px)); border-left-width: 1px; }
|
|
691
|
+
|
|
692
|
+
.dock {
|
|
693
|
+
position: fixed;
|
|
694
|
+
z-index: var(--_z);
|
|
695
|
+
width: var(--_trigger-size);
|
|
696
|
+
height: var(--_trigger-size);
|
|
697
|
+
--_ox: calc(var(--_offset-x) + env(safe-area-inset-left, 0px));
|
|
698
|
+
--_ox-r: calc(var(--_offset-x) + env(safe-area-inset-right, 0px));
|
|
699
|
+
--_oy: calc(var(--_offset-y) + env(safe-area-inset-top, 0px));
|
|
700
|
+
--_oy-b: calc(var(--_offset-y) + env(safe-area-inset-bottom, 0px));
|
|
701
|
+
}
|
|
702
|
+
.dock[data-position="inline"] { position: relative; z-index: auto; }
|
|
703
|
+
.dock[data-position^="top"] { top: var(--_oy); }
|
|
704
|
+
.dock[data-position^="bottom"] { bottom: var(--_oy-b); }
|
|
705
|
+
.dock[data-position$="left"] { left: var(--_ox); }
|
|
706
|
+
.dock[data-position$="right"] { right: var(--_ox-r); }
|
|
707
|
+
.dock[data-position="top"], .dock[data-position="bottom"], .dock[data-position="center"] {
|
|
708
|
+
left: calc(50% - var(--_trigger-size) / 2);
|
|
709
|
+
}
|
|
710
|
+
.dock[data-position="left"], .dock[data-position="right"], .dock[data-position="center"] {
|
|
711
|
+
top: calc(50% - var(--_trigger-size) / 2);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.trigger, .hub, .node {
|
|
715
|
+
all: unset;
|
|
716
|
+
box-sizing: border-box;
|
|
717
|
+
display: grid;
|
|
718
|
+
place-items: center;
|
|
719
|
+
border-radius: var(--_node-radius);
|
|
720
|
+
color: var(--_fg);
|
|
721
|
+
background: var(--_surface);
|
|
722
|
+
border: var(--_border-width) solid var(--_border);
|
|
723
|
+
box-shadow: var(--_shadow), 0 0 0 .5px var(--_outline);
|
|
724
|
+
-webkit-backdrop-filter: blur(var(--_blur)) saturate(1.8);
|
|
725
|
+
backdrop-filter: blur(var(--_blur)) saturate(1.8);
|
|
726
|
+
cursor: pointer;
|
|
727
|
+
touch-action: none;
|
|
728
|
+
user-select: none;
|
|
729
|
+
-webkit-user-select: none;
|
|
730
|
+
-webkit-touch-callout: none;
|
|
731
|
+
-webkit-tap-highlight-color: transparent;
|
|
732
|
+
}
|
|
733
|
+
.trigger:focus-visible, .hub:focus-visible, .node:focus-visible {
|
|
734
|
+
outline: 3px solid var(--_accent);
|
|
735
|
+
outline-offset: 3px;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.trigger, .hub { border-radius: var(--_trigger-radius); }
|
|
739
|
+
.trigger {
|
|
740
|
+
position: relative;
|
|
741
|
+
width: 100%;
|
|
742
|
+
height: 100%;
|
|
743
|
+
transition: scale 220ms var(--_ease), box-shadow 220ms;
|
|
744
|
+
}
|
|
745
|
+
.trigger:hover { box-shadow: var(--_shadow), 0 0 0 .5px var(--_outline), 0 0 0 6px color-mix(in srgb, var(--_accent) 10%, transparent); }
|
|
746
|
+
.trigger[data-pressing] { scale: .92; }
|
|
747
|
+
.trigger-icon, .hub-icon {
|
|
748
|
+
display: grid;
|
|
749
|
+
place-items: center;
|
|
750
|
+
width: var(--_icon-size);
|
|
751
|
+
height: var(--_icon-size);
|
|
752
|
+
pointer-events: none;
|
|
753
|
+
}
|
|
754
|
+
.trigger-icon[data-default] { rotate: var(--_icon-rotate, 0deg); }
|
|
755
|
+
.icon-own { display: contents; }
|
|
756
|
+
.trigger-icon[data-slotted] .icon-own { display: none; }
|
|
757
|
+
.icon-own > svg, .icon-own > img, .hub-icon > svg, .trigger-icon ::slotted(*) { width: 100%; height: 100%; display: block; }
|
|
758
|
+
.icon-own > img { object-fit: contain; }
|
|
759
|
+
|
|
760
|
+
.hold {
|
|
761
|
+
position: absolute;
|
|
762
|
+
inset: -5px;
|
|
763
|
+
width: calc(100% + 10px);
|
|
764
|
+
height: calc(100% + 10px);
|
|
765
|
+
rotate: -90deg;
|
|
766
|
+
pointer-events: none;
|
|
767
|
+
overflow: visible;
|
|
768
|
+
}
|
|
769
|
+
.hold circle {
|
|
770
|
+
fill: none;
|
|
771
|
+
stroke: var(--_accent);
|
|
772
|
+
stroke-width: 2.5;
|
|
773
|
+
stroke-linecap: round;
|
|
774
|
+
stroke-dasharray: 1 1;
|
|
775
|
+
stroke-dashoffset: 1;
|
|
776
|
+
opacity: 0;
|
|
777
|
+
transition: opacity 120ms, stroke-dashoffset 120ms;
|
|
778
|
+
}
|
|
779
|
+
.trigger[data-pressing] .hold circle {
|
|
780
|
+
opacity: 1;
|
|
781
|
+
stroke-dashoffset: 0;
|
|
782
|
+
transition: opacity 80ms, stroke-dashoffset var(--_hold) linear;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/* --------------------------------------------------------------- overlay */
|
|
786
|
+
|
|
787
|
+
.overlay {
|
|
788
|
+
position: fixed;
|
|
789
|
+
inset: 0;
|
|
790
|
+
width: 100%;
|
|
791
|
+
height: 100%;
|
|
792
|
+
max-width: none;
|
|
793
|
+
max-height: none;
|
|
794
|
+
margin: 0;
|
|
795
|
+
padding: 0;
|
|
796
|
+
border: 0;
|
|
797
|
+
background: transparent;
|
|
798
|
+
color: inherit;
|
|
799
|
+
overflow: hidden;
|
|
800
|
+
overscroll-behavior: none;
|
|
801
|
+
z-index: var(--_z);
|
|
802
|
+
touch-action: none;
|
|
803
|
+
}
|
|
804
|
+
.overlay:not([data-state]) { display: none; }
|
|
805
|
+
.overlay::backdrop { background: transparent; }
|
|
806
|
+
.overlay:focus { outline: none; }
|
|
807
|
+
|
|
808
|
+
.backdrop {
|
|
809
|
+
position: absolute;
|
|
810
|
+
inset: 0;
|
|
811
|
+
background: var(--_backdrop);
|
|
812
|
+
-webkit-backdrop-filter: blur(var(--_backdrop-blur)) saturate(1.2);
|
|
813
|
+
backdrop-filter: blur(var(--_backdrop-blur)) saturate(1.2);
|
|
814
|
+
opacity: 0;
|
|
815
|
+
transition: opacity var(--_dur) var(--_ease);
|
|
816
|
+
}
|
|
817
|
+
.root:not([data-backdrop]) .backdrop { background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
818
|
+
.overlay[data-state="open"] .backdrop { opacity: 1; }
|
|
819
|
+
|
|
820
|
+
.edges {
|
|
821
|
+
position: absolute;
|
|
822
|
+
inset: 0;
|
|
823
|
+
width: 100%;
|
|
824
|
+
height: 100%;
|
|
825
|
+
overflow: visible;
|
|
826
|
+
pointer-events: none;
|
|
827
|
+
}
|
|
828
|
+
.edge {
|
|
829
|
+
fill: none;
|
|
830
|
+
stroke: var(--_edge);
|
|
831
|
+
stroke-width: var(--_edge-width);
|
|
832
|
+
stroke-linecap: round;
|
|
833
|
+
stroke-dasharray: 1 1;
|
|
834
|
+
stroke-dashoffset: 1;
|
|
835
|
+
opacity: 0;
|
|
836
|
+
transition: stroke-dashoffset var(--_dur) var(--_ease) var(--_delay, 0ms), opacity 160ms var(--_delay, 0ms), stroke 160ms, stroke-width 160ms;
|
|
837
|
+
}
|
|
838
|
+
.edge[data-shown] { stroke-dashoffset: 0; opacity: 1; }
|
|
839
|
+
.edge[data-dim] { opacity: .45; }
|
|
840
|
+
.edge[data-lit] { stroke: var(--_lit, var(--_accent)); stroke-width: calc(var(--_edge-width) + .5px); }
|
|
841
|
+
|
|
842
|
+
.root[data-edges="none"] .edges { display: none; }
|
|
843
|
+
|
|
844
|
+
.layer, .labels { position: absolute; inset: 0; pointer-events: none; }
|
|
845
|
+
|
|
846
|
+
/* ----------------------------------------------------------------- nodes */
|
|
847
|
+
|
|
848
|
+
.hub {
|
|
849
|
+
position: absolute;
|
|
850
|
+
pointer-events: auto;
|
|
851
|
+
transition: scale 220ms var(--_ease);
|
|
852
|
+
}
|
|
853
|
+
.hub[data-active] { scale: 1.08; }
|
|
854
|
+
.hub-icon { transition: rotate var(--_dur) var(--_spring), opacity 160ms; }
|
|
855
|
+
.overlay:not([data-state="open"]) .hub-icon { rotate: -90deg; opacity: 0; }
|
|
856
|
+
|
|
857
|
+
.node {
|
|
858
|
+
position: absolute;
|
|
859
|
+
left: 0;
|
|
860
|
+
top: 0;
|
|
861
|
+
width: var(--_node-size);
|
|
862
|
+
height: var(--_node-size);
|
|
863
|
+
margin: calc(var(--_node-size) / -2) 0 0 calc(var(--_node-size) / -2);
|
|
864
|
+
pointer-events: auto;
|
|
865
|
+
scale: 1;
|
|
866
|
+
--_tint: var(--_node-accent, var(--_accent));
|
|
867
|
+
transition:
|
|
868
|
+
translate var(--_dur) var(--_spring) var(--_delay, 0ms),
|
|
869
|
+
scale var(--_dur) var(--_spring) var(--_delay, 0ms),
|
|
870
|
+
opacity calc(var(--_dur) * .6) var(--_ease) var(--_delay, 0ms),
|
|
871
|
+
background-color 160ms, border-color 160ms, box-shadow 160ms, color 160ms;
|
|
872
|
+
}
|
|
873
|
+
.node[data-state="dim"] { opacity: var(--_dim-opacity); scale: var(--_dim-scale); }
|
|
874
|
+
.node[data-state="path"] { border-color: color-mix(in srgb, var(--_tint) 55%, transparent); color: var(--_tint); }
|
|
875
|
+
.node[data-active] {
|
|
876
|
+
background: var(--_surface-active);
|
|
877
|
+
color: var(--_tint);
|
|
878
|
+
opacity: 1;
|
|
879
|
+
scale: var(--_active-scale);
|
|
880
|
+
box-shadow: var(--_shadow), 0 0 0 2px var(--_tint), 0 0 0 7px color-mix(in srgb, var(--_tint) 18%, transparent);
|
|
881
|
+
}
|
|
882
|
+
.node[data-current] { color: var(--_tint); }
|
|
883
|
+
.node[data-current]::before {
|
|
884
|
+
content: "";
|
|
885
|
+
position: absolute;
|
|
886
|
+
inset: -4px;
|
|
887
|
+
border-radius: inherit;
|
|
888
|
+
border: 1.5px dashed color-mix(in srgb, var(--_tint) 70%, transparent);
|
|
889
|
+
pointer-events: none;
|
|
890
|
+
}
|
|
891
|
+
.node[aria-disabled="true"] { opacity: .35; cursor: not-allowed; }
|
|
892
|
+
.node[data-enter], .node[data-leave] { scale: .35; opacity: 0; }
|
|
893
|
+
.node[data-leave] { pointer-events: none; transition-duration: calc(var(--_dur) * .7); }
|
|
894
|
+
|
|
895
|
+
/* A knob on the rim, pointing where the children will unfold. */
|
|
896
|
+
.node[data-branch]::after {
|
|
897
|
+
content: "";
|
|
898
|
+
position: absolute;
|
|
899
|
+
width: 7px;
|
|
900
|
+
height: 7px;
|
|
901
|
+
border-radius: 50%;
|
|
902
|
+
background: var(--_surface-active);
|
|
903
|
+
box-shadow: 0 0 0 1.5px var(--_muted);
|
|
904
|
+
translate: calc(cos(var(--_a, 0deg)) * (var(--_node-size) / 2 - 1px)) calc(sin(var(--_a, 0deg)) * (var(--_node-size) / 2 - 1px));
|
|
905
|
+
transition: background-color 160ms, box-shadow 160ms;
|
|
906
|
+
}
|
|
907
|
+
.node[data-branch][data-current-trail]::after,
|
|
908
|
+
.node[data-branch][data-state="path"]::after,
|
|
909
|
+
.node[data-branch][data-active]::after { background: var(--_tint); box-shadow: 0 0 0 1.5px var(--_tint); }
|
|
910
|
+
.node[data-state="path"]::after { opacity: 0; }
|
|
911
|
+
|
|
912
|
+
.icon {
|
|
913
|
+
display: grid;
|
|
914
|
+
place-items: center;
|
|
915
|
+
width: var(--_icon-size);
|
|
916
|
+
height: var(--_icon-size);
|
|
917
|
+
pointer-events: none;
|
|
918
|
+
}
|
|
919
|
+
.icon > svg, .icon > img { width: 100%; height: 100%; display: block; }
|
|
920
|
+
.icon > img { object-fit: contain; border-radius: 4px; }
|
|
921
|
+
.glyph { font-size: calc(var(--_icon-size) * .92); line-height: 1; }
|
|
922
|
+
.mono { font-weight: 650; font-size: calc(var(--_icon-size) * .8); line-height: 1; letter-spacing: -.01em; }
|
|
923
|
+
|
|
924
|
+
/* ---------------------------------------------------------------- labels */
|
|
925
|
+
|
|
926
|
+
.label {
|
|
927
|
+
position: absolute;
|
|
928
|
+
left: 0;
|
|
929
|
+
top: 0;
|
|
930
|
+
box-sizing: border-box;
|
|
931
|
+
width: max-content;
|
|
932
|
+
max-width: var(--unfold-label-max-width, 160px);
|
|
933
|
+
padding: 5px 10px 6px;
|
|
934
|
+
border-radius: var(--_label-radius);
|
|
935
|
+
background: var(--_label-bg);
|
|
936
|
+
color: var(--_label-fg);
|
|
937
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / .06), 0 4px 14px -4px rgb(0 0 0 / .18), 0 0 0 .5px var(--_outline);
|
|
938
|
+
-webkit-backdrop-filter: blur(var(--_blur));
|
|
939
|
+
backdrop-filter: blur(var(--_blur));
|
|
940
|
+
overflow-wrap: anywhere;
|
|
941
|
+
pointer-events: none;
|
|
942
|
+
opacity: 0;
|
|
943
|
+
/* Labels never slide: a sliding label could cross another one on its way. */
|
|
944
|
+
transition: opacity 140ms var(--_ease);
|
|
945
|
+
}
|
|
946
|
+
.label[data-visible] { opacity: 1; transition-delay: var(--_label-delay, 0ms), 0ms; }
|
|
947
|
+
.label[data-instant] { transition: none; }
|
|
948
|
+
.label .title {
|
|
949
|
+
display: block;
|
|
950
|
+
text-wrap: balance;
|
|
951
|
+
font-family: var(--unfold-label-font, var(--unfold-font));
|
|
952
|
+
font-size: var(--_label-size);
|
|
953
|
+
font-weight: var(--_label-weight);
|
|
954
|
+
line-height: 1.25;
|
|
955
|
+
letter-spacing: var(--_label-tracking);
|
|
956
|
+
text-transform: var(--_label-case);
|
|
957
|
+
}
|
|
958
|
+
.label[data-go] .title::after { content: " →"; color: var(--_muted); font-weight: 500; }
|
|
959
|
+
.label .desc { display: none; margin-top: 2px; font-weight: 450; font-size: var(--_desc-size); line-height: 1.35; color: var(--_muted); }
|
|
960
|
+
.label[data-active] { max-width: var(--unfold-label-max-width-active, 240px); }
|
|
961
|
+
/* The wrapped variant, used where a one-line label doesn't fit. Words stay whole (hyphenated if needed). */
|
|
962
|
+
.label[data-narrow] {
|
|
963
|
+
max-width: var(--unfold-label-narrow-width, 96px);
|
|
964
|
+
min-width: min-content;
|
|
965
|
+
overflow-wrap: normal;
|
|
966
|
+
hyphens: auto;
|
|
967
|
+
}
|
|
968
|
+
.label[data-active]:not([data-compact]) .desc { display: block; }
|
|
969
|
+
.labels .measure { position: absolute; left: 0; top: 0; visibility: hidden; }
|
|
970
|
+
|
|
971
|
+
.sr-only {
|
|
972
|
+
position: absolute;
|
|
973
|
+
width: 1px;
|
|
974
|
+
height: 1px;
|
|
975
|
+
overflow: hidden;
|
|
976
|
+
clip-path: inset(50%);
|
|
977
|
+
white-space: nowrap;
|
|
978
|
+
}
|
|
979
|
+
.safe-probe {
|
|
980
|
+
position: fixed;
|
|
981
|
+
inset: 0;
|
|
982
|
+
visibility: hidden;
|
|
983
|
+
pointer-events: none;
|
|
984
|
+
padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/* Right-to-left: "back" points the other way. */
|
|
988
|
+
:host(:dir(rtl)) .hub[data-icon="back"] .hub-icon { scale: -1 1; }
|
|
989
|
+
|
|
990
|
+
@media (prefers-contrast: more) {
|
|
991
|
+
.root {
|
|
992
|
+
--_border-width: 2px;
|
|
993
|
+
--_border: currentColor;
|
|
994
|
+
--_muted: var(--_fg);
|
|
995
|
+
--_surface: var(--_surface-active);
|
|
996
|
+
--_label-bg: var(--_surface-active);
|
|
997
|
+
--_edge: color-mix(in srgb, var(--_fg) 60%, transparent);
|
|
998
|
+
--_dim-opacity: 1;
|
|
999
|
+
--_blur: 0px;
|
|
1000
|
+
}
|
|
1001
|
+
.label { border: 1.5px solid currentColor; }
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
1005
|
+
.root { --_surface: var(--_surface-active); --_label-bg: var(--_surface-active); --_blur: 0px; --_backdrop-blur: 0px; --_dock-blur: 0px; }
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/* Windows High Contrast and other forced palettes: states move from colour/shadow to outlines. */
|
|
1009
|
+
@media (forced-colors: active) {
|
|
1010
|
+
.trigger, .hub, .node { border: 2px solid ButtonText; }
|
|
1011
|
+
.node[data-active], .hub[data-active] { outline: 3px solid Highlight; outline-offset: 2px; }
|
|
1012
|
+
.node[data-state="path"] { border-color: Highlight; }
|
|
1013
|
+
.node[data-state="dim"] { opacity: 1; }
|
|
1014
|
+
.node[data-current]::before { border-color: Highlight; }
|
|
1015
|
+
.node[data-branch]::after { background: ButtonText; box-shadow: none; }
|
|
1016
|
+
.edge { stroke: CanvasText; }
|
|
1017
|
+
.edge[data-lit] { stroke: Highlight; }
|
|
1018
|
+
.label { border: 1px solid CanvasText; }
|
|
1019
|
+
.backdrop { background: Canvas; opacity: .9; }
|
|
1020
|
+
.hold circle { stroke: Highlight; }
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1024
|
+
.root { --_dur: 1ms; --_spring: linear; }
|
|
1025
|
+
.label { transition: opacity 120ms; }
|
|
1026
|
+
}
|
|
1027
|
+
`, L = Object.freeze({
|
|
1028
|
+
pages: "Pages",
|
|
1029
|
+
close: "Close navigation",
|
|
1030
|
+
backToTop: "Back to all pages",
|
|
1031
|
+
back: "Back to {label}"
|
|
1032
|
+
}), R = Object.freeze({
|
|
1033
|
+
pages: Object.freeze([]),
|
|
1034
|
+
position: "bottom-right",
|
|
1035
|
+
dock: "float",
|
|
1036
|
+
offset: 24,
|
|
1037
|
+
holdDelay: 220,
|
|
1038
|
+
expandDelay: 140,
|
|
1039
|
+
openOnTap: !0,
|
|
1040
|
+
nodeSize: 52,
|
|
1041
|
+
triggerSize: 60,
|
|
1042
|
+
spacing: 96,
|
|
1043
|
+
gap: 16,
|
|
1044
|
+
labels: "auto",
|
|
1045
|
+
edges: "curved",
|
|
1046
|
+
backdrop: !0,
|
|
1047
|
+
haptics: !0,
|
|
1048
|
+
theme: "auto",
|
|
1049
|
+
current: void 0,
|
|
1050
|
+
label: "Navigation",
|
|
1051
|
+
arrowKeys: "tree",
|
|
1052
|
+
strings: Object.freeze({}),
|
|
1053
|
+
triggerIcon: void 0,
|
|
1054
|
+
iconResolver: void 0,
|
|
1055
|
+
navigate: void 0
|
|
1056
|
+
});
|
|
1057
|
+
function z(e) {
|
|
1058
|
+
return typeof e == "string" || typeof e == "function" || typeof e == "object" && !!e && "cloneNode" in e && typeof e.cloneNode == "function";
|
|
1059
|
+
}
|
|
1060
|
+
var ue = {
|
|
1061
|
+
position: [
|
|
1062
|
+
"top-left",
|
|
1063
|
+
"top",
|
|
1064
|
+
"top-right",
|
|
1065
|
+
"left",
|
|
1066
|
+
"center",
|
|
1067
|
+
"right",
|
|
1068
|
+
"bottom-left",
|
|
1069
|
+
"bottom",
|
|
1070
|
+
"bottom-right",
|
|
1071
|
+
"inline"
|
|
1072
|
+
],
|
|
1073
|
+
dock: ["float", "bar"],
|
|
1074
|
+
labels: [
|
|
1075
|
+
"auto",
|
|
1076
|
+
"always",
|
|
1077
|
+
"hover",
|
|
1078
|
+
"none"
|
|
1079
|
+
],
|
|
1080
|
+
edges: [
|
|
1081
|
+
"curved",
|
|
1082
|
+
"straight",
|
|
1083
|
+
"step",
|
|
1084
|
+
"none"
|
|
1085
|
+
],
|
|
1086
|
+
theme: [
|
|
1087
|
+
"auto",
|
|
1088
|
+
"light",
|
|
1089
|
+
"dark"
|
|
1090
|
+
],
|
|
1091
|
+
arrowKeys: ["tree", "spatial"]
|
|
1092
|
+
};
|
|
1093
|
+
function de(e, t) {
|
|
1094
|
+
if (!t || typeof t != "object" || Array.isArray(t)) throw TypeError("[unfold-nav] Options must be an object.");
|
|
1095
|
+
let n = { ...e };
|
|
1096
|
+
for (let [e, r] of Object.entries(t)) {
|
|
1097
|
+
if (!Object.hasOwn(R, e)) continue;
|
|
1098
|
+
let t = e;
|
|
1099
|
+
n[t] = r === void 0 ? R[t] : r;
|
|
1100
|
+
}
|
|
1101
|
+
for (let [e, t] of Object.entries(ue)) if (!t.includes(n[e])) throw TypeError(`[unfold-nav] Invalid ${e}. Expected ${t.join(", ")}.`);
|
|
1102
|
+
for (let e of [
|
|
1103
|
+
"nodeSize",
|
|
1104
|
+
"triggerSize",
|
|
1105
|
+
"spacing",
|
|
1106
|
+
"gap",
|
|
1107
|
+
"holdDelay",
|
|
1108
|
+
"expandDelay"
|
|
1109
|
+
]) {
|
|
1110
|
+
let t = n[e], r = e === "nodeSize" || e === "triggerSize" || e === "spacing";
|
|
1111
|
+
if (typeof t != "number" || !Number.isFinite(t) || (r ? t <= 0 : t < 0)) throw RangeError(`[unfold-nav] ${e} must be a finite ${r ? "positive" : "non-negative"} number.`);
|
|
1112
|
+
}
|
|
1113
|
+
let r = n.offset, i = typeof r == "number" ? [r] : r && typeof r == "object" ? [r.x, r.y] : [];
|
|
1114
|
+
if (!i.length || i.some((e) => typeof e != "number" || !Number.isFinite(e) || e < 0)) throw RangeError("[unfold-nav] offset must be a non-negative number or { x, y }.");
|
|
1115
|
+
for (let e of [
|
|
1116
|
+
"openOnTap",
|
|
1117
|
+
"backdrop",
|
|
1118
|
+
"haptics"
|
|
1119
|
+
]) if (typeof n[e] != "boolean") throw TypeError(`[unfold-nav] ${e} must be a boolean.`);
|
|
1120
|
+
if (typeof n.label != "string" || !n.label.trim()) throw TypeError("[unfold-nav] label must be a non-empty string.");
|
|
1121
|
+
if (n.current != null && typeof n.current != "string") throw TypeError("[unfold-nav] current must be a URL string, null or undefined.");
|
|
1122
|
+
for (let e of ["navigate", "iconResolver"]) if (n[e] !== void 0 && typeof n[e] != "function") throw TypeError(`[unfold-nav] ${e} must be a function.`);
|
|
1123
|
+
if (n.triggerIcon !== void 0 && !z(n.triggerIcon)) throw TypeError("[unfold-nav] Invalid triggerIcon.");
|
|
1124
|
+
if (!n.strings || typeof n.strings != "object" || Array.isArray(n.strings)) throw TypeError("[unfold-nav] strings must be an object.");
|
|
1125
|
+
for (let e of Object.keys(L)) if (n.strings[e] !== void 0 && typeof n.strings[e] != "string") throw TypeError(`[unfold-nav] strings.${e} must be a string.`);
|
|
1126
|
+
return n.strings = Object.fromEntries(Object.entries(n.strings).filter(([e, t]) => Object.hasOwn(L, e) && t !== void 0)), n;
|
|
1127
|
+
}
|
|
1128
|
+
//#endregion
|
|
1129
|
+
//#region src/tree.ts
|
|
1130
|
+
function B(e) {
|
|
1131
|
+
let t = Array.isArray(e) ? {
|
|
1132
|
+
label: "Navigation",
|
|
1133
|
+
children: e
|
|
1134
|
+
} : e ?? {
|
|
1135
|
+
label: "Navigation",
|
|
1136
|
+
children: []
|
|
1137
|
+
}, n = /* @__PURE__ */ new Map(), r = {
|
|
1138
|
+
id: "",
|
|
1139
|
+
page: t,
|
|
1140
|
+
parent: null,
|
|
1141
|
+
children: [],
|
|
1142
|
+
depth: 0,
|
|
1143
|
+
index: 0
|
|
1144
|
+
}, i = /* @__PURE__ */ new WeakSet(), a = (e, t) => {
|
|
1145
|
+
if (!e || typeof e != "object" || Array.isArray(e)) throw TypeError(`[unfold-nav] ${t} must be a page object.`);
|
|
1146
|
+
if (typeof e.label != "string" || !e.label.trim()) throw TypeError(`[unfold-nav] ${t}.label must be a non-empty string.`);
|
|
1147
|
+
for (let n of [
|
|
1148
|
+
"id",
|
|
1149
|
+
"href",
|
|
1150
|
+
"target",
|
|
1151
|
+
"description",
|
|
1152
|
+
"color"
|
|
1153
|
+
]) if (e[n] !== void 0 && typeof e[n] != "string") throw TypeError(`[unfold-nav] ${t}.${n} must be a string.`);
|
|
1154
|
+
if (e.children !== void 0 && !Array.isArray(e.children)) throw TypeError(`[unfold-nav] ${t}.children must be an array.`);
|
|
1155
|
+
if (e.disabled !== void 0 && typeof e.disabled != "boolean") throw TypeError(`[unfold-nav] ${t}.disabled must be a boolean.`);
|
|
1156
|
+
if (e.icon !== void 0 && !z(e.icon)) throw TypeError(`[unfold-nav] ${t}.icon is invalid.`);
|
|
1157
|
+
if (i.has(e)) throw TypeError(`[unfold-nav] ${t} contains a cyclic page tree.`);
|
|
1158
|
+
};
|
|
1159
|
+
a(t, "pages"), i.add(t);
|
|
1160
|
+
let o = (e, t, r) => {
|
|
1161
|
+
(t ?? []).forEach((t, s) => {
|
|
1162
|
+
let c = [...r, s];
|
|
1163
|
+
a(t, `pages[${c.join("].children[")}]`);
|
|
1164
|
+
let l = t.id != null && t.id !== "" ? String(t.id) : `n${c.join(".")}`;
|
|
1165
|
+
if (n.has(l)) {
|
|
1166
|
+
let e = 2;
|
|
1167
|
+
for (; n.has(`${l}~${e}`);) e++;
|
|
1168
|
+
l = `${l}~${e}`;
|
|
1169
|
+
}
|
|
1170
|
+
let u = {
|
|
1171
|
+
id: l,
|
|
1172
|
+
page: t,
|
|
1173
|
+
parent: e,
|
|
1174
|
+
children: [],
|
|
1175
|
+
depth: e.depth + 1,
|
|
1176
|
+
index: s
|
|
1177
|
+
};
|
|
1178
|
+
n.set(l, u), e.children.push(u), i.add(t), o(u, t.children, c), i.delete(t);
|
|
1179
|
+
});
|
|
1180
|
+
};
|
|
1181
|
+
return o(r, t.children, []), {
|
|
1182
|
+
root: r,
|
|
1183
|
+
byId: n
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
function V(e) {
|
|
1187
|
+
let t = [];
|
|
1188
|
+
for (let n = e; n && n.depth > 0; n = n.parent) t.unshift(n.id);
|
|
1189
|
+
return t;
|
|
1190
|
+
}
|
|
1191
|
+
var H = (e) => e.length > 1 ? e.replace(/\/+$/, "") : e;
|
|
1192
|
+
function U(e, t, n) {
|
|
1193
|
+
let r;
|
|
1194
|
+
try {
|
|
1195
|
+
r = new URL(t, n);
|
|
1196
|
+
} catch {
|
|
1197
|
+
return null;
|
|
1198
|
+
}
|
|
1199
|
+
let i = H(r.pathname), a = null, o = -1, s = null, c = -1;
|
|
1200
|
+
for (let t of e.byId.values()) {
|
|
1201
|
+
let e = t.page.href;
|
|
1202
|
+
if (!e) continue;
|
|
1203
|
+
let l;
|
|
1204
|
+
try {
|
|
1205
|
+
l = new URL(e, n);
|
|
1206
|
+
} catch {
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
if (l.origin !== r.origin || l.search && l.search !== r.search || l.hash && l.hash !== r.hash) continue;
|
|
1210
|
+
let u = H(l.pathname);
|
|
1211
|
+
if (u === i) {
|
|
1212
|
+
let e = +!!l.search + +!!l.hash;
|
|
1213
|
+
(!a || e > o || e === o && t.depth > a.depth) && (a = t, o = e);
|
|
1214
|
+
} else u !== "/" && i.startsWith(u + "/") && u.length > c && (s = t, c = u.length);
|
|
1215
|
+
}
|
|
1216
|
+
return a ?? s;
|
|
1217
|
+
}
|
|
1218
|
+
//#endregion
|
|
1219
|
+
//#region src/insets.ts
|
|
1220
|
+
var fe = [
|
|
1221
|
+
"top",
|
|
1222
|
+
"right",
|
|
1223
|
+
"bottom",
|
|
1224
|
+
"left"
|
|
1225
|
+
], W = /* @__PURE__ */ new WeakMap();
|
|
1226
|
+
function pe(e, t, n, r = 0) {
|
|
1227
|
+
let i = W.get(t);
|
|
1228
|
+
if (!i && !n) return;
|
|
1229
|
+
i || (i = {
|
|
1230
|
+
owners: /* @__PURE__ */ new Map(),
|
|
1231
|
+
previous: /* @__PURE__ */ new Map()
|
|
1232
|
+
}, W.set(t, i)), n ? i.owners.set(e, {
|
|
1233
|
+
edge: n,
|
|
1234
|
+
size: r
|
|
1235
|
+
}) : i.owners.delete(e);
|
|
1236
|
+
let a = t.documentElement.style;
|
|
1237
|
+
for (let e of fe) {
|
|
1238
|
+
let t = `--unfold-inset-${e}`, n = [...i.owners.values()].filter((t) => t.edge === e).map((e) => e.size);
|
|
1239
|
+
if (n.length) i.previous.has(e) || i.previous.set(e, {
|
|
1240
|
+
value: a.getPropertyValue(t),
|
|
1241
|
+
priority: a.getPropertyPriority(t)
|
|
1242
|
+
}), a.setProperty(t, `calc(${Math.max(...n)}px + env(safe-area-inset-${e}, 0px))`);
|
|
1243
|
+
else {
|
|
1244
|
+
let n = i.previous.get(e);
|
|
1245
|
+
n && (n.value ? a.setProperty(t, n.value, n.priority) : a.removeProperty(t), i.previous.delete(e));
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
i.owners.size || W.delete(t);
|
|
1249
|
+
}
|
|
1250
|
+
//#endregion
|
|
1251
|
+
//#region src/navigation.ts
|
|
1252
|
+
function me(e, t) {
|
|
1253
|
+
try {
|
|
1254
|
+
let n = new URL(e, t);
|
|
1255
|
+
return [
|
|
1256
|
+
"http:",
|
|
1257
|
+
"https:",
|
|
1258
|
+
"mailto:",
|
|
1259
|
+
"tel:",
|
|
1260
|
+
"sms:"
|
|
1261
|
+
].includes(n.protocol) ? n.href : null;
|
|
1262
|
+
} catch {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
//#endregion
|
|
1267
|
+
//#region src/element.ts
|
|
1268
|
+
var G = Object.keys(R), K = {
|
|
1269
|
+
pages: "pages",
|
|
1270
|
+
position: "position",
|
|
1271
|
+
dock: "dock",
|
|
1272
|
+
offset: "offset",
|
|
1273
|
+
"hold-delay": "holdDelay",
|
|
1274
|
+
"expand-delay": "expandDelay",
|
|
1275
|
+
"open-on-tap": "openOnTap",
|
|
1276
|
+
"node-size": "nodeSize",
|
|
1277
|
+
"trigger-size": "triggerSize",
|
|
1278
|
+
spacing: "spacing",
|
|
1279
|
+
gap: "gap",
|
|
1280
|
+
labels: "labels",
|
|
1281
|
+
edges: "edges",
|
|
1282
|
+
backdrop: "backdrop",
|
|
1283
|
+
haptics: "haptics",
|
|
1284
|
+
theme: "theme",
|
|
1285
|
+
current: "current",
|
|
1286
|
+
label: "label",
|
|
1287
|
+
"arrow-keys": "arrowKeys",
|
|
1288
|
+
"trigger-icon": "triggerIcon"
|
|
1289
|
+
};
|
|
1290
|
+
function he(e, t) {
|
|
1291
|
+
if (t === null) return R[e];
|
|
1292
|
+
if (e === "offset") {
|
|
1293
|
+
let [e, n = e] = t.trim().split(/[\s,]+/).map(Number);
|
|
1294
|
+
return {
|
|
1295
|
+
x: e,
|
|
1296
|
+
y: n
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
if (e === "pages") return JSON.parse(t);
|
|
1300
|
+
switch (typeof R[e]) {
|
|
1301
|
+
case "number": return Number(t);
|
|
1302
|
+
case "boolean": return !/^(false|0|off|no)$/i.test(t.trim());
|
|
1303
|
+
}
|
|
1304
|
+
return t;
|
|
1305
|
+
}
|
|
1306
|
+
var ge = "http://www.w3.org/2000/svg", _e = "", q = typeof HTMLElement < "u" && "showPopover" in HTMLElement.prototype, ve = typeof HTMLElement > "u" ? class {} : HTMLElement, J = {
|
|
1307
|
+
ArrowUp: {
|
|
1308
|
+
x: 0,
|
|
1309
|
+
y: -1
|
|
1310
|
+
},
|
|
1311
|
+
ArrowDown: {
|
|
1312
|
+
x: 0,
|
|
1313
|
+
y: 1
|
|
1314
|
+
},
|
|
1315
|
+
ArrowLeft: {
|
|
1316
|
+
x: -1,
|
|
1317
|
+
y: 0
|
|
1318
|
+
},
|
|
1319
|
+
ArrowRight: {
|
|
1320
|
+
x: 1,
|
|
1321
|
+
y: 0
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
function Y(e, t, n, r = "") {
|
|
1325
|
+
n ? e.setAttribute(t, r) : e.removeAttribute(t);
|
|
1326
|
+
}
|
|
1327
|
+
function X(e, t, n) {
|
|
1328
|
+
let r = [t];
|
|
1329
|
+
for (let [e, i] of Object.entries(n)) i && r.push(`${t}-${e}`);
|
|
1330
|
+
let i = r.join(" ");
|
|
1331
|
+
e.getAttribute("part") !== i && e.setAttribute("part", i);
|
|
1332
|
+
}
|
|
1333
|
+
var Z = class extends ve {
|
|
1334
|
+
static get observedAttributes() {
|
|
1335
|
+
return Object.keys(K);
|
|
1336
|
+
}
|
|
1337
|
+
opts = { ...R };
|
|
1338
|
+
text = L;
|
|
1339
|
+
tree = B([]);
|
|
1340
|
+
currentId = null;
|
|
1341
|
+
currentTrail = /* @__PURE__ */ new Set();
|
|
1342
|
+
state = "closed";
|
|
1343
|
+
mode = "tap";
|
|
1344
|
+
path = [];
|
|
1345
|
+
active = null;
|
|
1346
|
+
focusId = null;
|
|
1347
|
+
views = /* @__PURE__ */ new Map();
|
|
1348
|
+
placed = /* @__PURE__ */ new Map();
|
|
1349
|
+
fanCache = /* @__PURE__ */ new Map();
|
|
1350
|
+
labelSizes = /* @__PURE__ */ new Map();
|
|
1351
|
+
branchLabelSizes = /* @__PURE__ */ new Map();
|
|
1352
|
+
narrowSizes = /* @__PURE__ */ new Map();
|
|
1353
|
+
narrowBranchSizes = /* @__PURE__ */ new Map();
|
|
1354
|
+
hub = {
|
|
1355
|
+
x: 0,
|
|
1356
|
+
y: 0,
|
|
1357
|
+
r: 30
|
|
1358
|
+
};
|
|
1359
|
+
bounds = {
|
|
1360
|
+
x: 0,
|
|
1361
|
+
y: 0,
|
|
1362
|
+
w: 0,
|
|
1363
|
+
h: 0
|
|
1364
|
+
};
|
|
1365
|
+
animationTimers = /* @__PURE__ */ new Set();
|
|
1366
|
+
pointerId = null;
|
|
1367
|
+
pointerType = "mouse";
|
|
1368
|
+
downAt = {
|
|
1369
|
+
x: 0,
|
|
1370
|
+
y: 0
|
|
1371
|
+
};
|
|
1372
|
+
lastPoint = {
|
|
1373
|
+
x: 0,
|
|
1374
|
+
y: 0
|
|
1375
|
+
};
|
|
1376
|
+
leftHub = !1;
|
|
1377
|
+
holdTimer = 0;
|
|
1378
|
+
dwellTimer = 0;
|
|
1379
|
+
dwellTarget = null;
|
|
1380
|
+
closeTimer = 0;
|
|
1381
|
+
resizeFrame = 0;
|
|
1382
|
+
openedAt = 0;
|
|
1383
|
+
lastPointerUp = -Infinity;
|
|
1384
|
+
typeahead = {
|
|
1385
|
+
text: "",
|
|
1386
|
+
at: 0
|
|
1387
|
+
};
|
|
1388
|
+
lastKeyActivation = -Infinity;
|
|
1389
|
+
els;
|
|
1390
|
+
constructor() {
|
|
1391
|
+
if (typeof document > "u") throw Error("[unfold-nav] Create navigation elements in a browser after mounting.");
|
|
1392
|
+
super();
|
|
1393
|
+
let e = this.attachShadow({ mode: "open" });
|
|
1394
|
+
e.innerHTML = `<style>${le}</style>
|
|
1395
|
+
<div class="root" part="root">
|
|
1396
|
+
<div class="dock-bar" part="dock-bar" aria-hidden="true"></div>
|
|
1397
|
+
<div class="dock" part="dock">
|
|
1398
|
+
<button class="trigger" part="trigger" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="graph">
|
|
1399
|
+
<svg class="hold" viewBox="0 0 100 100" aria-hidden="true"><circle cx="50" cy="50" r="47" pathLength="1"/></svg>
|
|
1400
|
+
<span class="trigger-icon" part="trigger-icon" aria-hidden="true"><slot name="icon"></slot><span class="icon-own"></span></span>
|
|
1401
|
+
</button>
|
|
1402
|
+
</div>
|
|
1403
|
+
<dialog class="overlay" part="overlay" id="graph">
|
|
1404
|
+
<div class="backdrop" part="backdrop" aria-hidden="true"></div>
|
|
1405
|
+
<svg class="edges" part="edges" aria-hidden="true"></svg>
|
|
1406
|
+
<div class="layer" role="tree"></div>
|
|
1407
|
+
<div class="labels" aria-hidden="true"><div class="measure"></div></div>
|
|
1408
|
+
<button class="hub" part="hub" type="button"><span class="hub-icon" aria-hidden="true"></span></button>
|
|
1409
|
+
</dialog>
|
|
1410
|
+
<div class="safe-probe" aria-hidden="true"></div>
|
|
1411
|
+
</div>`;
|
|
1412
|
+
let t = (t) => e.querySelector(t);
|
|
1413
|
+
this.els = {
|
|
1414
|
+
root: t(".root"),
|
|
1415
|
+
dockBar: t(".dock-bar"),
|
|
1416
|
+
dock: t(".dock"),
|
|
1417
|
+
trigger: t(".trigger"),
|
|
1418
|
+
triggerIcon: t(".trigger-icon"),
|
|
1419
|
+
iconSlot: t("slot[name=\"icon\"]"),
|
|
1420
|
+
iconOwn: t(".icon-own"),
|
|
1421
|
+
overlay: t(".overlay"),
|
|
1422
|
+
edges: t(".edges"),
|
|
1423
|
+
layer: t(".layer"),
|
|
1424
|
+
labels: t(".labels"),
|
|
1425
|
+
measure: t(".measure"),
|
|
1426
|
+
hub: t(".hub"),
|
|
1427
|
+
hubIcon: t(".hub-icon"),
|
|
1428
|
+
probe: t(".safe-probe")
|
|
1429
|
+
}, q && this.els.overlay.setAttribute("popover", "manual"), this.els.iconSlot.addEventListener("slotchange", () => this.syncSlotted());
|
|
1430
|
+
let { trigger: n, overlay: r } = this.els;
|
|
1431
|
+
n.addEventListener("pointerdown", this.onPointerDown), n.addEventListener("pointermove", this.onPointerMove), n.addEventListener("pointerup", this.onPointerUp), n.addEventListener("pointercancel", this.onPointerCancel), n.addEventListener("lostpointercapture", this.onLostCapture), n.addEventListener("click", this.onTriggerClick), n.addEventListener("keydown", this.onTriggerKey), n.addEventListener("contextmenu", (e) => e.preventDefault()), r.addEventListener("click", this.onOverlayClick), r.addEventListener("pointermove", this.onOverlayHover), r.addEventListener("keydown", this.onOverlayKey), r.addEventListener("cancel", this.onCancel), r.addEventListener("close", this.onDialogClose), r.addEventListener("wheel", (e) => e.preventDefault(), { passive: !1 }), r.addEventListener("touchmove", (e) => e.preventDefault(), { passive: !1 }), r.addEventListener("contextmenu", (e) => e.preventDefault()), this.applyOptions();
|
|
1432
|
+
}
|
|
1433
|
+
configure(e) {
|
|
1434
|
+
let t = de(this.opts, e), n = Object.hasOwn(e, "pages"), r = n ? B(t.pages) : this.tree;
|
|
1435
|
+
if (this.opts = t, this.tree = r, n && this.state !== "closed") {
|
|
1436
|
+
let e = this.state === "open", t = this.focusInside();
|
|
1437
|
+
this.finishClose(), t && this.isConnected && this.els.trigger.focus({ preventScroll: !0 }), e && this.emit("unfold-close");
|
|
1438
|
+
}
|
|
1439
|
+
return this.fanCache.clear(), this.clearLabelSizes(), this.applyOptions(), this.state === "open" && (this.measure(), this.render()), this;
|
|
1440
|
+
}
|
|
1441
|
+
get isOpen() {
|
|
1442
|
+
return this.state === "open";
|
|
1443
|
+
}
|
|
1444
|
+
open({ focus: e = !1 } = {}) {
|
|
1445
|
+
this.show("tap", e ? "keyboard" : "pointer");
|
|
1446
|
+
}
|
|
1447
|
+
close({ focusTrigger: e = !1 } = {}) {
|
|
1448
|
+
if (this.state !== "open") return;
|
|
1449
|
+
let t = this.focusInside();
|
|
1450
|
+
this.state = "closing", window.clearTimeout(this.holdTimer), window.clearTimeout(this.dwellTimer), this.holdTimer = this.dwellTimer = 0, this.dwellTarget = null, this.pointerId = null, window.removeEventListener("keydown", this.onWindowKey, !0);
|
|
1451
|
+
let { overlay: n, trigger: r, hub: i } = this.els;
|
|
1452
|
+
if (n.dataset.state = "closing", n.setAttribute("aria-hidden", "true"), i.tabIndex = -1, n.open && (n.close(), q)) try {
|
|
1453
|
+
n.showPopover();
|
|
1454
|
+
} catch {}
|
|
1455
|
+
r.setAttribute("aria-expanded", "false");
|
|
1456
|
+
let a = [...this.views.values()].filter((e) => !e.leaveTimer).reverse(), o = this.reducedMotion ? 0 : Math.min(12, 120 / Math.max(1, a.length));
|
|
1457
|
+
a.forEach((e, t) => this.leave(e, this.hub, t * o)), this.closeTimer = window.setTimeout(() => this.finishClose(), this.duration + a.length * o + 60), (e || t) && r.focus({ preventScroll: !0 }), this.emit("unfold-close");
|
|
1458
|
+
}
|
|
1459
|
+
toggle() {
|
|
1460
|
+
this.state === "open" ? this.close() : this.open();
|
|
1461
|
+
}
|
|
1462
|
+
connectedCallback() {
|
|
1463
|
+
for (let e of G) this.upgradeProperty(e);
|
|
1464
|
+
if (!this.tree.root.children.length) {
|
|
1465
|
+
let e = this.querySelector("script[type=\"application/json\"]");
|
|
1466
|
+
if (e?.textContent?.trim()) try {
|
|
1467
|
+
this.configure({ pages: JSON.parse(e.textContent) });
|
|
1468
|
+
} catch (e) {
|
|
1469
|
+
console.warn("[unfold-nav] Invalid inline pages:", e);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
window.addEventListener("resize", this.onResize), document.fonts?.addEventListener("loadingdone", this.onFontsLoaded), this.publishInsets(), this.onResize();
|
|
1473
|
+
}
|
|
1474
|
+
disconnectedCallback() {
|
|
1475
|
+
window.removeEventListener("resize", this.onResize), window.removeEventListener("keydown", this.onWindowKey, !0), document.fonts?.removeEventListener("loadingdone", this.onFontsLoaded), window.clearTimeout(this.holdTimer), window.clearTimeout(this.dwellTimer), this.holdTimer = this.dwellTimer = 0, this.pointerId = null, this.els.trigger.removeAttribute("data-pressing"), cancelAnimationFrame(this.resizeFrame), this.resizeFrame = 0, this.finishClose(), this.publishInsets();
|
|
1476
|
+
}
|
|
1477
|
+
attributeChangedCallback(e, t, n) {
|
|
1478
|
+
if (t === n) return;
|
|
1479
|
+
let r = K[e];
|
|
1480
|
+
if (r) try {
|
|
1481
|
+
this.configure({ [r]: he(r, n) });
|
|
1482
|
+
} catch (t) {
|
|
1483
|
+
console.warn(`[unfold-nav] Ignoring invalid ${e} attribute:`, t);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
upgradeProperty(e) {
|
|
1487
|
+
if (Object.prototype.hasOwnProperty.call(this, e)) {
|
|
1488
|
+
let t = this[e];
|
|
1489
|
+
delete this[e], this.configure({ [e]: t });
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
applyOptions() {
|
|
1493
|
+
let e = this.opts, { root: t, dock: n, dockBar: r, trigger: i, layer: a, overlay: o } = this.els;
|
|
1494
|
+
this.text = {
|
|
1495
|
+
...L,
|
|
1496
|
+
...e.strings
|
|
1497
|
+
}, t.dataset.theme = e.theme, t.dataset.edges = e.edges, t.dataset.dock = e.dock, Y(t, "data-backdrop", e.backdrop), n.dataset.position = e.position;
|
|
1498
|
+
let s = this.dockEdge();
|
|
1499
|
+
Y(r, "data-edge", !!s, s ?? "");
|
|
1500
|
+
let c = this.offsets;
|
|
1501
|
+
t.style.setProperty("--_offset-x", `${c.x}px`), t.style.setProperty("--_offset-y", `${c.y}px`), t.style.setProperty("--_trigger-size", `${e.triggerSize}px`), t.style.setProperty("--_node-size", `${e.nodeSize}px`), t.style.setProperty("--_hold", `${e.holdDelay}ms`), i.setAttribute("aria-label", e.label), o.setAttribute("aria-label", e.label), a.setAttribute("aria-label", this.text.pages), this.syncIcon(), this.publishInsets();
|
|
1502
|
+
}
|
|
1503
|
+
get offsets() {
|
|
1504
|
+
let e = this.opts.offset;
|
|
1505
|
+
return typeof e == "number" ? {
|
|
1506
|
+
x: e,
|
|
1507
|
+
y: e
|
|
1508
|
+
} : e;
|
|
1509
|
+
}
|
|
1510
|
+
dockEdge() {
|
|
1511
|
+
let e = this.opts.position;
|
|
1512
|
+
return e === "center" || e === "inline" ? null : e.startsWith("top") ? "top" : e.startsWith("bottom") ? "bottom" : e;
|
|
1513
|
+
}
|
|
1514
|
+
publishInsets() {
|
|
1515
|
+
let e = this.isConnected ? this.dockEdge() : null, t = this.offsets, n = this.opts.triggerSize + 2 * (e === "top" || e === "bottom" ? t.y : t.x);
|
|
1516
|
+
pe(this, this.ownerDocument, e, n);
|
|
1517
|
+
}
|
|
1518
|
+
syncIcon() {
|
|
1519
|
+
let e = this.opts, t = n(e.triggerIcon ?? this.tree.root.page.icon, e.iconResolver);
|
|
1520
|
+
this.els.iconOwn.replaceChildren(t ?? n(a, void 0)), this.els.iconOwn.toggleAttribute("data-custom", !!t), this.syncSlotted();
|
|
1521
|
+
}
|
|
1522
|
+
syncSlotted() {
|
|
1523
|
+
let e = this.els.iconSlot.assignedNodes().length > 0;
|
|
1524
|
+
Y(this.els.triggerIcon, "data-slotted", e), Y(this.els.triggerIcon, "data-default", !e && !this.els.iconOwn.hasAttribute("data-custom")), this.isConnected && this.orientIcon();
|
|
1525
|
+
}
|
|
1526
|
+
show(e, t) {
|
|
1527
|
+
if (this.state === "open" || !this.isConnected) return;
|
|
1528
|
+
window.clearTimeout(this.closeTimer), this.state = "open", this.mode = e, this.path = [], this.active = null, this.focusId = null, this.dwellTarget = null, this.computeCurrent();
|
|
1529
|
+
let { overlay: n, trigger: r, hub: i } = this.els;
|
|
1530
|
+
if (n.dataset.state = "open", n.dataset.mode = e, n.removeAttribute("aria-hidden"), i.tabIndex = 0, this.present(e === "tap"), r.setAttribute("aria-expanded", "true"), this.openedAt = performance.now(), this.measure(), this.render(), this.haptic(10), e === "drag" && window.addEventListener("keydown", this.onWindowKey, !0), this.emit("unfold-open", { mode: e }), e === "tap" && t !== "none") {
|
|
1531
|
+
let e = this.initialFocusId();
|
|
1532
|
+
e && this.focusNode(e, t === "keyboard");
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
present(e) {
|
|
1536
|
+
let t = this.els.overlay;
|
|
1537
|
+
try {
|
|
1538
|
+
e ? (q && t.matches(":popover-open") && t.hidePopover(), t.open || t.showModal()) : !t.open && !(q && t.matches(":popover-open")) && (q ? t.showPopover() : t.show());
|
|
1539
|
+
} catch {}
|
|
1540
|
+
}
|
|
1541
|
+
finishClose() {
|
|
1542
|
+
window.clearTimeout(this.closeTimer), this.state = "closed", window.removeEventListener("keydown", this.onWindowKey, !0), window.clearTimeout(this.holdTimer), window.clearTimeout(this.dwellTimer), this.holdTimer = this.dwellTimer = 0, this.dwellTarget = null, this.pointerId = null, this.els.trigger.removeAttribute("data-pressing");
|
|
1543
|
+
for (let e of this.animationTimers) window.clearTimeout(e);
|
|
1544
|
+
this.animationTimers.clear();
|
|
1545
|
+
for (let e of this.views.values()) window.clearTimeout(e.leaveTimer), e.node.remove(), e.label.remove(), e.edge.remove();
|
|
1546
|
+
this.views.clear(), this.placed.clear();
|
|
1547
|
+
let { overlay: e } = this.els;
|
|
1548
|
+
try {
|
|
1549
|
+
e.open && e.close(), q && e.matches(":popover-open") && e.hidePopover();
|
|
1550
|
+
} catch {}
|
|
1551
|
+
e.removeAttribute("data-state"), e.removeAttribute("aria-hidden"), this.els.trigger.setAttribute("aria-expanded", "false");
|
|
1552
|
+
}
|
|
1553
|
+
onCancel = (e) => {
|
|
1554
|
+
e.preventDefault(), this.state === "open" && (this.path.length ? this.goUp(!0) : this.close({ focusTrigger: !0 }));
|
|
1555
|
+
};
|
|
1556
|
+
onDialogClose = () => {
|
|
1557
|
+
this.state === "open" && !this.els.overlay.open && !(q && this.els.overlay.matches(":popover-open")) && (this.finishClose(), this.emit("unfold-close"), this.els.trigger.focus({ preventScroll: !0 }));
|
|
1558
|
+
};
|
|
1559
|
+
onWindowKey = (e) => {
|
|
1560
|
+
e.key === "Escape" && this.state === "open" && this.mode === "drag" && (e.preventDefault(), this.close());
|
|
1561
|
+
};
|
|
1562
|
+
focusInside() {
|
|
1563
|
+
let e = this.shadowRoot?.activeElement;
|
|
1564
|
+
return !!e && this.els.overlay.contains(e);
|
|
1565
|
+
}
|
|
1566
|
+
computeCurrent() {
|
|
1567
|
+
let e = this.opts.current === void 0 ? location.href : this.opts.current, t = e ? U(this.tree, e, location.href) : null;
|
|
1568
|
+
this.currentId = t?.id ?? null, this.currentTrail = new Set(V(t));
|
|
1569
|
+
}
|
|
1570
|
+
initialFocusId() {
|
|
1571
|
+
return (this.currentId ? V(this.tree.byId.get(this.currentId)) : [])[0] ?? this.tree.root.children[0]?.id ?? null;
|
|
1572
|
+
}
|
|
1573
|
+
measure() {
|
|
1574
|
+
let { trigger: e, hub: t, probe: n, overlay: r } = this.els, i = e.getBoundingClientRect(), a = e.offsetWidth / 2, o = {
|
|
1575
|
+
x: i.left + i.width / 2,
|
|
1576
|
+
y: i.top + i.height / 2,
|
|
1577
|
+
r: a
|
|
1578
|
+
};
|
|
1579
|
+
(o.x !== this.hub.x || o.y !== this.hub.y || o.r !== this.hub.r) && this.fanCache.clear(), this.hub = o, Object.assign(t.style, {
|
|
1580
|
+
left: `${o.x - a}px`,
|
|
1581
|
+
top: `${o.y - a}px`,
|
|
1582
|
+
width: `${a * 2}px`,
|
|
1583
|
+
height: `${a * 2}px`
|
|
1584
|
+
});
|
|
1585
|
+
let s = r.getBoundingClientRect(), c = s.width || document.documentElement.clientWidth, l = s.height || window.innerHeight, u = getComputedStyle(n), d = {
|
|
1586
|
+
t: parseFloat(u.paddingTop) || 0,
|
|
1587
|
+
r: parseFloat(u.paddingRight) || 0,
|
|
1588
|
+
b: parseFloat(u.paddingBottom) || 0,
|
|
1589
|
+
l: parseFloat(u.paddingLeft) || 0
|
|
1590
|
+
}, f = {
|
|
1591
|
+
x: d.l + 8,
|
|
1592
|
+
y: d.t + 8,
|
|
1593
|
+
w: c - d.l - d.r - 16,
|
|
1594
|
+
h: l - d.t - d.b - 16
|
|
1595
|
+
};
|
|
1596
|
+
(f.w !== this.bounds.w || f.h !== this.bounds.h) && this.fanCache.clear(), this.bounds = f;
|
|
1597
|
+
}
|
|
1598
|
+
orientIcon() {
|
|
1599
|
+
let e = this.els.trigger.getBoundingClientRect(), t = e.left + e.width / 2, n = e.top + e.height / 2, r = document.documentElement.clientWidth / 2 - t, i = window.innerHeight / 2 - n, a = Math.hypot(r, i) < 2 ? 0 : Math.atan2(i, r) * 180 / Math.PI + 90;
|
|
1600
|
+
this.els.root.style.setProperty("--_icon-rotate", `${a.toFixed(1)}deg`);
|
|
1601
|
+
}
|
|
1602
|
+
onResize = () => {
|
|
1603
|
+
cancelAnimationFrame(this.resizeFrame), this.resizeFrame = requestAnimationFrame(() => {
|
|
1604
|
+
this.resizeFrame = 0, this.isConnected && (this.orientIcon(), this.state === "open" && (this.measure(), this.render()));
|
|
1605
|
+
});
|
|
1606
|
+
};
|
|
1607
|
+
clearLabelSizes() {
|
|
1608
|
+
for (let e of [
|
|
1609
|
+
this.labelSizes,
|
|
1610
|
+
this.branchLabelSizes,
|
|
1611
|
+
this.narrowSizes,
|
|
1612
|
+
this.narrowBranchSizes
|
|
1613
|
+
]) e.clear();
|
|
1614
|
+
}
|
|
1615
|
+
onFontsLoaded = () => {
|
|
1616
|
+
this.clearLabelSizes(), this.fanCache.clear(), this.state === "open" && this.render();
|
|
1617
|
+
};
|
|
1618
|
+
render() {
|
|
1619
|
+
if (this.state !== "open") return;
|
|
1620
|
+
let { root: e, byId: t } = this.tree, n = this.opts.nodeSize / 2, r = [{
|
|
1621
|
+
key: "",
|
|
1622
|
+
parentId: null,
|
|
1623
|
+
childIds: e.children.map((e) => e.id)
|
|
1624
|
+
}], i = [];
|
|
1625
|
+
for (let e of this.path) {
|
|
1626
|
+
let n = t.get(e);
|
|
1627
|
+
if (!n || !n.children.length || (n.parent?.id ?? "") !== (i[i.length - 1] ?? "")) break;
|
|
1628
|
+
i.push(e), r.push({
|
|
1629
|
+
key: i.join(_e),
|
|
1630
|
+
parentId: e,
|
|
1631
|
+
childIds: n.children.map((e) => e.id)
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
this.path = i;
|
|
1635
|
+
let a = new Set(i), c = r[r.length - 1].parentId ?? "", l = this.opts.labels !== "none";
|
|
1636
|
+
l && this.measureLabels(r.flatMap((e) => e.childIds)), this.placed = F({
|
|
1637
|
+
hub: this.hub,
|
|
1638
|
+
bounds: this.bounds,
|
|
1639
|
+
levels: r,
|
|
1640
|
+
nodeRadius: n,
|
|
1641
|
+
distance: this.opts.spacing,
|
|
1642
|
+
gap: this.opts.gap,
|
|
1643
|
+
edgeStyle: this.opts.edges,
|
|
1644
|
+
labelSize: l ? (e) => this.sizesOf(e, !1) : void 0,
|
|
1645
|
+
branchLabelSize: l ? (e) => this.sizesOf(e, !0) : void 0,
|
|
1646
|
+
labelPad: this.labelPad
|
|
1647
|
+
}, this.fanCache);
|
|
1648
|
+
for (let e of this.views.values()) !this.placed.has(e.tree.id) && !e.leaveTimer && this.leave(e, e.from, 0);
|
|
1649
|
+
let u = this.focusId && this.placed.has(this.focusId) ? this.focusId : this.initialFocusId(), d = [];
|
|
1650
|
+
for (let e of r) {
|
|
1651
|
+
let r = (e.parentId ? this.views.get(e.parentId) : null)?.node ?? null;
|
|
1652
|
+
for (let i of e.childIds) {
|
|
1653
|
+
let o = this.placed.get(i), s = this.views.get(i);
|
|
1654
|
+
s ? s.leaveTimer && (window.clearTimeout(s.leaveTimer), s.leaveTimer = 0, s.node.removeAttribute("data-leave"), s.edge.setAttribute("data-shown", "")) : (s = this.createView(t.get(i), o), this.views.set(i, s), r ? r.after(s.node) : this.els.layer.append(s.node), d.push(s)), r = s.node, s.from = o.from;
|
|
1655
|
+
let { node: l, edge: f, tree: p } = s, m = a.has(i) ? "path" : (p.parent?.id ?? "") === c ? "frontier" : "dim";
|
|
1656
|
+
l.dataset.state = m, Y(l, "data-active", i === this.active), Y(l, "data-current", i === this.currentId), Y(l, "data-current-trail", this.currentTrail.has(i) && i !== this.currentId), i === this.currentId ? l.setAttribute("aria-current", "page") : l.removeAttribute("aria-current"), p.children.length && l.setAttribute("aria-expanded", String(a.has(i))), l.tabIndex = i === u ? 0 : -1, l.style.setProperty("--_a", `${o.angle.toFixed(4)}rad`), d.includes(s) || (l.style.translate = `${o.x}px ${o.y}px`), X(l, "node", {
|
|
1657
|
+
active: i === this.active,
|
|
1658
|
+
current: i === this.currentId,
|
|
1659
|
+
trail: this.currentTrail.has(i) && i !== this.currentId,
|
|
1660
|
+
path: m === "path",
|
|
1661
|
+
frontier: m === "frontier",
|
|
1662
|
+
dim: m === "dim",
|
|
1663
|
+
branch: p.children.length > 0,
|
|
1664
|
+
disabled: !!p.page.disabled
|
|
1665
|
+
});
|
|
1666
|
+
let h = e.parentId == null ? this.hub : {
|
|
1667
|
+
...this.placed.get(e.parentId),
|
|
1668
|
+
r: n
|
|
1669
|
+
}, g = a.has(i) || i === this.active, _ = m === "dim" && i !== this.active;
|
|
1670
|
+
f.setAttribute("d", S(h, {
|
|
1671
|
+
x: o.x,
|
|
1672
|
+
y: o.y,
|
|
1673
|
+
r: n
|
|
1674
|
+
}, this.opts.edges, o.parentAngle).d), Y(f, "data-lit", g), Y(f, "data-dim", _), X(f, "edge", {
|
|
1675
|
+
lit: g,
|
|
1676
|
+
dim: _
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
d.length && this.animateIn(d), this.renderLabels();
|
|
1681
|
+
let f = this.els.hub, p = i.length ? "back" : "close";
|
|
1682
|
+
f.dataset.icon !== p && (f.dataset.icon = p, this.els.hubIcon.innerHTML = i.length ? s : o);
|
|
1683
|
+
let m = i.length > 1 ? t.get(i[i.length - 2]).page.label : null;
|
|
1684
|
+
f.setAttribute("aria-label", i.length ? m ? this.text.back.replace("{label}", m) : this.text.backToTop : this.text.close), Y(f, "data-active", this.mode === "drag" && this.dwellTarget === "hub"), X(f, "hub", {
|
|
1685
|
+
back: i.length > 0,
|
|
1686
|
+
active: f.hasAttribute("data-active")
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
get labelPad() {
|
|
1690
|
+
let e = parseFloat(getComputedStyle(this.els.root).getPropertyValue("--_active-scale")) || 1.14;
|
|
1691
|
+
return this.opts.nodeSize / 2 * Math.max(0, e - 1) + 8;
|
|
1692
|
+
}
|
|
1693
|
+
buildLabel(e) {
|
|
1694
|
+
let t = document.createElement("div");
|
|
1695
|
+
t.className = "label", t.setAttribute("part", "label");
|
|
1696
|
+
let n = document.createElement("span");
|
|
1697
|
+
if (n.className = "title", n.textContent = e.page.label, t.append(n), e.page.description) {
|
|
1698
|
+
let n = document.createElement("span");
|
|
1699
|
+
n.className = "desc", n.textContent = e.page.description, t.append(n);
|
|
1700
|
+
}
|
|
1701
|
+
return t;
|
|
1702
|
+
}
|
|
1703
|
+
sizesOf(e, t) {
|
|
1704
|
+
let n = (t ? this.branchLabelSizes.get(e) : null) ?? this.labelSizes.get(e);
|
|
1705
|
+
if (!n) return null;
|
|
1706
|
+
let r = (t ? this.narrowBranchSizes.get(e) : null) ?? this.narrowSizes.get(e);
|
|
1707
|
+
return r ? [n, r] : n;
|
|
1708
|
+
}
|
|
1709
|
+
measureLabels(e) {
|
|
1710
|
+
let t = e.filter((e) => !this.labelSizes.has(e));
|
|
1711
|
+
if (!t.length) return;
|
|
1712
|
+
let n = this.els.measure, r = (e) => e.children.length && e.page.href ? [!1, !0] : [!1], i = t.flatMap((e) => {
|
|
1713
|
+
let t = this.tree.byId.get(e);
|
|
1714
|
+
return r(t).flatMap((r) => [!1, !0].map((i) => {
|
|
1715
|
+
let a = this.buildLabel(t);
|
|
1716
|
+
return Y(a, "data-go", r), Y(a, "data-narrow", i), n.append(a), {
|
|
1717
|
+
id: e,
|
|
1718
|
+
el: a,
|
|
1719
|
+
go: r,
|
|
1720
|
+
narrow: i
|
|
1721
|
+
};
|
|
1722
|
+
}));
|
|
1723
|
+
}), a = (e) => ({
|
|
1724
|
+
w: Math.ceil(e.offsetWidth) + 1,
|
|
1725
|
+
h: Math.ceil(e.offsetHeight) + 1
|
|
1726
|
+
});
|
|
1727
|
+
for (let { id: e, el: t, go: n, narrow: r } of i) (r ? n ? this.narrowBranchSizes : this.narrowSizes : n ? this.branchLabelSizes : this.labelSizes).set(e, a(t));
|
|
1728
|
+
for (let [e, n] of [[this.labelSizes, this.narrowSizes], [this.branchLabelSizes, this.narrowBranchSizes]]) for (let r of t) {
|
|
1729
|
+
let t = n.get(r);
|
|
1730
|
+
t && t.w >= (e.get(r)?.w ?? 0) - 1 && n.delete(r);
|
|
1731
|
+
}
|
|
1732
|
+
n.replaceChildren();
|
|
1733
|
+
}
|
|
1734
|
+
createView(e, t) {
|
|
1735
|
+
let i = e.page, a = document.createElement("button");
|
|
1736
|
+
a.type = "button", a.className = "node", a.setAttribute("part", "node"), a.setAttribute("role", "treeitem"), a.setAttribute("aria-label", i.label), a.setAttribute("aria-level", String(e.depth)), a.setAttribute("aria-setsize", String(e.parent?.children.length ?? 1)), a.setAttribute("aria-posinset", String(e.index + 1)), i.description && a.setAttribute("aria-description", i.description), i.disabled && a.setAttribute("aria-disabled", "true"), e.children.length && (a.dataset.branch = ""), i.color && a.style.setProperty("--_node-accent", i.color), a.dataset.id = e.id;
|
|
1737
|
+
let o = document.createElement("span");
|
|
1738
|
+
o.className = "icon", o.setAttribute("part", "icon"), o.setAttribute("aria-hidden", "true"), o.append(n(i.icon, this.opts.iconResolver, i) ?? r(i.label)), a.append(o);
|
|
1739
|
+
let s = this.buildLabel(e);
|
|
1740
|
+
this.els.labels.append(s);
|
|
1741
|
+
let c = document.createElementNS(ge, "path");
|
|
1742
|
+
return c.setAttribute("class", "edge"), c.setAttribute("part", "edge"), c.setAttribute("pathLength", "1"), i.color && c.style.setProperty("--_lit", i.color), this.els.edges.append(c), {
|
|
1743
|
+
tree: e,
|
|
1744
|
+
node: a,
|
|
1745
|
+
label: s,
|
|
1746
|
+
edge: c,
|
|
1747
|
+
from: t.from,
|
|
1748
|
+
leaveTimer: 0,
|
|
1749
|
+
shownAt: null
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
animateIn(e) {
|
|
1753
|
+
let t = this.reducedMotion ? 0 : 22;
|
|
1754
|
+
for (let t of e) t.node.style.transition = "none", t.node.style.translate = `${t.from.x}px ${t.from.y}px`, t.node.dataset.enter = "";
|
|
1755
|
+
this.els.layer.offsetWidth, e.forEach((e, n) => {
|
|
1756
|
+
let r = this.placed.get(e.tree.id), i = n * t;
|
|
1757
|
+
e.node.style.transition = "", e.node.style.setProperty("--_delay", `${i}ms`), e.edge.style.setProperty("--_delay", `${i}ms`), e.label.style.setProperty("--_label-delay", `${i + this.duration * .6}ms`), e.node.style.translate = `${r.x}px ${r.y}px`, e.node.removeAttribute("data-enter"), e.edge.setAttribute("data-shown", "");
|
|
1758
|
+
let a = window.setTimeout(() => {
|
|
1759
|
+
this.animationTimers.delete(a), e.node.style.removeProperty("--_delay"), e.edge.style.removeProperty("--_delay"), e.label.style.removeProperty("--_label-delay");
|
|
1760
|
+
}, i + this.duration);
|
|
1761
|
+
this.animationTimers.add(a);
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
leave(e, t, n) {
|
|
1765
|
+
let { node: r, edge: i, label: a } = e;
|
|
1766
|
+
if (this.shadowRoot?.activeElement === r && this.state === "open") {
|
|
1767
|
+
let t = e.tree.parent ? this.views.get(e.tree.parent.id) : null;
|
|
1768
|
+
t && !t.leaveTimer ? (this.focusId = t.tree.id, t.node.tabIndex = 0, t.node.focus({ preventScroll: !0 })) : this.els.hub.focus({ preventScroll: !0 });
|
|
1769
|
+
}
|
|
1770
|
+
r.style.setProperty("--_delay", `${n}ms`), i.style.setProperty("--_delay", `${n}ms`), r.style.translate = `${t.x}px ${t.y}px`, r.setAttribute("data-leave", ""), r.removeAttribute("data-active"), r.setAttribute("part", "node node-leaving"), i.setAttribute("part", "edge"), a.setAttribute("part", "label"), r.tabIndex = -1, i.removeAttribute("data-shown"), a.removeAttribute("data-visible"), e.shownAt = null, e.leaveTimer = window.setTimeout(() => {
|
|
1771
|
+
r.remove(), a.remove(), i.remove(), this.views.delete(e.tree.id);
|
|
1772
|
+
}, n + this.duration * .7 + 40);
|
|
1773
|
+
}
|
|
1774
|
+
renderLabels() {
|
|
1775
|
+
let e = this.opts.labels, t = this.opts.nodeSize / 2, n = [...this.views.values()].filter((e) => !e.leaveTimer), r = /* @__PURE__ */ new Map();
|
|
1776
|
+
for (let e of n) {
|
|
1777
|
+
let n = this.placed.get(e.tree.id);
|
|
1778
|
+
r.set(e.tree.id, {
|
|
1779
|
+
x: n.x,
|
|
1780
|
+
y: n.y,
|
|
1781
|
+
r: t
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
let i = this.opts.edges === "none" ? [] : n.map((e) => this.placed.get(e.tree.id).edge), a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set(), c = this.labelPad, l = (e, t = i) => ({
|
|
1785
|
+
bounds: this.bounds,
|
|
1786
|
+
circles: [this.hub, ...r.values()],
|
|
1787
|
+
taken: [...a].filter(([t]) => t !== e).map(([, e]) => e),
|
|
1788
|
+
edges: t,
|
|
1789
|
+
pad: c
|
|
1790
|
+
}), u = (e, t = i) => {
|
|
1791
|
+
let n = l(e, t), a = this.active ? r.get(this.active) : null, o = r.get(e), s = n.circles.map((e) => e === a && e !== o ? {
|
|
1792
|
+
...e,
|
|
1793
|
+
r: e.r + c - 6
|
|
1794
|
+
} : e);
|
|
1795
|
+
return {
|
|
1796
|
+
...n,
|
|
1797
|
+
circles: s,
|
|
1798
|
+
pad: 6,
|
|
1799
|
+
ownPad: c
|
|
1800
|
+
};
|
|
1801
|
+
}, d = (e, t) => ![...a].some(([n, r]) => n !== t && p(e, r, 4)), f = (e, t, n) => {
|
|
1802
|
+
a.set(e, t), t.w < n.w - 1 ? o.add(e) : o.delete(e);
|
|
1803
|
+
}, m = (e, t) => !!e && !!t && e.w >= t.w - 1 && e.h >= t.h - 1;
|
|
1804
|
+
for (let e of n) Y(e.label, "data-go", this.mode === "tap" && e.node.dataset.state === "path" && !!e.tree.page.href), e.tree.id !== this.active && e.label.removeAttribute("data-active"), e.label.removeAttribute("data-compact"), e.label.removeAttribute("data-narrow");
|
|
1805
|
+
if (e === "auto" || e === "always") {
|
|
1806
|
+
let t = [...n].sort((e, t) => Number(t.node.dataset.state === "frontier") - Number(e.node.dataset.state === "frontier"));
|
|
1807
|
+
for (let n of t) {
|
|
1808
|
+
let t = n.tree.id, r = n.node.dataset.state, i = this.placed.get(t).label;
|
|
1809
|
+
(r === "frontier" || r === "dim" && e === "always") && i && d(i, t) && f(t, i, this.labelSizes.get(t) ?? i);
|
|
1810
|
+
}
|
|
1811
|
+
for (let e of n) {
|
|
1812
|
+
let t = e.tree.id;
|
|
1813
|
+
if (a.has(t) || t === this.active || e.node.dataset.state !== "frontier") continue;
|
|
1814
|
+
let n = this.placed.get(t), i = this.sizesOf(t, !1);
|
|
1815
|
+
if (!i) continue;
|
|
1816
|
+
let o = r.get(t), s = u(t), c = k(o, i, n.angle, s) ?? k(o, i, n.angle, {
|
|
1817
|
+
...s,
|
|
1818
|
+
edges: [n.edge]
|
|
1819
|
+
});
|
|
1820
|
+
c && f(t, c, this.labelSizes.get(t));
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
let h = this.active ? this.views.get(this.active) : null;
|
|
1824
|
+
if (h && !h.leaveTimer && e !== "none") {
|
|
1825
|
+
let e = h.tree.id, t = this.placed.get(e), n = r.get(e), i = h.label, o = h.node.dataset.state === "path", c = (r) => {
|
|
1826
|
+
let i = u(e);
|
|
1827
|
+
return k(n, r, t.angle, i) ?? k(n, r, t.angle, {
|
|
1828
|
+
...i,
|
|
1829
|
+
edges: [t.edge]
|
|
1830
|
+
}) ?? (o ? k(n, r, t.angle, {
|
|
1831
|
+
...i,
|
|
1832
|
+
edges: []
|
|
1833
|
+
}) : null);
|
|
1834
|
+
}, l = () => ({
|
|
1835
|
+
w: i.offsetWidth + 1,
|
|
1836
|
+
h: i.offsetHeight + 1
|
|
1837
|
+
});
|
|
1838
|
+
i.setAttribute("data-active", "");
|
|
1839
|
+
let p = l(), g = h.tree.page.description ? c(p) : null;
|
|
1840
|
+
if (!g) {
|
|
1841
|
+
s.add(e), i.setAttribute("data-compact", ""), p = l();
|
|
1842
|
+
let n = (o ? this.narrowBranchSizes.get(e) : null) ?? this.narrowSizes.get(e), r = n ? [p, n] : p, f = o ? t.pathLabel : t.label, h = a.get(e) ?? (f && d(f, e) ? f : null);
|
|
1843
|
+
if (g = h && (m(h, p) || m(h, n)) ? h : c(r), !g) {
|
|
1844
|
+
let t = u(e), n = Math.atan2(this.bounds.y + this.bounds.h / 2 - this.hub.y, this.bounds.x + this.bounds.w / 2 - this.hub.x);
|
|
1845
|
+
g = k(this.hub, r, n, t) ?? k(this.hub, r, n, {
|
|
1846
|
+
...t,
|
|
1847
|
+
edges: []
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
g ? f(e, g, p) : a.delete(e);
|
|
1852
|
+
}
|
|
1853
|
+
if (e === "auto" || e === "always") for (let e of this.path) {
|
|
1854
|
+
if (e === this.active || a.has(e)) continue;
|
|
1855
|
+
let t = this.views.get(e);
|
|
1856
|
+
if (!t || t.leaveTimer) continue;
|
|
1857
|
+
let n = this.placed.get(e), o = {
|
|
1858
|
+
w: t.label.offsetWidth + 1,
|
|
1859
|
+
h: t.label.offsetHeight + 1
|
|
1860
|
+
}, s = this.narrowBranchSizes.get(e) ?? this.narrowSizes.get(e), c = s ? [o, s] : o, l = n.pathLabel && (m(n.pathLabel, o) || m(n.pathLabel, s)) && d(n.pathLabel, e) ? n.pathLabel : null, p = r.get(e), h = [
|
|
1861
|
+
0,
|
|
1862
|
+
12,
|
|
1863
|
+
28,
|
|
1864
|
+
48
|
|
1865
|
+
], g = l ?? k(p, c, n.angle, {
|
|
1866
|
+
...u(e),
|
|
1867
|
+
rings: h
|
|
1868
|
+
}) ?? k(p, c, n.angle + Math.PI, {
|
|
1869
|
+
...u(e, i.filter((e) => e !== n.edge)),
|
|
1870
|
+
rings: h
|
|
1871
|
+
});
|
|
1872
|
+
g && f(e, g, o);
|
|
1873
|
+
}
|
|
1874
|
+
for (let e of this.views.values()) {
|
|
1875
|
+
let t = e.tree.id, n = e.leaveTimer ? null : a.get(t) ?? null, r = t === this.active && !!n;
|
|
1876
|
+
if (Y(e.label, "data-active", r), Y(e.label, "data-narrow", !!n && o.has(t)), s.has(t) || e.label.removeAttribute("data-compact"), X(e.label, "label", {
|
|
1877
|
+
active: r,
|
|
1878
|
+
path: e.node.dataset.state === "path"
|
|
1879
|
+
}), !n) {
|
|
1880
|
+
e.label.removeAttribute("data-visible"), e.shownAt = null;
|
|
1881
|
+
continue;
|
|
1882
|
+
}
|
|
1883
|
+
let i = e.shownAt && (Math.abs(e.shownAt.x - n.x) > 1 || Math.abs(e.shownAt.y - n.y) > 1);
|
|
1884
|
+
e.label.style.translate = `${n.x.toFixed(1)}px ${n.y.toFixed(1)}px`, e.label.setAttribute("data-visible", ""), i && !this.reducedMotion && e.label.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
1885
|
+
duration: 160,
|
|
1886
|
+
easing: "ease-out"
|
|
1887
|
+
}), e.shownAt = n;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
onPointerDown = (e) => {
|
|
1891
|
+
if (!e.isPrimary || e.pointerType === "mouse" && e.button !== 0 || this.state === "open") return;
|
|
1892
|
+
e.preventDefault();
|
|
1893
|
+
let { trigger: t } = this.els;
|
|
1894
|
+
try {
|
|
1895
|
+
t.setPointerCapture(e.pointerId);
|
|
1896
|
+
} catch {}
|
|
1897
|
+
this.pointerId = e.pointerId, this.pointerType = e.pointerType, this.downAt = this.lastPoint = {
|
|
1898
|
+
x: e.clientX,
|
|
1899
|
+
y: e.clientY
|
|
1900
|
+
}, this.leftHub = !1, t.setAttribute("data-pressing", ""), this.holdTimer = window.setTimeout(() => this.beginDrag(), this.opts.holdDelay);
|
|
1901
|
+
};
|
|
1902
|
+
beginDrag() {
|
|
1903
|
+
window.clearTimeout(this.holdTimer), this.holdTimer = 0, this.els.trigger.removeAttribute("data-pressing"), this.show("drag", "none");
|
|
1904
|
+
}
|
|
1905
|
+
onPointerMove = (e) => {
|
|
1906
|
+
if (e.pointerId !== this.pointerId) return;
|
|
1907
|
+
let t = this.lastPoint = {
|
|
1908
|
+
x: e.clientX,
|
|
1909
|
+
y: e.clientY
|
|
1910
|
+
};
|
|
1911
|
+
if (this.state !== "open") {
|
|
1912
|
+
if (this.holdTimer && Math.hypot(t.x - this.downAt.x, t.y - this.downAt.y) > 10) this.beginDrag();
|
|
1913
|
+
else return;
|
|
1914
|
+
}
|
|
1915
|
+
this.mode === "drag" && this.dragTo(t);
|
|
1916
|
+
};
|
|
1917
|
+
onPointerUp = (e) => {
|
|
1918
|
+
if (e.pointerId !== this.pointerId) return;
|
|
1919
|
+
this.pointerId = null, this.lastPointerUp = performance.now();
|
|
1920
|
+
let t = this.holdTimer !== 0;
|
|
1921
|
+
if (window.clearTimeout(this.holdTimer), this.holdTimer = 0, this.els.trigger.removeAttribute("data-pressing"), this.state !== "open") {
|
|
1922
|
+
t && this.opts.openOnTap && this.show("tap", "pointer");
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
this.mode === "drag" && this.release({
|
|
1926
|
+
x: e.clientX,
|
|
1927
|
+
y: e.clientY
|
|
1928
|
+
});
|
|
1929
|
+
};
|
|
1930
|
+
onPointerCancel = (e) => {
|
|
1931
|
+
e.pointerId === this.pointerId && (this.pointerId = null, window.clearTimeout(this.holdTimer), this.holdTimer = 0, this.els.trigger.removeAttribute("data-pressing"), this.state === "open" && this.mode === "drag" && this.close());
|
|
1932
|
+
};
|
|
1933
|
+
onLostCapture = (e) => {
|
|
1934
|
+
e.pointerId === this.pointerId && (this.pointerId = null, window.clearTimeout(this.holdTimer), this.holdTimer = 0, this.els.trigger.removeAttribute("data-pressing"), this.state === "open" && this.mode === "drag" && this.release(this.lastPoint));
|
|
1935
|
+
};
|
|
1936
|
+
onTriggerClick = (e) => {
|
|
1937
|
+
performance.now() - this.lastPointerUp < 700 || (this.state === "open" ? this.close({ focusTrigger: !0 }) : this.show("tap", e.detail === 0 ? "keyboard" : "pointer"));
|
|
1938
|
+
};
|
|
1939
|
+
onTriggerKey = (e) => {
|
|
1940
|
+
this.state === "closed" && (e.key === "ArrowUp" || e.key === "ArrowDown") && (e.preventDefault(), this.show("tap", "keyboard"));
|
|
1941
|
+
};
|
|
1942
|
+
hitAt(e) {
|
|
1943
|
+
let t = [], n = [], r = this.opts.nodeSize / 2;
|
|
1944
|
+
for (let [e, i] of this.placed) {
|
|
1945
|
+
let a = this.views.get(e);
|
|
1946
|
+
a && !a.leaveTimer && (t.push(e), n.push({
|
|
1947
|
+
x: i.x,
|
|
1948
|
+
y: i.y,
|
|
1949
|
+
r
|
|
1950
|
+
}));
|
|
1951
|
+
}
|
|
1952
|
+
t.push("hub"), n.push(this.hub);
|
|
1953
|
+
let i = se(e, n, this.pointerType === "mouse" ? 6 : 14);
|
|
1954
|
+
if (i >= 0) return t[i];
|
|
1955
|
+
for (let t of this.views.values()) if (!t.leaveTimer && t.shownAt && m(t.shownAt, e)) return t.tree.id;
|
|
1956
|
+
return null;
|
|
1957
|
+
}
|
|
1958
|
+
dragTo(e) {
|
|
1959
|
+
let t = this.hitAt(e);
|
|
1960
|
+
t === "hub" ? (this.setActive(null), this.dwell(this.leftHub && this.path.length ? "hub" : null)) : t ? (this.leftHub = !0, this.setActive(t), this.dwell(t)) : (Math.hypot(e.x - this.hub.x, e.y - this.hub.y) > this.hub.r + 6 && (this.leftHub = !0), this.setActive(null), this.dwellTarget && this.dwellTarget !== "hub" && this.isBeyond(e, this.dwellTarget) || this.dwell(null)), Y(this.els.hub, "data-active", this.dwellTarget === "hub");
|
|
1961
|
+
}
|
|
1962
|
+
isBeyond(e, t) {
|
|
1963
|
+
let n = this.placed.get(t);
|
|
1964
|
+
if (!n || !this.tree.byId.get(t)?.children.length) return !1;
|
|
1965
|
+
let r = n.x - n.from.x, i = n.y - n.from.y, a = Math.hypot(r, i) || 1, o = r / a, s = i / a, c = e.x - n.from.x, l = e.y - n.from.y, u = c * o + l * s, d = Math.abs(c * s - l * o);
|
|
1966
|
+
return u > a && u < a + this.opts.spacing * 1.2 && d < this.opts.spacing * .55;
|
|
1967
|
+
}
|
|
1968
|
+
dwell(e) {
|
|
1969
|
+
e !== this.dwellTarget && (window.clearTimeout(this.dwellTimer), this.dwellTimer = 0, this.dwellTarget = e, e && (this.dwellTimer = window.setTimeout(() => {
|
|
1970
|
+
if (this.dwellTimer = 0, e === "hub") return this.setPath([]);
|
|
1971
|
+
let t = this.tree.byId.get(e);
|
|
1972
|
+
t && !t.page.disabled && this.setPath(V(t.children.length ? t : t.parent));
|
|
1973
|
+
}, this.opts.expandDelay)));
|
|
1974
|
+
}
|
|
1975
|
+
release(e) {
|
|
1976
|
+
window.clearTimeout(this.dwellTimer), this.dwellTimer = 0, this.dwellTarget = null;
|
|
1977
|
+
let t = this.hitAt(e);
|
|
1978
|
+
if (t && t !== "hub") {
|
|
1979
|
+
let e = this.tree.byId.get(t);
|
|
1980
|
+
if (!e.page.disabled) {
|
|
1981
|
+
if (e.page.href || !e.children.length) return this.select(e, "release");
|
|
1982
|
+
this.path = V(e);
|
|
1983
|
+
}
|
|
1984
|
+
return this.toTapMode(t);
|
|
1985
|
+
}
|
|
1986
|
+
if (!this.leftHub) return this.toTapMode(null);
|
|
1987
|
+
this.close();
|
|
1988
|
+
}
|
|
1989
|
+
toTapMode(e) {
|
|
1990
|
+
this.mode = "tap", this.els.overlay.dataset.mode = "tap", window.removeEventListener("keydown", this.onWindowKey, !0), this.present(!0), this.render();
|
|
1991
|
+
let t = e ?? this.initialFocusId();
|
|
1992
|
+
t && this.focusNode(t, !1);
|
|
1993
|
+
}
|
|
1994
|
+
onOverlayHover = (e) => {
|
|
1995
|
+
if (this.state !== "open" || this.mode !== "tap" || e.pointerType !== "mouse") return;
|
|
1996
|
+
let t = this.hitAt({
|
|
1997
|
+
x: e.clientX,
|
|
1998
|
+
y: e.clientY
|
|
1999
|
+
});
|
|
2000
|
+
this.setActive(t === "hub" ? null : t);
|
|
2001
|
+
};
|
|
2002
|
+
onOverlayClick = (e) => {
|
|
2003
|
+
if (this.state !== "open" || this.mode !== "tap") return;
|
|
2004
|
+
let t = performance.now();
|
|
2005
|
+
if (t - this.openedAt < 250 || e.detail === 0 && t - this.lastKeyActivation < 500) return;
|
|
2006
|
+
let n = e.target;
|
|
2007
|
+
if (n.closest(".hub")) return this.hubAction(e.detail === 0);
|
|
2008
|
+
let r = n.closest(".node")?.dataset.id ?? null;
|
|
2009
|
+
if (!r && e.detail !== 0) {
|
|
2010
|
+
let t = this.hitAt({
|
|
2011
|
+
x: e.clientX,
|
|
2012
|
+
y: e.clientY
|
|
2013
|
+
});
|
|
2014
|
+
r = t === "hub" ? null : t;
|
|
2015
|
+
}
|
|
2016
|
+
let i = r ? this.tree.byId.get(r) : null;
|
|
2017
|
+
if (!i) return this.close();
|
|
2018
|
+
let a = e.detail === 0 ? "keyboard" : "click";
|
|
2019
|
+
this.focusNode(i.id, a === "keyboard"), this.activate(i, a, e.metaKey || e.ctrlKey || e.button === 1);
|
|
2020
|
+
};
|
|
2021
|
+
hubAction(e) {
|
|
2022
|
+
this.path.length ? this.goUp(e) : this.close({ focusTrigger: !0 });
|
|
2023
|
+
}
|
|
2024
|
+
onOverlayKey = (e) => {
|
|
2025
|
+
if (this.state !== "open") return;
|
|
2026
|
+
let t = e.key;
|
|
2027
|
+
if (t === "Escape") {
|
|
2028
|
+
e.preventDefault(), this.close({ focusTrigger: !0 });
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
2031
|
+
if (this.mode !== "tap") return;
|
|
2032
|
+
let n = e.composedPath()[0], r = n instanceof Element ? n.closest(".node") : null;
|
|
2033
|
+
if (!r) {
|
|
2034
|
+
if (n === this.els.hub) return;
|
|
2035
|
+
if (t in J || t === "Home" || t === "End") {
|
|
2036
|
+
e.preventDefault();
|
|
2037
|
+
let t = this.focusId && this.placed.has(this.focusId) ? this.focusId : this.initialFocusId();
|
|
2038
|
+
t && this.focusNode(t);
|
|
2039
|
+
}
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
let i = this.tree.byId.get(r.dataset.id);
|
|
2043
|
+
if (i) {
|
|
2044
|
+
if (this.focusId !== i.id && (this.focusId = i.id), t === "Enter" || t === " ") return e.preventDefault(), this.lastKeyActivation = performance.now(), this.activateKey(i, e.metaKey || e.ctrlKey);
|
|
2045
|
+
if (t === "Backspace") return e.preventDefault(), this.stepBack(i);
|
|
2046
|
+
if (this.opts.arrowKeys === "spatial" ? this.spatialKey(i, t) : this.treeKey(i, t)) {
|
|
2047
|
+
e.preventDefault();
|
|
2048
|
+
return;
|
|
2049
|
+
}
|
|
2050
|
+
t.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey && t !== " " && this.typeAhead(i, t);
|
|
2051
|
+
}
|
|
2052
|
+
};
|
|
2053
|
+
visibleOrder() {
|
|
2054
|
+
let e = [], t = (n) => {
|
|
2055
|
+
for (let r of n) e.push(r.id), this.path.includes(r.id) && t(r.children);
|
|
2056
|
+
};
|
|
2057
|
+
return t(this.tree.root.children), e;
|
|
2058
|
+
}
|
|
2059
|
+
treeKey(e, t) {
|
|
2060
|
+
let n = getComputedStyle(this).direction === "rtl", r = this.visibleOrder(), i = r.indexOf(e.id), a = this.path.includes(e.id);
|
|
2061
|
+
if (t === "ArrowDown") i < r.length - 1 && this.focusNode(r[i + 1]);
|
|
2062
|
+
else if (t === "ArrowUp") i > 0 && this.focusNode(r[i - 1]);
|
|
2063
|
+
else if (t === (n ? "ArrowLeft" : "ArrowRight")) e.children.length && !e.page.disabled && (a ? this.focusNode(e.children[0].id) : (this.path = V(e), this.haptic(6), this.focusNode(e.id)));
|
|
2064
|
+
else if (t === (n ? "ArrowRight" : "ArrowLeft")) a ? (this.path = V(e.parent), this.focusNode(e.id)) : e.parent && e.parent.depth > 0 && this.focusNode(e.parent.id);
|
|
2065
|
+
else if (t === "Home") this.focusNode(r[0]);
|
|
2066
|
+
else if (t === "End") this.focusNode(r[r.length - 1]);
|
|
2067
|
+
else return !1;
|
|
2068
|
+
return !0;
|
|
2069
|
+
}
|
|
2070
|
+
spatialKey(e, t) {
|
|
2071
|
+
if (t in J) {
|
|
2072
|
+
let n = this.placed.get(e.id);
|
|
2073
|
+
if (!n) return !0;
|
|
2074
|
+
let r = J[t], i = null, a = Infinity;
|
|
2075
|
+
for (let [t, o] of this.placed) {
|
|
2076
|
+
if (t === e.id || this.views.get(t)?.leaveTimer) continue;
|
|
2077
|
+
let s = o.x - n.x, c = o.y - n.y, l = s * r.x + c * r.y;
|
|
2078
|
+
if (l <= 1) continue;
|
|
2079
|
+
let u = Math.abs(s * r.y - c * r.x);
|
|
2080
|
+
if (u > l * 2.2) continue;
|
|
2081
|
+
let d = l + u * 2;
|
|
2082
|
+
d < a && (a = d, i = t);
|
|
2083
|
+
}
|
|
2084
|
+
return i && this.focusNode(i), !0;
|
|
2085
|
+
}
|
|
2086
|
+
if (t === "Home" || t === "End") {
|
|
2087
|
+
let n = e.parent?.children ?? [], r = t === "Home" ? n[0] : n[n.length - 1];
|
|
2088
|
+
return r && this.focusNode(r.id), !0;
|
|
2089
|
+
}
|
|
2090
|
+
return !1;
|
|
2091
|
+
}
|
|
2092
|
+
activateKey(e, t) {
|
|
2093
|
+
if (!e.page.disabled) {
|
|
2094
|
+
if (this.opts.arrowKeys === "spatial") return this.activate(e, "keyboard", t);
|
|
2095
|
+
if (e.page.href || !e.children.length) return this.select(e, "keyboard", t);
|
|
2096
|
+
this.path = this.path.includes(e.id) ? V(e.parent) : V(e), this.haptic(6), this.focusNode(e.id);
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
stepBack(e) {
|
|
2100
|
+
e.parent && e.parent.depth > 0 ? (this.path = V(e.parent.parent), this.focusNode(e.parent.id)) : this.path.length && (this.path = [], this.focusNode(e.id));
|
|
2101
|
+
}
|
|
2102
|
+
typeAhead(e, t) {
|
|
2103
|
+
let n = performance.now();
|
|
2104
|
+
this.typeahead.text = n - this.typeahead.at < 700 ? this.typeahead.text + t.toLowerCase() : t.toLowerCase(), this.typeahead.at = n;
|
|
2105
|
+
let r = this.opts.arrowKeys === "spatial" ? (e.parent?.children ?? []).map((e) => e.id) : this.visibleOrder(), i = this.typeahead.text, a = r.indexOf(e.id), o = i.length === 1 ? a + 1 : a;
|
|
2106
|
+
for (let e = 0; e < r.length; e++) {
|
|
2107
|
+
let t = r[(o + e) % r.length];
|
|
2108
|
+
if (this.tree.byId.get(t).page.label.toLowerCase().startsWith(i)) return this.focusNode(t);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
goUp(e) {
|
|
2112
|
+
let t = this.path[this.path.length - 1];
|
|
2113
|
+
this.path = this.path.slice(0, -1), t ? this.focusNode(t, e) : this.render();
|
|
2114
|
+
}
|
|
2115
|
+
focusNode(e, t = !0) {
|
|
2116
|
+
this.focusId = e, t && (this.active = e), this.render(), this.views.get(e)?.node.focus({ preventScroll: !0 }), t && this.emitHighlight();
|
|
2117
|
+
}
|
|
2118
|
+
activate(e, t, n = !1) {
|
|
2119
|
+
if (e.page.disabled) return;
|
|
2120
|
+
if (n && e.page.href) return this.select(e, t, !0);
|
|
2121
|
+
let r = this.path.includes(e.id);
|
|
2122
|
+
if (e.children.length && !r) {
|
|
2123
|
+
this.path = V(e), this.haptic(6), t === "keyboard" ? this.focusNode(e.children[0].id) : (this.active = e.id, this.render());
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2126
|
+
if (e.children.length && !e.page.href) {
|
|
2127
|
+
this.path = V(e.parent), t === "keyboard" ? this.focusNode(e.id) : this.render();
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
this.select(e, t, n);
|
|
2131
|
+
}
|
|
2132
|
+
select(e, t, n = !1) {
|
|
2133
|
+
let r = {
|
|
2134
|
+
page: e.page,
|
|
2135
|
+
trail: V(e).map((e) => this.tree.byId.get(e).page),
|
|
2136
|
+
via: t
|
|
2137
|
+
}, i = this.emit("unfold-select", r, !0);
|
|
2138
|
+
if (this.haptic(12), this.close({ focusTrigger: t === "keyboard" }), !i) return;
|
|
2139
|
+
let { href: a, target: o } = e.page;
|
|
2140
|
+
if (this.opts.navigate && !(a && (n || o && o !== "_self"))) {
|
|
2141
|
+
this.opts.navigate(e.page, r);
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
if (!a) return;
|
|
2145
|
+
let s = me(a, document.baseURI);
|
|
2146
|
+
if (!s) {
|
|
2147
|
+
console.warn("[unfold-nav] Refusing an unsupported navigation URL:", a);
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2150
|
+
n || o && o !== "_self" ? window.open(s, n ? "_blank" : o, "noopener") : location.assign(s);
|
|
2151
|
+
}
|
|
2152
|
+
setActive(e) {
|
|
2153
|
+
e !== this.active && (this.active = e, e && this.mode === "drag" && this.haptic(4), this.render(), this.emitHighlight());
|
|
2154
|
+
}
|
|
2155
|
+
setPath(e) {
|
|
2156
|
+
e.length === this.path.length && e.every((e, t) => e === this.path[t]) || (this.path = e, this.haptic(6), this.render());
|
|
2157
|
+
}
|
|
2158
|
+
emit(e, t, n = !1) {
|
|
2159
|
+
return this.dispatchEvent(new CustomEvent(e, {
|
|
2160
|
+
detail: t,
|
|
2161
|
+
bubbles: !0,
|
|
2162
|
+
composed: !0,
|
|
2163
|
+
cancelable: n
|
|
2164
|
+
}));
|
|
2165
|
+
}
|
|
2166
|
+
emitHighlight() {
|
|
2167
|
+
let e = this.active ? this.tree.byId.get(this.active)?.page ?? null : null;
|
|
2168
|
+
this.emit("unfold-highlight", { page: e });
|
|
2169
|
+
}
|
|
2170
|
+
haptic(e) {
|
|
2171
|
+
if (this.opts.haptics) try {
|
|
2172
|
+
navigator.vibrate?.(e);
|
|
2173
|
+
} catch {}
|
|
2174
|
+
}
|
|
2175
|
+
get reducedMotion() {
|
|
2176
|
+
return matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
2177
|
+
}
|
|
2178
|
+
get duration() {
|
|
2179
|
+
let e = getComputedStyle(this.els.root).getPropertyValue("--_dur").trim(), t = parseFloat(e);
|
|
2180
|
+
return Number.isFinite(t) ? e.endsWith("ms") ? t : e.endsWith("s") ? t * 1e3 : t : 340;
|
|
2181
|
+
}
|
|
2182
|
+
};
|
|
2183
|
+
if (typeof HTMLElement < "u") for (let e of G) Object.defineProperty(Z.prototype, e, {
|
|
2184
|
+
configurable: !0,
|
|
2185
|
+
enumerable: !0,
|
|
2186
|
+
get() {
|
|
2187
|
+
return this.opts[e];
|
|
2188
|
+
},
|
|
2189
|
+
set(t) {
|
|
2190
|
+
this.configure({ [e]: t });
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
//#endregion
|
|
2194
|
+
//#region src/index.ts
|
|
2195
|
+
var Q = "unfold-nav";
|
|
2196
|
+
function $(e = Q) {
|
|
2197
|
+
typeof customElements > "u" || customElements.get(e) || customElements.define(e, e === "unfold-nav" ? Z : class extends Z {});
|
|
2198
|
+
}
|
|
2199
|
+
$();
|
|
2200
|
+
function ye(e, t) {
|
|
2201
|
+
if (typeof document > "u") throw Error("[unfold-nav] Call createUnfoldNav in a browser after mounting.");
|
|
2202
|
+
let n = t ?? document.body;
|
|
2203
|
+
if (!n) throw Error("[unfold-nav] Wait for document.body or provide a container.");
|
|
2204
|
+
$();
|
|
2205
|
+
let r = document.createElement(Q);
|
|
2206
|
+
return r.configure(e), n.append(r), r;
|
|
2207
|
+
}
|
|
2208
|
+
//#endregion
|
|
2209
|
+
export { R as DEFAULT_OPTIONS, L as DEFAULT_STRINGS, Q as TAG, Z as UnfoldNav, B as buildTree, ye as createUnfoldNav, $ as define, U as findCurrent, F as layoutGraph, P as placeFan, k as placeLabel };
|
|
2210
|
+
|
|
2211
|
+
//# sourceMappingURL=unfold-nav.js.map
|