@xsynaptic/sonic-ui 0.4.0 → 0.5.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 (240) hide show
  1. package/README.md +2 -21
  2. package/dist/default/dat.js +50 -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 +367 -0
  14. package/dist/default/elements/meter.js +149 -61
  15. package/dist/default/elements/number.js +21 -8
  16. package/dist/default/elements/radio-group.js +185 -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 +24 -13
  22. package/dist/default/elements/split.js +249 -0
  23. package/dist/default/elements/switch.js +279 -0
  24. package/dist/default/elements/value-element.js +691 -0
  25. package/dist/default/elements/{range-entry.js → value-entry.js} +3 -3
  26. package/dist/default/elements/wave-element.js +77 -0
  27. package/dist/default/elements/waveform.js +305 -0
  28. package/dist/default/elements/wavestrip.js +182 -0
  29. package/dist/default/elements/xy.js +473 -0
  30. package/dist/default/index.js +10 -2
  31. package/dist/default/lib/adsr-shape.js +108 -0
  32. package/dist/default/lib/ballistics.js +55 -0
  33. package/dist/default/lib/canvas-surface.js +192 -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 +62 -0
  42. package/dist/default/lib/hold.js +38 -0
  43. package/dist/default/lib/marker-band.js +36 -0
  44. package/dist/default/lib/marker-rider.js +114 -0
  45. package/dist/default/lib/math.js +12 -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 +43 -0
  49. package/dist/default/lib/render.js +20 -5
  50. package/dist/default/lib/resample-peaks.js +36 -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/dev/dat.d.ts +19 -0
  58. package/dist/dev/dat.js +51 -0
  59. package/dist/dev/dat.js.map +1 -0
  60. package/dist/dev/define/button.d.ts +2 -0
  61. package/dist/dev/define/button.js +8 -0
  62. package/dist/dev/define/button.js.map +1 -0
  63. package/dist/dev/define/dial.js.map +1 -1
  64. package/dist/dev/define/envelope.d.ts +2 -0
  65. package/dist/dev/define/envelope.js +8 -0
  66. package/dist/dev/define/envelope.js.map +1 -0
  67. package/dist/dev/define/meter.js.map +1 -1
  68. package/dist/dev/define/number.js.map +1 -1
  69. package/dist/dev/define/segmented.js.map +1 -1
  70. package/dist/dev/define/slider.js.map +1 -1
  71. package/dist/dev/define/split.d.ts +2 -0
  72. package/dist/dev/define/split.js +8 -0
  73. package/dist/dev/define/split.js.map +1 -0
  74. package/dist/dev/define/switch.d.ts +2 -0
  75. package/dist/dev/define/switch.js +8 -0
  76. package/dist/dev/define/switch.js.map +1 -0
  77. package/dist/dev/define/waveform.d.ts +2 -0
  78. package/dist/dev/define/waveform.js +8 -0
  79. package/dist/dev/define/waveform.js.map +1 -0
  80. package/dist/dev/define/wavestrip.d.ts +2 -0
  81. package/dist/dev/define/wavestrip.js +8 -0
  82. package/dist/dev/define/wavestrip.js.map +1 -0
  83. package/dist/dev/define/xy.d.ts +2 -0
  84. package/dist/dev/define/xy.js +8 -0
  85. package/dist/dev/define/xy.js.map +1 -0
  86. package/dist/dev/define.d.ts +15 -3
  87. package/dist/dev/define.js +7 -1
  88. package/dist/dev/elements/{key.d.ts → button.d.ts} +8 -6
  89. package/dist/dev/elements/button.js +166 -0
  90. package/dist/dev/elements/button.js.map +1 -0
  91. package/dist/dev/elements/dial.d.ts +6 -4
  92. package/dist/dev/elements/dial.js +16 -22
  93. package/dist/dev/elements/dial.js.map +1 -1
  94. package/dist/dev/elements/envelope.d.ts +36 -0
  95. package/dist/dev/elements/envelope.js +372 -0
  96. package/dist/dev/elements/envelope.js.map +1 -0
  97. package/dist/dev/elements/form-element.d.ts +1 -1
  98. package/dist/dev/elements/form-element.js.map +1 -1
  99. package/dist/dev/elements/meter.d.ts +10 -5
  100. package/dist/dev/elements/meter.js +149 -61
  101. package/dist/dev/elements/meter.js.map +1 -1
  102. package/dist/dev/elements/number.d.ts +7 -3
  103. package/dist/dev/elements/number.js +21 -8
  104. package/dist/dev/elements/number.js.map +1 -1
  105. package/dist/dev/elements/radio-group.d.ts +25 -0
  106. package/dist/dev/elements/radio-group.js +186 -0
  107. package/dist/dev/elements/radio-group.js.map +1 -0
  108. package/dist/dev/elements/readout-claim.js +82 -0
  109. package/dist/dev/elements/readout-claim.js.map +1 -0
  110. package/dist/dev/elements/readout.js +36 -0
  111. package/dist/dev/elements/readout.js.map +1 -0
  112. package/dist/dev/elements/segmented.d.ts +4 -10
  113. package/dist/dev/elements/segmented.js +9 -159
  114. package/dist/dev/elements/segmented.js.map +1 -1
  115. package/dist/dev/elements/slider.d.ts +6 -6
  116. package/dist/dev/elements/slider.js +42 -51
  117. package/dist/dev/elements/slider.js.map +1 -1
  118. package/dist/dev/elements/sonic-element.d.ts +4 -3
  119. package/dist/dev/elements/sonic-element.js +51 -22
  120. package/dist/dev/elements/sonic-element.js.map +1 -1
  121. package/dist/dev/elements/split.d.ts +21 -0
  122. package/dist/dev/elements/split.js +258 -0
  123. package/dist/dev/elements/split.js.map +1 -0
  124. package/dist/dev/elements/switch.d.ts +35 -0
  125. package/dist/dev/elements/switch.js +280 -0
  126. package/dist/dev/elements/switch.js.map +1 -0
  127. package/dist/dev/elements/value-element.d.ts +84 -0
  128. package/dist/dev/elements/value-element.js +692 -0
  129. package/dist/dev/elements/value-element.js.map +1 -0
  130. package/dist/dev/elements/{range-entry.js → value-entry.js} +4 -4
  131. package/dist/dev/elements/value-entry.js.map +1 -0
  132. package/dist/dev/elements/wave-element.d.ts +36 -0
  133. package/dist/dev/elements/wave-element.js +78 -0
  134. package/dist/dev/elements/wave-element.js.map +1 -0
  135. package/dist/dev/elements/waveform.d.ts +55 -0
  136. package/dist/dev/elements/waveform.js +306 -0
  137. package/dist/dev/elements/waveform.js.map +1 -0
  138. package/dist/dev/elements/wavestrip.d.ts +51 -0
  139. package/dist/dev/elements/wavestrip.js +183 -0
  140. package/dist/dev/elements/wavestrip.js.map +1 -0
  141. package/dist/dev/elements/xy.d.ts +62 -0
  142. package/dist/dev/elements/xy.js +474 -0
  143. package/dist/dev/elements/xy.js.map +1 -0
  144. package/dist/dev/index.d.ts +11 -2
  145. package/dist/dev/index.js +10 -2
  146. package/dist/dev/lib/adsr-shape.js +109 -0
  147. package/dist/dev/lib/adsr-shape.js.map +1 -0
  148. package/dist/dev/lib/ballistics.js +56 -0
  149. package/dist/dev/lib/ballistics.js.map +1 -0
  150. package/dist/dev/lib/canvas-surface.d.ts +25 -0
  151. package/dist/dev/lib/canvas-surface.js +193 -0
  152. package/dist/dev/lib/canvas-surface.js.map +1 -0
  153. package/dist/dev/lib/copy-node.js +32 -2
  154. package/dist/dev/lib/copy-node.js.map +1 -1
  155. package/dist/dev/lib/crossfade.d.ts +12 -0
  156. package/dist/dev/lib/crossfade.js +23 -0
  157. package/dist/dev/lib/crossfade.js.map +1 -0
  158. package/dist/dev/lib/distribute.d.ts +4 -0
  159. package/dist/dev/lib/distribute.js +216 -0
  160. package/dist/dev/lib/distribute.js.map +1 -0
  161. package/dist/dev/lib/drag-step.js +100 -0
  162. package/dist/dev/lib/drag-step.js.map +1 -0
  163. package/dist/dev/lib/envelope-curve.d.ts +4 -0
  164. package/dist/dev/lib/envelope-curve.js +10 -0
  165. package/dist/dev/lib/envelope-curve.js.map +1 -0
  166. package/dist/dev/lib/field.d.ts +4 -0
  167. package/dist/dev/lib/field.js +95 -0
  168. package/dist/dev/lib/field.js.map +1 -0
  169. package/dist/dev/lib/focus-by-pointer.js +29 -0
  170. package/dist/dev/lib/focus-by-pointer.js.map +1 -0
  171. package/dist/dev/lib/frame-timeline.js +63 -0
  172. package/dist/dev/lib/frame-timeline.js.map +1 -0
  173. package/dist/dev/lib/hold.js +39 -0
  174. package/dist/dev/lib/hold.js.map +1 -0
  175. package/dist/dev/lib/marker-band.js +37 -0
  176. package/dist/dev/lib/marker-band.js.map +1 -0
  177. package/dist/dev/lib/marker-rider.js +115 -0
  178. package/dist/dev/lib/marker-rider.js.map +1 -0
  179. package/dist/dev/lib/math.js +12 -3
  180. package/dist/dev/lib/math.js.map +1 -1
  181. package/dist/dev/lib/modifier-press.js +12 -0
  182. package/dist/dev/lib/modifier-press.js.map +1 -0
  183. package/dist/dev/lib/number-list.js +6 -6
  184. package/dist/dev/lib/number-list.js.map +1 -1
  185. package/dist/dev/lib/pointer-drag.js +44 -0
  186. package/dist/dev/lib/pointer-drag.js.map +1 -0
  187. package/dist/dev/lib/read-px-property.js.map +1 -1
  188. package/dist/dev/lib/render.js +20 -5
  189. package/dist/dev/lib/render.js.map +1 -1
  190. package/dist/dev/lib/resample-peaks.js +37 -0
  191. package/dist/dev/lib/resample-peaks.js.map +1 -0
  192. package/dist/dev/lib/strip-scene.js +49 -0
  193. package/dist/dev/lib/strip-scene.js.map +1 -0
  194. package/dist/dev/lib/taper.js +23 -17
  195. package/dist/dev/lib/taper.js.map +1 -1
  196. package/dist/dev/lib/time-regions.d.ts +4 -0
  197. package/dist/dev/lib/time-regions.js +9 -0
  198. package/dist/dev/lib/time-regions.js.map +1 -0
  199. package/dist/dev/lib/tracking-clock.js +36 -0
  200. package/dist/dev/lib/tracking-clock.js.map +1 -0
  201. package/dist/dev/lib/value-mapping.d.ts +23 -0
  202. package/dist/dev/lib/value-mapping.js +116 -0
  203. package/dist/dev/lib/value-mapping.js.map +1 -0
  204. package/dist/dev/lib/waveform-buckets.d.ts +9 -0
  205. package/dist/dev/lib/waveform-buckets.js +42 -0
  206. package/dist/dev/lib/waveform-buckets.js.map +1 -0
  207. package/dist/skins/ivory.css +1 -2
  208. package/dist/styles/button.css +212 -0
  209. package/dist/styles/controls.css +8 -1
  210. package/dist/styles/dial.css +88 -42
  211. package/dist/styles/envelope.css +159 -0
  212. package/dist/styles/led.css +36 -5
  213. package/dist/styles/material.css +277 -76
  214. package/dist/styles/meter.css +33 -48
  215. package/dist/styles/number.css +5 -1
  216. package/dist/styles/panel.css +59 -0
  217. package/dist/styles/ring.css +74 -0
  218. package/dist/styles/segmented.css +21 -48
  219. package/dist/styles/slider.css +175 -39
  220. package/dist/styles/switch.css +347 -0
  221. package/dist/styles/waveform.css +173 -0
  222. package/dist/styles/wavestrip.css +215 -0
  223. package/dist/styles/xy.css +204 -0
  224. package/package.json +14 -2
  225. package/dist/default/define/key.js +0 -7
  226. package/dist/default/elements/key.js +0 -169
  227. package/dist/default/elements/range-element.js +0 -546
  228. package/dist/default/lib/detent.js +0 -17
  229. package/dist/dev/define/key.d.ts +0 -2
  230. package/dist/dev/define/key.js +0 -8
  231. package/dist/dev/define/key.js.map +0 -1
  232. package/dist/dev/elements/key.js +0 -170
  233. package/dist/dev/elements/key.js.map +0 -1
  234. package/dist/dev/elements/range-element.d.ts +0 -64
  235. package/dist/dev/elements/range-element.js +0 -547
  236. package/dist/dev/elements/range-element.js.map +0 -1
  237. package/dist/dev/elements/range-entry.js.map +0 -1
  238. package/dist/dev/lib/detent.js +0 -18
  239. package/dist/dev/lib/detent.js.map +0 -1
  240. package/dist/styles/key.css +0 -242
@@ -1,547 +0,0 @@
1
- import { requireChild } from "../lib/render.js";
2
- import { writeAttribute } from "../lib/write-attribute.js";
3
- import { SonicFormElement } from "./form-element.js";
4
- import { RangeEntry } from "./range-entry.js";
5
- import { copyNode } from "../lib/copy-node.js";
6
- import { passDetent } from "../lib/detent.js";
7
- import { clamp, clampUnit, trimFloat, wrapUnit } from "../lib/math.js";
8
- import { nearestEntry, parseNumberList } from "../lib/number-list.js";
9
- import { readPxProperty } from "../lib/read-px-property.js";
10
- import { linearTaper, listTaper, logTaper, skewTaper } from "../lib/taper.js";
11
-
12
- //#region src/elements/range-element.ts
13
- const detentZonePx = 8;
14
- const fineScale = .1;
15
- const keyRevealMs = 1e3;
16
- const pageSteps = 10;
17
- const revealMs = 250;
18
- const revealPx = 4;
19
- const canPopover = "togglePopover" in HTMLElement.prototype;
20
- let instanceCount = 0;
21
- const resetKeys = /* @__PURE__ */ new Set(["Backspace", "Delete"]);
22
- const endKeys = /* @__PURE__ */ new Set(["End", "Home"]);
23
- const keySteps = /* @__PURE__ */ new Map([
24
- ["ArrowDown", -1],
25
- ["ArrowLeft", -1],
26
- ["ArrowRight", 1],
27
- ["ArrowUp", 1],
28
- ["PageDown", -10],
29
- ["PageUp", pageSteps]
30
- ]);
31
- const roleAttributes = [
32
- "aria-disabled",
33
- "aria-orientation",
34
- "aria-valuemax",
35
- "aria-valuemin",
36
- "aria-valuenow",
37
- "aria-valuetext",
38
- "role",
39
- "tabindex"
40
- ];
41
- function scaleValue(mark) {
42
- const text = mark.dataset.sonicValue?.trim();
43
- return text ? Number(text) : NaN;
44
- }
45
- function scaleMark(original) {
46
- const mark = copyNode(original);
47
- if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return [];
48
- if (!Number.isFinite(scaleValue(mark))) return [];
49
- const isTick = mark.childElementCount === 0 && mark.textContent.trim() === "";
50
- mark.classList.add(isTick ? "sonic-scale-tick" : "sonic-scale-label");
51
- return [mark];
52
- }
53
- var SonicRangeElement = class extends SonicFormElement {
54
- static observedAttributes = [
55
- ...SonicFormElement.observedAttributes,
56
- "detent",
57
- "max",
58
- "midpoint",
59
- "min",
60
- "notched",
61
- "origin",
62
- "readout",
63
- "step",
64
- "taper",
65
- "value",
66
- "values"
67
- ];
68
- get default() {
69
- return this.optionalNumberAttribute("default");
70
- }
71
- set default(value) {
72
- this.reflect("default", value);
73
- }
74
- get detent() {
75
- return this.optionalNumberAttribute("detent");
76
- }
77
- set detent(value) {
78
- this.reflect("detent", value);
79
- }
80
- get dimmed() {
81
- return this.hasAttribute("dimmed");
82
- }
83
- set dimmed(isDimmed) {
84
- this.reflect("dimmed", isDimmed);
85
- }
86
- get doublePress() {
87
- return this.getAttribute("double-press") === "reset" ? "reset" : "type";
88
- }
89
- set doublePress(gesture) {
90
- this.reflect("double-press", gesture);
91
- }
92
- get formatValue() {
93
- return this.#formatValue;
94
- }
95
- set formatValue(format) {
96
- this.#formatValue = format;
97
- this.render();
98
- }
99
- get max() {
100
- return this.numberAttribute("max", 100);
101
- }
102
- set max(value) {
103
- this.reflect("max", value);
104
- }
105
- get midpoint() {
106
- return this.optionalNumberAttribute("midpoint");
107
- }
108
- set midpoint(value) {
109
- this.reflect("midpoint", value);
110
- }
111
- get min() {
112
- return this.numberAttribute("min", 0);
113
- }
114
- set min(value) {
115
- this.reflect("min", value);
116
- }
117
- get notched() {
118
- return this.hasAttribute("notched");
119
- }
120
- set notched(isNotched) {
121
- this.reflect("notched", isNotched);
122
- }
123
- get origin() {
124
- return this.optionalNumberAttribute("origin");
125
- }
126
- set origin(value) {
127
- this.reflect("origin", value);
128
- }
129
- get parseValue() {
130
- return this.#parseValue;
131
- }
132
- set parseValue(parse) {
133
- this.#parseValue = parse;
134
- }
135
- get readout() {
136
- return this.hasAttribute("readout");
137
- }
138
- set readout(isShown) {
139
- this.reflect("readout", isShown);
140
- }
141
- get step() {
142
- return this.numberAttribute("step", 1);
143
- }
144
- set step(value) {
145
- this.reflect("step", value);
146
- }
147
- get taper() {
148
- return this.getAttribute("taper") === "log" ? "log" : "linear";
149
- }
150
- set taper(curve) {
151
- this.reflect("taper", curve);
152
- }
153
- get value() {
154
- return this.#value;
155
- }
156
- set value(next) {
157
- if (this.#drag) return;
158
- this.#write(next);
159
- }
160
- get values() {
161
- return parseNumberList(this.getAttribute("values"));
162
- }
163
- set values(entries) {
164
- this.reflect("values", entries?.join(" "));
165
- }
166
- #drag;
167
- #entries;
168
- #entry;
169
- #formatValue;
170
- #instance = String(instanceCount += 1);
171
- #isDirty = false;
172
- #keyRevealTimer;
173
- #parseValue;
174
- #readout;
175
- #scale;
176
- #value = 0;
177
- attributeChangedCallback(name) {
178
- this.#entries = parseNumberList(this.getAttribute("values"));
179
- if (name === "value") {
180
- if (this.#drag) return;
181
- this.#isDirty = false;
182
- }
183
- if (name === "disabled" && this.isDisabled()) {
184
- this.#entry?.close(false);
185
- this.#endDrag();
186
- }
187
- this.#value = this.#clamp(this.#isDirty ? this.#value : this.numberAttribute("value", this.min));
188
- this.render();
189
- }
190
- connectedCallback() {
191
- this.upgradeProperties("default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "step", "taper", "values", "detent", "formatValue", "parseValue", "value");
192
- super.connectedCallback();
193
- }
194
- bindGestures(control, signal, grab) {
195
- const entry = this.#bindEntry(control, signal);
196
- control.addEventListener("pointerdown", (event) => {
197
- if (event.button !== 0 || this.isDisabled() || entry.isOpen) return;
198
- if (event.pointerType === "touch") event.preventDefault();
199
- control.focus();
200
- if (event.metaKey || event.ctrlKey) {
201
- this.#reset();
202
- return;
203
- }
204
- const fromValue = this.#value;
205
- const axis = grab(event);
206
- if (!axis) return;
207
- const startPosition = axis.position(event);
208
- const drag = {
209
- detent: this.#detentHold(control, axis.travelPx),
210
- fromValue,
211
- isRevealed: false,
212
- lastPosition: startPosition,
213
- pointerId: event.pointerId,
214
- position: axis.position,
215
- rawFraction: this.fraction(this.#value),
216
- revealTimer: void 0,
217
- startPosition,
218
- travelPx: axis.travelPx
219
- };
220
- drag.revealTimer = setTimeout(() => {
221
- this.#reveal(drag);
222
- }, revealMs);
223
- this.#drag = drag;
224
- control.setPointerCapture(event.pointerId);
225
- this.toggleState("dragging", true);
226
- }, { signal });
227
- control.addEventListener("pointermove", (event) => {
228
- const drag = this.#drag;
229
- if (event.pointerId !== drag?.pointerId) return;
230
- const position = drag.position(event);
231
- const scale = event.shiftKey ? fineScale : 1;
232
- const next = this.#move(drag, (position - drag.lastPosition) / drag.travelPx * scale);
233
- drag.lastPosition = position;
234
- if (Math.abs(position - drag.startPosition) >= revealPx) this.#reveal(drag);
235
- this.input(next);
236
- }, { signal });
237
- const endDrag = (event) => {
238
- if (event.pointerId === this.#drag?.pointerId) this.#endDrag();
239
- };
240
- control.addEventListener("pointercancel", (event) => {
241
- endDrag(event);
242
- entry.forgetPress();
243
- }, { signal });
244
- control.addEventListener("lostpointercapture", endDrag, { signal });
245
- control.addEventListener("pointerup", (event) => {
246
- if (event.pointerId !== this.#drag?.pointerId) return;
247
- this.#endDrag();
248
- if (!entry.press(event) || this.springTarget() !== void 0) return;
249
- if (this.doublePress === "reset") this.#reset();
250
- else entry.open();
251
- }, { signal });
252
- this.#bindKeys(control, entry, signal);
253
- signal.addEventListener("abort", () => {
254
- this.#endDrag();
255
- this.#hideForKeys();
256
- }, { once: true });
257
- }
258
- bindScale(control, scale, signal) {
259
- this.#scale = scale;
260
- this.mirrorChildren({
261
- control,
262
- copy: (originals) => {
263
- scale.replaceChildren(...originals.flatMap((original) => scaleMark(original)));
264
- this.renderScale();
265
- },
266
- isCopied: (child) => child instanceof Element && child.matches("[data-sonic-value]")
267
- }, signal);
268
- }
269
- clampRange(next) {
270
- const min = this.min;
271
- if (!this.wraps()) return clamp(next, min, this.#max());
272
- const range = this.range();
273
- if (range <= 0) return min;
274
- const offset = trimFloat(((next - min) % range + range) % range);
275
- return offset >= range ? min : trimFloat(min + offset);
276
- }
277
- controlRole() {
278
- return "slider";
279
- }
280
- fraction(value) {
281
- return (this.#taper() ?? linearTaper(this.min, this.#max())).position(value);
282
- }
283
- input(next) {
284
- const previous = this.#value;
285
- this.#write(next);
286
- if (this.#value === previous) return false;
287
- this.dispatchEvent(new Event("input", {
288
- bubbles: true,
289
- composed: true
290
- }));
291
- return true;
292
- }
293
- modulationFractions(amount) {
294
- const value = this.fraction(this.#value);
295
- const modulated = this.fraction(this.#value + amount);
296
- return [Math.min(value, modulated), Math.max(value, modulated)];
297
- }
298
- originFraction() {
299
- return this.fraction(this.restValue());
300
- }
301
- positions() {
302
- const positions = this.#entries?.length ?? Math.round(this.range() / this.step) + (this.wraps() ? 0 : 1);
303
- if (!this.notched || !Number.isFinite(positions) || positions < 2) return;
304
- return positions;
305
- }
306
- range() {
307
- return this.#max() - this.min;
308
- }
309
- renderAria(control, orientation) {
310
- this.writeFormValue(String(this.#value), String(this.#value));
311
- if (this.#entry?.isOpen) {
312
- for (const name of roleAttributes) control.removeAttribute(name);
313
- this.forwardNaming(control, false);
314
- this.#renderReadout();
315
- return;
316
- }
317
- const [low, high] = this.#bounds();
318
- control.setAttribute("role", this.controlRole());
319
- control.setAttribute("aria-valuemin", String(low));
320
- control.setAttribute("aria-valuemax", String(high));
321
- control.setAttribute("aria-valuenow", String(this.#value));
322
- if (orientation) control.setAttribute("aria-orientation", orientation);
323
- writeAttribute(control, "aria-valuetext", this.#formatValue?.(this.#value));
324
- this.forwardNaming(control, true);
325
- this.#renderDisabled(control);
326
- this.#renderReadout();
327
- }
328
- renderScale() {
329
- const marks = this.#scale?.children ?? [];
330
- for (const mark of marks) {
331
- if (!(mark instanceof HTMLElement || mark instanceof SVGElement)) continue;
332
- const at = String(this.fraction(this.clampRange(scaleValue(mark))));
333
- if (mark.style.getPropertyValue("--_sonic-scale-at") !== at) mark.style.setProperty("--_sonic-scale-at", at);
334
- }
335
- }
336
- restoreState(state) {
337
- this.value = Number(state);
338
- }
339
- restValue() {
340
- return this.origin ?? this.#bounds()[0];
341
- }
342
- springTarget() {}
343
- valueAt(fraction) {
344
- return (this.#taper() ?? linearTaper(this.min, this.#max())).value(fraction);
345
- }
346
- valueText() {
347
- return this.#formatValue?.(this.#value) ?? String(this.#value);
348
- }
349
- wraps() {
350
- return false;
351
- }
352
- #bindEntry(control, signal) {
353
- const input = requireChild(control, "input", HTMLInputElement);
354
- const bubble = control.querySelector("[popover]");
355
- input.id = `sonic-entry-${this.#instance}`;
356
- if (bubble) {
357
- const anchor = `--sonic-readout-${this.#instance}`;
358
- this.#readout = {
359
- bubble,
360
- text: requireChild(bubble, "span", HTMLElement)
361
- };
362
- control.style.setProperty("anchor-name", anchor);
363
- bubble.style.setProperty("position-anchor", anchor);
364
- }
365
- const entry = new RangeEntry(input, {
366
- commit: (text) => {
367
- this.#commit((this.#parseValue ?? Number.parseFloat)(text));
368
- },
369
- text: () => this.#parseValue ? this.valueText() : String(this.#value),
370
- toggle: (isOpen) => {
371
- if (isOpen) this.forwardNaming(input, true);
372
- this.toggleState("editing", isOpen);
373
- this.render();
374
- }
375
- });
376
- this.#entry = entry;
377
- entry.bind(control, signal);
378
- return entry;
379
- }
380
- #bindKeys(control, entry, signal) {
381
- control.addEventListener("keydown", (event) => {
382
- if (this.isDisabled() || event.defaultPrevented || event.target !== control) return;
383
- if (event.key === "Enter") {
384
- if (this.springTarget() !== void 0) return;
385
- event.preventDefault();
386
- entry.open();
387
- return;
388
- }
389
- const next = this.#keyTarget(event.key);
390
- if (next === void 0) return;
391
- event.preventDefault();
392
- this.#commit(next);
393
- this.#revealForKeys();
394
- }, { signal });
395
- control.addEventListener("keyup", (event) => {
396
- if (keySteps.has(event.key) || endKeys.has(event.key)) this.#springBack();
397
- }, { signal });
398
- control.addEventListener("blur", () => {
399
- this.#hideForKeys();
400
- this.#springBack();
401
- }, { signal });
402
- }
403
- #bounds() {
404
- const entries = this.#entries;
405
- return [entries?.[0] ?? this.min, entries?.at(-1) ?? this.#max()];
406
- }
407
- #clamp(next) {
408
- const entries = this.#entries;
409
- if (entries) return nearestEntry(entries, next);
410
- const min = this.min;
411
- const step = this.step;
412
- const stepped = step > 0 ? min + Math.round((next - min) / step) * step : next;
413
- return this.clampRange(trimFloat(stepped));
414
- }
415
- #commit(next) {
416
- if (this.input(next)) this.dispatchEvent(new Event("change", { bubbles: true }));
417
- }
418
- #detentHold(control, travelPx) {
419
- const detent = this.detent;
420
- if (detent === void 0) return void 0;
421
- const value = this.#clamp(detent);
422
- const zonePx = readPxProperty(getComputedStyle(control), "--_sonic-detent-zone", detentZonePx);
423
- return {
424
- place: this.fraction(value),
425
- slack: value === this.#value ? 0 : void 0,
426
- value,
427
- zone: zonePx / travelPx
428
- };
429
- }
430
- #end(step) {
431
- if (!this.wraps()) return this.#bounds()[1];
432
- return this.min + (Math.ceil(this.range() / step) - 1) * step;
433
- }
434
- #endDrag() {
435
- const drag = this.#drag;
436
- if (!drag) return;
437
- clearTimeout(drag.revealTimer);
438
- this.#drag = void 0;
439
- this.toggleState("dragging", false);
440
- this.#renderReadout();
441
- if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
442
- this.#springBack();
443
- }
444
- #hideForKeys() {
445
- clearTimeout(this.#keyRevealTimer);
446
- if (this.#keyRevealTimer === void 0) return;
447
- this.#keyRevealTimer = void 0;
448
- this.#renderReadout();
449
- }
450
- #isValueShown() {
451
- return (this.#drag?.isRevealed === true || this.#keyRevealTimer !== void 0) && this.readout;
452
- }
453
- #keyTarget(key) {
454
- if (key === "Home") return this.#bounds()[0];
455
- const step = this.step > 0 ? this.step : this.range() / 100;
456
- if (key === "End") return this.#end(step);
457
- if (resetKeys.has(key)) return this.default;
458
- const steps = keySteps.get(key);
459
- if (steps === void 0) return void 0;
460
- return this.#stopAtDetent(this.#stepBy(steps, step));
461
- }
462
- #max() {
463
- return Math.max(this.min, this.max);
464
- }
465
- #move(drag, delta) {
466
- const { detent } = drag;
467
- const to = drag.rawFraction + delta;
468
- const next = detent ? passDetent(detent, drag.rawFraction, to) : to;
469
- if (detent && next === void 0) {
470
- drag.rawFraction = detent.place;
471
- return detent.value;
472
- }
473
- const place = next ?? to;
474
- drag.rawFraction = this.wraps() ? wrapUnit(place) : clampUnit(place);
475
- return this.valueAt(drag.rawFraction);
476
- }
477
- #renderDisabled(control) {
478
- if (this.isDisabled()) {
479
- control.setAttribute("aria-disabled", "true");
480
- control.removeAttribute("tabindex");
481
- return;
482
- }
483
- control.removeAttribute("aria-disabled");
484
- control.setAttribute("tabindex", "0");
485
- }
486
- #renderReadout() {
487
- const readout = this.#readout;
488
- if (!readout || !canPopover || !this.isConnected) return;
489
- const isEditing = this.#entry?.isOpen === true;
490
- readout.text.hidden = isEditing;
491
- if (!isEditing) readout.text.textContent = this.valueText();
492
- readout.bubble.togglePopover(isEditing || this.#isValueShown());
493
- }
494
- #reset() {
495
- this.#commit(this.default ?? NaN);
496
- }
497
- #reveal(drag) {
498
- if (drag.isRevealed || this.#drag !== drag) return;
499
- drag.isRevealed = true;
500
- this.#renderReadout();
501
- }
502
- #revealForKeys() {
503
- clearTimeout(this.#keyRevealTimer);
504
- this.#keyRevealTimer = setTimeout(() => {
505
- this.#hideForKeys();
506
- }, keyRevealMs);
507
- this.#renderReadout();
508
- }
509
- #springBack() {
510
- const target = this.springTarget();
511
- if (target !== void 0) this.#commit(target);
512
- }
513
- #stepBy(steps, step) {
514
- const entries = this.#entries;
515
- if (entries) return entries[clamp(entries.indexOf(this.#value) + steps, 0, entries.length - 1)] ?? this.#value;
516
- const taper = this.#taper();
517
- if (!taper) return this.#value + steps * step;
518
- const next = this.#clamp(taper.value(taper.position(this.#value) + steps / 100));
519
- return next === this.#value ? this.#value + Math.sign(steps) * step : next;
520
- }
521
- #stopAtDetent(next) {
522
- const detent = this.detent;
523
- if (detent === void 0) return next;
524
- const value = this.#clamp(detent);
525
- return (this.#value - value) * (next - value) < 0 ? value : next;
526
- }
527
- #taper() {
528
- const entries = this.#entries;
529
- if (entries) return listTaper(entries);
530
- if (this.notched || this.wraps()) return void 0;
531
- const min = this.min;
532
- const max = this.#max();
533
- return (this.taper === "log" ? logTaper(min, max) : void 0) ?? skewTaper(min, max, this.midpoint ?? NaN);
534
- }
535
- #write(next) {
536
- if (!Number.isFinite(next)) return;
537
- this.#isDirty = true;
538
- const clamped = this.#clamp(next);
539
- if (clamped === this.#value) return;
540
- this.#value = clamped;
541
- this.render();
542
- }
543
- };
544
-
545
- //#endregion
546
- export { SonicRangeElement };
547
- //# sourceMappingURL=range-element.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"range-element.js","names":[],"sources":["../../../src/elements/range-element.ts"],"sourcesContent":["import type { DetentHold } from '#lib/detent.ts';\nimport type { Taper } from '#lib/taper.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { RangeEntry } from '#elements/range-entry.ts';\nimport { copyNode } from '#lib/copy-node.ts';\nimport { passDetent } from '#lib/detent.ts';\nimport { clamp, clampUnit, trimFloat, wrapUnit } from '#lib/math.ts';\nimport { nearestEntry, parseNumberList } from '#lib/number-list.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { requireChild } from '#lib/render.ts';\nimport { linearTaper, listTaper, logTaper, skewTaper } from '#lib/taper.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\n// `position` grows with the value\nexport interface RangeAxis {\n\tposition: (event: PointerEvent) => number;\n\ttravelPx: number;\n}\n\ninterface RangeDrag extends RangeAxis {\n\tdetent: DetentHold | undefined;\n\tfromValue: number;\n\tisRevealed: boolean;\n\tlastPosition: number;\n\tpointerId: number;\n\t// Unstepped, or a slow drag rounds back to where it started\n\trawFraction: number;\n\trevealTimer: ReturnType<typeof setTimeout> | undefined;\n\tstartPosition: number;\n}\n\nconst detentZonePx = 8;\nconst fineScale = 0.1;\nconst keyRevealMs = 1000;\nconst pageSteps = 10;\nconst revealMs = 250;\nconst revealPx = 4;\n\n// happy-dom has no popover API\nconst canPopover = 'togglePopover' in HTMLElement.prototype;\n\n// A shared anchor name resolves to the last one on the page\nlet instanceCount = 0;\n\n// A Mac keyboard's Delete sends Backspace\nconst resetKeys = new Set(['Backspace', 'Delete']);\n\nconst endKeys = new Set(['End', 'Home']);\n\nconst keySteps = new Map([\n\t['ArrowDown', -1],\n\t['ArrowLeft', -1],\n\t['ArrowRight', 1],\n\t['ArrowUp', 1],\n\t['PageDown', -pageSteps],\n\t['PageUp', pageSteps],\n]);\n\n// A slider's children are presentational, so these come off while the entry is open\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\n// Blank is not zero, and a mark with no value has no place\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): Array<ScaleMark> {\n\tconst mark = copyNode(original);\n\tif (!(mark instanceof HTMLElement || mark instanceof SVGElement)) return [];\n\tif (!Number.isFinite(scaleValue(mark))) return [];\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\n// As on `<input type=\"range\">`, the property never writes the `value` attribute back\nexport abstract class SonicRangeElement 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'values',\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\t// Named for the absent attribute, as `input.type` reads `text`\n\tget doublePress(): 'reset' | 'type' {\n\t\treturn this.getAttribute('double-press') === 'reset' ? 'reset' : 'type';\n\t}\n\n\tset doublePress(gesture: 'reset' | 'type' | undefined) {\n\t\tthis.reflect('double-press', gesture);\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\t// Unclamped by `min`, so reading it back never pins the range\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\t// `undefined` while unset, so reading it back never pins it to `min`\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 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\t// A drag owns the value, so a timer's write can't pull the cap from under the pointer\n\tset value(next: number) {\n\t\tif (this.#drag) return;\n\n\t\tthis.#write(next);\n\t}\n\n\tget values(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('values'));\n\t}\n\n\tset values(entries: Array<number> | undefined) {\n\t\tthis.reflect('values', entries?.join(' '));\n\t}\n\n\t#drag: RangeDrag | undefined;\n\n\t#entries: Array<number> | undefined;\n\n\t#entry: RangeEntry | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t// Re-read from the attribute until the property is set, since `max` may arrive after `value`\n\t#isDirty = false;\n\n\t#keyRevealTimer: ReturnType<typeof setTimeout> | undefined;\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#readout: undefined | { bubble: HTMLElement; text: HTMLElement };\n\n\t#scale: HTMLElement | undefined;\n\n\t#value = 0;\n\n\tattributeChangedCallback(name: string): void {\n\t\tthis.#entries = parseNumberList(this.getAttribute('values'));\n\t\tif (name === 'value') {\n\t\t\tif (this.#drag) return;\n\n\t\t\tthis.#isDirty = false;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) {\n\t\t\tthis.#entry?.close(false);\n\t\t\tthis.#endDrag();\n\t\t}\n\n\t\tthis.#value = this.#clamp(\n\t\t\tthis.#isDirty ? this.#value : this.numberAttribute('value', this.min),\n\t\t);\n\t\tthis.render();\n\t}\n\n\t// The range before `value`, or a value set with its `max` before upgrade clamps to the old one\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'step',\n\t\t\t'taper',\n\t\t\t'values',\n\t\t\t'detent',\n\t\t\t'formatValue',\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) => RangeAxis | undefined,\n\t): void {\n\t\tconst entry = this.#bindEntry(control, signal);\n\n\t\tcontrol.addEventListener(\n\t\t\t'pointerdown',\n\t\t\t(event) => {\n\t\t\t\tif (event.button !== 0 || this.isDisabled() || entry.isOpen) return;\n\n\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\tif (event.pointerType === 'touch') event.preventDefault();\n\t\t\t\tcontrol.focus();\n\t\t\t\tif (event.metaKey || event.ctrlKey) {\n\t\t\t\t\tthis.#reset();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst fromValue = this.#value;\n\t\t\t\tconst axis = grab(event);\n\t\t\t\tif (!axis) return;\n\n\t\t\t\tconst startPosition = axis.position(event);\n\t\t\t\tconst drag: RangeDrag = {\n\t\t\t\t\tdetent: this.#detentHold(control, axis.travelPx),\n\t\t\t\t\tfromValue,\n\t\t\t\t\tisRevealed: false,\n\t\t\t\t\tlastPosition: startPosition,\n\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t\tposition: axis.position,\n\t\t\t\t\trawFraction: this.fraction(this.#value),\n\t\t\t\t\trevealTimer: undefined,\n\t\t\t\t\tstartPosition,\n\t\t\t\t\ttravelPx: axis.travelPx,\n\t\t\t\t};\n\n\t\t\t\tdrag.revealTimer = setTimeout(() => {\n\t\t\t\t\tthis.#reveal(drag);\n\t\t\t\t}, revealMs);\n\t\t\t\tthis.#drag = drag;\n\t\t\t\tcontrol.setPointerCapture(event.pointerId);\n\t\t\t\tthis.toggleState('dragging', true);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tcontrol.addEventListener(\n\t\t\t'pointermove',\n\t\t\t(event) => {\n\t\t\t\tconst drag = this.#drag;\n\t\t\t\tif (event.pointerId !== drag?.pointerId) return;\n\n\t\t\t\tconst position = drag.position(event);\n\t\t\t\tconst scale = event.shiftKey ? fineScale : 1;\n\n\t\t\t\t// Per move, so pressing Shift mid-drag changes pace without a jump\n\t\t\t\tconst next = this.#move(drag, ((position - drag.lastPosition) / drag.travelPx) * scale);\n\n\t\t\t\tdrag.lastPosition = position;\n\t\t\t\tif (Math.abs(position - drag.startPosition) >= revealPx) this.#reveal(drag);\n\t\t\t\tthis.input(next);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\n\t\tconst endDrag = (event: PointerEvent): void => {\n\t\t\tif (event.pointerId === this.#drag?.pointerId) this.#endDrag();\n\t\t};\n\n\t\tcontrol.addEventListener(\n\t\t\t'pointercancel',\n\t\t\t(event) => {\n\t\t\t\tendDrag(event);\n\t\t\t\tentry.forgetPress();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\t// Other code can release capture without a `pointerup`\n\t\tcontrol.addEventListener('lostpointercapture', endDrag, { signal });\n\t\tcontrol.addEventListener(\n\t\t\t'pointerup',\n\t\t\t(event) => {\n\t\t\t\tif (event.pointerId !== this.#drag?.pointerId) return;\n\n\t\t\t\tthis.#endDrag();\n\t\t\t\tif (!entry.press(event) || this.springTarget() !== undefined) return;\n\n\t\t\t\tif (this.doublePress === 'reset') this.#reset();\n\t\t\t\telse entry.open();\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.#endDrag();\n\t\t\t\tthis.#hideForKeys();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tprotected bindScale(control: HTMLElement, scale: HTMLElement, signal: AbortSignal): void {\n\t\tthis.#scale = scale;\n\t\tthis.mirrorChildren(\n\t\t\t{\n\t\t\t\tcontrol,\n\t\t\t\tcopy: (originals) => {\n\t\t\t\t\tscale.replaceChildren(...originals.flatMap((original) => scaleMark(original)));\n\t\t\t\t\tthis.renderScale();\n\t\t\t\t},\n\t\t\t\tisCopied: (child) => child instanceof Element && child.matches('[data-sonic-value]'),\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tprotected clampRange(next: number): number {\n\t\tconst min = this.min;\n\t\tif (!this.wraps()) return clamp(next, min, this.#max());\n\n\t\tconst range = this.range();\n\t\tif (range <= 0) return min;\n\n\t\tconst offset = trimFloat((((next - min) % range) + range) % range);\n\n\t\treturn offset >= range ? min : trimFloat(min + offset);\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected fraction(value: number): number {\n\t\treturn (this.#taper() ?? linearTaper(this.min, this.#max())).position(value);\n\t}\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#value;\n\n\t\tthis.#write(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 modulationFractions(amount: number): [number, number] {\n\t\tconst value = this.fraction(this.#value);\n\t\tconst modulated = this.fraction(this.#value + amount);\n\n\t\treturn [Math.min(value, modulated), Math.max(value, modulated)];\n\t}\n\n\tprotected originFraction(): number {\n\t\treturn this.fraction(this.restValue());\n\t}\n\n\tprotected positions(): number | undefined {\n\t\tconst positions =\n\t\t\tthis.#entries?.length ?? Math.round(this.range() / this.step) + (this.wraps() ? 0 : 1);\n\n\t\tif (!this.notched || !Number.isFinite(positions) || positions < 2) return;\n\n\t\treturn positions;\n\t}\n\n\tprotected range(): number {\n\t\treturn this.#max() - this.min;\n\t}\n\n\t// Per render rather than per write, so a range with no `value` attribute submits its minimum too\n\tprotected 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.#bounds();\n\n\t\tcontrol.setAttribute('role', this.controlRole());\n\t\tcontrol.setAttribute('aria-valuemin', String(low));\n\t\tcontrol.setAttribute('aria-valuemax', String(high));\n\t\tcontrol.setAttribute('aria-valuenow', String(this.#value));\n\t\tif (orientation) control.setAttribute('aria-orientation', orientation);\n\t\twriteAttribute(control, 'aria-valuetext', this.#formatValue?.(this.#value));\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.#renderReadout();\n\t}\n\n\t// Runs on every input, while the places move only with the range\n\tprotected renderScale(): void {\n\t\tconst marks = this.#scale?.children ?? [];\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(this.fraction(this.clampRange(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\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected restValue(): number {\n\t\treturn this.origin ?? this.#bounds()[0];\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected valueAt(fraction: number): number {\n\t\treturn (this.#taper() ?? linearTaper(this.min, this.#max())).value(fraction);\n\t}\n\n\tprotected valueText(): string {\n\t\treturn this.#formatValue?.(this.#value) ?? String(this.#value);\n\t}\n\n\tprotected wraps(): boolean {\n\t\treturn false;\n\t}\n\n\t#bindEntry(control: HTMLElement, signal: AbortSignal): RangeEntry {\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) {\n\t\t\tconst anchor = `--sonic-readout-${this.#instance}`;\n\n\t\t\tthis.#readout = { bubble, text: requireChild(bubble, 'span', HTMLElement) };\n\t\t\tcontrol.style.setProperty('anchor-name', anchor);\n\t\t\tbubble.style.setProperty('position-anchor', anchor);\n\t\t}\n\n\t\tconst entry = new RangeEntry(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: RangeEntry, 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\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.#commit(next);\n\t\t\t\tthis.#revealForKeys();\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\tif (keySteps.has(event.key) || endKeys.has(event.key)) this.#springBack();\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.#hideForKeys();\n\t\t\t\tthis.#springBack();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#bounds(): [number, number] {\n\t\tconst entries = this.#entries;\n\n\t\treturn [entries?.[0] ?? this.min, entries?.at(-1) ?? this.#max()];\n\t}\n\n\t#clamp(next: number): number {\n\t\tconst entries = this.#entries;\n\t\tif (entries) return nearestEntry(entries, next);\n\n\t\tconst min = this.min;\n\t\tconst step = this.step;\n\t\tconst stepped = step > 0 ? min + Math.round((next - min) / step) * step : next;\n\n\t\t// A step like 0.01 leaves float residue\n\t\treturn this.clampRange(trimFloat(stepped));\n\t}\n\n\t#commit(next: number): void {\n\t\tif (this.input(next)) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n\n\t#detentHold(control: HTMLElement, travelPx: number): DetentHold | undefined {\n\t\tconst detent = this.detent;\n\t\tif (detent === undefined) return undefined;\n\n\t\tconst value = this.#clamp(detent);\n\t\tconst zonePx = readPxProperty(getComputedStyle(control), '--_sonic-detent-zone', detentZonePx);\n\n\t\treturn {\n\t\t\tplace: this.fraction(value),\n\t\t\tslack: value === this.#value ? 0 : undefined,\n\t\t\tvalue,\n\t\t\tzone: zonePx / travelPx,\n\t\t};\n\t}\n\n\t#end(step: number): number {\n\t\tif (!this.wraps()) return this.#bounds()[1];\n\n\t\treturn this.min + (Math.ceil(this.range() / step) - 1) * step;\n\t}\n\n\t#endDrag(): void {\n\t\tconst drag = this.#drag;\n\t\tif (!drag) return;\n\n\t\tclearTimeout(drag.revealTimer);\n\t\tthis.#drag = undefined;\n\t\tthis.toggleState('dragging', false);\n\t\tthis.#renderReadout();\n\t\tif (this.#value !== drag.fromValue) this.dispatchEvent(new Event('change', { bubbles: true }));\n\t\tthis.#springBack();\n\t}\n\n\t#hideForKeys(): void {\n\t\tclearTimeout(this.#keyRevealTimer);\n\t\tif (this.#keyRevealTimer === undefined) return;\n\n\t\tthis.#keyRevealTimer = undefined;\n\t\tthis.#renderReadout();\n\t}\n\n\t#isValueShown(): boolean {\n\t\tconst isRevealed = this.#drag?.isRevealed === true || this.#keyRevealTimer !== undefined;\n\n\t\treturn isRevealed && this.readout;\n\t}\n\n\t#keyTarget(key: string): number | undefined {\n\t\tif (key === 'Home') return this.#bounds()[0];\n\t\tconst step = this.step > 0 ? this.step : this.range() / 100;\n\n\t\tif (key === 'End') return this.#end(step);\n\t\tif (resetKeys.has(key)) return this.default;\n\n\t\tconst steps = keySteps.get(key);\n\t\tif (steps === undefined) return undefined;\n\n\t\treturn this.#stopAtDetent(this.#stepBy(steps, step));\n\t}\n\n\t#max(): number {\n\t\treturn Math.max(this.min, this.max);\n\t}\n\n\t#move(drag: RangeDrag, delta: number): number {\n\t\tconst { detent } = drag;\n\t\tconst to = drag.rawFraction + delta;\n\t\tconst next = detent ? passDetent(detent, drag.rawFraction, to) : to;\n\n\t\tif (detent && next === undefined) {\n\t\t\tdrag.rawFraction = detent.place;\n\t\t\treturn detent.value;\n\t\t}\n\n\t\tconst place = next ?? to;\n\n\t\tdrag.rawFraction = this.wraps() ? wrapUnit(place) : clampUnit(place);\n\n\t\treturn this.valueAt(drag.rawFraction);\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tif (this.isDisabled()) {\n\t\t\tcontrol.setAttribute('aria-disabled', 'true');\n\t\t\tcontrol.removeAttribute('tabindex');\n\t\t\treturn;\n\t\t}\n\n\t\tcontrol.removeAttribute('aria-disabled');\n\t\tcontrol.setAttribute('tabindex', '0');\n\t}\n\n\t#renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout || !canPopover || !this.isConnected) return;\n\n\t\tconst isEditing = this.#entry?.isOpen === true;\n\n\t\treadout.text.hidden = isEditing;\n\t\tif (!isEditing) readout.text.textContent = this.valueText();\n\t\treadout.bubble.togglePopover(isEditing || this.#isValueShown());\n\t}\n\n\t#reset(): void {\n\t\tthis.#commit(this.default ?? NaN);\n\t}\n\n\t#reveal(drag: RangeDrag): void {\n\t\tif (drag.isRevealed || this.#drag !== drag) return;\n\n\t\tdrag.isRevealed = true;\n\t\tthis.#renderReadout();\n\t}\n\n\t#revealForKeys(): void {\n\t\tclearTimeout(this.#keyRevealTimer);\n\t\tthis.#keyRevealTimer = setTimeout(() => {\n\t\t\tthis.#hideForKeys();\n\t\t}, keyRevealMs);\n\t\tthis.#renderReadout();\n\t}\n\n\t#springBack(): void {\n\t\tconst target = this.springTarget();\n\n\t\tif (target !== undefined) this.#commit(target);\n\t}\n\n\t#stepBy(steps: number, step: number): number {\n\t\tconst entries = this.#entries;\n\t\tif (entries) {\n\t\t\tconst index = clamp(entries.indexOf(this.#value) + steps, 0, entries.length - 1);\n\n\t\t\treturn entries[index] ?? this.#value;\n\t\t}\n\n\t\tconst taper = this.#taper();\n\t\tif (!taper) return this.#value + steps * step;\n\n\t\t// By travel, since steps at the wide end would take forever; at least one step, or the snap holds it in place\n\t\tconst next = this.#clamp(taper.value(taper.position(this.#value) + steps / 100));\n\n\t\treturn next === this.#value ? this.#value + Math.sign(steps) * step : next;\n\t}\n\n\t#stopAtDetent(next: number): number {\n\t\tconst detent = this.detent;\n\t\tif (detent === undefined) return next;\n\n\t\tconst value = this.#clamp(detent);\n\n\t\treturn (this.#value - value) * (next - value) < 0 ? value : next;\n\t}\n\n\t// Notches are evenly spaced, so a notched control stays linear\n\t#taper(): Taper | undefined {\n\t\tconst entries = this.#entries;\n\t\tif (entries) return listTaper(entries);\n\t\tif (this.notched || this.wraps()) return undefined;\n\n\t\tconst min = this.min;\n\t\tconst max = this.#max();\n\t\tconst log = this.taper === 'log' ? logTaper(min, max) : undefined;\n\n\t\treturn log ?? skewTaper(min, max, this.midpoint ?? NaN);\n\t}\n\n\t#write(next: number): void {\n\t\tif (!Number.isFinite(next)) return;\n\n\t\tthis.#isDirty = true;\n\n\t\tconst clamped = this.#clamp(next);\n\t\tif (clamped === this.#value) return;\n\n\t\tthis.#value = clamped;\n\t\tthis.render();\n\t}\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"range-entry.js","names":[],"sources":["../../../src/elements/range-entry.ts"],"sourcesContent":["interface Press {\n\ttime: number;\n\tx: number;\n\ty: number;\n}\n\ninterface RangeEntryOptions {\n\tcommit: (text: string) => void;\n\ttext: () => string;\n\ttoggle: (isOpen: boolean) => void;\n}\n\n// Not `dblclick`, which iOS may not deliver under `touch-action: none`\nconst doublePressMs = 500;\nconst doublePressPx = 4;\n\nfunction isDoublePress(previous: Press | undefined, next: Press): boolean {\n\tif (!previous) return false;\n\n\treturn (\n\t\tnext.time - previous.time < doublePressMs &&\n\t\tMath.hypot(next.x - previous.x, next.y - previous.y) < doublePressPx\n\t);\n}\n\nexport class RangeEntry {\n\tget isOpen(): boolean {\n\t\treturn this.#isOpen;\n\t}\n\n\treadonly #input: HTMLInputElement;\n\n\t#isOpen = false;\n\n\t#lastPress: Press | undefined;\n\n\t#openedText = '';\n\n\treadonly #options: RangeEntryOptions;\n\n\tconstructor(input: HTMLInputElement, options: RangeEntryOptions) {\n\t\tthis.#input = input;\n\t\tthis.#options = options;\n\t}\n\n\tbind(control: HTMLElement, signal: AbortSignal): void {\n\t\tconst input = this.#input;\n\n\t\tinput.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.isComposing || (event.key !== 'Enter' && event.key !== 'Escape')) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.close(event.key === 'Enter');\n\t\t\t\tcontrol.focus();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tinput.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tthis.close(true);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\n\t\t// The field's own events would reach the host's listeners as if the value had moved\n\t\tfor (const type of ['change', 'input']) {\n\t\t\tinput.addEventListener(\n\t\t\t\ttype,\n\t\t\t\t(event) => {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t}\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.close(false);\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t// Closes first, so the committed value renders with the control's role back in place\n\tclose(isCommitting: boolean): void {\n\t\tif (!this.#isOpen) return;\n\n\t\tthis.#isOpen = false;\n\t\tthis.#input.hidden = true;\n\t\tthis.#options.toggle(false);\n\t\t// A format that rounds would otherwise write its rounding back\n\t\tif (isCommitting && this.#input.value !== this.#openedText)\n\t\t\tthis.#options.commit(this.#input.value);\n\t}\n\n\tforgetPress(): void {\n\t\tthis.#lastPress = undefined;\n\t}\n\n\topen(): void {\n\t\tconst input = this.#input;\n\n\t\tthis.#isOpen = true;\n\t\tthis.#openedText = this.#options.text();\n\t\tinput.value = this.#openedText;\n\t\tinput.hidden = false;\n\t\tthis.#options.toggle(true);\n\t\tinput.focus();\n\t\tinput.select();\n\t}\n\n\tpress(event: PointerEvent): boolean {\n\t\tconst press = { time: event.timeStamp, x: event.clientX, y: event.clientY };\n\t\tconst previous = this.#lastPress;\n\n\t\tthis.#lastPress = press;\n\t\tif (!isDoublePress(previous, press)) return false;\n\n\t\tthis.#lastPress = undefined;\n\n\t\treturn true;\n\t}\n}\n"],"mappings":";AAaA,MAAM,gBAAgB;AACtB,MAAM,gBAAgB;AAEtB,SAAS,cAAc,UAA6B,MAAsB;CACzE,IAAI,CAAC,UAAU,OAAO;CAEtB,OACC,KAAK,OAAO,SAAS,OAAO,iBAC5B,KAAK,MAAM,KAAK,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,CAAC,IAAI;AAEzD;AAEA,IAAa,aAAb,MAAwB;CACvB,IAAI,SAAkB;EACrB,OAAO,KAAK;CACb;CAEA,AAAS;CAET,UAAU;CAEV;CAEA,cAAc;CAEd,AAAS;CAET,YAAY,OAAyB,SAA4B;EAChE,KAAK,SAAS;EACd,KAAK,WAAW;CACjB;CAEA,KAAK,SAAsB,QAA2B;EACrD,MAAM,QAAQ,KAAK;EAEnB,MAAM,iBACL,YACC,UAAU;GACV,IAAI,MAAM,eAAgB,MAAM,QAAQ,WAAW,MAAM,QAAQ,UAAW;GAE5E,MAAM,eAAe;GACrB,KAAK,MAAM,MAAM,QAAQ,OAAO;GAChC,QAAQ,MAAM;EACf,GACA,EAAE,OAAO,CACV;EACA,MAAM,iBACL,cACM;GACL,KAAK,MAAM,IAAI;EAChB,GACA,EAAE,OAAO,CACV;EAGA,KAAK,MAAM,QAAQ,CAAC,UAAU,OAAO,GACpC,MAAM,iBACL,OACC,UAAU;GACV,MAAM,gBAAgB;EACvB,GACA,EAAE,OAAO,CACV;EAED,OAAO,iBACN,eACM;GACL,KAAK,MAAM,KAAK;EACjB,GACA,EAAE,MAAM,KAAK,CACd;CACD;CAGA,MAAM,cAA6B;EAClC,IAAI,CAAC,KAAK,SAAS;EAEnB,KAAK,UAAU;EACf,KAAK,OAAO,SAAS;EACrB,KAAK,SAAS,OAAO,KAAK;EAE1B,IAAI,gBAAgB,KAAK,OAAO,UAAU,KAAK,aAC9C,KAAK,SAAS,OAAO,KAAK,OAAO,KAAK;CACxC;CAEA,cAAoB;EACnB,KAAK,aAAa;CACnB;CAEA,OAAa;EACZ,MAAM,QAAQ,KAAK;EAEnB,KAAK,UAAU;EACf,KAAK,cAAc,KAAK,SAAS,KAAK;EACtC,MAAM,QAAQ,KAAK;EACnB,MAAM,SAAS;EACf,KAAK,SAAS,OAAO,IAAI;EACzB,MAAM,MAAM;EACZ,MAAM,OAAO;CACd;CAEA,MAAM,OAA8B;EACnC,MAAM,QAAQ;GAAE,MAAM,MAAM;GAAW,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ;EAC1E,MAAM,WAAW,KAAK;EAEtB,KAAK,aAAa;EAClB,IAAI,CAAC,cAAc,UAAU,KAAK,GAAG,OAAO;EAE5C,KAAK,aAAa;EAElB,OAAO;CACR;AACD"}
@@ -1,18 +0,0 @@
1
- //#region src/lib/detent.ts
2
- function isAcross(from, to, place) {
3
- return from !== place && (from - place) * (to - place) <= 0;
4
- }
5
- function passDetent(hold, from, to) {
6
- if (hold.slack === void 0 && !isAcross(from, to, hold.place)) return to;
7
- const slack = (hold.slack ?? 0) + to - hold.place;
8
- if (Math.abs(slack) <= hold.zone) {
9
- hold.slack = slack;
10
- return;
11
- }
12
- hold.slack = void 0;
13
- return hold.place + slack - Math.sign(slack) * hold.zone;
14
- }
15
-
16
- //#endregion
17
- export { passDetent };
18
- //# sourceMappingURL=detent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"detent.js","names":[],"sources":["../../../src/lib/detent.ts"],"sourcesContent":["// Places run 0 to 1 along the travel; `slack` is how far past the detent the pointer has pushed, set while held\nexport interface DetentHold {\n\tplace: number;\n\tslack: number | undefined;\n\tvalue: number;\n\tzone: number;\n}\n\nfunction isAcross(from: number, to: number, place: number): boolean {\n\treturn from !== place && (from - place) * (to - place) <= 0;\n}\n\n// The next place along the travel, or `undefined` while the detent holds\nexport function passDetent(hold: DetentHold, from: number, to: number): number | undefined {\n\tif (hold.slack === undefined && !isAcross(from, to, hold.place)) return to;\n\n\t// Held, `from` is the detent's place, so the move adds to the slack\n\tconst slack = (hold.slack ?? 0) + to - hold.place;\n\n\tif (Math.abs(slack) <= hold.zone) {\n\t\thold.slack = slack;\n\t\treturn undefined;\n\t}\n\n\thold.slack = undefined;\n\n\treturn hold.place + slack - Math.sign(slack) * hold.zone;\n}\n"],"mappings":";AAQA,SAAS,SAAS,MAAc,IAAY,OAAwB;CACnE,OAAO,SAAS,UAAU,OAAO,UAAU,KAAK,UAAU;AAC3D;AAGA,SAAgB,WAAW,MAAkB,MAAc,IAAgC;CAC1F,IAAI,KAAK,UAAU,UAAa,CAAC,SAAS,MAAM,IAAI,KAAK,KAAK,GAAG,OAAO;CAGxE,MAAM,SAAS,KAAK,SAAS,KAAK,KAAK,KAAK;CAE5C,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM;EACjC,KAAK,QAAQ;EACb;CACD;CAEA,KAAK,QAAQ;CAEb,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK;AACrD"}