@xsynaptic/sonic-ui 0.26.0 → 0.28.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 (127) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -0
  3. package/dist/default/define/ticker.js +7 -0
  4. package/dist/default/define.js +1 -0
  5. package/dist/default/elements/{display-element.js → analyser-element.js} +10 -12
  6. package/dist/default/elements/button.js +12 -9
  7. package/dist/default/elements/dial.js +9 -13
  8. package/dist/default/elements/envelope.js +26 -23
  9. package/dist/default/elements/field-gesture.js +49 -8
  10. package/dist/default/elements/meter.js +6 -8
  11. package/dist/default/elements/number.js +5 -14
  12. package/dist/default/elements/position-group.js +4 -4
  13. package/dist/default/elements/radio-group.js +6 -9
  14. package/dist/default/elements/segmented.js +7 -4
  15. package/dist/default/elements/slider.js +12 -13
  16. package/dist/default/elements/sonic-element.js +7 -5
  17. package/dist/default/elements/spectrum.js +3 -3
  18. package/dist/default/elements/switch.js +11 -6
  19. package/dist/default/elements/ticker.js +313 -0
  20. package/dist/default/elements/toggle.js +14 -8
  21. package/dist/default/elements/value-element.js +11 -3
  22. package/dist/default/elements/wave-element.js +11 -12
  23. package/dist/default/elements/waveform.js +1 -4
  24. package/dist/default/elements/wavestrip.js +3 -6
  25. package/dist/default/elements/xy.js +34 -47
  26. package/dist/default/index.js +2 -1
  27. package/dist/default/lib/cancel-zone.js +12 -0
  28. package/dist/default/lib/canvas-surface.js +13 -1
  29. package/dist/default/lib/distribute.js +2 -3
  30. package/dist/default/lib/mirror-children.js +1 -1
  31. package/dist/default/lib/pointer-drag.js +8 -2
  32. package/dist/default/lib/render.js +2 -2
  33. package/dist/default/lib/ticker-leg.js +54 -0
  34. package/dist/dev/define/ticker.d.ts +2 -0
  35. package/dist/dev/define/ticker.js +8 -0
  36. package/dist/dev/define/ticker.js.map +1 -0
  37. package/dist/dev/define.d.ts +3 -1
  38. package/dist/dev/define.js +1 -0
  39. package/dist/dev/elements/{display-element.d.ts → analyser-element.d.ts} +3 -3
  40. package/dist/dev/elements/{display-element.js → analyser-element.js} +11 -14
  41. package/dist/dev/elements/analyser-element.js.map +1 -0
  42. package/dist/dev/elements/button.d.ts +4 -1
  43. package/dist/dev/elements/button.js +12 -14
  44. package/dist/dev/elements/button.js.map +1 -1
  45. package/dist/dev/elements/dial.d.ts +4 -2
  46. package/dist/dev/elements/dial.js +9 -17
  47. package/dist/dev/elements/dial.js.map +1 -1
  48. package/dist/dev/elements/envelope.d.ts +5 -1
  49. package/dist/dev/elements/envelope.js +26 -27
  50. package/dist/dev/elements/envelope.js.map +1 -1
  51. package/dist/dev/elements/field-gesture.js +49 -8
  52. package/dist/dev/elements/field-gesture.js.map +1 -1
  53. package/dist/dev/elements/meter.d.ts +2 -1
  54. package/dist/dev/elements/meter.js +6 -9
  55. package/dist/dev/elements/meter.js.map +1 -1
  56. package/dist/dev/elements/number.d.ts +2 -2
  57. package/dist/dev/elements/number.js +5 -15
  58. package/dist/dev/elements/number.js.map +1 -1
  59. package/dist/dev/elements/position-group.js +4 -4
  60. package/dist/dev/elements/position-group.js.map +1 -1
  61. package/dist/dev/elements/radio-group.d.ts +1 -2
  62. package/dist/dev/elements/radio-group.js +6 -9
  63. package/dist/dev/elements/radio-group.js.map +1 -1
  64. package/dist/dev/elements/segmented.d.ts +4 -2
  65. package/dist/dev/elements/segmented.js +7 -9
  66. package/dist/dev/elements/segmented.js.map +1 -1
  67. package/dist/dev/elements/slider.d.ts +4 -2
  68. package/dist/dev/elements/slider.js +12 -17
  69. package/dist/dev/elements/slider.js.map +1 -1
  70. package/dist/dev/elements/sonic-element.d.ts +6 -7
  71. package/dist/dev/elements/sonic-element.js +14 -83
  72. package/dist/dev/elements/sonic-element.js.map +1 -1
  73. package/dist/dev/elements/spectrum.d.ts +2 -2
  74. package/dist/dev/elements/spectrum.js +3 -3
  75. package/dist/dev/elements/spectrum.js.map +1 -1
  76. package/dist/dev/elements/switch.d.ts +4 -1
  77. package/dist/dev/elements/switch.js +11 -10
  78. package/dist/dev/elements/switch.js.map +1 -1
  79. package/dist/dev/elements/ticker.d.ts +25 -0
  80. package/dist/dev/elements/ticker.js +314 -0
  81. package/dist/dev/elements/ticker.js.map +1 -0
  82. package/dist/dev/elements/toggle.d.ts +4 -1
  83. package/dist/dev/elements/toggle.js +14 -13
  84. package/dist/dev/elements/toggle.js.map +1 -1
  85. package/dist/dev/elements/value-element.d.ts +4 -3
  86. package/dist/dev/elements/value-element.js +11 -3
  87. package/dist/dev/elements/value-element.js.map +1 -1
  88. package/dist/dev/elements/wave-element.d.ts +2 -2
  89. package/dist/dev/elements/wave-element.js +11 -16
  90. package/dist/dev/elements/wave-element.js.map +1 -1
  91. package/dist/dev/elements/waveform.d.ts +0 -1
  92. package/dist/dev/elements/waveform.js +1 -4
  93. package/dist/dev/elements/waveform.js.map +1 -1
  94. package/dist/dev/elements/wavestrip.js +3 -6
  95. package/dist/dev/elements/wavestrip.js.map +1 -1
  96. package/dist/dev/elements/xy.d.ts +4 -1
  97. package/dist/dev/elements/xy.js +34 -51
  98. package/dist/dev/elements/xy.js.map +1 -1
  99. package/dist/dev/index.d.ts +4 -1
  100. package/dist/dev/index.js +2 -1
  101. package/dist/dev/lib/cancel-zone.js +13 -0
  102. package/dist/dev/lib/cancel-zone.js.map +1 -0
  103. package/dist/dev/lib/canvas-surface.js +13 -1
  104. package/dist/dev/lib/canvas-surface.js.map +1 -1
  105. package/dist/dev/lib/check-styles.d.ts +8 -0
  106. package/dist/dev/lib/check-styles.js +95 -0
  107. package/dist/dev/lib/check-styles.js.map +1 -0
  108. package/dist/dev/lib/distribute.js +2 -3
  109. package/dist/dev/lib/distribute.js.map +1 -1
  110. package/dist/dev/lib/mirror-children.js +9 -7
  111. package/dist/dev/lib/mirror-children.js.map +1 -1
  112. package/dist/dev/lib/pointer-drag.js +8 -2
  113. package/dist/dev/lib/pointer-drag.js.map +1 -1
  114. package/dist/dev/lib/render.js +2 -2
  115. package/dist/dev/lib/render.js.map +1 -1
  116. package/dist/dev/lib/ticker-leg.js +55 -0
  117. package/dist/dev/lib/ticker-leg.js.map +1 -0
  118. package/dist/styles/controls.css +1 -0
  119. package/dist/styles/dial.css +28 -5
  120. package/dist/styles/material/cap.css +16 -5
  121. package/dist/styles/material/core.css +1 -0
  122. package/dist/styles/slider.css +2 -1
  123. package/dist/styles/switch.css +3 -1
  124. package/dist/styles/ticker.css +115 -0
  125. package/dist/styles/toggle.css +7 -5
  126. package/package.json +2 -1
  127. package/dist/dev/elements/display-element.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @xsynaptic/sonic-ui
2
2
 
3
+ ## 0.28.0
4
+
5
+ ### Minor Changes
6
+
7
+ - `--sonic-gloss` scales a cap's sheen apart from `--sonic-relief`: 0 is matte, 1 the default. A slider cap has no sheen until the token is set, so there `1` is not the same as unset.
8
+ - - `<sonic-ticker>`: one line of content that scrolls there and back when it does not fit its box, registered by `./define/ticker` with `ticker.css`, which needs no material sheet. It stands still with an ellipsis under reduced motion, and pauses under a mouse, while a link round it has keyboard focus, off screen, and while `paused` is set. A drag along the line moves the tape; with `cancellable` a drag that strays past `--sonic-cancel-zone`, shared with the wave strip, puts it back. `text` replaces the content. A link among the children is copied and still navigates.
9
+ - Ticker surface: tokens `--sonic-ticker-rate` (a length a second, `40px`), `--sonic-ticker-hold` (`2s`) and `--sonic-ticker-fade` (`0.75rem`); hook classes `.sonic-ticker` and `.sonic-ticker-tape`; states `data-sonic-overflowing`, `data-sonic-dragging`, `data-sonic-cancelling` and `data-sonic-paused`, and `data-sonic-clipped` naming each end with content past it.
10
+
11
+ ### Patch Changes
12
+
13
+ - Switch and toggle: the bat and the cap land with a small overshoot, and the switch's flip takes 120ms, up from 90ms.
14
+ - Split: a move the siblings cannot absorb on their own steps is turned back, so the total holds across mixed step grids.
15
+
16
+ ## 0.27.0
17
+
18
+ ### Minor Changes
19
+
20
+ - - Envelope: a handle drag reports its reveal as the other controls with a readout do, with `data-sonic-revealed` on `.sonic-envelope`, a bubbling `sonic-reveal` event and a read-only `revealed` property.
21
+ - The `FieldAxis` and `SplitMode` types are exported.
22
+
3
23
  ## 0.26.0
4
24
 
5
25
  ### Minor Changes
package/README.md CHANGED
@@ -88,6 +88,7 @@ A skin is one rule that sets tokens on a class; copy `dist/skins/flat.css` to st
88
88
  | `slider.css` | core, cap, glass, readout, value, groove, scale |
89
89
  | `spectrum.css` | core |
90
90
  | `switch.css` | core, cap |
91
+ | `ticker.css` | |
91
92
  | `toggle.css` | core, cap, well, keycap |
92
93
  | `waveform.css` | core, cap, glass, readout, value |
93
94
  | `wavestrip.css` | core, cap, glass, readout, value |
@@ -0,0 +1,7 @@
1
+ import { defineOnce } from "../elements/define-once.js";
2
+ import { SonicTicker } from "../elements/ticker.js";
3
+
4
+ //#region src/define/ticker.ts
5
+ defineOnce("sonic-ticker", SonicTicker);
6
+
7
+ //#endregion
@@ -9,6 +9,7 @@ import "./define/slider.js";
9
9
  import "./define/spectrum.js";
10
10
  import "./define/split.js";
11
11
  import "./define/switch.js";
12
+ import "./define/ticker.js";
12
13
  import "./define/toggle.js";
13
14
  import "./define/waveform.js";
14
15
  import "./define/wavestrip.js";
@@ -1,8 +1,8 @@
1
1
  import { SonicElement } from "./sonic-element.js";
2
- import { bindSurface } from "../lib/canvas-surface.js";
2
+ import { bindControlSurface } from "../lib/canvas-surface.js";
3
3
 
4
- //#region src/elements/display-element.ts
5
- var SonicDisplayElement = class extends SonicElement {
4
+ //#region src/elements/analyser-element.ts
5
+ var SonicAnalyserElement = class extends SonicElement {
6
6
  static observedAttributes = [
7
7
  ...SonicElement.observedAttributes,
8
8
  "fill",
@@ -55,21 +55,19 @@ var SonicDisplayElement = class extends SonicElement {
55
55
  }
56
56
  connect(signal) {
57
57
  const control = this.control;
58
- this.keepControl(control, signal);
59
- this.#surface = bindSurface({
58
+ this.keepControl(signal);
59
+ this.#surface = bindControlSurface({
60
60
  canvas: this.canvas,
61
61
  colours: this.colours,
62
- fill: {
63
- control,
64
- sizeProperty: this.sizeProperty
65
- },
62
+ control,
63
+ fill: this.fill,
66
64
  numbers: this.numbers,
67
65
  paint: (context, frame) => {
68
66
  this.#paint(context, frame);
69
67
  },
70
- signal
68
+ signal,
69
+ sizeProperty: this.sizeProperty
71
70
  });
72
- this.#surface.setFill(this.fill);
73
71
  }
74
72
  surface() {
75
73
  return this.#surface;
@@ -87,4 +85,4 @@ var SonicDisplayElement = class extends SonicElement {
87
85
  };
88
86
 
89
87
  //#endregion
90
- export { SonicDisplayElement };
88
+ export { SonicAnalyserElement };
@@ -88,7 +88,13 @@ var SonicButton = class extends SonicFormElement {
88
88
  set value(value) {
89
89
  this.reflect("value", value);
90
90
  }
91
- #button = renderButton();
91
+ boxProbe = {
92
+ property: "padding-inline-start",
93
+ ratio: "--_sonic-button-padding-ratio",
94
+ selector: ".sonic-button-cap > :not(svg, .sonic-led)"
95
+ };
96
+ control = renderButton();
97
+ sheet = "button.css";
92
98
  #holding;
93
99
  #isDirty = false;
94
100
  #pressed = false;
@@ -101,10 +107,10 @@ var SonicButton = class extends SonicFormElement {
101
107
  this.attributeChangedCallback("pressed");
102
108
  }
103
109
  activate() {
104
- this.#button.click();
110
+ this.control.click();
105
111
  }
106
112
  connect(signal) {
107
- const button = this.#button;
113
+ const button = this.control;
108
114
  const cap = requireChild(button, ".sonic-button-cap", HTMLSpanElement);
109
115
  this.upgradeProperties("armed", "busy", "defaultPressed", "legend", "momentary", "softDisabled", "latching", "pressed", "value");
110
116
  mirrorChildren(this, {
@@ -130,11 +136,11 @@ var SonicButton = class extends SonicFormElement {
130
136
  bindKeyPress(button, signal);
131
137
  }
132
138
  focusTarget() {
133
- return this.#button;
139
+ return this.control;
134
140
  }
135
141
  render() {
136
142
  if (!this.isBound()) return;
137
- const button = this.#button;
143
+ const button = this.control;
138
144
  writeAttribute(button, "disabled", this.isDisabled() ? "" : void 0);
139
145
  writeAttribute(button, "aria-disabled", this.#isSoftDisabled() ? "true" : void 0);
140
146
  writeAttribute(button, "aria-busy", this.busy ? "true" : void 0);
@@ -149,9 +155,6 @@ var SonicButton = class extends SonicFormElement {
149
155
  restoreState(state) {
150
156
  if (this.latching) this.pressed = state === "true";
151
157
  }
152
- stateTarget() {
153
- return this.#button;
154
- }
155
158
  #bindMomentary(button, signal) {
156
159
  const holding = bindHold(button, {
157
160
  canHold: () => !this.isDisabled() && !this.#isSoftDisabled(),
@@ -190,7 +193,7 @@ var SonicButton = class extends SonicFormElement {
190
193
  }
191
194
  #showLegend() {
192
195
  const legend = this.legend;
193
- for (const part of this.#button.querySelectorAll(":scope > .sonic-button-cap > [data-sonic-when]")) {
196
+ for (const part of this.control.querySelectorAll(":scope > .sonic-button-cap > [data-sonic-when]")) {
194
197
  const when = part.dataset.sonicWhen ?? "";
195
198
  part.toggleAttribute("data-sonic-hidden", !pressWhens.has(when) && when !== legend);
196
199
  }
@@ -51,8 +51,13 @@ var SonicDial = class extends SonicValueElement {
51
51
  set modulationValue(value) {
52
52
  this.#modulation.write(value, this.isBound() ? this.mapping() : void 0);
53
53
  }
54
- #dial = renderDial();
55
- #modulation = createModulation(this.#dial, "dial", (isModulated) => {
54
+ boxProbe = {
55
+ property: "margin-bottom",
56
+ selector: "[popover]"
57
+ };
58
+ control = renderDial();
59
+ sheet = "dial.css";
60
+ #modulation = createModulation(this.control, "dial", (isModulated) => {
56
61
  this.toggleState("modulated", isModulated);
57
62
  });
58
63
  connectedCallback() {
@@ -60,16 +65,13 @@ var SonicDial = class extends SonicValueElement {
60
65
  super.connectedCallback();
61
66
  }
62
67
  connect(signal) {
63
- const dial = this.#dial;
68
+ const dial = this.control;
64
69
  bindScale(this, {
65
70
  control: dial,
66
71
  marks: requireChild(dial, ".sonic-dial-scale", HTMLDivElement)
67
72
  }, signal);
68
73
  this.render();
69
- this.bindGestures(dial, signal, () => ({
70
- position: (event) => -event.clientY,
71
- travelPx: this.travelPx(dial, "--_sonic-dial-travel")
72
- }));
74
+ this.bindGestures(signal, () => this.upwardAxis("--_sonic-dial-travel"));
73
75
  }
74
76
  draw() {
75
77
  this.#modulation.draw({
@@ -79,15 +81,9 @@ var SonicDial = class extends SonicValueElement {
79
81
  value: this.value
80
82
  });
81
83
  }
82
- focusTarget() {
83
- return this.#dial;
84
- }
85
84
  isWrapping() {
86
85
  return this.endless;
87
86
  }
88
- stateTarget() {
89
- return this.#dial;
90
- }
91
87
  };
92
88
 
93
89
  //#endregion
@@ -2,7 +2,6 @@ import { writeAttribute } from "../lib/write-attribute.js";
2
2
  import { SonicElement } from "./sonic-element.js";
3
3
  import { requireChild, template } from "../lib/render.js";
4
4
  import { Readout } from "./readout.js";
5
- import { ReadoutClaim } from "./readout-claim.js";
6
5
  import { SonicValueElement, linkValue } from "./value-element.js";
7
6
  import { bindFieldGesture } from "./field-gesture.js";
8
7
  import { adsrPath, adsrShape, adsrStages, timeStages } from "../lib/adsr-shape.js";
@@ -116,28 +115,33 @@ var SonicEnvelope = class extends SonicElement {
116
115
  set releaseCurve(id) {
117
116
  this.reflect("release-curve", id);
118
117
  }
118
+ get revealed() {
119
+ return this.hasState("revealed");
120
+ }
119
121
  get sustain() {
120
122
  return this.getAttribute("sustain") ?? "";
121
123
  }
122
124
  set sustain(id) {
123
125
  this.reflect("sustain", id);
124
126
  }
127
+ boxProbe = {
128
+ property: "margin-bottom",
129
+ selector: "[popover]"
130
+ };
131
+ control = renderEnvelope();
132
+ sheet = "envelope.css";
125
133
  #bindings = /* @__PURE__ */ new Map();
126
- #claim = new ReadoutClaim(() => {
127
- this.#renderReadout();
128
- });
129
- #envelope = renderEnvelope();
130
- #curveHandles = stageParts(this.#envelope, "sonic-envelope-curve", curveStages);
131
- #fill = requireChild(this.#envelope, ".sonic-envelope-fill", SVGElement);
132
- #floor = requireChild(this.#envelope, ".sonic-envelope-floor", SVGElement);
134
+ #curveHandles = stageParts(this.control, "sonic-envelope-curve", curveStages);
135
+ #fill = requireChild(this.control, ".sonic-envelope-fill", SVGElement);
136
+ #floor = requireChild(this.control, ".sonic-envelope-floor", SVGElement);
133
137
  #gesture;
134
- #graph = requireChild(this.#envelope, ".sonic-envelope-graph", SVGElement);
135
- #handles = stageParts(this.#envelope, "sonic-envelope-handle", timeStages);
138
+ #graph = requireChild(this.control, ".sonic-envelope-graph", SVGElement);
139
+ #handles = stageParts(this.control, "sonic-envelope-handle", timeStages);
136
140
  #held;
137
141
  #isDriving = false;
138
- #line = requireChild(this.#envelope, ".sonic-envelope-line", SVGElement);
139
- #readout = new Readout(requireChild(this.#envelope, ".sonic-envelope-readout", HTMLDivElement));
140
- #reticle = requireChild(this.#envelope, ".sonic-envelope-reticle", HTMLDivElement);
142
+ #line = requireChild(this.control, ".sonic-envelope-line", SVGElement);
143
+ #readout = new Readout(requireChild(this.control, ".sonic-envelope-readout", HTMLDivElement));
144
+ #reticle = requireChild(this.control, ".sonic-envelope-reticle", HTMLDivElement);
141
145
  #shape = adsrShape({});
142
146
  #waiting = /* @__PURE__ */ new Set();
143
147
  #warned = /* @__PURE__ */ new Set();
@@ -156,17 +160,13 @@ var SonicEnvelope = class extends SonicElement {
156
160
  super.connectedCallback();
157
161
  }
158
162
  connect(signal) {
159
- const envelope = this.#envelope;
160
- this.keepControl(envelope, signal);
163
+ this.keepControl(signal);
161
164
  this.#bind();
162
- this.#bindPointer(envelope, signal);
165
+ this.#bindPointer(this.control, signal);
163
166
  signal.addEventListener("abort", () => {
164
167
  this.#unbind();
165
168
  }, { once: true });
166
169
  }
167
- stateTarget() {
168
- return this.#envelope;
169
- }
170
170
  #bind() {
171
171
  this.#gesture?.end();
172
172
  this.#unbind();
@@ -187,7 +187,7 @@ var SonicEnvelope = class extends SonicElement {
187
187
  }
188
188
  #bindPointer(envelope, signal) {
189
189
  this.#gesture = bindFieldGesture(envelope, {
190
- claim: this.#claim,
190
+ element: this,
191
191
  grab: (event) => this.#grab(event),
192
192
  input: ({ drives }, next) => {
193
193
  this.#isDriving = true;
@@ -204,8 +204,11 @@ var SonicEnvelope = class extends SonicElement {
204
204
  binding.link.change();
205
205
  }
206
206
  },
207
- toggle: (isDragging) => {
208
- this.toggleState("dragging", isDragging);
207
+ renderReadout: () => {
208
+ this.#renderReadout();
209
+ },
210
+ toggle: (state, isOn) => {
211
+ this.toggleState(state, isOn);
209
212
  }
210
213
  }, signal);
211
214
  }
@@ -319,7 +322,7 @@ var SonicEnvelope = class extends SonicElement {
319
322
  }
320
323
  this.#readout.show({
321
324
  anchor: drag.part,
322
- isOpen: this.#claim.isRevealed && this.readout,
325
+ isOpen: this.#gesture?.isRevealed() === true && this.readout,
323
326
  text: drag.drives.map(({ binding }) => binding.element.valueText).join(", ")
324
327
  });
325
328
  }
@@ -1,6 +1,8 @@
1
1
  import { bindDrag } from "../lib/pointer-drag.js";
2
- import { revealDelay } from "./readout-claim.js";
2
+ import { ReadoutClaim, revealDelay } from "./readout-claim.js";
3
+ import { createDoublePress } from "../lib/double-press.js";
3
4
  import { dragThresholdPx } from "../lib/drag-step.js";
5
+ import { isMenuPress, isResetPress } from "../lib/modifier-press.js";
4
6
  import { pointerMove, pointerPosition, startFieldDrag, stepFieldDrag } from "../lib/field.js";
5
7
 
6
8
  //#region src/elements/field-gesture.ts
@@ -23,16 +25,39 @@ function startAxis(hold) {
23
25
  travelPx
24
26
  };
25
27
  }
28
+ function createReveal({ element, renderReadout, toggle }) {
29
+ let isRevealed = false;
30
+ const show = () => {
31
+ if (claim.isRevealed !== isRevealed) {
32
+ isRevealed = claim.isRevealed;
33
+ toggle("revealed", isRevealed);
34
+ element.dispatchEvent(new Event("sonic-reveal", { bubbles: true }));
35
+ }
36
+ renderReadout();
37
+ };
38
+ const claim = new ReadoutClaim(show);
39
+ return {
40
+ claim,
41
+ show
42
+ };
43
+ }
26
44
  function bindFieldGesture(target, options, signal) {
27
- const { claim } = options;
45
+ const { reset, resetsOnDoublePress } = options;
46
+ const { claim, show } = createReveal(options);
47
+ const doublePress = reset && resetsOnDoublePress ? createDoublePress() : void 0;
28
48
  let pointerType;
49
+ const grab = (event) => {
50
+ if (isMenuPress(event)) return void 0;
51
+ if (!reset || !isResetPress(event)) return options.grab(event);
52
+ reset();
53
+ };
29
54
  const drag = bindDrag(target, {
30
55
  cancel: ({ from, hold }) => {
31
56
  options.input(hold, from);
32
57
  },
33
58
  grab: (event) => {
34
59
  pointerType = event.pointerType;
35
- const hold = options.grab(event);
60
+ const hold = grab(event);
36
61
  if (!hold) {
37
62
  pointerType = void 0;
38
63
  return;
@@ -53,8 +78,8 @@ function bindFieldGesture(target, options, signal) {
53
78
  })
54
79
  };
55
80
  },
56
- lift: ({ hold }, event) => {
57
- options.lift?.(hold, event);
81
+ lift: (_held, event) => {
82
+ if (doublePress?.press(event) === true && resetsOnDoublePress?.() === true) reset?.();
58
83
  },
59
84
  move: (held, event) => {
60
85
  const { axes } = held.hold;
@@ -63,7 +88,10 @@ function bindFieldGesture(target, options, signal) {
63
88
  y: axes.y?.model.mapping()
64
89
  }, held.state, flip(pointerMove(event), held.hold));
65
90
  held.state = step.state;
66
- if (step.state.isEngaged) claim.reveal("drag");
91
+ if (step.state.isEngaged) {
92
+ claim.reveal("drag");
93
+ show();
94
+ }
67
95
  options.input(held.hold, step);
68
96
  },
69
97
  release: ({ from, hold }) => {
@@ -71,12 +99,25 @@ function bindFieldGesture(target, options, signal) {
71
99
  options.release(hold, fieldAxes.filter((axis) => hold.axes[axis]?.model.value !== from[axis]));
72
100
  pointerType = void 0;
73
101
  },
74
- toggle: options.toggle
102
+ toggle: (isDragging) => {
103
+ options.toggle("dragging", isDragging);
104
+ }
75
105
  }, signal);
106
+ target.addEventListener("pointercancel", () => {
107
+ doublePress?.forget();
108
+ }, { signal });
76
109
  return {
110
+ concealKeys: () => {
111
+ if (claim.conceal("keys")) show();
112
+ },
77
113
  current: () => drag.current()?.hold,
78
114
  end: drag.end,
79
- pointerType: () => pointerType
115
+ isRevealed: () => claim.isRevealed,
116
+ pointerType: () => pointerType,
117
+ revealKeys: () => {
118
+ claim.reveal("keys");
119
+ show();
120
+ }
80
121
  };
81
122
  }
82
123
 
@@ -109,6 +109,8 @@ var SonicMeter = class extends SonicElement {
109
109
  set value(value) {
110
110
  this.reflect("value", value);
111
111
  }
112
+ control = renderMeter();
113
+ sheet = "meter.css";
112
114
  #bar = -Infinity;
113
115
  #carryMs = 0;
114
116
  #clipAt = -Infinity;
@@ -116,7 +118,6 @@ var SonicMeter = class extends SonicElement {
116
118
  #isValueShown = false;
117
119
  #lastFrame;
118
120
  #level = 0;
119
- #meter = renderMeter();
120
121
  #peak = -Infinity;
121
122
  #peakHold = -Infinity;
122
123
  #peakHoldAt = -Infinity;
@@ -138,7 +139,7 @@ var SonicMeter = class extends SonicElement {
138
139
  connect(signal) {
139
140
  const now = performance.now();
140
141
  this.upgradeProperties("ballistics", "max", "min", "orientation", "origin", "segments", "value", "level");
141
- this.keepControl(this.#meter, signal);
142
+ this.keepControl(signal);
142
143
  this.#renderSegments();
143
144
  this.#render(now);
144
145
  this.#schedule(now);
@@ -148,9 +149,6 @@ var SonicMeter = class extends SonicElement {
148
149
  this.#lastFrame = void 0;
149
150
  }, { once: true });
150
151
  }
151
- stateTarget() {
152
- return this.#meter;
153
- }
154
152
  #isSettled(now) {
155
153
  if (this.#isValueShown) return true;
156
154
  if (now - this.#clipAt < holdMs) return false;
@@ -175,7 +173,7 @@ var SonicMeter = class extends SonicElement {
175
173
  }
176
174
  #render(now) {
177
175
  if (!this.isBound()) return;
178
- const meter = this.#meter;
176
+ const meter = this.control;
179
177
  const origin = this.origin === void 0 ? 0 : this.#proportionOf(this.origin);
180
178
  meter.style.setProperty("--_sonic-meter-min", String(this.min));
181
179
  meter.style.setProperty("--_sonic-meter-max", String(this.max));
@@ -196,7 +194,7 @@ var SonicMeter = class extends SonicElement {
196
194
  }
197
195
  #renderSegments() {
198
196
  if (!this.isBound()) return;
199
- const meter = this.#meter;
197
+ const meter = this.control;
200
198
  const segments = this.#segments;
201
199
  this.toggleState("ladder", segments !== void 0);
202
200
  if (!segments) {
@@ -212,7 +210,7 @@ var SonicMeter = class extends SonicElement {
212
210
  meter.style.setProperty("--_sonic-meter-clip-segments", segmentsBelow(segments, "clip"));
213
211
  }
214
212
  #renderStill(bar) {
215
- const { style } = this.#meter;
213
+ const { style } = this.control;
216
214
  style.setProperty("--_sonic-meter-bar", String(bar));
217
215
  style.setProperty("--_sonic-meter-peak-hold", "0");
218
216
  style.setProperty("--_sonic-meter-clipped", "0");
@@ -22,20 +22,17 @@ var SonicNumber = class extends SonicValueElement {
22
22
  set press(gesture) {
23
23
  this.reflect("press", gesture);
24
24
  }
25
- #number = renderNumber();
26
- #digits = requireChild(this.#number, ".sonic-number-value", HTMLSpanElement);
25
+ control = renderNumber();
26
+ sheet = "number.css";
27
+ #digits = requireChild(this.control, ".sonic-number-value", HTMLSpanElement);
27
28
  connectedCallback() {
28
29
  this.upgradeProperties("press");
29
30
  super.connectedCallback();
30
31
  }
31
32
  connect(signal) {
32
- const number = this.#number;
33
- this.keepControl(number, signal);
33
+ this.keepControl(signal);
34
34
  this.render();
35
- this.bindGestures(number, signal, () => ({
36
- position: (event) => -event.clientY,
37
- travelPx: this.travelPx(number, "--_sonic-number-travel")
38
- }));
35
+ this.bindGestures(signal, () => this.upwardAxis("--_sonic-number-travel"));
39
36
  }
40
37
  controlRole() {
41
38
  return "spinbutton";
@@ -43,12 +40,6 @@ var SonicNumber = class extends SonicValueElement {
43
40
  draw() {
44
41
  this.#digits.textContent = this.valueText;
45
42
  }
46
- focusTarget() {
47
- return this.#number;
48
- }
49
- stateTarget() {
50
- return this.#number;
51
- }
52
43
  tapTarget() {
53
44
  if (this.press !== "step") return void 0;
54
45
  const mapping = this.mapping();
@@ -81,7 +81,7 @@ var SonicPositionGroupElement = class extends SonicRadioGroupElement {
81
81
  connect(signal) {
82
82
  this.upgradeProperties("defaultChecked", "checked", "orientation");
83
83
  super.connect(signal);
84
- this.#holding = bindHold(this.group, {
84
+ this.#holding = bindHold(this.control, {
85
85
  canHold: () => !this.isDisabled(),
86
86
  leave: "focusout",
87
87
  onHold: () => {
@@ -129,7 +129,7 @@ var SonicPositionGroupElement = class extends SonicRadioGroupElement {
129
129
  }
130
130
  render() {
131
131
  if (!this.isBound()) return;
132
- const group = this.group;
132
+ const group = this.control;
133
133
  const count = this.options().length;
134
134
  if (count === 0) {
135
135
  this.#renderBare();
@@ -156,12 +156,12 @@ var SonicPositionGroupElement = class extends SonicRadioGroupElement {
156
156
  springBack() {
157
157
  const rest = restOf(this.positions(), this.checkedIndex());
158
158
  if (rest === void 0) return;
159
- const isFocused = this.group.contains(this.ownerDocument.activeElement);
159
+ const isFocused = this.control.contains(this.ownerDocument.activeElement);
160
160
  this.select(rest);
161
161
  if (isFocused) this.options()[rest]?.focus();
162
162
  }
163
163
  #renderBare() {
164
- const group = this.group;
164
+ const group = this.control;
165
165
  const bare = this.bare;
166
166
  const isChecked = this.checked;
167
167
  writeAttribute(group, "role", void 0);
@@ -43,7 +43,7 @@ var SonicRadioGroupElement = class extends SonicFormElement {
43
43
  return false;
44
44
  }
45
45
  connect(signal) {
46
- const group = this.group;
46
+ const group = this.control;
47
47
  this.upgradeProperties("value");
48
48
  mirrorChildren(this, {
49
49
  control: group,
@@ -91,10 +91,10 @@ var SonicRadioGroupElement = class extends SonicFormElement {
91
91
  optionOf(target) {
92
92
  if (!(target instanceof Element)) return void 0;
93
93
  const option = target.closest("[role=\"radio\"]");
94
- return option instanceof HTMLButtonElement && option.parentElement === this.group ? option : void 0;
94
+ return option instanceof HTMLButtonElement && option.parentElement === this.control ? option : void 0;
95
95
  }
96
96
  options() {
97
- return [...this.group.children].filter((child) => child instanceof HTMLButtonElement && child.getAttribute("role") === "radio");
97
+ return [...this.control.children].filter((child) => child instanceof HTMLButtonElement && child.getAttribute("role") === "radio");
98
98
  }
99
99
  placeCopies(copies) {
100
100
  this.#copyOptions(copies);
@@ -109,7 +109,7 @@ var SonicRadioGroupElement = class extends SonicFormElement {
109
109
  });
110
110
  }
111
111
  refocusAt(index) {
112
- if (this.group.matches(":focus-within")) this.options()[index]?.focus();
112
+ if (this.control.matches(":focus-within")) this.options()[index]?.focus();
113
113
  }
114
114
  releaseTarget(index) {
115
115
  return index;
@@ -126,7 +126,7 @@ var SonicRadioGroupElement = class extends SonicFormElement {
126
126
  writeAttribute(option, "aria-checked", String(option === checked));
127
127
  writeAttribute(option, "tabindex", option === focusable ? "0" : "-1");
128
128
  }
129
- this.forwardNaming(this.group, true);
129
+ this.forwardNaming(this.control, true);
130
130
  this.writeFormValue(checked ? this.#value : null, this.#value);
131
131
  }
132
132
  restoreState(state) {
@@ -139,9 +139,6 @@ var SonicRadioGroupElement = class extends SonicFormElement {
139
139
  this.value = next;
140
140
  this.dispatchEvent(new Event("change", { bubbles: true }));
141
141
  }
142
- stateTarget() {
143
- return this.group;
144
- }
145
142
  stepFrom(from, step) {
146
143
  return stepFrom(this.positions(), from, {
147
144
  isWrapping: this.isWrapping(),
@@ -178,7 +175,7 @@ var SonicRadioGroupElement = class extends SonicFormElement {
178
175
  }, signal);
179
176
  }
180
177
  #copyOptions(copies) {
181
- const group = this.group;
178
+ const group = this.control;
182
179
  const options = this.options();
183
180
  const focused = this.optionOf(group.querySelector(":scope > :focus"));
184
181
  const focusedValue = focused && optionValue(focused);
@@ -9,10 +9,13 @@ const renderOption = template(`
9
9
  </button>
10
10
  `, HTMLButtonElement);
11
11
  var SonicSegmented = class extends SonicRadioGroupElement {
12
- group = renderSegmented();
13
- connect(signal) {
14
- super.connect(signal);
15
- }
12
+ boxProbe = {
13
+ property: "padding-inline-start",
14
+ ratio: "--_sonic-segmented-padding-ratio",
15
+ selector: ".sonic-segmented-cap"
16
+ };
17
+ control = renderSegmented();
18
+ sheet = "segmented.css";
16
19
  renderOption() {
17
20
  return renderOption();
18
21
  }