@alekstar79/context-menu 2.0.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.
@@ -0,0 +1,709 @@
1
+ const I = {
2
+ sectors: [],
3
+ sprite: "../icons.svg",
4
+ innerRadius: 50,
5
+ outerRadius: 150,
6
+ opacity: 0.7
7
+ };
8
+ function J(o) {
9
+ return { ...I, ...o };
10
+ }
11
+ const A = /* @__PURE__ */ new Map();
12
+ function H(o) {
13
+ if (A.has(o))
14
+ return A.get(o);
15
+ const e = document.createElement("canvas").getContext("2d");
16
+ if (!e) {
17
+ const c = { ascent: 9, descent: 3, height: 12 };
18
+ return A.set(o, c), c;
19
+ }
20
+ e.font = o;
21
+ const s = e.measureText("A"), i = s.actualBoundingBoxAscent ?? 9, n = s.actualBoundingBoxDescent ?? 3, r = i + n, a = { ascent: i, descent: n, height: r };
22
+ return A.set(o, a), a;
23
+ }
24
+ let R = null;
25
+ function N() {
26
+ if (R) return R;
27
+ const o = document.createElement("div");
28
+ o.className = "radial-hint", o.style.position = "absolute", o.style.visibility = "hidden", o.style.pointerEvents = "none", o.textContent = "A", document.body.appendChild(o);
29
+ const t = window.getComputedStyle(o), e = `${t.fontWeight} ${t.fontSize} ${t.fontFamily}`;
30
+ document.body.removeChild(o);
31
+ const s = H(e);
32
+ return R = s, s;
33
+ }
34
+ function q(o) {
35
+ const t = "http://www.w3.org/2000/svg", e = document.createElementNS(t, "svg");
36
+ e.style.position = "absolute", e.style.visibility = "hidden", document.body.appendChild(e);
37
+ const s = document.createElementNS(t, "text");
38
+ s.textContent = o, e.appendChild(s);
39
+ const i = s.getComputedTextLength();
40
+ return document.body.removeChild(e), i;
41
+ }
42
+ const D = (o) => o % 360 * Math.PI / 180, T = /,?([a-z]),?/gi;
43
+ function O() {
44
+ return this.join(",").replace(T, "$1");
45
+ }
46
+ const z = (o) => {
47
+ if (!o) return null;
48
+ let t = [];
49
+ return Array.isArray(o) && Array.isArray(o[0]) && (t = o.map((e) => [...e])), t.length || String(o).replace(/([rstm])\s*,?\s*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig, (e, s, i) => {
50
+ const n = [];
51
+ return i.replace(/(-?\d*\.?\d*(?:e[\-+]?\d+)?)\s*,?\s*/ig, (r, a) => (a && n.push(+a), "")), t.push([s, ...n]), "";
52
+ }), t.toString = O, t;
53
+ }, _ = (o) => {
54
+ const t = z(o), e = new C();
55
+ if (t)
56
+ for (let s = 0, i = t.length; s < i; s++) {
57
+ const n = t[s];
58
+ switch (n[0].toLowerCase()) {
59
+ case "t":
60
+ e.translate(n[1], n[2] || 0);
61
+ break;
62
+ case "r":
63
+ e.rotate(n[1], n[2] || 0, n[3] || 0);
64
+ break;
65
+ case "s":
66
+ e.scale(n[1] || 1, n[2] || n[1] || 1, n[3] || 0, n[4] || 0);
67
+ break;
68
+ case "m":
69
+ e.add(n[1] || 1, n[2] || 0, n[3] || 0, n[4] || 1, n[5] || 0, n[6] || 0);
70
+ break;
71
+ }
72
+ }
73
+ return e;
74
+ }, G = { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
75
+ class C {
76
+ a;
77
+ b;
78
+ c;
79
+ d;
80
+ e;
81
+ f;
82
+ /**
83
+ * Creates a new matrix.
84
+ * If no arguments are given, creates an identity matrix.
85
+ * If an object with a,b,c,d,e,f properties is provided (e.g., SVGMatrix), copies its values.
86
+ */
87
+ constructor(t, e, s, i, n, r) {
88
+ if (t instanceof SVGMatrix) {
89
+ Object.assign(this, t);
90
+ return;
91
+ }
92
+ t != null ? Object.assign(this, { a: +t, b: +e, c: +s, d: +i, e: +n, f: +r }) : Object.assign(this, G);
93
+ }
94
+ /**
95
+ * Multiplies current matrix by another matrix.
96
+ */
97
+ add(t, e, s, i, n, r) {
98
+ if (t instanceof C)
99
+ return this.add(t.a, t.b, t.c, t.d, t.e, t.f);
100
+ const a = t * this.a + e * this.c, c = t * this.b + e * this.d;
101
+ return this.e += n * this.a + r * this.c, this.f += n * this.b + r * this.d, this.c = s * this.a + i * this.c, this.d = s * this.b + i * this.d, this.a = a, this.b = c, this;
102
+ }
103
+ /**
104
+ * Returns inverse matrix.
105
+ */
106
+ invert() {
107
+ const t = this.a * this.d - this.b * this.c;
108
+ return new C(
109
+ this.d / t,
110
+ -this.b / t,
111
+ -this.c / t,
112
+ this.a / t,
113
+ (this.c * this.f - this.d * this.e) / t,
114
+ (this.b * this.e - this.a * this.f) / t
115
+ );
116
+ }
117
+ /**
118
+ * Returns a copy of the matrix.
119
+ */
120
+ clone() {
121
+ return new C(this.a, this.b, this.c, this.d, this.e, this.f);
122
+ }
123
+ /**
124
+ * Translates the matrix by x and y.
125
+ */
126
+ translate(t, e = 0) {
127
+ return this.add(1, 0, 0, 1, t, e);
128
+ }
129
+ /**
130
+ * Scales the matrix by x and y, optionally about point (cx, cy).
131
+ */
132
+ scale(t, e = t, s, i) {
133
+ return (s != null || i != null) && this.translate(s, i), this.a *= t, this.b *= t, this.c *= e, this.d *= e, (s != null || i != null) && this.translate(-s, -i), this;
134
+ }
135
+ /**
136
+ * Rotates the matrix by angle (degrees) about point (x, y).
137
+ */
138
+ rotate(t, e = 0, s = 0) {
139
+ t = D(t);
140
+ const i = +Math.cos(t).toFixed(9), n = +Math.sin(t).toFixed(9);
141
+ return this.add(i, n, -n, i, e, s), this.add(1, 0, 0, 1, -e, -s);
142
+ }
143
+ /**
144
+ * Applies matrix to point (x, y) and returns resulting x.
145
+ */
146
+ x(t, e) {
147
+ return t * this.a + e * this.c + this.e;
148
+ }
149
+ /**
150
+ * Applies matrix to point (x, y) and returns resulting y.
151
+ */
152
+ y(t, e) {
153
+ return t * this.b + e * this.d + this.f;
154
+ }
155
+ /**
156
+ * Returns matrix as an SVG matrix string.
157
+ */
158
+ toString() {
159
+ return `matrix(${this.a},${this.b},${this.c},${this.d},${this.e},${this.f})`;
160
+ }
161
+ }
162
+ const b = {
163
+ linear: (o) => o,
164
+ easeinout: (o) => {
165
+ if (o === 1) return 1;
166
+ if (o === 0) return 0;
167
+ const t = 0.48 - o / 1.04, e = Math.sqrt(0.1734 + t * t), s = e - t, i = Math.pow(Math.abs(s), 1 / 3) * (s < 0 ? -1 : 1), n = -e - t, r = Math.pow(Math.abs(n), 1 / 3) * (n < 0 ? -1 : 1), a = i + r + 0.5;
168
+ return (1 - a) * 3 * a * a + a * a * a;
169
+ },
170
+ elastic: (o) => o === 0 || o === 1 ? o : Math.pow(2, -10 * o) * Math.sin((o - 0.075) * (2 * Math.PI) / 0.3) + 1
171
+ };
172
+ function P(o, t, e, s, i = b.linear, n) {
173
+ const r = performance.now();
174
+ let a = !1, c = 0;
175
+ const l = (h) => {
176
+ if (a) return;
177
+ const p = h - r, u = Math.min(p / s, 1), d = i(u);
178
+ if (Array.isArray(o) && Array.isArray(t)) {
179
+ const m = o.map((y, w) => y + (t[w] - y) * d);
180
+ e(m);
181
+ } else {
182
+ const m = o + (t - o) * d;
183
+ e(m);
184
+ }
185
+ u < 1 ? c = requestAnimationFrame(l) : n?.();
186
+ };
187
+ return c = requestAnimationFrame(l), {
188
+ stop: () => {
189
+ a = !0, cancelAnimationFrame(c);
190
+ }
191
+ };
192
+ }
193
+ let W = 0;
194
+ const $ = /* @__PURE__ */ new WeakMap();
195
+ function x(o, t) {
196
+ if ($.has(o)) {
197
+ const s = $.get(o);
198
+ return t && !s.paper && (s.paper = t), s;
199
+ }
200
+ const e = new B(o, t);
201
+ return $.set(o, e), e;
202
+ }
203
+ class B {
204
+ node;
205
+ paper;
206
+ _id;
207
+ constructor(t, e) {
208
+ this.node = t, this.paper = e, this._id = "e" + (W++).toString(36);
209
+ }
210
+ get type() {
211
+ return this.node.tagName;
212
+ }
213
+ get id() {
214
+ return this.node.id || this._id;
215
+ }
216
+ parent() {
217
+ return this.node.parentNode ? x(this.node.parentNode, this.paper) : null;
218
+ }
219
+ children() {
220
+ return Array.from(this.node.children).map((t) => x(t, this.paper));
221
+ }
222
+ clear() {
223
+ for (; this.node.firstChild; )
224
+ this.node.removeChild(this.node.firstChild);
225
+ return this;
226
+ }
227
+ attr(t, e) {
228
+ if (typeof t == "string")
229
+ return e === void 0 ? this.node.getAttribute(t) : (this._setAttr(t, e), this);
230
+ if (typeof t == "object") {
231
+ for (const s in t)
232
+ this._setAttr(s, t[s]);
233
+ return this;
234
+ }
235
+ return this;
236
+ }
237
+ _setAttr(t, e) {
238
+ t === "textpath" ? this._setTextPath(e) : t === "text" ? this._setText(e) : this.node.setAttribute(t, String(e));
239
+ }
240
+ _setText(t) {
241
+ const e = this.node.querySelector("textPath");
242
+ e ? e.textContent = t : this.node.textContent = t;
243
+ }
244
+ _setTextPath(t) {
245
+ if (this.node.tagName !== "text") return;
246
+ const e = this.node;
247
+ let s = e.querySelector("textPath"), i = "";
248
+ if (s)
249
+ i = s.textContent || "";
250
+ else {
251
+ for (let r = 0; r < e.childNodes.length; r++) {
252
+ const a = e.childNodes[r];
253
+ a.nodeType === 3 && (i += a.textContent);
254
+ }
255
+ for (; e.firstChild; )
256
+ e.removeChild(e.firstChild);
257
+ s = document.createElementNS("http://www.w3.org/2000/svg", "textPath"), e.appendChild(s), e.removeAttribute("x"), e.removeAttribute("y");
258
+ }
259
+ let n;
260
+ if (t.startsWith("#"))
261
+ n = t;
262
+ else {
263
+ if (!this.paper)
264
+ throw new Error("No paper reference for creating defs");
265
+ const r = this.paper.defs, a = "p" + Date.now() + Math.random().toString(36).slice(2), c = document.createElementNS("http://www.w3.org/2000/svg", "path");
266
+ c.setAttribute("d", t), c.id = a, r.node.appendChild(c), n = "#" + a;
267
+ }
268
+ s.setAttributeNS("http://www.w3.org/1999/xlink", "href", n), i && (s.textContent = i);
269
+ }
270
+ addClass(t) {
271
+ const e = t.trim().split(/\s+/);
272
+ for (const s of e)
273
+ s && this.node.classList.add(s);
274
+ return this;
275
+ }
276
+ removeClass(t) {
277
+ const e = t.trim().split(/\s+/);
278
+ for (const s of e)
279
+ s && this.node.classList.remove(s);
280
+ return this;
281
+ }
282
+ transform(t) {
283
+ if (t === void 0) return this;
284
+ if (t instanceof C)
285
+ this.node.setAttribute("transform", t.toString());
286
+ else {
287
+ const e = _(t);
288
+ this.node.setAttribute("transform", e.toString());
289
+ }
290
+ return this;
291
+ }
292
+ getBBox() {
293
+ if (this.node.isConnected) {
294
+ const i = this.node.getBBox();
295
+ return {
296
+ x: i.x,
297
+ y: i.y,
298
+ width: i.width,
299
+ height: i.height,
300
+ cx: i.x + i.width / 2,
301
+ cy: i.y + i.height / 2,
302
+ x2: i.x + i.width,
303
+ y2: i.y + i.height
304
+ };
305
+ }
306
+ const e = document.createElementNS("http://www.w3.org/2000/svg", "svg");
307
+ e.style.position = "absolute", e.style.visibility = "hidden", e.style.pointerEvents = "none", document.body.appendChild(e), e.appendChild(this.node);
308
+ const s = this.node.getBBox();
309
+ return e.removeChild(this.node), document.body.removeChild(e), {
310
+ x: s.x,
311
+ y: s.y,
312
+ width: s.width,
313
+ height: s.height,
314
+ cx: s.x + s.width / 2,
315
+ cy: s.y + s.height / 2,
316
+ x2: s.x + s.width,
317
+ y2: s.y + s.height
318
+ };
319
+ }
320
+ select(t) {
321
+ const e = this.node.querySelector(t);
322
+ return e ? x(e, this.paper) : null;
323
+ }
324
+ selectAll(t) {
325
+ const e = this.node.querySelectorAll(t);
326
+ return Array.from(e).map((s) => x(s, this.paper));
327
+ }
328
+ clone() {
329
+ return x(this.node.cloneNode(!0), this.paper);
330
+ }
331
+ add(t) {
332
+ return this.node.appendChild(t.node), this;
333
+ }
334
+ hover(t, e) {
335
+ return this.node.addEventListener("mouseover", t), this.node.addEventListener("mouseout", e), this;
336
+ }
337
+ mouseup(t) {
338
+ return this.node.addEventListener("mouseup", t), this;
339
+ }
340
+ }
341
+ class k extends B {
342
+ defs;
343
+ constructor(t) {
344
+ super(t, null), this.paper = this, $.set(t, this);
345
+ let e = t.querySelector("defs");
346
+ e || (e = document.createElementNS("http://www.w3.org/2000/svg", "defs"), t.appendChild(e)), this.defs = x(e, this);
347
+ }
348
+ g(...t) {
349
+ const e = document.createElementNS("http://www.w3.org/2000/svg", "g");
350
+ this.node.appendChild(e);
351
+ const s = x(e, this);
352
+ return t.length === 1 && t[0] && !t[0].node ? s.attr(t[0]) : t.length && t.forEach((i) => {
353
+ i instanceof B && s.add(i);
354
+ }), s;
355
+ }
356
+ path(t) {
357
+ const e = document.createElementNS("http://www.w3.org/2000/svg", "path");
358
+ this.node.appendChild(e);
359
+ const s = x(e, this);
360
+ return t && (typeof t == "string" ? s.attr("d", t) : s.attr(t)), s;
361
+ }
362
+ circle(t, e, s) {
363
+ const i = document.createElementNS("http://www.w3.org/2000/svg", "circle");
364
+ this.node.appendChild(i);
365
+ const n = x(i, this);
366
+ return typeof t == "object" ? n.attr(t) : t != null && n.attr({ cx: t, cy: e ?? t, r: s ?? 0 }), n;
367
+ }
368
+ text(t, e, s) {
369
+ const i = document.createElementNS("http://www.w3.org/2000/svg", "text");
370
+ this.node.appendChild(i);
371
+ const n = x(i, this);
372
+ return typeof t == "object" ? n.attr(t) : t != null && n.attr({ x: t, y: e ?? t, text: s ?? "" }), n;
373
+ }
374
+ }
375
+ class Y {
376
+ frag;
377
+ constructor(t) {
378
+ this.frag = t;
379
+ }
380
+ select(t) {
381
+ const e = this.frag.querySelector(t);
382
+ return e ? x(e) : null;
383
+ }
384
+ selectAll(t) {
385
+ const e = this.frag.querySelectorAll(t);
386
+ return Array.from(e).map((s) => x(s));
387
+ }
388
+ }
389
+ function j(o) {
390
+ if (typeof o == "string") {
391
+ const t = document.querySelector(o);
392
+ return t ? new k(t) : null;
393
+ }
394
+ return o instanceof SVGSVGElement ? new k(o) : null;
395
+ }
396
+ function V(o) {
397
+ const t = document.createElement("div");
398
+ let e = o.trim();
399
+ e.match(/^\s*<\s*svg/i) || (e = "<svg>" + e + "</svg>"), t.innerHTML = e;
400
+ const s = t.querySelector("svg"), i = document.createDocumentFragment();
401
+ if (s)
402
+ for (; s.firstChild; )
403
+ i.appendChild(s.firstChild);
404
+ return new Y(i);
405
+ }
406
+ const X = (o, t, e) => o > e ? e : o < t ? t : o, L = /* @__PURE__ */ new WeakMap(), E = /* @__PURE__ */ new WeakMap();
407
+ function M(o, t, e, s) {
408
+ return s = (s - 90) * Math.PI / 180, {
409
+ x: o + e * Math.cos(s),
410
+ y: t + e * Math.sin(s)
411
+ };
412
+ }
413
+ function S(o, t, e, s, i, n, r) {
414
+ const a = M(o, t, e, s %= 360), c = M(o, t, e, i %= 360);
415
+ return `${n ? "L" : "M"}${a.x} ${a.y} A${e} ${e}, 0, ${i - s >= 180 ? 1 : 0}, ${r ? 0 : 1}, ${c.x} ${c.y}`;
416
+ }
417
+ function F(o, t, e, s, i, n) {
418
+ return `${S(o, t, e, i, n, !1, !1)} ${S(o, t, s, n, i, !0, !0)}Z`;
419
+ }
420
+ class Q {
421
+ config;
422
+ events = {};
423
+ container;
424
+ snap;
425
+ angle;
426
+ size = 500;
427
+ c = this.size / 2;
428
+ element;
429
+ area;
430
+ duration = 300;
431
+ icons = null;
432
+ theme = "light";
433
+ constructor(t) {
434
+ this.config = t, this.size = 2 * t.outerRadius, this.c = this.size / 2, this.angle = 360 / (this.config.sectors.length || 6), this.element = this.createMenuElement(), this.snap = j(this.element.querySelector("svg")), this.area = this.snap, this.container = this.area.g().transform("s0"), this.init().catch(console.error);
435
+ }
436
+ createMenuElement() {
437
+ const t = document.createElement("div");
438
+ t.className = "context theme--light hidden", t.style.position = "fixed", t.style.top = "0", t.style.left = "0", t.style.width = "100vw", t.style.height = "100vh", t.style.overflow = "visible", t.style.pointerEvents = "auto";
439
+ const e = document.createElementNS("http://www.w3.org/2000/svg", "svg");
440
+ return e.setAttribute("width", this.size.toString()), e.setAttribute("height", this.size.toString()), e.setAttribute("viewBox", `0 0 ${this.size} ${this.size}`), e.style.position = "absolute", e.style.display = "block", e.style.overflow = "visible", e.style.pointerEvents = "auto", e.classList.add("radial-menu-svg"), e.addEventListener("wheel", (s) => {
441
+ s.preventDefault(), this.transformOpacity(s);
442
+ }), e.addEventListener("contextmenu", (s) => {
443
+ s.stopPropagation(), s.preventDefault(), this.hide();
444
+ }), e.addEventListener("click", (s) => {
445
+ s.stopPropagation(), this.hide();
446
+ }), t.addEventListener("click", (s) => {
447
+ s.target === t && this.hide();
448
+ }), t.appendChild(e), t;
449
+ }
450
+ async init() {
451
+ await this.loadIcons(), this.updateButtons();
452
+ }
453
+ async loadIcons() {
454
+ if (!this.icons)
455
+ try {
456
+ const t = await fetch(this.config.sprite);
457
+ t.ok && (this.icons = V(await t.text()));
458
+ } catch (t) {
459
+ console.error("Failed to load icons:", t);
460
+ }
461
+ }
462
+ updateButtons() {
463
+ if (!(!this.icons || !this.container) && (this.container.clear(), this.config.sectors.forEach((t) => {
464
+ const e = this.createIcon(t);
465
+ if (e) {
466
+ const s = this.createButton(t, this.createSector(), e, this.createHint(t));
467
+ this.container.add(s);
468
+ }
469
+ }), this.config.centralButton)) {
470
+ const t = this.createCentralButton(this.config.centralButton);
471
+ t && this.container.add(t);
472
+ }
473
+ }
474
+ createSector() {
475
+ const t = this.config.color ?? "#1976D2";
476
+ return this.area.path(F(this.c, this.c, this.config.outerRadius, this.config.innerRadius, 0, this.angle)).attr({ fill: t, stroke: t, opacity: this.config.opacity }).addClass("radial-sector");
477
+ }
478
+ createButton(t, e, s, i) {
479
+ const n = this.area.g(e, s, i);
480
+ return n.hover(
481
+ () => {
482
+ n.select(".radial-hint")?.addClass("active");
483
+ const r = n.select(".radial-hint-bg");
484
+ r && (r.addClass("active"), r.node.style.opacity = String(this.config.opacity)), this.animateButtonHover(n, 0, 1, 200, b.easeinout);
485
+ },
486
+ () => {
487
+ n.select(".radial-hint")?.removeClass("active");
488
+ const r = n.select(".radial-hint-bg");
489
+ r && (r.removeClass("active"), r.node.style.opacity = "0"), this.animateButtonHover(n, 1, 0, 2e3, b.elastic);
490
+ }
491
+ ), n.mouseup((r) => {
492
+ r.button === 0 && (this.emit("click", { icon: t.icon, hint: t.hint }), t.onclick?.());
493
+ }), n;
494
+ }
495
+ createIcon(t) {
496
+ if (!this.icons) return null;
497
+ const e = this.icons.select(`#${t.icon}`);
498
+ if (!e)
499
+ return console.error(`Icon #${t.icon} not found in SVG`), null;
500
+ const s = e.clone(), i = s.getBBox(), n = (this.config.innerRadius + this.config.outerRadius) / 2, a = (this.config.outerRadius - this.config.innerRadius) * 0.5 / i.height, c = t.iconRadius ?? this.config.iconRadius ?? n, l = t.iconScale ?? this.config.iconScale ?? a, h = this.angle / 2, p = h + (t.rotate || 0);
501
+ E.set(s, { midRadius: c, scale: l, rotation: p, bbox: i });
502
+ const u = M(this.c, this.c, c, h), d = new C();
503
+ return d.translate(u.x, u.y), d.scale(l), d.rotate(p, 0, 0), d.translate(-i.cx, -i.cy), s.transform(d), s.addClass("radial-icon");
504
+ }
505
+ createHint(t) {
506
+ const e = this.area.g();
507
+ e.addClass("hint-group");
508
+ const s = t.hintPadding ?? this.config.hintPadding, i = N(), n = t.hint || t.icon, r = q(n), a = 2;
509
+ let c, l = 0;
510
+ if (s !== void 0)
511
+ l = i.height + 2 * s, c = this.config.outerRadius + l / 2 + a;
512
+ else {
513
+ const v = i.height * 0.75;
514
+ c = this.config.outerRadius + v;
515
+ }
516
+ const p = r / c * 180 / Math.PI, u = this.angle / 2, d = u - p / 2, m = u + p / 2, y = S(this.c, this.c, c, d, m, !1, !1);
517
+ if (s !== void 0) {
518
+ const v = this.config.color ?? "#1976D2", g = this.area.path(y).attr({
519
+ stroke: v,
520
+ "stroke-width": `${l}`,
521
+ "stroke-linecap": "round",
522
+ fill: "none",
523
+ "vector-effect": "non-scaling-stroke"
524
+ }).addClass("radial-hint-bg");
525
+ g.node.style.opacity = "0", e.add(g);
526
+ }
527
+ const w = this.area.text(0, 0, n).addClass("radial-hint").attr({
528
+ fill: this.theme === "light" ? "#333333" : "#7a7a7a",
529
+ textpath: y
530
+ }), f = w.select("textPath");
531
+ return f && (f.attr("dominant-baseline", "central"), f.attr("startOffset", "50%")), e.add(w), L.set(e, {
532
+ sectorMidAngle: u,
533
+ baseRadius: c,
534
+ textLength: r
535
+ }), e;
536
+ }
537
+ createCentralButton(t) {
538
+ const e = this.config.innerRadius * 0.6, s = t.iconRadius ?? this.config.iconRadius ?? e, i = this.config.color ?? "#1976D2", n = this.area.circle({
539
+ cx: this.c,
540
+ cy: this.c,
541
+ r: s,
542
+ fill: i,
543
+ stroke: i,
544
+ opacity: this.config.opacity
545
+ }).addClass("radial-sector central-sector");
546
+ n.node.dataset.initialRadius = `${s}`;
547
+ let r = null, a = null;
548
+ t.icon && (r = this.createCentralIcon(t, s)), t.hint && (a = this.createCentralHint(t, s));
549
+ const c = [n, r, a].filter((h) => h !== null), l = this.area.g(...c).addClass("central-button");
550
+ return l.hover(
551
+ () => {
552
+ l.select(".central-hint")?.addClass("active");
553
+ const h = l.select(".radial-hint-bg");
554
+ h && (h.addClass("active"), h.node.style.opacity = String(this.config.opacity)), this.animateCentralHover(l, !0);
555
+ },
556
+ () => {
557
+ l.select(".central-hint")?.removeClass("active");
558
+ const h = l.select(".radial-hint-bg");
559
+ h && (h.removeClass("active"), h.node.style.opacity = "0"), this.animateCentralHover(l, !1);
560
+ }
561
+ ), l.mouseup((h) => {
562
+ h.button === 0 && (this.emit("click", { icon: t.icon, hint: t.hint || "" }), t.onclick?.());
563
+ }), l;
564
+ }
565
+ createCentralIcon(t, e) {
566
+ if (!this.icons) return null;
567
+ const s = this.icons.select(`#${t.icon}`);
568
+ if (!s)
569
+ return console.error(`Icon #${t.icon} not found in SVG`), null;
570
+ const i = s.clone(), n = i.getBBox(), r = e * 0.8 / Math.max(n.width, n.height), a = t.iconScale ?? this.config.iconScale ?? r, c = new C();
571
+ return c.translate(this.c, this.c), c.scale(a), c.translate(-n.cx, -n.cy), i.transform(c).addClass("radial-icon central-icon"), E.set(i, {
572
+ midRadius: 0,
573
+ rotation: 0,
574
+ scale: a,
575
+ bbox: n
576
+ }), i;
577
+ }
578
+ createCentralHint(t, e) {
579
+ const s = this.area.g(), i = t.hintPadding ?? this.config.hintPadding, n = N(), r = t.hint ?? "";
580
+ let a, c = 0;
581
+ i !== void 0 ? (c = n.height + 2 * i, a = t.hintOffset ?? c / 2 + 2) : t.hintOffset != null ? a = t.hintOffset : a = t.hintDistance ?? 8;
582
+ const h = e + a;
583
+ let p, u, d;
584
+ if (t.hintStartAngle != null && t.hintEndAngle != null)
585
+ p = t.hintStartAngle, u = t.hintEndAngle, d = p > u;
586
+ else {
587
+ const g = (t.hintSpan ?? 120) / 2;
588
+ (t.hintPosition ?? "top") === "bottom" ? (p = 180 + g, u = 180 - g, d = !0) : (p = 360 - g, u = g, d = !1);
589
+ }
590
+ const m = S(this.c, this.c, h, p, u, !1, d);
591
+ if (i !== void 0) {
592
+ const v = this.config.color ?? "#1976D2", g = this.area.path(m).attr({
593
+ stroke: v,
594
+ "stroke-width": `${c}`,
595
+ "stroke-linecap": "round",
596
+ fill: "none",
597
+ "vector-effect": "non-scaling-stroke"
598
+ }).addClass("radial-hint-bg");
599
+ g.node.style.opacity = "0", s.add(g);
600
+ }
601
+ const y = this.area.text(0, 0, r).addClass("radial-hint central-hint").attr({
602
+ fill: this.theme === "light" ? "#333333" : "#7a7a7a",
603
+ textpath: m
604
+ }), w = y.select("textPath");
605
+ w && (w.attr("dominant-baseline", "central"), w.attr("startOffset", "50%"));
606
+ const f = y.node;
607
+ return f.dataset.hintOffset = a.toString(), f.dataset.startAngle = p.toString(), f.dataset.endAngle = u.toString(), f.dataset.alter = d ? "true" : "false", f.dataset.centerX = this.c.toString(), f.dataset.centerY = this.c.toString(), s.add(y), s;
608
+ }
609
+ show(t) {
610
+ this.element.classList.remove("hidden");
611
+ const e = this.element.querySelector("svg");
612
+ e.style.left = t.clientX - this.c + "px", e.style.top = t.clientY - this.c + "px", this.animateContainer(0, 1, this.duration * 8, b.elastic), this.animateButtons(0, 1, this.duration, this.duration * 8, b.elastic);
613
+ }
614
+ hide() {
615
+ this.animateContainer(1, 0, this.duration, b.easeinout, () => {
616
+ this.element.classList.add("hidden");
617
+ }), this.animateButtons(1, 0, this.duration, this.duration, b.easeinout);
618
+ }
619
+ animate(t, e, s, i, n, r, a, c) {
620
+ t.animation ||= [], t.animation[e]?.stop(), t.animation[e] = P(s, i, a, n, r, c);
621
+ }
622
+ animateContainer(t, e, s, i, n) {
623
+ this.animate(this, 0, t, e, s, i, (r) => {
624
+ this.container.transform(`r${90 - 90 * r},${this.c},${this.c}s${r},${r},${this.c},${this.c}`);
625
+ }, n);
626
+ }
627
+ animateButtons(t, e, s, i, n) {
628
+ const r = (a, c) => Math.random() * (c - a) + a;
629
+ this.container.children().forEach((a, c) => {
630
+ const l = a.node.classList.contains("central-button");
631
+ this.animate(a, 0, t, e, r(s, i), n, (h) => {
632
+ l ? a.transform(`s${h},${h},${this.c},${this.c}`) : a.transform(`r${this.angle * c},${this.c},${this.c}s${h},${h},${this.c},${this.c}`);
633
+ });
634
+ });
635
+ }
636
+ animateButtonHover(t, e, s, i, n, r) {
637
+ const a = t.select(".radial-icon"), c = a ? E.get(a) : void 0, l = t.select(".hint-group"), h = l ? L.get(l) : void 0;
638
+ this.animate(t, 1, e, s, i, n, (p) => {
639
+ const u = p * 10;
640
+ if (t.select(".radial-sector")?.attr({
641
+ d: F(this.c, this.c, this.config.outerRadius - u, this.config.innerRadius, 0, this.angle)
642
+ }), a && c) {
643
+ const d = c.midRadius - u, m = c.scale * (1 - p * 0.1), y = this.angle / 2, w = M(this.c, this.c, d, y), f = new C();
644
+ f.translate(w.x, w.y), f.scale(m), f.rotate(c.rotation, 0, 0), f.translate(-c.bbox.cx, -c.bbox.cy), a.transform(f);
645
+ }
646
+ if (h && l) {
647
+ const d = h.baseRadius - u, m = h.textLength / d * 180 / Math.PI, y = h.sectorMidAngle - m / 2, w = h.sectorMidAngle + m / 2, f = S(this.c, this.c, d, y, w, !1, !1), v = l.select(".radial-hint");
648
+ v && v.attr("textpath", f);
649
+ const g = l.select(".radial-hint-bg");
650
+ g && g.attr("d", f);
651
+ }
652
+ }, r);
653
+ }
654
+ animateCentralHover(t, e) {
655
+ const s = t.select(".central-sector"), i = t.select(".central-icon"), n = t.select(".central-hint"), r = t.select(".radial-hint-bg");
656
+ if (!s || !i) return;
657
+ const a = parseFloat(s.node.dataset.initialRadius || "30"), c = parseFloat(s.attr("r")), l = e ? a - 8 : a, h = i ? E.get(i) : void 0;
658
+ let p = 12, u = 0, d = 0, m = this.c, y = this.c, w = !1;
659
+ n && (p = parseFloat(n.node.dataset.hintOffset || "12"), u = parseFloat(n.node.dataset.startAngle || "0"), d = parseFloat(n.node.dataset.endAngle || "0"), m = parseFloat(n.node.dataset.centerX || this.c.toString()), y = parseFloat(n.node.dataset.centerY || this.c.toString()), w = n.node.dataset.alter === "true"), P(c, l, (f) => {
660
+ if (s.attr("r", f), i && h) {
661
+ const v = h.scale * (f / a), g = new C();
662
+ g.translate(this.c, this.c), g.scale(v), g.translate(-h.bbox.cx, -h.bbox.cy), i.transform(g);
663
+ }
664
+ if (n) {
665
+ const v = f + p, g = S(m, y, v, u, d, !1, w);
666
+ n.attr({ textpath: g }), r && r.attr({ d: g });
667
+ }
668
+ }, 200, b.easeinout);
669
+ }
670
+ transformOpacity(t) {
671
+ const e = t.deltaY > 0 ? 0.03 : -0.03;
672
+ this.config.opacity = X(this.config.opacity + e, 0.4, 1), this.area.selectAll(".radial-sector").forEach((s) => {
673
+ s.attr({ opacity: this.config.opacity });
674
+ }), this.area.selectAll(".radial-hint-bg.active").forEach((s) => {
675
+ s.node.style.opacity = String(this.config.opacity);
676
+ });
677
+ }
678
+ on(t, e) {
679
+ (this.events[t] ??= []).push(e);
680
+ }
681
+ emit(t, e) {
682
+ this.events[t] && this.events[t].forEach((s) => s(e));
683
+ }
684
+ }
685
+ class K {
686
+ menu;
687
+ constructor(t, e) {
688
+ this.menu = new Q(e), t.appendChild(this.menu.element), e.autoBindContextMenu !== !1 && this.bindEvents();
689
+ }
690
+ bindEvents() {
691
+ window.addEventListener("contextmenu", (t) => {
692
+ t.preventDefault(), this.menu.show(t);
693
+ });
694
+ }
695
+ on(t, e) {
696
+ this.menu.on(t, e);
697
+ }
698
+ show(t) {
699
+ this.menu.show(t);
700
+ }
701
+ hide() {
702
+ this.menu.hide();
703
+ }
704
+ }
705
+ export {
706
+ K as Manager,
707
+ J as defineConfig
708
+ };
709
+ //# sourceMappingURL=context-menu.js.map