@xsynaptic/sonic-ui 0.1.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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/dist/define/dial.d.ts +2 -0
  4. package/dist/define/dial.js +8 -0
  5. package/dist/define/dial.js.map +1 -0
  6. package/dist/define/key.d.ts +2 -0
  7. package/dist/define/key.js +8 -0
  8. package/dist/define/key.js.map +1 -0
  9. package/dist/define/meter.d.ts +2 -0
  10. package/dist/define/meter.js +8 -0
  11. package/dist/define/meter.js.map +1 -0
  12. package/dist/define/segmented.d.ts +2 -0
  13. package/dist/define/segmented.js +8 -0
  14. package/dist/define/segmented.js.map +1 -0
  15. package/dist/define/slider.d.ts +2 -0
  16. package/dist/define/slider.js +8 -0
  17. package/dist/define/slider.js.map +1 -0
  18. package/dist/define.d.ts +11 -0
  19. package/dist/define.js +5 -0
  20. package/dist/elements/define-once.js +8 -0
  21. package/dist/elements/define-once.js.map +1 -0
  22. package/dist/elements/dial.d.ts +15 -0
  23. package/dist/elements/dial.js +57 -0
  24. package/dist/elements/dial.js.map +1 -0
  25. package/dist/elements/key.d.ts +17 -0
  26. package/dist/elements/key.js +99 -0
  27. package/dist/elements/key.js.map +1 -0
  28. package/dist/elements/meter.d.ts +17 -0
  29. package/dist/elements/meter.js +119 -0
  30. package/dist/elements/meter.js.map +1 -0
  31. package/dist/elements/range-element.d.ts +32 -0
  32. package/dist/elements/range-element.js +348 -0
  33. package/dist/elements/range-element.js.map +1 -0
  34. package/dist/elements/range-entry.js +73 -0
  35. package/dist/elements/range-entry.js.map +1 -0
  36. package/dist/elements/segmented.d.ts +17 -0
  37. package/dist/elements/segmented.js +104 -0
  38. package/dist/elements/segmented.js.map +1 -0
  39. package/dist/elements/slider.d.ts +15 -0
  40. package/dist/elements/slider.js +70 -0
  41. package/dist/elements/slider.js.map +1 -0
  42. package/dist/elements/sonic-element.d.ts +20 -0
  43. package/dist/elements/sonic-element.js +94 -0
  44. package/dist/elements/sonic-element.js.map +1 -0
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.js +7 -0
  47. package/dist/lib/read-px-property.js +9 -0
  48. package/dist/lib/read-px-property.js.map +1 -0
  49. package/dist/lib/render.js +19 -0
  50. package/dist/lib/render.js.map +1 -0
  51. package/dist/lib/taper.js +33 -0
  52. package/dist/lib/taper.js.map +1 -0
  53. package/dist/lib/write-attribute.js +12 -0
  54. package/dist/lib/write-attribute.js.map +1 -0
  55. package/dist/skins/ivory.css +8 -0
  56. package/dist/skins/lime.css +10 -0
  57. package/dist/skins/slate.css +10 -0
  58. package/dist/styles/controls.css +8 -0
  59. package/dist/styles/dial.css +265 -0
  60. package/dist/styles/key.css +137 -0
  61. package/dist/styles/material.css +229 -0
  62. package/dist/styles/meter.css +271 -0
  63. package/dist/styles/screen.css +47 -0
  64. package/dist/styles/segmented.css +147 -0
  65. package/dist/styles/slider.css +204 -0
  66. package/package.json +76 -0
@@ -0,0 +1,348 @@
1
+ import { RangeEntry } from "./range-entry.js";
2
+ import { writeAttribute } from "../lib/write-attribute.js";
3
+ import { SonicElement } from "./sonic-element.js";
4
+ import { requireChild } from "../lib/render.js";
5
+ import { clampUnit, linearTaper, logTaper, skewTaper } from "../lib/taper.js";
6
+
7
+ //#region src/elements/range-element.ts
8
+ const fineScale = .1;
9
+ const keyRevealMs = 1e3;
10
+ const pageSteps = 10;
11
+ const revealMs = 250;
12
+ const revealPx = 4;
13
+ const canPopover = "togglePopover" in HTMLElement.prototype;
14
+ let anchorCount = 0;
15
+ const resetKeys = /* @__PURE__ */ new Set(["Backspace", "Delete"]);
16
+ const keySteps = /* @__PURE__ */ new Map([
17
+ ["ArrowDown", -1],
18
+ ["ArrowLeft", -1],
19
+ ["ArrowRight", 1],
20
+ ["ArrowUp", 1],
21
+ ["PageDown", -10],
22
+ ["PageUp", pageSteps]
23
+ ]);
24
+ const sliderAttributes = [
25
+ "aria-disabled",
26
+ "aria-orientation",
27
+ "aria-valuemax",
28
+ "aria-valuemin",
29
+ "aria-valuenow",
30
+ "aria-valuetext",
31
+ "role",
32
+ "tabindex"
33
+ ];
34
+ var SonicRangeElement = class extends SonicElement {
35
+ static observedAttributes = [
36
+ ...SonicElement.observedAttributes,
37
+ "max",
38
+ "midpoint",
39
+ "min",
40
+ "notched",
41
+ "origin",
42
+ "readout",
43
+ "step",
44
+ "taper",
45
+ "value"
46
+ ];
47
+ get formatValue() {
48
+ return this.#formatValue;
49
+ }
50
+ set formatValue(format) {
51
+ this.#formatValue = format;
52
+ this.render();
53
+ }
54
+ get parseValue() {
55
+ return this.#parseValue;
56
+ }
57
+ set parseValue(parse) {
58
+ this.#parseValue = parse;
59
+ }
60
+ get value() {
61
+ return this.#value;
62
+ }
63
+ set value(next) {
64
+ if (this.#drag) return;
65
+ this.#write(next);
66
+ }
67
+ #anchor = `--sonic-readout-${String(anchorCount += 1)}`;
68
+ #drag;
69
+ #entry;
70
+ #formatValue;
71
+ #isDirty = false;
72
+ #keyRevealTimer;
73
+ #parseValue;
74
+ #readout;
75
+ #value = 0;
76
+ attributeChangedCallback(name) {
77
+ if (name === "value") {
78
+ if (this.#drag) return;
79
+ this.#isDirty = false;
80
+ }
81
+ if (name === "disabled" && this.disabled) {
82
+ this.#entry?.close(false);
83
+ this.#endDrag();
84
+ }
85
+ this.#value = this.#clamp(this.#isDirty ? this.#value : this.numberAttribute("value", this.min()));
86
+ this.render();
87
+ }
88
+ connectedCallback() {
89
+ this.upgradeProperty("formatValue");
90
+ this.upgradeProperty("parseValue");
91
+ this.upgradeProperty("value");
92
+ super.connectedCallback();
93
+ }
94
+ bindGestures(control, signal, grab) {
95
+ const entry = this.#bindEntry(control, signal);
96
+ control.addEventListener("pointerdown", (event) => {
97
+ if (event.button !== 0 || this.disabled || entry.isOpen) return;
98
+ control.focus();
99
+ if (event.metaKey || event.ctrlKey) {
100
+ this.#reset();
101
+ return;
102
+ }
103
+ const fromValue = this.#value;
104
+ const axis = grab(event);
105
+ if (!axis) return;
106
+ const startPosition = axis.position(event);
107
+ const drag = {
108
+ fromValue,
109
+ isRevealed: false,
110
+ lastPosition: startPosition,
111
+ pointerId: event.pointerId,
112
+ position: axis.position,
113
+ rawFraction: this.fraction(this.#value),
114
+ revealTimer: void 0,
115
+ startPosition,
116
+ travelPx: axis.travelPx
117
+ };
118
+ drag.revealTimer = setTimeout(() => {
119
+ this.#reveal(drag);
120
+ }, revealMs);
121
+ this.#drag = drag;
122
+ control.setPointerCapture(event.pointerId);
123
+ this.toggleState("dragging", true);
124
+ }, { signal });
125
+ control.addEventListener("pointermove", (event) => {
126
+ const drag = this.#drag;
127
+ if (event.pointerId !== drag?.pointerId) return;
128
+ const position = drag.position(event);
129
+ const scale = event.shiftKey ? fineScale : 1;
130
+ drag.rawFraction = clampUnit(drag.rawFraction + (position - drag.lastPosition) / drag.travelPx * scale);
131
+ drag.lastPosition = position;
132
+ if (Math.abs(position - drag.startPosition) >= revealPx) this.#reveal(drag);
133
+ this.input(this.valueAt(drag.rawFraction));
134
+ }, { signal });
135
+ const endDrag = (event) => {
136
+ if (event.pointerId === this.#drag?.pointerId) this.#endDrag();
137
+ };
138
+ control.addEventListener("pointercancel", (event) => {
139
+ endDrag(event);
140
+ entry.forgetPress();
141
+ }, { signal });
142
+ control.addEventListener("lostpointercapture", endDrag, { signal });
143
+ control.addEventListener("pointerup", (event) => {
144
+ if (event.pointerId !== this.#drag?.pointerId) return;
145
+ this.#endDrag();
146
+ if (!entry.press(event)) return;
147
+ if (this.getAttribute("double-press") === "reset") this.#reset();
148
+ else entry.open();
149
+ }, { signal });
150
+ this.#bindKeys(control, entry, signal);
151
+ signal.addEventListener("abort", () => {
152
+ this.#endDrag();
153
+ this.#hideForKeys();
154
+ }, { once: true });
155
+ }
156
+ clampRange(next) {
157
+ return Math.min(this.max(), Math.max(this.min(), next));
158
+ }
159
+ fraction(value) {
160
+ return (this.#taper() ?? linearTaper(this.min(), this.max())).position(value);
161
+ }
162
+ input(next) {
163
+ const previous = this.#value;
164
+ this.#write(next);
165
+ if (this.#value === previous) return false;
166
+ this.dispatchEvent(new Event("input", {
167
+ bubbles: true,
168
+ composed: true
169
+ }));
170
+ return true;
171
+ }
172
+ max() {
173
+ return Math.max(this.min(), this.numberAttribute("max", 100));
174
+ }
175
+ min() {
176
+ return this.numberAttribute("min", 0);
177
+ }
178
+ originFraction() {
179
+ return this.fraction(this.numberAttribute("origin", this.min()));
180
+ }
181
+ positions() {
182
+ const positions = Math.round(this.range() / this.#step()) + 1;
183
+ if (!this.hasAttribute("notched") || !Number.isFinite(positions) || positions < 2) return;
184
+ return positions;
185
+ }
186
+ range() {
187
+ return this.max() - this.min();
188
+ }
189
+ renderAria(control, orientation) {
190
+ if (this.#entry?.isOpen) {
191
+ for (const name of sliderAttributes) control.removeAttribute(name);
192
+ this.forwardNaming(control, false);
193
+ this.#renderReadout();
194
+ return;
195
+ }
196
+ control.setAttribute("role", "slider");
197
+ control.setAttribute("aria-valuemin", String(this.min()));
198
+ control.setAttribute("aria-valuemax", String(this.max()));
199
+ control.setAttribute("aria-valuenow", String(this.#value));
200
+ if (orientation) control.setAttribute("aria-orientation", orientation);
201
+ writeAttribute(control, "aria-valuetext", this.#formatValue?.(this.#value));
202
+ this.forwardNaming(control, true);
203
+ this.#renderDisabled(control);
204
+ this.#renderReadout();
205
+ }
206
+ valueAt(fraction) {
207
+ return (this.#taper() ?? linearTaper(this.min(), this.max())).value(fraction);
208
+ }
209
+ #bindEntry(control, signal) {
210
+ const input = requireChild(control, "input", HTMLInputElement);
211
+ const bubble = requireChild(control, "[popover]", HTMLElement);
212
+ this.#readout = {
213
+ bubble,
214
+ text: requireChild(bubble, "span", HTMLElement)
215
+ };
216
+ control.style.setProperty("anchor-name", this.#anchor);
217
+ bubble.style.setProperty("position-anchor", this.#anchor);
218
+ const entry = new RangeEntry(input, {
219
+ commit: (text) => {
220
+ this.#commit((this.#parseValue ?? Number.parseFloat)(text));
221
+ },
222
+ text: () => this.#parseValue ? this.#valueText() : String(this.#value),
223
+ toggle: (isOpen) => {
224
+ if (isOpen) this.forwardNaming(input, true);
225
+ this.toggleState("editing", isOpen);
226
+ this.render();
227
+ }
228
+ });
229
+ this.#entry = entry;
230
+ entry.bind(control, signal);
231
+ return entry;
232
+ }
233
+ #bindKeys(control, entry, signal) {
234
+ control.addEventListener("keydown", (event) => {
235
+ if (this.disabled || event.defaultPrevented || event.target !== control) return;
236
+ if (event.key === "Enter") {
237
+ event.preventDefault();
238
+ entry.open();
239
+ return;
240
+ }
241
+ const next = this.#keyTarget(event.key);
242
+ if (next === void 0) return;
243
+ event.preventDefault();
244
+ this.#commit(next);
245
+ this.#revealForKeys();
246
+ }, { signal });
247
+ control.addEventListener("blur", () => {
248
+ this.#hideForKeys();
249
+ }, { signal });
250
+ }
251
+ #clamp(next) {
252
+ const min = this.min();
253
+ const step = this.#step();
254
+ const stepped = step > 0 ? min + Math.round((next - min) / step) * step : next;
255
+ return this.clampRange(Number(stepped.toPrecision(12)));
256
+ }
257
+ #commit(next) {
258
+ if (this.input(next)) this.dispatchEvent(new Event("change", { bubbles: true }));
259
+ }
260
+ #endDrag() {
261
+ const drag = this.#drag;
262
+ if (!drag) return;
263
+ clearTimeout(drag.revealTimer);
264
+ this.#drag = void 0;
265
+ this.toggleState("dragging", false);
266
+ this.#renderReadout();
267
+ if (this.#value !== drag.fromValue) this.dispatchEvent(new Event("change", { bubbles: true }));
268
+ }
269
+ #hideForKeys() {
270
+ clearTimeout(this.#keyRevealTimer);
271
+ if (this.#keyRevealTimer === void 0) return;
272
+ this.#keyRevealTimer = void 0;
273
+ this.#renderReadout();
274
+ }
275
+ #isValueShown() {
276
+ return (this.#drag?.isRevealed === true || this.#keyRevealTimer !== void 0) && this.hasAttribute("readout");
277
+ }
278
+ #keyTarget(key) {
279
+ if (key === "Home") return this.min();
280
+ if (key === "End") return this.max();
281
+ if (resetKeys.has(key)) return this.#resetValue();
282
+ const steps = keySteps.get(key);
283
+ if (steps === void 0) return void 0;
284
+ const step = this.#step() > 0 ? this.#step() : this.range() / 100;
285
+ const taper = this.#taper();
286
+ if (!taper) return this.#value + steps * step;
287
+ const next = this.#clamp(taper.value(taper.position(this.#value) + steps / 100));
288
+ return next === this.#value ? this.#value + Math.sign(steps) * step : next;
289
+ }
290
+ #renderDisabled(control) {
291
+ if (this.disabled) {
292
+ control.setAttribute("aria-disabled", "true");
293
+ control.removeAttribute("tabindex");
294
+ return;
295
+ }
296
+ control.removeAttribute("aria-disabled");
297
+ control.setAttribute("tabindex", "0");
298
+ }
299
+ #renderReadout() {
300
+ const readout = this.#readout;
301
+ if (!readout || !canPopover || !this.isConnected) return;
302
+ const isEditing = this.#entry?.isOpen === true;
303
+ readout.text.hidden = isEditing;
304
+ if (!isEditing) readout.text.textContent = this.#valueText();
305
+ readout.bubble.togglePopover(isEditing || this.#isValueShown());
306
+ }
307
+ #reset() {
308
+ this.#commit(this.numberAttribute("default", NaN));
309
+ }
310
+ #resetValue() {
311
+ const value = this.numberAttribute("default", NaN);
312
+ return Number.isFinite(value) ? value : void 0;
313
+ }
314
+ #reveal(drag) {
315
+ if (drag.isRevealed || this.#drag !== drag) return;
316
+ drag.isRevealed = true;
317
+ this.#renderReadout();
318
+ }
319
+ #revealForKeys() {
320
+ clearTimeout(this.#keyRevealTimer);
321
+ this.#keyRevealTimer = setTimeout(() => {
322
+ this.#hideForKeys();
323
+ }, keyRevealMs);
324
+ this.#renderReadout();
325
+ }
326
+ #step() {
327
+ return this.numberAttribute("step", 1);
328
+ }
329
+ #taper() {
330
+ if (this.hasAttribute("notched")) return void 0;
331
+ const min = this.min();
332
+ const max = this.max();
333
+ return (this.getAttribute("taper") === "log" ? logTaper(min, max) : void 0) ?? skewTaper(min, max, this.numberAttribute("midpoint", NaN));
334
+ }
335
+ #valueText() {
336
+ return this.#formatValue?.(this.#value) ?? String(this.#value);
337
+ }
338
+ #write(next) {
339
+ if (!Number.isFinite(next)) return;
340
+ this.#isDirty = true;
341
+ this.#value = this.#clamp(next);
342
+ this.render();
343
+ }
344
+ };
345
+
346
+ //#endregion
347
+ export { SonicRangeElement };
348
+ //# sourceMappingURL=range-element.js.map
@@ -0,0 +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 { RangeEntry } from '#elements/range-entry.ts';\nimport { SonicElement } from '#elements/sonic-element.ts';\nimport { requireChild } from '#lib/render.ts';\nimport { clampUnit, linearTaper, 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\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 anchorCount = 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 sliderAttributes = [\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 SonicElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicElement.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 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\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 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\treadonly #anchor = `--sonic-readout-${String((anchorCount += 1))}`;\n\n\t#drag: RangeDrag | undefined;\n\n\t#entry: RangeEntry | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\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.disabled) {\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\toverride connectedCallback(): void {\n\t\tthis.upgradeProperty('formatValue');\n\t\tthis.upgradeProperty('parseValue');\n\t\tthis.upgradeProperty('value');\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.disabled || entry.isOpen) return;\n\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\tdrag.rawFraction = clampUnit(\n\t\t\t\t\tdrag.rawFraction + ((position - drag.lastPosition) / drag.travelPx) * scale,\n\t\t\t\t);\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.getAttribute('double-press') === '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\treturn Math.min(this.max(), Math.max(this.min(), next));\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 max(): number {\n\t\treturn Math.max(this.min(), this.numberAttribute('max', 100));\n\t}\n\n\tprotected min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tprotected originFraction(): number {\n\t\treturn this.fraction(this.numberAttribute('origin', this.min()));\n\t}\n\n\tprotected positions(): number | undefined {\n\t\tconst positions = Math.round(this.range() / this.#step()) + 1;\n\n\t\tif (!this.hasAttribute('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\tprotected abstract render(): void;\n\n\tprotected renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tif (this.#entry?.isOpen) {\n\t\t\tfor (const name of sliderAttributes) 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', 'slider');\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 valueAt(fraction: number): number {\n\t\treturn (this.#taper() ?? linearTaper(this.min(), this.max())).value(fraction);\n\t}\n\n\t#bindEntry(control: HTMLElement, signal: AbortSignal): RangeEntry {\n\t\tconst input = requireChild(control, 'input', HTMLInputElement);\n\t\tconst bubble = requireChild(control, '[popover]', HTMLElement);\n\n\t\tthis.#readout = { bubble, text: requireChild(bubble, 'span', HTMLElement) };\n\t\tcontrol.style.setProperty('anchor-name', this.#anchor);\n\t\tbubble.style.setProperty('position-anchor', this.#anchor);\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.disabled || 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#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.hasAttribute('readout');\n\t}\n\n\t#keyTarget(key: string): number | undefined {\n\t\tif (key === 'Home') return this.min();\n\t\tif (key === 'End') return this.max();\n\t\tif (resetKeys.has(key)) return this.#resetValue();\n\n\t\tconst steps = keySteps.get(key);\n\t\tif (steps === undefined) return undefined;\n\n\t\tconst step = this.#step() > 0 ? this.#step() : this.range() / 100;\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#renderDisabled(control: HTMLElement): void {\n\t\tif (this.disabled) {\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.numberAttribute('default', NaN));\n\t}\n\n\t#resetValue(): number | undefined {\n\t\tconst value = this.numberAttribute('default', NaN);\n\n\t\treturn Number.isFinite(value) ? value : undefined;\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#step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\t// Notches are evenly spaced, so a notched control stays linear\n\t#taper(): Taper | undefined {\n\t\tif (this.hasAttribute('notched')) return undefined;\n\n\t\tconst min = this.min();\n\t\tconst max = this.max();\n\t\tconst log = this.getAttribute('taper') === 'log' ? logTaper(min, max) : undefined;\n\n\t\treturn log ?? skewTaper(min, max, this.numberAttribute('midpoint', NaN));\n\t}\n\n\t#valueText(): string {\n\t\treturn this.#formatValue?.(this.#value) ?? String(this.#value);\n\t}\n\n\t#write(next: number): void {\n\t\tif (!Number.isFinite(next)) return;\n\n\t\tthis.#isDirty = true;\n\t\tthis.#value = this.#clamp(next);\n\t\tthis.render();\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ //#region src/elements/range-entry.ts
2
+ const doublePressMs = 500;
3
+ const doublePressPx = 4;
4
+ function isDoublePress(previous, next) {
5
+ if (!previous) return false;
6
+ return next.time - previous.time < doublePressMs && Math.hypot(next.x - previous.x, next.y - previous.y) < doublePressPx;
7
+ }
8
+ var RangeEntry = class {
9
+ get isOpen() {
10
+ return this.#isOpen;
11
+ }
12
+ #input;
13
+ #isOpen = false;
14
+ #lastPress;
15
+ #options;
16
+ constructor(input, options) {
17
+ this.#input = input;
18
+ this.#options = options;
19
+ }
20
+ bind(control, signal) {
21
+ const input = this.#input;
22
+ input.addEventListener("keydown", (event) => {
23
+ if (event.isComposing || event.key !== "Enter" && event.key !== "Escape") return;
24
+ event.preventDefault();
25
+ this.close(event.key === "Enter");
26
+ control.focus();
27
+ }, { signal });
28
+ input.addEventListener("blur", () => {
29
+ this.close(true);
30
+ }, { signal });
31
+ for (const type of ["change", "input"]) input.addEventListener(type, (event) => {
32
+ event.stopPropagation();
33
+ }, { signal });
34
+ signal.addEventListener("abort", () => {
35
+ this.close(false);
36
+ }, { once: true });
37
+ }
38
+ close(isCommitting) {
39
+ if (!this.#isOpen) return;
40
+ this.#isOpen = false;
41
+ this.#input.hidden = true;
42
+ this.#options.toggle(false);
43
+ if (isCommitting) this.#options.commit(this.#input.value);
44
+ }
45
+ forgetPress() {
46
+ this.#lastPress = void 0;
47
+ }
48
+ open() {
49
+ const input = this.#input;
50
+ this.#isOpen = true;
51
+ input.value = this.#options.text();
52
+ input.hidden = false;
53
+ this.#options.toggle(true);
54
+ input.focus();
55
+ input.select();
56
+ }
57
+ press(event) {
58
+ const press = {
59
+ time: event.timeStamp,
60
+ x: event.clientX,
61
+ y: event.clientY
62
+ };
63
+ const previous = this.#lastPress;
64
+ this.#lastPress = press;
65
+ if (!isDoublePress(previous, press)) return false;
66
+ this.#lastPress = void 0;
67
+ return true;
68
+ }
69
+ };
70
+
71
+ //#endregion
72
+ export { RangeEntry };
73
+ //# sourceMappingURL=range-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"range-entry.js","names":[],"sources":["../../src/elements/range-entry.ts"],"sourcesContent":["interface Press {\n\ttime: number;\n\tx: number;\n\ty: number;\n}\n\ninterface RangeEntryOptions {\n\tcommit: (text: string) => void;\n\ttext: () => string;\n\ttoggle: (isOpen: boolean) => void;\n}\n\n// Not `dblclick`, which iOS may not deliver under `touch-action: none`\nconst doublePressMs = 500;\nconst doublePressPx = 4;\n\nfunction isDoublePress(previous: Press | undefined, next: Press): boolean {\n\tif (!previous) return false;\n\n\treturn (\n\t\tnext.time - previous.time < doublePressMs &&\n\t\tMath.hypot(next.x - previous.x, next.y - previous.y) < doublePressPx\n\t);\n}\n\nexport class RangeEntry {\n\tget isOpen(): boolean {\n\t\treturn this.#isOpen;\n\t}\n\n\treadonly #input: HTMLInputElement;\n\n\t#isOpen = false;\n\n\t#lastPress: Press | undefined;\n\n\treadonly #options: RangeEntryOptions;\n\n\tconstructor(input: HTMLInputElement, options: RangeEntryOptions) {\n\t\tthis.#input = input;\n\t\tthis.#options = options;\n\t}\n\n\tbind(control: HTMLElement, signal: AbortSignal): void {\n\t\tconst input = this.#input;\n\n\t\tinput.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.isComposing || (event.key !== 'Enter' && event.key !== 'Escape')) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.close(event.key === 'Enter');\n\t\t\t\tcontrol.focus();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tinput.addEventListener(\n\t\t\t'blur',\n\t\t\t() => {\n\t\t\t\tthis.close(true);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\n\t\t// The field's own events would reach the host's listeners as if the value had moved\n\t\tfor (const type of ['change', 'input']) {\n\t\t\tinput.addEventListener(\n\t\t\t\ttype,\n\t\t\t\t(event) => {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t}\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.close(false);\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t// Closes first, so the committed value renders with the control's role back in place\n\tclose(isCommitting: boolean): void {\n\t\tif (!this.#isOpen) return;\n\n\t\tthis.#isOpen = false;\n\t\tthis.#input.hidden = true;\n\t\tthis.#options.toggle(false);\n\t\tif (isCommitting) this.#options.commit(this.#input.value);\n\t}\n\n\tforgetPress(): void {\n\t\tthis.#lastPress = undefined;\n\t}\n\n\topen(): void {\n\t\tconst input = this.#input;\n\n\t\tthis.#isOpen = true;\n\t\tinput.value = this.#options.text();\n\t\tinput.hidden = false;\n\t\tthis.#options.toggle(true);\n\t\tinput.focus();\n\t\tinput.select();\n\t}\n\n\tpress(event: PointerEvent): boolean {\n\t\tconst press = { time: event.timeStamp, x: event.clientX, y: event.clientY };\n\t\tconst previous = this.#lastPress;\n\n\t\tthis.#lastPress = press;\n\t\tif (!isDoublePress(previous, press)) return false;\n\n\t\tthis.#lastPress = undefined;\n\n\t\treturn true;\n\t}\n}\n"],"mappings":";AAaA,MAAM,gBAAgB;AACtB,MAAM,gBAAgB;AAEtB,SAAS,cAAc,UAA6B,MAAsB;CACzE,IAAI,CAAC,UAAU,OAAO;CAEtB,OACC,KAAK,OAAO,SAAS,OAAO,iBAC5B,KAAK,MAAM,KAAK,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,CAAC,IAAI;AAEzD;AAEA,IAAa,aAAb,MAAwB;CACvB,IAAI,SAAkB;EACrB,OAAO,KAAK;CACb;CAEA,AAAS;CAET,UAAU;CAEV;CAEA,AAAS;CAET,YAAY,OAAyB,SAA4B;EAChE,KAAK,SAAS;EACd,KAAK,WAAW;CACjB;CAEA,KAAK,SAAsB,QAA2B;EACrD,MAAM,QAAQ,KAAK;EAEnB,MAAM,iBACL,YACC,UAAU;GACV,IAAI,MAAM,eAAgB,MAAM,QAAQ,WAAW,MAAM,QAAQ,UAAW;GAE5E,MAAM,eAAe;GACrB,KAAK,MAAM,MAAM,QAAQ,OAAO;GAChC,QAAQ,MAAM;EACf,GACA,EAAE,OAAO,CACV;EACA,MAAM,iBACL,cACM;GACL,KAAK,MAAM,IAAI;EAChB,GACA,EAAE,OAAO,CACV;EAGA,KAAK,MAAM,QAAQ,CAAC,UAAU,OAAO,GACpC,MAAM,iBACL,OACC,UAAU;GACV,MAAM,gBAAgB;EACvB,GACA,EAAE,OAAO,CACV;EAED,OAAO,iBACN,eACM;GACL,KAAK,MAAM,KAAK;EACjB,GACA,EAAE,MAAM,KAAK,CACd;CACD;CAGA,MAAM,cAA6B;EAClC,IAAI,CAAC,KAAK,SAAS;EAEnB,KAAK,UAAU;EACf,KAAK,OAAO,SAAS;EACrB,KAAK,SAAS,OAAO,KAAK;EAC1B,IAAI,cAAc,KAAK,SAAS,OAAO,KAAK,OAAO,KAAK;CACzD;CAEA,cAAoB;EACnB,KAAK,aAAa;CACnB;CAEA,OAAa;EACZ,MAAM,QAAQ,KAAK;EAEnB,KAAK,UAAU;EACf,MAAM,QAAQ,KAAK,SAAS,KAAK;EACjC,MAAM,SAAS;EACf,KAAK,SAAS,OAAO,IAAI;EACzB,MAAM,MAAM;EACZ,MAAM,OAAO;CACd;CAEA,MAAM,OAA8B;EACnC,MAAM,QAAQ;GAAE,MAAM,MAAM;GAAW,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ;EAC1E,MAAM,WAAW,KAAK;EAEtB,KAAK,aAAa;EAClB,IAAI,CAAC,cAAc,UAAU,KAAK,GAAG,OAAO;EAE5C,KAAK,aAAa;EAElB,OAAO;CACR;AACD"}
@@ -0,0 +1,17 @@
1
+ import { SonicElement } from "./sonic-element.js";
2
+ //#region src/elements/segmented.d.ts
3
+ declare global {
4
+ interface HTMLElementTagNameMap {
5
+ 'sonic-segmented': SonicSegmented;
6
+ }
7
+ }
8
+ export declare class SonicSegmented extends SonicElement {
9
+ #private;
10
+ static readonly observedAttributes: string[];
11
+ get value(): string;
12
+ set value(next: string);
13
+ attributeChangedCallback(name: string): void;
14
+ protected connect(signal: AbortSignal): void;
15
+ }
16
+ //#endregion
17
+ //# sourceMappingURL=segmented.d.ts.map
@@ -0,0 +1,104 @@
1
+ import { SonicElement } from "./sonic-element.js";
2
+ import { template } from "../lib/render.js";
3
+
4
+ //#region src/elements/segmented.ts
5
+ const renderSegmented = template(`<div class="sonic-segmented" role="radiogroup"></div>`, HTMLDivElement);
6
+ const renderSegment = template(`
7
+ <button class="sonic-segmented-segment" role="radio" type="button">
8
+ <span class="sonic-segmented-cap"></span>
9
+ </button>
10
+ `, HTMLButtonElement);
11
+ const keySteps = /* @__PURE__ */ new Map([
12
+ ["ArrowDown", 1],
13
+ ["ArrowLeft", -1],
14
+ ["ArrowRight", 1],
15
+ ["ArrowUp", -1]
16
+ ]);
17
+ function segmentValue(segment) {
18
+ return segment.querySelector("[data-sonic-value]")?.dataset.sonicValue;
19
+ }
20
+ var SonicSegmented = class extends SonicElement {
21
+ static observedAttributes = [...SonicElement.observedAttributes, "value"];
22
+ get value() {
23
+ return this.#value;
24
+ }
25
+ set value(next) {
26
+ this.#value = next;
27
+ this.#render();
28
+ }
29
+ #segmented = renderSegmented();
30
+ #value = "";
31
+ attributeChangedCallback(name) {
32
+ if (name === "value") this.#value = this.getAttribute("value") ?? "";
33
+ this.#render();
34
+ }
35
+ connect(signal) {
36
+ const segmented = this.#segmented;
37
+ this.upgradeProperty("value");
38
+ this.adoptChildren(() => {
39
+ const segments = [...this.querySelectorAll(":scope > [data-sonic-value]")];
40
+ const isReplaced = segmented.parentNode !== this;
41
+ if (isReplaced) segmented.replaceChildren();
42
+ for (const child of segments) {
43
+ const segment = renderSegment();
44
+ segment.firstElementChild?.append(child);
45
+ segmented.append(segment);
46
+ }
47
+ this.appendOnce(segmented);
48
+ if (isReplaced || segments.length > 0) this.#render();
49
+ }, signal);
50
+ this.#render();
51
+ this.checkStyles(segmented, "segmented.css");
52
+ segmented.addEventListener("click", (event) => {
53
+ const segment = this.#segmentOf(event.target);
54
+ if (segment) this.#select(segment);
55
+ }, { signal });
56
+ segmented.addEventListener("keydown", (event) => {
57
+ if (event.defaultPrevented) return;
58
+ const segment = this.#segmentOf(event.target);
59
+ const next = segment && this.#keyTarget(segment, event.key);
60
+ if (!next) return;
61
+ event.preventDefault();
62
+ this.#select(next);
63
+ next.focus();
64
+ }, { signal });
65
+ }
66
+ #keyTarget(segment, key) {
67
+ const segments = this.#segments();
68
+ if (key === "Home") return segments[0];
69
+ if (key === "End") return segments.at(-1);
70
+ const step = keySteps.get(key);
71
+ if (step === void 0) return void 0;
72
+ return segments[(segments.indexOf(segment) + step + segments.length) % segments.length];
73
+ }
74
+ #render() {
75
+ const segmented = this.#segmented;
76
+ const segments = this.#segments();
77
+ const checked = segments.find((segment) => segmentValue(segment) === this.#value);
78
+ const focusable = checked ?? segments[0];
79
+ for (const segment of segments) {
80
+ segment.disabled = this.disabled;
81
+ segment.setAttribute("aria-checked", String(segment === checked));
82
+ segment.tabIndex = segment === focusable ? 0 : -1;
83
+ }
84
+ this.forwardNaming(segmented, true);
85
+ }
86
+ #segmentOf(target) {
87
+ if (!(target instanceof Element)) return void 0;
88
+ const segment = target.closest(".sonic-segmented-segment");
89
+ return segment instanceof HTMLButtonElement && segment.parentElement === this.#segmented ? segment : void 0;
90
+ }
91
+ #segments() {
92
+ return [...this.#segmented.children].filter((child) => child instanceof HTMLButtonElement);
93
+ }
94
+ #select(segment) {
95
+ const next = segmentValue(segment);
96
+ if (next === void 0 || next === this.#value) return;
97
+ this.value = next;
98
+ this.dispatchEvent(new Event("change", { bubbles: true }));
99
+ }
100
+ };
101
+
102
+ //#endregion
103
+ export { SonicSegmented };
104
+ //# sourceMappingURL=segmented.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segmented.js","names":[],"sources":["../../src/elements/segmented.ts"],"sourcesContent":["import { SonicElement } from '#elements/sonic-element.ts';\nimport { template } from '#lib/render.ts';\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-segmented': SonicSegmented;\n\t}\n}\n\nconst renderSegmented = template(\n\t/* HTML */ `<div class=\"sonic-segmented\" role=\"radiogroup\"></div>`,\n\tHTMLDivElement,\n);\n\nconst renderSegment = template(\n\t/* HTML */ `\n\t\t<button class=\"sonic-segmented-segment\" role=\"radio\" type=\"button\">\n\t\t\t<span class=\"sonic-segmented-cap\"></span>\n\t\t</button>\n\t`,\n\tHTMLButtonElement,\n);\n\n// RTL is not mirrored\nconst keySteps = new Map([\n\t['ArrowDown', 1],\n\t['ArrowLeft', -1],\n\t['ArrowRight', 1],\n\t['ArrowUp', -1],\n]);\n\nfunction segmentValue(segment: Element): string | undefined {\n\treturn segment.querySelector<HTMLElement | SVGElement>('[data-sonic-value]')?.dataset.sonicValue;\n}\n\nexport class SonicSegmented extends SonicElement {\n\tstatic override readonly observedAttributes = [...SonicElement.observedAttributes, 'value'];\n\n\t// As on the range, the property never writes the `value` attribute back\n\tget value(): string {\n\t\treturn this.#value;\n\t}\n\n\tset value(next: string) {\n\t\tthis.#value = next;\n\t\tthis.#render();\n\t}\n\n\treadonly #segmented = renderSegmented();\n\n\t#value = '';\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (name === 'value') this.#value = this.getAttribute('value') ?? '';\n\t\tthis.#render();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst segmented = this.#segmented;\n\n\t\tthis.upgradeProperty('value');\n\t\tthis.adoptChildren(() => {\n\t\t\tconst segments = [...this.querySelectorAll(':scope > [data-sonic-value]')];\n\t\t\tconst isReplaced = segmented.parentNode !== this;\n\n\t\t\t// Arrivals after a replacement take the old options' place\n\t\t\tif (isReplaced) segmented.replaceChildren();\n\t\t\tfor (const child of segments) {\n\t\t\t\tconst segment = renderSegment();\n\n\t\t\t\tsegment.firstElementChild?.append(child);\n\t\t\t\tsegmented.append(segment);\n\t\t\t}\n\t\t\tthis.appendOnce(segmented);\n\t\t\tif (isReplaced || segments.length > 0) this.#render();\n\t\t}, signal);\n\t\tthis.#render();\n\t\tthis.checkStyles(segmented, 'segmented.css');\n\n\t\tsegmented.addEventListener(\n\t\t\t'click',\n\t\t\t(event) => {\n\t\t\t\tconst segment = this.#segmentOf(event.target);\n\t\t\t\tif (segment) this.#select(segment);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tsegmented.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tif (event.defaultPrevented) return;\n\n\t\t\t\tconst segment = this.#segmentOf(event.target);\n\t\t\t\tconst next = segment && this.#keyTarget(segment, event.key);\n\t\t\t\tif (!next) return;\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#select(next);\n\t\t\t\tnext.focus();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#keyTarget(segment: HTMLButtonElement, key: string): HTMLButtonElement | undefined {\n\t\tconst segments = this.#segments();\n\n\t\tif (key === 'Home') return segments[0];\n\t\tif (key === 'End') return segments.at(-1);\n\n\t\tconst step = keySteps.get(key);\n\t\tif (step === undefined) return undefined;\n\n\t\tconst index = segments.indexOf(segment) + step;\n\n\t\treturn segments[(index + segments.length) % segments.length];\n\t}\n\n\t#render(): void {\n\t\tconst segmented = this.#segmented;\n\t\tconst segments = this.#segments();\n\t\tconst checked = segments.find((segment) => segmentValue(segment) === this.#value);\n\t\tconst focusable = checked ?? segments[0];\n\n\t\tfor (const segment of segments) {\n\t\t\tsegment.disabled = this.disabled;\n\t\t\tsegment.setAttribute('aria-checked', String(segment === checked));\n\t\t\tsegment.tabIndex = segment === focusable ? 0 : -1;\n\t\t}\n\t\tthis.forwardNaming(segmented, true);\n\t}\n\n\t#segmentOf(target: EventTarget | null): HTMLButtonElement | undefined {\n\t\tif (!(target instanceof Element)) return undefined;\n\n\t\tconst segment = target.closest('.sonic-segmented-segment');\n\n\t\treturn segment instanceof HTMLButtonElement && segment.parentElement === this.#segmented\n\t\t\t? segment\n\t\t\t: undefined;\n\t}\n\n\t#segments(): Array<HTMLButtonElement> {\n\t\treturn [...this.#segmented.children].filter(\n\t\t\t(child): child is HTMLButtonElement => child instanceof HTMLButtonElement,\n\t\t);\n\t}\n\n\t#select(segment: HTMLButtonElement): void {\n\t\tconst next = segmentValue(segment);\n\t\tif (next === undefined || next === this.#value) return;\n\n\t\tthis.value = next;\n\t\tthis.dispatchEvent(new Event('change', { bubbles: true }));\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { SonicRangeElement } from "./range-element.js";
2
+ //#region src/elements/slider.d.ts
3
+ declare global {
4
+ interface HTMLElementTagNameMap {
5
+ 'sonic-slider': SonicSlider;
6
+ }
7
+ }
8
+ export declare class SonicSlider extends SonicRangeElement {
9
+ #private;
10
+ static readonly observedAttributes: string[];
11
+ protected connect(signal: AbortSignal): void;
12
+ protected render(): void;
13
+ }
14
+ //#endregion
15
+ //# sourceMappingURL=slider.d.ts.map