@xsynaptic/sonic-ui 0.8.0 → 0.9.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 (52) hide show
  1. package/README.md +0 -2
  2. package/dist/default/elements/dial.js +12 -3
  3. package/dist/default/elements/envelope.js +2 -2
  4. package/dist/default/elements/modulation.js +45 -0
  5. package/dist/default/elements/readout-claim.js +8 -3
  6. package/dist/default/elements/slider.js +15 -17
  7. package/dist/default/elements/value-element.js +89 -330
  8. package/dist/default/elements/value-gestures.js +301 -0
  9. package/dist/default/elements/waveform.js +5 -2
  10. package/dist/default/elements/wavestrip.js +5 -15
  11. package/dist/default/elements/xy.js +9 -20
  12. package/dist/default/lib/asked-value.js +21 -0
  13. package/dist/default/lib/canvas-surface.js +3 -0
  14. package/dist/default/lib/marker-rider.js +6 -3
  15. package/dist/default/lib/read-ms-property.js +10 -0
  16. package/dist/dev/elements/dial.js +12 -3
  17. package/dist/dev/elements/dial.js.map +1 -1
  18. package/dist/dev/elements/envelope.js +2 -2
  19. package/dist/dev/elements/envelope.js.map +1 -1
  20. package/dist/dev/elements/modulation.js +46 -0
  21. package/dist/dev/elements/modulation.js.map +1 -0
  22. package/dist/dev/elements/readout-claim.js +8 -3
  23. package/dist/dev/elements/readout-claim.js.map +1 -1
  24. package/dist/dev/elements/slider.d.ts +0 -1
  25. package/dist/dev/elements/slider.js +15 -17
  26. package/dist/dev/elements/slider.js.map +1 -1
  27. package/dist/dev/elements/value-element.d.ts +8 -13
  28. package/dist/dev/elements/value-element.js +89 -330
  29. package/dist/dev/elements/value-element.js.map +1 -1
  30. package/dist/dev/elements/value-gestures.d.ts +10 -0
  31. package/dist/dev/elements/value-gestures.js +302 -0
  32. package/dist/dev/elements/value-gestures.js.map +1 -0
  33. package/dist/dev/elements/waveform.js +5 -2
  34. package/dist/dev/elements/waveform.js.map +1 -1
  35. package/dist/dev/elements/wavestrip.d.ts +0 -1
  36. package/dist/dev/elements/wavestrip.js +5 -15
  37. package/dist/dev/elements/wavestrip.js.map +1 -1
  38. package/dist/dev/elements/xy.js +9 -20
  39. package/dist/dev/elements/xy.js.map +1 -1
  40. package/dist/dev/lib/asked-value.js +22 -0
  41. package/dist/dev/lib/asked-value.js.map +1 -0
  42. package/dist/dev/lib/canvas-surface.d.ts +1 -0
  43. package/dist/dev/lib/canvas-surface.js +3 -0
  44. package/dist/dev/lib/canvas-surface.js.map +1 -1
  45. package/dist/dev/lib/marker-rider.js +6 -3
  46. package/dist/dev/lib/marker-rider.js.map +1 -1
  47. package/dist/dev/lib/read-ms-property.js +11 -0
  48. package/dist/dev/lib/read-ms-property.js.map +1 -0
  49. package/dist/styles/material.css +18 -0
  50. package/dist/styles/waveform.css +10 -0
  51. package/dist/styles/wavestrip.css +4 -1
  52. package/package.json +1 -1
@@ -1,20 +1,15 @@
1
1
  import { clamp, toNumber, trimFloat } from "../lib/math.js";
2
2
  import { writeAttribute } from "../lib/write-attribute.js";
3
3
  import { SonicFormElement } from "./form-element.js";
4
- import { requireChild } from "../lib/render.js";
5
- import { bindDrag } from "../lib/pointer-drag.js";
6
- import { ReadoutClaim } from "./readout-claim.js";
7
4
  import { Readout } from "./readout.js";
8
- import { ValueEntry } from "./value-entry.js";
9
- import { dragThresholdPx, startDrag, stepDrag } from "../lib/drag-step.js";
10
- import { focusByPointer } from "../lib/focus-by-pointer.js";
11
- import { isMenuPress, isResetPress } from "../lib/modifier-press.js";
12
- import { parseNumberList } from "../lib/number-list.js";
13
5
  import { readPxProperty } from "../lib/read-px-property.js";
14
- import { resetKeys, valueMapping } from "../lib/value-mapping.js";
6
+ import { parseNumberList } from "../lib/number-list.js";
7
+ import { valueMapping } from "../lib/value-mapping.js";
8
+ import { ValueGestures } from "./value-gestures.js";
9
+ import { moveTo, resnap, setAsked } from "../lib/asked-value.js";
10
+ import { bindHoverPreview } from "../lib/hover-preview.js";
15
11
 
16
12
  //#region src/elements/value-element.ts
17
- const detentZonePx = 8;
18
13
  const fallbackTravelPx = 160;
19
14
  let instanceCount = 0;
20
15
  const proportionAttributes = /* @__PURE__ */ new Set([
@@ -68,7 +63,7 @@ var SonicValueElement = class extends SonicFormElement {
68
63
  element.#limit = bounds;
69
64
  },
70
65
  mapping: () => element.mapping(),
71
- value: () => element.#value,
66
+ value: () => element.#cell.value,
72
67
  watch: (listener) => {
73
68
  element.#watchers.add(listener);
74
69
  return () => {
@@ -96,7 +91,8 @@ var SonicValueElement = class extends SonicFormElement {
96
91
  this.reflect("dimmed", isDimmed);
97
92
  }
98
93
  get doublePress() {
99
- return this.getAttribute("double-press") === "reset" ? "reset" : "entry";
94
+ const gesture = this.getAttribute("double-press");
95
+ return gesture === "none" || gesture === "reset" ? gesture : "entry";
100
96
  }
101
97
  set doublePress(gesture) {
102
98
  this.reflect("double-press", gesture);
@@ -158,7 +154,7 @@ var SonicValueElement = class extends SonicFormElement {
158
154
  this.#parseValue = parse;
159
155
  }
160
156
  get pointerType() {
161
- return this.#dragging()?.pointerType;
157
+ return this.#gestures?.pointerType();
162
158
  }
163
159
  get positions() {
164
160
  return parseNumberList(this.getAttribute("positions"));
@@ -191,7 +187,7 @@ var SonicValueElement = class extends SonicFormElement {
191
187
  this.reflect("taper", curve);
192
188
  }
193
189
  get value() {
194
- return this.#value;
190
+ return this.#cell.value;
195
191
  }
196
192
  set value(next) {
197
193
  if (next === void 0 || next === null) {
@@ -203,33 +199,27 @@ var SonicValueElement = class extends SonicFormElement {
203
199
  this.heldWrite(value);
204
200
  return;
205
201
  }
206
- this.#write(value);
207
- if (Number.isFinite(value)) this.#asked = value;
202
+ if (setAsked(this.#cell, this.mapping(), value)) this.render();
208
203
  }
209
204
  get valueText() {
210
- return this.#textFor(this.#value);
205
+ return this.#textFor(this.#cell.value);
211
206
  }
212
- #asked;
213
- #claim = new ReadoutClaim(() => {
214
- this.#renderHold();
215
- });
216
- #entry;
207
+ #cell = {
208
+ asked: void 0,
209
+ value: 0
210
+ };
217
211
  #formatSpokenValue;
218
212
  #formatValue;
213
+ #gestures;
219
214
  #heldAt;
215
+ #hover;
220
216
  #instance = String(instanceCount += 1);
221
- #isModulated = false;
222
- #isRevealed = false;
223
- #keyScrub;
224
217
  #land;
225
218
  #limit;
226
219
  #mapping;
227
- #modulationValue;
228
220
  #parseValue;
229
- #pointerDrag;
230
221
  #positions;
231
222
  #readout;
232
- #value = 0;
233
223
  #watchers = /* @__PURE__ */ new Set();
234
224
  attributeChangedCallback(name) {
235
225
  this.#mapping = void 0;
@@ -239,10 +229,10 @@ var SonicValueElement = class extends SonicFormElement {
239
229
  this.heldWrite(this.numberAttribute("value", this.min));
240
230
  return;
241
231
  }
242
- this.#asked = void 0;
232
+ this.#cell.asked = void 0;
243
233
  }
244
- if (name === "disabled" && this.isDisabled()) this.#endHolds();
245
- this.#value = this.mapping().snap(this.#asked ?? this.numberAttribute("value", this.min));
234
+ if (name === "disabled" && this.isDisabled()) this.#gestures?.end();
235
+ resnap(this.#cell, this.mapping(), this.numberAttribute("value", this.min));
246
236
  if (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();
247
237
  this.render();
248
238
  }
@@ -251,93 +241,84 @@ var SonicValueElement = class extends SonicFormElement {
251
241
  super.connectedCallback();
252
242
  }
253
243
  bindGestures(control, signal, grab) {
254
- const entry = this.#bindEntry(control, signal);
255
- this.#pointerDrag = bindDrag(control, {
256
- cancel: (drag) => {
257
- if (drag.isKeptOnCancel !== true) this.input(drag.fromValue);
244
+ const bubble = control.querySelector("[popover]");
245
+ if (bubble) this.#readout = {
246
+ anchor: control,
247
+ bubble: new Readout(bubble)
248
+ };
249
+ this.#gestures = new ValueGestures({
250
+ default: () => this.default,
251
+ detent: () => this.detent,
252
+ dispatch: (type) => {
253
+ this.dispatchEvent(new Event(type, { bubbles: true }));
258
254
  },
259
- grab: (event) => {
260
- if (isMenuPress(event) || this.isDisabled() || entry.isOpen) return;
261
- this.toggleState("springing", false);
262
- if (event.pointerType === "touch") event.preventDefault();
263
- focusByPointer(control);
264
- if (isResetPress(event)) {
265
- this.#reset();
266
- return;
267
- }
268
- const fromValue = this.#value;
269
- const axis = grab(event);
270
- if (!axis) return;
271
- const drag = {
272
- ...axis,
273
- fromValue,
274
- isOutside: false,
275
- isRevealed: false,
276
- pointerType: event.pointerType,
277
- revealTimer: void 0,
278
- state: this.#startDrag(control, axis, event)
279
- };
280
- drag.revealTimer = setTimeout(() => {
281
- this.#reveal(drag);
282
- }, 250);
283
- return drag;
255
+ doublePress: () => this.doublePress,
256
+ entryId: `sonic-entry-${this.#instance}`,
257
+ entryText: () => this.#parseValue ? this.valueText : String(this.#cell.value),
258
+ forwardNaming: (target, isNamed) => {
259
+ this.forwardNaming(target, isNamed);
284
260
  },
285
- lift: (drag, event) => {
286
- const tap = drag.state.isEngaged ? void 0 : this.tapTarget();
287
- if (tap !== void 0) {
288
- entry.forgetPress();
289
- this.#commit(tap);
290
- return;
291
- }
292
- if (!entry.press(event) || this.springTarget() !== void 0) return;
293
- if (this.doublePress === "reset") this.#reset();
294
- else entry.open();
261
+ holdChanged: () => {
262
+ this.#renderHold();
295
263
  },
296
- move: (drag, event) => {
297
- this.#dragTo(drag, event);
264
+ input: (next) => this.input(next),
265
+ isDisabled: () => this.isDisabled(),
266
+ keyStep: () => this.keyStep,
267
+ land: (target, direction) => this.#land?.(target, direction) ?? target,
268
+ limit: () => this.#limit,
269
+ mapping: () => this.mapping(),
270
+ parse: (text) => (this.#parseValue ?? Number.parseFloat)(text),
271
+ render: () => {
272
+ this.render();
298
273
  },
299
- release: (drag) => {
300
- this.#releaseDrag(drag);
274
+ scrubsKeyRepeat: () => this.scrubsKeyRepeat(),
275
+ springTarget: () => this.springTarget(),
276
+ tapTarget: () => this.tapTarget(),
277
+ toggleState: (state, isOn) => {
278
+ this.toggleState(state, isOn);
301
279
  },
302
- toggle: (isDragging) => {
303
- this.toggleState("dragging", isDragging);
304
- }
280
+ value: () => this.#cell.value
281
+ }, control);
282
+ this.#gestures.bind(signal, grab);
283
+ }
284
+ bindHover(control, signal, { canShow, place, valueAt }) {
285
+ this.#hover = bindHoverPreview(control, {
286
+ canShow,
287
+ dismiss: () => {
288
+ this.render();
289
+ },
290
+ isTaken: () => this.#isEditing() || this.isRevealed(),
291
+ show: () => {
292
+ this.renderReadout();
293
+ place();
294
+ },
295
+ valueAt
305
296
  }, signal);
306
- control.addEventListener("pointercancel", () => {
307
- entry.forgetPress();
308
- }, { signal });
309
- this.#bindKeys(control, entry, signal);
310
- signal.addEventListener("abort", () => {
311
- this.#endKeyScrub();
312
- this.#concealKeyReveal();
313
- }, { once: true });
314
297
  }
315
298
  controlOrientation() {}
316
299
  controlRole() {
317
300
  return "slider";
318
301
  }
319
302
  heldFrom() {
320
- return this.#dragging()?.fromValue ?? this.#keyScrub?.fromValue;
303
+ return this.#gestures?.heldFrom();
321
304
  }
322
305
  heldWrite(next) {
323
306
  this.#heldAt = next;
324
307
  }
325
308
  holdChanged() {}
326
309
  input(next) {
327
- const previous = this.#value;
328
- this.#write(this.#limit ? clamp(next, ...this.#limit) : next);
329
- if (this.#value === previous) return false;
310
+ const previous = this.#cell.value;
311
+ const target = this.#limit ? clamp(next, ...this.#limit) : next;
312
+ if (moveTo(this.#cell, this.mapping(), target)) this.render();
313
+ if (this.#cell.value === previous) return false;
330
314
  this.dispatchEvent(new Event("input", {
331
315
  bubbles: true,
332
316
  composed: true
333
317
  }));
334
318
  return true;
335
319
  }
336
- isEditing() {
337
- return this.#entry?.isOpen === true;
338
- }
339
320
  isRevealed() {
340
- return this.#claim.isRevealed;
321
+ return this.#gestures?.isRevealed() === true;
341
322
  }
342
323
  isWrapping() {
343
324
  return false;
@@ -363,15 +344,11 @@ var SonicValueElement = class extends SonicFormElement {
363
344
  }
364
345
  playback() {
365
346
  const from = this.heldFrom();
366
- return from === void 0 ? this.#value : this.#heldAt ?? from;
347
+ return from === void 0 ? this.#cell.value : this.#heldAt ?? from;
367
348
  }
368
- previewValue() {}
369
349
  proportionsChanged() {}
370
- readModulationValue() {
371
- return this.#modulationValue;
372
- }
373
350
  readoutValue() {
374
- return this.#shown().value ?? this.#value;
351
+ return this.#shown().value ?? this.#cell.value;
375
352
  }
376
353
  render() {
377
354
  if (this.isBound()) this.#renderControl();
@@ -399,147 +376,15 @@ var SonicValueElement = class extends SonicFormElement {
399
376
  travelPx(control, property) {
400
377
  return Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));
401
378
  }
402
- writeModulationValue(control, prefix, next) {
403
- const value = next === void 0 || next === null ? void 0 : toNumber(next);
404
- if (value !== void 0 && !Number.isFinite(value)) return;
405
- this.#modulationValue = value;
406
- if (this.isBound()) this.#writeModulationProportion(control, prefix);
407
- }
408
- writeProportions(control, prefix, modulation) {
409
- const { style } = control;
410
- const mapping = this.mapping();
411
- const value = mapping.proportionOf(this.#value);
412
- const reach = mapping.proportionOf(this.#value + modulation);
413
- const { positionCount } = mapping;
414
- style.setProperty(`--_sonic-${prefix}-value`, String(value));
415
- style.setProperty(`--_sonic-${prefix}-origin`, String(mapping.proportionOf(this.originValue())));
416
- style.setProperty(`--_sonic-${prefix}-modulation-from`, String(Math.min(value, reach)));
417
- style.setProperty(`--_sonic-${prefix}-modulation-to`, String(Math.max(value, reach)));
418
- if (positionCount === void 0) style.removeProperty(`--_sonic-${prefix}-position-count`);
419
- else style.setProperty(`--_sonic-${prefix}-position-count`, String(positionCount));
420
- this.#writeModulationProportion(control, prefix);
421
- }
422
- #bindEntry(control, signal) {
423
- const input = requireChild(control, "input", HTMLInputElement);
424
- const bubble = control.querySelector("[popover]");
425
- input.id = `sonic-entry-${this.#instance}`;
426
- if (bubble) this.#readout = {
427
- anchor: control,
428
- bubble: new Readout(bubble)
429
- };
430
- const entry = new ValueEntry(input, {
431
- commit: (text) => {
432
- this.#commit((this.#parseValue ?? Number.parseFloat)(text));
433
- },
434
- text: () => this.#parseValue ? this.valueText : String(this.#value),
435
- toggle: (isOpen) => {
436
- if (isOpen) this.forwardNaming(input, true);
437
- this.toggleState("editing", isOpen);
438
- this.render();
439
- }
440
- });
441
- this.#entry = entry;
442
- entry.bind(control, signal);
443
- return entry;
444
- }
445
- #bindKeys(control, entry, signal) {
446
- control.addEventListener("keydown", (event) => {
447
- if (this.isDisabled() || event.defaultPrevented || event.target !== control) return;
448
- this.toggleState("springing", false);
449
- if (event.key === "Enter") {
450
- if (this.springTarget() !== void 0) return;
451
- event.preventDefault();
452
- entry.open();
453
- return;
454
- }
455
- const next = this.#keyTarget(event.key);
456
- if (next === void 0) return;
457
- event.preventDefault();
458
- this.#keyTo(event, next);
459
- this.#claim.reveal("keys");
460
- this.#renderHold();
461
- }, { signal });
462
- control.addEventListener("keyup", (event) => {
463
- const isMeta = event.key === "Meta";
464
- if (isMeta || event.key === this.#keyScrub?.key) this.#endKeyScrub();
465
- if (isMeta && this.#dragging()) return;
466
- if (isMeta || this.mapping().keyTarget(event.key, this.#value) !== void 0) this.#springBack();
467
- }, { signal });
468
- control.addEventListener("blur", () => {
469
- this.#endKeyScrub();
470
- this.#concealKeyReveal();
471
- this.#springBack();
472
- }, { signal });
473
- }
474
- #commit(next, direction = 0) {
475
- const landed = Number.isFinite(next) ? this.#land?.(next, direction) ?? next : next;
476
- if (this.input(landed)) this.dispatchEvent(new Event("change", { bubbles: true }));
477
- }
478
- #concealKeyReveal() {
479
- if (this.#claim.conceal("keys")) this.#renderHold();
480
- }
481
- #dragging() {
482
- return this.#pointerDrag?.current();
483
- }
484
- #dragTo(drag, event) {
485
- const isOutside = drag.outside?.(event) === true;
486
- const wasEngaged = drag.state.isEngaged;
487
- const mapping = this.mapping();
488
- const { state, value } = stepDrag(mapping, drag.state, {
489
- isFine: event.shiftKey,
490
- isOutside,
491
- position: drag.position(event)
492
- });
493
- drag.state = this.#withinLimit(mapping, state);
494
- if (value === void 0) return;
495
- if (!wasEngaged) this.#reveal(drag);
496
- const isCrossing = isOutside !== drag.isOutside;
497
- if (isCrossing) {
498
- drag.isOutside = isOutside;
499
- this.toggleState("cancelling", isOutside);
500
- }
501
- this.input(isOutside ? drag.fromValue : value);
502
- if (isCrossing) this.#renderDragReveal(drag);
503
- }
504
- #endHolds() {
505
- this.#entry?.close(false);
506
- this.#pointerDrag?.end();
507
- this.#endKeyScrub();
508
- }
509
- #endKeyScrub() {
510
- const scrub = this.#keyScrub;
511
- if (!scrub) return;
512
- this.#keyScrub = void 0;
513
- this.#renderHold();
514
- if (this.#value !== scrub.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
379
+ #isEditing() {
380
+ return this.#gestures?.isEditing() === true;
515
381
  }
516
382
  #isHeld() {
517
- return this.#dragging() !== void 0 || this.#keyScrub !== void 0;
518
- }
519
- #keyTarget(key) {
520
- if (resetKeys.has(key)) return this.default;
521
- return this.mapping().keyTarget(key, this.#value, this.keyStep);
522
- }
523
- #keyTo(event, next) {
524
- if (event.repeat && this.scrubsKeyRepeat()) {
525
- this.#scrubKey(event.key, next);
526
- return;
527
- }
528
- this.#endKeyScrub();
529
- this.#commit(next, next > this.#value ? 1 : -1);
530
- }
531
- #releaseDrag(drag) {
532
- clearTimeout(drag.revealTimer);
533
- this.#claim.conceal("drag");
534
- this.toggleState("cancelling", false);
535
- this.#renderHold();
536
- this.#showRevealed(false);
537
- if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
538
- this.#springBack();
383
+ return this.#gestures?.isHeld() === true;
539
384
  }
540
385
  #renderAria(control, orientation) {
541
- this.writeFormValue(String(this.#value), String(this.#value));
542
- if (this.#entry?.isOpen) {
386
+ this.writeFormValue(String(this.#cell.value), String(this.#cell.value));
387
+ if (this.#isEditing()) {
543
388
  for (const name of roleAttributes) control.removeAttribute(name);
544
389
  this.forwardNaming(control, false);
545
390
  this.renderReadout();
@@ -551,14 +396,15 @@ var SonicValueElement = class extends SonicFormElement {
551
396
  writeAttribute(control, "aria-valuemax", String(high));
552
397
  writeAttribute(control, "aria-valuenow", String(this.#spokenNow()));
553
398
  if (orientation) writeAttribute(control, "aria-orientation", orientation);
554
- writeAttribute(control, "aria-valuetext", (this.#formatSpokenValue ?? this.#formatValue)?.(this.#value));
399
+ writeAttribute(control, "aria-valuetext", (this.#formatSpokenValue ?? this.#formatValue)?.(this.#cell.value));
555
400
  this.forwardNaming(control, true);
556
401
  this.#renderDisabled(control);
557
402
  this.renderReadout();
558
403
  }
559
404
  #renderControl() {
405
+ if (this.#isEditing() || this.isRevealed()) this.#hover?.clear();
560
406
  this.draw();
561
- this.toggleState("at-origin", !this.isWrapping() && this.#value === this.mapping().snap(this.originValue()));
407
+ this.toggleState("at-origin", !this.isWrapping() && this.#cell.value === this.mapping().snap(this.originValue()));
562
408
  this.#renderAria(this.focusTarget(), this.controlOrientation());
563
409
  }
564
410
  #renderDisabled(control) {
@@ -567,117 +413,30 @@ var SonicValueElement = class extends SonicFormElement {
567
413
  const stop = this.getAttribute("tabindex") === "-1" ? "-1" : "0";
568
414
  writeAttribute(control, "tabindex", isDisabled ? void 0 : stop);
569
415
  }
570
- #renderDragReveal(drag) {
571
- const isRevealed = drag.isRevealed && !drag.isOutside;
572
- if (isRevealed) this.#claim.reveal("drag");
573
- else this.#claim.conceal("drag");
574
- this.#renderHold();
575
- this.#showRevealed(isRevealed);
576
- }
577
416
  #renderHold() {
578
417
  if (this.heldFrom() === void 0) this.#heldAt = void 0;
579
418
  this.renderReadout();
580
419
  this.holdChanged();
581
420
  }
582
- #reset() {
583
- this.#commit(this.default ?? NaN);
584
- }
585
- #reveal(drag) {
586
- if (drag.isRevealed || this.#dragging() !== drag) return;
587
- drag.isRevealed = true;
588
- this.#renderDragReveal(drag);
589
- }
590
- #scrubKey(key, next) {
591
- if (this.#keyScrub?.key !== key) {
592
- this.#endKeyScrub();
593
- this.#keyScrub = {
594
- fromValue: this.#value,
595
- key
596
- };
597
- }
598
- this.input(next);
599
- }
600
421
  #shown() {
601
- if (this.isEditing()) return {
422
+ if (this.#isEditing()) return {
602
423
  isOpen: true,
603
424
  value: void 0
604
425
  };
605
- const isRevealed = this.#claim.isRevealed;
606
- const preview = isRevealed ? void 0 : this.previewValue();
426
+ const isRevealed = this.isRevealed();
427
+ const preview = isRevealed ? void 0 : this.#hover?.value();
607
428
  return {
608
429
  isOpen: (isRevealed || preview !== void 0) && this.readout,
609
- value: preview ?? this.#value
430
+ value: preview ?? this.#cell.value
610
431
  };
611
432
  }
612
- #showRevealed(isRevealed) {
613
- if (isRevealed === this.#isRevealed) return;
614
- this.#isRevealed = isRevealed;
615
- this.toggleState("revealed", isRevealed);
616
- this.dispatchEvent(new Event("sonic-reveal", { bubbles: true }));
617
- }
618
433
  #spokenNow() {
619
434
  const step = this.spokenStep;
620
- return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#value / step) * step) : this.#value;
621
- }
622
- #springBack() {
623
- const target = this.springTarget();
624
- if (target === void 0) return;
625
- if (this.mapping().snap(target) !== this.#value) this.toggleState("springing", true);
626
- this.#commit(target);
627
- }
628
- #startDrag(control, axis, event) {
629
- const mapping = this.mapping();
630
- const detent = this.detent;
631
- const start = {
632
- from: this.#value,
633
- position: axis.position(event),
634
- proportion: axis.fromProportion ?? mapping.proportionOf(this.#value),
635
- thresholdPx: dragThresholdPx(event.pointerType),
636
- travelPx: axis.travelPx
637
- };
638
- if (detent === void 0) return startDrag(mapping, start);
639
- const zonePx = readPxProperty(getComputedStyle(control), "--_sonic-detent-zone", detentZonePx);
640
- return startDrag(mapping, {
641
- ...start,
642
- detent: {
643
- value: detent,
644
- zone: zonePx / axis.travelPx
645
- }
646
- });
435
+ return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#cell.value / step) * step) : this.#cell.value;
647
436
  }
648
437
  #textFor(value) {
649
438
  return this.#formatValue?.(value) ?? String(value);
650
439
  }
651
- #withinLimit(mapping, state) {
652
- const limit = this.#limit;
653
- if (!limit || mapping.isWrapping) return state;
654
- const [low, high] = limit;
655
- return {
656
- ...state,
657
- rawProportion: clamp(state.rawProportion, mapping.proportionOf(low), mapping.proportionOf(high))
658
- };
659
- }
660
- #write(next) {
661
- if (!Number.isFinite(next)) return;
662
- const clamped = this.mapping().snap(next);
663
- this.#asked = clamped;
664
- if (clamped === this.#value) return;
665
- this.#value = clamped;
666
- this.render();
667
- }
668
- #writeModulationProportion(control, prefix) {
669
- const modulationValue = this.isWrapping() ? void 0 : this.#modulationValue;
670
- const isModulated = modulationValue !== void 0;
671
- if (isModulated !== this.#isModulated) {
672
- this.#isModulated = isModulated;
673
- this.toggleState("modulated", isModulated);
674
- }
675
- if (modulationValue === void 0) {
676
- control.style.removeProperty(`--_sonic-${prefix}-modulation-value`);
677
- return;
678
- }
679
- control.style.setProperty(`--_sonic-${prefix}-modulation-value`, String(this.mapping().proportionOf(modulationValue)));
680
- }
681
440
  };
682
441
 
683
442
  //#endregion