@ixfx/components 0.0.8 → 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.
@@ -0,0 +1,2687 @@
1
+ import { customElement, property, queryAssignedElements } from "lit/decorators.js";
2
+ import { Circles, degreeToRadian, radianArc, radianToDegree, radiansSum } from "ixfx/geometry.js";
3
+ import * as Numbers from "ixfx/numbers.js";
4
+ import { clamp } from "ixfx/numbers.js";
5
+ import { getCssVariable, getCssVariablesWithFallback } from "ixfx/dom.js";
6
+ import { createRef, ref } from "lit/directives/ref.js";
7
+ import { Trees } from "ixfx/collections.js";
8
+ import { join } from "lit/directives/join.js";
9
+ import { customElement as customElement$1 } from "lit/decorators/custom-element.js";
10
+ import { property as property$1 } from "lit/decorators/property.js";
11
+ import { CanvasHelper, Colour, Drawing } from "ixfx/visual.js";
12
+ import { Pathed } from "ixfx";
13
+ import { repeat } from "lit/directives/repeat.js";
14
+
15
+ //#region node_modules/@lit/reactive-element/css-tag.js
16
+ /**
17
+ * @license
18
+ * Copyright 2019 Google LLC
19
+ * SPDX-License-Identifier: BSD-3-Clause
20
+ */
21
+ const t$1 = globalThis, e$1 = t$1.ShadowRoot && (void 0 === t$1.ShadyCSS || t$1.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$2 = Symbol(), o$3 = /* @__PURE__ */ new WeakMap();
22
+ var n$1 = class {
23
+ constructor(t$2, e$3, o$4) {
24
+ if (this._$cssResult$ = !0, o$4 !== s$2) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
25
+ this.cssText = t$2, this.t = e$3;
26
+ }
27
+ get styleSheet() {
28
+ let t$2 = this.o;
29
+ const s$3 = this.t;
30
+ if (e$1 && void 0 === t$2) {
31
+ const e$3 = void 0 !== s$3 && 1 === s$3.length;
32
+ e$3 && (t$2 = o$3.get(s$3)), void 0 === t$2 && ((this.o = t$2 = new CSSStyleSheet()).replaceSync(this.cssText), e$3 && o$3.set(s$3, t$2));
33
+ }
34
+ return t$2;
35
+ }
36
+ toString() {
37
+ return this.cssText;
38
+ }
39
+ };
40
+ const r$1 = (t$2) => new n$1("string" == typeof t$2 ? t$2 : t$2 + "", void 0, s$2), i$1 = (t$2, ...e$3) => {
41
+ const o$4 = 1 === t$2.length ? t$2[0] : e$3.reduce(((e$4, s$3, o$5) => e$4 + ((t$3) => {
42
+ if (!0 === t$3._$cssResult$) return t$3.cssText;
43
+ if ("number" == typeof t$3) return t$3;
44
+ throw Error("Value passed to 'css' function must be a 'css' function result: " + t$3 + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.");
45
+ })(s$3) + t$2[o$5 + 1]), t$2[0]);
46
+ return new n$1(o$4, t$2, s$2);
47
+ }, S$1 = (s$3, o$4) => {
48
+ if (e$1) s$3.adoptedStyleSheets = o$4.map(((t$2) => t$2 instanceof CSSStyleSheet ? t$2 : t$2.styleSheet));
49
+ else for (const e$3 of o$4) {
50
+ const o$5 = document.createElement("style"), n$3 = t$1.litNonce;
51
+ void 0 !== n$3 && o$5.setAttribute("nonce", n$3), o$5.textContent = e$3.cssText, s$3.appendChild(o$5);
52
+ }
53
+ }, c$1 = e$1 ? (t$2) => t$2 : (t$2) => t$2 instanceof CSSStyleSheet ? ((t$3) => {
54
+ let e$3 = "";
55
+ for (const s$3 of t$3.cssRules) e$3 += s$3.cssText;
56
+ return r$1(e$3);
57
+ })(t$2) : t$2;
58
+
59
+ //#endregion
60
+ //#region node_modules/@lit/reactive-element/reactive-element.js
61
+ /**
62
+ * @license
63
+ * Copyright 2017 Google LLC
64
+ * SPDX-License-Identifier: BSD-3-Clause
65
+ */ const { is: i$3, defineProperty: e$2, getOwnPropertyDescriptor: h$1, getOwnPropertyNames: r$2, getOwnPropertySymbols: o$2, getPrototypeOf: n$2 } = Object, a$1 = globalThis, c$2 = a$1.trustedTypes, l$1 = c$2 ? c$2.emptyScript : "", p$1 = a$1.reactiveElementPolyfillSupport, d$1 = (t$2, s$3) => t$2, u$1 = {
66
+ toAttribute(t$2, s$3) {
67
+ switch (s$3) {
68
+ case Boolean:
69
+ t$2 = t$2 ? l$1 : null;
70
+ break;
71
+ case Object:
72
+ case Array: t$2 = null == t$2 ? t$2 : JSON.stringify(t$2);
73
+ }
74
+ return t$2;
75
+ },
76
+ fromAttribute(t$2, s$3) {
77
+ let i$4 = t$2;
78
+ switch (s$3) {
79
+ case Boolean:
80
+ i$4 = null !== t$2;
81
+ break;
82
+ case Number:
83
+ i$4 = null === t$2 ? null : Number(t$2);
84
+ break;
85
+ case Object:
86
+ case Array: try {
87
+ i$4 = JSON.parse(t$2);
88
+ } catch (t$3) {
89
+ i$4 = null;
90
+ }
91
+ }
92
+ return i$4;
93
+ }
94
+ }, f$1 = (t$2, s$3) => !i$3(t$2, s$3), b$1 = {
95
+ attribute: !0,
96
+ type: String,
97
+ converter: u$1,
98
+ reflect: !1,
99
+ useDefault: !1,
100
+ hasChanged: f$1
101
+ };
102
+ Symbol.metadata ??= Symbol("metadata"), a$1.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap();
103
+ var y = class extends HTMLElement {
104
+ static addInitializer(t$2) {
105
+ this._$Ei(), (this.l ??= []).push(t$2);
106
+ }
107
+ static get observedAttributes() {
108
+ return this.finalize(), this._$Eh && [...this._$Eh.keys()];
109
+ }
110
+ static createProperty(t$2, s$3 = b$1) {
111
+ if (s$3.state && (s$3.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(t$2) && ((s$3 = Object.create(s$3)).wrapped = !0), this.elementProperties.set(t$2, s$3), !s$3.noAccessor) {
112
+ const i$4 = Symbol(), h$2 = this.getPropertyDescriptor(t$2, i$4, s$3);
113
+ void 0 !== h$2 && e$2(this.prototype, t$2, h$2);
114
+ }
115
+ }
116
+ static getPropertyDescriptor(t$2, s$3, i$4) {
117
+ const { get: e$3, set: r$3 } = h$1(this.prototype, t$2) ?? {
118
+ get() {
119
+ return this[s$3];
120
+ },
121
+ set(t$3) {
122
+ this[s$3] = t$3;
123
+ }
124
+ };
125
+ return {
126
+ get: e$3,
127
+ set(s$4) {
128
+ const h$2 = e$3?.call(this);
129
+ r$3?.call(this, s$4), this.requestUpdate(t$2, h$2, i$4);
130
+ },
131
+ configurable: !0,
132
+ enumerable: !0
133
+ };
134
+ }
135
+ static getPropertyOptions(t$2) {
136
+ return this.elementProperties.get(t$2) ?? b$1;
137
+ }
138
+ static _$Ei() {
139
+ if (this.hasOwnProperty(d$1("elementProperties"))) return;
140
+ const t$2 = n$2(this);
141
+ t$2.finalize(), void 0 !== t$2.l && (this.l = [...t$2.l]), this.elementProperties = new Map(t$2.elementProperties);
142
+ }
143
+ static finalize() {
144
+ if (this.hasOwnProperty(d$1("finalized"))) return;
145
+ if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(d$1("properties"))) {
146
+ const t$3 = this.properties, s$3 = [...r$2(t$3), ...o$2(t$3)];
147
+ for (const i$4 of s$3) this.createProperty(i$4, t$3[i$4]);
148
+ }
149
+ const t$2 = this[Symbol.metadata];
150
+ if (null !== t$2) {
151
+ const s$3 = litPropertyMetadata.get(t$2);
152
+ if (void 0 !== s$3) for (const [t$3, i$4] of s$3) this.elementProperties.set(t$3, i$4);
153
+ }
154
+ this._$Eh = /* @__PURE__ */ new Map();
155
+ for (const [t$3, s$3] of this.elementProperties) {
156
+ const i$4 = this._$Eu(t$3, s$3);
157
+ void 0 !== i$4 && this._$Eh.set(i$4, t$3);
158
+ }
159
+ this.elementStyles = this.finalizeStyles(this.styles);
160
+ }
161
+ static finalizeStyles(s$3) {
162
+ const i$4 = [];
163
+ if (Array.isArray(s$3)) {
164
+ const e$3 = new Set(s$3.flat(Infinity).reverse());
165
+ for (const s$4 of e$3) i$4.unshift(c$1(s$4));
166
+ } else void 0 !== s$3 && i$4.push(c$1(s$3));
167
+ return i$4;
168
+ }
169
+ static _$Eu(t$2, s$3) {
170
+ const i$4 = s$3.attribute;
171
+ return !1 === i$4 ? void 0 : "string" == typeof i$4 ? i$4 : "string" == typeof t$2 ? t$2.toLowerCase() : void 0;
172
+ }
173
+ constructor() {
174
+ super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev();
175
+ }
176
+ _$Ev() {
177
+ this._$ES = new Promise(((t$2) => this.enableUpdating = t$2)), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), this.constructor.l?.forEach(((t$2) => t$2(this)));
178
+ }
179
+ addController(t$2) {
180
+ (this._$EO ??= /* @__PURE__ */ new Set()).add(t$2), void 0 !== this.renderRoot && this.isConnected && t$2.hostConnected?.();
181
+ }
182
+ removeController(t$2) {
183
+ this._$EO?.delete(t$2);
184
+ }
185
+ _$E_() {
186
+ const t$2 = /* @__PURE__ */ new Map(), s$3 = this.constructor.elementProperties;
187
+ for (const i$4 of s$3.keys()) this.hasOwnProperty(i$4) && (t$2.set(i$4, this[i$4]), delete this[i$4]);
188
+ t$2.size > 0 && (this._$Ep = t$2);
189
+ }
190
+ createRenderRoot() {
191
+ const t$2 = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
192
+ return S$1(t$2, this.constructor.elementStyles), t$2;
193
+ }
194
+ connectedCallback() {
195
+ this.renderRoot ??= this.createRenderRoot(), this.enableUpdating(!0), this._$EO?.forEach(((t$2) => t$2.hostConnected?.()));
196
+ }
197
+ enableUpdating(t$2) {}
198
+ disconnectedCallback() {
199
+ this._$EO?.forEach(((t$2) => t$2.hostDisconnected?.()));
200
+ }
201
+ attributeChangedCallback(t$2, s$3, i$4) {
202
+ this._$AK(t$2, i$4);
203
+ }
204
+ _$ET(t$2, s$3) {
205
+ const i$4 = this.constructor.elementProperties.get(t$2), e$3 = this.constructor._$Eu(t$2, i$4);
206
+ if (void 0 !== e$3 && !0 === i$4.reflect) {
207
+ const h$2 = (void 0 !== i$4.converter?.toAttribute ? i$4.converter : u$1).toAttribute(s$3, i$4.type);
208
+ this._$Em = t$2, null == h$2 ? this.removeAttribute(e$3) : this.setAttribute(e$3, h$2), this._$Em = null;
209
+ }
210
+ }
211
+ _$AK(t$2, s$3) {
212
+ const i$4 = this.constructor, e$3 = i$4._$Eh.get(t$2);
213
+ if (void 0 !== e$3 && this._$Em !== e$3) {
214
+ const t$3 = i$4.getPropertyOptions(e$3), h$2 = "function" == typeof t$3.converter ? { fromAttribute: t$3.converter } : void 0 !== t$3.converter?.fromAttribute ? t$3.converter : u$1;
215
+ this._$Em = e$3;
216
+ const r$3 = h$2.fromAttribute(s$3, t$3.type);
217
+ this[e$3] = r$3 ?? this._$Ej?.get(e$3) ?? r$3, this._$Em = null;
218
+ }
219
+ }
220
+ requestUpdate(t$2, s$3, i$4) {
221
+ if (void 0 !== t$2) {
222
+ const e$3 = this.constructor, h$2 = this[t$2];
223
+ if (i$4 ??= e$3.getPropertyOptions(t$2), !((i$4.hasChanged ?? f$1)(h$2, s$3) || i$4.useDefault && i$4.reflect && h$2 === this._$Ej?.get(t$2) && !this.hasAttribute(e$3._$Eu(t$2, i$4)))) return;
224
+ this.C(t$2, s$3, i$4);
225
+ }
226
+ !1 === this.isUpdatePending && (this._$ES = this._$EP());
227
+ }
228
+ C(t$2, s$3, { useDefault: i$4, reflect: e$3, wrapped: h$2 }, r$3) {
229
+ i$4 && !(this._$Ej ??= /* @__PURE__ */ new Map()).has(t$2) && (this._$Ej.set(t$2, r$3 ?? s$3 ?? this[t$2]), !0 !== h$2 || void 0 !== r$3) || (this._$AL.has(t$2) || (this.hasUpdated || i$4 || (s$3 = void 0), this._$AL.set(t$2, s$3)), !0 === e$3 && this._$Em !== t$2 && (this._$Eq ??= /* @__PURE__ */ new Set()).add(t$2));
230
+ }
231
+ async _$EP() {
232
+ this.isUpdatePending = !0;
233
+ try {
234
+ await this._$ES;
235
+ } catch (t$3) {
236
+ Promise.reject(t$3);
237
+ }
238
+ const t$2 = this.scheduleUpdate();
239
+ return null != t$2 && await t$2, !this.isUpdatePending;
240
+ }
241
+ scheduleUpdate() {
242
+ return this.performUpdate();
243
+ }
244
+ performUpdate() {
245
+ if (!this.isUpdatePending) return;
246
+ if (!this.hasUpdated) {
247
+ if (this.renderRoot ??= this.createRenderRoot(), this._$Ep) {
248
+ for (const [t$4, s$4] of this._$Ep) this[t$4] = s$4;
249
+ this._$Ep = void 0;
250
+ }
251
+ const t$3 = this.constructor.elementProperties;
252
+ if (t$3.size > 0) for (const [s$4, i$4] of t$3) {
253
+ const { wrapped: t$4 } = i$4, e$3 = this[s$4];
254
+ !0 !== t$4 || this._$AL.has(s$4) || void 0 === e$3 || this.C(s$4, void 0, i$4, e$3);
255
+ }
256
+ }
257
+ let t$2 = !1;
258
+ const s$3 = this._$AL;
259
+ try {
260
+ t$2 = this.shouldUpdate(s$3), t$2 ? (this.willUpdate(s$3), this._$EO?.forEach(((t$3) => t$3.hostUpdate?.())), this.update(s$3)) : this._$EM();
261
+ } catch (s$4) {
262
+ throw t$2 = !1, this._$EM(), s$4;
263
+ }
264
+ t$2 && this._$AE(s$3);
265
+ }
266
+ willUpdate(t$2) {}
267
+ _$AE(t$2) {
268
+ this._$EO?.forEach(((t$3) => t$3.hostUpdated?.())), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(t$2)), this.updated(t$2);
269
+ }
270
+ _$EM() {
271
+ this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1;
272
+ }
273
+ get updateComplete() {
274
+ return this.getUpdateComplete();
275
+ }
276
+ getUpdateComplete() {
277
+ return this._$ES;
278
+ }
279
+ shouldUpdate(t$2) {
280
+ return !0;
281
+ }
282
+ update(t$2) {
283
+ this._$Eq &&= this._$Eq.forEach(((t$3) => this._$ET(t$3, this[t$3]))), this._$EM();
284
+ }
285
+ updated(t$2) {}
286
+ firstUpdated(t$2) {}
287
+ };
288
+ y.elementStyles = [], y.shadowRootOptions = { mode: "open" }, y[d$1("elementProperties")] = /* @__PURE__ */ new Map(), y[d$1("finalized")] = /* @__PURE__ */ new Map(), p$1?.({ ReactiveElement: y }), (a$1.reactiveElementVersions ??= []).push("2.1.1");
289
+
290
+ //#endregion
291
+ //#region node_modules/lit-html/lit-html.js
292
+ /**
293
+ * @license
294
+ * Copyright 2017 Google LLC
295
+ * SPDX-License-Identifier: BSD-3-Clause
296
+ */
297
+ const t = globalThis, i$2 = t.trustedTypes, s$1 = i$2 ? i$2.createPolicy("lit-html", { createHTML: (t$2) => t$2 }) : void 0, e = "$lit$", h = `lit$${Math.random().toFixed(9).slice(2)}$`, o$1 = "?" + h, n = `<${o$1}>`, r = document, l = () => r.createComment(""), c = (t$2) => null === t$2 || "object" != typeof t$2 && "function" != typeof t$2, a = Array.isArray, u = (t$2) => a(t$2) || "function" == typeof t$2?.[Symbol.iterator], d = "[ \n\f\r]", f = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, v = /-->/g, _ = />/g, m = RegExp(`>|${d}(?:([^\\s"'>=/]+)(${d}*=${d}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`, "g"), p = /'/g, g = /"/g, $ = /^(?:script|style|textarea|title)$/i, y$1 = (t$2) => (i$4, ...s$3) => ({
298
+ _$litType$: t$2,
299
+ strings: i$4,
300
+ values: s$3
301
+ }), x = y$1(1), b = y$1(2), w = y$1(3), T = Symbol.for("lit-noChange"), E = Symbol.for("lit-nothing"), A = /* @__PURE__ */ new WeakMap(), C = r.createTreeWalker(r, 129);
302
+ function P(t$2, i$4) {
303
+ if (!a(t$2) || !t$2.hasOwnProperty("raw")) throw Error("invalid template strings array");
304
+ return void 0 !== s$1 ? s$1.createHTML(i$4) : i$4;
305
+ }
306
+ const V = (t$2, i$4) => {
307
+ const s$3 = t$2.length - 1, o$4 = [];
308
+ let r$3, l$2 = 2 === i$4 ? "<svg>" : 3 === i$4 ? "<math>" : "", c$3 = f;
309
+ for (let i$5 = 0; i$5 < s$3; i$5++) {
310
+ const s$4 = t$2[i$5];
311
+ let a$2, u$2, d$2 = -1, y$2 = 0;
312
+ for (; y$2 < s$4.length && (c$3.lastIndex = y$2, u$2 = c$3.exec(s$4), null !== u$2);) y$2 = c$3.lastIndex, c$3 === f ? "!--" === u$2[1] ? c$3 = v : void 0 !== u$2[1] ? c$3 = _ : void 0 !== u$2[2] ? ($.test(u$2[2]) && (r$3 = RegExp("</" + u$2[2], "g")), c$3 = m) : void 0 !== u$2[3] && (c$3 = m) : c$3 === m ? ">" === u$2[0] ? (c$3 = r$3 ?? f, d$2 = -1) : void 0 === u$2[1] ? d$2 = -2 : (d$2 = c$3.lastIndex - u$2[2].length, a$2 = u$2[1], c$3 = void 0 === u$2[3] ? m : "\"" === u$2[3] ? g : p) : c$3 === g || c$3 === p ? c$3 = m : c$3 === v || c$3 === _ ? c$3 = f : (c$3 = m, r$3 = void 0);
313
+ const x$1 = c$3 === m && t$2[i$5 + 1].startsWith("/>") ? " " : "";
314
+ l$2 += c$3 === f ? s$4 + n : d$2 >= 0 ? (o$4.push(a$2), s$4.slice(0, d$2) + e + s$4.slice(d$2) + h + x$1) : s$4 + h + (-2 === d$2 ? i$5 : x$1);
315
+ }
316
+ return [P(t$2, l$2 + (t$2[s$3] || "<?>") + (2 === i$4 ? "</svg>" : 3 === i$4 ? "</math>" : "")), o$4];
317
+ };
318
+ var N = class N {
319
+ constructor({ strings: t$2, _$litType$: s$3 }, n$3) {
320
+ let r$3;
321
+ this.parts = [];
322
+ let c$3 = 0, a$2 = 0;
323
+ const u$2 = t$2.length - 1, d$2 = this.parts, [f$2, v$1] = V(t$2, s$3);
324
+ if (this.el = N.createElement(f$2, n$3), C.currentNode = this.el.content, 2 === s$3 || 3 === s$3) {
325
+ const t$3 = this.el.content.firstChild;
326
+ t$3.replaceWith(...t$3.childNodes);
327
+ }
328
+ for (; null !== (r$3 = C.nextNode()) && d$2.length < u$2;) {
329
+ if (1 === r$3.nodeType) {
330
+ if (r$3.hasAttributes()) for (const t$3 of r$3.getAttributeNames()) if (t$3.endsWith(e)) {
331
+ const i$4 = v$1[a$2++], s$4 = r$3.getAttribute(t$3).split(h), e$3 = /([.?@])?(.*)/.exec(i$4);
332
+ d$2.push({
333
+ type: 1,
334
+ index: c$3,
335
+ name: e$3[2],
336
+ strings: s$4,
337
+ ctor: "." === e$3[1] ? H : "?" === e$3[1] ? I : "@" === e$3[1] ? L : k
338
+ }), r$3.removeAttribute(t$3);
339
+ } else t$3.startsWith(h) && (d$2.push({
340
+ type: 6,
341
+ index: c$3
342
+ }), r$3.removeAttribute(t$3));
343
+ if ($.test(r$3.tagName)) {
344
+ const t$3 = r$3.textContent.split(h), s$4 = t$3.length - 1;
345
+ if (s$4 > 0) {
346
+ r$3.textContent = i$2 ? i$2.emptyScript : "";
347
+ for (let i$4 = 0; i$4 < s$4; i$4++) r$3.append(t$3[i$4], l()), C.nextNode(), d$2.push({
348
+ type: 2,
349
+ index: ++c$3
350
+ });
351
+ r$3.append(t$3[s$4], l());
352
+ }
353
+ }
354
+ } else if (8 === r$3.nodeType) if (r$3.data === o$1) d$2.push({
355
+ type: 2,
356
+ index: c$3
357
+ });
358
+ else {
359
+ let t$3 = -1;
360
+ for (; -1 !== (t$3 = r$3.data.indexOf(h, t$3 + 1));) d$2.push({
361
+ type: 7,
362
+ index: c$3
363
+ }), t$3 += h.length - 1;
364
+ }
365
+ c$3++;
366
+ }
367
+ }
368
+ static createElement(t$2, i$4) {
369
+ const s$3 = r.createElement("template");
370
+ return s$3.innerHTML = t$2, s$3;
371
+ }
372
+ };
373
+ function S(t$2, i$4, s$3 = t$2, e$3) {
374
+ if (i$4 === T) return i$4;
375
+ let h$2 = void 0 !== e$3 ? s$3._$Co?.[e$3] : s$3._$Cl;
376
+ const o$4 = c(i$4) ? void 0 : i$4._$litDirective$;
377
+ return h$2?.constructor !== o$4 && (h$2?._$AO?.(!1), void 0 === o$4 ? h$2 = void 0 : (h$2 = new o$4(t$2), h$2._$AT(t$2, s$3, e$3)), void 0 !== e$3 ? (s$3._$Co ??= [])[e$3] = h$2 : s$3._$Cl = h$2), void 0 !== h$2 && (i$4 = S(t$2, h$2._$AS(t$2, i$4.values), h$2, e$3)), i$4;
378
+ }
379
+ var M = class {
380
+ constructor(t$2, i$4) {
381
+ this._$AV = [], this._$AN = void 0, this._$AD = t$2, this._$AM = i$4;
382
+ }
383
+ get parentNode() {
384
+ return this._$AM.parentNode;
385
+ }
386
+ get _$AU() {
387
+ return this._$AM._$AU;
388
+ }
389
+ u(t$2) {
390
+ const { el: { content: i$4 }, parts: s$3 } = this._$AD, e$3 = (t$2?.creationScope ?? r).importNode(i$4, !0);
391
+ C.currentNode = e$3;
392
+ let h$2 = C.nextNode(), o$4 = 0, n$3 = 0, l$2 = s$3[0];
393
+ for (; void 0 !== l$2;) {
394
+ if (o$4 === l$2.index) {
395
+ let i$5;
396
+ 2 === l$2.type ? i$5 = new R(h$2, h$2.nextSibling, this, t$2) : 1 === l$2.type ? i$5 = new l$2.ctor(h$2, l$2.name, l$2.strings, this, t$2) : 6 === l$2.type && (i$5 = new z(h$2, this, t$2)), this._$AV.push(i$5), l$2 = s$3[++n$3];
397
+ }
398
+ o$4 !== l$2?.index && (h$2 = C.nextNode(), o$4++);
399
+ }
400
+ return C.currentNode = r, e$3;
401
+ }
402
+ p(t$2) {
403
+ let i$4 = 0;
404
+ for (const s$3 of this._$AV) void 0 !== s$3 && (void 0 !== s$3.strings ? (s$3._$AI(t$2, s$3, i$4), i$4 += s$3.strings.length - 2) : s$3._$AI(t$2[i$4])), i$4++;
405
+ }
406
+ };
407
+ var R = class R {
408
+ get _$AU() {
409
+ return this._$AM?._$AU ?? this._$Cv;
410
+ }
411
+ constructor(t$2, i$4, s$3, e$3) {
412
+ this.type = 2, this._$AH = E, this._$AN = void 0, this._$AA = t$2, this._$AB = i$4, this._$AM = s$3, this.options = e$3, this._$Cv = e$3?.isConnected ?? !0;
413
+ }
414
+ get parentNode() {
415
+ let t$2 = this._$AA.parentNode;
416
+ const i$4 = this._$AM;
417
+ return void 0 !== i$4 && 11 === t$2?.nodeType && (t$2 = i$4.parentNode), t$2;
418
+ }
419
+ get startNode() {
420
+ return this._$AA;
421
+ }
422
+ get endNode() {
423
+ return this._$AB;
424
+ }
425
+ _$AI(t$2, i$4 = this) {
426
+ t$2 = S(this, t$2, i$4), c(t$2) ? t$2 === E || null == t$2 || "" === t$2 ? (this._$AH !== E && this._$AR(), this._$AH = E) : t$2 !== this._$AH && t$2 !== T && this._(t$2) : void 0 !== t$2._$litType$ ? this.$(t$2) : void 0 !== t$2.nodeType ? this.T(t$2) : u(t$2) ? this.k(t$2) : this._(t$2);
427
+ }
428
+ O(t$2) {
429
+ return this._$AA.parentNode.insertBefore(t$2, this._$AB);
430
+ }
431
+ T(t$2) {
432
+ this._$AH !== t$2 && (this._$AR(), this._$AH = this.O(t$2));
433
+ }
434
+ _(t$2) {
435
+ this._$AH !== E && c(this._$AH) ? this._$AA.nextSibling.data = t$2 : this.T(r.createTextNode(t$2)), this._$AH = t$2;
436
+ }
437
+ $(t$2) {
438
+ const { values: i$4, _$litType$: s$3 } = t$2, e$3 = "number" == typeof s$3 ? this._$AC(t$2) : (void 0 === s$3.el && (s$3.el = N.createElement(P(s$3.h, s$3.h[0]), this.options)), s$3);
439
+ if (this._$AH?._$AD === e$3) this._$AH.p(i$4);
440
+ else {
441
+ const t$3 = new M(e$3, this), s$4 = t$3.u(this.options);
442
+ t$3.p(i$4), this.T(s$4), this._$AH = t$3;
443
+ }
444
+ }
445
+ _$AC(t$2) {
446
+ let i$4 = A.get(t$2.strings);
447
+ return void 0 === i$4 && A.set(t$2.strings, i$4 = new N(t$2)), i$4;
448
+ }
449
+ k(t$2) {
450
+ a(this._$AH) || (this._$AH = [], this._$AR());
451
+ const i$4 = this._$AH;
452
+ let s$3, e$3 = 0;
453
+ for (const h$2 of t$2) e$3 === i$4.length ? i$4.push(s$3 = new R(this.O(l()), this.O(l()), this, this.options)) : s$3 = i$4[e$3], s$3._$AI(h$2), e$3++;
454
+ e$3 < i$4.length && (this._$AR(s$3 && s$3._$AB.nextSibling, e$3), i$4.length = e$3);
455
+ }
456
+ _$AR(t$2 = this._$AA.nextSibling, i$4) {
457
+ for (this._$AP?.(!1, !0, i$4); t$2 !== this._$AB;) {
458
+ const i$5 = t$2.nextSibling;
459
+ t$2.remove(), t$2 = i$5;
460
+ }
461
+ }
462
+ setConnected(t$2) {
463
+ void 0 === this._$AM && (this._$Cv = t$2, this._$AP?.(t$2));
464
+ }
465
+ };
466
+ var k = class {
467
+ get tagName() {
468
+ return this.element.tagName;
469
+ }
470
+ get _$AU() {
471
+ return this._$AM._$AU;
472
+ }
473
+ constructor(t$2, i$4, s$3, e$3, h$2) {
474
+ this.type = 1, this._$AH = E, this._$AN = void 0, this.element = t$2, this.name = i$4, this._$AM = e$3, this.options = h$2, s$3.length > 2 || "" !== s$3[0] || "" !== s$3[1] ? (this._$AH = Array(s$3.length - 1).fill(/* @__PURE__ */ new String()), this.strings = s$3) : this._$AH = E;
475
+ }
476
+ _$AI(t$2, i$4 = this, s$3, e$3) {
477
+ const h$2 = this.strings;
478
+ let o$4 = !1;
479
+ if (void 0 === h$2) t$2 = S(this, t$2, i$4, 0), o$4 = !c(t$2) || t$2 !== this._$AH && t$2 !== T, o$4 && (this._$AH = t$2);
480
+ else {
481
+ const e$4 = t$2;
482
+ let n$3, r$3;
483
+ for (t$2 = h$2[0], n$3 = 0; n$3 < h$2.length - 1; n$3++) r$3 = S(this, e$4[s$3 + n$3], i$4, n$3), r$3 === T && (r$3 = this._$AH[n$3]), o$4 ||= !c(r$3) || r$3 !== this._$AH[n$3], r$3 === E ? t$2 = E : t$2 !== E && (t$2 += (r$3 ?? "") + h$2[n$3 + 1]), this._$AH[n$3] = r$3;
484
+ }
485
+ o$4 && !e$3 && this.j(t$2);
486
+ }
487
+ j(t$2) {
488
+ t$2 === E ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t$2 ?? "");
489
+ }
490
+ };
491
+ var H = class extends k {
492
+ constructor() {
493
+ super(...arguments), this.type = 3;
494
+ }
495
+ j(t$2) {
496
+ this.element[this.name] = t$2 === E ? void 0 : t$2;
497
+ }
498
+ };
499
+ var I = class extends k {
500
+ constructor() {
501
+ super(...arguments), this.type = 4;
502
+ }
503
+ j(t$2) {
504
+ this.element.toggleAttribute(this.name, !!t$2 && t$2 !== E);
505
+ }
506
+ };
507
+ var L = class extends k {
508
+ constructor(t$2, i$4, s$3, e$3, h$2) {
509
+ super(t$2, i$4, s$3, e$3, h$2), this.type = 5;
510
+ }
511
+ _$AI(t$2, i$4 = this) {
512
+ if ((t$2 = S(this, t$2, i$4, 0) ?? E) === T) return;
513
+ const s$3 = this._$AH, e$3 = t$2 === E && s$3 !== E || t$2.capture !== s$3.capture || t$2.once !== s$3.once || t$2.passive !== s$3.passive, h$2 = t$2 !== E && (s$3 === E || e$3);
514
+ e$3 && this.element.removeEventListener(this.name, this, s$3), h$2 && this.element.addEventListener(this.name, this, t$2), this._$AH = t$2;
515
+ }
516
+ handleEvent(t$2) {
517
+ "function" == typeof this._$AH ? this._$AH.call(this.options?.host ?? this.element, t$2) : this._$AH.handleEvent(t$2);
518
+ }
519
+ };
520
+ var z = class {
521
+ constructor(t$2, i$4, s$3) {
522
+ this.element = t$2, this.type = 6, this._$AN = void 0, this._$AM = i$4, this.options = s$3;
523
+ }
524
+ get _$AU() {
525
+ return this._$AM._$AU;
526
+ }
527
+ _$AI(t$2) {
528
+ S(this, t$2);
529
+ }
530
+ };
531
+ const Z = {
532
+ M: e,
533
+ P: h,
534
+ A: o$1,
535
+ C: 1,
536
+ L: V,
537
+ R: M,
538
+ D: u,
539
+ V: S,
540
+ I: R,
541
+ H: k,
542
+ N: I,
543
+ U: L,
544
+ B: H,
545
+ F: z
546
+ }, j = t.litHtmlPolyfillSupport;
547
+ j?.(N, R), (t.litHtmlVersions ??= []).push("3.3.1");
548
+ const B = (t$2, i$4, s$3) => {
549
+ const e$3 = s$3?.renderBefore ?? i$4;
550
+ let h$2 = e$3._$litPart$;
551
+ if (void 0 === h$2) {
552
+ const t$3 = s$3?.renderBefore ?? null;
553
+ e$3._$litPart$ = h$2 = new R(i$4.insertBefore(l(), t$3), t$3, void 0, s$3 ?? {});
554
+ }
555
+ return h$2._$AI(t$2), h$2;
556
+ };
557
+
558
+ //#endregion
559
+ //#region node_modules/lit-element/lit-element.js
560
+ /**
561
+ * @license
562
+ * Copyright 2017 Google LLC
563
+ * SPDX-License-Identifier: BSD-3-Clause
564
+ */ const s = globalThis;
565
+ var i = class extends y {
566
+ constructor() {
567
+ super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
568
+ }
569
+ createRenderRoot() {
570
+ const t$2 = super.createRenderRoot();
571
+ return this.renderOptions.renderBefore ??= t$2.firstChild, t$2;
572
+ }
573
+ update(t$2) {
574
+ const r$3 = this.render();
575
+ this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t$2), this._$Do = B(r$3, this.renderRoot, this.renderOptions);
576
+ }
577
+ connectedCallback() {
578
+ super.connectedCallback(), this._$Do?.setConnected(!0);
579
+ }
580
+ disconnectedCallback() {
581
+ super.disconnectedCallback(), this._$Do?.setConnected(!1);
582
+ }
583
+ render() {
584
+ return T;
585
+ }
586
+ };
587
+ i._$litElement$ = !0, i["finalized"] = !0, s.litElementHydrateSupport?.({ LitElement: i });
588
+ const o = s.litElementPolyfillSupport;
589
+ o?.({ LitElement: i });
590
+ (s.litElementVersions ??= []).push("4.2.1");
591
+
592
+ //#endregion
593
+ //#region src/util/circle-arc.ts
594
+ const piPi$1 = Math.PI * 2;
595
+ const precompute = (arc) => {
596
+ let rotation = 0;
597
+ const anchor = arc.anchor ?? `south`;
598
+ const rangeRadian = arc.rangeRadian ?? radianToDegree(300);
599
+ let invert = false;
600
+ switch (anchor) {
601
+ case `east`: break;
602
+ case `south-east`:
603
+ rotation = -Math.PI / 4;
604
+ break;
605
+ case `north`:
606
+ rotation = Math.PI / 2;
607
+ invert = true;
608
+ break;
609
+ case `south`:
610
+ default: rotation = Math.PI * 3 / 2;
611
+ }
612
+ const rangeRemainder = piPi$1 - rangeRadian;
613
+ let startAngle = rotation - rangeRemainder / 2;
614
+ let endAngle = rotation + rangeRemainder / 2;
615
+ const midAngle = rotation - Math.PI;
616
+ if (invert) {
617
+ const oldStart = startAngle;
618
+ startAngle = endAngle;
619
+ endAngle = oldStart;
620
+ }
621
+ const startPoint = Circles.pointOnPerimeter(arc, startAngle);
622
+ const endPoint = Circles.pointOnPerimeter(arc, endAngle);
623
+ const midPoint = Circles.pointOnPerimeter(arc, midAngle);
624
+ return {
625
+ ...arc,
626
+ anchor,
627
+ rangeRadian,
628
+ midPoint,
629
+ midAngle,
630
+ startPoint,
631
+ endPoint,
632
+ rotation,
633
+ startAngle,
634
+ endAngle,
635
+ invert
636
+ };
637
+ };
638
+ const interpolatePoint = (arc, t$2) => {
639
+ const angle = arc.rangeRadian * t$2;
640
+ return Circles.pointOnPerimeter(arc, arc.startAngle - angle);
641
+ };
642
+ const arcPart = (track, startAngle, endAngle, cw) => {
643
+ const startPoint = Circles.pointOnPerimeter(track, startAngle);
644
+ const endPoint = Circles.pointOnPerimeter(track, endAngle);
645
+ return {
646
+ startPoint,
647
+ endPoint,
648
+ startAngle,
649
+ endAngle,
650
+ range: radianArc(startAngle, endAngle, cw)
651
+ };
652
+ };
653
+ const partToSvg = (arc, part, largeArc = true, clockwise = true) => {
654
+ const rotation = 0;
655
+ return [`M ${part.startPoint.x} ${part.startPoint.y}`, `A ${arc.radius} ${arc.radius} ${rotation} ${largeArc ? `1` : `0`} ${clockwise ? `1` : `0`} ${part.endPoint.x} ${part.endPoint.y}`];
656
+ };
657
+ const toSvg = (arc, largeArc = true, clockwise = true) => {
658
+ const rotation = 0;
659
+ return [`M ${arc.startPoint.x} ${arc.startPoint.y}`, `A ${arc.radius} ${arc.radius} ${rotation} ${largeArc ? `1` : `0`} ${clockwise ? `1` : `0`} ${arc.endPoint.x} ${arc.endPoint.y}`];
660
+ };
661
+
662
+ //#endregion
663
+ //#region src/util/content-editable.ts
664
+ const focus = (el, selectAll) => {
665
+ el.focus();
666
+ if (selectAll) {
667
+ const range = document.createRange();
668
+ range.selectNodeContents(el);
669
+ const sel = window.getSelection();
670
+ if (sel) {
671
+ sel.removeAllRanges();
672
+ sel.addRange(range);
673
+ }
674
+ }
675
+ };
676
+
677
+ //#endregion
678
+ //#region src/util/svg-editable-text.ts
679
+ var SvgEditLabel = class extends EventTarget {
680
+ textRef = createRef();
681
+ editorRef = createRef();
682
+ #keyDownBound = this.#onKeyDown.bind(this);
683
+ #blurBound = this.#onBlur.bind(this);
684
+ onEditMode;
685
+ onInput;
686
+ #renderLabel(data) {
687
+ const { fill, x: x$1, y: y$2, displayValue, anchor, hideValue } = data;
688
+ if (hideValue) return b``;
689
+ return b`<text ${ref(this.textRef)} id="label-value" @click=${() => this.#onValueClick()} fill=${fill} text-anchor=${anchor} x=${x$1} y=${y$2}>${displayValue}</text>`;
690
+ }
691
+ #onValueClick() {
692
+ this.#onEditMode(true);
693
+ }
694
+ #onEditMode(enabled) {
695
+ if (this.onEditMode !== void 0) this.onEditMode(enabled, this);
696
+ this.dispatchEvent(new CustomEvent(`edit-mode`, { detail: { enabled } }));
697
+ }
698
+ #renderEdit(data) {
699
+ let { anchor, editValue, x: x$1, y: y$2 } = data;
700
+ let w$1 = 5;
701
+ let h$2 = 5;
702
+ if (this.textRef.value) {
703
+ const bbox = this.textRef.value.getBBox();
704
+ x$1 = x$1 - bbox.width / 2;
705
+ y$2 = y$2 - bbox.height + 4.5;
706
+ w$1 = bbox.width + 5;
707
+ h$2 = bbox.height;
708
+ }
709
+ return b`
710
+ <foreignObject text-anchor=${anchor} width=${w$1} height=${h$2} x=${x$1} y=${y$2}>
711
+ <div ${ref(this.editorRef)} @blur=${this.#blurBound} @keydown=${this.#keyDownBound} xmlns="http://www.w3.org/1999/xhtml" tab-index=0 contentEditable=true>${editValue}</div>
712
+ </foreignObject>`;
713
+ }
714
+ render(data) {
715
+ if (data.editMode) return this.#renderEdit(data);
716
+ else return this.#renderLabel(data);
717
+ }
718
+ #onBlur(event) {
719
+ const rawValue = event.target.innerText;
720
+ if (this.onInput) this.onInput(rawValue);
721
+ this.#onEditMode(false);
722
+ }
723
+ #onKeyDown(event) {
724
+ const key = event.key;
725
+ if (key === `Escape`) {
726
+ this.#onEditMode(false);
727
+ return;
728
+ } else if (key === `Enter`) {
729
+ const rawValue = event.target.innerText;
730
+ if (this.onInput) this.onInput(rawValue);
731
+ this.#onEditMode(false);
732
+ return;
733
+ }
734
+ }
735
+ onUpdated() {
736
+ if (this.editorRef.value) focus(this.editorRef.value, true);
737
+ }
738
+ static styles = i$1`
739
+ :host {
740
+ display: inline-block;
741
+ --value-label-color: unset;
742
+ }
743
+ input {
744
+ font:unset;
745
+ position:absolute;
746
+ background:unset;
747
+ }
748
+
749
+ foreignObject>div {
750
+ width:-webkit-fill-available;
751
+ background:red;
752
+ margin: 0;
753
+ padding: 0;
754
+ line-height: unset;
755
+ }
756
+ `;
757
+ };
758
+
759
+ //#endregion
760
+ //#region node_modules/@oxc-project/runtime/src/helpers/esm/decorate.js
761
+ function __decorate(decorators, target, key, desc) {
762
+ var c$3 = arguments.length, r$3 = c$3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d$2;
763
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r$3 = Reflect.decorate(decorators, target, key, desc);
764
+ else for (var i$4 = decorators.length - 1; i$4 >= 0; i$4--) if (d$2 = decorators[i$4]) r$3 = (c$3 < 3 ? d$2(r$3) : c$3 > 3 ? d$2(target, key, r$3) : d$2(target, key)) || r$3;
765
+ return c$3 > 3 && r$3 && Object.defineProperty(target, key, r$3), r$3;
766
+ }
767
+
768
+ //#endregion
769
+ //#region src/dial.ts
770
+ const piPi = Math.PI * 2;
771
+ let DialElement = class DialElement$1 extends i {
772
+ rangeAngle = 300;
773
+ rangeAnchor = `south`;
774
+ labelPosition = `edge`;
775
+ spread = false;
776
+ hideValue = false;
777
+ hideTerminators = false;
778
+ showKnob = false;
779
+ bipolar = false;
780
+ needleStyle = `to-track`;
781
+ value = 50;
782
+ step = 10;
783
+ stepFine = 1;
784
+ radius = .5;
785
+ min = 0;
786
+ max = 100;
787
+ textRelativeHeight = 5;
788
+ valueLabelRef = createRef();
789
+ valueLabel = {
790
+ anchor: `start`,
791
+ x: 0,
792
+ fill: ``,
793
+ hideValue: this.hideValue,
794
+ y: 0,
795
+ editMode: false,
796
+ displayValue: 0,
797
+ editValue: 0
798
+ };
799
+ #editableLabel;
800
+ #onPointerDownBound = this.#onPointerDown.bind(this);
801
+ #onPointerDragBound = this.#onPointerDrag.bind(this);
802
+ #onDragStopBound = this.#onDragStop.bind(this);
803
+ constructor() {
804
+ super();
805
+ this.#editableLabel = new SvgEditLabel();
806
+ this.#editableLabel.onEditMode = (enabled, _source) => {
807
+ this.valueLabel = {
808
+ ...this.valueLabel,
809
+ editMode: enabled
810
+ };
811
+ };
812
+ this.#editableLabel.onInput = (value) => {
813
+ const f$2 = Number.parseFloat(value);
814
+ if (Number.isNaN(f$2)) return;
815
+ this.#setValue(f$2);
816
+ };
817
+ }
818
+ #computeTextLabelPosition(vars, arc) {
819
+ let x$1 = 0;
820
+ let y$2 = 0;
821
+ let textAnchor = `middle`;
822
+ if (this.labelPosition === `inner`) {
823
+ x$1 = arc.x;
824
+ y$2 = arc.y + this.textRelativeHeight / 4;
825
+ } else switch (this.rangeAnchor) {
826
+ case `north`:
827
+ x$1 = 50;
828
+ y$2 = this.textRelativeHeight * 1.5;
829
+ break;
830
+ case `east`:
831
+ x$1 = 75;
832
+ y$2 = 50;
833
+ textAnchor = `start`;
834
+ break;
835
+ case `south-east`:
836
+ x$1 = 99;
837
+ y$2 = 90;
838
+ textAnchor = `end`;
839
+ break;
840
+ default:
841
+ x$1 = 50;
842
+ y$2 = 95;
843
+ }
844
+ x$1 += vars.value_label_x;
845
+ y$2 += vars.value_label_y;
846
+ return {
847
+ x: x$1,
848
+ y: y$2,
849
+ anchor: textAnchor
850
+ };
851
+ }
852
+ #computeArc(vars) {
853
+ const textHeight = this.textRelativeHeight;
854
+ let maxRadius = 50 - Math.max(vars.track_width, vars.value_width) * 3;
855
+ let middleY = 50;
856
+ const cornerRange = this.rangeAnchor === `south-east`;
857
+ if (this.labelPosition === `below`) {
858
+ maxRadius -= textHeight;
859
+ middleY -= textHeight;
860
+ }
861
+ if (cornerRange) {
862
+ middleY += textHeight / 2;
863
+ maxRadius -= 3;
864
+ }
865
+ return {
866
+ maxRadius,
867
+ middleY
868
+ };
869
+ }
870
+ #renderTrackArc(vars, value, arc, part) {
871
+ if (vars.track_width <= 0) return b``;
872
+ const hiddenTrack = vars.track_width <= vars.value_width;
873
+ let largeArc = true;
874
+ const clockwise = true;
875
+ let arcSvgBits = [];
876
+ if (hiddenTrack && !this.bipolar) {
877
+ let startAt = part.endAngle - .1;
878
+ const arcPart$1 = arcPart(arc, startAt, arc.endAngle, true);
879
+ const d$2 = radianArc(startAt, arc.endAngle, true);
880
+ if (value > .97) arcSvgBits = toSvg(arc, largeArc, clockwise);
881
+ else {
882
+ largeArc = d$2 > Math.PI;
883
+ arcSvgBits = partToSvg(arc, arcPart$1, largeArc, clockwise);
884
+ }
885
+ } else arcSvgBits = toSvg(arc, largeArc, clockwise);
886
+ const s$3 = b`
887
+ <path
888
+ d="${arcSvgBits.join(" ")}"
889
+ fill="none"
890
+ stroke-linecap="round"
891
+ stroke="${vars.track_color}"
892
+ stroke-width="${vars.track_width}"
893
+ />
894
+ `;
895
+ return s$3;
896
+ }
897
+ #getBipolarValue(value, arc) {
898
+ if (value < .5) {
899
+ const pc = Numbers.scale(value, 0, .5);
900
+ const distance = radianArc(arc.startAngle, arc.midAngle, true) * pc;
901
+ const startAngle = radiansSum(arc.startAngle, distance, false);
902
+ return arcPart(arc, startAngle, arc.midAngle, true);
903
+ } else {
904
+ const pc = Numbers.scale(value, .5, 1);
905
+ const distance = radianArc(arc.midAngle, arc.endAngle, true) * pc;
906
+ const endAngle = radiansSum(arc.midAngle, distance, false);
907
+ return arcPart(arc, arc.midAngle, endAngle, true);
908
+ }
909
+ }
910
+ #getUnipolarValue(value, arc) {
911
+ const angle = value * arc.rangeRadian;
912
+ const endAngle = Numbers.wrap(arc.startAngle - angle, 0, piPi);
913
+ const arcValue = arcPart(arc, arc.startAngle, endAngle, true);
914
+ return arcValue;
915
+ }
916
+ getRelativeValue() {
917
+ return Numbers.scale(this.value, this.min, this.max);
918
+ }
919
+ #renderValueArc(vars, value, arc, part) {
920
+ let largeArc = false;
921
+ const clockwise = !arc.invert;
922
+ if (part.range > Math.PI) largeArc = true;
923
+ const arcSvgBits = partToSvg(arc, part, largeArc, clockwise);
924
+ const showValueArc = this.bipolar ? value === .5 : value === 0;
925
+ const arcValueSvg = showValueArc ? b`` : b`<path
926
+ d="${arcSvgBits.join(" ")}"
927
+ fill="none"
928
+ stroke="${vars.value_color}"
929
+ stroke-width="${vars.value_width}"
930
+ />`;
931
+ const needleStart = vars.needle_start * arc.radius;
932
+ let needleEnd = 1;
933
+ switch (this.needleStyle) {
934
+ case `none`: return arcValueSvg;
935
+ case `to-knob`:
936
+ needleEnd = vars.knob_radius * arc.radius;
937
+ break;
938
+ case `to-track`:
939
+ needleEnd = arc.radius;
940
+ break;
941
+ }
942
+ needleEnd += vars.needle_overshoot * (needleEnd - needleStart);
943
+ const line = {
944
+ a: interpolatePoint({
945
+ ...arc,
946
+ radius: needleStart
947
+ }, value),
948
+ b: interpolatePoint({
949
+ ...arc,
950
+ radius: needleEnd
951
+ }, value)
952
+ };
953
+ const needleLine = b`<line
954
+ x1=${line.a.x}
955
+ y1=${line.a.y}
956
+ x2=${line.b.x}
957
+ y2=${line.b.y}
958
+ stroke-linecap="round"
959
+ stroke=${vars.needle_color}
960
+ stroke-width=${vars.needle_width}
961
+ />`;
962
+ return [arcValueSvg, needleLine];
963
+ }
964
+ #renderKnob(vars, arc) {
965
+ if (!this.showKnob) return b``;
966
+ return b`<circle r=${arc.radius * vars.knob_radius} cx=${arc.x} cy=${arc.y} fill=${vars.knob_color} />`;
967
+ }
968
+ #renderPoints(radius, fill, ...circles) {
969
+ return circles.map((c$3) => b`<circle fill=${fill} r=${radius} cx=${c$3.x} cy=${c$3.y} />`);
970
+ }
971
+ render() {
972
+ const vars = this.resolveVariables();
973
+ const arcSize = this.#computeArc(vars);
974
+ const circlePre = {
975
+ x: 50,
976
+ y: arcSize.middleY,
977
+ radius: arcSize.maxRadius,
978
+ anchor: this.rangeAnchor,
979
+ rangeRadian: degreeToRadian(this.rangeAngle)
980
+ };
981
+ const circle = precompute(circlePre);
982
+ const relativeValue = this.getRelativeValue();
983
+ const valueArc = this.bipolar ? this.#getBipolarValue(relativeValue, circle) : this.#getUnipolarValue(relativeValue, circle);
984
+ let terminators = [];
985
+ const terminatorSize = Math.max(vars.value_width, vars.track_width);
986
+ if (!this.hideTerminators) {
987
+ let lightStart = this.value !== this.min;
988
+ if (this.bipolar) lightStart = this.value === this.min;
989
+ const atEnd = this.value === this.max;
990
+ const startTerminator = this.#renderPoints(terminatorSize, lightStart ? vars.value_color : vars.track_color, circle.startPoint);
991
+ const endTerminator = this.#renderPoints(terminatorSize, atEnd ? vars.value_color : vars.track_color, circle.endPoint);
992
+ terminators = [...startTerminator, ...endTerminator];
993
+ }
994
+ if (this.bipolar) {
995
+ const mid = (this.max - this.min) / 2;
996
+ const atMid = this.value.toFixed(1) === mid.toFixed(1);
997
+ const midPoint = b`<circle @click=${this.onMidpointClick} fill=${atMid ? vars.value_color : vars.track_color} r=${terminatorSize * 1.5} cx=${circle.midPoint.x} cy=${circle.midPoint.y} />`;
998
+ terminators.push(midPoint);
999
+ }
1000
+ const textLabelPos = this.#computeTextLabelPosition(vars, circle);
1001
+ this.valueLabel = {
1002
+ ...this.valueLabel,
1003
+ ...textLabelPos,
1004
+ hideValue: this.hideValue,
1005
+ displayValue: this.valueToLabel(this.value),
1006
+ editValue: this.value
1007
+ };
1008
+ return x`<svg tabindex=0 @pointerdown=${this.#onPointerDownBound} @wheel=${this.onMouseWheel} @keydown=${this.onKeyDown} overflow="hidden" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
1009
+ ${this.#renderTrackArc(vars, relativeValue, circle, valueArc)}
1010
+ ${this.#renderKnob(vars, circle)}
1011
+ ${terminators}
1012
+ ${this.#renderValueArc(vars, relativeValue, circle, valueArc)}
1013
+ ${this.#editableLabel.render(this.valueLabel)}
1014
+ </svg>`;
1015
+ }
1016
+ #onPointerDown(_event) {
1017
+ window.addEventListener(`pointermove`, this.#onPointerDragBound);
1018
+ window.addEventListener(`pointercancel`, this.#onDragStopBound);
1019
+ window.addEventListener(`pointerup`, this.#onDragStopBound);
1020
+ }
1021
+ #onPointerDrag(event) {
1022
+ const y$2 = event.movementY / this.clientHeight;
1023
+ const r$3 = this.range * y$2;
1024
+ this.#setValue(this.value - r$3);
1025
+ }
1026
+ #onDragStop() {
1027
+ window.removeEventListener(`pointerup`, this.#onDragStopBound);
1028
+ window.removeEventListener(`pointercancel`, this.#onDragStopBound);
1029
+ window.removeEventListener(`pointermove`, this.#onPointerDragBound);
1030
+ }
1031
+ updated(_changedProperties) {
1032
+ this.#editableLabel.onUpdated();
1033
+ }
1034
+ onMidpointClick() {
1035
+ this.#setValue((this.max - this.min) / 2);
1036
+ }
1037
+ /**
1038
+ * Manually sets the value, clamping to min/max range.
1039
+ * Fires 'change' event.
1040
+ * @param value
1041
+ * @returns
1042
+ */
1043
+ #setValue(value) {
1044
+ const old = this.value;
1045
+ value = Numbers.clamp(value, this.min, this.max);
1046
+ if (value === old) return;
1047
+ this.value = value;
1048
+ this.valueLabel = {
1049
+ ...this.valueLabel,
1050
+ displayValue: this.valueToLabel(value),
1051
+ editValue: value
1052
+ };
1053
+ this.dispatchEvent(new CustomEvent(`change`, { detail: {
1054
+ previousValue: old,
1055
+ newValue: value
1056
+ } }));
1057
+ }
1058
+ onMouseWheel(event) {
1059
+ const shift = event.shiftKey;
1060
+ const amount = shift ? this.stepFine : this.step;
1061
+ this.deltaChange(amount * event.deltaY * .01);
1062
+ event.preventDefault();
1063
+ }
1064
+ deltaChange(amount) {
1065
+ this.#setValue(this.value + amount);
1066
+ }
1067
+ onKeyDown(event) {
1068
+ const key = event.key;
1069
+ const shift = event.shiftKey;
1070
+ if (this.valueLabel.editMode) return;
1071
+ const amount = shift ? this.stepFine : this.step;
1072
+ if (key === `ArrowLeft` || key === `ArrowDown`) this.deltaChange(-amount);
1073
+ else if (key === `ArrowRight` || key === `ArrowUp`) this.deltaChange(amount);
1074
+ else if (Number.parseInt(key).toString() === key) this.valueLabel = {
1075
+ ...this.valueLabel,
1076
+ editMode: true
1077
+ };
1078
+ }
1079
+ onPointerMove(event) {
1080
+ const { x: x$1, y: y$2 } = event;
1081
+ console.log(`x: ${x$1} y:${y$2}`);
1082
+ }
1083
+ resolveVariables() {
1084
+ const vars = getCssVariablesWithFallback({
1085
+ track_width: 10,
1086
+ track_color: `gray`,
1087
+ value_width: 10,
1088
+ value_color: `red`,
1089
+ value_label_color: `unset`,
1090
+ value_label_x: 0,
1091
+ value_label_y: 0,
1092
+ needle_overshoot: .2,
1093
+ needle_start: .6,
1094
+ needle_color: `black`,
1095
+ needle_width: 10,
1096
+ knob_color: `black`,
1097
+ knob_radius: .8
1098
+ }, this);
1099
+ return vars;
1100
+ }
1101
+ set valueToLabel(fn) {
1102
+ this.#valueToLabel = fn;
1103
+ this.requestUpdate();
1104
+ }
1105
+ get valueToLabel() {
1106
+ return this.#valueToLabel;
1107
+ }
1108
+ get range() {
1109
+ return this.max - this.min;
1110
+ }
1111
+ #valueToLabel = (value) => {
1112
+ return value.toFixed(1);
1113
+ };
1114
+ static styles = i$1`
1115
+ :host {
1116
+ display: inline-block;
1117
+ --value-label-color: unset;
1118
+ }
1119
+ text {
1120
+ user-select:none;
1121
+ }
1122
+
1123
+ `;
1124
+ };
1125
+ __decorate([property({ type: Number })], DialElement.prototype, "rangeAngle", void 0);
1126
+ __decorate([property({ type: String })], DialElement.prototype, "rangeAnchor", void 0);
1127
+ __decorate([property({ type: String })], DialElement.prototype, "labelPosition", void 0);
1128
+ __decorate([property({ type: Boolean })], DialElement.prototype, "spread", void 0);
1129
+ __decorate([property({ type: Boolean })], DialElement.prototype, "hideValue", void 0);
1130
+ __decorate([property({ type: Boolean })], DialElement.prototype, "hideTerminators", void 0);
1131
+ __decorate([property({ type: Boolean })], DialElement.prototype, "showKnob", void 0);
1132
+ __decorate([property({ type: Boolean })], DialElement.prototype, "bipolar", void 0);
1133
+ __decorate([property({ type: String })], DialElement.prototype, "needleStyle", void 0);
1134
+ __decorate([property({ type: Number })], DialElement.prototype, "value", void 0);
1135
+ __decorate([property({ type: Number })], DialElement.prototype, "step", void 0);
1136
+ __decorate([property({ type: Number })], DialElement.prototype, "stepFine", void 0);
1137
+ __decorate([property({ type: Number })], DialElement.prototype, "radius", void 0);
1138
+ __decorate([property({ type: Number })], DialElement.prototype, "min", void 0);
1139
+ __decorate([property({ type: Number })], DialElement.prototype, "max", void 0);
1140
+ __decorate([property({ type: Number })], DialElement.prototype, "textRelativeHeight", void 0);
1141
+ __decorate([property({ type: Object })], DialElement.prototype, "valueLabel", void 0);
1142
+ DialElement = __decorate([customElement("ixfx-dial")], DialElement);
1143
+
1144
+ //#endregion
1145
+ //#region src/selecthorizontal.ts
1146
+ let SelectHorizontalElement = class SelectHorizontalElement$1 extends i {
1147
+ editMode = false;
1148
+ render() {
1149
+ console.log(`render`);
1150
+ return x`
1151
+ <option>pre</option>
1152
+ <slot></slot>
1153
+ <option>post</option>
1154
+ `;
1155
+ }
1156
+ static styles = i$1`
1157
+ :host {
1158
+ display: flex;
1159
+ overflow: scroll;
1160
+ width: 100%;
1161
+ scroll-snap-type: x mandatory;
1162
+ scrollbar-width: none;
1163
+ }
1164
+
1165
+ ::slotted(*),option {
1166
+ user-select: none;
1167
+ scroll-snap-align: start;
1168
+ border: 1px solid silver;
1169
+ color:red;
1170
+ }
1171
+ `;
1172
+ };
1173
+ __decorate([property({ type: Boolean })], SelectHorizontalElement.prototype, "editMode", void 0);
1174
+ SelectHorizontalElement = __decorate([customElement("ixfx-selecthorizontal-element")], SelectHorizontalElement);
1175
+
1176
+ //#endregion
1177
+ //#region src/crumb-navigation.ts
1178
+ let CrumbNavigationElement = class CrumbNavigationElement$1 extends i {
1179
+ tree;
1180
+ selectedNode;
1181
+ constructor() {
1182
+ super();
1183
+ const t$2 = Trees.Mutable.createNode({
1184
+ key: `root`,
1185
+ label: `root`
1186
+ });
1187
+ const nodeC = Trees.Mutable.addValue({
1188
+ key: `c`,
1189
+ label: `c:`
1190
+ }, t$2);
1191
+ const nodeUsers = Trees.Mutable.addValue({
1192
+ key: `users`,
1193
+ label: `users`
1194
+ }, nodeC);
1195
+ Trees.Mutable.addValue({
1196
+ key: `guest`,
1197
+ label: `guest`
1198
+ }, nodeUsers);
1199
+ Trees.Mutable.addValue({
1200
+ key: `ch`,
1201
+ label: `ch`
1202
+ }, nodeUsers);
1203
+ Trees.Mutable.addValue({
1204
+ key: `admin`,
1205
+ label: `admin`
1206
+ }, nodeUsers);
1207
+ Trees.Mutable.addValue({
1208
+ key: `jane`,
1209
+ label: `jane`
1210
+ }, nodeUsers);
1211
+ Trees.Mutable.addValue({
1212
+ key: `barry`,
1213
+ label: `barry`
1214
+ }, nodeUsers);
1215
+ Trees.Mutable.addValue({
1216
+ key: `reallylongoptionwow`,
1217
+ label: `reallylongoptionwow`
1218
+ }, nodeUsers);
1219
+ this.selectedNode = nodeUsers;
1220
+ this.tree = t$2;
1221
+ }
1222
+ #previousSelectionKey = ``;
1223
+ #onPartClick = (event) => {
1224
+ const part = event.target.value;
1225
+ const n$3 = Trees.Traverse.findAnyChildByValue(this.tree, part);
1226
+ if (n$3) this.#setSelected(n$3);
1227
+ };
1228
+ /**
1229
+ * Sets the selected node and fires event
1230
+ * @param node
1231
+ */
1232
+ #setSelected(node) {
1233
+ const previous = this.selectedNode;
1234
+ if (previous) this.#previousSelectionKey = previous.value?.key ?? ``;
1235
+ else this.#previousSelectionKey = ``;
1236
+ this.selectedNode = node;
1237
+ this.dispatchEvent(new CustomEvent(`change`, { detail: {
1238
+ selected: node,
1239
+ previous
1240
+ } }));
1241
+ }
1242
+ #onSubPartClick = (event) => {
1243
+ const currentlySelected = this.selectedNode;
1244
+ if (!currentlySelected) {
1245
+ console.warn(`Bug. No selectedNode`);
1246
+ return;
1247
+ }
1248
+ const currentlySelectedKey = currentlySelected.value?.key;
1249
+ if (!currentlySelectedKey) {
1250
+ console.warn(`Bug. No key for selected value`);
1251
+ return;
1252
+ }
1253
+ const li = event.target;
1254
+ if (!li) {
1255
+ console.warn(`Bug. No LI element`);
1256
+ return;
1257
+ }
1258
+ const key = li.getAttribute(`data-key`) ?? ``;
1259
+ if (!key) {
1260
+ console.warn(`Bug. No data-key attribute`);
1261
+ return;
1262
+ }
1263
+ for (const c$3 of currentlySelected.childrenStore) if (c$3.value?.key === key) {
1264
+ this.#setSelected(c$3);
1265
+ break;
1266
+ }
1267
+ };
1268
+ updated(_changedProperties) {
1269
+ if (!this.shadowRoot) return;
1270
+ const hsiElement = this.shadowRoot.querySelector(`.horiz-select-items`);
1271
+ if (!hsiElement) return;
1272
+ const ulElement = hsiElement.querySelector(`ul`);
1273
+ const btnExpand = this.shadowRoot.querySelector(`#btnExpand`);
1274
+ if (ulElement.getBoundingClientRect().width > hsiElement.getBoundingClientRect().width) btnExpand.style.display = `inline`;
1275
+ else btnExpand.style.display = `none`;
1276
+ for (const li of ulElement.querySelectorAll(`li`)) {
1277
+ const key = li.getAttribute(`data-key`) ?? ``;
1278
+ if (key === this.#previousSelectionKey) {
1279
+ this.#scrollToValue(li);
1280
+ break;
1281
+ }
1282
+ }
1283
+ }
1284
+ #scrollToValue(li) {
1285
+ let l$2 = li.offsetLeft;
1286
+ const ul = li.parentElement;
1287
+ if (!ul) return;
1288
+ l$2 -= ul.offsetLeft;
1289
+ const horizSelectItems = ul.parentElement;
1290
+ if (!horizSelectItems) return;
1291
+ horizSelectItems.scroll({
1292
+ left: l$2,
1293
+ top: 0,
1294
+ behavior: `smooth`
1295
+ });
1296
+ const horizSelect = horizSelectItems.parentElement;
1297
+ if (!horizSelect) return;
1298
+ horizSelect.style.minWidth = li.getBoundingClientRect().width + "px";
1299
+ }
1300
+ render() {
1301
+ const t$2 = this.tree;
1302
+ const sel = this.selectedNode ?? t$2;
1303
+ let parts = [];
1304
+ parts.push(x`<div .value=${sel.value} @click=${this.#onPartClick}>${sel.value?.label}</div>`);
1305
+ for (const p$2 of Trees.Traverse.parents(sel)) {
1306
+ if (p$2.value === void 0) continue;
1307
+ const v$1 = p$2.value;
1308
+ parts.push(x`<div .value=${v$1} @click=${this.#onPartClick}>${v$1.label}</div>`);
1309
+ }
1310
+ parts.reverse();
1311
+ const currentOpt = this.#renderFinalOption();
1312
+ return x`<div class="parts">${join(parts, x`<span class="separator">&rsaquo;</span>`)}</div>
1313
+ ${currentOpt}`;
1314
+ }
1315
+ #renderFinalOption() {
1316
+ const s$3 = this.selectedNode;
1317
+ if (s$3 === void 0) {
1318
+ console.warn(`No selectedNode`);
1319
+ return x``;
1320
+ }
1321
+ return this.#renderOptions(s$3, this.#previousSelectionKey);
1322
+ }
1323
+ #renderOptions(node, preselectKey) {
1324
+ if (node.childrenStore.length === 0) return x``;
1325
+ const options = node.childrenStore.map((c$3) => x`<li class="${c$3.value?.key === preselectKey ? `previous` : ``}" @click=${this.#onSubPartClick} data-key=${c$3.value?.key}>${c$3.value?.label}</li>`);
1326
+ return x`
1327
+ <span class="separator">&rsaquo;</span>
1328
+ <div class="horiz-select">
1329
+ <div class="horiz-select-items">
1330
+ <ul>
1331
+ ${options}
1332
+ </ul>
1333
+ </div>
1334
+ <div id="pop" popover anchor="btnExpand">
1335
+ <ul>
1336
+ ${options}
1337
+ </ul>
1338
+ </div>
1339
+ <button popovertarget="pop" id="btnExpand">&and;</button>
1340
+ </div>
1341
+ `;
1342
+ }
1343
+ static styles = i$1`
1344
+ :host {
1345
+ --text-highlight: red;
1346
+ --separator: silver;
1347
+ --padding-s: 0.12ch;
1348
+ display: flex;
1349
+ overflow: scroll;
1350
+ width: 100%;
1351
+ scroll-snap-type: x mandatory;
1352
+ scrollbar-width: none;
1353
+ }
1354
+ #btnExpand {
1355
+ scale: 0.5;
1356
+ margin:0;
1357
+ }
1358
+ .parts {
1359
+ display: flex;
1360
+ }
1361
+ .parts > div {
1362
+ cursor: pointer;
1363
+ margin-right: var(--padding-s);
1364
+
1365
+ }
1366
+ .parts > div:hover {
1367
+ color: var(--text-highlight);
1368
+ }
1369
+
1370
+ .horiz-select {
1371
+ display:flex;
1372
+ min-width: 5ch;
1373
+ }
1374
+ .horiz-select-items {
1375
+ overflow-y: scroll;
1376
+ scrollbar-width: none;
1377
+ scroll-behavior: smooth;
1378
+ }
1379
+
1380
+ .separator {
1381
+ margin-left: var(--padding-s);
1382
+ margin-right: var(--padding-s);
1383
+ color: var(--separator);
1384
+ }
1385
+ #pop {
1386
+ top: anchor(bottom);
1387
+ left: anchor(left);
1388
+ padding: 1ch;
1389
+ }
1390
+ #pop {
1391
+ ul {
1392
+ list-style: none;
1393
+ padding: 0;
1394
+ margin: 0;
1395
+ }
1396
+ li {
1397
+ cursor: pointer;
1398
+ opacity: 0.8;
1399
+ }
1400
+ li.previous {
1401
+ opacity: 0.9;
1402
+ }
1403
+ li:hover {
1404
+ opacity: 1;
1405
+ }
1406
+ }
1407
+
1408
+ .horiz-select-items {
1409
+ ul {
1410
+ list-style: none;
1411
+ padding: 0;
1412
+ margin: 0;
1413
+ display: inline;
1414
+ }
1415
+
1416
+ li {
1417
+ display: inline;
1418
+ margin-left: var(--padding-s);
1419
+ margin-right: var(--padding-s);
1420
+ cursor: pointer;
1421
+ opacity: 0.3;
1422
+ }
1423
+ li.previous {
1424
+ opacity: 0.6;
1425
+ }
1426
+ li:hover {
1427
+ opacity: 1;
1428
+ }
1429
+
1430
+ li:not(:last-child):after {
1431
+ content: ',';
1432
+ }
1433
+ }
1434
+ ::slotted(*),option {
1435
+ user-select: none;
1436
+ scroll-snap-align: start;
1437
+ border: 1px solid silver;
1438
+ color:red;
1439
+ }
1440
+ `;
1441
+ };
1442
+ __decorate([property({ type: Object })], CrumbNavigationElement.prototype, "tree", void 0);
1443
+ __decorate([property({ type: Object })], CrumbNavigationElement.prototype, "selectedNode", void 0);
1444
+ CrumbNavigationElement = __decorate([customElement("ixfx-crumb-navigation")], CrumbNavigationElement);
1445
+
1446
+ //#endregion
1447
+ //#region src/crumb-nav.ts
1448
+ let CrumbNavElement = class CrumbNavElement$1 extends i {
1449
+ segments = [];
1450
+ editing = false;
1451
+ editPath = ``;
1452
+ onNavPopup;
1453
+ constructor() {
1454
+ super();
1455
+ this.onclick = () => {
1456
+ console.log(`click`);
1457
+ this.editing = true;
1458
+ };
1459
+ this.segments = [
1460
+ {
1461
+ label: `root`,
1462
+ key: `root`
1463
+ },
1464
+ {
1465
+ label: `This PC`,
1466
+ key: `ThisPC`
1467
+ },
1468
+ {
1469
+ label: `Storage (D:)`,
1470
+ key: `D:`
1471
+ },
1472
+ {
1473
+ label: `Archives`,
1474
+ key: `Archives`
1475
+ },
1476
+ {
1477
+ label: `Tumblr`,
1478
+ key: `Tumblr`
1479
+ },
1480
+ {
1481
+ label: `whatevruk`,
1482
+ key: `whatevruk`
1483
+ }
1484
+ ];
1485
+ }
1486
+ updated(_changedProperties) {
1487
+ if (this.editing) {
1488
+ this.shadowRoot?.querySelector(`input`)?.focus();
1489
+ this.shadowRoot?.querySelector(`input`)?.select();
1490
+ }
1491
+ }
1492
+ setSegmentsWithPath(path, separator = `/`) {
1493
+ const split = path.split(separator);
1494
+ let root = ``;
1495
+ let segments = [];
1496
+ for (const s$3 of split) {
1497
+ root += s$3 + separator;
1498
+ segments.push({
1499
+ key: root,
1500
+ label: s$3
1501
+ });
1502
+ }
1503
+ this.segments = segments;
1504
+ this.editPath = path;
1505
+ }
1506
+ renderSegment(s$3, i$4) {
1507
+ const last = i$4 === this.segments.length - 1;
1508
+ const caret = x`<div .data=${s$3} @click=${this.onCaretClick} class="caret">&rsaquo;</div>`;
1509
+ return x`<div class="seg ${s$3.ensureVisible ? `chosen` : ``}" >
1510
+ <label .data=${s$3} title=${s$3.label} @click=${this.onLabelClick}>
1511
+ ${s$3.label}
1512
+ </label>
1513
+ ${last ? `` : caret}
1514
+ </div>`;
1515
+ }
1516
+ async onCaretClick(event) {
1517
+ const data = event.target.data;
1518
+ console.log(data);
1519
+ event.preventDefault();
1520
+ event.stopPropagation();
1521
+ if (this.onNavPopup) {
1522
+ for await (const item of this.onNavPopup(data)) console.log(item);
1523
+ console.log(`done`);
1524
+ }
1525
+ }
1526
+ onLabelClick(event) {
1527
+ const data = event.target.data;
1528
+ event.preventDefault();
1529
+ event.stopPropagation();
1530
+ this.dispatchEvent(new CustomEvent(`navigate`, { detail: data }));
1531
+ }
1532
+ render() {
1533
+ if (this.editing) return x`<input @keyup=${this.onInputKeyUp} @blur=${this.onInputBlur} value=${this.editPath} type="text">`;
1534
+ else {
1535
+ const segs = this.segments.map((s$3, index) => this.renderSegment(s$3, index));
1536
+ return x`${segs}`;
1537
+ }
1538
+ }
1539
+ onInputKeyUp(event) {
1540
+ const el = this.shadowRoot?.querySelector(`input`);
1541
+ if (!el) return;
1542
+ if (event.key === `Enter`) {
1543
+ console.log(`asf`);
1544
+ this.editPath = el.value;
1545
+ this.editing = false;
1546
+ } else if (event.key === `Escape`) this.editing = false;
1547
+ }
1548
+ onInputBlur() {
1549
+ this.editing = false;
1550
+ }
1551
+ static styles = i$1`
1552
+ :host {
1553
+ --text-highlight: red;
1554
+ --separator: silver;
1555
+ --padding: 0.5em;
1556
+ --padding-s: 0.1em;
1557
+ --padding-m: 0.25em;
1558
+ --hover-bg: darkgray;
1559
+ --hover-fg: unset;
1560
+ display: flex;
1561
+ width: 100%;
1562
+ gap: var(--padding-s);
1563
+ transition: all 2s ease-in-out;
1564
+ cursor: text;
1565
+ }
1566
+
1567
+ .seg {
1568
+ cursor: pointer;
1569
+ display:flex;
1570
+ flex-wrap: nowrap;
1571
+ align-items:center;
1572
+ user-select: none;
1573
+ overflow:hidden;
1574
+ }
1575
+
1576
+ input {
1577
+ appearance: none;
1578
+ border: 0;
1579
+ width: 100%;
1580
+ margin:var(--padding-s);
1581
+ padding: calc(2*var(--padding-s));
1582
+ font:unset;
1583
+ }
1584
+ .seg:hover {
1585
+ * {
1586
+ color: var(--hover-fg);
1587
+ background: color-mix(in srgb, var(--hover-bg) 20%, transparent);
1588
+ }
1589
+ }
1590
+ .seg {
1591
+ * {
1592
+ transition: all 0.2s ease-in-out;
1593
+ }
1594
+ }
1595
+
1596
+ label {
1597
+ height: 100%;
1598
+ white-space:nowrap;
1599
+ text-overflow: ellipsis;
1600
+ align-content: center;
1601
+ overflow: hidden;
1602
+ padding: 0 var(--padding-s) 0 var(--padding-s);
1603
+ }
1604
+
1605
+ label:hover,.caret:hover {
1606
+ background: var(--hover-bg) !important;
1607
+ }
1608
+
1609
+ .seg:hover,.seg.chosen {
1610
+ overflow:unset;
1611
+ }
1612
+
1613
+ .caret {
1614
+ padding: var(--padding-m);
1615
+ margin-left: var(--padding-s);
1616
+ margin-left: var(--padding-s);
1617
+ }
1618
+ `;
1619
+ };
1620
+ __decorate([property({ type: Object })], CrumbNavElement.prototype, "segments", void 0);
1621
+ __decorate([property({ type: Boolean })], CrumbNavElement.prototype, "editing", void 0);
1622
+ __decorate([property({ type: String })], CrumbNavElement.prototype, "editPath", void 0);
1623
+ CrumbNavElement = __decorate([customElement("ixfx-crumb-nav")], CrumbNavElement);
1624
+
1625
+ //#endregion
1626
+ //#region src/tabs/tab-list-item.ts
1627
+ let TabListItemElement = class TabListItemElement$1 extends i {
1628
+ closeable = true;
1629
+ render() {
1630
+ return x`<div ><slot part="header"></slot></div>`;
1631
+ }
1632
+ static styles = i$1`
1633
+ :host {
1634
+ --selected-colour: blue;
1635
+ --selected-border-width: 1px;
1636
+ --padding: 0.5ch;
1637
+ --hover-background: whitesmoke;
1638
+ display: inline;
1639
+ user-select:none;
1640
+ box-sizing: border-box;
1641
+ }
1642
+
1643
+ :host([selected])>div {
1644
+ color: var(--selected-colour);
1645
+ border-bottom: var(--selected-border-width) solid var(--selected-colour);
1646
+ }
1647
+ div {
1648
+ padding:var(--padding) calc(2*var(--padding)) var(--padding) calc(2*var(--padding));
1649
+ border-bottom: var(--selected-border-width) solid transparent;
1650
+
1651
+ }
1652
+
1653
+ div:hover {
1654
+ background-color: var(--hover-background);
1655
+ color:unset !important;
1656
+
1657
+ }
1658
+ `;
1659
+ };
1660
+ __decorate([property({ type: Boolean })], TabListItemElement.prototype, "closeable", void 0);
1661
+ TabListItemElement = __decorate([customElement("ixfx-tab-list-item")], TabListItemElement);
1662
+
1663
+ //#endregion
1664
+ //#region src/tabs/tab-list.ts
1665
+ let TabListElement = class TabListElement$1 extends i {
1666
+ horizontal = true;
1667
+ _listItems;
1668
+ render() {
1669
+ return x`
1670
+ <div tabindex=0 @keyup=${this.#onKeyUp} @click=${this.#onSlotClick} id="container" class=${this.horizontal ? `horizontal` : `vertical`}>
1671
+ <slot></slot>
1672
+ </div>`;
1673
+ }
1674
+ #onKeyUp = (event) => {
1675
+ const key = event.key;
1676
+ if (key === `ArrowUp` && !this.horizontal) {
1677
+ this.#selectPrevious();
1678
+ return;
1679
+ } else if (key === `ArrowDown` && !this.horizontal) {
1680
+ this.#selectNext();
1681
+ return;
1682
+ } else if (key === `ArrowRight` && this.horizontal) {
1683
+ this.#selectNext();
1684
+ return;
1685
+ } else if (key === `ArrowLeft` && this.horizontal) {
1686
+ this.#selectPrevious();
1687
+ return;
1688
+ }
1689
+ };
1690
+ getSelectedElement() {
1691
+ for (const el of this._listItems) if (this.#isSelected(el)) return el;
1692
+ }
1693
+ #isSelected(el) {
1694
+ const v$1 = el.getAttribute(`selected`);
1695
+ if (v$1 === null) return false;
1696
+ return el.hasAttribute(`selected`);
1697
+ }
1698
+ selectElement(el) {
1699
+ const existing = this.getSelectedElement();
1700
+ if (existing) existing.removeAttribute(`selected`);
1701
+ el.setAttribute(`selected`, ``);
1702
+ }
1703
+ #selectNext() {
1704
+ let found = false;
1705
+ for (const el of this._listItems) if (this.#isSelected(el) && !found) found = true;
1706
+ else if (found) {
1707
+ this.selectElement(el);
1708
+ break;
1709
+ }
1710
+ }
1711
+ #selectPrevious() {
1712
+ let prev;
1713
+ for (const el of this._listItems) if (this.#isSelected(el) && prev) this.selectElement(prev);
1714
+ else prev = el;
1715
+ }
1716
+ #onSlotClick = (event) => {
1717
+ this.focus();
1718
+ const t$2 = event.target;
1719
+ const previous = this.getSelectedElement();
1720
+ this.selectElement(t$2);
1721
+ const forId = t$2.getAttribute(`for`);
1722
+ this.dispatchEvent(new CustomEvent(`change`, { detail: {
1723
+ previous,
1724
+ selected: t$2.id,
1725
+ for: forId ?? ``
1726
+ } }));
1727
+ };
1728
+ static styles = i$1`
1729
+ :host {
1730
+ display: inline-block;
1731
+ --activated-colour: blue;
1732
+ --colur: pink;
1733
+ }
1734
+ text {
1735
+ user-select:none;
1736
+ }
1737
+ #container {
1738
+ display:flex;
1739
+ }
1740
+ #container.horizontal {
1741
+ flex-direction: row;
1742
+ }
1743
+ #container.vertical {
1744
+ flex-direction: column;
1745
+ }
1746
+
1747
+ ::slotted(.activated) {
1748
+ --colour: var(--activated-colour);
1749
+ }
1750
+ `;
1751
+ };
1752
+ __decorate([property({ type: Boolean })], TabListElement.prototype, "horizontal", void 0);
1753
+ __decorate([queryAssignedElements()], TabListElement.prototype, "_listItems", void 0);
1754
+ TabListElement = __decorate([customElement("ixfx-tab-list")], TabListElement);
1755
+
1756
+ //#endregion
1757
+ //#region src/tabs/tab-panel.ts
1758
+ let TabPanelElement = class TabPanelElement$1 extends i {
1759
+ render() {
1760
+ return x`<slot></slot>`;
1761
+ }
1762
+ static styles = i$1`
1763
+ :host {
1764
+ display:none;
1765
+ height:100%;
1766
+ width:100%;
1767
+ }
1768
+
1769
+ :host([selected]) {
1770
+ background: whitesmoke;
1771
+ display:block;
1772
+ }
1773
+ `;
1774
+ };
1775
+ TabPanelElement = __decorate([customElement("ixfx-tab-panel")], TabPanelElement);
1776
+
1777
+ //#endregion
1778
+ //#region src/tabs/tab-panels.ts
1779
+ let TabPanelsElement = class TabPanelsElement$1 extends i {
1780
+ _listItems;
1781
+ /**
1782
+ * Triggered when a panel is being de-selected
1783
+ */
1784
+ onUnselectedPanel;
1785
+ /**
1786
+ * Triggered before panel is selected
1787
+ */
1788
+ onSelectingPanel;
1789
+ /**
1790
+ * Triggered after panel is selected
1791
+ */
1792
+ onSelectedPanel;
1793
+ render() {
1794
+ return x`<slot></slot>`;
1795
+ }
1796
+ getSelectedElement() {
1797
+ for (const el of this._listItems) if (this.#isSelected(el)) return el;
1798
+ }
1799
+ #isSelected(el) {
1800
+ return el.hasAttribute(`selected`);
1801
+ }
1802
+ #unselect(el) {
1803
+ el.removeAttribute(`selected`);
1804
+ if (this.onUnselectedPanel) this.onUnselectedPanel(el.id, el);
1805
+ }
1806
+ #select(el) {
1807
+ if (this.onSelectingPanel) this.onSelectingPanel(el.id, el);
1808
+ el.setAttribute(`selected`, ``);
1809
+ if (this.onSelectedPanel) this.onSelectedPanel(el.id, el);
1810
+ }
1811
+ syncWithList(el) {
1812
+ const t$2 = el.getSelectedElement();
1813
+ if (!t$2) return;
1814
+ const forEl = t$2.getAttribute(`for`);
1815
+ if (!forEl) return;
1816
+ this.selectPanel(forEl);
1817
+ }
1818
+ selectPanel(id) {
1819
+ const current = this.getSelectedElement();
1820
+ if (current) {
1821
+ if (current.id === id) return;
1822
+ this.#unselect(current);
1823
+ }
1824
+ let found = false;
1825
+ for (const el of this._listItems) if (el.id === id) {
1826
+ this.#select(el);
1827
+ found = true;
1828
+ }
1829
+ return found;
1830
+ }
1831
+ static styles = i$1`
1832
+ :host {
1833
+ display: block;
1834
+ }
1835
+
1836
+ `;
1837
+ };
1838
+ __decorate([queryAssignedElements()], TabPanelsElement.prototype, "_listItems", void 0);
1839
+ TabPanelsElement = __decorate([customElement("ixfx-tab-panels")], TabPanelsElement);
1840
+
1841
+ //#endregion
1842
+ //#region src/split-layout/split-layout.ts
1843
+ let SplitLayoutElement = class SplitLayoutElement$1 extends i {
1844
+ layout = `vertical`;
1845
+ sizeA = ``;
1846
+ sizeB = ``;
1847
+ fixedA = false;
1848
+ fixedB = false;
1849
+ #elementBounds;
1850
+ render() {
1851
+ const sizePrefix = this.layout === `vertical` ? `width` : `height`;
1852
+ let sizeA = this.sizeA;
1853
+ let sizeB = this.sizeB;
1854
+ if (sizeA.length === 0 && sizeB.length === 0) sizeB = sizeA = `50%`;
1855
+ else if (sizeA.length === 0) sizeA = `auto`;
1856
+ else if (sizeB.length === 0) sizeB = `auto`;
1857
+ sizeA = `${sizePrefix}:${sizeA}`;
1858
+ sizeB = `${sizePrefix}:${sizeB}`;
1859
+ return x`
1860
+ <div id="zone">
1861
+ <slot style=${sizeA} name="a"></slot>
1862
+ <div @pointerdown=${this.#onResizeHandleDown} class="resize-handle"></div>
1863
+ <slot style=${sizeB} name="b"></slot>
1864
+ </div>`;
1865
+ }
1866
+ getZone() {
1867
+ if (!this.shadowRoot) return;
1868
+ const el = this.shadowRoot.querySelector(`#zone`);
1869
+ if (!el) return void 0;
1870
+ return el;
1871
+ }
1872
+ #onResizeHandleDown = (event) => {
1873
+ event.preventDefault();
1874
+ const zoneEl = this.getZone();
1875
+ if (zoneEl) zoneEl.classList.add(`user-resizing`);
1876
+ this.#elementBounds = this.getBoundingClientRect();
1877
+ window.addEventListener(`pointerup`, this.#onResizeHandleUp);
1878
+ window.addEventListener(`pointermove`, this.#onResizeHandleMove);
1879
+ };
1880
+ #onResizeHandleUp = (event) => {
1881
+ event.preventDefault();
1882
+ const zoneEl = this.getZone();
1883
+ if (zoneEl) zoneEl.classList.remove(`user-resizing`);
1884
+ window.removeEventListener(`pointerup`, this.#onResizeHandleUp);
1885
+ window.removeEventListener(`pointermove`, this.#onResizeHandleMove);
1886
+ };
1887
+ #onResizeHandleMove = (event) => {
1888
+ const bounds = this.#elementBounds;
1889
+ if (!bounds) return;
1890
+ if (this.layout === `horizontal`) {
1891
+ let y$2 = event.y - bounds.y;
1892
+ let relativeY = clamp(y$2 / bounds.height);
1893
+ if (this.fixedA) this.sizeA = `${relativeY * bounds.height}px`;
1894
+ else this.sizeA = `${relativeY * 100}%`;
1895
+ if (this.fixedB) this.sizeB = `${(1 - relativeY) * bounds.height}px`;
1896
+ else this.sizeB = `${(1 - relativeY) * 100}%`;
1897
+ } else {
1898
+ let x$1 = event.x - bounds.x;
1899
+ let relativeX = clamp(x$1 / bounds.width);
1900
+ if (this.fixedA) this.sizeA = `${relativeX * bounds.width}px`;
1901
+ else this.sizeA = `${relativeX * 100}%`;
1902
+ if (this.fixedB) this.sizeB = `${(1 - relativeX) * bounds.width}px`;
1903
+ else this.sizeB = `${(1 - relativeX) * 100}%`;
1904
+ }
1905
+ event.preventDefault();
1906
+ };
1907
+ static styles = i$1`
1908
+ :host {
1909
+ --handle-size: 2px;
1910
+ --handle-colour: whitesmoke;
1911
+ --handle-hover-colour: darkblue;
1912
+ --handle-active-colour: blue;
1913
+
1914
+ display: block;
1915
+ box-sizing: border-box;
1916
+ width:100%;
1917
+ height:100%;
1918
+ }
1919
+ * {
1920
+ box-sizing: border-box;
1921
+ }
1922
+ #zone {
1923
+ display:flex;
1924
+ height: 100%;
1925
+ }
1926
+ slot {
1927
+ display:block;
1928
+ }
1929
+ :slotted(*) {
1930
+ width: 100%;
1931
+ height: 100%;
1932
+ }
1933
+
1934
+ .resize-handle {
1935
+ background-color: var(--handle-colour);
1936
+ width: var(--handle-size);
1937
+ height:100%;
1938
+ cursor: ew-resize;
1939
+ }
1940
+ #zone.user-resizing {
1941
+ slot {
1942
+ opacity: 0.5;
1943
+ }
1944
+ .resize-handle {
1945
+ background-color: var(--handle-active-colour);
1946
+ }
1947
+ }
1948
+ .resize-handle:hover {
1949
+ background-color: var(--handle-hover-colour);
1950
+ }
1951
+
1952
+ :host([layout='horizontal']) {
1953
+ slot {
1954
+
1955
+ }
1956
+ #zone {
1957
+ flex-direction: column;
1958
+ }
1959
+ .resize-handle {
1960
+ background-color: silver;
1961
+ height: var(--handle-size);
1962
+ width:100%;
1963
+ cursor: ns-resize;
1964
+ }
1965
+ }
1966
+
1967
+ `;
1968
+ };
1969
+ __decorate([property({ type: String })], SplitLayoutElement.prototype, "layout", void 0);
1970
+ __decorate([property({ type: String })], SplitLayoutElement.prototype, "sizeA", void 0);
1971
+ __decorate([property({ type: String })], SplitLayoutElement.prototype, "sizeB", void 0);
1972
+ __decorate([property({ type: Boolean })], SplitLayoutElement.prototype, "fixedA", void 0);
1973
+ __decorate([property({ type: Boolean })], SplitLayoutElement.prototype, "fixedB", void 0);
1974
+ SplitLayoutElement = __decorate([customElement("ixfx-split-layout")], SplitLayoutElement);
1975
+
1976
+ //#endregion
1977
+ //#region src/charts/plot.ts
1978
+ let PlotElement = class PlotElement$1 extends i {
1979
+ streaming = true;
1980
+ hideLegend = false;
1981
+ maxLength = 500;
1982
+ dataWidth = 5;
1983
+ fixedMax = NaN;
1984
+ fixedMin = NaN;
1985
+ lineWidth = 2;
1986
+ renderStyle = `dot`;
1987
+ manualDraw = false;
1988
+ padding = 5;
1989
+ paused = false;
1990
+ #series = /* @__PURE__ */ new Map();
1991
+ #canvas;
1992
+ #drawing;
1993
+ #legendColour = ``;
1994
+ #hue = 0;
1995
+ canvasEl = createRef();
1996
+ seriesRanges = /* @__PURE__ */ new Map();
1997
+ get series() {
1998
+ return [...this.#series.values()];
1999
+ }
2000
+ get seriesCount() {
2001
+ return this.#series.size;
2002
+ }
2003
+ /**
2004
+ * Returns a `PlotElement` instance based on a query
2005
+ * ```js
2006
+ * PlotElement.fromQuery(`#someplot`); // PlotElement
2007
+ * ```
2008
+ *
2009
+ * Throws an error if query does not match.
2010
+ * @param query
2011
+ * @returns
2012
+ */
2013
+ static fromQuery(query) {
2014
+ const el = document.querySelector(query);
2015
+ if (!el) throw new Error(`Query does not match an element`);
2016
+ if (el.nodeName === "PLOT-ELEMENT") return el;
2017
+ throw new Error(`Elment is not a PlotElement ('${el.nodeName}')`);
2018
+ }
2019
+ /**
2020
+ * Delete a series.
2021
+ * Returns _true_ if there was a series to delete
2022
+ * @param name
2023
+ * @returns
2024
+ */
2025
+ deleteSeries(name) {
2026
+ name = name.toLowerCase();
2027
+ const s$3 = this.#series.get(name);
2028
+ if (!s$3) return false;
2029
+ this.#series.delete(name);
2030
+ return true;
2031
+ }
2032
+ /**
2033
+ * Keeps the series, but deletes its data
2034
+ * @param name
2035
+ * @returns
2036
+ */
2037
+ clearSeries(name) {
2038
+ name = name.toLowerCase();
2039
+ const s$3 = this.#series.get(name);
2040
+ if (!s$3) return false;
2041
+ this.#series.clear();
2042
+ return true;
2043
+ }
2044
+ /**
2045
+ * Delete all data & series
2046
+ */
2047
+ clear() {
2048
+ this.#series.clear();
2049
+ }
2050
+ /**
2051
+ * Keeps all series, but deletes their data
2052
+ */
2053
+ clearData() {
2054
+ for (const s$3 of this.#series.values()) s$3.clear();
2055
+ }
2056
+ render() {
2057
+ return x`<canvas ${ref(this.canvasEl)}></canvas>`;
2058
+ }
2059
+ #setupCanvas() {
2060
+ if (this.#canvas !== void 0) return this.#canvas;
2061
+ const canvas = this.canvasEl.value;
2062
+ if (!canvas) throw new Error(`canvas element not found`);
2063
+ const c$3 = new CanvasHelper(canvas);
2064
+ this.#canvas = c$3;
2065
+ this.#drawing = Drawing.makeHelper(c$3.ctx);
2066
+ return c$3;
2067
+ }
2068
+ connectedCallback() {
2069
+ super.connectedCallback();
2070
+ }
2071
+ firstUpdated(_changedProperties) {
2072
+ const ro = new ResizeObserver((event) => {
2073
+ const c$3 = this.#setupCanvas();
2074
+ if (!c$3) return;
2075
+ const entry = event[0];
2076
+ c$3.setLogicalSize(entry.contentRect);
2077
+ });
2078
+ ro.observe(this);
2079
+ this.updateColours();
2080
+ }
2081
+ updateColours() {
2082
+ this.#legendColour = getCssVariable(`legend-fg`, `black`);
2083
+ }
2084
+ plot(value, seriesName = ``, skipDrawing = false) {
2085
+ if (typeof value !== "number") throw new Error(`Can only add numbers. Got: ${typeof value}`);
2086
+ let s$3 = this.#series.get(seriesName.toLowerCase());
2087
+ if (s$3 === void 0) {
2088
+ s$3 = new PlotSeries(seriesName, this.colourGenerator(seriesName), this);
2089
+ this.#series.set(seriesName.toLowerCase(), s$3);
2090
+ }
2091
+ s$3.push(value);
2092
+ if (!this.manualDraw && !skipDrawing) this.draw();
2093
+ return s$3;
2094
+ }
2095
+ /**
2096
+ * Draw a set of key-value pairs as a batch.
2097
+ * @param value
2098
+ */
2099
+ plotObject(value) {
2100
+ for (const p$2 of Pathed.getPathsAndData(value, true)) this.plot(p$2.value, p$2.path, true);
2101
+ this.draw();
2102
+ }
2103
+ colourGenerator(_series) {
2104
+ const c$3 = Colour.HslSpace.scalar(this.#hue, .9, .4);
2105
+ this.#hue = Numbers.wrap(this.#hue + .1);
2106
+ return c$3;
2107
+ }
2108
+ draw() {
2109
+ if (this.paused) return;
2110
+ const c$3 = this.#canvas;
2111
+ const d$2 = this.#drawing;
2112
+ const padding = this.padding;
2113
+ if (!d$2 || !c$3) return;
2114
+ c$3.clear();
2115
+ const ctx = d$2.ctx;
2116
+ const axisYwidth = this.computeAxisYWidth(c$3);
2117
+ const remainingWidth = c$3.width - axisYwidth;
2118
+ const clLegend = this.computeLegend(c$3, remainingWidth, padding);
2119
+ const plotHeight = c$3.height - clLegend.bounds.height - padding;
2120
+ const cy = {
2121
+ width: axisYwidth,
2122
+ height: plotHeight
2123
+ };
2124
+ const cp = this.computePlot(c$3, plotHeight, cy.width, padding);
2125
+ const cl = {
2126
+ ...clLegend.bounds,
2127
+ x: cy.width,
2128
+ y: cp.y + cp.height + padding
2129
+ };
2130
+ let globalScaler;
2131
+ if (!Number.isNaN(this.fixedMax) && !Number.isNaN(this.fixedMin)) globalScaler = Numbers.scaler(this.fixedMin, this.fixedMax);
2132
+ if (!this.hideLegend) {
2133
+ ctx.save();
2134
+ ctx.translate(cl.x + padding, cl.y + padding);
2135
+ this.drawLegend(cl, d$2);
2136
+ ctx.restore();
2137
+ }
2138
+ ctx.save();
2139
+ ctx.translate(cp.x + padding, cp.y + padding);
2140
+ for (const series of this.#series.values()) {
2141
+ const seriesScale = this.seriesRanges.get(series.name);
2142
+ const data = seriesScale === void 0 ? globalScaler === void 0 ? series.getScaled() : series.getScaledBy(globalScaler) : series.getScaledBy(Numbers.scaler(seriesScale[0], seriesScale[1]));
2143
+ const colour = Colour.toCssColour(series.colour);
2144
+ switch (this.renderStyle) {
2145
+ case `line`:
2146
+ this.drawLineSeries(data, cp, d$2, colour);
2147
+ break;
2148
+ default: this.drawDotSeries(data, cp, d$2, colour);
2149
+ }
2150
+ }
2151
+ ctx.restore();
2152
+ }
2153
+ drawLegend(cl, d$2) {
2154
+ const textColour = this.#legendColour;
2155
+ const padding = this.padding;
2156
+ let x$1 = 0;
2157
+ let y$2 = padding;
2158
+ const swatchSize = 10;
2159
+ const ctx = d$2.ctx;
2160
+ for (const series of this.#series.values()) {
2161
+ ctx.fillStyle = Colour.toCssColour(series.colour);
2162
+ ctx.fillRect(x$1, y$2, swatchSize, swatchSize);
2163
+ ctx.fillStyle = textColour;
2164
+ x$1 += swatchSize + padding;
2165
+ const m$1 = ctx.measureText(series.name);
2166
+ ctx.textBaseline = `middle`;
2167
+ ctx.fillText(series.name, x$1, y$2 + swatchSize / 2);
2168
+ x$1 += m$1.width + padding;
2169
+ if (x$1 >= cl.width) {
2170
+ y$2 += 10 + padding;
2171
+ x$1 = 0;
2172
+ }
2173
+ }
2174
+ }
2175
+ drawLineSeries(data, cp, d$2, colour) {
2176
+ const pointWidth = this.streaming ? this.dataWidth : cp.width / data.length;
2177
+ let x$1 = 0;
2178
+ if (this.streaming) x$1 = cp.width - pointWidth * data.length;
2179
+ const pos = data.map((d$3) => {
2180
+ x$1 += pointWidth;
2181
+ return {
2182
+ x: x$1,
2183
+ y: (1 - d$3) * cp.height,
2184
+ radius: pointWidth
2185
+ };
2186
+ });
2187
+ const trimmed = pos.filter((p$2) => {
2188
+ if (p$2.x < 0) return false;
2189
+ return true;
2190
+ });
2191
+ d$2.connectedPoints(trimmed, {
2192
+ strokeStyle: colour,
2193
+ lineWidth: this.lineWidth
2194
+ });
2195
+ }
2196
+ drawDotSeries(data, cp, d$2, colour) {
2197
+ const pointWidth = this.streaming ? this.dataWidth : cp.width / data.length;
2198
+ let x$1 = 0;
2199
+ if (this.streaming) x$1 = cp.width - pointWidth * data.length;
2200
+ const pos = data.map((d$3) => {
2201
+ x$1 += pointWidth;
2202
+ return {
2203
+ x: x$1,
2204
+ y: (1 - d$3) * cp.height,
2205
+ radius: pointWidth
2206
+ };
2207
+ });
2208
+ const trimmed = pos.filter((p$2) => {
2209
+ if (p$2.x < 0) return false;
2210
+ return true;
2211
+ });
2212
+ d$2.dot(trimmed, {
2213
+ filled: true,
2214
+ fillStyle: colour
2215
+ });
2216
+ }
2217
+ computePlot(c$3, plotHeight, axisYwidth, padding) {
2218
+ return {
2219
+ x: axisYwidth,
2220
+ y: 0,
2221
+ width: c$3.width - axisYwidth - padding,
2222
+ height: plotHeight - padding - padding
2223
+ };
2224
+ }
2225
+ computeAxisYWidth(_c) {
2226
+ return 0;
2227
+ }
2228
+ #swatchSize = 10;
2229
+ computeLegend(c$3, maxWidth, padding) {
2230
+ if (this.hideLegend) return {
2231
+ bounds: {
2232
+ width: 0,
2233
+ height: 0
2234
+ },
2235
+ parts: []
2236
+ };
2237
+ const ctx = c$3.ctx;
2238
+ const series = [...this.#series.values()];
2239
+ let largestH = 0;
2240
+ const sizes = series.map((s$3) => {
2241
+ let width = this.#swatchSize + padding;
2242
+ const m$1 = ctx.measureText(s$3.name);
2243
+ width += m$1.width;
2244
+ const height = m$1.emHeightAscent + m$1.emHeightDescent;
2245
+ largestH = Math.max(height, largestH);
2246
+ return {
2247
+ width,
2248
+ height
2249
+ };
2250
+ });
2251
+ const parts = [];
2252
+ let x$1 = padding;
2253
+ let y$2 = padding;
2254
+ let usedWidthMax = 0;
2255
+ for (const s$3 of sizes) {
2256
+ parts.push({
2257
+ x: x$1,
2258
+ y: y$2,
2259
+ ...s$3
2260
+ });
2261
+ x$1 += s$3.width;
2262
+ usedWidthMax = Math.max(x$1, usedWidthMax);
2263
+ if (x$1 >= maxWidth) {
2264
+ x$1 = padding;
2265
+ y$2 += largestH + padding;
2266
+ }
2267
+ }
2268
+ const bounds = {
2269
+ width: usedWidthMax,
2270
+ height: y$2 + largestH + padding
2271
+ };
2272
+ return {
2273
+ bounds,
2274
+ parts
2275
+ };
2276
+ }
2277
+ getSeries(name) {
2278
+ return this.#series.get(name);
2279
+ }
2280
+ static styles = i$1`
2281
+ :host {
2282
+ width: 100%;
2283
+ height: 100%;
2284
+ display: block;
2285
+ }
2286
+ `;
2287
+ };
2288
+ __decorate([property$1({
2289
+ attribute: `streaming`,
2290
+ type: Boolean
2291
+ })], PlotElement.prototype, "streaming", void 0);
2292
+ __decorate([property$1({
2293
+ attribute: `hide-legend`,
2294
+ type: Boolean
2295
+ })], PlotElement.prototype, "hideLegend", void 0);
2296
+ __decorate([property$1({
2297
+ attribute: `max-length`,
2298
+ type: Number
2299
+ })], PlotElement.prototype, "maxLength", void 0);
2300
+ __decorate([property$1({
2301
+ attribute: `data-width`,
2302
+ type: Number
2303
+ })], PlotElement.prototype, "dataWidth", void 0);
2304
+ __decorate([property$1({
2305
+ attribute: `fixed-max`,
2306
+ type: Number
2307
+ })], PlotElement.prototype, "fixedMax", void 0);
2308
+ __decorate([property$1({
2309
+ attribute: `fixed-min`,
2310
+ type: Number
2311
+ })], PlotElement.prototype, "fixedMin", void 0);
2312
+ __decorate([property$1({
2313
+ attribute: `line-width`,
2314
+ type: Number
2315
+ })], PlotElement.prototype, "lineWidth", void 0);
2316
+ __decorate([property$1({
2317
+ attribute: `render`,
2318
+ type: String
2319
+ })], PlotElement.prototype, "renderStyle", void 0);
2320
+ __decorate([property$1({
2321
+ attribute: `manual-draw`,
2322
+ type: Boolean
2323
+ })], PlotElement.prototype, "manualDraw", void 0);
2324
+ PlotElement = __decorate([customElement$1(`ixfx-plot-element`)], PlotElement);
2325
+ var PlotSeries = class {
2326
+ data = [];
2327
+ minSeen = Number.MAX_SAFE_INTEGER;
2328
+ maxSeen = Number.MIN_SAFE_INTEGER;
2329
+ constructor(name, colour, plot) {
2330
+ this.name = name;
2331
+ this.colour = colour;
2332
+ this.plot = plot;
2333
+ }
2334
+ clear() {
2335
+ this.data = [];
2336
+ this.resetScale();
2337
+ }
2338
+ /**
2339
+ * Returns a copy of the data scaled by the current
2340
+ * range of the data
2341
+ * @returns
2342
+ */
2343
+ getScaled() {
2344
+ let min = this.minSeen;
2345
+ let max = this.maxSeen;
2346
+ if (Number.isNaN(min)) min = 0;
2347
+ if (Number.isNaN(max)) max = 1;
2348
+ const s$3 = Numbers.scaler(min, max);
2349
+ return this.getScaledBy(s$3);
2350
+ }
2351
+ getScaledBy(scaler) {
2352
+ return this.data.map((v$1) => {
2353
+ if (typeof v$1 !== `number`) throw new Error(`Data should just be numbers. Got: ${typeof v$1}`);
2354
+ if (Number.isNaN(v$1)) throw new Error(`data contains NaN`);
2355
+ const scaled = scaler(v$1);
2356
+ if (Number.isNaN(scaled)) throw new Error(`NaN. v: ${v$1} scaled: ${scaled}`);
2357
+ return Numbers.clamp(scaled);
2358
+ });
2359
+ }
2360
+ push(value) {
2361
+ if (typeof value !== "number") throw new Error(`Can only add numbers. Got: ${typeof value}`);
2362
+ this.data.push(value);
2363
+ if (this.data.length > this.plot.maxLength && this.plot.streaming) this.data = this.data.slice(1);
2364
+ this.minSeen = Math.min(this.minSeen, value);
2365
+ this.maxSeen = Math.max(this.maxSeen, value);
2366
+ }
2367
+ resetScale() {
2368
+ this.minSeen = Number.MAX_SAFE_INTEGER;
2369
+ this.maxSeen = Number.MIN_SAFE_INTEGER;
2370
+ }
2371
+ };
2372
+
2373
+ //#endregion
2374
+ //#region src/util/compare.ts
2375
+ /**
2376
+ * Sort numbers in ascending order.
2377
+ *
2378
+ * ```js
2379
+ * [10, 4, 5, 0].sort(numericComparer);
2380
+ * // Yields: [0, 4, 5, 10]
2381
+ * [10, 4, 5, 0].sort(comparerInverse(numericComparer));
2382
+ * // Yields: [ 10, 5, 4, 0]
2383
+ * ```
2384
+ * @param x
2385
+ * @param y
2386
+ * @returns
2387
+ */
2388
+ const numericComparer = (x$1, y$2) => {
2389
+ if (x$1 === y$2) return 0;
2390
+ if (x$1 > y$2) return 1;
2391
+ return -1;
2392
+ };
2393
+ /**
2394
+ * Compares numbers by numeric value, otherwise uses the default
2395
+ * logic of string comparison.
2396
+ *
2397
+ * Is an ascending sort:
2398
+ * * b, a, c -> a, b, c
2399
+ * * 10, 5, 100 -> 5, 10, 100
2400
+ *
2401
+ * Returns -1 if x is less than y
2402
+ * Returns 1 if x is greater than y
2403
+ * Returns 0 if x is the same as y
2404
+ * @param x
2405
+ * @param y
2406
+ * @see {@link comparerInverse} Inverted order
2407
+ * @returns
2408
+ */
2409
+ const defaultComparer = (x$1, y$2) => {
2410
+ if (typeof x$1 === `number` && typeof y$2 === `number`) return numericComparer(x$1, y$2);
2411
+ return jsComparer(x$1, y$2);
2412
+ };
2413
+ /**
2414
+ * Default sort comparer, following same sematics as Array.sort.
2415
+ * Consider using {@link defaultComparer} to get more logical sorting of numbers.
2416
+ *
2417
+ * Note: numbers are sorted in alphabetical order, eg:
2418
+ * ```js
2419
+ * [ 10, 20, 5, 100 ].sort(jsComparer); // same as .sort()
2420
+ * // Yields: [10, 100, 20, 5]
2421
+ * ```
2422
+ *
2423
+ * Returns -1 if x is less than y
2424
+ * Returns 1 if x is greater than y
2425
+ * Returns 0 if x is the same as y
2426
+ * @param x
2427
+ * @param y
2428
+ * @returns
2429
+ */
2430
+ const jsComparer = (x$1, y$2) => {
2431
+ if (x$1 === void 0 && y$2 === void 0) return 0;
2432
+ if (x$1 === void 0) return 1;
2433
+ if (y$2 === void 0) return -1;
2434
+ const xString = defaultToString(x$1);
2435
+ const yString = defaultToString(y$2);
2436
+ if (xString < yString) return -1;
2437
+ if (xString > yString) return 1;
2438
+ return 0;
2439
+ };
2440
+ const defaultToString = (object) => {
2441
+ if (object === null) return `null`;
2442
+ if (typeof object === `boolean` || typeof object === `number`) return object.toString();
2443
+ if (typeof object === `string`) return object;
2444
+ if (typeof object === `symbol`) throw new TypeError(`Symbol cannot be converted to string`);
2445
+ return JSON.stringify(object);
2446
+ };
2447
+
2448
+ //#endregion
2449
+ //#region src/util/key-value.ts
2450
+ const getSorter = (sortStyle) => {
2451
+ switch (sortStyle) {
2452
+ case `value`: return sorterByValueIndex(1, false);
2453
+ case `value-reverse`: return sorterByValueIndex(1, true);
2454
+ case `key`: return sorterByValueIndex(0, false);
2455
+ case `key-reverse`: return sorterByValueIndex(0, true);
2456
+ default: throw new Error(`Unknown sorting value '${sortStyle}'. Expecting: value, value-reverse, key or key-reverse`);
2457
+ }
2458
+ };
2459
+ const sorterByValueIndex = (index, reverse = false) => {
2460
+ return (values) => {
2461
+ const s$3 = values.toSorted((a$2, b$2) => defaultComparer(a$2[index], b$2[index]));
2462
+ if (reverse) return s$3.reverse();
2463
+ return s$3;
2464
+ };
2465
+ };
2466
+
2467
+ //#endregion
2468
+ //#region src/charts/frequency-histogram-plot.ts
2469
+ /**
2470
+ * Creates and drives a HistogramVis instance.
2471
+ * Data should be an outer array containing two-element arrays for each
2472
+ * data point. The first element of the inner array is expected to be the key, the second the frequency.
2473
+ * For example, `[`apples`, 2]` means the key `apples` was counted twice.
2474
+ *
2475
+ * Usage:
2476
+ * .sortBy() automatically sorts prior to visualisation. By default off.
2477
+ * .update(data) full set of data to plot
2478
+ * .clear() empties plot - same as calling `update([])`
2479
+ * .el - The `HistogramVis` instance, or undefined if not created/disposed
2480
+ *
2481
+ * ```
2482
+ * const plot = new FrequencyHistogramPlot(document.getElementById('histogram'));
2483
+ * plot.sortBy('key'); // Automatically sort by key
2484
+ * ...
2485
+ * plot.update([[`apples`, 2], [`oranges', 0], [`bananas`, 5]])
2486
+ * ```
2487
+ *
2488
+ * @export
2489
+ * @class FrequencyHistogramPlot
2490
+ */
2491
+ var FrequencyHistogramPlot = class {
2492
+ el;
2493
+ #sorter;
2494
+ constructor(el) {
2495
+ this.el = el;
2496
+ }
2497
+ setAutoSort(sortStyle) {
2498
+ this.#sorter = getSorter(sortStyle);
2499
+ }
2500
+ clear() {
2501
+ if (this.el === void 0) return;
2502
+ this.el.data = [];
2503
+ }
2504
+ dispose() {
2505
+ const el = this.el;
2506
+ if (el === void 0) return;
2507
+ el.remove();
2508
+ }
2509
+ update(data) {
2510
+ if (this.el === void 0) {
2511
+ console.warn(`FrequencyHistogramPlot this.el undefined`);
2512
+ return;
2513
+ }
2514
+ this.el.data = this.#sorter === void 0 ? [...data] : this.#sorter(data);
2515
+ }
2516
+ };
2517
+
2518
+ //#endregion
2519
+ //#region src/charts/histogram-vis.ts
2520
+ const jsonData = (object) => {
2521
+ if (object === null || object === void 0 || object === `undefined`) return;
2522
+ try {
2523
+ if (typeof object === `string`) {
2524
+ if (object.length === 0) return;
2525
+ const o$4 = JSON.parse(object);
2526
+ if (!Array.isArray(o$4)) {
2527
+ console.error(`Histogram innerText should be JSON array`);
2528
+ return;
2529
+ }
2530
+ for (const [index, element] of o$4.entries()) {
2531
+ if (!Array.isArray(element)) {
2532
+ console.error(`Histogram array should consist of inner arrays`);
2533
+ return;
2534
+ }
2535
+ if (element.length !== 2) {
2536
+ console.error(`Histogram inner arrays should consist of two elements`);
2537
+ return;
2538
+ }
2539
+ if (typeof element[0] !== `string`) {
2540
+ console.error(`First element of inner array should be a string (index ${index})`);
2541
+ return;
2542
+ }
2543
+ if (typeof element[1] !== `number`) {
2544
+ console.error(`Second element of inner array should be a number (index ${index})`);
2545
+ return;
2546
+ }
2547
+ }
2548
+ return o$4;
2549
+ }
2550
+ } catch (error) {
2551
+ console.log(object);
2552
+ console.error(error);
2553
+ }
2554
+ };
2555
+ let HistogramVis = class HistogramVis$1 extends i {
2556
+ static styles = i$1`
2557
+ :host {
2558
+ }
2559
+ div.container {
2560
+ display: flex;
2561
+ flex-direction: column;
2562
+ height: 100%;
2563
+ }
2564
+ div.chart {
2565
+ display: grid;
2566
+ flex: 1;
2567
+ grid-template-rows: 1fr 1px min-content;
2568
+ justify-items: center;
2569
+ }
2570
+ div.bar {
2571
+ display: flex;
2572
+ flex-direction: column-reverse;
2573
+ align-items: center;
2574
+ justify-self: normal;
2575
+ padding-left: 0.3vw;
2576
+ padding-right: 0.3vw;
2577
+ }
2578
+ div.bar > div.barTrack {
2579
+ background-color: var(--histogram-bar-color, gray);
2580
+ align-self: stretch;
2581
+ }
2582
+ div.xAxisLabels,
2583
+ div.data {
2584
+ font-size: min(1vw, 1em);
2585
+ color: var(--histogram-label-color, currentColor);
2586
+ }
2587
+ div.xAxisLabels {
2588
+ width: 100%;
2589
+ text-overflow: ellipsis;
2590
+ overflow: hidden;
2591
+ white-space: nowrap;
2592
+ text-align: center;
2593
+ }
2594
+ div.xAxis {
2595
+ background-color: var(--histogram-axis-color, silver);
2596
+ width: 100%;
2597
+ height: 100%;
2598
+ }
2599
+ `;
2600
+ constructor() {
2601
+ super();
2602
+ this.data = [];
2603
+ this.showDataLabels = true;
2604
+ this.height = `100%`;
2605
+ this.showXAxis = true;
2606
+ this.json = void 0;
2607
+ }
2608
+ connectedCallback() {
2609
+ if (!this.hasAttribute(`json`)) this.setAttribute(`json`, this.innerText);
2610
+ super.connectedCallback();
2611
+ }
2612
+ barTemplate(bar, index, _totalBars) {
2613
+ const { percentage } = bar;
2614
+ const [key, freq] = bar.data;
2615
+ const rowStart = 1;
2616
+ const rowEnd = 2;
2617
+ const colStart = index + 1;
2618
+ const colEnd = colStart + 1;
2619
+ const dataLabel = x`<div class="data">${freq}</div>`;
2620
+ const xAxis = x`${key}`;
2621
+ return x`
2622
+ <div
2623
+ class="bar"
2624
+ style="grid-area: ${rowStart} / ${colStart} / ${rowEnd} / ${colEnd}"
2625
+ >
2626
+ <div class="barTrack" style="height: ${(percentage ?? 0) * 100}%"></div>
2627
+ ${this.showDataLabels ? dataLabel : ``}
2628
+ </div>
2629
+ <div
2630
+ class="xAxisLabels"
2631
+ style="grid-area: ${rowStart + 2} / ${colStart} / ${rowEnd + 2} / ${colEnd}"
2632
+ >
2633
+ ${this.showXAxis ? xAxis : ``}
2634
+ </div>
2635
+ `;
2636
+ }
2637
+ render() {
2638
+ if ((this.data === void 0 || this.data.length === 0) && this.json === void 0) return x``;
2639
+ const d$2 = this.data ?? this.json;
2640
+ const length = d$2.length;
2641
+ const highestCount = Math.max(...d$2.map((d$3) => d$3[1]));
2642
+ const bars = d$2.map((kv) => ({
2643
+ data: kv,
2644
+ percentage: kv[1] / highestCount
2645
+ }));
2646
+ const xAxis = x`
2647
+ <div
2648
+ class="xAxis"
2649
+ style="grid-area: 2 / 1 / 3 / ${d$2.length + 1}"
2650
+ ></div>
2651
+ `;
2652
+ const height = this.height ? `height: ${this.height};` : ``;
2653
+ const h$2 = x`
2654
+ <style>
2655
+ div.chart {
2656
+ grid-template-columns: repeat(${d$2.length}, minmax(2px, 1fr));
2657
+ }
2658
+ </style>
2659
+ <div class="container" style="${height}">
2660
+ <div class="chart">
2661
+ ${repeat(bars, (bar) => bar.data[0], (b$2, index) => this.barTemplate(b$2, index, length))}
2662
+ ${this.showXAxis ? xAxis : ``}
2663
+ </div>
2664
+ </div>
2665
+ `;
2666
+ return h$2;
2667
+ }
2668
+ };
2669
+ __decorate([property$1()], HistogramVis.prototype, "data", void 0);
2670
+ __decorate([property$1()], HistogramVis.prototype, "showDataLabels", void 0);
2671
+ __decorate([property$1()], HistogramVis.prototype, "height", void 0);
2672
+ __decorate([property$1()], HistogramVis.prototype, "showXAxis", void 0);
2673
+ __decorate([property$1({
2674
+ converter: jsonData,
2675
+ type: Object
2676
+ })], HistogramVis.prototype, "json", void 0);
2677
+ HistogramVis = __decorate([customElement$1(`histogram-vis`)], HistogramVis);
2678
+
2679
+ //#endregion
2680
+ //#region src/index.ts
2681
+ const init = () => {
2682
+ console.log(`Init`);
2683
+ };
2684
+
2685
+ //#endregion
2686
+ export { CrumbNavElement, CrumbNavigationElement, DialElement, FrequencyHistogramPlot, HistogramVis, PlotElement, PlotSeries, SelectHorizontalElement, SplitLayoutElement, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, init };
2687
+ //# sourceMappingURL=index.js.map