@xsynaptic/sonic-ui 0.3.0 → 0.4.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 (41) hide show
  1. package/dist/default/elements/dial.js +5 -3
  2. package/dist/default/elements/key.js +29 -4
  3. package/dist/default/elements/meter.js +63 -9
  4. package/dist/default/elements/number.js +1 -1
  5. package/dist/default/elements/range-element.js +134 -21
  6. package/dist/default/elements/slider.js +49 -3
  7. package/dist/default/lib/detent.js +17 -0
  8. package/dist/default/lib/math.js +16 -0
  9. package/dist/default/lib/number-list.js +14 -0
  10. package/dist/default/lib/taper.js +17 -7
  11. package/dist/dev/elements/dial.js +5 -3
  12. package/dist/dev/elements/dial.js.map +1 -1
  13. package/dist/dev/elements/key.d.ts +4 -0
  14. package/dist/dev/elements/key.js +29 -4
  15. package/dist/dev/elements/key.js.map +1 -1
  16. package/dist/dev/elements/meter.d.ts +6 -0
  17. package/dist/dev/elements/meter.js +63 -9
  18. package/dist/dev/elements/meter.js.map +1 -1
  19. package/dist/dev/elements/number.js +1 -1
  20. package/dist/dev/elements/range-element.d.ts +8 -0
  21. package/dist/dev/elements/range-element.js +134 -21
  22. package/dist/dev/elements/range-element.js.map +1 -1
  23. package/dist/dev/elements/slider.d.ts +6 -0
  24. package/dist/dev/elements/slider.js +49 -3
  25. package/dist/dev/elements/slider.js.map +1 -1
  26. package/dist/dev/lib/detent.js +18 -0
  27. package/dist/dev/lib/detent.js.map +1 -0
  28. package/dist/dev/lib/math.js +17 -0
  29. package/dist/dev/lib/math.js.map +1 -0
  30. package/dist/dev/lib/number-list.js +15 -0
  31. package/dist/dev/lib/number-list.js.map +1 -0
  32. package/dist/dev/lib/taper.js +17 -7
  33. package/dist/dev/lib/taper.js.map +1 -1
  34. package/dist/styles/dial.css +43 -3
  35. package/dist/styles/key.css +60 -15
  36. package/dist/styles/led.css +8 -1
  37. package/dist/styles/material.css +50 -1
  38. package/dist/styles/meter.css +101 -5
  39. package/dist/styles/segmented.css +2 -7
  40. package/dist/styles/slider.css +94 -32
  41. package/package.json +1 -1
@@ -9,6 +9,8 @@ export declare abstract class SonicRangeElement extends SonicFormElement {
9
9
  static readonly observedAttributes: string[];
10
10
  get default(): number | undefined;
11
11
  set default(value: number | undefined);
12
+ get detent(): number | undefined;
13
+ set detent(value: number | undefined);
12
14
  get dimmed(): boolean;
13
15
  set dimmed(isDimmed: boolean);
14
16
  get doublePress(): 'reset' | 'type';
@@ -35,9 +37,12 @@ export declare abstract class SonicRangeElement extends SonicFormElement {
35
37
  set taper(curve: 'linear' | 'log' | undefined);
36
38
  get value(): number;
37
39
  set value(next: number);
40
+ get values(): Array<number> | undefined;
41
+ set values(entries: Array<number> | undefined);
38
42
  attributeChangedCallback(name: string): void;
39
43
  connectedCallback(): void;
40
44
  protected bindGestures(control: HTMLElement, signal: AbortSignal, grab: (event: PointerEvent) => RangeAxis | undefined): void;
45
+ protected bindScale(control: HTMLElement, scale: HTMLElement, signal: AbortSignal): void;
41
46
  protected clampRange(next: number): number;
42
47
  protected controlRole(): 'slider' | 'spinbutton';
43
48
  protected fraction(value: number): number;
@@ -47,7 +52,10 @@ export declare abstract class SonicRangeElement extends SonicFormElement {
47
52
  protected positions(): number | undefined;
48
53
  protected range(): number;
49
54
  protected renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void;
55
+ protected renderScale(): void;
50
56
  protected restoreState(state: string): void;
57
+ protected restValue(): number;
58
+ protected springTarget(): number | undefined;
51
59
  protected valueAt(fraction: number): number;
52
60
  protected valueText(): string;
53
61
  protected wraps(): boolean;
@@ -2,9 +2,15 @@ import { requireChild } from "../lib/render.js";
2
2
  import { writeAttribute } from "../lib/write-attribute.js";
3
3
  import { SonicFormElement } from "./form-element.js";
4
4
  import { RangeEntry } from "./range-entry.js";
5
- import { clampUnit, linearTaper, logTaper, skewTaper, wrapUnit } from "../lib/taper.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";
6
11
 
7
12
  //#region src/elements/range-element.ts
13
+ const detentZonePx = 8;
8
14
  const fineScale = .1;
9
15
  const keyRevealMs = 1e3;
10
16
  const pageSteps = 10;
@@ -13,6 +19,7 @@ const revealPx = 4;
13
19
  const canPopover = "togglePopover" in HTMLElement.prototype;
14
20
  let instanceCount = 0;
15
21
  const resetKeys = /* @__PURE__ */ new Set(["Backspace", "Delete"]);
22
+ const endKeys = /* @__PURE__ */ new Set(["End", "Home"]);
16
23
  const keySteps = /* @__PURE__ */ new Map([
17
24
  ["ArrowDown", -1],
18
25
  ["ArrowLeft", -1],
@@ -31,9 +38,22 @@ const roleAttributes = [
31
38
  "role",
32
39
  "tabindex"
33
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
+ }
34
53
  var SonicRangeElement = class extends SonicFormElement {
35
54
  static observedAttributes = [
36
55
  ...SonicFormElement.observedAttributes,
56
+ "detent",
37
57
  "max",
38
58
  "midpoint",
39
59
  "min",
@@ -42,7 +62,8 @@ var SonicRangeElement = class extends SonicFormElement {
42
62
  "readout",
43
63
  "step",
44
64
  "taper",
45
- "value"
65
+ "value",
66
+ "values"
46
67
  ];
47
68
  get default() {
48
69
  return this.optionalNumberAttribute("default");
@@ -50,6 +71,12 @@ var SonicRangeElement = class extends SonicFormElement {
50
71
  set default(value) {
51
72
  this.reflect("default", value);
52
73
  }
74
+ get detent() {
75
+ return this.optionalNumberAttribute("detent");
76
+ }
77
+ set detent(value) {
78
+ this.reflect("detent", value);
79
+ }
53
80
  get dimmed() {
54
81
  return this.hasAttribute("dimmed");
55
82
  }
@@ -130,7 +157,14 @@ var SonicRangeElement = class extends SonicFormElement {
130
157
  if (this.#drag) return;
131
158
  this.#write(next);
132
159
  }
160
+ get values() {
161
+ return parseNumberList(this.getAttribute("values"));
162
+ }
163
+ set values(entries) {
164
+ this.reflect("values", entries?.join(" "));
165
+ }
133
166
  #drag;
167
+ #entries;
134
168
  #entry;
135
169
  #formatValue;
136
170
  #instance = String(instanceCount += 1);
@@ -138,8 +172,10 @@ var SonicRangeElement = class extends SonicFormElement {
138
172
  #keyRevealTimer;
139
173
  #parseValue;
140
174
  #readout;
175
+ #scale;
141
176
  #value = 0;
142
177
  attributeChangedCallback(name) {
178
+ this.#entries = parseNumberList(this.getAttribute("values"));
143
179
  if (name === "value") {
144
180
  if (this.#drag) return;
145
181
  this.#isDirty = false;
@@ -152,7 +188,7 @@ var SonicRangeElement = class extends SonicFormElement {
152
188
  this.render();
153
189
  }
154
190
  connectedCallback() {
155
- this.upgradeProperties("default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "step", "taper", "formatValue", "parseValue", "value");
191
+ this.upgradeProperties("default", "dimmed", "doublePress", "max", "midpoint", "min", "notched", "origin", "readout", "step", "taper", "values", "detent", "formatValue", "parseValue", "value");
156
192
  super.connectedCallback();
157
193
  }
158
194
  bindGestures(control, signal, grab) {
@@ -170,6 +206,7 @@ var SonicRangeElement = class extends SonicFormElement {
170
206
  if (!axis) return;
171
207
  const startPosition = axis.position(event);
172
208
  const drag = {
209
+ detent: this.#detentHold(control, axis.travelPx),
173
210
  fromValue,
174
211
  isRevealed: false,
175
212
  lastPosition: startPosition,
@@ -192,11 +229,10 @@ var SonicRangeElement = class extends SonicFormElement {
192
229
  if (event.pointerId !== drag?.pointerId) return;
193
230
  const position = drag.position(event);
194
231
  const scale = event.shiftKey ? fineScale : 1;
195
- const fraction = drag.rawFraction + (position - drag.lastPosition) / drag.travelPx * scale;
196
- drag.rawFraction = this.wraps() ? wrapUnit(fraction) : clampUnit(fraction);
232
+ const next = this.#move(drag, (position - drag.lastPosition) / drag.travelPx * scale);
197
233
  drag.lastPosition = position;
198
234
  if (Math.abs(position - drag.startPosition) >= revealPx) this.#reveal(drag);
199
- this.input(this.valueAt(drag.rawFraction));
235
+ this.input(next);
200
236
  }, { signal });
201
237
  const endDrag = (event) => {
202
238
  if (event.pointerId === this.#drag?.pointerId) this.#endDrag();
@@ -209,7 +245,7 @@ var SonicRangeElement = class extends SonicFormElement {
209
245
  control.addEventListener("pointerup", (event) => {
210
246
  if (event.pointerId !== this.#drag?.pointerId) return;
211
247
  this.#endDrag();
212
- if (!entry.press(event)) return;
248
+ if (!entry.press(event) || this.springTarget() !== void 0) return;
213
249
  if (this.doublePress === "reset") this.#reset();
214
250
  else entry.open();
215
251
  }, { signal });
@@ -219,13 +255,24 @@ var SonicRangeElement = class extends SonicFormElement {
219
255
  this.#hideForKeys();
220
256
  }, { once: true });
221
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
+ }
222
269
  clampRange(next) {
223
270
  const min = this.min;
224
- if (!this.wraps()) return Math.min(this.#max(), Math.max(min, next));
271
+ if (!this.wraps()) return clamp(next, min, this.#max());
225
272
  const range = this.range();
226
273
  if (range <= 0) return min;
227
- const offset = Number((((next - min) % range + range) % range).toPrecision(12));
228
- return offset >= range ? min : Number((min + offset).toPrecision(12));
274
+ const offset = trimFloat(((next - min) % range + range) % range);
275
+ return offset >= range ? min : trimFloat(min + offset);
229
276
  }
230
277
  controlRole() {
231
278
  return "slider";
@@ -249,10 +296,10 @@ var SonicRangeElement = class extends SonicFormElement {
249
296
  return [Math.min(value, modulated), Math.max(value, modulated)];
250
297
  }
251
298
  originFraction() {
252
- return this.fraction(this.origin ?? this.min);
299
+ return this.fraction(this.restValue());
253
300
  }
254
301
  positions() {
255
- const positions = Math.round(this.range() / this.step) + (this.wraps() ? 0 : 1);
302
+ const positions = this.#entries?.length ?? Math.round(this.range() / this.step) + (this.wraps() ? 0 : 1);
256
303
  if (!this.notched || !Number.isFinite(positions) || positions < 2) return;
257
304
  return positions;
258
305
  }
@@ -267,9 +314,10 @@ var SonicRangeElement = class extends SonicFormElement {
267
314
  this.#renderReadout();
268
315
  return;
269
316
  }
317
+ const [low, high] = this.#bounds();
270
318
  control.setAttribute("role", this.controlRole());
271
- control.setAttribute("aria-valuemin", String(this.min));
272
- control.setAttribute("aria-valuemax", String(this.#max()));
319
+ control.setAttribute("aria-valuemin", String(low));
320
+ control.setAttribute("aria-valuemax", String(high));
273
321
  control.setAttribute("aria-valuenow", String(this.#value));
274
322
  if (orientation) control.setAttribute("aria-orientation", orientation);
275
323
  writeAttribute(control, "aria-valuetext", this.#formatValue?.(this.#value));
@@ -277,9 +325,21 @@ var SonicRangeElement = class extends SonicFormElement {
277
325
  this.#renderDisabled(control);
278
326
  this.#renderReadout();
279
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
+ }
280
336
  restoreState(state) {
281
337
  this.value = Number(state);
282
338
  }
339
+ restValue() {
340
+ return this.origin ?? this.#bounds()[0];
341
+ }
342
+ springTarget() {}
283
343
  valueAt(fraction) {
284
344
  return (this.#taper() ?? linearTaper(this.min, this.#max())).value(fraction);
285
345
  }
@@ -321,6 +381,7 @@ var SonicRangeElement = class extends SonicFormElement {
321
381
  control.addEventListener("keydown", (event) => {
322
382
  if (this.isDisabled() || event.defaultPrevented || event.target !== control) return;
323
383
  if (event.key === "Enter") {
384
+ if (this.springTarget() !== void 0) return;
324
385
  event.preventDefault();
325
386
  entry.open();
326
387
  return;
@@ -331,21 +392,43 @@ var SonicRangeElement = class extends SonicFormElement {
331
392
  this.#commit(next);
332
393
  this.#revealForKeys();
333
394
  }, { signal });
395
+ control.addEventListener("keyup", (event) => {
396
+ if (keySteps.has(event.key) || endKeys.has(event.key)) this.#springBack();
397
+ }, { signal });
334
398
  control.addEventListener("blur", () => {
335
399
  this.#hideForKeys();
400
+ this.#springBack();
336
401
  }, { signal });
337
402
  }
403
+ #bounds() {
404
+ const entries = this.#entries;
405
+ return [entries?.[0] ?? this.min, entries?.at(-1) ?? this.#max()];
406
+ }
338
407
  #clamp(next) {
408
+ const entries = this.#entries;
409
+ if (entries) return nearestEntry(entries, next);
339
410
  const min = this.min;
340
411
  const step = this.step;
341
412
  const stepped = step > 0 ? min + Math.round((next - min) / step) * step : next;
342
- return this.clampRange(Number(stepped.toPrecision(12)));
413
+ return this.clampRange(trimFloat(stepped));
343
414
  }
344
415
  #commit(next) {
345
416
  if (this.input(next)) this.dispatchEvent(new Event("change", { bubbles: true }));
346
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
+ }
347
430
  #end(step) {
348
- if (!this.wraps()) return this.#max();
431
+ if (!this.wraps()) return this.#bounds()[1];
349
432
  return this.min + (Math.ceil(this.range() / step) - 1) * step;
350
433
  }
351
434
  #endDrag() {
@@ -356,6 +439,7 @@ var SonicRangeElement = class extends SonicFormElement {
356
439
  this.toggleState("dragging", false);
357
440
  this.#renderReadout();
358
441
  if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
442
+ this.#springBack();
359
443
  }
360
444
  #hideForKeys() {
361
445
  clearTimeout(this.#keyRevealTimer);
@@ -367,20 +451,29 @@ var SonicRangeElement = class extends SonicFormElement {
367
451
  return (this.#drag?.isRevealed === true || this.#keyRevealTimer !== void 0) && this.readout;
368
452
  }
369
453
  #keyTarget(key) {
370
- if (key === "Home") return this.min;
454
+ if (key === "Home") return this.#bounds()[0];
371
455
  const step = this.step > 0 ? this.step : this.range() / 100;
372
456
  if (key === "End") return this.#end(step);
373
457
  if (resetKeys.has(key)) return this.default;
374
458
  const steps = keySteps.get(key);
375
459
  if (steps === void 0) return void 0;
376
- const taper = this.#taper();
377
- if (!taper) return this.#value + steps * step;
378
- const next = this.#clamp(taper.value(taper.position(this.#value) + steps / 100));
379
- return next === this.#value ? this.#value + Math.sign(steps) * step : next;
460
+ return this.#stopAtDetent(this.#stepBy(steps, step));
380
461
  }
381
462
  #max() {
382
463
  return Math.max(this.min, this.max);
383
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
+ }
384
477
  #renderDisabled(control) {
385
478
  if (this.isDisabled()) {
386
479
  control.setAttribute("aria-disabled", "true");
@@ -413,7 +506,27 @@ var SonicRangeElement = class extends SonicFormElement {
413
506
  }, keyRevealMs);
414
507
  this.#renderReadout();
415
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
+ }
416
527
  #taper() {
528
+ const entries = this.#entries;
529
+ if (entries) return listTaper(entries);
417
530
  if (this.notched || this.wraps()) return void 0;
418
531
  const min = this.min;
419
532
  const max = this.#max();
@@ -1 +1 @@
1
- {"version":3,"file":"range-element.js","names":[],"sources":["../../../src/elements/range-element.ts"],"sourcesContent":["import type { Taper } from '#lib/taper.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { RangeEntry } from '#elements/range-entry.ts';\nimport { requireChild } from '#lib/render.ts';\nimport { clampUnit, linearTaper, logTaper, skewTaper, wrapUnit } 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\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 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 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\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'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];\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 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\t#drag: RangeDrag | 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#value = 0;\n\n\tattributeChangedCallback(name: string): void {\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'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\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 fraction =\n\t\t\t\t\tdrag.rawFraction + ((position - drag.lastPosition) / drag.travelPx) * scale;\n\n\t\t\t\tdrag.rawFraction = this.wraps() ? wrapUnit(fraction) : clampUnit(fraction);\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(this.valueAt(drag.rawFraction));\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)) 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 clampRange(next: number): number {\n\t\tconst min = this.min;\n\t\tif (!this.wraps()) return Math.min(this.#max(), Math.max(min, next));\n\n\t\tconst range = this.range();\n\t\tif (range <= 0) return min;\n\n\t\tconst offset = Number(((((next - min) % range) + range) % range).toPrecision(12));\n\n\t\treturn offset >= range ? min : Number((min + offset).toPrecision(12));\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.origin ?? this.min);\n\t}\n\n\tprotected positions(): number | undefined {\n\t\tconst positions = 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\tcontrol.setAttribute('role', this.controlRole());\n\t\tcontrol.setAttribute('aria-valuemin', String(this.min));\n\t\tcontrol.setAttribute('aria-valuemax', String(this.#max()));\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\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\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\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'blur',\n\t\t\t() => {\n\t\t\t\tthis.#hideForKeys();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#clamp(next: number): number {\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(Number(stepped.toPrecision(12)));\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#end(step: number): number {\n\t\tif (!this.wraps()) return this.#max();\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}\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.min;\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\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#max(): number {\n\t\treturn Math.max(this.min, this.max);\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// Notches are evenly spaced, so a notched control stays linear\n\t#taper(): Taper | undefined {\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
+ {"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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"}
@@ -5,19 +5,25 @@ declare global {
5
5
  'sonic-slider': SonicSlider;
6
6
  }
7
7
  }
8
+ export type BufferedRanges = Iterable<readonly [number, number]> | TimeRanges;
8
9
  export declare class SonicSlider extends SonicRangeElement {
9
10
  #private;
10
11
  static readonly observedAttributes: string[];
12
+ get buffered(): Array<[number, number]>;
13
+ set buffered(ranges: BufferedRanges | undefined);
11
14
  get groovePress(): 'jump' | 'none';
12
15
  set groovePress(gesture: 'jump' | 'none' | undefined);
13
16
  get modulation(): number;
14
17
  set modulation(amount: number | undefined);
15
18
  get orientation(): 'horizontal' | 'vertical';
16
19
  set orientation(direction: 'horizontal' | 'vertical' | undefined);
20
+ get spring(): boolean;
21
+ set spring(isSpring: boolean);
17
22
  connectedCallback(): void;
18
23
  protected connect(signal: AbortSignal): void;
19
24
  protected focusTarget(): HTMLElement;
20
25
  protected render(): void;
26
+ protected springTarget(): number | undefined;
21
27
  }
22
28
  //#endregion
23
29
  //# sourceMappingURL=slider.d.ts.map
@@ -2,8 +2,18 @@ import { requireChild, template } from "../lib/render.js";
2
2
  import { SonicRangeElement } from "./range-element.js";
3
3
 
4
4
  //#region src/elements/slider.ts
5
+ function readRanges(ranges) {
6
+ if ("start" in ranges) return Array.from({ length: ranges.length }, (_entry, index) => [ranges.start(index), ranges.end(index)]);
7
+ return [...ranges].map(([start, end]) => [start, end]);
8
+ }
9
+ function grooveStop(fraction) {
10
+ if (fraction <= 0) return "0%";
11
+ if (fraction >= 1) return "100%";
12
+ return `calc(${String(fraction)} * var(--_sonic-slider-travel) + var(--_sonic-slider-groove) / 2)`;
13
+ }
5
14
  const renderSlider = template(`
6
15
  <div class="sonic-slider" role="slider" tabindex="0">
16
+ <div class="sonic-slider-scale" aria-hidden="true"></div>
7
17
  <div class="sonic-slider-marks"></div>
8
18
  <div class="sonic-slider-groove"></div>
9
19
  <div class="sonic-slider-modulation"></div>
@@ -25,8 +35,16 @@ var SonicSlider = class extends SonicRangeElement {
25
35
  static observedAttributes = [
26
36
  ...SonicRangeElement.observedAttributes,
27
37
  "modulation",
28
- "orientation"
38
+ "orientation",
39
+ "spring"
29
40
  ];
41
+ get buffered() {
42
+ return this.#buffered.map(([start, end]) => [start, end]);
43
+ }
44
+ set buffered(ranges) {
45
+ this.#buffered = ranges ? readRanges(ranges).toSorted((first, second) => first[0] - second[0]) : [];
46
+ this.render();
47
+ }
30
48
  get groovePress() {
31
49
  return this.getAttribute("groove-press") === "none" ? "none" : "jump";
32
50
  }
@@ -45,15 +63,22 @@ var SonicSlider = class extends SonicRangeElement {
45
63
  set orientation(direction) {
46
64
  this.reflect("orientation", direction);
47
65
  }
66
+ get spring() {
67
+ return this.hasAttribute("spring");
68
+ }
69
+ set spring(isSpring) {
70
+ this.reflect("spring", isSpring);
71
+ }
72
+ #buffered = [];
48
73
  #slider = renderSlider();
49
74
  connectedCallback() {
50
- this.upgradeProperties("groovePress", "modulation", "orientation");
75
+ this.upgradeProperties("buffered", "groovePress", "modulation", "orientation", "spring");
51
76
  super.connectedCallback();
52
77
  }
53
78
  connect(signal) {
54
79
  const slider = this.#slider;
55
80
  const cap = requireChild(slider, ".sonic-slider-cap", HTMLDivElement);
56
- this.appendOnce(slider);
81
+ this.bindScale(slider, requireChild(slider, ".sonic-slider-scale", HTMLDivElement), signal);
57
82
  this.render();
58
83
  this.checkStyles(slider, "slider.css");
59
84
  this.bindGestures(slider, signal, (event) => {
@@ -77,8 +102,13 @@ var SonicSlider = class extends SonicRangeElement {
77
102
  slider.style.setProperty("--_sonic-slider-modulation-to", String(modulationTo));
78
103
  if (positions === void 0) slider.style.removeProperty("--_sonic-slider-positions");
79
104
  else slider.style.setProperty("--_sonic-slider-positions", String(positions));
105
+ this.#renderBuffered(slider);
106
+ this.renderScale();
80
107
  this.renderAria(slider, this.orientation);
81
108
  }
109
+ springTarget() {
110
+ return this.spring ? this.restValue() : void 0;
111
+ }
82
112
  #axis(slider, cap) {
83
113
  const track = slider.getBoundingClientRect();
84
114
  const capBox = cap.getBoundingClientRect();
@@ -93,6 +123,22 @@ var SonicSlider = class extends SonicRangeElement {
93
123
  travelPx: Math.max(1, track.width - capBox.width)
94
124
  };
95
125
  }
126
+ #renderBuffered(slider) {
127
+ if (this.#buffered.length === 0) {
128
+ slider.style.removeProperty("--_sonic-slider-buffered-ranges");
129
+ return;
130
+ }
131
+ const stops = this.#buffered.flatMap(([start, end]) => {
132
+ const from = grooveStop(this.fraction(Math.min(start, end)));
133
+ const to = grooveStop(this.fraction(Math.max(start, end)));
134
+ return [
135
+ `transparent ${from}`,
136
+ `var(--_sonic-slider-buffered) ${from} ${to}`,
137
+ `transparent ${to}`
138
+ ];
139
+ });
140
+ slider.style.setProperty("--_sonic-slider-buffered-ranges", `linear-gradient(var(--_sonic-slider-toward), ${stops.join(", ")})`);
141
+ }
96
142
  };
97
143
 
98
144
  //#endregion