@xsynaptic/sonic-ui 0.1.0 → 0.2.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 (117) hide show
  1. package/README.md +8 -1
  2. package/dist/default/define/dial.js +7 -0
  3. package/dist/default/define/key.js +7 -0
  4. package/dist/default/define/meter.js +7 -0
  5. package/dist/default/define/segmented.js +7 -0
  6. package/dist/default/define/slider.js +7 -0
  7. package/dist/default/elements/define-once.js +7 -0
  8. package/dist/{elements → default/elements}/dial.js +15 -3
  9. package/dist/default/elements/form-element.js +56 -0
  10. package/dist/default/elements/key.js +144 -0
  11. package/dist/{elements → default/elements}/meter.js +27 -16
  12. package/dist/default/elements/range-element.js +410 -0
  13. package/dist/{elements → default/elements}/range-entry.js +5 -4
  14. package/dist/default/elements/segmented.js +173 -0
  15. package/dist/{elements → default/elements}/slider.js +23 -8
  16. package/dist/default/elements/sonic-element.js +153 -0
  17. package/dist/{index.js → default/index.js} +2 -1
  18. package/dist/default/lib/copy-node.js +30 -0
  19. package/dist/default/lib/percent.js +12 -0
  20. package/dist/default/lib/read-px-property.js +8 -0
  21. package/dist/{lib → default/lib}/render.js +9 -2
  22. package/dist/default/lib/taper.js +32 -0
  23. package/dist/default/lib/write-attribute.js +11 -0
  24. package/dist/dev/define/dial.js.map +1 -0
  25. package/dist/dev/define/key.js.map +1 -0
  26. package/dist/dev/define/meter.js.map +1 -0
  27. package/dist/dev/define/segmented.js.map +1 -0
  28. package/dist/dev/define/slider.js.map +1 -0
  29. package/dist/dev/define.js +5 -0
  30. package/dist/dev/elements/define-once.js.map +1 -0
  31. package/dist/{elements → dev/elements}/dial.d.ts +4 -0
  32. package/dist/dev/elements/dial.js +70 -0
  33. package/dist/dev/elements/dial.js.map +1 -0
  34. package/dist/dev/elements/form-element.d.ts +22 -0
  35. package/dist/dev/elements/form-element.js +57 -0
  36. package/dist/dev/elements/form-element.js.map +1 -0
  37. package/dist/dev/elements/key.d.ts +30 -0
  38. package/dist/{elements → dev/elements}/key.js +71 -25
  39. package/dist/dev/elements/key.js.map +1 -0
  40. package/dist/{elements → dev/elements}/meter.d.ts +6 -0
  41. package/dist/dev/elements/meter.js +131 -0
  42. package/dist/dev/elements/meter.js.map +1 -0
  43. package/dist/{elements → dev/elements}/range-element.d.ts +25 -5
  44. package/dist/{elements → dev/elements}/range-element.js +116 -53
  45. package/dist/dev/elements/range-element.js.map +1 -0
  46. package/dist/dev/elements/range-entry.js +75 -0
  47. package/dist/dev/elements/range-entry.js.map +1 -0
  48. package/dist/{elements → dev/elements}/segmented.d.ts +5 -2
  49. package/dist/dev/elements/segmented.js +174 -0
  50. package/dist/dev/elements/segmented.js.map +1 -0
  51. package/dist/{elements → dev/elements}/slider.d.ts +6 -0
  52. package/dist/dev/elements/slider.js +86 -0
  53. package/dist/dev/elements/slider.js.map +1 -0
  54. package/dist/dev/elements/sonic-element.d.ts +33 -0
  55. package/dist/dev/elements/sonic-element.js +169 -0
  56. package/dist/dev/elements/sonic-element.js.map +1 -0
  57. package/dist/{index.d.ts → dev/index.d.ts} +2 -1
  58. package/dist/dev/index.js +8 -0
  59. package/dist/dev/lib/copy-node.js +31 -0
  60. package/dist/dev/lib/copy-node.js.map +1 -0
  61. package/dist/dev/lib/percent.d.ts +5 -0
  62. package/dist/dev/lib/percent.js +13 -0
  63. package/dist/dev/lib/percent.js.map +1 -0
  64. package/dist/dev/lib/read-px-property.js.map +1 -0
  65. package/dist/dev/lib/render.js +27 -0
  66. package/dist/dev/lib/render.js.map +1 -0
  67. package/dist/dev/lib/taper.js.map +1 -0
  68. package/dist/dev/lib/write-attribute.js.map +1 -0
  69. package/dist/skins/ivory.css +3 -3
  70. package/dist/skins/slate.css +4 -4
  71. package/dist/styles/controls.css +0 -1
  72. package/dist/styles/dial.css +33 -13
  73. package/dist/styles/key.css +30 -10
  74. package/dist/styles/material.css +58 -10
  75. package/dist/styles/meter.css +25 -5
  76. package/dist/styles/screen.css +7 -1
  77. package/dist/styles/segmented.css +24 -7
  78. package/dist/styles/slider.css +17 -4
  79. package/package.json +13 -12
  80. package/dist/define/dial.js.map +0 -1
  81. package/dist/define/key.js.map +0 -1
  82. package/dist/define/meter.js.map +0 -1
  83. package/dist/define/segmented.js.map +0 -1
  84. package/dist/define/slider.js.map +0 -1
  85. package/dist/elements/define-once.js.map +0 -1
  86. package/dist/elements/dial.js.map +0 -1
  87. package/dist/elements/key.d.ts +0 -17
  88. package/dist/elements/key.js.map +0 -1
  89. package/dist/elements/meter.js.map +0 -1
  90. package/dist/elements/range-element.js.map +0 -1
  91. package/dist/elements/range-entry.js.map +0 -1
  92. package/dist/elements/segmented.js +0 -104
  93. package/dist/elements/segmented.js.map +0 -1
  94. package/dist/elements/slider.js.map +0 -1
  95. package/dist/elements/sonic-element.d.ts +0 -20
  96. package/dist/elements/sonic-element.js +0 -94
  97. package/dist/elements/sonic-element.js.map +0 -1
  98. package/dist/lib/read-px-property.js.map +0 -1
  99. package/dist/lib/render.js.map +0 -1
  100. package/dist/lib/taper.js.map +0 -1
  101. package/dist/lib/write-attribute.js.map +0 -1
  102. /package/dist/{define.js → default/define.js} +0 -0
  103. /package/dist/{define → dev/define}/dial.d.ts +0 -0
  104. /package/dist/{define → dev/define}/dial.js +0 -0
  105. /package/dist/{define → dev/define}/key.d.ts +0 -0
  106. /package/dist/{define → dev/define}/key.js +0 -0
  107. /package/dist/{define → dev/define}/meter.d.ts +0 -0
  108. /package/dist/{define → dev/define}/meter.js +0 -0
  109. /package/dist/{define → dev/define}/segmented.d.ts +0 -0
  110. /package/dist/{define → dev/define}/segmented.js +0 -0
  111. /package/dist/{define → dev/define}/slider.d.ts +0 -0
  112. /package/dist/{define → dev/define}/slider.js +0 -0
  113. /package/dist/{define.d.ts → dev/define.d.ts} +0 -0
  114. /package/dist/{elements → dev/elements}/define-once.js +0 -0
  115. /package/dist/{lib → dev/lib}/read-px-property.js +0 -0
  116. /package/dist/{lib → dev/lib}/taper.js +0 -0
  117. /package/dist/{lib → dev/lib}/write-attribute.js +0 -0
@@ -1,52 +1,105 @@
1
- import { SonicElement } from "./sonic-element.js";
2
1
  import { requireChild, template } from "../lib/render.js";
2
+ import { SonicFormElement } from "./form-element.js";
3
+ import { copyNode } from "../lib/copy-node.js";
3
4
 
4
5
  //#region src/elements/key.ts
5
6
  const renderKey = template(`
6
7
  <button class="sonic-key" type="button"><span class="sonic-key-cap"></span></button>
7
8
  `, HTMLButtonElement);
8
9
  const holdKeys = /* @__PURE__ */ new Set([" ", "Enter"]);
9
- var SonicKey = class extends SonicElement {
10
+ var SonicKey = class extends SonicFormElement {
10
11
  static observedAttributes = [
11
- ...SonicElement.observedAttributes,
12
+ ...SonicFormElement.observedAttributes,
12
13
  "momentary",
13
14
  "pressed",
14
- "toggle"
15
+ "toggle",
16
+ "value"
15
17
  ];
16
- get pressed() {
18
+ get defaultPressed() {
17
19
  return this.hasAttribute("pressed");
18
20
  }
21
+ set defaultPressed(isPressed) {
22
+ this.reflect("pressed", isPressed);
23
+ }
24
+ get momentary() {
25
+ return this.hasAttribute("momentary");
26
+ }
27
+ set momentary(isMomentary) {
28
+ this.reflect("momentary", isMomentary);
29
+ }
30
+ get pressed() {
31
+ return this.#isDirty ? this.#pressed : this.defaultPressed;
32
+ }
19
33
  set pressed(isPressed) {
20
- this.toggleAttribute("pressed", isPressed);
34
+ this.#isDirty = true;
35
+ this.#pressed = isPressed === true;
36
+ this.render();
37
+ }
38
+ get toggle() {
39
+ return this.hasAttribute("toggle");
40
+ }
41
+ set toggle(isToggle) {
42
+ this.reflect("toggle", isToggle);
43
+ }
44
+ get value() {
45
+ return this.getAttribute("value") ?? "on";
46
+ }
47
+ set value(value) {
48
+ this.reflect("value", value);
21
49
  }
22
50
  #holder;
51
+ #isDirty = false;
23
52
  #key = renderKey();
53
+ #pressed = false;
24
54
  attributeChangedCallback(name) {
25
- if (name === "disabled" && this.disabled) this.#release();
26
- this.#render();
55
+ if (name === "pressed") this.#isDirty = false;
56
+ if (name === "disabled" && this.isDisabled()) this.#release();
57
+ this.render();
58
+ }
59
+ formResetCallback() {
60
+ this.attributeChangedCallback("pressed");
61
+ }
62
+ activate() {
63
+ this.#key.click();
27
64
  }
28
65
  connect(signal) {
29
66
  const key = this.#key;
30
67
  const cap = requireChild(key, ".sonic-key-cap", HTMLSpanElement);
31
- this.upgradeProperty("pressed");
32
- this.adoptChildren(() => {
33
- const arrivals = [...this.childNodes].filter((node) => node !== key);
34
- if (key.parentNode === this) cap.append(...arrivals);
35
- else cap.replaceChildren(...arrivals);
36
- this.appendOnce(key);
68
+ this.upgradeProperties("defaultPressed", "momentary", "toggle", "pressed", "value");
69
+ this.mirrorChildren({
70
+ control: key,
71
+ copy: (originals) => {
72
+ cap.replaceChildren(...originals.map((original) => copyNode(original)));
73
+ }
37
74
  }, signal);
38
- this.#render();
75
+ this.render();
39
76
  this.checkStyles(key, "key.css");
40
77
  signal.addEventListener("abort", () => {
41
78
  this.#release();
42
79
  }, { once: true });
43
80
  key.addEventListener("click", () => {
44
- if (!this.hasAttribute("toggle")) return;
81
+ if (!this.toggle) return;
45
82
  this.pressed = !this.pressed;
46
83
  this.dispatchEvent(new Event("change", { bubbles: true }));
47
84
  }, { signal });
48
85
  this.#bindMomentary(key, signal);
49
86
  }
87
+ focusTarget() {
88
+ return this.#key;
89
+ }
90
+ render() {
91
+ const key = this.#key;
92
+ key.disabled = this.isDisabled();
93
+ key.removeAttribute("aria-pressed");
94
+ if (this.toggle) key.setAttribute("aria-pressed", String(this.pressed));
95
+ this.toggleState("pressed", this.pressed);
96
+ this.forwardNaming(key, true);
97
+ const submitted = this.toggle && this.pressed ? this.value : null;
98
+ this.writeFormValue(submitted, String(this.pressed));
99
+ }
100
+ restoreState(state) {
101
+ if (this.toggle) this.pressed = state === "true";
102
+ }
50
103
  #bindMomentary(key, signal) {
51
104
  const releasePointer = (event) => {
52
105
  if (event.pointerId === this.#holder) this.#release();
@@ -71,13 +124,13 @@ var SonicKey = class extends SonicElement {
71
124
  }, { signal });
72
125
  }
73
126
  #hold(holder) {
74
- if (this.disabled || this.#holder !== void 0) return;
127
+ if (this.isDisabled() || this.#holder !== void 0) return;
75
128
  this.#holder = holder;
76
129
  this.pressed = true;
77
130
  this.dispatchEvent(new Event("change", { bubbles: true }));
78
131
  }
79
132
  #isMomentary() {
80
- return this.hasAttribute("momentary") && !this.hasAttribute("toggle");
133
+ return this.momentary && !this.toggle;
81
134
  }
82
135
  #release() {
83
136
  if (this.#holder === void 0) return;
@@ -85,13 +138,6 @@ var SonicKey = class extends SonicElement {
85
138
  this.pressed = false;
86
139
  this.dispatchEvent(new Event("change", { bubbles: true }));
87
140
  }
88
- #render() {
89
- const key = this.#key;
90
- key.disabled = this.disabled;
91
- key.removeAttribute("aria-pressed");
92
- if (this.hasAttribute("toggle")) key.setAttribute("aria-pressed", String(this.pressed));
93
- this.forwardNaming(key, true);
94
- }
95
141
  };
96
142
 
97
143
  //#endregion
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.js","names":[],"sources":["../../../src/elements/key.ts"],"sourcesContent":["import { SonicFormElement } from '#elements/form-element.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { requireChild, template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-key': SonicKey;\n\t}\n}\n\nconst renderKey = template(\n\t/* HTML */ `\n\t\t<button class=\"sonic-key\" type=\"button\"><span class=\"sonic-key-cap\"></span></button>\n\t`,\n\tHTMLButtonElement,\n);\n\nconst holdKeys = new Set([' ', 'Enter']);\n\nexport class SonicKey extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'momentary',\n\t\t'pressed',\n\t\t'toggle',\n\t\t'value',\n\t];\n\n\t// The `pressed` attribute, as `defaultChecked` holds a checkbox's `checked` attribute\n\tget defaultPressed(): boolean {\n\t\treturn this.hasAttribute('pressed');\n\t}\n\n\tset defaultPressed(isPressed: boolean) {\n\t\tthis.reflect('pressed', isPressed);\n\t}\n\n\tget momentary(): boolean {\n\t\treturn this.hasAttribute('momentary');\n\t}\n\n\tset momentary(isMomentary: boolean) {\n\t\tthis.reflect('momentary', isMomentary);\n\t}\n\n\t// The live state, which never writes the attribute, as `value` on the range\n\tget pressed(): boolean {\n\t\treturn this.#isDirty ? this.#pressed : this.defaultPressed;\n\t}\n\n\tset pressed(isPressed: boolean | undefined) {\n\t\tthis.#isDirty = true;\n\t\tthis.#pressed = isPressed === true;\n\t\tthis.render();\n\t}\n\n\tget toggle(): boolean {\n\t\treturn this.hasAttribute('toggle');\n\t}\n\n\tset toggle(isToggle: boolean) {\n\t\tthis.reflect('toggle', isToggle);\n\t}\n\n\t// What a pressed toggle submits, reading `on` while unset as a checkbox does\n\tget value(): string {\n\t\treturn this.getAttribute('value') ?? 'on';\n\t}\n\n\tset value(value: string | undefined) {\n\t\tthis.reflect('value', value);\n\t}\n\n\t#holder: number | string | undefined;\n\n\t// Re-read from the attribute until a press or a write\n\t// An attribute write clears it, so a framework driving `pressed` keeps control\n\t#isDirty = false;\n\n\treadonly #key = renderKey();\n\n\t#pressed = false;\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (name === 'pressed') this.#isDirty = false;\n\t\tif (name === 'disabled' && this.isDisabled()) this.#release();\n\t\tthis.render();\n\t}\n\n\t// Back to the `pressed` attribute, as a checkbox resets to `checked`\n\toverride formResetCallback(): void {\n\t\tthis.attributeChangedCallback('pressed');\n\t}\n\n\t// As a checkbox's label toggles it\n\tprotected override activate(): void {\n\t\tthis.#key.click();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst key = this.#key;\n\t\tconst cap = requireChild(key, '.sonic-key-cap', HTMLSpanElement);\n\n\t\tthis.upgradeProperties('defaultPressed', 'momentary', 'toggle', 'pressed', 'value');\n\t\tthis.mirrorChildren(\n\t\t\t{\n\t\t\t\tcontrol: key,\n\t\t\t\tcopy: (originals) => {\n\t\t\t\t\tcap.replaceChildren(...originals.map((original) => copyNode(original)));\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tthis.render();\n\t\tthis.checkStyles(key, 'key.css');\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#release();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\n\t\tkey.addEventListener(\n\t\t\t'click',\n\t\t\t() => {\n\t\t\t\tif (!this.toggle) return;\n\n\t\t\t\tthis.pressed = !this.pressed;\n\t\t\t\tthis.dispatchEvent(new Event('change', { bubbles: true }));\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindMomentary(key, signal);\n\t}\n\n\tprotected override focusTarget(): HTMLElement {\n\t\treturn this.#key;\n\t}\n\n\tprotected render(): void {\n\t\tconst key = this.#key;\n\n\t\tkey.disabled = this.isDisabled();\n\t\tkey.removeAttribute('aria-pressed');\n\t\tif (this.toggle) key.setAttribute('aria-pressed', String(this.pressed));\n\t\tthis.toggleState('pressed', this.pressed);\n\t\tthis.forwardNaming(key, true);\n\n\t\t// eslint-disable-next-line unicorn/no-null -- `null` submits nothing\n\t\tconst submitted = this.toggle && this.pressed ? this.value : null;\n\n\t\t// The state restores an unpressed toggle too\n\t\tthis.writeFormValue(submitted, String(this.pressed));\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tif (this.toggle) this.pressed = state === 'true';\n\t}\n\n\t// Not `click`, which lands a tap late by the finger's dwell\n\t#bindMomentary(key: HTMLButtonElement, signal: AbortSignal): void {\n\t\tconst releasePointer = (event: PointerEvent): void => {\n\t\t\tif (event.pointerId === this.#holder) this.#release();\n\t\t};\n\n\t\tkey.addEventListener(\n\t\t\t'pointerdown',\n\t\t\t(event) => {\n\t\t\t\tif (event.button !== 0 || !this.#isMomentary()) return;\n\n\t\t\t\tkey.setPointerCapture(event.pointerId);\n\t\t\t\tthis.#hold(event.pointerId);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tkey.addEventListener('lostpointercapture', releasePointer, { signal });\n\t\tkey.addEventListener('pointercancel', releasePointer, { signal });\n\t\tkey.addEventListener('pointerup', releasePointer, { signal });\n\t\tkey.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.repeat || !holdKeys.has(event.key) || !this.#isMomentary()) return;\n\n\t\t\t\tthis.#hold(event.key);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tkey.addEventListener(\n\t\t\t'keyup',\n\t\t\t(event) => {\n\t\t\t\tif (event.key === this.#holder) this.#release();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\t// Keyboard holds only; a finger on the next pad takes focus while this one is still held\n\t\tkey.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tif (typeof this.#holder === 'string') this.#release();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#hold(holder: number | string): void {\n\t\tif (this.isDisabled() || this.#holder !== undefined) return;\n\n\t\tthis.#holder = holder;\n\t\tthis.pressed = true;\n\t\tthis.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#isMomentary(): boolean {\n\t\treturn this.momentary && !this.toggle;\n\t}\n\n\t#release(): void {\n\t\tif (this.#holder === undefined) return;\n\n\t\tthis.#holder = undefined;\n\t\tthis.pressed = false;\n\t\tthis.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n}\n"],"mappings":"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"}
@@ -10,6 +10,12 @@ export declare class SonicMeter extends SonicElement {
10
10
  static readonly observedAttributes: string[];
11
11
  get level(): number;
12
12
  set level(amplitude: number);
13
+ get max(): number;
14
+ set max(decibels: number | undefined);
15
+ get min(): number;
16
+ set min(decibels: number | undefined);
17
+ get orientation(): 'horizontal' | 'vertical';
18
+ set orientation(direction: 'horizontal' | 'vertical' | undefined);
13
19
  attributeChangedCallback(): void;
14
20
  protected connect(signal: AbortSignal): void;
15
21
  }
@@ -0,0 +1,131 @@
1
+ import { template } from "../lib/render.js";
2
+ import { SonicElement } from "./sonic-element.js";
3
+
4
+ //#region src/elements/meter.ts
5
+ const renderMeter = template(`
6
+ <div aria-hidden="true" class="sonic-meter">
7
+ <div class="sonic-meter-segments"></div>
8
+ <div class="sonic-meter-level"></div>
9
+ <div class="sonic-meter-clip"></div>
10
+ </div>
11
+ `, HTMLDivElement);
12
+ const releaseDecibelsPerSecond = 20;
13
+ const holdMs = 1500;
14
+ function toDecibels(amplitude) {
15
+ return 20 * Math.log10(Math.abs(amplitude));
16
+ }
17
+ var SonicMeter = class extends SonicElement {
18
+ static observedAttributes = [
19
+ "disabled",
20
+ "max",
21
+ "min"
22
+ ];
23
+ get level() {
24
+ return this.#level;
25
+ }
26
+ set level(amplitude) {
27
+ if (!Number.isFinite(amplitude)) return;
28
+ const decibels = toDecibels(amplitude);
29
+ const now = performance.now();
30
+ this.#level = amplitude;
31
+ this.#target = decibels;
32
+ this.#bar = Math.max(this.#bar, decibels);
33
+ if (decibels >= this.#peak) {
34
+ this.#peak = decibels;
35
+ this.#peakAt = now;
36
+ }
37
+ if (decibels >= 0) this.#clipAt = now;
38
+ this.#render(now);
39
+ this.#schedule(now);
40
+ }
41
+ get max() {
42
+ return this.numberAttribute("max", 0);
43
+ }
44
+ set max(decibels) {
45
+ this.reflect("max", decibels);
46
+ }
47
+ get min() {
48
+ return this.numberAttribute("min", -60);
49
+ }
50
+ set min(decibels) {
51
+ this.reflect("min", decibels);
52
+ }
53
+ get orientation() {
54
+ return this.getAttribute("orientation") === "horizontal" ? "horizontal" : "vertical";
55
+ }
56
+ set orientation(direction) {
57
+ this.reflect("orientation", direction);
58
+ }
59
+ #bar = -Infinity;
60
+ #clipAt = -Infinity;
61
+ #frame;
62
+ #lastFrame;
63
+ #level = 0;
64
+ #meter = renderMeter();
65
+ #peak = -Infinity;
66
+ #peakAt = -Infinity;
67
+ #target = -Infinity;
68
+ attributeChangedCallback() {
69
+ const now = performance.now();
70
+ this.#render(now);
71
+ this.#schedule(now);
72
+ }
73
+ connect(signal) {
74
+ const now = performance.now();
75
+ this.upgradeProperties("max", "min", "orientation", "level");
76
+ this.appendOnce(this.#meter);
77
+ this.#render(now);
78
+ this.#schedule(now);
79
+ this.checkStyles(this.#meter, "meter.css");
80
+ signal.addEventListener("abort", () => {
81
+ if (this.#frame !== void 0) cancelAnimationFrame(this.#frame);
82
+ this.#frame = void 0;
83
+ this.#lastFrame = void 0;
84
+ }, { once: true });
85
+ }
86
+ #fraction(decibels) {
87
+ const min = this.min;
88
+ const range = this.max - min;
89
+ return range > 0 ? Math.min(1, Math.max(0, (decibels - min) / range)) : 0;
90
+ }
91
+ #isSettled(now) {
92
+ const floor = this.min;
93
+ return this.#bar <= Math.max(this.#target, floor) && this.#peak <= Math.max(this.#bar, floor) && now - this.#clipAt >= holdMs;
94
+ }
95
+ #render(now) {
96
+ const meter = this.#meter;
97
+ meter.style.setProperty("--_sonic-meter-min", String(this.min));
98
+ meter.style.setProperty("--_sonic-meter-max", String(this.max));
99
+ if (this.disabled) {
100
+ meter.style.setProperty("--_sonic-meter-level", "0");
101
+ meter.style.setProperty("--_sonic-meter-peak", "0");
102
+ meter.style.setProperty("--_sonic-meter-clipped", "0");
103
+ return;
104
+ }
105
+ meter.style.setProperty("--_sonic-meter-level", String(this.#fraction(this.#bar)));
106
+ meter.style.setProperty("--_sonic-meter-peak", String(this.#fraction(this.#peak)));
107
+ meter.style.setProperty("--_sonic-meter-clipped", now - this.#clipAt < holdMs ? "1" : "0");
108
+ }
109
+ #schedule(now) {
110
+ if (this.#frame !== void 0 || !this.isConnected || this.#isSettled(now)) return;
111
+ if (this.#lastFrame === void 0) this.#lastFrame = now;
112
+ this.#frame = requestAnimationFrame(this.#tick);
113
+ }
114
+ #tick = (time) => {
115
+ const fall = releaseDecibelsPerSecond * Math.max(0, time - (this.#lastFrame ?? time)) / 1e3;
116
+ this.#frame = void 0;
117
+ this.#lastFrame = time;
118
+ this.#bar = Math.max(this.#target, this.min, this.#bar - fall);
119
+ if (time - this.#peakAt >= holdMs) this.#peak = Math.max(this.#bar, this.#peak - fall);
120
+ this.#render(time);
121
+ if (this.#isSettled(time)) {
122
+ this.#lastFrame = void 0;
123
+ return;
124
+ }
125
+ this.#frame = requestAnimationFrame(this.#tick);
126
+ };
127
+ };
128
+
129
+ //#endregion
130
+ export { SonicMeter };
131
+ //# sourceMappingURL=meter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter.js","names":[],"sources":["../../../src/elements/meter.ts"],"sourcesContent":["import { SonicElement } from '#elements/sonic-element.ts';\nimport { template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-meter': SonicMeter;\n\t}\n}\n\nconst renderMeter = template(\n\t/* HTML */ `\n\t\t<div aria-hidden=\"true\" class=\"sonic-meter\">\n\t\t\t<div class=\"sonic-meter-segments\"></div>\n\t\t\t<div class=\"sonic-meter-level\"></div>\n\t\t\t<div class=\"sonic-meter-clip\"></div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nconst releaseDecibelsPerSecond = 20;\nconst holdMs = 1500;\n\nfunction toDecibels(amplitude: number): number {\n\treturn 20 * Math.log10(Math.abs(amplitude));\n}\n\n// `level` is a linear amplitude; `min` and `max` are dBFS\nexport class SonicMeter extends SonicElement {\n\tstatic override readonly observedAttributes = ['disabled', 'max', 'min'];\n\n\tget level(): number {\n\t\treturn this.#level;\n\t}\n\n\tset level(amplitude: number) {\n\t\tif (!Number.isFinite(amplitude)) return;\n\n\t\tconst decibels = toDecibels(amplitude);\n\t\tconst now = performance.now();\n\n\t\tthis.#level = amplitude;\n\t\tthis.#target = decibels;\n\t\tthis.#bar = Math.max(this.#bar, decibels);\n\t\tif (decibels >= this.#peak) {\n\t\t\tthis.#peak = decibels;\n\t\t\tthis.#peakAt = now;\n\t\t}\n\t\tif (decibels >= 0) this.#clipAt = now;\n\t\tthis.#render(now);\n\t\tthis.#schedule(now);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 0);\n\t}\n\n\tset max(decibels: number | undefined) {\n\t\tthis.reflect('max', decibels);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', -60);\n\t}\n\n\tset min(decibels: number | undefined) {\n\t\tthis.reflect('min', decibels);\n\t}\n\n\tget orientation(): 'horizontal' | 'vertical' {\n\t\treturn this.getAttribute('orientation') === 'horizontal' ? 'horizontal' : 'vertical';\n\t}\n\n\tset orientation(direction: 'horizontal' | 'vertical' | undefined) {\n\t\tthis.reflect('orientation', direction);\n\t}\n\n\t#bar = -Infinity;\n\n\t#clipAt = -Infinity;\n\n\t#frame: number | undefined;\n\n\t#lastFrame: number | undefined;\n\n\t#level = 0;\n\n\treadonly #meter = renderMeter();\n\n\t#peak = -Infinity;\n\n\t#peakAt = -Infinity;\n\n\t#target = -Infinity;\n\n\tattributeChangedCallback(): void {\n\t\tconst now = performance.now();\n\n\t\tthis.#render(now);\n\t\tthis.#schedule(now);\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst now = performance.now();\n\n\t\tthis.upgradeProperties('max', 'min', 'orientation', 'level');\n\t\tthis.appendOnce(this.#meter);\n\t\tthis.#render(now);\n\t\tthis.#schedule(now);\n\t\tthis.checkStyles(this.#meter, 'meter.css');\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tif (this.#frame !== undefined) cancelAnimationFrame(this.#frame);\n\t\t\t\tthis.#frame = undefined;\n\t\t\t\tthis.#lastFrame = undefined;\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#fraction(decibels: number): number {\n\t\tconst min = this.min;\n\t\tconst range = this.max - min;\n\n\t\treturn range > 0 ? Math.min(1, Math.max(0, (decibels - min) / range)) : 0;\n\t}\n\n\t#isSettled(now: number): boolean {\n\t\tconst floor = this.min;\n\n\t\treturn (\n\t\t\tthis.#bar <= Math.max(this.#target, floor) &&\n\t\t\tthis.#peak <= Math.max(this.#bar, floor) &&\n\t\t\tnow - this.#clipAt >= holdMs\n\t\t);\n\t}\n\n\t#render(now: number): void {\n\t\tconst meter = this.#meter;\n\n\t\tmeter.style.setProperty('--_sonic-meter-min', String(this.min));\n\t\tmeter.style.setProperty('--_sonic-meter-max', String(this.max));\n\n\t\t// Disabled puts the light out, as on the other controls; the ballistics keep running so it lights up mid-fall\n\t\tif (this.disabled) {\n\t\t\tmeter.style.setProperty('--_sonic-meter-level', '0');\n\t\t\tmeter.style.setProperty('--_sonic-meter-peak', '0');\n\t\t\tmeter.style.setProperty('--_sonic-meter-clipped', '0');\n\t\t\treturn;\n\t\t}\n\n\t\tmeter.style.setProperty('--_sonic-meter-level', String(this.#fraction(this.#bar)));\n\t\tmeter.style.setProperty('--_sonic-meter-peak', String(this.#fraction(this.#peak)));\n\t\tmeter.style.setProperty('--_sonic-meter-clipped', now - this.#clipAt < holdMs ? '1' : '0');\n\t}\n\n\t#schedule(now: number): void {\n\t\tif (this.#frame !== undefined || !this.isConnected || this.#isSettled(now)) return;\n\n\t\tif (this.#lastFrame === undefined) this.#lastFrame = now;\n\t\tthis.#frame = requestAnimationFrame(this.#tick);\n\t}\n\n\t// Timed by the frame rather than counted, so a 120Hz display falls at the same speed\n\treadonly #tick = (time: number): void => {\n\t\tconst fall = (releaseDecibelsPerSecond * Math.max(0, time - (this.#lastFrame ?? time))) / 1000;\n\n\t\tthis.#frame = undefined;\n\t\tthis.#lastFrame = time;\n\t\tthis.#bar = Math.max(this.#target, this.min, this.#bar - fall);\n\t\tif (time - this.#peakAt >= holdMs) this.#peak = Math.max(this.#bar, this.#peak - fall);\n\t\tthis.#render(time);\n\t\tif (this.#isSettled(time)) {\n\t\t\tthis.#lastFrame = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#frame = requestAnimationFrame(this.#tick);\n\t};\n}\n"],"mappings":"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"}
@@ -1,16 +1,38 @@
1
- import { SonicElement } from "./sonic-element.js";
1
+ import { SonicFormElement } from "./form-element.js";
2
2
  //#region src/elements/range-element.d.ts
3
3
  export interface RangeAxis {
4
4
  position: (event: PointerEvent) => number;
5
5
  travelPx: number;
6
6
  }
7
- export declare abstract class SonicRangeElement extends SonicElement {
7
+ export declare abstract class SonicRangeElement extends SonicFormElement {
8
8
  #private;
9
9
  static readonly observedAttributes: string[];
10
+ get default(): number | undefined;
11
+ set default(value: number | undefined);
12
+ get dimmed(): boolean;
13
+ set dimmed(isDimmed: boolean);
14
+ get doublePress(): 'reset' | 'type';
15
+ set doublePress(gesture: 'reset' | 'type' | undefined);
10
16
  get formatValue(): ((value: number) => string) | undefined;
11
17
  set formatValue(format: ((value: number) => string) | undefined);
18
+ get max(): number;
19
+ set max(value: number | undefined);
20
+ get midpoint(): number | undefined;
21
+ set midpoint(value: number | undefined);
22
+ get min(): number;
23
+ set min(value: number | undefined);
24
+ get notched(): boolean;
25
+ set notched(isNotched: boolean);
26
+ get origin(): number | undefined;
27
+ set origin(value: number | undefined);
12
28
  get parseValue(): ((text: string) => number) | undefined;
13
29
  set parseValue(parse: ((text: string) => number) | undefined);
30
+ get readout(): boolean;
31
+ set readout(isShown: boolean);
32
+ get step(): number;
33
+ set step(value: number | undefined);
34
+ get taper(): 'linear' | 'log';
35
+ set taper(curve: 'linear' | 'log' | undefined);
14
36
  get value(): number;
15
37
  set value(next: number);
16
38
  attributeChangedCallback(name: string): void;
@@ -19,13 +41,11 @@ export declare abstract class SonicRangeElement extends SonicElement {
19
41
  protected clampRange(next: number): number;
20
42
  protected fraction(value: number): number;
21
43
  protected input(next: number): boolean;
22
- protected max(): number;
23
- protected min(): number;
24
44
  protected originFraction(): number;
25
45
  protected positions(): number | undefined;
26
46
  protected range(): number;
27
- protected abstract render(): void;
28
47
  protected renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void;
48
+ protected restoreState(state: string): void;
29
49
  protected valueAt(fraction: number): number;
30
50
  }
31
51
  //#endregion