@xsynaptic/sonic-ui 0.5.0 → 0.6.1

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 (138) hide show
  1. package/README.md +3 -1
  2. package/dist/default/dat.js +5 -4
  3. package/dist/default/define/button.js +1 -1
  4. package/dist/default/define.js +2 -2
  5. package/dist/default/elements/button.js +6 -5
  6. package/dist/default/elements/dial.js +5 -1
  7. package/dist/default/elements/envelope.js +46 -18
  8. package/dist/default/elements/meter.js +12 -8
  9. package/dist/default/elements/number.js +1 -1
  10. package/dist/default/elements/radio-group.js +46 -47
  11. package/dist/default/elements/readout-claim.js +0 -29
  12. package/dist/default/elements/readout.js +1 -1
  13. package/dist/default/elements/scale.js +43 -0
  14. package/dist/default/elements/slider.js +16 -3
  15. package/dist/default/elements/sonic-element.js +17 -55
  16. package/dist/default/elements/switch.js +33 -39
  17. package/dist/default/elements/value-element.js +142 -187
  18. package/dist/default/elements/wave-element.js +5 -2
  19. package/dist/default/elements/waveform.js +35 -12
  20. package/dist/default/elements/wavestrip.js +59 -18
  21. package/dist/default/elements/xy.js +34 -19
  22. package/dist/default/index.js +2 -2
  23. package/dist/default/lib/adsr-shape.js +5 -0
  24. package/dist/default/lib/ballistics.js +2 -2
  25. package/dist/default/lib/canvas-surface.js +13 -2
  26. package/dist/default/lib/distribute.js +1 -1
  27. package/dist/default/lib/drag-step.js +4 -4
  28. package/dist/default/lib/frame-timeline.js +2 -1
  29. package/dist/default/lib/marker-band.js +54 -10
  30. package/dist/default/lib/marker-rider.js +10 -4
  31. package/dist/default/lib/math.js +6 -1
  32. package/dist/default/lib/mirror-children.js +64 -0
  33. package/dist/default/lib/owned-control.js +10 -0
  34. package/dist/default/lib/pointer-drag.js +8 -5
  35. package/dist/default/lib/resample-peaks.js +11 -1
  36. package/dist/default/lib/time-regions.js +4 -1
  37. package/dist/default/lib/write-attribute.js +1 -0
  38. package/dist/dev/dat.d.ts +2 -2
  39. package/dist/dev/dat.js +5 -4
  40. package/dist/dev/dat.js.map +1 -1
  41. package/dist/dev/define/button.js +1 -1
  42. package/dist/dev/define.d.ts +4 -4
  43. package/dist/dev/define.js +2 -2
  44. package/dist/dev/elements/button.js +6 -5
  45. package/dist/dev/elements/button.js.map +1 -1
  46. package/dist/dev/elements/dial.d.ts +1 -1
  47. package/dist/dev/elements/dial.js +5 -1
  48. package/dist/dev/elements/dial.js.map +1 -1
  49. package/dist/dev/elements/envelope.js +46 -18
  50. package/dist/dev/elements/envelope.js.map +1 -1
  51. package/dist/dev/elements/meter.d.ts +1 -1
  52. package/dist/dev/elements/meter.js +12 -8
  53. package/dist/dev/elements/meter.js.map +1 -1
  54. package/dist/dev/elements/number.js +1 -1
  55. package/dist/dev/elements/number.js.map +1 -1
  56. package/dist/dev/elements/radio-group.js +46 -47
  57. package/dist/dev/elements/radio-group.js.map +1 -1
  58. package/dist/dev/elements/readout-claim.js +0 -29
  59. package/dist/dev/elements/readout-claim.js.map +1 -1
  60. package/dist/dev/elements/readout.js +1 -1
  61. package/dist/dev/elements/readout.js.map +1 -1
  62. package/dist/dev/elements/scale.js +44 -0
  63. package/dist/dev/elements/scale.js.map +1 -0
  64. package/dist/dev/elements/slider.d.ts +4 -1
  65. package/dist/dev/elements/slider.js +16 -3
  66. package/dist/dev/elements/slider.js.map +1 -1
  67. package/dist/dev/elements/sonic-element.d.ts +2 -8
  68. package/dist/dev/elements/sonic-element.js +18 -55
  69. package/dist/dev/elements/sonic-element.js.map +1 -1
  70. package/dist/dev/elements/switch.js +33 -39
  71. package/dist/dev/elements/switch.js.map +1 -1
  72. package/dist/dev/elements/value-element.d.ts +6 -8
  73. package/dist/dev/elements/value-element.js +142 -187
  74. package/dist/dev/elements/value-element.js.map +1 -1
  75. package/dist/dev/elements/wave-element.d.ts +1 -0
  76. package/dist/dev/elements/wave-element.js +5 -2
  77. package/dist/dev/elements/wave-element.js.map +1 -1
  78. package/dist/dev/elements/waveform.d.ts +1 -1
  79. package/dist/dev/elements/waveform.js +35 -12
  80. package/dist/dev/elements/waveform.js.map +1 -1
  81. package/dist/dev/elements/wavestrip.d.ts +4 -0
  82. package/dist/dev/elements/wavestrip.js +59 -18
  83. package/dist/dev/elements/wavestrip.js.map +1 -1
  84. package/dist/dev/elements/xy.d.ts +3 -3
  85. package/dist/dev/elements/xy.js +34 -19
  86. package/dist/dev/elements/xy.js.map +1 -1
  87. package/dist/dev/index.d.ts +2 -2
  88. package/dist/dev/index.js +2 -2
  89. package/dist/dev/lib/adsr-shape.js +5 -0
  90. package/dist/dev/lib/adsr-shape.js.map +1 -1
  91. package/dist/dev/lib/ballistics.js +2 -2
  92. package/dist/dev/lib/ballistics.js.map +1 -1
  93. package/dist/dev/lib/canvas-surface.d.ts +1 -0
  94. package/dist/dev/lib/canvas-surface.js +13 -2
  95. package/dist/dev/lib/canvas-surface.js.map +1 -1
  96. package/dist/dev/lib/distribute.js +1 -1
  97. package/dist/dev/lib/distribute.js.map +1 -1
  98. package/dist/dev/lib/drag-step.js +4 -4
  99. package/dist/dev/lib/drag-step.js.map +1 -1
  100. package/dist/dev/lib/frame-timeline.js +2 -1
  101. package/dist/dev/lib/frame-timeline.js.map +1 -1
  102. package/dist/dev/lib/marker-band.js +54 -10
  103. package/dist/dev/lib/marker-band.js.map +1 -1
  104. package/dist/dev/lib/marker-rider.js +10 -4
  105. package/dist/dev/lib/marker-rider.js.map +1 -1
  106. package/dist/dev/lib/math.js +6 -1
  107. package/dist/dev/lib/math.js.map +1 -1
  108. package/dist/dev/lib/mirror-children.js +80 -0
  109. package/dist/dev/lib/mirror-children.js.map +1 -0
  110. package/dist/dev/lib/owned-control.js +23 -0
  111. package/dist/dev/lib/owned-control.js.map +1 -0
  112. package/dist/dev/lib/pointer-drag.js +8 -5
  113. package/dist/dev/lib/pointer-drag.js.map +1 -1
  114. package/dist/dev/lib/resample-peaks.js +11 -1
  115. package/dist/dev/lib/resample-peaks.js.map +1 -1
  116. package/dist/dev/lib/time-regions.js +4 -1
  117. package/dist/dev/lib/time-regions.js.map +1 -1
  118. package/dist/dev/lib/write-attribute.js +1 -0
  119. package/dist/dev/lib/write-attribute.js.map +1 -1
  120. package/dist/skins/amber.css +8 -0
  121. package/dist/skins/flat.css +26 -0
  122. package/dist/skins/ivory.css +1 -0
  123. package/dist/skins/lime.css +2 -0
  124. package/dist/skins/slate.css +2 -0
  125. package/dist/styles/button.css +59 -10
  126. package/dist/styles/dial.css +24 -16
  127. package/dist/styles/envelope.css +58 -13
  128. package/dist/styles/led.css +20 -4
  129. package/dist/styles/material.css +143 -55
  130. package/dist/styles/meter.css +8 -4
  131. package/dist/styles/panel.css +7 -4
  132. package/dist/styles/segmented.css +27 -5
  133. package/dist/styles/slider.css +2 -1
  134. package/dist/styles/switch.css +65 -23
  135. package/dist/styles/waveform.css +28 -5
  136. package/dist/styles/wavestrip.css +23 -6
  137. package/dist/styles/xy.css +48 -27
  138. package/package.json +2 -5
@@ -1,4 +1,5 @@
1
- import { attachSlots } from "../lib/render.js";
1
+ import { toNumber } from "../lib/math.js";
2
+ import { appendOnce } from "../lib/owned-control.js";
2
3
  import { writeAttribute } from "../lib/write-attribute.js";
3
4
 
4
5
  //#region src/elements/sonic-element.ts
@@ -22,7 +23,6 @@ var SonicElement = class extends HTMLElement {
22
23
  }
23
24
  internals = "attachInternals" in HTMLElement.prototype ? this.attachInternals() : void 0;
24
25
  #connection;
25
- #slots;
26
26
  blur() {
27
27
  this.#focused()?.blur();
28
28
  }
@@ -30,13 +30,14 @@ var SonicElement = class extends HTMLElement {
30
30
  this.upgradeProperties("disabled");
31
31
  if (this.#connection) return;
32
32
  const connection = new AbortController();
33
+ this.#connection = connection;
33
34
  try {
34
35
  this.connect(connection.signal);
35
36
  } catch (error) {
36
37
  connection.abort();
38
+ this.#connection = void 0;
37
39
  throw error;
38
40
  }
39
- this.#connection = connection;
40
41
  }
41
42
  connectedMoveCallback() {}
42
43
  disconnectedCallback() {
@@ -56,12 +57,6 @@ var SonicElement = class extends HTMLElement {
56
57
  }
57
58
  if (!this.isDisabled() && !this.#focused()) target.focus(options);
58
59
  }
59
- appendOnce(control) {
60
- const [hook] = control.classList;
61
- const stale = [...this.children].filter((child) => child !== control && hook !== void 0 && child.classList.contains(hook));
62
- for (const child of stale) child.remove();
63
- if (control.parentNode !== this) this.append(control);
64
- }
65
60
  checkStyles(control, sheet) {}
66
61
  focusTarget() {}
67
62
  forwardNaming(target, isNamed) {
@@ -73,36 +68,19 @@ var SonicElement = class extends HTMLElement {
73
68
  }
74
69
  if (labels.length > 0) writeLabelledBy(target, labels);
75
70
  }
71
+ isBound() {
72
+ return this.#connection !== void 0;
73
+ }
76
74
  isDisabled() {
77
75
  return this.disabled || this.matches(":disabled");
78
76
  }
79
- mirrorChildren({ control, copy, isCopied = () => true, place }, signal) {
80
- const slots = this.#slots ?? attachSlots(this);
81
- let copies = /* @__PURE__ */ new Map();
82
- this.#slots = slots;
83
- const mirror = (touched) => {
84
- this.appendOnce(control);
85
- const children = [...this.childNodes].filter((child) => child !== control);
86
- const slotted = children.filter((child) => child instanceof Element || child instanceof Text);
87
- const kept = copies;
88
- copies = new Map(children.filter((child) => isCopied(child)).map((original) => [original, touched && !touched.has(original) && kept.has(original) ? kept.get(original) : copy(original)]));
89
- place([...copies.values()].filter((made) => made !== void 0));
90
- slots.shown.assign(...slotted.filter((child) => !isCopied(child)), control);
91
- slots.kept.assign(...slotted.filter((child) => isCopied(child)));
77
+ keepControl(control, signal) {
78
+ const keep = () => {
79
+ appendOnce(this, control);
92
80
  };
93
- const observer = new MutationObserver((records) => {
94
- const changes = records.filter((record) => this.#isCopiedChange(record, control, isCopied));
95
- if (changes.length === 0) return;
96
- if (changes.some((record) => record.target === this)) mirror();
97
- else mirror(new Set(changes.map((record) => this.#childHolding(record.target))));
98
- });
99
- mirror();
100
- observer.observe(this, {
101
- attributes: true,
102
- characterData: true,
103
- childList: true,
104
- subtree: true
105
- });
81
+ const observer = new MutationObserver(keep);
82
+ keep();
83
+ observer.observe(this, { childList: true });
106
84
  signal.addEventListener("abort", () => {
107
85
  observer.disconnect();
108
86
  }, { once: true });
@@ -111,9 +89,7 @@ var SonicElement = class extends HTMLElement {
111
89
  return [];
112
90
  }
113
91
  numberAttribute(name, fallback) {
114
- const attribute = this.getAttribute(name);
115
- if (attribute === null || attribute.trim() === "") return fallback;
116
- const parsed = Number(attribute);
92
+ const parsed = toNumber(this.getAttribute(name));
117
93
  return Number.isFinite(parsed) ? parsed : fallback;
118
94
  }
119
95
  optionalNumberAttribute(name) {
@@ -121,11 +97,11 @@ var SonicElement = class extends HTMLElement {
121
97
  return Number.isNaN(value) ? void 0 : value;
122
98
  }
123
99
  reflect(name, value) {
124
- if (value === true) {
125
- this.setAttribute(name, "");
100
+ if (typeof value !== "number" && typeof value !== "string" && value !== true) {
101
+ this.removeAttribute(name);
126
102
  return;
127
103
  }
128
- writeAttribute(this, name, value === false || value === null ? void 0 : value?.toString());
104
+ this.setAttribute(name, value === true ? "" : value.toString());
129
105
  }
130
106
  toggleState(state, isOn) {
131
107
  if (isOn) this.internals?.states.add(state);
@@ -139,25 +115,11 @@ var SonicElement = class extends HTMLElement {
139
115
  this[name] = value;
140
116
  }
141
117
  }
142
- #childHolding(node) {
143
- let current = node;
144
- while (current && current.parentNode !== this) current = current.parentNode;
145
- return current ?? void 0;
146
- }
147
118
  #focused() {
148
119
  const root = this.getRootNode();
149
120
  const active = root instanceof ShadowRoot ? root.activeElement : this.ownerDocument.activeElement;
150
121
  return active instanceof HTMLElement && this.contains(active) ? active : void 0;
151
122
  }
152
- #isCopiedChange(record, control, isCopied) {
153
- if (record.target === this) {
154
- if (record.type === "attributes") return false;
155
- return record.removedNodes.length > 0 || [...record.addedNodes].some((node) => node !== control);
156
- }
157
- const child = this.#childHolding(record.target);
158
- if (child === void 0 || child === control) return false;
159
- return isCopied(child) || record.type === "attributes" && record.target === child;
160
- }
161
123
  };
162
124
 
163
125
  //#endregion
@@ -1,7 +1,8 @@
1
1
  import { clamp } from "../lib/math.js";
2
- import { requireChild, template } from "../lib/render.js";
3
2
  import { writeAttribute } from "../lib/write-attribute.js";
4
3
  import { bindHold } from "../lib/hold.js";
4
+ import { requireChild, template } from "../lib/render.js";
5
+ import { bindDrag } from "../lib/pointer-drag.js";
5
6
  import { SonicRadioGroupElement, isUnder, optionValue } from "./radio-group.js";
6
7
 
7
8
  //#region src/elements/switch.ts
@@ -60,7 +61,6 @@ var SonicSwitch = class extends SonicRadioGroupElement {
60
61
  group = renderSwitch();
61
62
  #bare = renderBare();
62
63
  #bat = requireChild(this.group, ".sonic-switch-bat", HTMLSpanElement);
63
- #batPress;
64
64
  #checked = false;
65
65
  #holding;
66
66
  #isClickSwallowed = false;
@@ -92,7 +92,7 @@ var SonicSwitch = class extends SonicRadioGroupElement {
92
92
  option.focus();
93
93
  }
94
94
  claimPress(option, event) {
95
- if (this.#grabBat(event)) return true;
95
+ if (this.#isOnBat(event)) return true;
96
96
  if (!this.#isMomentary(option)) return false;
97
97
  this.group.setPointerCapture(event.pointerId);
98
98
  this.#hold(option, event.pointerId);
@@ -108,9 +108,8 @@ var SonicSwitch = class extends SonicRadioGroupElement {
108
108
  this.#isClickSwallowed = false;
109
109
  if (!isSwallowed) this.#setChecked(!this.checked);
110
110
  }, { signal });
111
- this.#bare.addEventListener("pointerdown", (event) => {
111
+ this.#bare.addEventListener("pointerdown", () => {
112
112
  this.#isClickSwallowed = false;
113
- if (event.button === 0 && !this.isDisabled()) this.#grabBat(event);
114
113
  }, { signal });
115
114
  this.#bindBat(group, signal);
116
115
  this.#holding = bindHold(group, {
@@ -138,12 +137,13 @@ var SonicSwitch = class extends SonicRadioGroupElement {
138
137
  return option;
139
138
  }
140
139
  render() {
140
+ if (!this.isBound()) return;
141
141
  const group = this.group;
142
142
  const options = this.options();
143
143
  if (options.length > 0) {
144
144
  this.#bare.remove();
145
145
  writeAttribute(group, "role", "radiogroup");
146
- group.dataset.sonicPositionCount = String(options.length);
146
+ writeAttribute(group, "data-sonic-position-count", String(options.length));
147
147
  super.render();
148
148
  this.#renderThrow(this.#checkedIndex(options));
149
149
  return;
@@ -153,8 +153,8 @@ var SonicSwitch = class extends SonicRadioGroupElement {
153
153
  writeAttribute(group, "role", void 0);
154
154
  delete group.dataset.sonicPositionCount;
155
155
  if (bare.parentElement !== group) group.append(bare);
156
- bare.disabled = this.isDisabled();
157
- bare.setAttribute("aria-checked", String(isChecked));
156
+ writeAttribute(bare, "disabled", this.isDisabled() ? "" : void 0);
157
+ writeAttribute(bare, "aria-checked", String(isChecked));
158
158
  this.forwardNaming(group, false);
159
159
  this.forwardNaming(bare, true);
160
160
  const onSide = this.orientation === "horizontal" ? 1 : -1;
@@ -172,41 +172,32 @@ var SonicSwitch = class extends SonicRadioGroupElement {
172
172
  return this.orientation === "horizontal" ? event.clientX : event.clientY;
173
173
  }
174
174
  #bindBat(group, signal) {
175
- const drop = (event) => {
176
- if (event.pointerId === this.#batPress?.pointerId) this.#batPress = void 0;
177
- };
178
- group.addEventListener("pointermove", (event) => {
179
- const press = this.#batPress;
180
- if (press?.pointerId !== event.pointerId || this.isDisabled()) return;
181
- const delta = this.#along(event) - press.last;
182
- if (Math.abs(delta) < this.#bat.getBoundingClientRect().width / 4) return;
183
- press.hasMoved = true;
184
- press.last = this.#along(event);
185
- this.#throwBy(Math.sign(delta), event.pointerId);
186
- }, { signal });
187
- group.addEventListener("pointerup", (event) => {
188
- const press = this.#batPress;
189
- if (press?.pointerId !== event.pointerId) return;
190
- this.#batPress = void 0;
191
- if (!press.hasMoved && !this.isDisabled()) this.#pressBat(event);
192
- this.#isClickSwallowed = true;
193
- }, { signal });
194
- group.addEventListener("pointercancel", drop, { signal });
195
- group.addEventListener("lostpointercapture", drop, { signal });
175
+ bindDrag(group, {
176
+ grab: (event) => {
177
+ if (!(event.target === this.#bare || this.optionOf(event.target) !== void 0) || this.isDisabled() || !this.#isOnBat(event)) return;
178
+ return {
179
+ hasMoved: false,
180
+ last: this.#along(event),
181
+ width: this.#bat.getBoundingClientRect().width
182
+ };
183
+ },
184
+ lift: (press, event) => {
185
+ if (!press.hasMoved && !this.isDisabled()) this.#pressBat(event);
186
+ this.#isClickSwallowed = true;
187
+ },
188
+ move: (press, event) => {
189
+ if (this.isDisabled()) return;
190
+ const delta = this.#along(event) - press.last;
191
+ if (Math.abs(delta) < press.width / 4) return;
192
+ press.hasMoved = true;
193
+ press.last = this.#along(event);
194
+ this.#throwBy(Math.sign(delta), event.pointerId);
195
+ }
196
+ }, signal);
196
197
  }
197
198
  #checkedIndex(options) {
198
199
  return options.findIndex((option) => optionValue(option) === this.value);
199
200
  }
200
- #grabBat(event) {
201
- if (!isUnder(this.#bat, event.clientX, event.clientY)) return false;
202
- this.group.setPointerCapture(event.pointerId);
203
- this.#batPress = {
204
- hasMoved: false,
205
- last: this.#along(event),
206
- pointerId: event.pointerId
207
- };
208
- return true;
209
- }
210
201
  #hasSprungFrom(option) {
211
202
  if (!option || !this.#isMomentary(option)) return false;
212
203
  this.#holding?.release();
@@ -222,6 +213,9 @@ var SonicSwitch = class extends SonicRadioGroupElement {
222
213
  const options = this.options();
223
214
  return (option === options[0] || option === options.at(-1)) && options.length > 1 && option.querySelector("[data-sonic-value]")?.hasAttribute("data-sonic-momentary") === true;
224
215
  }
216
+ #isOnBat(event) {
217
+ return isUnder(this.#bat, event.clientX, event.clientY);
218
+ }
225
219
  #pressBat(event) {
226
220
  const options = this.options();
227
221
  if (options.length === 0) {