@xsynaptic/sonic-ui 0.6.0 → 0.8.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.
Files changed (118) hide show
  1. package/README.md +4 -0
  2. package/dist/default/define/spectrum.js +7 -0
  3. package/dist/default/define.js +1 -0
  4. package/dist/default/elements/button.js +33 -4
  5. package/dist/default/elements/dial.js +5 -1
  6. package/dist/default/elements/display-element.js +77 -0
  7. package/dist/default/elements/envelope.js +15 -3
  8. package/dist/default/elements/meter.js +1 -1
  9. package/dist/default/elements/radio-group.js +3 -2
  10. package/dist/default/elements/readout-claim.js +0 -29
  11. package/dist/default/elements/scale.js +43 -0
  12. package/dist/default/elements/slider.js +82 -3
  13. package/dist/default/elements/sonic-element.js +2 -67
  14. package/dist/default/elements/spectrum.js +230 -0
  15. package/dist/default/elements/switch.js +1 -1
  16. package/dist/default/elements/value-element.js +81 -91
  17. package/dist/default/elements/wave-element.js +59 -9
  18. package/dist/default/elements/waveform.js +56 -10
  19. package/dist/default/elements/wavestrip.js +45 -21
  20. package/dist/default/elements/xy.js +3 -2
  21. package/dist/default/index.js +2 -1
  22. package/dist/default/lib/canvas-surface.js +7 -4
  23. package/dist/default/lib/frame-timeline.js +2 -2
  24. package/dist/default/lib/hover-preview.js +46 -0
  25. package/dist/default/lib/marker-rider.js +7 -4
  26. package/dist/default/lib/mirror-children.js +64 -0
  27. package/dist/default/lib/owned-control.js +10 -0
  28. package/dist/default/lib/pointer-drag.js +7 -2
  29. package/dist/default/lib/spectrum-columns.js +74 -0
  30. package/dist/default/lib/spectrum-levels.js +55 -0
  31. package/dist/default/lib/strip-scene.js +12 -1
  32. package/dist/default/lib/time-regions.js +8 -1
  33. package/dist/dev/define/spectrum.d.ts +2 -0
  34. package/dist/dev/define/spectrum.js +8 -0
  35. package/dist/dev/define/spectrum.js.map +1 -0
  36. package/dist/dev/define.d.ts +3 -1
  37. package/dist/dev/define.js +1 -0
  38. package/dist/dev/elements/button.d.ts +2 -0
  39. package/dist/dev/elements/button.js +33 -4
  40. package/dist/dev/elements/button.js.map +1 -1
  41. package/dist/dev/elements/dial.js +5 -1
  42. package/dist/dev/elements/dial.js.map +1 -1
  43. package/dist/dev/elements/display-element.d.ts +29 -0
  44. package/dist/dev/elements/display-element.js +78 -0
  45. package/dist/dev/elements/display-element.js.map +1 -0
  46. package/dist/dev/elements/envelope.js +15 -3
  47. package/dist/dev/elements/envelope.js.map +1 -1
  48. package/dist/dev/elements/meter.js +1 -1
  49. package/dist/dev/elements/radio-group.js +3 -2
  50. package/dist/dev/elements/radio-group.js.map +1 -1
  51. package/dist/dev/elements/readout-claim.js +0 -29
  52. package/dist/dev/elements/readout-claim.js.map +1 -1
  53. package/dist/dev/elements/scale.js +44 -0
  54. package/dist/dev/elements/scale.js.map +1 -0
  55. package/dist/dev/elements/slider.d.ts +9 -0
  56. package/dist/dev/elements/slider.js +82 -3
  57. package/dist/dev/elements/slider.js.map +1 -1
  58. package/dist/dev/elements/sonic-element.d.ts +0 -8
  59. package/dist/dev/elements/sonic-element.js +3 -90
  60. package/dist/dev/elements/sonic-element.js.map +1 -1
  61. package/dist/dev/elements/spectrum.d.ts +59 -0
  62. package/dist/dev/elements/spectrum.js +231 -0
  63. package/dist/dev/elements/spectrum.js.map +1 -0
  64. package/dist/dev/elements/switch.js +1 -1
  65. package/dist/dev/elements/value-element.d.ts +8 -6
  66. package/dist/dev/elements/value-element.js +81 -91
  67. package/dist/dev/elements/value-element.js.map +1 -1
  68. package/dist/dev/elements/wave-element.d.ts +8 -2
  69. package/dist/dev/elements/wave-element.js +59 -9
  70. package/dist/dev/elements/wave-element.js.map +1 -1
  71. package/dist/dev/elements/waveform.d.ts +12 -4
  72. package/dist/dev/elements/waveform.js +56 -10
  73. package/dist/dev/elements/waveform.js.map +1 -1
  74. package/dist/dev/elements/wavestrip.d.ts +7 -0
  75. package/dist/dev/elements/wavestrip.js +45 -21
  76. package/dist/dev/elements/wavestrip.js.map +1 -1
  77. package/dist/dev/elements/xy.js +3 -2
  78. package/dist/dev/elements/xy.js.map +1 -1
  79. package/dist/dev/index.d.ts +4 -1
  80. package/dist/dev/index.js +2 -1
  81. package/dist/dev/lib/canvas-surface.d.ts +4 -3
  82. package/dist/dev/lib/canvas-surface.js +7 -4
  83. package/dist/dev/lib/canvas-surface.js.map +1 -1
  84. package/dist/dev/lib/frame-timeline.js +2 -2
  85. package/dist/dev/lib/frame-timeline.js.map +1 -1
  86. package/dist/dev/lib/hover-preview.js +47 -0
  87. package/dist/dev/lib/hover-preview.js.map +1 -0
  88. package/dist/dev/lib/marker-rider.js +7 -4
  89. package/dist/dev/lib/marker-rider.js.map +1 -1
  90. package/dist/dev/lib/mirror-children.js +80 -0
  91. package/dist/dev/lib/mirror-children.js.map +1 -0
  92. package/dist/dev/lib/owned-control.js +23 -0
  93. package/dist/dev/lib/owned-control.js.map +1 -0
  94. package/dist/dev/lib/pointer-drag.js +7 -2
  95. package/dist/dev/lib/pointer-drag.js.map +1 -1
  96. package/dist/dev/lib/spectrum-columns.js +75 -0
  97. package/dist/dev/lib/spectrum-columns.js.map +1 -0
  98. package/dist/dev/lib/spectrum-levels.js +56 -0
  99. package/dist/dev/lib/spectrum-levels.js.map +1 -0
  100. package/dist/dev/lib/strip-scene.js +12 -1
  101. package/dist/dev/lib/strip-scene.js.map +1 -1
  102. package/dist/dev/lib/time-regions.js +8 -1
  103. package/dist/dev/lib/time-regions.js.map +1 -1
  104. package/dist/skins/flat.css +2 -1
  105. package/dist/styles/button.css +28 -1
  106. package/dist/styles/controls.css +1 -0
  107. package/dist/styles/envelope.css +30 -30
  108. package/dist/styles/led.css +18 -2
  109. package/dist/styles/material.css +90 -29
  110. package/dist/styles/meter.css +22 -18
  111. package/dist/styles/panel.css +2 -1
  112. package/dist/styles/slider.css +42 -5
  113. package/dist/styles/spectrum.css +105 -0
  114. package/dist/styles/switch.css +10 -7
  115. package/dist/styles/waveform.css +38 -16
  116. package/dist/styles/wavestrip.css +22 -4
  117. package/dist/styles/xy.css +14 -30
  118. package/package.json +2 -1
@@ -1,8 +1,8 @@
1
- import { clamp, toNumber } from "../lib/math.js";
2
- import { placeChildren, requireChild } from "../lib/render.js";
1
+ import { clamp, toNumber, trimFloat } from "../lib/math.js";
3
2
  import { writeAttribute } from "../lib/write-attribute.js";
4
3
  import { SonicFormElement } from "./form-element.js";
5
- import { copyNode } from "../lib/copy-node.js";
4
+ import { requireChild } from "../lib/render.js";
5
+ import { bindDrag } from "../lib/pointer-drag.js";
6
6
  import { ReadoutClaim } from "./readout-claim.js";
7
7
  import { Readout } from "./readout.js";
8
8
  import { ValueEntry } from "./value-entry.js";
@@ -10,9 +10,7 @@ import { dragThresholdPx, startDrag, stepDrag } from "../lib/drag-step.js";
10
10
  import { focusByPointer } from "../lib/focus-by-pointer.js";
11
11
  import { isMenuPress, isResetPress } from "../lib/modifier-press.js";
12
12
  import { parseNumberList } from "../lib/number-list.js";
13
- import { bindDrag } from "../lib/pointer-drag.js";
14
13
  import { readPxProperty } from "../lib/read-px-property.js";
15
- import { readRegions } from "../lib/time-regions.js";
16
14
  import { resetKeys, valueMapping } from "../lib/value-mapping.js";
17
15
 
18
16
  //#region src/elements/value-element.ts
@@ -37,18 +35,6 @@ const roleAttributes = [
37
35
  "role",
38
36
  "tabindex"
39
37
  ];
40
- function scaleValue(mark) {
41
- const text = mark.dataset.sonicValue?.trim();
42
- return text ? Number(text) : NaN;
43
- }
44
- function scaleMark(original) {
45
- const mark = copyNode(original);
46
- if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return void 0;
47
- if (!Number.isFinite(scaleValue(mark))) return void 0;
48
- const isTick = mark.childElementCount === 0 && mark.textContent.trim() === "";
49
- mark.classList.add(isTick ? "sonic-scale-tick" : "sonic-scale-label");
50
- return mark;
51
- }
52
38
  let link;
53
39
  function linkValue(element) {
54
40
  return link(element);
@@ -63,7 +49,9 @@ var SonicValueElement = class extends SonicFormElement {
63
49
  "notched",
64
50
  "origin",
65
51
  "readout",
52
+ "spoken-step",
66
53
  "step",
54
+ "tabindex",
67
55
  "taper",
68
56
  "value",
69
57
  "positions"
@@ -89,13 +77,6 @@ var SonicValueElement = class extends SonicFormElement {
89
77
  }
90
78
  });
91
79
  }
92
- get buffered() {
93
- return this.#buffered.map(([start, end]) => [start, end]);
94
- }
95
- set buffered(regions) {
96
- this.#buffered = regions ? readRegions(regions).toSorted((first, second) => first[0] - second[0]) : [];
97
- this.render();
98
- }
99
80
  get default() {
100
81
  return this.optionalNumberAttribute("default");
101
82
  }
@@ -176,6 +157,9 @@ var SonicValueElement = class extends SonicFormElement {
176
157
  set parseValue(parse) {
177
158
  this.#parseValue = parse;
178
159
  }
160
+ get pointerType() {
161
+ return this.#dragging()?.pointerType;
162
+ }
179
163
  get positions() {
180
164
  return parseNumberList(this.getAttribute("positions"));
181
165
  }
@@ -188,6 +172,12 @@ var SonicValueElement = class extends SonicFormElement {
188
172
  set readout(isShown) {
189
173
  this.reflect("readout", isShown);
190
174
  }
175
+ get spokenStep() {
176
+ return this.optionalNumberAttribute("spoken-step");
177
+ }
178
+ set spokenStep(value) {
179
+ this.reflect("spoken-step", value);
180
+ }
191
181
  get step() {
192
182
  return this.numberAttribute("step", 1);
193
183
  }
@@ -220,16 +210,16 @@ var SonicValueElement = class extends SonicFormElement {
220
210
  return this.#textFor(this.#value);
221
211
  }
222
212
  #asked;
223
- #buffered = [];
224
213
  #claim = new ReadoutClaim(() => {
225
214
  this.#renderHold();
226
215
  });
227
216
  #entry;
228
- #escapeWatch;
229
217
  #formatSpokenValue;
230
218
  #formatValue;
219
+ #heldAt;
231
220
  #instance = String(instanceCount += 1);
232
221
  #isModulated = false;
222
+ #isRevealed = false;
233
223
  #keyScrub;
234
224
  #land;
235
225
  #limit;
@@ -239,7 +229,6 @@ var SonicValueElement = class extends SonicFormElement {
239
229
  #pointerDrag;
240
230
  #positions;
241
231
  #readout;
242
- #scaleMarks;
243
232
  #value = 0;
244
233
  #watchers = /* @__PURE__ */ new Set();
245
234
  attributeChangedCallback(name) {
@@ -258,7 +247,7 @@ var SonicValueElement = class extends SonicFormElement {
258
247
  this.render();
259
248
  }
260
249
  connectedCallback() {
261
- this.upgradeProperties("buffered", "default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "step", "taper", "positions", "detent", "formatValue", "formatSpokenValue", "keyStep", "parseValue", "value");
250
+ this.upgradeProperties("default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "spokenStep", "step", "taper", "positions", "detent", "formatValue", "formatSpokenValue", "keyStep", "parseValue", "value");
262
251
  super.connectedCallback();
263
252
  }
264
253
  bindGestures(control, signal, grab) {
@@ -284,6 +273,7 @@ var SonicValueElement = class extends SonicFormElement {
284
273
  fromValue,
285
274
  isOutside: false,
286
275
  isRevealed: false,
276
+ pointerType: event.pointerType,
287
277
  revealTimer: void 0,
288
278
  state: this.#startDrag(control, axis, event)
289
279
  };
@@ -322,19 +312,6 @@ var SonicValueElement = class extends SonicFormElement {
322
312
  this.#concealKeyReveal();
323
313
  }, { once: true });
324
314
  }
325
- bindScale(control, marks, signal) {
326
- this.#scaleMarks = marks;
327
- this.mirrorChildren({
328
- control,
329
- copy: scaleMark,
330
- isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]"),
331
- isPassed: (child) => child instanceof Element && child.matches(".sonic-led"),
332
- place: (copies) => {
333
- placeChildren(marks, copies);
334
- this.#renderScale();
335
- }
336
- }, signal);
337
- }
338
315
  controlOrientation() {}
339
316
  controlRole() {
340
317
  return "slider";
@@ -342,13 +319,10 @@ var SonicValueElement = class extends SonicFormElement {
342
319
  heldFrom() {
343
320
  return this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;
344
321
  }
345
- heldWrite(_next) {}
346
- holdChanged() {}
347
- hoverReadout(value) {
348
- this.#claim.hover(value);
349
- this.#renderReadout();
350
- this.#watchEscape(value !== void 0);
322
+ heldWrite(next) {
323
+ this.#heldAt = next;
351
324
  }
325
+ holdChanged() {}
352
326
  input(next) {
353
327
  const previous = this.#value;
354
328
  this.#write(this.#limit ? clamp(next, ...this.#limit) : next);
@@ -359,6 +333,9 @@ var SonicValueElement = class extends SonicFormElement {
359
333
  }));
360
334
  return true;
361
335
  }
336
+ isEditing() {
337
+ return this.#entry?.isOpen === true;
338
+ }
362
339
  isRevealed() {
363
340
  return this.#claim.isRevealed;
364
341
  }
@@ -384,17 +361,33 @@ var SonicValueElement = class extends SonicFormElement {
384
361
  originValue() {
385
362
  return this.origin ?? this.mapping().bounds[0];
386
363
  }
364
+ playback() {
365
+ const from = this.heldFrom();
366
+ return from === void 0 ? this.#value : this.#heldAt ?? from;
367
+ }
368
+ previewValue() {}
387
369
  proportionsChanged() {}
388
370
  readModulationValue() {
389
371
  return this.#modulationValue;
390
372
  }
391
373
  readoutValue() {
392
- return this.#claim.shown(this.#value, this.readout).value ?? this.#value;
374
+ return this.#shown().value ?? this.#value;
393
375
  }
394
376
  render() {
395
377
  if (this.isBound()) this.#renderControl();
396
378
  for (const listener of this.#watchers) listener();
397
379
  }
380
+ renderReadout() {
381
+ const readout = this.#readout;
382
+ if (!readout) return;
383
+ const { isOpen, value } = this.#shown();
384
+ const text = value === void 0 ? void 0 : this.#textFor(value);
385
+ readout.bubble.show({
386
+ anchor: readout.anchor,
387
+ isOpen: isOpen && text !== "",
388
+ text
389
+ });
390
+ }
398
391
  restoreState(state) {
399
392
  this.value = Number(state);
400
393
  }
@@ -440,7 +433,6 @@ var SonicValueElement = class extends SonicFormElement {
440
433
  },
441
434
  text: () => this.#parseValue ? this.valueText : String(this.#value),
442
435
  toggle: (isOpen) => {
443
- this.#claim.edit(isOpen);
444
436
  if (isOpen) this.forwardNaming(input, true);
445
437
  this.toggleState("editing", isOpen);
446
438
  this.render();
@@ -501,10 +493,13 @@ var SonicValueElement = class extends SonicFormElement {
501
493
  drag.state = this.#withinLimit(mapping, state);
502
494
  if (value === void 0) return;
503
495
  if (!wasEngaged) this.#reveal(drag);
496
+ const isCrossing = isOutside !== drag.isOutside;
497
+ if (isCrossing) {
498
+ drag.isOutside = isOutside;
499
+ this.toggleState("cancelling", isOutside);
500
+ }
504
501
  this.input(isOutside ? drag.fromValue : value);
505
- if (isOutside === drag.isOutside) return;
506
- drag.isOutside = isOutside;
507
- this.#renderDragReveal(drag);
502
+ if (isCrossing) this.#renderDragReveal(drag);
508
503
  }
509
504
  #endHolds() {
510
505
  this.#entry?.close(false);
@@ -536,7 +531,9 @@ var SonicValueElement = class extends SonicFormElement {
536
531
  #releaseDrag(drag) {
537
532
  clearTimeout(drag.revealTimer);
538
533
  this.#claim.conceal("drag");
534
+ this.toggleState("cancelling", false);
539
535
  this.#renderHold();
536
+ this.#showRevealed(false);
540
537
  if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
541
538
  this.#springBack();
542
539
  }
@@ -545,59 +542,43 @@ var SonicValueElement = class extends SonicFormElement {
545
542
  if (this.#entry?.isOpen) {
546
543
  for (const name of roleAttributes) control.removeAttribute(name);
547
544
  this.forwardNaming(control, false);
548
- this.#renderReadout();
545
+ this.renderReadout();
549
546
  return;
550
547
  }
551
548
  const [low, high] = this.mapping().bounds;
552
549
  writeAttribute(control, "role", this.controlRole());
553
550
  writeAttribute(control, "aria-valuemin", String(low));
554
551
  writeAttribute(control, "aria-valuemax", String(high));
555
- writeAttribute(control, "aria-valuenow", String(this.#value));
552
+ writeAttribute(control, "aria-valuenow", String(this.#spokenNow()));
556
553
  if (orientation) writeAttribute(control, "aria-orientation", orientation);
557
554
  writeAttribute(control, "aria-valuetext", (this.#formatSpokenValue ?? this.#formatValue)?.(this.#value));
558
555
  this.forwardNaming(control, true);
559
556
  this.#renderDisabled(control);
560
- this.#renderReadout();
557
+ this.renderReadout();
561
558
  }
562
559
  #renderControl() {
563
560
  this.draw();
564
- this.#renderScale();
565
561
  this.toggleState("at-origin", !this.isWrapping() && this.#value === this.mapping().snap(this.originValue()));
566
562
  this.#renderAria(this.focusTarget(), this.controlOrientation());
567
563
  }
568
564
  #renderDisabled(control) {
569
565
  const isDisabled = this.isDisabled();
570
566
  writeAttribute(control, "aria-disabled", isDisabled ? "true" : void 0);
571
- writeAttribute(control, "tabindex", isDisabled ? void 0 : "0");
567
+ const stop = this.getAttribute("tabindex") === "-1" ? "-1" : "0";
568
+ writeAttribute(control, "tabindex", isDisabled ? void 0 : stop);
572
569
  }
573
570
  #renderDragReveal(drag) {
574
- if (drag.isRevealed && !drag.isOutside) this.#claim.reveal("drag");
571
+ const isRevealed = drag.isRevealed && !drag.isOutside;
572
+ if (isRevealed) this.#claim.reveal("drag");
575
573
  else this.#claim.conceal("drag");
576
574
  this.#renderHold();
575
+ this.#showRevealed(isRevealed);
577
576
  }
578
577
  #renderHold() {
579
- this.#renderReadout();
578
+ if (this.heldFrom() === void 0) this.#heldAt = void 0;
579
+ this.renderReadout();
580
580
  this.holdChanged();
581
581
  }
582
- #renderReadout() {
583
- const readout = this.#readout;
584
- if (!readout) return;
585
- const { isOpen, value } = this.#claim.shown(this.#value, this.readout);
586
- readout.bubble.show({
587
- anchor: readout.anchor,
588
- isOpen,
589
- text: value === void 0 ? void 0 : this.#textFor(value)
590
- });
591
- }
592
- #renderScale() {
593
- const marks = this.#scaleMarks?.children ?? [];
594
- const mapping = this.mapping();
595
- for (const mark of marks) {
596
- if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;
597
- const at = String(mapping.proportionOf(scaleValue(mark)));
598
- if (mark.style.getPropertyValue("--_sonic-scale-at") !== at) mark.style.setProperty("--_sonic-scale-at", at);
599
- }
600
- }
601
582
  #reset() {
602
583
  this.#commit(this.default ?? NaN);
603
584
  }
@@ -616,6 +597,28 @@ var SonicValueElement = class extends SonicFormElement {
616
597
  }
617
598
  this.input(next);
618
599
  }
600
+ #shown() {
601
+ if (this.isEditing()) return {
602
+ isOpen: true,
603
+ value: void 0
604
+ };
605
+ const isRevealed = this.#claim.isRevealed;
606
+ const preview = isRevealed ? void 0 : this.previewValue();
607
+ return {
608
+ isOpen: (isRevealed || preview !== void 0) && this.readout,
609
+ value: preview ?? this.#value
610
+ };
611
+ }
612
+ #showRevealed(isRevealed) {
613
+ if (isRevealed === this.#isRevealed) return;
614
+ this.#isRevealed = isRevealed;
615
+ this.toggleState("revealed", isRevealed);
616
+ this.dispatchEvent(new Event("sonic-reveal", { bubbles: true }));
617
+ }
618
+ #spokenNow() {
619
+ const step = this.spokenStep;
620
+ return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#value / step) * step) : this.#value;
621
+ }
619
622
  #springBack() {
620
623
  const target = this.springTarget();
621
624
  if (target === void 0) return;
@@ -645,19 +648,6 @@ var SonicValueElement = class extends SonicFormElement {
645
648
  #textFor(value) {
646
649
  return this.#formatValue?.(value) ?? String(value);
647
650
  }
648
- #watchEscape(isHovered) {
649
- if (!isHovered) {
650
- this.#escapeWatch?.abort();
651
- this.#escapeWatch = void 0;
652
- return;
653
- }
654
- if (this.#escapeWatch) return;
655
- const watch = new AbortController();
656
- this.#escapeWatch = watch;
657
- this.ownerDocument.addEventListener("keydown", (event) => {
658
- if (event.key === "Escape" && this.#claim.dismiss()) this.#renderHold();
659
- }, { signal: watch.signal });
660
- }
661
651
  #withinLimit(mapping, state) {
662
652
  const limit = this.#limit;
663
653
  if (!limit || mapping.isWrapping) return state;
@@ -1 +1 @@
1
- {"version":3,"file":"value-element.js","names":[],"sources":["../../../src/elements/value-element.ts"],"sourcesContent":["import type { DragState } from '#lib/drag-step.ts';\nimport type { PointerDrag } from '#lib/pointer-drag.ts';\nimport type { TimeRegions } from '#lib/time-regions.ts';\nimport type { ValueMapping } from '#lib/value-mapping.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { ReadoutClaim, revealMs } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { ValueEntry } from '#elements/value-entry.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { dragThresholdPx, startDrag, stepDrag } from '#lib/drag-step.ts';\nimport { focusByPointer } from '#lib/focus-by-pointer.ts';\nimport { clamp, toNumber } from '#lib/math.ts';\nimport { isMenuPress, isResetPress } from '#lib/modifier-press.ts';\nimport { parseNumberList } from '#lib/number-list.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { placeChildren, requireChild } from '#lib/render.ts';\nimport { readRegions } from '#lib/time-regions.ts';\nimport { resetKeys, valueMapping } from '#lib/value-mapping.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\nexport interface ValueAxis {\n\tfromProportion?: number;\n\tisKeptOnCancel?: boolean;\n\toutside?: (event: PointerEvent) => boolean;\n\tposition: (event: PointerEvent) => number;\n\ttravelPx: number;\n}\n\ninterface ValueDrag extends ValueAxis {\n\tfromValue: number;\n\tisOutside: boolean;\n\tisRevealed: boolean;\n\trevealTimer: ReturnType<typeof setTimeout> | undefined;\n\tstate: DragState;\n}\n\ninterface KeyScrub {\n\tfromValue: number;\n\tkey: string;\n}\n\nconst detentZonePx = 8;\nconst fallbackTravelPx = 160;\n\nlet instanceCount = 0;\n\nconst proportionAttributes = new Set(['max', 'midpoint', 'min', 'notched', 'positions', 'taper']);\n\nconst roleAttributes = [\n\t'aria-disabled',\n\t'aria-orientation',\n\t'aria-valuemax',\n\t'aria-valuemin',\n\t'aria-valuenow',\n\t'aria-valuetext',\n\t'role',\n\t'tabindex',\n];\n\ntype ScaleMark = HTMLElement | SVGElement;\n\nfunction scaleValue(mark: ScaleMark): number {\n\tconst text = mark.dataset.sonicValue?.trim();\n\n\treturn text ? Number(text) : NaN;\n}\n\nfunction scaleMark(original: ChildNode): ScaleMark | undefined {\n\tconst mark = copyNode(original);\n\tif (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return undefined;\n\tif (!Number.isFinite(scaleValue(mark))) return undefined;\n\n\tconst isTick = mark.childElementCount === 0 && mark.textContent.trim() === '';\n\n\tmark.classList.add(isTick ? 'sonic-scale-tick' : 'sonic-scale-label');\n\n\treturn mark;\n}\n\ntype ValueLanding = (target: number, direction: -1 | 0 | 1) => number;\n\nexport interface ValueLink {\n\tinput: (next: number, isMover?: boolean) => boolean;\n\tisDisabled: () => boolean;\n\tisHeld: () => boolean;\n\tland: (resolve: undefined | ValueLanding) => void;\n\tlimit: (bounds: [number, number] | undefined) => void;\n\tmapping: () => ValueMapping;\n\tvalue: () => number;\n\twatch: (listener: () => void) => () => void;\n}\n\n// Filled from inside the class, so it reaches protected members and nothing lands on the element's public type\nlet link: (element: SonicValueElement) => ValueLink;\n\nexport function linkValue(element: SonicValueElement): ValueLink {\n\treturn link(element);\n}\n\nexport abstract class SonicValueElement extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'detent',\n\t\t'max',\n\t\t'midpoint',\n\t\t'min',\n\t\t'notched',\n\t\t'origin',\n\t\t'readout',\n\t\t'step',\n\t\t'taper',\n\t\t'value',\n\t\t'positions',\n\t];\n\n\tstatic {\n\t\tlink = (element) => ({\n\t\t\tinput: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),\n\t\t\tisDisabled: () => element.isDisabled(),\n\t\t\tisHeld: () => element.#isHeld(),\n\t\t\tland: (resolve) => {\n\t\t\t\telement.#land = resolve;\n\t\t\t},\n\t\t\tlimit: (bounds) => {\n\t\t\t\telement.#limit = bounds;\n\t\t\t},\n\t\t\tmapping: () => element.mapping(),\n\t\t\tvalue: () => element.#value,\n\t\t\twatch: (listener) => {\n\t\t\t\telement.#watchers.add(listener);\n\n\t\t\t\treturn () => {\n\t\t\t\t\telement.#watchers.delete(listener);\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tget buffered(): Array<[number, number]> {\n\t\treturn this.#buffered.map(([start, end]) => [start, end]);\n\t}\n\n\tset buffered(regions: TimeRegions | undefined) {\n\t\tthis.#buffered = regions\n\t\t\t? readRegions(regions).toSorted((first, second) => first[0] - second[0])\n\t\t\t: [];\n\t\tthis.render();\n\t}\n\n\tget default(): number | undefined {\n\t\treturn this.optionalNumberAttribute('default');\n\t}\n\n\tset default(value: number | undefined) {\n\t\tthis.reflect('default', value);\n\t}\n\n\tget detent(): number | undefined {\n\t\treturn this.optionalNumberAttribute('detent');\n\t}\n\n\tset detent(value: number | undefined) {\n\t\tthis.reflect('detent', value);\n\t}\n\n\tget dimmed(): boolean {\n\t\treturn this.hasAttribute('dimmed');\n\t}\n\n\tset dimmed(isDimmed: boolean) {\n\t\tthis.reflect('dimmed', isDimmed);\n\t}\n\n\tget doublePress(): 'entry' | 'reset' {\n\t\treturn this.getAttribute('double-press') === 'reset' ? 'reset' : 'entry';\n\t}\n\n\tset doublePress(gesture: 'entry' | 'reset' | undefined) {\n\t\tthis.reflect('double-press', gesture);\n\t}\n\n\tget formatSpokenValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatSpokenValue;\n\t}\n\n\tset formatSpokenValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatSpokenValue = format;\n\t\tthis.render();\n\t}\n\n\tget formatValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatValue;\n\t}\n\n\tset formatValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatValue = format;\n\t\tthis.render();\n\t}\n\n\tget keyStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('key-step');\n\t}\n\n\tset keyStep(value: number | undefined) {\n\t\tthis.reflect('key-step', value);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 100);\n\t}\n\n\tset max(value: number | undefined) {\n\t\tthis.reflect('max', value);\n\t}\n\n\tget midpoint(): number | undefined {\n\t\treturn this.optionalNumberAttribute('midpoint');\n\t}\n\n\tset midpoint(value: number | undefined) {\n\t\tthis.reflect('midpoint', value);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tset min(value: number | undefined) {\n\t\tthis.reflect('min', value);\n\t}\n\n\tget notched(): boolean {\n\t\treturn this.hasAttribute('notched');\n\t}\n\n\tset notched(isNotched: boolean) {\n\t\tthis.reflect('notched', isNotched);\n\t}\n\n\tget origin(): number | undefined {\n\t\treturn this.optionalNumberAttribute('origin');\n\t}\n\n\tset origin(value: number | undefined) {\n\t\tthis.reflect('origin', value);\n\t}\n\n\tget parseValue(): ((text: string) => number) | undefined {\n\t\treturn this.#parseValue;\n\t}\n\n\tset parseValue(parse: ((text: string) => number) | undefined) {\n\t\tthis.#parseValue = parse;\n\t}\n\n\tget positions(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('positions'));\n\t}\n\n\tset positions(positions: Array<number> | undefined) {\n\t\tthis.reflect('positions', positions?.join(' '));\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isShown: boolean) {\n\t\tthis.reflect('readout', isShown);\n\t}\n\n\tget step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\tset step(value: number | undefined) {\n\t\tthis.reflect('step', value);\n\t}\n\n\tget taper(): 'linear' | 'log' {\n\t\treturn this.getAttribute('taper') === 'log' ? 'log' : 'linear';\n\t}\n\n\tset taper(curve: 'linear' | 'log' | undefined) {\n\t\tthis.reflect('taper', curve);\n\t}\n\n\tget value(): number {\n\t\treturn this.#value;\n\t}\n\n\tset value(next: null | number | undefined) {\n\t\t// A framework removes a prop by setting the property to `undefined`\n\t\tif (next === undefined || next === null) {\n\t\t\tthis.formResetCallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = toNumber(next);\n\n\t\tif (this.#isHeld()) {\n\t\t\tthis.heldWrite(value);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#write(value);\n\t\tif (Number.isFinite(value)) this.#asked = value;\n\t}\n\n\tget valueText(): string {\n\t\treturn this.#textFor(this.#value);\n\t}\n\n\t#asked: number | undefined;\n\n\t#buffered: Array<[number, number]> = [];\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderHold();\n\t});\n\n\t#entry: undefined | ValueEntry;\n\n\t#escapeWatch: AbortController | undefined;\n\n\t#formatSpokenValue: ((value: number) => string) | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t#isModulated = false;\n\n\t#keyScrub: KeyScrub | undefined;\n\n\t#land: undefined | ValueLanding;\n\n\t#limit: [number, number] | undefined;\n\n\t// Every attribute it reads is observed; a subclass adding an input to `isWrapping()` has to observe it\n\t#mapping: undefined | ValueMapping;\n\n\t#modulationValue: number | undefined;\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#pointerDrag: PointerDrag<ValueDrag> | undefined;\n\n\t#positions: Array<number> | undefined;\n\n\t#readout: undefined | { anchor: HTMLElement; bubble: Readout };\n\n\t#scaleMarks: HTMLElement | undefined;\n\n\t#value = 0;\n\n\treadonly #watchers = new Set<() => void>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tthis.#mapping = undefined;\n\t\tthis.#positions = parseNumberList(this.getAttribute('positions'));\n\t\tif (name === 'value') {\n\t\t\tif (this.#isHeld()) {\n\t\t\t\tthis.heldWrite(this.numberAttribute('value', this.min));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.#asked = undefined;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) this.#endHolds();\n\n\t\tthis.#value = this.mapping().snap(this.#asked ?? this.numberAttribute('value', this.min));\n\t\tif (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();\n\t\tthis.render();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(\n\t\t\t'buffered',\n\t\t\t'default',\n\t\t\t'dimmed',\n\t\t\t'doublePress',\n\t\t\t'max',\n\t\t\t'midpoint',\n\t\t\t'min',\n\t\t\t'notched',\n\t\t\t'origin',\n\t\t\t'readout',\n\t\t\t'step',\n\t\t\t'taper',\n\t\t\t'positions',\n\t\t\t'detent',\n\t\t\t'formatValue',\n\t\t\t'formatSpokenValue',\n\t\t\t'keyStep',\n\t\t\t'parseValue',\n\t\t\t'value',\n\t\t);\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected bindGestures(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\tgrab: (event: PointerEvent) => undefined | ValueAxis,\n\t): void {\n\t\tconst entry = this.#bindEntry(control, signal);\n\n\t\tthis.#pointerDrag = bindDrag<ValueDrag>(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tcancel: (drag) => {\n\t\t\t\t\tif (drag.isKeptOnCancel !== true) this.input(drag.fromValue);\n\t\t\t\t},\n\t\t\t\tgrab: (event) => {\n\t\t\t\t\tif (isMenuPress(event) || this.isDisabled() || entry.isOpen) return;\n\n\t\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\t\t// A click listener above makes WebKit send a tap's compatibility mousedown, which blurs the entry a double tap just opened\n\t\t\t\t\tif (event.pointerType === 'touch') event.preventDefault();\n\t\t\t\t\tfocusByPointer(control);\n\t\t\t\t\tif (isResetPress(event)) {\n\t\t\t\t\t\tthis.#reset();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fromValue = this.#value;\n\t\t\t\t\tconst axis = grab(event);\n\t\t\t\t\tif (!axis) return;\n\n\t\t\t\t\tconst drag: ValueDrag = {\n\t\t\t\t\t\t...axis,\n\t\t\t\t\t\tfromValue,\n\t\t\t\t\t\tisOutside: false,\n\t\t\t\t\t\tisRevealed: false,\n\t\t\t\t\t\trevealTimer: undefined,\n\t\t\t\t\t\tstate: this.#startDrag(control, axis, event),\n\t\t\t\t\t};\n\n\t\t\t\t\tdrag.revealTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.#reveal(drag);\n\t\t\t\t\t}, revealMs);\n\n\t\t\t\t\treturn drag;\n\t\t\t\t},\n\t\t\t\tlift: (drag, event) => {\n\t\t\t\t\tconst tap = drag.state.isEngaged ? undefined : this.tapTarget();\n\n\t\t\t\t\tif (tap !== undefined) {\n\t\t\t\t\t\tentry.forgetPress();\n\t\t\t\t\t\tthis.#commit(tap);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!entry.press(event) || this.springTarget() !== undefined) return;\n\n\t\t\t\t\tif (this.doublePress === 'reset') this.#reset();\n\t\t\t\t\telse entry.open();\n\t\t\t\t},\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\tthis.#dragTo(drag, event);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tthis.#releaseDrag(drag);\n\t\t\t\t},\n\t\t\t\ttoggle: (isDragging) => {\n\t\t\t\t\tthis.toggleState('dragging', isDragging);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'pointercancel',\n\t\t\t() => {\n\t\t\t\tentry.forgetPress();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindKeys(control, entry, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected bindScale(control: HTMLElement, marks: HTMLElement, signal: AbortSignal): void {\n\t\tthis.#scaleMarks = marks;\n\t\tthis.mirrorChildren(\n\t\t\t{\n\t\t\t\tcontrol,\n\t\t\t\tcopy: scaleMark,\n\t\t\t\tisCopied: (child) => child instanceof Element && child.matches('[data-sonic-value]'),\n\t\t\t\tisPassed: (child) => child instanceof Element && child.matches('.sonic-led'),\n\t\t\t\tplace: (copies) => {\n\t\t\t\t\tplaceChildren(marks, copies);\n\t\t\t\t\tthis.#renderScale();\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tprotected controlOrientation(): 'horizontal' | 'vertical' | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected abstract draw(): void;\n\n\tprotected abstract override focusTarget(): HTMLElement;\n\n\tprotected heldFrom(): number | undefined {\n\t\treturn this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;\n\t}\n\n\tprotected heldWrite(_next: number): void {\n\t\t// Dropped unless a subclass draws where playback carries on\n\t}\n\n\tprotected holdChanged(): void {\n\t\t// Only a subclass draws a hold\n\t}\n\n\tprotected hoverReadout(value: number | undefined): void {\n\t\tthis.#claim.hover(value);\n\t\tthis.#renderReadout();\n\t\tthis.#watchEscape(value !== undefined);\n\t}\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#value;\n\n\t\tthis.#write(this.#limit ? clamp(next, ...this.#limit) : next);\n\t\tif (this.#value === previous) return false;\n\n\t\tthis.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n\n\t\treturn true;\n\t}\n\n\tprotected isRevealed(): boolean {\n\t\treturn this.#claim.isRevealed;\n\t}\n\n\tprotected isWrapping(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected mapping(): ValueMapping {\n\t\tif (this.#mapping) return this.#mapping;\n\n\t\tconst { detent, midpoint } = this;\n\n\t\tthis.#mapping = valueMapping({\n\t\t\t...(detent === undefined ? {} : { detent }),\n\t\t\t...(this.#positions ? { positions: this.#positions } : {}),\n\t\t\tmax: this.max,\n\t\t\t...(midpoint === undefined ? {} : { midpoint }),\n\t\t\tisNotched: this.notched,\n\t\t\tisWrapping: this.isWrapping(),\n\t\t\tmin: this.min,\n\t\t\tstep: this.step,\n\t\t\ttaper: this.taper,\n\t\t});\n\n\t\treturn this.#mapping;\n\t}\n\n\tprotected originValue(): number {\n\t\treturn this.origin ?? this.mapping().bounds[0];\n\t}\n\n\tprotected proportionsChanged(): void {\n\t\t// Runs when every proportion moves, never per input\n\t}\n\n\tprotected readModulationValue(): number | undefined {\n\t\treturn this.#modulationValue;\n\t}\n\n\tprotected readoutValue(): number {\n\t\treturn this.#claim.shown(this.#value, this.readout).value ?? this.#value;\n\t}\n\n\tprotected render(): void {\n\t\tif (this.isBound()) this.#renderControl();\n\t\tfor (const listener of this.#watchers) listener();\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected scrubsKeyRepeat(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected tapTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number {\n\t\treturn Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));\n\t}\n\n\tprotected writeModulationValue(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tnext: null | number | undefined,\n\t): void {\n\t\tconst value = next === undefined || next === null ? undefined : toNumber(next);\n\t\tif (value !== undefined && !Number.isFinite(value)) return;\n\n\t\tthis.#modulationValue = value;\n\t\tif (this.isBound()) this.#writeModulationProportion(control, prefix);\n\t}\n\n\tprotected writeProportions(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tmodulation: number,\n\t): void {\n\t\tconst { style } = control;\n\t\tconst mapping = this.mapping();\n\t\tconst value = mapping.proportionOf(this.#value);\n\t\tconst reach = mapping.proportionOf(this.#value + modulation);\n\t\tconst { positionCount } = mapping;\n\n\t\tstyle.setProperty(`--_sonic-${prefix}-value`, String(value));\n\t\tstyle.setProperty(\n\t\t\t`--_sonic-${prefix}-origin`,\n\t\t\tString(mapping.proportionOf(this.originValue())),\n\t\t);\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-from`, String(Math.min(value, reach)));\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-to`, String(Math.max(value, reach)));\n\t\tif (positionCount === undefined) style.removeProperty(`--_sonic-${prefix}-position-count`);\n\t\telse style.setProperty(`--_sonic-${prefix}-position-count`, String(positionCount));\n\t\tthis.#writeModulationProportion(control, prefix);\n\t}\n\n\t#bindEntry(control: HTMLElement, signal: AbortSignal): ValueEntry {\n\t\tconst input = requireChild(control, 'input', HTMLInputElement);\n\t\tconst bubble = control.querySelector<HTMLElement>('[popover]');\n\n\t\t// Chrome's issues panel flags a form field with no id or name; a `name` would submit it\n\t\tinput.id = `sonic-entry-${this.#instance}`;\n\t\tif (bubble) this.#readout = { anchor: control, bubble: new Readout(bubble) };\n\n\t\tconst entry = new ValueEntry(input, {\n\t\t\tcommit: (text) => {\n\t\t\t\t// eslint-disable-next-line unicorn/prefer-number-coercion -- `Number('')` is 0; an emptied field should leave the value alone\n\t\t\t\tthis.#commit((this.#parseValue ?? Number.parseFloat)(text));\n\t\t\t},\n\t\t\t// `Number.parseFloat` reads \"5 kHz\" as 5\n\t\t\ttext: () => (this.#parseValue ? this.valueText : String(this.#value)),\n\t\t\ttoggle: (isOpen) => {\n\t\t\t\tthis.#claim.edit(isOpen);\n\t\t\t\tif (isOpen) this.forwardNaming(input, true);\n\t\t\t\tthis.toggleState('editing', isOpen);\n\t\t\t\tthis.render();\n\t\t\t},\n\t\t});\n\n\t\tthis.#entry = entry;\n\t\tentry.bind(control, signal);\n\n\t\treturn entry;\n\t}\n\n\t#bindKeys(control: HTMLElement, entry: ValueEntry, signal: AbortSignal): void {\n\t\tcontrol.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (this.isDisabled() || event.defaultPrevented || event.target !== control) return;\n\n\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tif (this.springTarget() !== undefined) return;\n\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tentry.open();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst next = this.#keyTarget(event.key);\n\t\t\t\tif (next === undefined) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#keyTo(event, next);\n\t\t\t\tthis.#claim.reveal('keys');\n\t\t\t\tthis.#renderHold();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'keyup',\n\t\t\t(event) => {\n\t\t\t\t// macOS sends no `keyup` for a key let go while Cmd is down\n\t\t\t\tconst isMeta = event.key === 'Meta';\n\n\t\t\t\tif (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();\n\t\t\t\tif (isMeta && this.#dragging()) return;\n\t\t\t\tif (isMeta || this.mapping().keyTarget(event.key, this.#value) !== undefined) {\n\t\t\t\t\tthis.#springBack();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t\tthis.#springBack();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#commit(next: number, direction: -1 | 0 | 1 = 0): void {\n\t\tconst landed = Number.isFinite(next) ? (this.#land?.(next, direction) ?? next) : next;\n\n\t\tif (this.input(landed)) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#concealKeyReveal(): void {\n\t\tif (this.#claim.conceal('keys')) this.#renderHold();\n\t}\n\n\t#dragging(): undefined | ValueDrag {\n\t\treturn this.#pointerDrag?.current();\n\t}\n\n\t#dragTo(drag: ValueDrag, event: PointerEvent): void {\n\t\tconst isOutside = drag.outside?.(event) === true;\n\t\tconst wasEngaged = drag.state.isEngaged;\n\t\tconst mapping = this.mapping();\n\t\tconst { state, value } = stepDrag(mapping, drag.state, {\n\t\t\tisFine: event.shiftKey,\n\t\t\tisOutside,\n\t\t\tposition: drag.position(event),\n\t\t});\n\n\t\tdrag.state = this.#withinLimit(mapping, state);\n\t\tif (value === undefined) return;\n\n\t\tif (!wasEngaged) this.#reveal(drag);\n\t\tthis.input(isOutside ? drag.fromValue : value);\n\t\tif (isOutside === drag.isOutside) return;\n\n\t\tdrag.isOutside = isOutside;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#endHolds(): void {\n\t\tthis.#entry?.close(false);\n\t\tthis.#pointerDrag?.end();\n\t\tthis.#endKeyScrub();\n\t}\n\n\t#endKeyScrub(): void {\n\t\tconst scrub = this.#keyScrub;\n\t\tif (!scrub) return;\n\n\t\tthis.#keyScrub = undefined;\n\t\tthis.#renderHold();\n\t\tif (this.#value !== scrub.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#isHeld(): boolean {\n\t\treturn this.#dragging() !== undefined || this.#keyScrub !== undefined;\n\t}\n\n\t#keyTarget(key: string): number | undefined {\n\t\tif (resetKeys.has(key)) return this.default;\n\n\t\treturn this.mapping().keyTarget(key, this.#value, this.keyStep);\n\t}\n\n\t#keyTo(event: KeyboardEvent, next: number): void {\n\t\tif (event.repeat && this.scrubsKeyRepeat()) {\n\t\t\tthis.#scrubKey(event.key, next);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#endKeyScrub();\n\t\tthis.#commit(next, next > this.#value ? 1 : -1);\n\t}\n\n\t#releaseDrag(drag: ValueDrag): void {\n\t\tclearTimeout(drag.revealTimer);\n\t\tthis.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t\tif (this.#value !== drag.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t\tthis.#springBack();\n\t}\n\n\t#renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tthis.writeFormValue(String(this.#value), String(this.#value));\n\t\tif (this.#entry?.isOpen) {\n\t\t\tfor (const name of roleAttributes) control.removeAttribute(name);\n\t\t\tthis.forwardNaming(control, false);\n\t\t\tthis.#renderReadout();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [low, high] = this.mapping().bounds;\n\n\t\twriteAttribute(control, 'role', this.controlRole());\n\t\twriteAttribute(control, 'aria-valuemin', String(low));\n\t\twriteAttribute(control, 'aria-valuemax', String(high));\n\t\twriteAttribute(control, 'aria-valuenow', String(this.#value));\n\t\tif (orientation) writeAttribute(control, 'aria-orientation', orientation);\n\t\twriteAttribute(\n\t\t\tcontrol,\n\t\t\t'aria-valuetext',\n\t\t\t(this.#formatSpokenValue ?? this.#formatValue)?.(this.#value),\n\t\t);\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.#renderReadout();\n\t}\n\n\t#renderControl(): void {\n\t\tthis.draw();\n\t\tthis.#renderScale();\n\t\tthis.toggleState(\n\t\t\t'at-origin',\n\t\t\t!this.isWrapping() && this.#value === this.mapping().snap(this.originValue()),\n\t\t);\n\t\tthis.#renderAria(this.focusTarget(), this.controlOrientation());\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tconst isDisabled = this.isDisabled();\n\n\t\twriteAttribute(control, 'aria-disabled', isDisabled ? 'true' : undefined);\n\t\twriteAttribute(control, 'tabindex', isDisabled ? undefined : '0');\n\t}\n\n\t#renderDragReveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed && !drag.isOutside) this.#claim.reveal('drag');\n\t\telse this.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t}\n\n\t#renderHold(): void {\n\t\tthis.#renderReadout();\n\t\tthis.holdChanged();\n\t}\n\n\t#renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout) return;\n\n\t\tconst { isOpen, value } = this.#claim.shown(this.#value, this.readout);\n\n\t\treadout.bubble.show({\n\t\t\tanchor: readout.anchor,\n\t\t\tisOpen,\n\t\t\ttext: value === undefined ? undefined : this.#textFor(value),\n\t\t});\n\t}\n\n\t#renderScale(): void {\n\t\tconst marks = this.#scaleMarks?.children ?? [];\n\t\tconst mapping = this.mapping();\n\n\t\tfor (const mark of marks) {\n\t\t\tif (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;\n\n\t\t\tconst at = String(mapping.proportionOf(scaleValue(mark)));\n\n\t\t\tif (mark.style.getPropertyValue('--_sonic-scale-at') !== at) {\n\t\t\t\tmark.style.setProperty('--_sonic-scale-at', at);\n\t\t\t}\n\t\t}\n\t}\n\n\t#reset(): void {\n\t\tthis.#commit(this.default ?? NaN);\n\t}\n\n\t#reveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed || this.#dragging() !== drag) return;\n\n\t\tdrag.isRevealed = true;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#scrubKey(key: string, next: number): void {\n\t\tif (this.#keyScrub?.key !== key) {\n\t\t\tthis.#endKeyScrub();\n\t\t\tthis.#keyScrub = { fromValue: this.#value, key };\n\t\t}\n\t\tthis.input(next);\n\t}\n\n\t#springBack(): void {\n\t\tconst target = this.springTarget();\n\t\tif (target === undefined) return;\n\n\t\t// Set before the commit so a `change` listener reading styles sees the glide\n\t\tif (this.mapping().snap(target) !== this.#value) this.toggleState('springing', true);\n\t\tthis.#commit(target);\n\t}\n\n\t#startDrag(control: HTMLElement, axis: ValueAxis, event: PointerEvent): DragState {\n\t\tconst mapping = this.mapping();\n\t\tconst detent = this.detent;\n\t\tconst start = {\n\t\t\tfrom: this.#value,\n\t\t\tposition: axis.position(event),\n\t\t\tproportion: axis.fromProportion ?? mapping.proportionOf(this.#value),\n\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\ttravelPx: axis.travelPx,\n\t\t};\n\t\tif (detent === undefined) return startDrag(mapping, start);\n\n\t\tconst zonePx = readPxProperty(getComputedStyle(control), '--_sonic-detent-zone', detentZonePx);\n\n\t\treturn startDrag(mapping, {\n\t\t\t...start,\n\t\t\tdetent: { value: detent, zone: zonePx / axis.travelPx },\n\t\t});\n\t}\n\n\t#textFor(value: number): string {\n\t\treturn this.#formatValue?.(value) ?? String(value);\n\t}\n\n\t// A hover holds no focus, so the key is heard on the document (WCAG 1.4.13)\n\t#watchEscape(isHovered: boolean): void {\n\t\tif (!isHovered) {\n\t\t\tthis.#escapeWatch?.abort();\n\t\t\tthis.#escapeWatch = undefined;\n\t\t\treturn;\n\t\t}\n\t\tif (this.#escapeWatch) return;\n\n\t\tconst watch = new AbortController();\n\n\t\tthis.#escapeWatch = watch;\n\t\tthis.ownerDocument.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.key === 'Escape' && this.#claim.dismiss()) this.#renderHold();\n\t\t\t},\n\t\t\t{ signal: watch.signal },\n\t\t);\n\t}\n\n\t#withinLimit(mapping: ValueMapping, state: DragState): DragState {\n\t\tconst limit = this.#limit;\n\t\tif (!limit || mapping.isWrapping) return state;\n\n\t\tconst [low, high] = limit;\n\n\t\treturn {\n\t\t\t...state,\n\t\t\trawProportion: clamp(\n\t\t\t\tstate.rawProportion,\n\t\t\t\tmapping.proportionOf(low),\n\t\t\t\tmapping.proportionOf(high),\n\t\t\t),\n\t\t};\n\t}\n\n\t#write(next: number): void {\n\t\tif (!Number.isFinite(next)) return;\n\n\t\tconst clamped = this.mapping().snap(next);\n\n\t\tthis.#asked = clamped;\n\t\tif (clamped === this.#value) return;\n\n\t\tthis.#value = clamped;\n\t\tthis.render();\n\t}\n\n\t#writeModulationProportion(control: HTMLElement, prefix: 'dial' | 'slider'): void {\n\t\tconst modulationValue = this.isWrapping() ? undefined : this.#modulationValue;\n\t\tconst isModulated = modulationValue !== undefined;\n\n\t\tif (isModulated !== this.#isModulated) {\n\t\t\tthis.#isModulated = isModulated;\n\t\t\tthis.toggleState('modulated', isModulated);\n\t\t}\n\t\tif (modulationValue === undefined) {\n\t\t\tcontrol.style.removeProperty(`--_sonic-${prefix}-modulation-value`);\n\t\t\treturn;\n\t\t}\n\n\t\tcontrol.style.setProperty(\n\t\t\t`--_sonic-${prefix}-modulation-value`,\n\t\t\tString(this.mapping().proportionOf(modulationValue)),\n\t\t);\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"value-element.js","names":[],"sources":["../../../src/elements/value-element.ts"],"sourcesContent":["import type { DragState } from '#lib/drag-step.ts';\nimport type { PointerDrag } from '#lib/pointer-drag.ts';\nimport type { ValueMapping } from '#lib/value-mapping.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { ReadoutClaim, revealMs } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { ValueEntry } from '#elements/value-entry.ts';\nimport { dragThresholdPx, startDrag, stepDrag } from '#lib/drag-step.ts';\nimport { focusByPointer } from '#lib/focus-by-pointer.ts';\nimport { clamp, toNumber, trimFloat } from '#lib/math.ts';\nimport { isMenuPress, isResetPress } from '#lib/modifier-press.ts';\nimport { parseNumberList } from '#lib/number-list.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { requireChild } from '#lib/render.ts';\nimport { resetKeys, valueMapping } from '#lib/value-mapping.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\nexport interface ValueAxis {\n\tfromProportion?: number;\n\tisKeptOnCancel?: boolean;\n\toutside?: (event: PointerEvent) => boolean;\n\tposition: (event: PointerEvent) => number;\n\ttravelPx: number;\n}\n\ninterface ValueDrag extends ValueAxis {\n\tfromValue: number;\n\tisOutside: boolean;\n\tisRevealed: boolean;\n\tpointerType: string;\n\trevealTimer: ReturnType<typeof setTimeout> | undefined;\n\tstate: DragState;\n}\n\ninterface KeyScrub {\n\tfromValue: number;\n\tkey: string;\n}\n\nconst detentZonePx = 8;\nconst fallbackTravelPx = 160;\n\nlet instanceCount = 0;\n\nconst proportionAttributes = new Set(['max', 'midpoint', 'min', 'notched', 'positions', 'taper']);\n\nconst roleAttributes = [\n\t'aria-disabled',\n\t'aria-orientation',\n\t'aria-valuemax',\n\t'aria-valuemin',\n\t'aria-valuenow',\n\t'aria-valuetext',\n\t'role',\n\t'tabindex',\n];\n\ntype ValueLanding = (target: number, direction: -1 | 0 | 1) => number;\n\nexport interface ValueLink {\n\tinput: (next: number, isMover?: boolean) => boolean;\n\tisDisabled: () => boolean;\n\tisHeld: () => boolean;\n\tland: (resolve: undefined | ValueLanding) => void;\n\tlimit: (bounds: [number, number] | undefined) => void;\n\tmapping: () => ValueMapping;\n\tvalue: () => number;\n\twatch: (listener: () => void) => () => void;\n}\n\n// Filled from inside the class, so it reaches protected members and nothing lands on the element's public type\nlet link: (element: SonicValueElement) => ValueLink;\n\nexport function linkValue(element: SonicValueElement): ValueLink {\n\treturn link(element);\n}\n\nexport abstract class SonicValueElement extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'detent',\n\t\t'max',\n\t\t'midpoint',\n\t\t'min',\n\t\t'notched',\n\t\t'origin',\n\t\t'readout',\n\t\t'spoken-step',\n\t\t'step',\n\t\t'tabindex',\n\t\t'taper',\n\t\t'value',\n\t\t'positions',\n\t];\n\n\tstatic {\n\t\tlink = (element) => ({\n\t\t\tinput: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),\n\t\t\tisDisabled: () => element.isDisabled(),\n\t\t\tisHeld: () => element.#isHeld(),\n\t\t\tland: (resolve) => {\n\t\t\t\telement.#land = resolve;\n\t\t\t},\n\t\t\tlimit: (bounds) => {\n\t\t\t\telement.#limit = bounds;\n\t\t\t},\n\t\t\tmapping: () => element.mapping(),\n\t\t\tvalue: () => element.#value,\n\t\t\twatch: (listener) => {\n\t\t\t\telement.#watchers.add(listener);\n\n\t\t\t\treturn () => {\n\t\t\t\t\telement.#watchers.delete(listener);\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tget default(): number | undefined {\n\t\treturn this.optionalNumberAttribute('default');\n\t}\n\n\tset default(value: number | undefined) {\n\t\tthis.reflect('default', value);\n\t}\n\n\tget detent(): number | undefined {\n\t\treturn this.optionalNumberAttribute('detent');\n\t}\n\n\tset detent(value: number | undefined) {\n\t\tthis.reflect('detent', value);\n\t}\n\n\tget dimmed(): boolean {\n\t\treturn this.hasAttribute('dimmed');\n\t}\n\n\tset dimmed(isDimmed: boolean) {\n\t\tthis.reflect('dimmed', isDimmed);\n\t}\n\n\tget doublePress(): 'entry' | 'reset' {\n\t\treturn this.getAttribute('double-press') === 'reset' ? 'reset' : 'entry';\n\t}\n\n\tset doublePress(gesture: 'entry' | 'reset' | undefined) {\n\t\tthis.reflect('double-press', gesture);\n\t}\n\n\tget formatSpokenValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatSpokenValue;\n\t}\n\n\tset formatSpokenValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatSpokenValue = format;\n\t\tthis.render();\n\t}\n\n\tget formatValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatValue;\n\t}\n\n\tset formatValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatValue = format;\n\t\tthis.render();\n\t}\n\n\tget keyStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('key-step');\n\t}\n\n\tset keyStep(value: number | undefined) {\n\t\tthis.reflect('key-step', value);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 100);\n\t}\n\n\tset max(value: number | undefined) {\n\t\tthis.reflect('max', value);\n\t}\n\n\tget midpoint(): number | undefined {\n\t\treturn this.optionalNumberAttribute('midpoint');\n\t}\n\n\tset midpoint(value: number | undefined) {\n\t\tthis.reflect('midpoint', value);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tset min(value: number | undefined) {\n\t\tthis.reflect('min', value);\n\t}\n\n\tget notched(): boolean {\n\t\treturn this.hasAttribute('notched');\n\t}\n\n\tset notched(isNotched: boolean) {\n\t\tthis.reflect('notched', isNotched);\n\t}\n\n\tget origin(): number | undefined {\n\t\treturn this.optionalNumberAttribute('origin');\n\t}\n\n\tset origin(value: number | undefined) {\n\t\tthis.reflect('origin', value);\n\t}\n\n\tget parseValue(): ((text: string) => number) | undefined {\n\t\treturn this.#parseValue;\n\t}\n\n\tset parseValue(parse: ((text: string) => number) | undefined) {\n\t\tthis.#parseValue = parse;\n\t}\n\n\tget pointerType(): string | undefined {\n\t\treturn this.#dragging()?.pointerType;\n\t}\n\n\tget positions(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('positions'));\n\t}\n\n\tset positions(positions: Array<number> | undefined) {\n\t\tthis.reflect('positions', positions?.join(' '));\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isShown: boolean) {\n\t\tthis.reflect('readout', isShown);\n\t}\n\n\tget spokenStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('spoken-step');\n\t}\n\n\tset spokenStep(value: number | undefined) {\n\t\tthis.reflect('spoken-step', value);\n\t}\n\n\tget step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\tset step(value: number | undefined) {\n\t\tthis.reflect('step', value);\n\t}\n\n\tget taper(): 'linear' | 'log' {\n\t\treturn this.getAttribute('taper') === 'log' ? 'log' : 'linear';\n\t}\n\n\tset taper(curve: 'linear' | 'log' | undefined) {\n\t\tthis.reflect('taper', curve);\n\t}\n\n\tget value(): number {\n\t\treturn this.#value;\n\t}\n\n\tset value(next: null | number | undefined) {\n\t\t// A framework removes a prop by setting the property to `undefined`\n\t\tif (next === undefined || next === null) {\n\t\t\tthis.formResetCallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = toNumber(next);\n\n\t\tif (this.#isHeld()) {\n\t\t\tthis.heldWrite(value);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#write(value);\n\t\tif (Number.isFinite(value)) this.#asked = value;\n\t}\n\n\tget valueText(): string {\n\t\treturn this.#textFor(this.#value);\n\t}\n\n\t#asked: number | undefined;\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderHold();\n\t});\n\n\t#entry: undefined | ValueEntry;\n\n\t#formatSpokenValue: ((value: number) => string) | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\t#heldAt: number | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t#isModulated = false;\n\n\t#isRevealed = false;\n\n\t#keyScrub: KeyScrub | undefined;\n\n\t#land: undefined | ValueLanding;\n\n\t#limit: [number, number] | undefined;\n\n\t// Every attribute it reads is observed; a subclass adding an input to `isWrapping()` has to observe it\n\t#mapping: undefined | ValueMapping;\n\n\t#modulationValue: number | undefined;\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#pointerDrag: PointerDrag<ValueDrag> | undefined;\n\n\t#positions: Array<number> | undefined;\n\n\t#readout: undefined | { anchor: HTMLElement; bubble: Readout };\n\n\t#value = 0;\n\n\treadonly #watchers = new Set<() => void>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tthis.#mapping = undefined;\n\t\tthis.#positions = parseNumberList(this.getAttribute('positions'));\n\t\tif (name === 'value') {\n\t\t\tif (this.#isHeld()) {\n\t\t\t\tthis.heldWrite(this.numberAttribute('value', this.min));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.#asked = undefined;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) this.#endHolds();\n\n\t\tthis.#value = this.mapping().snap(this.#asked ?? this.numberAttribute('value', this.min));\n\t\tif (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();\n\t\tthis.render();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(\n\t\t\t'default',\n\t\t\t'dimmed',\n\t\t\t'doublePress',\n\t\t\t'max',\n\t\t\t'midpoint',\n\t\t\t'min',\n\t\t\t'notched',\n\t\t\t'origin',\n\t\t\t'readout',\n\t\t\t'spokenStep',\n\t\t\t'step',\n\t\t\t'taper',\n\t\t\t'positions',\n\t\t\t'detent',\n\t\t\t'formatValue',\n\t\t\t'formatSpokenValue',\n\t\t\t'keyStep',\n\t\t\t'parseValue',\n\t\t\t'value',\n\t\t);\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected bindGestures(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\tgrab: (event: PointerEvent) => undefined | ValueAxis,\n\t): void {\n\t\tconst entry = this.#bindEntry(control, signal);\n\n\t\tthis.#pointerDrag = bindDrag<ValueDrag>(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tcancel: (drag) => {\n\t\t\t\t\tif (drag.isKeptOnCancel !== true) this.input(drag.fromValue);\n\t\t\t\t},\n\t\t\t\tgrab: (event) => {\n\t\t\t\t\tif (isMenuPress(event) || this.isDisabled() || entry.isOpen) return;\n\n\t\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\t\t// A click listener above makes WebKit send a tap's compatibility mousedown, which blurs the entry a double tap just opened\n\t\t\t\t\tif (event.pointerType === 'touch') event.preventDefault();\n\t\t\t\t\tfocusByPointer(control);\n\t\t\t\t\tif (isResetPress(event)) {\n\t\t\t\t\t\tthis.#reset();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fromValue = this.#value;\n\t\t\t\t\tconst axis = grab(event);\n\t\t\t\t\tif (!axis) return;\n\n\t\t\t\t\tconst drag: ValueDrag = {\n\t\t\t\t\t\t...axis,\n\t\t\t\t\t\tfromValue,\n\t\t\t\t\t\tisOutside: false,\n\t\t\t\t\t\tisRevealed: false,\n\t\t\t\t\t\tpointerType: event.pointerType,\n\t\t\t\t\t\trevealTimer: undefined,\n\t\t\t\t\t\tstate: this.#startDrag(control, axis, event),\n\t\t\t\t\t};\n\n\t\t\t\t\tdrag.revealTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.#reveal(drag);\n\t\t\t\t\t}, revealMs);\n\n\t\t\t\t\treturn drag;\n\t\t\t\t},\n\t\t\t\tlift: (drag, event) => {\n\t\t\t\t\tconst tap = drag.state.isEngaged ? undefined : this.tapTarget();\n\n\t\t\t\t\tif (tap !== undefined) {\n\t\t\t\t\t\tentry.forgetPress();\n\t\t\t\t\t\tthis.#commit(tap);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!entry.press(event) || this.springTarget() !== undefined) return;\n\n\t\t\t\t\tif (this.doublePress === 'reset') this.#reset();\n\t\t\t\t\telse entry.open();\n\t\t\t\t},\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\tthis.#dragTo(drag, event);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tthis.#releaseDrag(drag);\n\t\t\t\t},\n\t\t\t\ttoggle: (isDragging) => {\n\t\t\t\t\tthis.toggleState('dragging', isDragging);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'pointercancel',\n\t\t\t() => {\n\t\t\t\tentry.forgetPress();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindKeys(control, entry, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected controlOrientation(): 'horizontal' | 'vertical' | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected abstract draw(): void;\n\n\tprotected abstract override focusTarget(): HTMLElement;\n\n\tprotected heldFrom(): number | undefined {\n\t\treturn this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;\n\t}\n\n\tprotected heldWrite(next: number): void {\n\t\tthis.#heldAt = next;\n\t}\n\n\tprotected holdChanged(): void {\n\t\t// Only a subclass draws a hold\n\t}\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#value;\n\n\t\tthis.#write(this.#limit ? clamp(next, ...this.#limit) : next);\n\t\tif (this.#value === previous) return false;\n\n\t\tthis.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n\n\t\treturn true;\n\t}\n\n\tprotected isEditing(): boolean {\n\t\treturn this.#entry?.isOpen === true;\n\t}\n\n\tprotected isRevealed(): boolean {\n\t\treturn this.#claim.isRevealed;\n\t}\n\n\tprotected isWrapping(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected mapping(): ValueMapping {\n\t\tif (this.#mapping) return this.#mapping;\n\n\t\tconst { detent, midpoint } = this;\n\n\t\tthis.#mapping = valueMapping({\n\t\t\t...(detent === undefined ? {} : { detent }),\n\t\t\t...(this.#positions ? { positions: this.#positions } : {}),\n\t\t\tmax: this.max,\n\t\t\t...(midpoint === undefined ? {} : { midpoint }),\n\t\t\tisNotched: this.notched,\n\t\t\tisWrapping: this.isWrapping(),\n\t\t\tmin: this.min,\n\t\t\tstep: this.step,\n\t\t\ttaper: this.taper,\n\t\t});\n\n\t\treturn this.#mapping;\n\t}\n\n\tprotected originValue(): number {\n\t\treturn this.origin ?? this.mapping().bounds[0];\n\t}\n\n\tprotected playback(): number {\n\t\tconst from = this.heldFrom();\n\n\t\treturn from === undefined ? this.#value : (this.#heldAt ?? from);\n\t}\n\n\tprotected previewValue(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected proportionsChanged(): void {\n\t\t// Runs when every proportion moves, never per input\n\t}\n\n\tprotected readModulationValue(): number | undefined {\n\t\treturn this.#modulationValue;\n\t}\n\n\tprotected readoutValue(): number {\n\t\treturn this.#shown().value ?? this.#value;\n\t}\n\n\tprotected render(): void {\n\t\tif (this.isBound()) this.#renderControl();\n\t\tfor (const listener of this.#watchers) listener();\n\t}\n\n\tprotected renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout) return;\n\n\t\tconst { isOpen, value } = this.#shown();\n\t\tconst text = value === undefined ? undefined : this.#textFor(value);\n\n\t\treadout.bubble.show({ anchor: readout.anchor, isOpen: isOpen && text !== '', text });\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected scrubsKeyRepeat(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected tapTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number {\n\t\treturn Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));\n\t}\n\n\tprotected writeModulationValue(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tnext: null | number | undefined,\n\t): void {\n\t\tconst value = next === undefined || next === null ? undefined : toNumber(next);\n\t\tif (value !== undefined && !Number.isFinite(value)) return;\n\n\t\tthis.#modulationValue = value;\n\t\tif (this.isBound()) this.#writeModulationProportion(control, prefix);\n\t}\n\n\tprotected writeProportions(\n\t\tcontrol: HTMLElement,\n\t\tprefix: 'dial' | 'slider',\n\t\tmodulation: number,\n\t): void {\n\t\tconst { style } = control;\n\t\tconst mapping = this.mapping();\n\t\tconst value = mapping.proportionOf(this.#value);\n\t\tconst reach = mapping.proportionOf(this.#value + modulation);\n\t\tconst { positionCount } = mapping;\n\n\t\tstyle.setProperty(`--_sonic-${prefix}-value`, String(value));\n\t\tstyle.setProperty(\n\t\t\t`--_sonic-${prefix}-origin`,\n\t\t\tString(mapping.proportionOf(this.originValue())),\n\t\t);\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-from`, String(Math.min(value, reach)));\n\t\tstyle.setProperty(`--_sonic-${prefix}-modulation-to`, String(Math.max(value, reach)));\n\t\tif (positionCount === undefined) style.removeProperty(`--_sonic-${prefix}-position-count`);\n\t\telse style.setProperty(`--_sonic-${prefix}-position-count`, String(positionCount));\n\t\tthis.#writeModulationProportion(control, prefix);\n\t}\n\n\t#bindEntry(control: HTMLElement, signal: AbortSignal): ValueEntry {\n\t\tconst input = requireChild(control, 'input', HTMLInputElement);\n\t\tconst bubble = control.querySelector<HTMLElement>('[popover]');\n\n\t\t// Chrome's issues panel flags a form field with no id or name; a `name` would submit it\n\t\tinput.id = `sonic-entry-${this.#instance}`;\n\t\tif (bubble) this.#readout = { anchor: control, bubble: new Readout(bubble) };\n\n\t\tconst entry = new ValueEntry(input, {\n\t\t\tcommit: (text) => {\n\t\t\t\t// eslint-disable-next-line unicorn/prefer-number-coercion -- `Number('')` is 0; an emptied field should leave the value alone\n\t\t\t\tthis.#commit((this.#parseValue ?? Number.parseFloat)(text));\n\t\t\t},\n\t\t\t// `Number.parseFloat` reads \"5 kHz\" as 5\n\t\t\ttext: () => (this.#parseValue ? this.valueText : String(this.#value)),\n\t\t\ttoggle: (isOpen) => {\n\t\t\t\tif (isOpen) this.forwardNaming(input, true);\n\t\t\t\tthis.toggleState('editing', isOpen);\n\t\t\t\tthis.render();\n\t\t\t},\n\t\t});\n\n\t\tthis.#entry = entry;\n\t\tentry.bind(control, signal);\n\n\t\treturn entry;\n\t}\n\n\t#bindKeys(control: HTMLElement, entry: ValueEntry, signal: AbortSignal): void {\n\t\tcontrol.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (this.isDisabled() || event.defaultPrevented || event.target !== control) return;\n\n\t\t\t\tthis.toggleState('springing', false);\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tif (this.springTarget() !== undefined) return;\n\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tentry.open();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst next = this.#keyTarget(event.key);\n\t\t\t\tif (next === undefined) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#keyTo(event, next);\n\t\t\t\tthis.#claim.reveal('keys');\n\t\t\t\tthis.#renderHold();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'keyup',\n\t\t\t(event) => {\n\t\t\t\t// macOS sends no `keyup` for a key let go while Cmd is down\n\t\t\t\tconst isMeta = event.key === 'Meta';\n\n\t\t\t\tif (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();\n\t\t\t\tif (isMeta && this.#dragging()) return;\n\t\t\t\tif (isMeta || this.mapping().keyTarget(event.key, this.#value) !== undefined) {\n\t\t\t\t\tthis.#springBack();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t\tthis.#concealKeyReveal();\n\t\t\t\tthis.#springBack();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#commit(next: number, direction: -1 | 0 | 1 = 0): void {\n\t\tconst landed = Number.isFinite(next) ? (this.#land?.(next, direction) ?? next) : next;\n\n\t\tif (this.input(landed)) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#concealKeyReveal(): void {\n\t\tif (this.#claim.conceal('keys')) this.#renderHold();\n\t}\n\n\t#dragging(): undefined | ValueDrag {\n\t\treturn this.#pointerDrag?.current();\n\t}\n\n\t#dragTo(drag: ValueDrag, event: PointerEvent): void {\n\t\tconst isOutside = drag.outside?.(event) === true;\n\t\tconst wasEngaged = drag.state.isEngaged;\n\t\tconst mapping = this.mapping();\n\t\tconst { state, value } = stepDrag(mapping, drag.state, {\n\t\t\tisFine: event.shiftKey,\n\t\t\tisOutside,\n\t\t\tposition: drag.position(event),\n\t\t});\n\n\t\tdrag.state = this.#withinLimit(mapping, state);\n\t\tif (value === undefined) return;\n\n\t\tif (!wasEngaged) this.#reveal(drag);\n\n\t\tconst isCrossing = isOutside !== drag.isOutside;\n\n\t\tif (isCrossing) {\n\t\t\tdrag.isOutside = isOutside;\n\t\t\tthis.toggleState('cancelling', isOutside);\n\t\t}\n\t\tthis.input(isOutside ? drag.fromValue : value);\n\t\tif (isCrossing) this.#renderDragReveal(drag);\n\t}\n\n\t#endHolds(): void {\n\t\tthis.#entry?.close(false);\n\t\tthis.#pointerDrag?.end();\n\t\tthis.#endKeyScrub();\n\t}\n\n\t#endKeyScrub(): void {\n\t\tconst scrub = this.#keyScrub;\n\t\tif (!scrub) return;\n\n\t\tthis.#keyScrub = undefined;\n\t\tthis.#renderHold();\n\t\tif (this.#value !== scrub.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#isHeld(): boolean {\n\t\treturn this.#dragging() !== undefined || this.#keyScrub !== undefined;\n\t}\n\n\t#keyTarget(key: string): number | undefined {\n\t\tif (resetKeys.has(key)) return this.default;\n\n\t\treturn this.mapping().keyTarget(key, this.#value, this.keyStep);\n\t}\n\n\t#keyTo(event: KeyboardEvent, next: number): void {\n\t\tif (event.repeat && this.scrubsKeyRepeat()) {\n\t\t\tthis.#scrubKey(event.key, next);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#endKeyScrub();\n\t\tthis.#commit(next, next > this.#value ? 1 : -1);\n\t}\n\n\t#releaseDrag(drag: ValueDrag): void {\n\t\tclearTimeout(drag.revealTimer);\n\t\tthis.#claim.conceal('drag');\n\t\tthis.toggleState('cancelling', false);\n\t\tthis.#renderHold();\n\t\tthis.#showRevealed(false);\n\t\tif (this.#value !== drag.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t\tthis.#springBack();\n\t}\n\n\t#renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tthis.writeFormValue(String(this.#value), String(this.#value));\n\t\tif (this.#entry?.isOpen) {\n\t\t\tfor (const name of roleAttributes) control.removeAttribute(name);\n\t\t\tthis.forwardNaming(control, false);\n\t\t\tthis.renderReadout();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [low, high] = this.mapping().bounds;\n\n\t\twriteAttribute(control, 'role', this.controlRole());\n\t\twriteAttribute(control, 'aria-valuemin', String(low));\n\t\twriteAttribute(control, 'aria-valuemax', String(high));\n\t\twriteAttribute(control, 'aria-valuenow', String(this.#spokenNow()));\n\t\tif (orientation) writeAttribute(control, 'aria-orientation', orientation);\n\t\twriteAttribute(\n\t\t\tcontrol,\n\t\t\t'aria-valuetext',\n\t\t\t(this.#formatSpokenValue ?? this.#formatValue)?.(this.#value),\n\t\t);\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.renderReadout();\n\t}\n\n\t#renderControl(): void {\n\t\tthis.draw();\n\t\tthis.toggleState(\n\t\t\t'at-origin',\n\t\t\t!this.isWrapping() && this.#value === this.mapping().snap(this.originValue()),\n\t\t);\n\t\tthis.#renderAria(this.focusTarget(), this.controlOrientation());\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tconst isDisabled = this.isDisabled();\n\n\t\twriteAttribute(control, 'aria-disabled', isDisabled ? 'true' : undefined);\n\t\t// The host is `display: contents`, so its tab stop is the control's\n\t\tconst stop = this.getAttribute('tabindex') === '-1' ? '-1' : '0';\n\n\t\twriteAttribute(control, 'tabindex', isDisabled ? undefined : stop);\n\t}\n\n\t#renderDragReveal(drag: ValueDrag): void {\n\t\tconst isRevealed = drag.isRevealed && !drag.isOutside;\n\n\t\tif (isRevealed) this.#claim.reveal('drag');\n\t\telse this.#claim.conceal('drag');\n\t\tthis.#renderHold();\n\t\tthis.#showRevealed(isRevealed);\n\t}\n\n\t#renderHold(): void {\n\t\tif (this.heldFrom() === undefined) this.#heldAt = undefined;\n\t\tthis.renderReadout();\n\t\tthis.holdChanged();\n\t}\n\n\t#reset(): void {\n\t\tthis.#commit(this.default ?? NaN);\n\t}\n\n\t#reveal(drag: ValueDrag): void {\n\t\tif (drag.isRevealed || this.#dragging() !== drag) return;\n\n\t\tdrag.isRevealed = true;\n\t\tthis.#renderDragReveal(drag);\n\t}\n\n\t#scrubKey(key: string, next: number): void {\n\t\tif (this.#keyScrub?.key !== key) {\n\t\t\tthis.#endKeyScrub();\n\t\t\tthis.#keyScrub = { fromValue: this.#value, key };\n\t\t}\n\t\tthis.input(next);\n\t}\n\n\t#shown(): { isOpen: boolean; value: number | undefined } {\n\t\tif (this.isEditing()) return { isOpen: true, value: undefined };\n\n\t\tconst isRevealed = this.#claim.isRevealed;\n\t\tconst preview = isRevealed ? undefined : this.previewValue();\n\n\t\treturn {\n\t\t\tisOpen: (isRevealed || preview !== undefined) && this.readout,\n\t\t\tvalue: preview ?? this.#value,\n\t\t};\n\t}\n\n\t#showRevealed(isRevealed: boolean): void {\n\t\tif (isRevealed === this.#isRevealed) return;\n\n\t\tthis.#isRevealed = isRevealed;\n\t\tthis.toggleState('revealed', isRevealed);\n\t\tthis.dispatchEvent(new Event('sonic-reveal', { bubbles: true }));\n\t}\n\n\t#spokenNow(): number {\n\t\tconst step = this.spokenStep;\n\n\t\treturn step !== undefined && step > 0\n\t\t\t? trimFloat(Math.round(this.#value / step) * step)\n\t\t\t: this.#value;\n\t}\n\n\t#springBack(): void {\n\t\tconst target = this.springTarget();\n\t\tif (target === undefined) return;\n\n\t\t// Set before the commit so a `change` listener reading styles sees the glide\n\t\tif (this.mapping().snap(target) !== this.#value) this.toggleState('springing', true);\n\t\tthis.#commit(target);\n\t}\n\n\t#startDrag(control: HTMLElement, axis: ValueAxis, event: PointerEvent): DragState {\n\t\tconst mapping = this.mapping();\n\t\tconst detent = this.detent;\n\t\tconst start = {\n\t\t\tfrom: this.#value,\n\t\t\tposition: axis.position(event),\n\t\t\tproportion: axis.fromProportion ?? mapping.proportionOf(this.#value),\n\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\ttravelPx: axis.travelPx,\n\t\t};\n\t\tif (detent === undefined) return startDrag(mapping, start);\n\n\t\tconst zonePx = readPxProperty(getComputedStyle(control), '--_sonic-detent-zone', detentZonePx);\n\n\t\treturn startDrag(mapping, {\n\t\t\t...start,\n\t\t\tdetent: { value: detent, zone: zonePx / axis.travelPx },\n\t\t});\n\t}\n\n\t#textFor(value: number): string {\n\t\treturn this.#formatValue?.(value) ?? String(value);\n\t}\n\n\t#withinLimit(mapping: ValueMapping, state: DragState): DragState {\n\t\tconst limit = this.#limit;\n\t\tif (!limit || mapping.isWrapping) return state;\n\n\t\tconst [low, high] = limit;\n\n\t\treturn {\n\t\t\t...state,\n\t\t\trawProportion: clamp(\n\t\t\t\tstate.rawProportion,\n\t\t\t\tmapping.proportionOf(low),\n\t\t\t\tmapping.proportionOf(high),\n\t\t\t),\n\t\t};\n\t}\n\n\t#write(next: number): void {\n\t\tif (!Number.isFinite(next)) return;\n\n\t\tconst clamped = this.mapping().snap(next);\n\n\t\tthis.#asked = clamped;\n\t\tif (clamped === this.#value) return;\n\n\t\tthis.#value = clamped;\n\t\tthis.render();\n\t}\n\n\t#writeModulationProportion(control: HTMLElement, prefix: 'dial' | 'slider'): void {\n\t\tconst modulationValue = this.isWrapping() ? undefined : this.#modulationValue;\n\t\tconst isModulated = modulationValue !== undefined;\n\n\t\tif (isModulated !== this.#isModulated) {\n\t\t\tthis.#isModulated = isModulated;\n\t\t\tthis.toggleState('modulated', isModulated);\n\t\t}\n\t\tif (modulationValue === undefined) {\n\t\t\tcontrol.style.removeProperty(`--_sonic-${prefix}-modulation-value`);\n\t\t\treturn;\n\t\t}\n\n\t\tcontrol.style.setProperty(\n\t\t\t`--_sonic-${prefix}-modulation-value`,\n\t\t\tString(this.mapping().proportionOf(modulationValue)),\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyCA,MAAM,eAAe;AACrB,MAAM,mBAAmB;AAEzB,IAAI,gBAAgB;AAEpB,MAAM,uCAAuB,IAAI,IAAI;CAAC;CAAO;CAAY;CAAO;CAAW;CAAa;AAAO,CAAC;AAEhG,MAAM,iBAAiB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AAgBA,IAAI;AAEJ,SAAgB,UAAU,SAAuC;CAChE,OAAO,KAAK,OAAO;AACpB;AAEA,IAAsB,oBAAtB,cAAgD,iBAAiB;CAChE,OAAyB,qBAAqB;EAC7C,GAAG,iBAAiB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD;CAEA;EACC,QAAQ,aAAa;GACpB,QAAQ,MAAM,UAAU,WAAW,WAAW,CAAC,QAAQ,QAAQ,MAAM,QAAQ,MAAM,IAAI;GACvF,kBAAkB,QAAQ,WAAW;GACrC,cAAc,QAAQ,QAAQ;GAC9B,OAAO,YAAY;IAClB,QAAQ,QAAQ;GACjB;GACA,QAAQ,WAAW;IAClB,QAAQ,SAAS;GAClB;GACA,eAAe,QAAQ,QAAQ;GAC/B,aAAa,QAAQ;GACrB,QAAQ,aAAa;IACpB,QAAQ,UAAU,IAAI,QAAQ;IAE9B,aAAa;KACZ,QAAQ,UAAU,OAAO,QAAQ;IAClC;GACD;EACD;CACD;CAEA,IAAI,UAA8B;EACjC,OAAO,KAAK,wBAAwB,SAAS;CAC9C;CAEA,IAAI,QAAQ,OAA2B;EACtC,KAAK,QAAQ,WAAW,KAAK;CAC9B;CAEA,IAAI,SAA6B;EAChC,OAAO,KAAK,wBAAwB,QAAQ;CAC7C;CAEA,IAAI,OAAO,OAA2B;EACrC,KAAK,QAAQ,UAAU,KAAK;CAC7B;CAEA,IAAI,SAAkB;EACrB,OAAO,KAAK,aAAa,QAAQ;CAClC;CAEA,IAAI,OAAO,UAAmB;EAC7B,KAAK,QAAQ,UAAU,QAAQ;CAChC;CAEA,IAAI,cAAiC;EACpC,OAAO,KAAK,aAAa,cAAc,MAAM,UAAU,UAAU;CAClE;CAEA,IAAI,YAAY,SAAwC;EACvD,KAAK,QAAQ,gBAAgB,OAAO;CACrC;CAEA,IAAI,oBAA6D;EAChE,OAAO,KAAK;CACb;CAEA,IAAI,kBAAkB,QAAiD;EACtE,KAAK,qBAAqB;EAC1B,KAAK,OAAO;CACb;CAEA,IAAI,cAAuD;EAC1D,OAAO,KAAK;CACb;CAEA,IAAI,YAAY,QAAiD;EAChE,KAAK,eAAe;EACpB,KAAK,OAAO;CACb;CAEA,IAAI,UAA8B;EACjC,OAAO,KAAK,wBAAwB,UAAU;CAC/C;CAEA,IAAI,QAAQ,OAA2B;EACtC,KAAK,QAAQ,YAAY,KAAK;CAC/B;CAEA,IAAI,MAAc;EACjB,OAAO,KAAK,gBAAgB,OAAO,GAAG;CACvC;CAEA,IAAI,IAAI,OAA2B;EAClC,KAAK,QAAQ,OAAO,KAAK;CAC1B;CAEA,IAAI,WAA+B;EAClC,OAAO,KAAK,wBAAwB,UAAU;CAC/C;CAEA,IAAI,SAAS,OAA2B;EACvC,KAAK,QAAQ,YAAY,KAAK;CAC/B;CAEA,IAAI,MAAc;EACjB,OAAO,KAAK,gBAAgB,OAAO,CAAC;CACrC;CAEA,IAAI,IAAI,OAA2B;EAClC,KAAK,QAAQ,OAAO,KAAK;CAC1B;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,QAAQ,WAAoB;EAC/B,KAAK,QAAQ,WAAW,SAAS;CAClC;CAEA,IAAI,SAA6B;EAChC,OAAO,KAAK,wBAAwB,QAAQ;CAC7C;CAEA,IAAI,OAAO,OAA2B;EACrC,KAAK,QAAQ,UAAU,KAAK;CAC7B;CAEA,IAAI,aAAqD;EACxD,OAAO,KAAK;CACb;CAEA,IAAI,WAAW,OAA+C;EAC7D,KAAK,cAAc;CACpB;CAEA,IAAI,cAAkC;EACrC,OAAO,KAAK,UAAU,CAAC,EAAE;CAC1B;CAEA,IAAI,YAAuC;EAC1C,OAAO,gBAAgB,KAAK,aAAa,WAAW,CAAC;CACtD;CAEA,IAAI,UAAU,WAAsC;EACnD,KAAK,QAAQ,aAAa,WAAW,KAAK,GAAG,CAAC;CAC/C;CAEA,IAAI,UAAmB;EACtB,OAAO,KAAK,aAAa,SAAS;CACnC;CAEA,IAAI,QAAQ,SAAkB;EAC7B,KAAK,QAAQ,WAAW,OAAO;CAChC;CAEA,IAAI,aAAiC;EACpC,OAAO,KAAK,wBAAwB,aAAa;CAClD;CAEA,IAAI,WAAW,OAA2B;EACzC,KAAK,QAAQ,eAAe,KAAK;CAClC;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK,gBAAgB,QAAQ,CAAC;CACtC;CAEA,IAAI,KAAK,OAA2B;EACnC,KAAK,QAAQ,QAAQ,KAAK;CAC3B;CAEA,IAAI,QAA0B;EAC7B,OAAO,KAAK,aAAa,OAAO,MAAM,QAAQ,QAAQ;CACvD;CAEA,IAAI,MAAM,OAAqC;EAC9C,KAAK,QAAQ,SAAS,KAAK;CAC5B;CAEA,IAAI,QAAgB;EACnB,OAAO,KAAK;CACb;CAEA,IAAI,MAAM,MAAiC;EAE1C,IAAI,SAAS,UAAa,SAAS,MAAM;GACxC,KAAK,kBAAkB;GACvB;EACD;EAEA,MAAM,QAAQ,SAAS,IAAI;EAE3B,IAAI,KAAK,QAAQ,GAAG;GACnB,KAAK,UAAU,KAAK;GACpB;EACD;EAEA,KAAK,OAAO,KAAK;EACjB,IAAI,OAAO,SAAS,KAAK,GAAG,KAAK,SAAS;CAC3C;CAEA,IAAI,YAAoB;EACvB,OAAO,KAAK,SAAS,KAAK,MAAM;CACjC;CAEA;CAEA,AAAS,SAAS,IAAI,mBAAmB;EACxC,KAAK,YAAY;CAClB,CAAC;CAED;CAEA;CAEA;CAEA;CAEA,AAAS,YAAY,OAAQ,iBAAiB,CAAE;CAEhD,eAAe;CAEf,cAAc;CAEd;CAEA;CAEA;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA,SAAS;CAET,AAAS,4BAAY,IAAI,IAAgB;CAEzC,yBAAyB,MAAoB;EAC5C,KAAK,WAAW;EAChB,KAAK,aAAa,gBAAgB,KAAK,aAAa,WAAW,CAAC;EAChE,IAAI,SAAS,SAAS;GACrB,IAAI,KAAK,QAAQ,GAAG;IACnB,KAAK,UAAU,KAAK,gBAAgB,SAAS,KAAK,GAAG,CAAC;IACtD;GACD;GAEA,KAAK,SAAS;EACf;EACA,IAAI,SAAS,cAAc,KAAK,WAAW,GAAG,KAAK,UAAU;EAE7D,KAAK,SAAS,KAAK,QAAQ,CAAC,CAAC,KAAK,KAAK,UAAU,KAAK,gBAAgB,SAAS,KAAK,GAAG,CAAC;EACxF,IAAI,qBAAqB,IAAI,IAAI,KAAK,KAAK,QAAQ,GAAG,KAAK,mBAAmB;EAC9E,KAAK,OAAO;CACb;CAEA,AAAS,oBAA0B;EAClC,KAAK,kBACJ,WACA,UACA,eACA,OACA,YACA,OACA,WACA,UACA,WACA,cACA,QACA,SACA,aACA,UACA,eACA,qBACA,WACA,cACA,OACD;EACA,MAAM,kBAAkB;CACzB;CAEA,AAAU,aACT,SACA,QACA,MACO;EACP,MAAM,QAAQ,KAAK,WAAW,SAAS,MAAM;EAE7C,KAAK,eAAe,SACnB,SACA;GACC,SAAS,SAAS;IACjB,IAAI,KAAK,mBAAmB,MAAM,KAAK,MAAM,KAAK,SAAS;GAC5D;GACA,OAAO,UAAU;IAChB,IAAI,YAAY,KAAK,KAAK,KAAK,WAAW,KAAK,MAAM,QAAQ;IAE7D,KAAK,YAAY,aAAa,KAAK;IAEnC,IAAI,MAAM,gBAAgB,SAAS,MAAM,eAAe;IACxD,eAAe,OAAO;IACtB,IAAI,aAAa,KAAK,GAAG;KACxB,KAAK,OAAO;KACZ;IACD;IAEA,MAAM,YAAY,KAAK;IACvB,MAAM,OAAO,KAAK,KAAK;IACvB,IAAI,CAAC,MAAM;IAEX,MAAM,OAAkB;KACvB,GAAG;KACH;KACA,WAAW;KACX,YAAY;KACZ,aAAa,MAAM;KACnB,aAAa;KACb,OAAO,KAAK,WAAW,SAAS,MAAM,KAAK;IAC5C;IAEA,KAAK,cAAc,iBAAiB;KACnC,KAAK,QAAQ,IAAI;IAClB,MAAW;IAEX,OAAO;GACR;GACA,OAAO,MAAM,UAAU;IACtB,MAAM,MAAM,KAAK,MAAM,YAAY,SAAY,KAAK,UAAU;IAE9D,IAAI,QAAQ,QAAW;KACtB,MAAM,YAAY;KAClB,KAAK,QAAQ,GAAG;KAChB;IACD;IACA,IAAI,CAAC,MAAM,MAAM,KAAK,KAAK,KAAK,aAAa,MAAM,QAAW;IAE9D,IAAI,KAAK,gBAAgB,SAAS,KAAK,OAAO;SACzC,MAAM,KAAK;GACjB;GACA,OAAO,MAAM,UAAU;IACtB,KAAK,QAAQ,MAAM,KAAK;GACzB;GACA,UAAU,SAAS;IAClB,KAAK,aAAa,IAAI;GACvB;GACA,SAAS,eAAe;IACvB,KAAK,YAAY,YAAY,UAAU;GACxC;EACD,GACA,MACD;EACA,QAAQ,iBACP,uBACM;GACL,MAAM,YAAY;EACnB,GACA,EAAE,OAAO,CACV;EACA,KAAK,UAAU,SAAS,OAAO,MAAM;EACrC,OAAO,iBACN,eACM;GACL,KAAK,aAAa;GAClB,KAAK,kBAAkB;EACxB,GACA,EAAE,MAAM,KAAK,CACd;CACD;CAEA,AAAU,qBAA4D,CAEtE;CAEA,AAAU,cAAuC;EAChD,OAAO;CACR;CAMA,AAAU,WAA+B;EACxC,OAAO,KAAK,UAAU,CAAC,EAAE,aAAa,KAAK,WAAW;CACvD;CAEA,AAAU,UAAU,MAAoB;EACvC,KAAK,UAAU;CAChB;CAEA,AAAU,cAAoB,CAE9B;CAEA,AAAU,MAAM,MAAuB;EACtC,MAAM,WAAW,KAAK;EAEtB,KAAK,OAAO,KAAK,SAAS,MAAM,MAAM,GAAG,KAAK,MAAM,IAAI,IAAI;EAC5D,IAAI,KAAK,WAAW,UAAU,OAAO;EAErC,KAAK,cAAc,IAAI,MAAM,SAAS;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;EAExE,OAAO;CACR;CAEA,AAAU,YAAqB;EAC9B,OAAO,KAAK,QAAQ,WAAW;CAChC;CAEA,AAAU,aAAsB;EAC/B,OAAO,KAAK,OAAO;CACpB;CAEA,AAAU,aAAsB;EAC/B,OAAO;CACR;CAEA,AAAU,UAAwB;EACjC,IAAI,KAAK,UAAU,OAAO,KAAK;EAE/B,MAAM,EAAE,QAAQ,aAAa;EAE7B,KAAK,WAAW,aAAa;GAC5B,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;GACzC,GAAI,KAAK,aAAa,EAAE,WAAW,KAAK,WAAW,IAAI,CAAC;GACxD,KAAK,KAAK;GACV,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;GAC7C,WAAW,KAAK;GAChB,YAAY,KAAK,WAAW;GAC5B,KAAK,KAAK;GACV,MAAM,KAAK;GACX,OAAO,KAAK;EACb,CAAC;EAED,OAAO,KAAK;CACb;CAEA,AAAU,cAAsB;EAC/B,OAAO,KAAK,UAAU,KAAK,QAAQ,CAAC,CAAC,OAAO;CAC7C;CAEA,AAAU,WAAmB;EAC5B,MAAM,OAAO,KAAK,SAAS;EAE3B,OAAO,SAAS,SAAY,KAAK,SAAU,KAAK,WAAW;CAC5D;CAEA,AAAU,eAAmC,CAE7C;CAEA,AAAU,qBAA2B,CAErC;CAEA,AAAU,sBAA0C;EACnD,OAAO,KAAK;CACb;CAEA,AAAU,eAAuB;EAChC,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,KAAK;CACpC;CAEA,AAAU,SAAe;EACxB,IAAI,KAAK,QAAQ,GAAG,KAAK,eAAe;EACxC,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS;CACjD;CAEA,AAAU,gBAAsB;EAC/B,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,SAAS;EAEd,MAAM,EAAE,QAAQ,UAAU,KAAK,OAAO;EACtC,MAAM,OAAO,UAAU,SAAY,SAAY,KAAK,SAAS,KAAK;EAElE,QAAQ,OAAO,KAAK;GAAE,QAAQ,QAAQ;GAAQ,QAAQ,UAAU,SAAS;GAAI;EAAK,CAAC;CACpF;CAEA,AAAU,aAAa,OAAqB;EAC3C,KAAK,QAAQ,OAAO,KAAK;CAC1B;CAEA,AAAU,kBAA2B;EACpC,OAAO;CACR;CAEA,AAAU,eAAmC,CAE7C;CAEA,AAAU,YAAgC,CAE1C;CAEA,AAAU,SAAS,SAAsB,UAAwC;EAChF,OAAO,KAAK,IAAI,GAAG,eAAe,iBAAiB,OAAO,GAAG,UAAU,gBAAgB,CAAC;CACzF;CAEA,AAAU,qBACT,SACA,QACA,MACO;EACP,MAAM,QAAQ,SAAS,UAAa,SAAS,OAAO,SAAY,SAAS,IAAI;EAC7E,IAAI,UAAU,UAAa,CAAC,OAAO,SAAS,KAAK,GAAG;EAEpD,KAAK,mBAAmB;EACxB,IAAI,KAAK,QAAQ,GAAG,KAAK,2BAA2B,SAAS,MAAM;CACpE;CAEA,AAAU,iBACT,SACA,QACA,YACO;EACP,MAAM,EAAE,UAAU;EAClB,MAAM,UAAU,KAAK,QAAQ;EAC7B,MAAM,QAAQ,QAAQ,aAAa,KAAK,MAAM;EAC9C,MAAM,QAAQ,QAAQ,aAAa,KAAK,SAAS,UAAU;EAC3D,MAAM,EAAE,kBAAkB;EAE1B,MAAM,YAAY,YAAY,OAAO,SAAS,OAAO,KAAK,CAAC;EAC3D,MAAM,YACL,YAAY,OAAO,UACnB,OAAO,QAAQ,aAAa,KAAK,YAAY,CAAC,CAAC,CAChD;EACA,MAAM,YAAY,YAAY,OAAO,mBAAmB,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC,CAAC;EACtF,MAAM,YAAY,YAAY,OAAO,iBAAiB,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC,CAAC;EACpF,IAAI,kBAAkB,QAAW,MAAM,eAAe,YAAY,OAAO,gBAAgB;OACpF,MAAM,YAAY,YAAY,OAAO,kBAAkB,OAAO,aAAa,CAAC;EACjF,KAAK,2BAA2B,SAAS,MAAM;CAChD;CAEA,WAAW,SAAsB,QAAiC;EACjE,MAAM,QAAQ,aAAa,SAAS,SAAS,gBAAgB;EAC7D,MAAM,SAAS,QAAQ,cAA2B,WAAW;EAG7D,MAAM,KAAK,eAAe,KAAK;EAC/B,IAAI,QAAQ,KAAK,WAAW;GAAE,QAAQ;GAAS,QAAQ,IAAI,QAAQ,MAAM;EAAE;EAE3E,MAAM,QAAQ,IAAI,WAAW,OAAO;GACnC,SAAS,SAAS;IAEjB,KAAK,SAAS,KAAK,eAAe,OAAO,WAAU,CAAE,IAAI,CAAC;GAC3D;GAEA,YAAa,KAAK,cAAc,KAAK,YAAY,OAAO,KAAK,MAAM;GACnE,SAAS,WAAW;IACnB,IAAI,QAAQ,KAAK,cAAc,OAAO,IAAI;IAC1C,KAAK,YAAY,WAAW,MAAM;IAClC,KAAK,OAAO;GACb;EACD,CAAC;EAED,KAAK,SAAS;EACd,MAAM,KAAK,SAAS,MAAM;EAE1B,OAAO;CACR;CAEA,UAAU,SAAsB,OAAmB,QAA2B;EAC7E,QAAQ,iBACP,YACC,UAAU;GACV,IAAI,KAAK,WAAW,KAAK,MAAM,oBAAoB,MAAM,WAAW,SAAS;GAE7E,KAAK,YAAY,aAAa,KAAK;GACnC,IAAI,MAAM,QAAQ,SAAS;IAC1B,IAAI,KAAK,aAAa,MAAM,QAAW;IAEvC,MAAM,eAAe;IACrB,MAAM,KAAK;IACX;GACD;GAEA,MAAM,OAAO,KAAK,WAAW,MAAM,GAAG;GACtC,IAAI,SAAS,QAAW;GAExB,MAAM,eAAe;GACrB,KAAK,OAAO,OAAO,IAAI;GACvB,KAAK,OAAO,OAAO,MAAM;GACzB,KAAK,YAAY;EAClB,GACA,EAAE,OAAO,CACV;EACA,QAAQ,iBACP,UACC,UAAU;GAEV,MAAM,SAAS,MAAM,QAAQ;GAE7B,IAAI,UAAU,MAAM,QAAQ,KAAK,WAAW,KAAK,KAAK,aAAa;GACnE,IAAI,UAAU,KAAK,UAAU,GAAG;GAChC,IAAI,UAAU,KAAK,QAAQ,CAAC,CAAC,UAAU,MAAM,KAAK,KAAK,MAAM,MAAM,QAClE,KAAK,YAAY;EAEnB,GACA,EAAE,OAAO,CACV;EACA,QAAQ,iBACP,cACM;GACL,KAAK,aAAa;GAClB,KAAK,kBAAkB;GACvB,KAAK,YAAY;EAClB,GACA,EAAE,OAAO,CACV;CACD;CAEA,QAAQ,MAAc,YAAwB,GAAS;EACtD,MAAM,SAAS,OAAO,SAAS,IAAI,IAAK,KAAK,QAAQ,MAAM,SAAS,KAAK,OAAQ;EAEjF,IAAI,KAAK,MAAM,MAAM,GAAG,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;CAClF;CAEA,oBAA0B;EACzB,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG,KAAK,YAAY;CACnD;CAEA,YAAmC;EAClC,OAAO,KAAK,cAAc,QAAQ;CACnC;CAEA,QAAQ,MAAiB,OAA2B;EACnD,MAAM,YAAY,KAAK,UAAU,KAAK,MAAM;EAC5C,MAAM,aAAa,KAAK,MAAM;EAC9B,MAAM,UAAU,KAAK,QAAQ;EAC7B,MAAM,EAAE,OAAO,UAAU,SAAS,SAAS,KAAK,OAAO;GACtD,QAAQ,MAAM;GACd;GACA,UAAU,KAAK,SAAS,KAAK;EAC9B,CAAC;EAED,KAAK,QAAQ,KAAK,aAAa,SAAS,KAAK;EAC7C,IAAI,UAAU,QAAW;EAEzB,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI;EAElC,MAAM,aAAa,cAAc,KAAK;EAEtC,IAAI,YAAY;GACf,KAAK,YAAY;GACjB,KAAK,YAAY,cAAc,SAAS;EACzC;EACA,KAAK,MAAM,YAAY,KAAK,YAAY,KAAK;EAC7C,IAAI,YAAY,KAAK,kBAAkB,IAAI;CAC5C;CAEA,YAAkB;EACjB,KAAK,QAAQ,MAAM,KAAK;EACxB,KAAK,cAAc,IAAI;EACvB,KAAK,aAAa;CACnB;CAEA,eAAqB;EACpB,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO;EAEZ,KAAK,YAAY;EACjB,KAAK,YAAY;EACjB,IAAI,KAAK,WAAW,MAAM,WAAW,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;CAC/F;CAEA,UAAmB;EAClB,OAAO,KAAK,UAAU,MAAM,UAAa,KAAK,cAAc;CAC7D;CAEA,WAAW,KAAiC;EAC3C,IAAI,UAAU,IAAI,GAAG,GAAG,OAAO,KAAK;EAEpC,OAAO,KAAK,QAAQ,CAAC,CAAC,UAAU,KAAK,KAAK,QAAQ,KAAK,OAAO;CAC/D;CAEA,OAAO,OAAsB,MAAoB;EAChD,IAAI,MAAM,UAAU,KAAK,gBAAgB,GAAG;GAC3C,KAAK,UAAU,MAAM,KAAK,IAAI;GAC9B;EACD;EAEA,KAAK,aAAa;EAClB,KAAK,QAAQ,MAAM,OAAO,KAAK,SAAS,IAAI,EAAE;CAC/C;CAEA,aAAa,MAAuB;EACnC,aAAa,KAAK,WAAW;EAC7B,KAAK,OAAO,QAAQ,MAAM;EAC1B,KAAK,YAAY,cAAc,KAAK;EACpC,KAAK,YAAY;EACjB,KAAK,cAAc,KAAK;EACxB,IAAI,KAAK,WAAW,KAAK,WAAW,KAAK,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;EAC7F,KAAK,YAAY;CAClB;CAEA,YAAY,SAAsB,aAA+C;EAChF,KAAK,eAAe,OAAO,KAAK,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;EAC5D,IAAI,KAAK,QAAQ,QAAQ;GACxB,KAAK,MAAM,QAAQ,gBAAgB,QAAQ,gBAAgB,IAAI;GAC/D,KAAK,cAAc,SAAS,KAAK;GACjC,KAAK,cAAc;GACnB;EACD;EAEA,MAAM,CAAC,KAAK,QAAQ,KAAK,QAAQ,CAAC,CAAC;EAEnC,eAAe,SAAS,QAAQ,KAAK,YAAY,CAAC;EAClD,eAAe,SAAS,iBAAiB,OAAO,GAAG,CAAC;EACpD,eAAe,SAAS,iBAAiB,OAAO,IAAI,CAAC;EACrD,eAAe,SAAS,iBAAiB,OAAO,KAAK,WAAW,CAAC,CAAC;EAClE,IAAI,aAAa,eAAe,SAAS,oBAAoB,WAAW;EACxE,eACC,SACA,mBACC,KAAK,sBAAsB,KAAK,aAAY,GAAI,KAAK,MAAM,CAC7D;EACA,KAAK,cAAc,SAAS,IAAI;EAChC,KAAK,gBAAgB,OAAO;EAC5B,KAAK,cAAc;CACpB;CAEA,iBAAuB;EACtB,KAAK,KAAK;EACV,KAAK,YACJ,aACA,CAAC,KAAK,WAAW,KAAK,KAAK,WAAW,KAAK,QAAQ,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAC7E;EACA,KAAK,YAAY,KAAK,YAAY,GAAG,KAAK,mBAAmB,CAAC;CAC/D;CAEA,gBAAgB,SAA4B;EAC3C,MAAM,aAAa,KAAK,WAAW;EAEnC,eAAe,SAAS,iBAAiB,aAAa,SAAS,MAAS;EAExE,MAAM,OAAO,KAAK,aAAa,UAAU,MAAM,OAAO,OAAO;EAE7D,eAAe,SAAS,YAAY,aAAa,SAAY,IAAI;CAClE;CAEA,kBAAkB,MAAuB;EACxC,MAAM,aAAa,KAAK,cAAc,CAAC,KAAK;EAE5C,IAAI,YAAY,KAAK,OAAO,OAAO,MAAM;OACpC,KAAK,OAAO,QAAQ,MAAM;EAC/B,KAAK,YAAY;EACjB,KAAK,cAAc,UAAU;CAC9B;CAEA,cAAoB;EACnB,IAAI,KAAK,SAAS,MAAM,QAAW,KAAK,UAAU;EAClD,KAAK,cAAc;EACnB,KAAK,YAAY;CAClB;CAEA,SAAe;EACd,KAAK,QAAQ,KAAK,WAAW,GAAG;CACjC;CAEA,QAAQ,MAAuB;EAC9B,IAAI,KAAK,cAAc,KAAK,UAAU,MAAM,MAAM;EAElD,KAAK,aAAa;EAClB,KAAK,kBAAkB,IAAI;CAC5B;CAEA,UAAU,KAAa,MAAoB;EAC1C,IAAI,KAAK,WAAW,QAAQ,KAAK;GAChC,KAAK,aAAa;GAClB,KAAK,YAAY;IAAE,WAAW,KAAK;IAAQ;GAAI;EAChD;EACA,KAAK,MAAM,IAAI;CAChB;CAEA,SAAyD;EACxD,IAAI,KAAK,UAAU,GAAG,OAAO;GAAE,QAAQ;GAAM,OAAO;EAAU;EAE9D,MAAM,aAAa,KAAK,OAAO;EAC/B,MAAM,UAAU,aAAa,SAAY,KAAK,aAAa;EAE3D,OAAO;GACN,SAAS,cAAc,YAAY,WAAc,KAAK;GACtD,OAAO,WAAW,KAAK;EACxB;CACD;CAEA,cAAc,YAA2B;EACxC,IAAI,eAAe,KAAK,aAAa;EAErC,KAAK,cAAc;EACnB,KAAK,YAAY,YAAY,UAAU;EACvC,KAAK,cAAc,IAAI,MAAM,gBAAgB,EAAE,SAAS,KAAK,CAAC,CAAC;CAChE;CAEA,aAAqB;EACpB,MAAM,OAAO,KAAK;EAElB,OAAO,SAAS,UAAa,OAAO,IACjC,UAAU,KAAK,MAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAC/C,KAAK;CACT;CAEA,cAAoB;EACnB,MAAM,SAAS,KAAK,aAAa;EACjC,IAAI,WAAW,QAAW;EAG1B,IAAI,KAAK,QAAQ,CAAC,CAAC,KAAK,MAAM,MAAM,KAAK,QAAQ,KAAK,YAAY,aAAa,IAAI;EACnF,KAAK,QAAQ,MAAM;CACpB;CAEA,WAAW,SAAsB,MAAiB,OAAgC;EACjF,MAAM,UAAU,KAAK,QAAQ;EAC7B,MAAM,SAAS,KAAK;EACpB,MAAM,QAAQ;GACb,MAAM,KAAK;GACX,UAAU,KAAK,SAAS,KAAK;GAC7B,YAAY,KAAK,kBAAkB,QAAQ,aAAa,KAAK,MAAM;GACnE,aAAa,gBAAgB,MAAM,WAAW;GAC9C,UAAU,KAAK;EAChB;EACA,IAAI,WAAW,QAAW,OAAO,UAAU,SAAS,KAAK;EAEzD,MAAM,SAAS,eAAe,iBAAiB,OAAO,GAAG,wBAAwB,YAAY;EAE7F,OAAO,UAAU,SAAS;GACzB,GAAG;GACH,QAAQ;IAAE,OAAO;IAAQ,MAAM,SAAS,KAAK;GAAS;EACvD,CAAC;CACF;CAEA,SAAS,OAAuB;EAC/B,OAAO,KAAK,eAAe,KAAK,KAAK,OAAO,KAAK;CAClD;CAEA,aAAa,SAAuB,OAA6B;EAChE,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,SAAS,QAAQ,YAAY,OAAO;EAEzC,MAAM,CAAC,KAAK,QAAQ;EAEpB,OAAO;GACN,GAAG;GACH,eAAe,MACd,MAAM,eACN,QAAQ,aAAa,GAAG,GACxB,QAAQ,aAAa,IAAI,CAC1B;EACD;CACD;CAEA,OAAO,MAAoB;EAC1B,IAAI,CAAC,OAAO,SAAS,IAAI,GAAG;EAE5B,MAAM,UAAU,KAAK,QAAQ,CAAC,CAAC,KAAK,IAAI;EAExC,KAAK,SAAS;EACd,IAAI,YAAY,KAAK,QAAQ;EAE7B,KAAK,SAAS;EACd,KAAK,OAAO;CACb;CAEA,2BAA2B,SAAsB,QAAiC;EACjF,MAAM,kBAAkB,KAAK,WAAW,IAAI,SAAY,KAAK;EAC7D,MAAM,cAAc,oBAAoB;EAExC,IAAI,gBAAgB,KAAK,cAAc;GACtC,KAAK,eAAe;GACpB,KAAK,YAAY,aAAa,WAAW;EAC1C;EACA,IAAI,oBAAoB,QAAW;GAClC,QAAQ,MAAM,eAAe,YAAY,OAAO,kBAAkB;GAClE;EACD;EAEA,QAAQ,MAAM,YACb,YAAY,OAAO,oBACnB,OAAO,KAAK,QAAQ,CAAC,CAAC,aAAa,eAAe,CAAC,CACpD;CACD;AACD"}
@@ -1,7 +1,7 @@
1
1
  import { SonicValueElement } from "./value-element.js";
2
2
  import { Surface, SurfaceFrame } from "../lib/canvas-surface.js";
3
3
  //#region src/elements/wave-element.d.ts
4
- interface WaveMarker {
4
+ export interface WaveMarker {
5
5
  dimmed?: boolean;
6
6
  end?: number;
7
7
  kind?: string;
@@ -10,6 +10,10 @@ interface WaveMarker {
10
10
  }
11
11
  export declare abstract class SonicWaveElement<Colour extends string, Length extends string = never> extends SonicValueElement {
12
12
  #private;
13
+ static readonly observedAttributes: string[];
14
+ get currentMarker(): undefined | WaveMarker;
15
+ get fill(): boolean;
16
+ set fill(isFilling: boolean);
13
17
  get markers(): Array<WaveMarker>;
14
18
  set markers(list: Iterable<WaveMarker> | undefined);
15
19
  protected abstract readonly canvas: HTMLCanvasElement;
@@ -17,6 +21,8 @@ export declare abstract class SonicWaveElement<Colour extends string, Length ext
17
21
  protected abstract readonly control: HTMLElement;
18
22
  protected abstract readonly lengths: Record<Length, `--_sonic-${string}`>;
19
23
  protected abstract readonly sheet: string;
24
+ protected abstract readonly sizeProperty: `--_sonic-${string}`;
25
+ attributeChangedCallback(name: string): void;
20
26
  connectedCallback(): void;
21
27
  repaint(): void;
22
28
  protected connect(signal: AbortSignal): void;
@@ -27,10 +33,10 @@ export declare abstract class SonicWaveElement<Colour extends string, Length ext
27
33
  protected markerList(): ReadonlyArray<WaveMarker>;
28
34
  protected markerProportions(): Array<[number, number]>;
29
35
  protected abstract paint(context: CanvasRenderingContext2D, frame: SurfaceFrame<Colour, Length>): void;
30
- protected playback(): number;
31
36
  protected proportionsChanged(): void;
32
37
  protected renderEmpty(): void;
33
38
  protected abstract renderMarkers(): void;
39
+ protected showCurrentMarker(seconds: number): void;
34
40
  protected surface(): Surface | undefined;
35
41
  }
36
42
  //#endregion