@xsynaptic/sonic-ui 0.4.0 → 0.6.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 (247) hide show
  1. package/README.md +3 -20
  2. package/dist/default/dat.js +51 -0
  3. package/dist/default/define/button.js +7 -0
  4. package/dist/default/define/envelope.js +7 -0
  5. package/dist/default/define/split.js +7 -0
  6. package/dist/default/define/switch.js +7 -0
  7. package/dist/default/define/waveform.js +7 -0
  8. package/dist/default/define/wavestrip.js +7 -0
  9. package/dist/default/define/xy.js +7 -0
  10. package/dist/default/define.js +7 -1
  11. package/dist/default/elements/button.js +165 -0
  12. package/dist/default/elements/dial.js +16 -22
  13. package/dist/default/elements/envelope.js +383 -0
  14. package/dist/default/elements/meter.js +155 -63
  15. package/dist/default/elements/number.js +22 -9
  16. package/dist/default/elements/radio-group.js +183 -0
  17. package/dist/default/elements/readout-claim.js +81 -0
  18. package/dist/default/elements/readout.js +35 -0
  19. package/dist/default/elements/segmented.js +9 -159
  20. package/dist/default/elements/slider.js +42 -51
  21. package/dist/default/elements/sonic-element.js +69 -31
  22. package/dist/default/elements/split.js +249 -0
  23. package/dist/default/elements/switch.js +273 -0
  24. package/dist/default/elements/value-element.js +694 -0
  25. package/dist/default/elements/{range-entry.js → value-entry.js} +3 -3
  26. package/dist/default/elements/wave-element.js +80 -0
  27. package/dist/default/elements/waveform.js +328 -0
  28. package/dist/default/elements/wavestrip.js +185 -0
  29. package/dist/default/elements/xy.js +487 -0
  30. package/dist/default/index.js +10 -2
  31. package/dist/default/lib/adsr-shape.js +113 -0
  32. package/dist/default/lib/ballistics.js +55 -0
  33. package/dist/default/lib/canvas-surface.js +203 -0
  34. package/dist/default/lib/copy-node.js +32 -2
  35. package/dist/default/lib/crossfade.js +22 -0
  36. package/dist/default/lib/distribute.js +215 -0
  37. package/dist/default/lib/drag-step.js +99 -0
  38. package/dist/default/lib/envelope-curve.js +9 -0
  39. package/dist/default/lib/field.js +94 -0
  40. package/dist/default/lib/focus-by-pointer.js +28 -0
  41. package/dist/default/lib/frame-timeline.js +63 -0
  42. package/dist/default/lib/hold.js +38 -0
  43. package/dist/default/lib/marker-band.js +80 -0
  44. package/dist/default/lib/marker-rider.js +120 -0
  45. package/dist/default/lib/math.js +17 -3
  46. package/dist/default/lib/modifier-press.js +11 -0
  47. package/dist/default/lib/number-list.js +6 -6
  48. package/dist/default/lib/pointer-drag.js +46 -0
  49. package/dist/default/lib/render.js +20 -5
  50. package/dist/default/lib/resample-peaks.js +46 -0
  51. package/dist/default/lib/strip-scene.js +48 -0
  52. package/dist/default/lib/taper.js +23 -17
  53. package/dist/default/lib/time-regions.js +8 -0
  54. package/dist/default/lib/tracking-clock.js +35 -0
  55. package/dist/default/lib/value-mapping.js +115 -0
  56. package/dist/default/lib/waveform-buckets.js +41 -0
  57. package/dist/default/lib/write-attribute.js +1 -0
  58. package/dist/dev/dat.d.ts +19 -0
  59. package/dist/dev/dat.js +52 -0
  60. package/dist/dev/dat.js.map +1 -0
  61. package/dist/dev/define/button.d.ts +2 -0
  62. package/dist/dev/define/button.js +8 -0
  63. package/dist/dev/define/button.js.map +1 -0
  64. package/dist/dev/define/dial.js.map +1 -1
  65. package/dist/dev/define/envelope.d.ts +2 -0
  66. package/dist/dev/define/envelope.js +8 -0
  67. package/dist/dev/define/envelope.js.map +1 -0
  68. package/dist/dev/define/meter.js.map +1 -1
  69. package/dist/dev/define/number.js.map +1 -1
  70. package/dist/dev/define/segmented.js.map +1 -1
  71. package/dist/dev/define/slider.js.map +1 -1
  72. package/dist/dev/define/split.d.ts +2 -0
  73. package/dist/dev/define/split.js +8 -0
  74. package/dist/dev/define/split.js.map +1 -0
  75. package/dist/dev/define/switch.d.ts +2 -0
  76. package/dist/dev/define/switch.js +8 -0
  77. package/dist/dev/define/switch.js.map +1 -0
  78. package/dist/dev/define/waveform.d.ts +2 -0
  79. package/dist/dev/define/waveform.js +8 -0
  80. package/dist/dev/define/waveform.js.map +1 -0
  81. package/dist/dev/define/wavestrip.d.ts +2 -0
  82. package/dist/dev/define/wavestrip.js +8 -0
  83. package/dist/dev/define/wavestrip.js.map +1 -0
  84. package/dist/dev/define/xy.d.ts +2 -0
  85. package/dist/dev/define/xy.js +8 -0
  86. package/dist/dev/define/xy.js.map +1 -0
  87. package/dist/dev/define.d.ts +15 -3
  88. package/dist/dev/define.js +7 -1
  89. package/dist/dev/elements/{key.d.ts → button.d.ts} +8 -6
  90. package/dist/dev/elements/button.js +166 -0
  91. package/dist/dev/elements/button.js.map +1 -0
  92. package/dist/dev/elements/dial.d.ts +6 -4
  93. package/dist/dev/elements/dial.js +16 -22
  94. package/dist/dev/elements/dial.js.map +1 -1
  95. package/dist/dev/elements/envelope.d.ts +36 -0
  96. package/dist/dev/elements/envelope.js +388 -0
  97. package/dist/dev/elements/envelope.js.map +1 -0
  98. package/dist/dev/elements/form-element.d.ts +1 -1
  99. package/dist/dev/elements/form-element.js.map +1 -1
  100. package/dist/dev/elements/meter.d.ts +11 -6
  101. package/dist/dev/elements/meter.js +155 -63
  102. package/dist/dev/elements/meter.js.map +1 -1
  103. package/dist/dev/elements/number.d.ts +7 -3
  104. package/dist/dev/elements/number.js +22 -9
  105. package/dist/dev/elements/number.js.map +1 -1
  106. package/dist/dev/elements/radio-group.d.ts +25 -0
  107. package/dist/dev/elements/radio-group.js +184 -0
  108. package/dist/dev/elements/radio-group.js.map +1 -0
  109. package/dist/dev/elements/readout-claim.js +82 -0
  110. package/dist/dev/elements/readout-claim.js.map +1 -0
  111. package/dist/dev/elements/readout.js +36 -0
  112. package/dist/dev/elements/readout.js.map +1 -0
  113. package/dist/dev/elements/segmented.d.ts +4 -10
  114. package/dist/dev/elements/segmented.js +9 -159
  115. package/dist/dev/elements/segmented.js.map +1 -1
  116. package/dist/dev/elements/slider.d.ts +6 -6
  117. package/dist/dev/elements/slider.js +42 -51
  118. package/dist/dev/elements/slider.js.map +1 -1
  119. package/dist/dev/elements/sonic-element.d.ts +6 -3
  120. package/dist/dev/elements/sonic-element.js +119 -40
  121. package/dist/dev/elements/sonic-element.js.map +1 -1
  122. package/dist/dev/elements/split.d.ts +21 -0
  123. package/dist/dev/elements/split.js +258 -0
  124. package/dist/dev/elements/split.js.map +1 -0
  125. package/dist/dev/elements/switch.d.ts +35 -0
  126. package/dist/dev/elements/switch.js +274 -0
  127. package/dist/dev/elements/switch.js.map +1 -0
  128. package/dist/dev/elements/value-element.d.ts +84 -0
  129. package/dist/dev/elements/value-element.js +695 -0
  130. package/dist/dev/elements/value-element.js.map +1 -0
  131. package/dist/dev/elements/{range-entry.js → value-entry.js} +4 -4
  132. package/dist/dev/elements/value-entry.js.map +1 -0
  133. package/dist/dev/elements/wave-element.d.ts +37 -0
  134. package/dist/dev/elements/wave-element.js +81 -0
  135. package/dist/dev/elements/wave-element.js.map +1 -0
  136. package/dist/dev/elements/waveform.d.ts +55 -0
  137. package/dist/dev/elements/waveform.js +329 -0
  138. package/dist/dev/elements/waveform.js.map +1 -0
  139. package/dist/dev/elements/wavestrip.d.ts +51 -0
  140. package/dist/dev/elements/wavestrip.js +186 -0
  141. package/dist/dev/elements/wavestrip.js.map +1 -0
  142. package/dist/dev/elements/xy.d.ts +62 -0
  143. package/dist/dev/elements/xy.js +488 -0
  144. package/dist/dev/elements/xy.js.map +1 -0
  145. package/dist/dev/index.d.ts +11 -2
  146. package/dist/dev/index.js +10 -2
  147. package/dist/dev/lib/adsr-shape.js +114 -0
  148. package/dist/dev/lib/adsr-shape.js.map +1 -0
  149. package/dist/dev/lib/ballistics.js +56 -0
  150. package/dist/dev/lib/ballistics.js.map +1 -0
  151. package/dist/dev/lib/canvas-surface.d.ts +26 -0
  152. package/dist/dev/lib/canvas-surface.js +204 -0
  153. package/dist/dev/lib/canvas-surface.js.map +1 -0
  154. package/dist/dev/lib/copy-node.js +32 -2
  155. package/dist/dev/lib/copy-node.js.map +1 -1
  156. package/dist/dev/lib/crossfade.d.ts +12 -0
  157. package/dist/dev/lib/crossfade.js +23 -0
  158. package/dist/dev/lib/crossfade.js.map +1 -0
  159. package/dist/dev/lib/distribute.d.ts +4 -0
  160. package/dist/dev/lib/distribute.js +216 -0
  161. package/dist/dev/lib/distribute.js.map +1 -0
  162. package/dist/dev/lib/drag-step.js +100 -0
  163. package/dist/dev/lib/drag-step.js.map +1 -0
  164. package/dist/dev/lib/envelope-curve.d.ts +4 -0
  165. package/dist/dev/lib/envelope-curve.js +10 -0
  166. package/dist/dev/lib/envelope-curve.js.map +1 -0
  167. package/dist/dev/lib/field.d.ts +4 -0
  168. package/dist/dev/lib/field.js +95 -0
  169. package/dist/dev/lib/field.js.map +1 -0
  170. package/dist/dev/lib/focus-by-pointer.js +29 -0
  171. package/dist/dev/lib/focus-by-pointer.js.map +1 -0
  172. package/dist/dev/lib/frame-timeline.js +64 -0
  173. package/dist/dev/lib/frame-timeline.js.map +1 -0
  174. package/dist/dev/lib/hold.js +39 -0
  175. package/dist/dev/lib/hold.js.map +1 -0
  176. package/dist/dev/lib/marker-band.js +81 -0
  177. package/dist/dev/lib/marker-band.js.map +1 -0
  178. package/dist/dev/lib/marker-rider.js +121 -0
  179. package/dist/dev/lib/marker-rider.js.map +1 -0
  180. package/dist/dev/lib/math.js +17 -3
  181. package/dist/dev/lib/math.js.map +1 -1
  182. package/dist/dev/lib/modifier-press.js +12 -0
  183. package/dist/dev/lib/modifier-press.js.map +1 -0
  184. package/dist/dev/lib/number-list.js +6 -6
  185. package/dist/dev/lib/number-list.js.map +1 -1
  186. package/dist/dev/lib/pointer-drag.js +47 -0
  187. package/dist/dev/lib/pointer-drag.js.map +1 -0
  188. package/dist/dev/lib/read-px-property.js.map +1 -1
  189. package/dist/dev/lib/render.js +20 -5
  190. package/dist/dev/lib/render.js.map +1 -1
  191. package/dist/dev/lib/resample-peaks.js +47 -0
  192. package/dist/dev/lib/resample-peaks.js.map +1 -0
  193. package/dist/dev/lib/strip-scene.js +49 -0
  194. package/dist/dev/lib/strip-scene.js.map +1 -0
  195. package/dist/dev/lib/taper.js +23 -17
  196. package/dist/dev/lib/taper.js.map +1 -1
  197. package/dist/dev/lib/time-regions.d.ts +4 -0
  198. package/dist/dev/lib/time-regions.js +9 -0
  199. package/dist/dev/lib/time-regions.js.map +1 -0
  200. package/dist/dev/lib/tracking-clock.js +36 -0
  201. package/dist/dev/lib/tracking-clock.js.map +1 -0
  202. package/dist/dev/lib/value-mapping.d.ts +23 -0
  203. package/dist/dev/lib/value-mapping.js +116 -0
  204. package/dist/dev/lib/value-mapping.js.map +1 -0
  205. package/dist/dev/lib/waveform-buckets.d.ts +9 -0
  206. package/dist/dev/lib/waveform-buckets.js +42 -0
  207. package/dist/dev/lib/waveform-buckets.js.map +1 -0
  208. package/dist/dev/lib/write-attribute.js +1 -0
  209. package/dist/dev/lib/write-attribute.js.map +1 -1
  210. package/dist/skins/amber.css +8 -0
  211. package/dist/skins/flat.css +25 -0
  212. package/dist/skins/ivory.css +2 -2
  213. package/dist/skins/lime.css +2 -0
  214. package/dist/skins/slate.css +2 -0
  215. package/dist/styles/button.css +240 -0
  216. package/dist/styles/controls.css +8 -1
  217. package/dist/styles/dial.css +110 -56
  218. package/dist/styles/envelope.css +204 -0
  219. package/dist/styles/led.css +39 -8
  220. package/dist/styles/material.css +343 -100
  221. package/dist/styles/meter.css +41 -52
  222. package/dist/styles/number.css +5 -1
  223. package/dist/styles/panel.css +61 -0
  224. package/dist/styles/ring.css +74 -0
  225. package/dist/styles/segmented.css +46 -51
  226. package/dist/styles/slider.css +177 -40
  227. package/dist/styles/switch.css +386 -0
  228. package/dist/styles/waveform.css +196 -0
  229. package/dist/styles/wavestrip.css +232 -0
  230. package/dist/styles/xy.css +241 -0
  231. package/package.json +15 -6
  232. package/dist/default/define/key.js +0 -7
  233. package/dist/default/elements/key.js +0 -169
  234. package/dist/default/elements/range-element.js +0 -546
  235. package/dist/default/lib/detent.js +0 -17
  236. package/dist/dev/define/key.d.ts +0 -2
  237. package/dist/dev/define/key.js +0 -8
  238. package/dist/dev/define/key.js.map +0 -1
  239. package/dist/dev/elements/key.js +0 -170
  240. package/dist/dev/elements/key.js.map +0 -1
  241. package/dist/dev/elements/range-element.d.ts +0 -64
  242. package/dist/dev/elements/range-element.js +0 -547
  243. package/dist/dev/elements/range-element.js.map +0 -1
  244. package/dist/dev/elements/range-entry.js.map +0 -1
  245. package/dist/dev/lib/detent.js +0 -18
  246. package/dist/dev/lib/detent.js.map +0 -1
  247. package/dist/styles/key.css +0 -242
@@ -0,0 +1,273 @@
1
+ import { clamp } from "../lib/math.js";
2
+ import { requireChild, template } from "../lib/render.js";
3
+ import { writeAttribute } from "../lib/write-attribute.js";
4
+ import { bindHold } from "../lib/hold.js";
5
+ import { bindDrag } from "../lib/pointer-drag.js";
6
+ import { SonicRadioGroupElement, isUnder, optionValue } from "./radio-group.js";
7
+
8
+ //#region src/elements/switch.ts
9
+ const renderSwitch = template(`
10
+ <div class="sonic-switch">
11
+ <span aria-hidden="true" class="sonic-switch-bushing"></span>
12
+ <span aria-hidden="true" class="sonic-switch-bat"></span>
13
+ </div>
14
+ `, HTMLDivElement);
15
+ const renderPosition = template(`
16
+ <button class="sonic-switch-position" role="radio" type="button">
17
+ <span class="sonic-switch-label"></span>
18
+ </button>
19
+ `, HTMLButtonElement);
20
+ const renderBare = template(`<button class="sonic-switch-position" role="switch" type="button"></button>`, HTMLButtonElement);
21
+ const pressCentreZone = .08;
22
+ function pressedIndex(index, count, offset) {
23
+ if (count === 2) return index === 0 ? 1 : 0;
24
+ const side = Math.abs(offset) < pressCentreZone ? 1 : Math.sign(offset);
25
+ const next = index + side;
26
+ return next < 0 || next >= count ? index - side : next;
27
+ }
28
+ var SonicSwitch = class extends SonicRadioGroupElement {
29
+ static observedAttributes = [
30
+ ...SonicRadioGroupElement.observedAttributes,
31
+ "checked",
32
+ "orientation"
33
+ ];
34
+ get checked() {
35
+ return this.#isDirty ? this.#checked : this.defaultChecked;
36
+ }
37
+ set checked(isChecked) {
38
+ this.#isDirty = true;
39
+ this.#checked = isChecked === true;
40
+ this.render();
41
+ }
42
+ get defaultChecked() {
43
+ return this.hasAttribute("checked");
44
+ }
45
+ set defaultChecked(isChecked) {
46
+ this.reflect("checked", isChecked);
47
+ }
48
+ get orientation() {
49
+ return this.getAttribute("orientation") === "horizontal" ? "horizontal" : "vertical";
50
+ }
51
+ set orientation(direction) {
52
+ this.reflect("orientation", direction);
53
+ }
54
+ get value() {
55
+ const value = super.value;
56
+ return value === "" && this.#isBare() ? "on" : value;
57
+ }
58
+ set value(next) {
59
+ super.value = next;
60
+ }
61
+ group = renderSwitch();
62
+ #bare = renderBare();
63
+ #bat = requireChild(this.group, ".sonic-switch-bat", HTMLSpanElement);
64
+ #checked = false;
65
+ #holding;
66
+ #isClickSwallowed = false;
67
+ #isDirty = false;
68
+ attributeChangedCallback(name) {
69
+ if (name === "checked") this.#isDirty = false;
70
+ if (this.isDisabled()) this.#holding?.release();
71
+ super.attributeChangedCallback(name);
72
+ }
73
+ formResetCallback() {
74
+ this.#isDirty = false;
75
+ super.formResetCallback();
76
+ }
77
+ activate() {
78
+ if (this.#isBare()) this.#bare.click();
79
+ else super.activate();
80
+ }
81
+ chooseByClick(option) {
82
+ super.chooseByClick(option);
83
+ if (this.#isMomentary(option)) this.#springBack();
84
+ }
85
+ chooseByKey(option, event) {
86
+ if (!this.#isMomentary(option)) {
87
+ super.chooseByKey(option, event);
88
+ return;
89
+ }
90
+ if (event.repeat) return;
91
+ this.#hold(option, event.key);
92
+ option.focus();
93
+ }
94
+ claimPress(option, event) {
95
+ if (this.#isOnBat(event)) return true;
96
+ if (!this.#isMomentary(option)) return false;
97
+ this.group.setPointerCapture(event.pointerId);
98
+ this.#hold(option, event.pointerId);
99
+ return true;
100
+ }
101
+ connect(signal) {
102
+ const group = this.group;
103
+ this.upgradeProperties("defaultChecked", "checked", "orientation");
104
+ super.connect(signal);
105
+ this.checkStyles(group, "switch.css");
106
+ this.#bare.addEventListener("click", (event) => {
107
+ const isSwallowed = this.#isClickSwallowed && event instanceof PointerEvent && event.pointerType !== "";
108
+ this.#isClickSwallowed = false;
109
+ if (!isSwallowed) this.#setChecked(!this.checked);
110
+ }, { signal });
111
+ this.#bare.addEventListener("pointerdown", () => {
112
+ this.#isClickSwallowed = false;
113
+ }, { signal });
114
+ this.#bindBat(group, signal);
115
+ this.#holding = bindHold(group, {
116
+ canHold: () => !this.isDisabled(),
117
+ leave: "focusout",
118
+ onHold: () => {
119
+ this.toggleState("held", true);
120
+ },
121
+ onRelease: () => {
122
+ this.toggleState("held", false);
123
+ this.#springBack();
124
+ }
125
+ }, signal);
126
+ }
127
+ focusTarget() {
128
+ return this.#isBare() ? this.#bare : super.focusTarget();
129
+ }
130
+ isWrapping() {
131
+ return false;
132
+ }
133
+ releaseTarget(option) {
134
+ if (this.#isMomentary(option)) return void 0;
135
+ const options = this.options();
136
+ if (options.length === 2 && optionValue(option) === this.value) return options.find((other) => other !== option);
137
+ return option;
138
+ }
139
+ render() {
140
+ if (!this.isBound()) return;
141
+ const group = this.group;
142
+ const options = this.options();
143
+ if (options.length > 0) {
144
+ this.#bare.remove();
145
+ writeAttribute(group, "role", "radiogroup");
146
+ writeAttribute(group, "data-sonic-position-count", String(options.length));
147
+ super.render();
148
+ this.#renderThrow(this.#checkedIndex(options));
149
+ return;
150
+ }
151
+ const bare = this.#bare;
152
+ const isChecked = this.checked;
153
+ writeAttribute(group, "role", void 0);
154
+ delete group.dataset.sonicPositionCount;
155
+ if (bare.parentElement !== group) group.append(bare);
156
+ writeAttribute(bare, "disabled", this.isDisabled() ? "" : void 0);
157
+ writeAttribute(bare, "aria-checked", String(isChecked));
158
+ this.forwardNaming(group, false);
159
+ this.forwardNaming(bare, true);
160
+ const onSide = this.orientation === "horizontal" ? 1 : -1;
161
+ group.style.setProperty("--_sonic-switch-at", String(isChecked ? onSide : -onSide));
162
+ this.writeFormValue(isChecked ? this.value : null, String(isChecked));
163
+ }
164
+ renderOption() {
165
+ return renderPosition();
166
+ }
167
+ restoreState(state) {
168
+ if (this.#isBare()) this.checked = state === "true";
169
+ else super.restoreState(state);
170
+ }
171
+ #along(event) {
172
+ return this.orientation === "horizontal" ? event.clientX : event.clientY;
173
+ }
174
+ #bindBat(group, 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);
197
+ }
198
+ #checkedIndex(options) {
199
+ return options.findIndex((option) => optionValue(option) === this.value);
200
+ }
201
+ #hasSprungFrom(option) {
202
+ if (!option || !this.#isMomentary(option)) return false;
203
+ this.#holding?.release();
204
+ return this.value !== optionValue(option);
205
+ }
206
+ #hold(option, by) {
207
+ if (this.#holding?.hold(by) === true) this.select(option);
208
+ }
209
+ #isBare() {
210
+ return this.options().length === 0;
211
+ }
212
+ #isMomentary(option) {
213
+ const options = this.options();
214
+ return (option === options[0] || option === options.at(-1)) && options.length > 1 && option.querySelector("[data-sonic-value]")?.hasAttribute("data-sonic-momentary") === true;
215
+ }
216
+ #isOnBat(event) {
217
+ return isUnder(this.#bat, event.clientX, event.clientY);
218
+ }
219
+ #pressBat(event) {
220
+ const options = this.options();
221
+ if (options.length === 0) {
222
+ this.#setChecked(!this.checked);
223
+ return;
224
+ }
225
+ const box = this.#bat.getBoundingClientRect();
226
+ const [start, size] = this.orientation === "horizontal" ? [box.left, box.width] : [box.top, box.height];
227
+ const offset = (this.#along(event) - start) / size - .5;
228
+ const option = options[pressedIndex(this.#checkedIndex(options), options.length, offset)];
229
+ if (!option) return;
230
+ this.chooseByClick(option);
231
+ this.#refocus(options);
232
+ }
233
+ #refocus(options) {
234
+ if (this.group.matches(":focus-within")) options[this.#checkedIndex(options)]?.focus();
235
+ }
236
+ #renderThrow(index) {
237
+ const count = this.options().length;
238
+ const at = index < 0 || count < 2 ? 0 : 2 * index / (count - 1) - 1;
239
+ this.group.style.setProperty("--_sonic-switch-at", String(at));
240
+ }
241
+ #setChecked(isChecked) {
242
+ if (isChecked === this.checked) return;
243
+ this.checked = isChecked;
244
+ this.dispatchEvent(new Event("change", { bubbles: true }));
245
+ }
246
+ #springBack() {
247
+ const options = this.options();
248
+ const index = this.#checkedIndex(options);
249
+ const held = options[index];
250
+ if (!held || !this.#isMomentary(held)) return;
251
+ const rest = options[index === 0 ? 1 : index - 1];
252
+ if (!rest) return;
253
+ const isFocused = this.group.contains(this.ownerDocument.activeElement);
254
+ this.select(rest);
255
+ if (isFocused) rest.focus();
256
+ }
257
+ #throwBy(direction, pointerId) {
258
+ const options = this.options();
259
+ if (options.length === 0) {
260
+ this.#setChecked(direction === (this.orientation === "horizontal" ? 1 : -1));
261
+ return;
262
+ }
263
+ const index = this.#checkedIndex(options);
264
+ const option = options[clamp(index + direction, 0, options.length - 1)];
265
+ if (!option || option === options[index] || this.#hasSprungFrom(options[index])) return;
266
+ if (this.#isMomentary(option)) this.#hold(option, pointerId);
267
+ else this.select(option);
268
+ this.#refocus(options);
269
+ }
270
+ };
271
+
272
+ //#endregion
273
+ export { SonicSwitch };