@xsynaptic/sonic-ui 0.16.0 → 0.18.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.
- package/CHANGELOG.md +20 -0
- package/README.md +112 -19
- package/dist/default/dat.js +1 -0
- package/dist/default/elements/button.js +2 -0
- package/dist/default/elements/dial.js +2 -0
- package/dist/default/elements/display-element.js +9 -7
- package/dist/default/elements/envelope.js +31 -72
- package/dist/default/elements/field-gesture.js +81 -0
- package/dist/default/elements/meter.js +4 -0
- package/dist/default/elements/position-group.js +42 -26
- package/dist/default/elements/radio-group.js +59 -56
- package/dist/default/elements/scale.js +3 -3
- package/dist/default/elements/slider.js +11 -13
- package/dist/default/elements/split.js +14 -13
- package/dist/default/elements/switch.js +31 -46
- package/dist/default/elements/toggle.js +20 -44
- package/dist/default/elements/value-element.js +65 -91
- package/dist/default/elements/value-gestures.js +22 -22
- package/dist/default/elements/wave-element.js +9 -12
- package/dist/default/elements/waveform.js +64 -249
- package/dist/default/elements/wavestrip.js +10 -5
- package/dist/default/elements/xy.js +67 -112
- package/dist/default/lib/canvas-surface.js +25 -0
- package/dist/default/lib/crossfade.js +1 -0
- package/dist/default/lib/envelope-curve.js +1 -0
- package/dist/default/lib/marker-rider.js +37 -14
- package/dist/default/lib/peaks-request.js +44 -0
- package/dist/default/lib/positions.js +58 -0
- package/dist/default/lib/scrub.js +12 -0
- package/dist/default/lib/value-model.js +62 -0
- package/dist/default/lib/waveform-scene.js +108 -0
- package/dist/default/lib/zoom-gesture.js +97 -1
- package/dist/dev/dat.d.ts +1 -0
- package/dist/dev/dat.js +1 -0
- package/dist/dev/dat.js.map +1 -1
- package/dist/dev/elements/button.d.ts +2 -0
- package/dist/dev/elements/button.js +2 -0
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.d.ts +2 -0
- package/dist/dev/elements/dial.js +2 -0
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/display-element.d.ts +5 -3
- package/dist/dev/elements/display-element.js +9 -7
- package/dist/dev/elements/display-element.js.map +1 -1
- package/dist/dev/elements/envelope.js +31 -72
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/field-gesture.js +82 -0
- package/dist/dev/elements/field-gesture.js.map +1 -0
- package/dist/dev/elements/meter.d.ts +10 -5
- package/dist/dev/elements/meter.js +4 -0
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/position-group.d.ts +12 -6
- package/dist/dev/elements/position-group.js +42 -26
- package/dist/dev/elements/position-group.js.map +1 -1
- package/dist/dev/elements/radio-group.d.ts +11 -7
- package/dist/dev/elements/radio-group.js +59 -56
- package/dist/dev/elements/radio-group.js.map +1 -1
- package/dist/dev/elements/scale.js +3 -3
- package/dist/dev/elements/scale.js.map +1 -1
- package/dist/dev/elements/slider.d.ts +4 -2
- package/dist/dev/elements/slider.js +11 -13
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/split.d.ts +1 -0
- package/dist/dev/elements/split.js +14 -13
- package/dist/dev/elements/split.js.map +1 -1
- package/dist/dev/elements/switch.d.ts +2 -2
- package/dist/dev/elements/switch.js +31 -46
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/toggle.js +20 -44
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +5 -5
- package/dist/dev/elements/value-element.js +65 -91
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/value-gestures.js +22 -22
- package/dist/dev/elements/value-gestures.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +7 -4
- package/dist/dev/elements/wave-element.js +9 -12
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +23 -22
- package/dist/dev/elements/waveform.js +64 -249
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.d.ts +5 -1
- package/dist/dev/elements/wavestrip.js +10 -5
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.js +67 -112
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +3 -2
- package/dist/dev/lib/canvas-surface.d.ts +1 -0
- package/dist/dev/lib/canvas-surface.js +25 -0
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/crossfade.d.ts +1 -0
- package/dist/dev/lib/crossfade.js +1 -0
- package/dist/dev/lib/crossfade.js.map +1 -1
- package/dist/dev/lib/envelope-curve.d.ts +1 -0
- package/dist/dev/lib/envelope-curve.js +1 -0
- package/dist/dev/lib/envelope-curve.js.map +1 -1
- package/dist/dev/lib/marker-rider.js +37 -14
- package/dist/dev/lib/marker-rider.js.map +1 -1
- package/dist/dev/lib/peaks-request.d.ts +5 -0
- package/dist/dev/lib/peaks-request.js +45 -0
- package/dist/dev/lib/peaks-request.js.map +1 -0
- package/dist/dev/lib/positions.d.ts +7 -0
- package/dist/dev/lib/positions.js +59 -0
- package/dist/dev/lib/positions.js.map +1 -0
- package/dist/dev/lib/scrub.d.ts +8 -0
- package/dist/dev/lib/scrub.js +13 -0
- package/dist/dev/lib/scrub.js.map +1 -0
- package/dist/dev/lib/time-regions.d.ts +1 -0
- package/dist/dev/lib/time-regions.js.map +1 -1
- package/dist/dev/lib/units.d.ts +8 -0
- package/dist/dev/lib/value-model.js +63 -0
- package/dist/dev/lib/value-model.js.map +1 -0
- package/dist/dev/lib/waveform-buckets.d.ts +1 -0
- package/dist/dev/lib/waveform-buckets.js.map +1 -1
- package/dist/dev/lib/waveform-scene.d.ts +11 -0
- package/dist/dev/lib/waveform-scene.js +109 -0
- package/dist/dev/lib/waveform-scene.js.map +1 -0
- package/dist/dev/lib/zoom-gesture.js +97 -1
- package/dist/dev/lib/zoom-gesture.js.map +1 -1
- package/dist/styles/button.css +16 -6
- package/dist/styles/waveform.css +12 -4
- package/package.json +1 -1
- package/dist/default/lib/asked-value.js +0 -21
- package/dist/default/lib/fill-watch.js +0 -29
- package/dist/dev/lib/asked-value.js +0 -22
- package/dist/dev/lib/asked-value.js.map +0 -1
- package/dist/dev/lib/fill-watch.js +0 -30
- package/dist/dev/lib/fill-watch.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.js","names":[],"sources":["../../../src/elements/toggle.ts"],"sourcesContent":["import type { ToggleTravel } from '#lib/toggle-travel.ts';\n\nimport { SonicPositionGroupElement } from '#elements/position-group.ts';\nimport { isUnder, optionValue } from '#elements/radio-group.ts';\nimport { dragThresholdPx } from '#lib/drag-step.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { placeChildren, requireChild, template } from '#lib/render.ts';\nimport { positionAt, travelFrom } from '#lib/toggle-travel.ts';\n\n// eslint-disable-next-line unicorn/consistent-boolean-name -- the name bundlers and other kits use\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-toggle': SonicToggle;\n\t}\n}\n\n// fallow-ignore-next-line code-duplication -- each control draws its own parts\nconst renderToggle = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-toggle\">\n\t\t\t<span aria-hidden=\"true\" class=\"sonic-toggle-well\"></span>\n\t\t\t<span aria-hidden=\"true\" class=\"sonic-toggle-cap\"></span>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nconst renderPosition = template(\n\t/* HTML */ `\n\t\t<button class=\"sonic-toggle-position\" role=\"radio\" type=\"button\">\n\t\t\t<span class=\"sonic-toggle-legend\"></span>\n\t\t</button>\n\t`,\n\tHTMLButtonElement,\n);\n\nconst renderBare = template(\n\t/* HTML */ `<button class=\"sonic-toggle-position\" role=\"switch\" type=\"button\"></button>`,\n\tHTMLButtonElement,\n);\n\ninterface CapDrag {\n\thasMoved: boolean;\n\tisHolding: boolean;\n\tposition: HTMLButtonElement | undefined;\n\tstart: number;\n\tthresholdPx: number;\n\ttravel: ToggleTravel;\n}\n\nexport class SonicToggle extends SonicPositionGroupElement {\n\tprotected readonly bare = renderBare();\n\n\tprotected readonly defaultOrientation = 'horizontal';\n\n\tprotected readonly group = renderToggle();\n\n\treadonly #cap = requireChild(this.group, '.sonic-toggle-cap', HTMLSpanElement);\n\n\t#draggedTo: number | undefined;\n\n\t#hasWarnedOfLegends = false;\n\n\treadonly #well = requireChild(this.group, '.sonic-toggle-well', HTMLSpanElement);\n\n\t// Every press is the toggle's own, so the base's slide-off never starts\n\tprotected override claimPress(): boolean {\n\t\treturn true;\n\t}\n\n\tprotected override connect(signal: AbortSignal): void {\n\t\tsuper.connect(signal);\n\t\tthis.checkStyles(this.group, 'toggle.css', ['cap', 'well', 'keycap']);\n\t\tthis.bare.addEventListener(\n\t\t\t'click',\n\t\t\t(event) => {\n\t\t\t\t// A pointer's press is taken on its release, before the click it sends\n\t\t\t\tif (event instanceof PointerEvent && event.pointerType !== '') return;\n\n\t\t\t\tthis.setChecked(!this.checked);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindCap(signal);\n\t}\n\n\tprotected override isMirrored(child: Node): boolean {\n\t\treturn super.isMirrored(child) || child === this.#fixedLegend();\n\t}\n\n\tprotected override placeCopies(copies: Array<Node>): void {\n\t\tconst positions = copies.filter((copy) => super.isMirrored(copy));\n\n\t\tplaceChildren(\n\t\t\tthis.#cap,\n\t\t\tcopies.filter((copy) => !positions.includes(copy)),\n\t\t);\n\t\tsuper.placeCopies(positions);\n\t}\n\n\tprotected override render(): void {\n\t\tif (!this.isBound()) return;\n\n\t\tif (__DEV__) this.#checkLegends();\n\t\tthis.group.style.setProperty('--_sonic-toggle-count', String(this.#stopCount()));\n\t\tthis.#placeCap(this.#draggedTo ?? this.#restingAt());\n\t\tsuper.render();\n\t\tfor (const [index, option] of this.options().entries()) {\n\t\t\toption.style.setProperty('--_sonic-toggle-index', String(index));\n\t\t}\n\t}\n\n\tprotected renderOption(): HTMLButtonElement {\n\t\treturn renderPosition();\n\t}\n\n\t#bindCap(signal: AbortSignal): void {\n\t\tbindDrag<CapDrag>(\n\t\t\tthis.group,\n\t\t\t{\n\t\t\t\tgrab: (event) => this.#grab(event),\n\t\t\t\tlift: (drag, event) => {\n\t\t\t\t\tif (drag.hasMoved || drag.isHolding || this.isDisabled()) return;\n\t\t\t\t\tif (!isUnder(this.group, event.clientX, event.clientY)) return;\n\n\t\t\t\t\tthis.#press(drag.position);\n\t\t\t\t},\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\t// A held finger wobbles, and a drag back across halfway would let go\n\t\t\t\t\tif (drag.isHolding || this.isDisabled()) return;\n\t\t\t\t\tconst pointer = this.along(event);\n\t\t\t\t\tif (!drag.hasMoved && Math.abs(pointer - drag.start) < drag.thresholdPx) return;\n\n\t\t\t\t\tdrag.hasMoved = true;\n\t\t\t\t\tthis.toggleState('dragging', true);\n\t\t\t\t\tthis.#slideTo(positionAt(drag.travel, pointer), event.pointerId);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tdelete (drag.position ?? this.bare).dataset.sonicPressed;\n\t\t\t\t\tthis.#draggedTo = undefined;\n\t\t\t\t\tthis.toggleState('dragging', false);\n\t\t\t\t\tthis.render();\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#checkLegends(): void {\n\t\tif (!__DEV__ || this.#hasWarnedOfLegends) return;\n\n\t\tconst count = this.options().length;\n\t\tif (count <= 3 || this.getAttribute('legends') !== 'outside') return;\n\n\t\tthis.#hasWarnedOfLegends = true;\n\t\tconsole.warn(\n\t\t\t`<sonic-toggle> lays out legends=\"outside\" for two or three positions, and this one has ${String(count)}`,\n\t\t);\n\t}\n\n\t#enabledEnds(): [number, number] {\n\t\tif (this.isBare()) return [0, 1];\n\n\t\tconst options = this.options();\n\t\tconst isEnabled = (option: HTMLButtonElement): boolean => !this.isOptionDisabled(option);\n\n\t\treturn [options.findIndex(isEnabled), options.findLastIndex(isEnabled)];\n\t}\n\n\t#fixedLegend(): Element | undefined {\n\t\treturn [...this.children].find((child) => child !== this.group && !super.isMirrored(child));\n\t}\n\n\t#grab(event: PointerEvent): CapDrag | undefined {\n\t\tconst position = this.optionOf(event.target);\n\t\tif (this.isDisabled() || (!position && event.target !== this.bare)) return undefined;\n\n\t\tconst isOnCap = isUnder(this.#cap, event.clientX, event.clientY);\n\t\tconst travel = this.#travel(event, isOnCap);\n\t\tif (!travel || this.#isBlocked(position, isOnCap)) return undefined;\n\n\t\t(position ?? this.bare).toggleAttribute('data-sonic-pressed', true);\n\n\t\treturn {\n\t\t\thasMoved: false,\n\t\t\tisHolding: this.#holdFrom(position, event.pointerId),\n\t\t\tposition,\n\t\t\tstart: this.along(event),\n\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\ttravel,\n\t\t};\n\t}\n\n\t#holdFrom(position: HTMLButtonElement | undefined, pointerId: number): boolean {\n\t\tconst target = position && this.pressTarget(position);\n\t\tif (!target || !this.isMomentary(target) || this.isOptionDisabled(target)) return false;\n\n\t\tthis.hold(target, pointerId);\n\n\t\treturn true;\n\t}\n\n\t#isBlocked(position: HTMLButtonElement | undefined, isOnCap: boolean): boolean {\n\t\treturn !isOnCap && position !== undefined && this.isOptionDisabled(position);\n\t}\n\n\t// On is up, as on hardware\n\t#onAt(): number {\n\t\treturn this.orientation === 'vertical' ? 0 : 1;\n\t}\n\n\t#placeCap(at: number): void {\n\t\tthis.group.style.setProperty('--_sonic-toggle-at', String(at));\n\t}\n\n\t#press(position: HTMLButtonElement | undefined): void {\n\t\tif (!position) {\n\t\t\tthis.setChecked(!this.checked);\n\t\t\treturn;\n\t\t}\n\n\t\tconst target = this.pressTarget(position);\n\t\tif (this.isOptionDisabled(target)) return;\n\n\t\tthis.select(target);\n\t\tthis.#refocus(target);\n\t}\n\n\t#refocus(position: HTMLButtonElement): void {\n\t\tif (this.group.matches(':focus-within')) position.focus();\n\t}\n\n\t#restingAt(): number {\n\t\tif (this.isBare()) return this.checked ? this.#onAt() : 1 - this.#onAt();\n\n\t\treturn Math.max(0, this.checkedIndex(this.options()));\n\t}\n\n\t#slideTo(at: number, pointerId: number): void {\n\t\tconst crossed = this.options()[Math.round(at)];\n\n\t\tthis.#draggedTo = at;\n\t\tthis.#placeCap(at);\n\t\tif (this.isBare()) {\n\t\t\tthis.setChecked(Math.round(at) === this.#onAt());\n\t\t\treturn;\n\t\t}\n\t\tif (!crossed || optionValue(crossed) === this.value) return;\n\n\t\tthis.releaseHold();\n\t\tif (this.isOptionDisabled(crossed) || optionValue(crossed) === this.value) return;\n\n\t\tif (this.isMomentary(crossed)) this.hold(crossed, pointerId);\n\t\telse this.select(crossed);\n\t\tthis.#refocus(crossed);\n\t}\n\n\t#stopCount(): number {\n\t\treturn this.options().length || 2;\n\t}\n\n\t#travel(event: PointerEvent, isOnCap: boolean): ToggleTravel | undefined {\n\t\tconst [first, last] = this.#enabledEnds();\n\t\tif (first < 0) return undefined;\n\n\t\tconst box = this.#well.getBoundingClientRect();\n\t\tconst [start, length, thickness] =\n\t\t\tthis.orientation === 'vertical'\n\t\t\t\t? [box.top, box.height, box.width]\n\t\t\t\t: [box.left, box.width, box.height];\n\n\t\treturn travelFrom({\n\t\t\tat: this.#restingAt(),\n\t\t\tcount: this.#stopCount(),\n\t\t\tfirst,\n\t\t\tisOnCap,\n\t\t\tlast,\n\t\t\tpointer: this.along(event),\n\t\t\twell: { length, start, thickness },\n\t\t});\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toggle.js","names":[],"sources":["../../../src/elements/toggle.ts"],"sourcesContent":["import type { ToggleTravel } from '#lib/toggle-travel.ts';\n\nimport { SonicPositionGroupElement } from '#elements/position-group.ts';\nimport { isUnder } from '#elements/radio-group.ts';\nimport { dragThresholdPx } from '#lib/drag-step.ts';\nimport { bindDrag } from '#lib/pointer-drag.ts';\nimport { enabledEnds } from '#lib/positions.ts';\nimport { placeChildren, requireChild, template } from '#lib/render.ts';\nimport { positionAt, travelFrom } from '#lib/toggle-travel.ts';\n\n// eslint-disable-next-line unicorn/consistent-boolean-name -- the name bundlers and other kits use\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-toggle': SonicToggle;\n\t}\n}\n\n// fallow-ignore-next-line code-duplication -- each control draws its own parts\nconst renderToggle = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-toggle\">\n\t\t\t<span aria-hidden=\"true\" class=\"sonic-toggle-well\"></span>\n\t\t\t<span aria-hidden=\"true\" class=\"sonic-toggle-cap\"></span>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nconst renderPosition = template(\n\t/* HTML */ `\n\t\t<button class=\"sonic-toggle-position\" role=\"radio\" type=\"button\">\n\t\t\t<span class=\"sonic-toggle-legend\"></span>\n\t\t</button>\n\t`,\n\tHTMLButtonElement,\n);\n\nconst renderBare = template(\n\t/* HTML */ `<button class=\"sonic-toggle-position\" role=\"switch\" type=\"button\"></button>`,\n\tHTMLButtonElement,\n);\n\ninterface CapDrag {\n\thasMoved: boolean;\n\tisHolding: boolean;\n\tmarked: HTMLButtonElement;\n\tposition: number;\n\tstart: number;\n\tthresholdPx: number;\n\ttravel: ToggleTravel;\n}\n\nexport class SonicToggle extends SonicPositionGroupElement {\n\tprotected readonly bare = renderBare();\n\n\tprotected readonly defaultOrientation = 'horizontal';\n\n\tprotected readonly group = renderToggle();\n\n\treadonly #cap = requireChild(this.group, '.sonic-toggle-cap', HTMLSpanElement);\n\n\t#draggedTo: number | undefined;\n\n\t#hasWarnedOfLegends = false;\n\n\treadonly #well = requireChild(this.group, '.sonic-toggle-well', HTMLSpanElement);\n\n\t// Every press is the toggle's own, so the base's slide-off never starts\n\tprotected override claimPress(): boolean {\n\t\treturn true;\n\t}\n\n\tprotected override connect(signal: AbortSignal): void {\n\t\tsuper.connect(signal);\n\t\tthis.checkStyles(this.group, 'toggle.css', ['cap', 'well', 'keycap']);\n\t\tthis.bare.addEventListener(\n\t\t\t'click',\n\t\t\t(event) => {\n\t\t\t\t// A pointer's press is taken on its release, before the click it sends\n\t\t\t\tif (event instanceof PointerEvent && event.pointerType !== '') return;\n\n\t\t\t\tthis.setChecked(!this.checked);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tthis.#bindCap(signal);\n\t}\n\n\tprotected override isMirrored(child: Node): boolean {\n\t\treturn super.isMirrored(child) || child === this.#fixedLegend();\n\t}\n\n\tprotected override placeCopies(copies: Array<Node>): void {\n\t\tconst positions = copies.filter((copy) => super.isMirrored(copy));\n\n\t\tplaceChildren(\n\t\t\tthis.#cap,\n\t\t\tcopies.filter((copy) => !positions.includes(copy)),\n\t\t);\n\t\tsuper.placeCopies(positions);\n\t}\n\n\tprotected override render(): void {\n\t\tif (!this.isBound()) return;\n\n\t\tif (__DEV__) this.#checkLegends();\n\t\tthis.group.style.setProperty('--_sonic-toggle-count', String(this.positions().length));\n\t\tthis.#placeCap(this.#draggedTo ?? this.#restingAt());\n\t\tsuper.render();\n\t\tfor (const [index, option] of this.options().entries()) {\n\t\t\toption.style.setProperty('--_sonic-toggle-index', String(index));\n\t\t}\n\t}\n\n\tprotected renderOption(): HTMLButtonElement {\n\t\treturn renderPosition();\n\t}\n\n\t#bindCap(signal: AbortSignal): void {\n\t\tbindDrag<CapDrag>(\n\t\t\tthis.group,\n\t\t\t{\n\t\t\t\tgrab: (event) => this.#grab(event),\n\t\t\t\tlift: (drag, event) => {\n\t\t\t\t\tif (drag.hasMoved || drag.isHolding || this.isDisabled()) return;\n\t\t\t\t\tif (!isUnder(this.group, event.clientX, event.clientY)) return;\n\n\t\t\t\t\tthis.#press(drag.position);\n\t\t\t\t},\n\t\t\t\tmove: (drag, event) => {\n\t\t\t\t\t// A held finger wobbles, and a drag back across halfway would let go\n\t\t\t\t\tif (drag.isHolding || this.isDisabled()) return;\n\t\t\t\t\tconst pointer = this.along(event);\n\t\t\t\t\tif (!drag.hasMoved && Math.abs(pointer - drag.start) < drag.thresholdPx) return;\n\n\t\t\t\t\tdrag.hasMoved = true;\n\t\t\t\t\tthis.toggleState('dragging', true);\n\t\t\t\t\tthis.#slideTo(positionAt(drag.travel, pointer), event.pointerId);\n\t\t\t\t},\n\t\t\t\trelease: (drag) => {\n\t\t\t\t\tdelete drag.marked.dataset.sonicPressed;\n\t\t\t\t\tthis.#draggedTo = undefined;\n\t\t\t\t\tthis.toggleState('dragging', false);\n\t\t\t\t\tthis.render();\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#checkLegends(): void {\n\t\tif (!__DEV__ || this.#hasWarnedOfLegends) return;\n\n\t\tconst count = this.options().length;\n\t\tif (count <= 3 || this.getAttribute('legends') !== 'outside') return;\n\n\t\tthis.#hasWarnedOfLegends = true;\n\t\tconsole.warn(\n\t\t\t`<sonic-toggle> lays out legends=\"outside\" for two or three positions, and this one has ${String(count)}`,\n\t\t);\n\t}\n\n\t#fixedLegend(): Element | undefined {\n\t\treturn [...this.children].find((child) => child !== this.group && !super.isMirrored(child));\n\t}\n\n\t#grab(event: PointerEvent): CapDrag | undefined {\n\t\tconst position = this.pressedIndex(event.target);\n\t\tif (this.isDisabled() || position < 0) return undefined;\n\n\t\tconst isOnCap = isUnder(this.#cap, event.clientX, event.clientY);\n\t\tconst travel = this.#travel(event, isOnCap);\n\t\tif (!travel || (!isOnCap && this.isOptionDisabled(position))) return undefined;\n\n\t\tconst marked = this.options()[position] ?? this.bare;\n\n\t\tmarked.toggleAttribute('data-sonic-pressed', true);\n\n\t\treturn {\n\t\t\thasMoved: false,\n\t\t\tisHolding: this.#holdFrom(position, event.pointerId),\n\t\t\tmarked,\n\t\t\tposition,\n\t\t\tstart: this.along(event),\n\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\ttravel,\n\t\t};\n\t}\n\n\t#holdFrom(position: number, pointerId: number): boolean {\n\t\tconst target = this.pressTarget(position);\n\t\tif (!this.isMomentary(target) || this.isOptionDisabled(target)) return false;\n\n\t\tthis.hold(target, pointerId);\n\n\t\treturn true;\n\t}\n\n\t#placeCap(at: number): void {\n\t\tthis.group.style.setProperty('--_sonic-toggle-at', String(at));\n\t}\n\n\t#press(position: number): void {\n\t\tconst target = this.pressTarget(position);\n\t\tif (this.isOptionDisabled(target)) return;\n\n\t\tthis.select(target);\n\t\tthis.refocusAt(target);\n\t}\n\n\t#restingAt(): number {\n\t\treturn Math.max(0, this.checkedIndex());\n\t}\n\n\t#slideTo(at: number, pointerId: number): void {\n\t\tconst crossed = Math.round(at);\n\n\t\tthis.#draggedTo = at;\n\t\tthis.#placeCap(at);\n\t\tif (this.isChecked(crossed)) return;\n\n\t\tthis.releaseHold();\n\t\tif (this.isOptionDisabled(crossed) || this.isChecked(crossed)) return;\n\n\t\tif (this.isMomentary(crossed)) this.hold(crossed, pointerId);\n\t\telse this.select(crossed);\n\t\tthis.refocusAt(crossed);\n\t}\n\n\t#travel(event: PointerEvent, isOnCap: boolean): ToggleTravel | undefined {\n\t\tconst [first, last] = enabledEnds(this.positions());\n\t\tif (first < 0) return undefined;\n\n\t\tconst box = this.#well.getBoundingClientRect();\n\t\tconst [start, length, thickness] =\n\t\t\tthis.orientation === 'vertical'\n\t\t\t\t? [box.top, box.height, box.width]\n\t\t\t\t: [box.left, box.width, box.height];\n\n\t\treturn travelFrom({\n\t\t\tat: this.#restingAt(),\n\t\t\tcount: this.positions().length,\n\t\t\tfirst,\n\t\t\tisOnCap,\n\t\t\tlast,\n\t\t\tpointer: this.along(event),\n\t\t\twell: { length, start, thickness },\n\t\t});\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SonicFormElement } from "./form-element.js";
|
|
2
2
|
import { ValueMapping } from "../lib/value-mapping.js";
|
|
3
3
|
import { ValueAxis } from "./value-gestures.js";
|
|
4
|
+
import { ScrubState } from "../lib/scrub.js";
|
|
4
5
|
//#region src/elements/value-element.d.ts
|
|
5
6
|
declare global {
|
|
6
7
|
interface HTMLElementEventMap {
|
|
@@ -50,11 +51,13 @@ export declare abstract class SonicValueElement extends SonicFormElement {
|
|
|
50
51
|
get parseValue(): ((text: string) => number) | undefined;
|
|
51
52
|
set parseValue(parse: ((text: string) => number) | undefined);
|
|
52
53
|
get pointerType(): string | undefined;
|
|
54
|
+
/** The values a stepped control stops at, spaced evenly along the travel whatever their spacing */
|
|
53
55
|
get positions(): Array<number> | undefined;
|
|
54
56
|
set positions(positions: Array<number> | undefined);
|
|
55
57
|
get readout(): boolean;
|
|
56
58
|
set readout(isShown: boolean);
|
|
57
59
|
get revealed(): boolean;
|
|
60
|
+
/** Rounds the value assistive technology hears, in value units; the value itself is untouched */
|
|
58
61
|
get spokenStep(): number | undefined;
|
|
59
62
|
set spokenStep(value: number | undefined);
|
|
60
63
|
get step(): number;
|
|
@@ -73,21 +76,18 @@ export declare abstract class SonicValueElement extends SonicFormElement {
|
|
|
73
76
|
protected controlRole(): 'slider' | 'spinbutton';
|
|
74
77
|
protected abstract draw(): void;
|
|
75
78
|
protected abstract focusTarget(): HTMLElement;
|
|
76
|
-
protected heldFrom(): number | undefined;
|
|
77
|
-
protected heldWrite(next: number): void;
|
|
78
|
-
protected holdChanged(): void;
|
|
79
79
|
protected input(next: number): boolean;
|
|
80
|
-
protected isRevealed(): boolean;
|
|
81
80
|
protected isWrapping(): boolean;
|
|
82
81
|
protected mapping(): ValueMapping;
|
|
83
82
|
protected originValue(): number;
|
|
84
|
-
protected playback(): number;
|
|
85
83
|
protected proportionsChanged(): void;
|
|
86
84
|
protected readoutValue(): number;
|
|
87
85
|
protected render(): void;
|
|
88
86
|
protected renderReadout(): void;
|
|
89
87
|
protected restoreState(state: string): void;
|
|
88
|
+
protected scrubChanged(): void;
|
|
90
89
|
protected scrubsKeyRepeat(): boolean;
|
|
90
|
+
protected scrubState(): ScrubState;
|
|
91
91
|
protected springTarget(): number | undefined;
|
|
92
92
|
protected tapTarget(): number | undefined;
|
|
93
93
|
protected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toNumber, trimFloat } from "../lib/math.js";
|
|
2
2
|
import { writeAttribute } from "../lib/write-attribute.js";
|
|
3
3
|
import { SonicFormElement } from "./form-element.js";
|
|
4
4
|
import { Readout } from "./readout.js";
|
|
5
5
|
import { readPxProperty } from "../lib/read-px-property.js";
|
|
6
6
|
import { parseNumberList } from "../lib/number-list.js";
|
|
7
|
-
import { valueMapping } from "../lib/value-mapping.js";
|
|
8
7
|
import { ValueGestures } from "./value-gestures.js";
|
|
9
|
-
import { moveTo, resnap, setAsked } from "../lib/asked-value.js";
|
|
10
8
|
import { bindHoverPreview } from "../lib/hover-preview.js";
|
|
9
|
+
import { createValueModel } from "../lib/value-model.js";
|
|
11
10
|
|
|
12
11
|
//#region src/elements/value-element.ts
|
|
13
12
|
const fallbackTravelPx = 160;
|
|
@@ -56,20 +55,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
56
55
|
input: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),
|
|
57
56
|
isDisabled: () => element.isDisabled(),
|
|
58
57
|
isHeld: () => element.#isHeld(),
|
|
59
|
-
|
|
60
|
-
element.#land = resolve;
|
|
61
|
-
},
|
|
62
|
-
limit: (bounds) => {
|
|
63
|
-
element.#limit = bounds;
|
|
64
|
-
},
|
|
65
|
-
mapping: () => element.mapping(),
|
|
66
|
-
value: () => element.#cell.value,
|
|
67
|
-
watch: (listener) => {
|
|
68
|
-
element.#watchers.add(listener);
|
|
69
|
-
return () => {
|
|
70
|
-
element.#watchers.delete(listener);
|
|
71
|
-
};
|
|
72
|
-
}
|
|
58
|
+
model: element.#model
|
|
73
59
|
});
|
|
74
60
|
}
|
|
75
61
|
get cancelling() {
|
|
@@ -177,6 +163,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
177
163
|
get pointerType() {
|
|
178
164
|
return this.#gestures?.pointerType();
|
|
179
165
|
}
|
|
166
|
+
/** The values a stepped control stops at, spaced evenly along the travel whatever their spacing */
|
|
180
167
|
get positions() {
|
|
181
168
|
return parseNumberList(this.getAttribute("positions"));
|
|
182
169
|
}
|
|
@@ -192,6 +179,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
192
179
|
get revealed() {
|
|
193
180
|
return this.hasState("revealed");
|
|
194
181
|
}
|
|
182
|
+
/** Rounds the value assistive technology hears, in value units; the value itself is untouched */
|
|
195
183
|
get spokenStep() {
|
|
196
184
|
return this.optionalNumberAttribute("spoken-step");
|
|
197
185
|
}
|
|
@@ -211,7 +199,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
211
199
|
this.reflect("taper", curve);
|
|
212
200
|
}
|
|
213
201
|
get value() {
|
|
214
|
-
return this.#
|
|
202
|
+
return this.#model.value;
|
|
215
203
|
}
|
|
216
204
|
set value(next) {
|
|
217
205
|
if (next === void 0 || next === null) {
|
|
@@ -220,18 +208,14 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
220
208
|
}
|
|
221
209
|
const value = toNumber(next);
|
|
222
210
|
if (this.#isHeld()) {
|
|
223
|
-
this
|
|
211
|
+
this.#writeHeld(value);
|
|
224
212
|
return;
|
|
225
213
|
}
|
|
226
|
-
if (
|
|
214
|
+
if (this.#model.write(value)) this.render();
|
|
227
215
|
}
|
|
228
216
|
get valueText() {
|
|
229
|
-
return this.#textFor(this.#
|
|
217
|
+
return this.#textFor(this.#model.value);
|
|
230
218
|
}
|
|
231
|
-
#cell = {
|
|
232
|
-
asked: void 0,
|
|
233
|
-
value: 0
|
|
234
|
-
};
|
|
235
219
|
#formatEntry;
|
|
236
220
|
#formatSpokenValue;
|
|
237
221
|
#formatValue;
|
|
@@ -239,25 +223,16 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
239
223
|
#heldAt;
|
|
240
224
|
#hover;
|
|
241
225
|
#instance = String(instanceCount += 1);
|
|
242
|
-
#
|
|
243
|
-
#limit;
|
|
244
|
-
#mapping;
|
|
226
|
+
#model = createValueModel(() => this.#spec());
|
|
245
227
|
#parseValue;
|
|
246
|
-
#positions;
|
|
247
228
|
#readout;
|
|
248
|
-
#watchers = /* @__PURE__ */ new Set();
|
|
249
229
|
attributeChangedCallback(name) {
|
|
250
|
-
this.#
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (this.#isHeld()) {
|
|
254
|
-
this.heldWrite(this.numberAttribute("value", this.min));
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
this.#cell.asked = void 0;
|
|
230
|
+
if (name === "value" && this.#isHeld()) {
|
|
231
|
+
this.#writeHeld(this.numberAttribute("value", this.min));
|
|
232
|
+
return;
|
|
258
233
|
}
|
|
259
234
|
if (name === "disabled" && this.isDisabled()) this.#gestures?.end();
|
|
260
|
-
|
|
235
|
+
this.#model.respec(this.numberAttribute("value", this.min), { forgetAsk: name === "value" });
|
|
261
236
|
if (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();
|
|
262
237
|
this.render();
|
|
263
238
|
}
|
|
@@ -287,26 +262,23 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
287
262
|
this.forwardNaming(target, isNamed);
|
|
288
263
|
},
|
|
289
264
|
hasEntry: () => this.entry !== "none",
|
|
290
|
-
holdChanged: () => {
|
|
291
|
-
this.#renderHold();
|
|
292
|
-
},
|
|
293
265
|
input: (next) => this.input(next),
|
|
294
266
|
isDisabled: () => this.isDisabled(),
|
|
295
267
|
keyStep: () => this.keyStep,
|
|
296
|
-
|
|
297
|
-
limit: () => this.#limit,
|
|
298
|
-
mapping: () => this.mapping(),
|
|
268
|
+
model: this.#model,
|
|
299
269
|
parse: (text) => (this.#parseValue ?? Number.parseFloat)(text),
|
|
300
270
|
render: () => {
|
|
301
271
|
this.render();
|
|
302
272
|
},
|
|
273
|
+
scrubChanged: () => {
|
|
274
|
+
this.#renderHold();
|
|
275
|
+
},
|
|
303
276
|
scrubsKeyRepeat: () => this.scrubsKeyRepeat(),
|
|
304
277
|
springTarget: () => this.springTarget(),
|
|
305
278
|
tapTarget: () => this.tapTarget(),
|
|
306
279
|
toggleState: (state, isOn) => {
|
|
307
280
|
this.toggleState(state, isOn);
|
|
308
|
-
}
|
|
309
|
-
value: () => this.#cell.value
|
|
281
|
+
}
|
|
310
282
|
}, control);
|
|
311
283
|
this.#gestures.bind(signal, grab);
|
|
312
284
|
control.addEventListener("pointerup", (event) => {
|
|
@@ -322,7 +294,7 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
322
294
|
dismiss: () => {
|
|
323
295
|
this.render();
|
|
324
296
|
},
|
|
325
|
-
isTaken: () => this.#isEditing() || this
|
|
297
|
+
isTaken: () => this.#isEditing() || this.#isRevealed(),
|
|
326
298
|
show: () => {
|
|
327
299
|
if (!this.readout) return;
|
|
328
300
|
this.renderReadout();
|
|
@@ -335,60 +307,32 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
335
307
|
controlRole() {
|
|
336
308
|
return "slider";
|
|
337
309
|
}
|
|
338
|
-
heldFrom() {
|
|
339
|
-
return this.#gestures?.heldFrom();
|
|
340
|
-
}
|
|
341
|
-
heldWrite(next) {
|
|
342
|
-
this.#heldAt = next;
|
|
343
|
-
}
|
|
344
|
-
holdChanged() {}
|
|
345
310
|
input(next) {
|
|
346
|
-
const previous = this.#
|
|
347
|
-
|
|
348
|
-
if (
|
|
349
|
-
if (this.#cell.value === previous) return false;
|
|
311
|
+
const previous = this.#model.value;
|
|
312
|
+
if (this.#model.input(next)) this.render();
|
|
313
|
+
if (this.#model.value === previous) return false;
|
|
350
314
|
this.dispatchEvent(new Event("input", {
|
|
351
315
|
bubbles: true,
|
|
352
316
|
composed: true
|
|
353
317
|
}));
|
|
354
318
|
return true;
|
|
355
319
|
}
|
|
356
|
-
isRevealed() {
|
|
357
|
-
return this.#gestures?.isRevealed() === true;
|
|
358
|
-
}
|
|
359
320
|
isWrapping() {
|
|
360
321
|
return false;
|
|
361
322
|
}
|
|
362
323
|
mapping() {
|
|
363
|
-
|
|
364
|
-
const { detent, midpoint } = this;
|
|
365
|
-
this.#mapping = valueMapping({
|
|
366
|
-
...detent === void 0 ? {} : { detent },
|
|
367
|
-
...this.#positions ? { positions: this.#positions } : {},
|
|
368
|
-
max: this.max,
|
|
369
|
-
...midpoint === void 0 ? {} : { midpoint },
|
|
370
|
-
isNotched: this.notched,
|
|
371
|
-
isWrapping: this.isWrapping(),
|
|
372
|
-
min: this.min,
|
|
373
|
-
step: this.step,
|
|
374
|
-
taper: this.taper
|
|
375
|
-
});
|
|
376
|
-
return this.#mapping;
|
|
324
|
+
return this.#model.mapping();
|
|
377
325
|
}
|
|
378
326
|
originValue() {
|
|
379
327
|
return this.origin ?? this.mapping().bounds[0];
|
|
380
328
|
}
|
|
381
|
-
playback() {
|
|
382
|
-
const from = this.heldFrom();
|
|
383
|
-
return from === void 0 ? this.#cell.value : this.#heldAt ?? from;
|
|
384
|
-
}
|
|
385
329
|
proportionsChanged() {}
|
|
386
330
|
readoutValue() {
|
|
387
|
-
return this.#shown().value ?? this.#
|
|
331
|
+
return this.#shown().value ?? this.#model.value;
|
|
388
332
|
}
|
|
389
333
|
render() {
|
|
390
334
|
if (this.isBound()) this.#renderControl();
|
|
391
|
-
|
|
335
|
+
this.#model.notify();
|
|
392
336
|
}
|
|
393
337
|
renderReadout() {
|
|
394
338
|
const readout = this.#readout;
|
|
@@ -404,16 +348,25 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
404
348
|
restoreState(state) {
|
|
405
349
|
this.value = Number(state);
|
|
406
350
|
}
|
|
351
|
+
scrubChanged() {}
|
|
407
352
|
scrubsKeyRepeat() {
|
|
408
353
|
return false;
|
|
409
354
|
}
|
|
355
|
+
scrubState() {
|
|
356
|
+
const from = this.#gestures?.scrubFrom();
|
|
357
|
+
return {
|
|
358
|
+
from,
|
|
359
|
+
isRevealed: this.#isRevealed(),
|
|
360
|
+
played: from === void 0 ? this.#model.value : this.#heldAt ?? from
|
|
361
|
+
};
|
|
362
|
+
}
|
|
410
363
|
springTarget() {}
|
|
411
364
|
tapTarget() {}
|
|
412
365
|
travelPx(control, property) {
|
|
413
366
|
return Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));
|
|
414
367
|
}
|
|
415
368
|
#entryText() {
|
|
416
|
-
const value = this.#
|
|
369
|
+
const value = this.#model.value;
|
|
417
370
|
if (this.#formatEntry) return this.#formatEntry(value);
|
|
418
371
|
if (!this.#parseValue) return String(value);
|
|
419
372
|
const text = this.valueText;
|
|
@@ -426,8 +379,11 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
426
379
|
#isHeld() {
|
|
427
380
|
return this.#gestures?.isHeld() === true;
|
|
428
381
|
}
|
|
382
|
+
#isRevealed() {
|
|
383
|
+
return this.#gestures?.isRevealed() === true;
|
|
384
|
+
}
|
|
429
385
|
#renderAria(control, orientation) {
|
|
430
|
-
this.writeFormValue(String(this.#
|
|
386
|
+
this.writeFormValue(String(this.#model.value), String(this.#model.value));
|
|
431
387
|
if (this.#isEditing()) {
|
|
432
388
|
for (const name of roleAttributes) control.removeAttribute(name);
|
|
433
389
|
this.forwardNaming(control, false);
|
|
@@ -446,9 +402,9 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
446
402
|
this.renderReadout();
|
|
447
403
|
}
|
|
448
404
|
#renderControl() {
|
|
449
|
-
if (this.#isEditing() || this
|
|
405
|
+
if (this.#isEditing() || this.#isRevealed()) this.#hover?.clear();
|
|
450
406
|
this.draw();
|
|
451
|
-
this.toggleState("at-origin", !this.isWrapping() && this.#
|
|
407
|
+
this.toggleState("at-origin", !this.isWrapping() && this.#model.value === this.mapping().snap(this.originValue()));
|
|
452
408
|
this.#renderAria(this.focusTarget(), this.controlOrientation());
|
|
453
409
|
}
|
|
454
410
|
#renderDisabled(control) {
|
|
@@ -458,30 +414,48 @@ var SonicValueElement = class extends SonicFormElement {
|
|
|
458
414
|
writeAttribute(control, "tabindex", isDisabled ? void 0 : stop);
|
|
459
415
|
}
|
|
460
416
|
#renderHold() {
|
|
461
|
-
if (this
|
|
417
|
+
if (this.#gestures?.scrubFrom() === void 0) this.#heldAt = void 0;
|
|
462
418
|
this.#hover?.restore();
|
|
463
419
|
this.renderReadout();
|
|
464
|
-
this.
|
|
420
|
+
this.scrubChanged();
|
|
465
421
|
}
|
|
466
422
|
#shown() {
|
|
467
423
|
if (this.#isEditing()) return {
|
|
468
424
|
isOpen: true,
|
|
469
425
|
value: void 0
|
|
470
426
|
};
|
|
471
|
-
const isRevealed = this
|
|
427
|
+
const isRevealed = this.#isRevealed();
|
|
472
428
|
const preview = isRevealed ? void 0 : this.#hover?.value();
|
|
473
429
|
return {
|
|
474
430
|
isOpen: (isRevealed || preview !== void 0) && this.readout,
|
|
475
|
-
value: preview ?? this.#
|
|
431
|
+
value: preview ?? this.#model.value
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
#spec() {
|
|
435
|
+
const { detent, midpoint, positions } = this;
|
|
436
|
+
return {
|
|
437
|
+
...detent === void 0 ? {} : { detent },
|
|
438
|
+
...positions ? { positions } : {},
|
|
439
|
+
max: this.max,
|
|
440
|
+
...midpoint === void 0 ? {} : { midpoint },
|
|
441
|
+
isNotched: this.notched,
|
|
442
|
+
isWrapping: this.isWrapping(),
|
|
443
|
+
min: this.min,
|
|
444
|
+
step: this.step,
|
|
445
|
+
taper: this.taper
|
|
476
446
|
};
|
|
477
447
|
}
|
|
478
448
|
#spokenNow() {
|
|
479
449
|
const step = this.spokenStep;
|
|
480
|
-
return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#
|
|
450
|
+
return step !== void 0 && step > 0 ? trimFloat(Math.round(this.#model.value / step) * step) : this.#model.value;
|
|
481
451
|
}
|
|
482
452
|
#textFor(value) {
|
|
483
453
|
return this.#formatValue?.(value) ?? String(value);
|
|
484
454
|
}
|
|
455
|
+
#writeHeld(next) {
|
|
456
|
+
this.#heldAt = next;
|
|
457
|
+
this.scrubChanged();
|
|
458
|
+
}
|
|
485
459
|
};
|
|
486
460
|
|
|
487
461
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"value-element.js","names":[],"sources":["../../../src/elements/value-element.ts"],"sourcesContent":["import type { ValueAxis } from '#elements/value-gestures.ts';\nimport type { AskedValue } from '#lib/asked-value.ts';\nimport type { HoverPreview } from '#lib/hover-preview.ts';\nimport type { ValueMapping } from '#lib/value-mapping.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { ValueGestures } from '#elements/value-gestures.ts';\nimport { moveTo, resnap, setAsked } from '#lib/asked-value.ts';\nimport { bindHoverPreview } from '#lib/hover-preview.ts';\nimport { clamp, toNumber, trimFloat } from '#lib/math.ts';\nimport { parseNumberList } from '#lib/number-list.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { valueMapping } from '#lib/value-mapping.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\n// eslint-disable-next-line unicorn/consistent-boolean-name -- the name bundlers and other kits use\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementEventMap {\n\t\t'sonic-hover': Event;\n\t\t'sonic-reveal': Event;\n\t}\n}\n\ninterface HoverBinding {\n\tcanShow?: () => boolean;\n\tplace: () => void;\n\tvalueAt: (event: PointerEvent) => number | undefined;\n}\n\nconst fallbackTravelPx = 160;\n\nlet instanceCount = 0;\n\nconst proportionAttributes = new Set(['max', 'midpoint', 'min', 'notched', 'positions', 'taper']);\n\nconst roleAttributes = [\n\t'aria-disabled',\n\t'aria-orientation',\n\t'aria-valuemax',\n\t'aria-valuemin',\n\t'aria-valuenow',\n\t'aria-valuetext',\n\t'role',\n\t'tabindex',\n];\n\ntype ValueLanding = (target: number, direction: -1 | 0 | 1) => number;\n\nexport interface ValueLink {\n\tinput: (next: number, isMover?: boolean) => boolean;\n\tisDisabled: () => boolean;\n\tisHeld: () => boolean;\n\tland: (resolve: undefined | ValueLanding) => void;\n\tlimit: (bounds: [number, number] | undefined) => void;\n\tmapping: () => ValueMapping;\n\tvalue: () => number;\n\twatch: (listener: () => void) => () => void;\n}\n\n// Filled from inside the class, so it reaches protected members and nothing lands on the element's public type\nlet link: (element: SonicValueElement) => ValueLink;\n\nexport function linkValue(element: SonicValueElement): ValueLink {\n\treturn link(element);\n}\n\nexport abstract class SonicValueElement extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'detent',\n\t\t'max',\n\t\t'midpoint',\n\t\t'min',\n\t\t'notched',\n\t\t'origin',\n\t\t'readout',\n\t\t'spoken-step',\n\t\t'step',\n\t\t'tabindex',\n\t\t'taper',\n\t\t'value',\n\t\t'positions',\n\t];\n\n\tstatic {\n\t\tlink = (element) => ({\n\t\t\tinput: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),\n\t\t\tisDisabled: () => element.isDisabled(),\n\t\t\tisHeld: () => element.#isHeld(),\n\t\t\tland: (resolve) => {\n\t\t\t\telement.#land = resolve;\n\t\t\t},\n\t\t\tlimit: (bounds) => {\n\t\t\t\telement.#limit = bounds;\n\t\t\t},\n\t\t\tmapping: () => element.mapping(),\n\t\t\tvalue: () => element.#cell.value,\n\t\t\twatch: (listener) => {\n\t\t\t\telement.#watchers.add(listener);\n\n\t\t\t\treturn () => {\n\t\t\t\t\telement.#watchers.delete(listener);\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tget cancelling(): boolean {\n\t\treturn this.hasState('cancelling');\n\t}\n\n\tget default(): number | undefined {\n\t\treturn this.optionalNumberAttribute('default');\n\t}\n\n\tset default(value: number | undefined) {\n\t\tthis.reflect('default', value);\n\t}\n\n\tget detent(): number | undefined {\n\t\treturn this.optionalNumberAttribute('detent');\n\t}\n\n\tset detent(value: number | undefined) {\n\t\tthis.reflect('detent', value);\n\t}\n\n\tget dimmed(): boolean {\n\t\treturn this.hasAttribute('dimmed');\n\t}\n\n\tset dimmed(isDimmed: boolean) {\n\t\tthis.reflect('dimmed', isDimmed);\n\t}\n\n\tget doublePress(): 'entry' | 'none' | 'reset' {\n\t\tconst gesture = this.getAttribute('double-press');\n\n\t\treturn gesture === 'none' || gesture === 'reset' ? gesture : 'entry';\n\t}\n\n\tset doublePress(gesture: 'entry' | 'none' | 'reset' | undefined) {\n\t\tthis.reflect('double-press', gesture);\n\t}\n\n\tget dragging(): boolean {\n\t\treturn this.hasState('dragging');\n\t}\n\n\tget entry(): 'none' | undefined {\n\t\treturn this.getAttribute('entry') === 'none' ? 'none' : undefined;\n\t}\n\n\tset entry(gesture: 'none' | undefined) {\n\t\tthis.reflect('entry', gesture);\n\t}\n\n\tget formatEntry(): ((value: number) => string) | undefined {\n\t\treturn this.#formatEntry;\n\t}\n\n\tset formatEntry(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatEntry = format;\n\t}\n\n\tget formatSpokenValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatSpokenValue;\n\t}\n\n\tset formatSpokenValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatSpokenValue = format;\n\t\tthis.render();\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 hoverValue(): number | undefined {\n\t\treturn this.#hover?.value();\n\t}\n\n\tget keyStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('key-step');\n\t}\n\n\tset keyStep(value: number | undefined) {\n\t\tthis.reflect('key-step', value);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 100);\n\t}\n\n\tset max(value: number | undefined) {\n\t\tthis.reflect('max', value);\n\t}\n\n\tget midpoint(): number | undefined {\n\t\treturn this.optionalNumberAttribute('midpoint');\n\t}\n\n\tset midpoint(value: number | undefined) {\n\t\tthis.reflect('midpoint', value);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tset min(value: number | undefined) {\n\t\tthis.reflect('min', value);\n\t}\n\n\tget notched(): boolean {\n\t\treturn this.hasAttribute('notched');\n\t}\n\n\tset notched(isNotched: boolean) {\n\t\tthis.reflect('notched', isNotched);\n\t}\n\n\tget origin(): number | undefined {\n\t\treturn this.optionalNumberAttribute('origin');\n\t}\n\n\tset origin(value: number | undefined) {\n\t\tthis.reflect('origin', value);\n\t}\n\n\tget parseValue(): ((text: string) => number) | undefined {\n\t\treturn this.#parseValue;\n\t}\n\n\tset parseValue(parse: ((text: string) => number) | undefined) {\n\t\tthis.#parseValue = parse;\n\t}\n\n\tget pointerType(): string | undefined {\n\t\treturn this.#gestures?.pointerType();\n\t}\n\n\tget positions(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('positions'));\n\t}\n\n\tset positions(positions: Array<number> | undefined) {\n\t\tthis.reflect('positions', positions?.join(' '));\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isShown: boolean) {\n\t\tthis.reflect('readout', isShown);\n\t}\n\n\tget revealed(): boolean {\n\t\treturn this.hasState('revealed');\n\t}\n\n\tget spokenStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('spoken-step');\n\t}\n\n\tset spokenStep(value: number | undefined) {\n\t\tthis.reflect('spoken-step', value);\n\t}\n\n\tget step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\tset step(value: number | undefined) {\n\t\tthis.reflect('step', value);\n\t}\n\n\tget taper(): 'linear' | 'log' {\n\t\treturn this.getAttribute('taper') === 'log' ? 'log' : 'linear';\n\t}\n\n\tset taper(curve: 'linear' | 'log' | undefined) {\n\t\tthis.reflect('taper', curve);\n\t}\n\n\tget value(): number {\n\t\treturn this.#cell.value;\n\t}\n\n\tset value(next: null | number | undefined) {\n\t\t// A framework removes a prop by setting the property to `undefined`\n\t\tif (next === undefined || next === null) {\n\t\t\tthis.formResetCallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = toNumber(next);\n\n\t\tif (this.#isHeld()) {\n\t\t\tthis.heldWrite(value);\n\t\t\treturn;\n\t\t}\n\n\t\tif (setAsked(this.#cell, this.mapping(), value)) this.render();\n\t}\n\n\tget valueText(): string {\n\t\treturn this.#textFor(this.#cell.value);\n\t}\n\n\treadonly #cell: AskedValue = { asked: undefined, value: 0 };\n\n\t#formatEntry: ((value: number) => string) | undefined;\n\n\t#formatSpokenValue: ((value: number) => string) | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\t#gestures: undefined | ValueGestures;\n\n\t#heldAt: number | undefined;\n\n\t#hover: HoverPreview | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t#land: undefined | ValueLanding;\n\n\t#limit: [number, number] | undefined;\n\n\t// Every attribute it reads is observed; a subclass adding an input to `isWrapping()` has to observe it\n\t#mapping: undefined | ValueMapping;\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#positions: Array<number> | undefined;\n\n\t#readout: undefined | { anchor: HTMLElement; bubble: Readout };\n\n\treadonly #watchers = new Set<() => void>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tthis.#mapping = undefined;\n\t\tthis.#positions = parseNumberList(this.getAttribute('positions'));\n\t\tif (name === 'value') {\n\t\t\tif (this.#isHeld()) {\n\t\t\t\tthis.heldWrite(this.numberAttribute('value', this.min));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.#cell.asked = undefined;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) this.#gestures?.end();\n\n\t\tresnap(this.#cell, this.mapping(), this.numberAttribute('value', this.min));\n\t\tif (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();\n\t\tthis.render();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(\n\t\t\t'default',\n\t\t\t'dimmed',\n\t\t\t'doublePress',\n\t\t\t'entry',\n\t\t\t'max',\n\t\t\t'midpoint',\n\t\t\t'min',\n\t\t\t'notched',\n\t\t\t'origin',\n\t\t\t'readout',\n\t\t\t'spokenStep',\n\t\t\t'step',\n\t\t\t'taper',\n\t\t\t'positions',\n\t\t\t'detent',\n\t\t\t'formatEntry',\n\t\t\t'formatValue',\n\t\t\t'formatSpokenValue',\n\t\t\t'keyStep',\n\t\t\t'parseValue',\n\t\t\t'value',\n\t\t);\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected abandonHold(): void {\n\t\tthis.#gestures?.abandon();\n\t}\n\n\tprotected bindGestures(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\tgrab: (event: PointerEvent) => undefined | ValueAxis,\n\t): void {\n\t\tconst bubble = control.querySelector<HTMLElement>('[popover]');\n\n\t\tif (bubble) this.#readout = { anchor: control, bubble: new Readout(bubble) };\n\t\tthis.#gestures = new ValueGestures(\n\t\t\t{\n\t\t\t\tdefault: () => this.default,\n\t\t\t\tdetent: () => this.detent,\n\t\t\t\tdispatch: (type) => {\n\t\t\t\t\tthis.dispatchEvent(new Event(type, { bubbles: true }));\n\t\t\t\t},\n\t\t\t\tdoublePress: () => this.doublePress,\n\t\t\t\tentryId: `sonic-entry-${this.#instance}`,\n\t\t\t\tentryText: () => this.#entryText(),\n\t\t\t\tforwardNaming: (target, isNamed) => {\n\t\t\t\t\tthis.forwardNaming(target, isNamed);\n\t\t\t\t},\n\t\t\t\thasEntry: () => this.entry !== 'none',\n\t\t\t\tholdChanged: () => {\n\t\t\t\t\tthis.#renderHold();\n\t\t\t\t},\n\t\t\t\tinput: (next) => this.input(next),\n\t\t\t\tisDisabled: () => this.isDisabled(),\n\t\t\t\tkeyStep: () => this.keyStep,\n\t\t\t\tland: (target, direction) => this.#land?.(target, direction) ?? target,\n\t\t\t\tlimit: () => this.#limit,\n\t\t\t\tmapping: () => this.mapping(),\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\tparse: (text) => (this.#parseValue ?? Number.parseFloat)(text),\n\t\t\t\trender: () => {\n\t\t\t\t\tthis.render();\n\t\t\t\t},\n\t\t\t\tscrubsKeyRepeat: () => this.scrubsKeyRepeat(),\n\t\t\t\tspringTarget: () => this.springTarget(),\n\t\t\t\ttapTarget: () => this.tapTarget(),\n\t\t\t\ttoggleState: (state, isOn) => {\n\t\t\t\t\tthis.toggleState(state, isOn);\n\t\t\t\t},\n\t\t\t\tvalue: () => this.#cell.value,\n\t\t\t},\n\t\t\tcontrol,\n\t\t);\n\t\tthis.#gestures.bind(signal, grab);\n\t\tcontrol.addEventListener(\n\t\t\t'pointerup',\n\t\t\t(event) => {\n\t\t\t\tthis.#hover?.lift(event);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\tprotected bindHover(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\t{ canShow = () => true, place, valueAt }: HoverBinding,\n\t): void {\n\t\tthis.#hover = bindHoverPreview(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tcanShow,\n\t\t\t\tchanged: () => {\n\t\t\t\t\tthis.dispatchEvent(new Event('sonic-hover', { bubbles: true }));\n\t\t\t\t},\n\t\t\t\tdismiss: () => {\n\t\t\t\t\tthis.render();\n\t\t\t\t},\n\t\t\t\tisTaken: () => this.#isEditing() || this.isRevealed(),\n\t\t\t\tshow: () => {\n\t\t\t\t\tif (!this.readout) return;\n\n\t\t\t\t\tthis.renderReadout();\n\t\t\t\t\tplace();\n\t\t\t\t},\n\t\t\t\tvalueAt,\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tprotected controlOrientation(): 'horizontal' | 'vertical' | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected abstract draw(): void;\n\n\tprotected abstract override focusTarget(): HTMLElement;\n\n\tprotected heldFrom(): number | undefined {\n\t\treturn this.#gestures?.heldFrom();\n\t}\n\n\tprotected heldWrite(next: number): void {\n\t\tthis.#heldAt = next;\n\t}\n\n\tprotected holdChanged(): void {\n\t\t// Only a subclass draws a hold\n\t}\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#cell.value;\n\n\t\tconst target = this.#limit ? clamp(next, ...this.#limit) : next;\n\n\t\tif (moveTo(this.#cell, this.mapping(), target)) this.render();\n\t\tif (this.#cell.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 isRevealed(): boolean {\n\t\treturn this.#gestures?.isRevealed() === true;\n\t}\n\n\tprotected isWrapping(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected mapping(): ValueMapping {\n\t\tif (this.#mapping) return this.#mapping;\n\n\t\tconst { detent, midpoint } = this;\n\n\t\tthis.#mapping = valueMapping({\n\t\t\t...(detent === undefined ? {} : { detent }),\n\t\t\t...(this.#positions ? { positions: this.#positions } : {}),\n\t\t\tmax: this.max,\n\t\t\t...(midpoint === undefined ? {} : { midpoint }),\n\t\t\tisNotched: this.notched,\n\t\t\tisWrapping: this.isWrapping(),\n\t\t\tmin: this.min,\n\t\t\tstep: this.step,\n\t\t\ttaper: this.taper,\n\t\t});\n\n\t\treturn this.#mapping;\n\t}\n\n\tprotected originValue(): number {\n\t\treturn this.origin ?? this.mapping().bounds[0];\n\t}\n\n\tprotected playback(): number {\n\t\tconst from = this.heldFrom();\n\n\t\treturn from === undefined ? this.#cell.value : (this.#heldAt ?? from);\n\t}\n\n\tprotected proportionsChanged(): void {\n\t\t// Runs when every proportion moves, never per input\n\t}\n\n\tprotected readoutValue(): number {\n\t\treturn this.#shown().value ?? this.#cell.value;\n\t}\n\n\tprotected render(): void {\n\t\tif (this.isBound()) this.#renderControl();\n\t\tfor (const listener of this.#watchers) listener();\n\t}\n\n\tprotected renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout) return;\n\n\t\tconst { isOpen, value } = this.#shown();\n\t\tconst text = value === undefined ? undefined : this.#textFor(value);\n\n\t\treadout.bubble.show({ anchor: readout.anchor, isOpen: isOpen && text !== '', text });\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected scrubsKeyRepeat(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected tapTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number {\n\t\treturn Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));\n\t}\n\n\t#entryText(): string {\n\t\tconst value = this.#cell.value;\n\n\t\tif (this.#formatEntry) return this.#formatEntry(value);\n\n\t\t// `Number.parseFloat` reads \"5 kHz\" as 5\n\t\tif (!this.#parseValue) return String(value);\n\n\t\tconst text = this.valueText;\n\n\t\tif (__DEV__ && !Number.isFinite(this.#parseValue(text))) {\n\t\t\tconsole.warn(\n\t\t\t\t`<${this.localName}> opens its entry with \"${text}\", which parseValue cannot read; set formatEntry`,\n\t\t\t);\n\t\t}\n\n\t\treturn text;\n\t}\n\n\t#isEditing(): boolean {\n\t\treturn this.#gestures?.isEditing() === true;\n\t}\n\n\t#isHeld(): boolean {\n\t\treturn this.#gestures?.isHeld() === true;\n\t}\n\n\t#renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tthis.writeFormValue(String(this.#cell.value), String(this.#cell.value));\n\t\tif (this.#isEditing()) {\n\t\t\tfor (const name of roleAttributes) control.removeAttribute(name);\n\t\t\tthis.forwardNaming(control, false);\n\t\t\tthis.renderReadout();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [low, high] = this.mapping().bounds;\n\n\t\twriteAttribute(control, 'role', this.controlRole());\n\t\twriteAttribute(control, 'aria-valuemin', String(low));\n\t\twriteAttribute(control, 'aria-valuemax', String(high));\n\t\twriteAttribute(control, 'aria-valuenow', String(this.#spokenNow()));\n\t\tif (orientation) writeAttribute(control, 'aria-orientation', orientation);\n\t\twriteAttribute(\n\t\t\tcontrol,\n\t\t\t'aria-valuetext',\n\t\t\t(this.#formatSpokenValue ?? this.#formatValue)?.(this.#spokenNow()),\n\t\t);\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.renderReadout();\n\t}\n\n\t#renderControl(): void {\n\t\t// A reveal or typed entry takes the readout from a hover\n\t\tif (this.#isEditing() || this.isRevealed()) this.#hover?.clear();\n\t\tthis.draw();\n\t\tthis.toggleState(\n\t\t\t'at-origin',\n\t\t\t!this.isWrapping() && this.#cell.value === this.mapping().snap(this.originValue()),\n\t\t);\n\t\tthis.#renderAria(this.focusTarget(), this.controlOrientation());\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tconst isDisabled = this.isDisabled();\n\n\t\twriteAttribute(control, 'aria-disabled', isDisabled ? 'true' : undefined);\n\t\t// The host is `display: contents`, so its tab stop is the control's\n\t\tconst stop = this.getAttribute('tabindex') === '-1' ? '-1' : '0';\n\n\t\twriteAttribute(control, 'tabindex', isDisabled ? undefined : stop);\n\t}\n\n\t#renderHold(): void {\n\t\tif (this.heldFrom() === undefined) this.#heldAt = undefined;\n\t\tthis.#hover?.restore();\n\t\tthis.renderReadout();\n\t\tthis.holdChanged();\n\t}\n\n\t#shown(): { isOpen: boolean; value: number | undefined } {\n\t\tif (this.#isEditing()) return { isOpen: true, value: undefined };\n\n\t\tconst isRevealed = this.isRevealed();\n\t\tconst preview = isRevealed ? undefined : this.#hover?.value();\n\n\t\treturn {\n\t\t\tisOpen: (isRevealed || preview !== undefined) && this.readout,\n\t\t\tvalue: preview ?? this.#cell.value,\n\t\t};\n\t}\n\n\t#spokenNow(): number {\n\t\tconst step = this.spokenStep;\n\n\t\treturn step !== undefined && step > 0\n\t\t\t? trimFloat(Math.round(this.#cell.value / step) * step)\n\t\t\t: this.#cell.value;\n\t}\n\n\t#textFor(value: number): string {\n\t\treturn this.#formatValue?.(value) ?? String(value);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"value-element.js","names":[],"sources":["../../../src/elements/value-element.ts"],"sourcesContent":["import type { ValueAxis } from '#elements/value-gestures.ts';\nimport type { HoverPreview } from '#lib/hover-preview.ts';\nimport type { ScrubState } from '#lib/scrub.ts';\nimport type { ValueMapping, ValueSpec } from '#lib/value-mapping.ts';\nimport type { ValueModel } from '#lib/value-model.ts';\n\nimport { SonicFormElement } from '#elements/form-element.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { ValueGestures } from '#elements/value-gestures.ts';\nimport { bindHoverPreview } from '#lib/hover-preview.ts';\nimport { toNumber, trimFloat } from '#lib/math.ts';\nimport { parseNumberList } from '#lib/number-list.ts';\nimport { readPxProperty } from '#lib/read-px-property.ts';\nimport { createValueModel } from '#lib/value-model.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\n// eslint-disable-next-line unicorn/consistent-boolean-name -- the name bundlers and other kits use\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementEventMap {\n\t\t'sonic-hover': Event;\n\t\t'sonic-reveal': Event;\n\t}\n}\n\ninterface HoverBinding {\n\tcanShow?: () => boolean;\n\tplace: () => void;\n\tvalueAt: (event: PointerEvent) => number | undefined;\n}\n\nconst fallbackTravelPx = 160;\n\nlet instanceCount = 0;\n\nconst proportionAttributes = new Set(['max', 'midpoint', 'min', 'notched', 'positions', 'taper']);\n\nconst roleAttributes = [\n\t'aria-disabled',\n\t'aria-orientation',\n\t'aria-valuemax',\n\t'aria-valuemin',\n\t'aria-valuenow',\n\t'aria-valuetext',\n\t'role',\n\t'tabindex',\n];\n\nexport interface ValueLink {\n\tinput: (next: number, isMover?: boolean) => boolean;\n\tisDisabled: () => boolean;\n\tisHeld: () => boolean;\n\tmodel: ValueModel;\n}\n\n// Filled from inside the class, so it reaches protected members and nothing lands on the element's public type\nlet link: (element: SonicValueElement) => ValueLink;\n\nexport function linkValue(element: SonicValueElement): ValueLink {\n\treturn link(element);\n}\n\nexport abstract class SonicValueElement extends SonicFormElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicFormElement.observedAttributes,\n\t\t'detent',\n\t\t'max',\n\t\t'midpoint',\n\t\t'min',\n\t\t'notched',\n\t\t'origin',\n\t\t'readout',\n\t\t'spoken-step',\n\t\t'step',\n\t\t'tabindex',\n\t\t'taper',\n\t\t'value',\n\t\t'positions',\n\t];\n\n\tstatic {\n\t\tlink = (element) => ({\n\t\t\tinput: (next, isMover = false) => (isMover || !element.#isHeld()) && element.input(next),\n\t\t\tisDisabled: () => element.isDisabled(),\n\t\t\tisHeld: () => element.#isHeld(),\n\t\t\tmodel: element.#model,\n\t\t});\n\t}\n\n\tget cancelling(): boolean {\n\t\treturn this.hasState('cancelling');\n\t}\n\n\tget default(): number | undefined {\n\t\treturn this.optionalNumberAttribute('default');\n\t}\n\n\tset default(value: number | undefined) {\n\t\tthis.reflect('default', value);\n\t}\n\n\tget detent(): number | undefined {\n\t\treturn this.optionalNumberAttribute('detent');\n\t}\n\n\tset detent(value: number | undefined) {\n\t\tthis.reflect('detent', value);\n\t}\n\n\tget dimmed(): boolean {\n\t\treturn this.hasAttribute('dimmed');\n\t}\n\n\tset dimmed(isDimmed: boolean) {\n\t\tthis.reflect('dimmed', isDimmed);\n\t}\n\n\tget doublePress(): 'entry' | 'none' | 'reset' {\n\t\tconst gesture = this.getAttribute('double-press');\n\n\t\treturn gesture === 'none' || gesture === 'reset' ? gesture : 'entry';\n\t}\n\n\tset doublePress(gesture: 'entry' | 'none' | 'reset' | undefined) {\n\t\tthis.reflect('double-press', gesture);\n\t}\n\n\tget dragging(): boolean {\n\t\treturn this.hasState('dragging');\n\t}\n\n\tget entry(): 'none' | undefined {\n\t\treturn this.getAttribute('entry') === 'none' ? 'none' : undefined;\n\t}\n\n\tset entry(gesture: 'none' | undefined) {\n\t\tthis.reflect('entry', gesture);\n\t}\n\n\tget formatEntry(): ((value: number) => string) | undefined {\n\t\treturn this.#formatEntry;\n\t}\n\n\tset formatEntry(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatEntry = format;\n\t}\n\n\tget formatSpokenValue(): ((value: number) => string) | undefined {\n\t\treturn this.#formatSpokenValue;\n\t}\n\n\tset formatSpokenValue(format: ((value: number) => string) | undefined) {\n\t\tthis.#formatSpokenValue = format;\n\t\tthis.render();\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 hoverValue(): number | undefined {\n\t\treturn this.#hover?.value();\n\t}\n\n\tget keyStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('key-step');\n\t}\n\n\tset keyStep(value: number | undefined) {\n\t\tthis.reflect('key-step', value);\n\t}\n\n\tget max(): number {\n\t\treturn this.numberAttribute('max', 100);\n\t}\n\n\tset max(value: number | undefined) {\n\t\tthis.reflect('max', value);\n\t}\n\n\tget midpoint(): number | undefined {\n\t\treturn this.optionalNumberAttribute('midpoint');\n\t}\n\n\tset midpoint(value: number | undefined) {\n\t\tthis.reflect('midpoint', value);\n\t}\n\n\tget min(): number {\n\t\treturn this.numberAttribute('min', 0);\n\t}\n\n\tset min(value: number | undefined) {\n\t\tthis.reflect('min', value);\n\t}\n\n\tget notched(): boolean {\n\t\treturn this.hasAttribute('notched');\n\t}\n\n\tset notched(isNotched: boolean) {\n\t\tthis.reflect('notched', isNotched);\n\t}\n\n\tget origin(): number | undefined {\n\t\treturn this.optionalNumberAttribute('origin');\n\t}\n\n\tset origin(value: number | undefined) {\n\t\tthis.reflect('origin', value);\n\t}\n\n\tget parseValue(): ((text: string) => number) | undefined {\n\t\treturn this.#parseValue;\n\t}\n\n\tset parseValue(parse: ((text: string) => number) | undefined) {\n\t\tthis.#parseValue = parse;\n\t}\n\n\tget pointerType(): string | undefined {\n\t\treturn this.#gestures?.pointerType();\n\t}\n\n\t/** The values a stepped control stops at, spaced evenly along the travel whatever their spacing */\n\tget positions(): Array<number> | undefined {\n\t\treturn parseNumberList(this.getAttribute('positions'));\n\t}\n\n\tset positions(positions: Array<number> | undefined) {\n\t\tthis.reflect('positions', positions?.join(' '));\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isShown: boolean) {\n\t\tthis.reflect('readout', isShown);\n\t}\n\n\tget revealed(): boolean {\n\t\treturn this.hasState('revealed');\n\t}\n\n\t/** Rounds the value assistive technology hears, in value units; the value itself is untouched */\n\tget spokenStep(): number | undefined {\n\t\treturn this.optionalNumberAttribute('spoken-step');\n\t}\n\n\tset spokenStep(value: number | undefined) {\n\t\tthis.reflect('spoken-step', value);\n\t}\n\n\tget step(): number {\n\t\treturn this.numberAttribute('step', 1);\n\t}\n\n\tset step(value: number | undefined) {\n\t\tthis.reflect('step', value);\n\t}\n\n\tget taper(): 'linear' | 'log' {\n\t\treturn this.getAttribute('taper') === 'log' ? 'log' : 'linear';\n\t}\n\n\tset taper(curve: 'linear' | 'log' | undefined) {\n\t\tthis.reflect('taper', curve);\n\t}\n\n\tget value(): number {\n\t\treturn this.#model.value;\n\t}\n\n\tset value(next: null | number | undefined) {\n\t\t// A framework removes a prop by setting the property to `undefined`\n\t\tif (next === undefined || next === null) {\n\t\t\tthis.formResetCallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = toNumber(next);\n\n\t\tif (this.#isHeld()) {\n\t\t\tthis.#writeHeld(value);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.#model.write(value)) this.render();\n\t}\n\n\tget valueText(): string {\n\t\treturn this.#textFor(this.#model.value);\n\t}\n\n\t#formatEntry: ((value: number) => string) | undefined;\n\n\t#formatSpokenValue: ((value: number) => string) | undefined;\n\n\t#formatValue: ((value: number) => string) | undefined;\n\n\t#gestures: undefined | ValueGestures;\n\n\t#heldAt: number | undefined;\n\n\t#hover: HoverPreview | undefined;\n\n\treadonly #instance = String((instanceCount += 1));\n\n\t// A subclass adding an input to `isWrapping()` has to observe it\n\treadonly #model = createValueModel(() => this.#spec());\n\n\t#parseValue: ((text: string) => number) | undefined;\n\n\t#readout: undefined | { anchor: HTMLElement; bubble: Readout };\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (name === 'value' && this.#isHeld()) {\n\t\t\tthis.#writeHeld(this.numberAttribute('value', this.min));\n\t\t\treturn;\n\t\t}\n\t\tif (name === 'disabled' && this.isDisabled()) this.#gestures?.end();\n\n\t\tthis.#model.respec(this.numberAttribute('value', this.min), { forgetAsk: name === 'value' });\n\t\tif (proportionAttributes.has(name) && this.isBound()) this.proportionsChanged();\n\t\tthis.render();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(\n\t\t\t'default',\n\t\t\t'dimmed',\n\t\t\t'doublePress',\n\t\t\t'entry',\n\t\t\t'max',\n\t\t\t'midpoint',\n\t\t\t'min',\n\t\t\t'notched',\n\t\t\t'origin',\n\t\t\t'readout',\n\t\t\t'spokenStep',\n\t\t\t'step',\n\t\t\t'taper',\n\t\t\t'positions',\n\t\t\t'detent',\n\t\t\t'formatEntry',\n\t\t\t'formatValue',\n\t\t\t'formatSpokenValue',\n\t\t\t'keyStep',\n\t\t\t'parseValue',\n\t\t\t'value',\n\t\t);\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected abandonHold(): void {\n\t\tthis.#gestures?.abandon();\n\t}\n\n\tprotected bindGestures(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\tgrab: (event: PointerEvent) => undefined | ValueAxis,\n\t): void {\n\t\tconst bubble = control.querySelector<HTMLElement>('[popover]');\n\n\t\tif (bubble) this.#readout = { anchor: control, bubble: new Readout(bubble) };\n\t\tthis.#gestures = new ValueGestures(\n\t\t\t{\n\t\t\t\tdefault: () => this.default,\n\t\t\t\tdetent: () => this.detent,\n\t\t\t\tdispatch: (type) => {\n\t\t\t\t\tthis.dispatchEvent(new Event(type, { bubbles: true }));\n\t\t\t\t},\n\t\t\t\tdoublePress: () => this.doublePress,\n\t\t\t\tentryId: `sonic-entry-${this.#instance}`,\n\t\t\t\tentryText: () => this.#entryText(),\n\t\t\t\tforwardNaming: (target, isNamed) => {\n\t\t\t\t\tthis.forwardNaming(target, isNamed);\n\t\t\t\t},\n\t\t\t\thasEntry: () => this.entry !== 'none',\n\t\t\t\tinput: (next) => this.input(next),\n\t\t\t\tisDisabled: () => this.isDisabled(),\n\t\t\t\tkeyStep: () => this.keyStep,\n\t\t\t\tmodel: this.#model,\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\tparse: (text) => (this.#parseValue ?? Number.parseFloat)(text),\n\t\t\t\trender: () => {\n\t\t\t\t\tthis.render();\n\t\t\t\t},\n\t\t\t\tscrubChanged: () => {\n\t\t\t\t\tthis.#renderHold();\n\t\t\t\t},\n\t\t\t\tscrubsKeyRepeat: () => this.scrubsKeyRepeat(),\n\t\t\t\tspringTarget: () => this.springTarget(),\n\t\t\t\ttapTarget: () => this.tapTarget(),\n\t\t\t\ttoggleState: (state, isOn) => {\n\t\t\t\t\tthis.toggleState(state, isOn);\n\t\t\t\t},\n\t\t\t},\n\t\t\tcontrol,\n\t\t);\n\t\tthis.#gestures.bind(signal, grab);\n\t\tcontrol.addEventListener(\n\t\t\t'pointerup',\n\t\t\t(event) => {\n\t\t\t\tthis.#hover?.lift(event);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\tprotected bindHover(\n\t\tcontrol: HTMLElement,\n\t\tsignal: AbortSignal,\n\t\t{ canShow = () => true, place, valueAt }: HoverBinding,\n\t): void {\n\t\tthis.#hover = bindHoverPreview(\n\t\t\tcontrol,\n\t\t\t{\n\t\t\t\tcanShow,\n\t\t\t\tchanged: () => {\n\t\t\t\t\tthis.dispatchEvent(new Event('sonic-hover', { bubbles: true }));\n\t\t\t\t},\n\t\t\t\tdismiss: () => {\n\t\t\t\t\tthis.render();\n\t\t\t\t},\n\t\t\t\tisTaken: () => this.#isEditing() || this.#isRevealed(),\n\t\t\t\tshow: () => {\n\t\t\t\t\tif (!this.readout) return;\n\n\t\t\t\t\tthis.renderReadout();\n\t\t\t\t\tplace();\n\t\t\t\t},\n\t\t\t\tvalueAt,\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tprotected controlOrientation(): 'horizontal' | 'vertical' | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected controlRole(): 'slider' | 'spinbutton' {\n\t\treturn 'slider';\n\t}\n\n\tprotected abstract draw(): void;\n\n\tprotected abstract override focusTarget(): HTMLElement;\n\n\tprotected input(next: number): boolean {\n\t\tconst previous = this.#model.value;\n\n\t\tif (this.#model.input(next)) this.render();\n\t\tif (this.#model.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 isWrapping(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected mapping(): ValueMapping {\n\t\treturn this.#model.mapping();\n\t}\n\n\tprotected originValue(): number {\n\t\treturn this.origin ?? this.mapping().bounds[0];\n\t}\n\n\tprotected proportionsChanged(): void {\n\t\t// Runs when every proportion moves, never per input\n\t}\n\n\tprotected readoutValue(): number {\n\t\treturn this.#shown().value ?? this.#model.value;\n\t}\n\n\tprotected render(): void {\n\t\tif (this.isBound()) this.#renderControl();\n\t\tthis.#model.notify();\n\t}\n\n\tprotected renderReadout(): void {\n\t\tconst readout = this.#readout;\n\t\tif (!readout) return;\n\n\t\tconst { isOpen, value } = this.#shown();\n\t\tconst text = value === undefined ? undefined : this.#textFor(value);\n\n\t\treadout.bubble.show({ anchor: readout.anchor, isOpen: isOpen && text !== '', text });\n\t}\n\n\tprotected restoreState(state: string): void {\n\t\tthis.value = Number(state);\n\t}\n\n\tprotected scrubChanged(): void {\n\t\t// Only a subclass draws a scrub\n\t}\n\n\tprotected scrubsKeyRepeat(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected scrubState(): ScrubState {\n\t\tconst from = this.#gestures?.scrubFrom();\n\n\t\treturn {\n\t\t\tfrom,\n\t\t\tisRevealed: this.#isRevealed(),\n\t\t\tplayed: from === undefined ? this.#model.value : (this.#heldAt ?? from),\n\t\t};\n\t}\n\n\tprotected springTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected tapTarget(): number | undefined {\n\t\treturn undefined;\n\t}\n\n\tprotected travelPx(control: HTMLElement, property: `--_sonic-${string}`): number {\n\t\treturn Math.max(1, readPxProperty(getComputedStyle(control), property, fallbackTravelPx));\n\t}\n\n\t#entryText(): string {\n\t\tconst value = this.#model.value;\n\n\t\tif (this.#formatEntry) return this.#formatEntry(value);\n\n\t\t// `Number.parseFloat` reads \"5 kHz\" as 5\n\t\tif (!this.#parseValue) return String(value);\n\n\t\tconst text = this.valueText;\n\n\t\tif (__DEV__ && !Number.isFinite(this.#parseValue(text))) {\n\t\t\tconsole.warn(\n\t\t\t\t`<${this.localName}> opens its entry with \"${text}\", which parseValue cannot read; set formatEntry`,\n\t\t\t);\n\t\t}\n\n\t\treturn text;\n\t}\n\n\t#isEditing(): boolean {\n\t\treturn this.#gestures?.isEditing() === true;\n\t}\n\n\t#isHeld(): boolean {\n\t\treturn this.#gestures?.isHeld() === true;\n\t}\n\n\t#isRevealed(): boolean {\n\t\treturn this.#gestures?.isRevealed() === true;\n\t}\n\n\t#renderAria(control: HTMLElement, orientation?: 'horizontal' | 'vertical'): void {\n\t\tthis.writeFormValue(String(this.#model.value), String(this.#model.value));\n\t\tif (this.#isEditing()) {\n\t\t\tfor (const name of roleAttributes) control.removeAttribute(name);\n\t\t\tthis.forwardNaming(control, false);\n\t\t\tthis.renderReadout();\n\t\t\treturn;\n\t\t}\n\n\t\tconst [low, high] = this.mapping().bounds;\n\n\t\twriteAttribute(control, 'role', this.controlRole());\n\t\twriteAttribute(control, 'aria-valuemin', String(low));\n\t\twriteAttribute(control, 'aria-valuemax', String(high));\n\t\twriteAttribute(control, 'aria-valuenow', String(this.#spokenNow()));\n\t\tif (orientation) writeAttribute(control, 'aria-orientation', orientation);\n\t\twriteAttribute(\n\t\t\tcontrol,\n\t\t\t'aria-valuetext',\n\t\t\t(this.#formatSpokenValue ?? this.#formatValue)?.(this.#spokenNow()),\n\t\t);\n\t\tthis.forwardNaming(control, true);\n\t\tthis.#renderDisabled(control);\n\t\tthis.renderReadout();\n\t}\n\n\t#renderControl(): void {\n\t\t// A reveal or typed entry takes the readout from a hover\n\t\tif (this.#isEditing() || this.#isRevealed()) this.#hover?.clear();\n\t\tthis.draw();\n\t\tthis.toggleState(\n\t\t\t'at-origin',\n\t\t\t!this.isWrapping() && this.#model.value === this.mapping().snap(this.originValue()),\n\t\t);\n\t\tthis.#renderAria(this.focusTarget(), this.controlOrientation());\n\t}\n\n\t#renderDisabled(control: HTMLElement): void {\n\t\tconst isDisabled = this.isDisabled();\n\n\t\twriteAttribute(control, 'aria-disabled', isDisabled ? 'true' : undefined);\n\t\t// The host is `display: contents`, so its tab stop is the control's\n\t\tconst stop = this.getAttribute('tabindex') === '-1' ? '-1' : '0';\n\n\t\twriteAttribute(control, 'tabindex', isDisabled ? undefined : stop);\n\t}\n\n\t#renderHold(): void {\n\t\tif (this.#gestures?.scrubFrom() === undefined) this.#heldAt = undefined;\n\t\tthis.#hover?.restore();\n\t\tthis.renderReadout();\n\t\tthis.scrubChanged();\n\t}\n\n\t#shown(): { isOpen: boolean; value: number | undefined } {\n\t\tif (this.#isEditing()) return { isOpen: true, value: undefined };\n\n\t\tconst isRevealed = this.#isRevealed();\n\t\tconst preview = isRevealed ? undefined : this.#hover?.value();\n\n\t\treturn {\n\t\t\tisOpen: (isRevealed || preview !== undefined) && this.readout,\n\t\t\tvalue: preview ?? this.#model.value,\n\t\t};\n\t}\n\n\t#spec(): ValueSpec {\n\t\tconst { detent, midpoint, positions } = this;\n\n\t\treturn {\n\t\t\t...(detent === undefined ? {} : { detent }),\n\t\t\t...(positions ? { positions } : {}),\n\t\t\tmax: this.max,\n\t\t\t...(midpoint === undefined ? {} : { midpoint }),\n\t\t\tisNotched: this.notched,\n\t\t\tisWrapping: this.isWrapping(),\n\t\t\tmin: this.min,\n\t\t\tstep: this.step,\n\t\t\ttaper: this.taper,\n\t\t};\n\t}\n\n\t#spokenNow(): number {\n\t\tconst step = this.spokenStep;\n\n\t\treturn step !== undefined && step > 0\n\t\t\t? trimFloat(Math.round(this.#model.value / step) * step)\n\t\t\t: this.#model.value;\n\t}\n\n\t#textFor(value: number): string {\n\t\treturn this.#formatValue?.(value) ?? String(value);\n\t}\n\n\t#writeHeld(next: number): void {\n\t\tthis.#heldAt = next;\n\t\tthis.scrubChanged();\n\t}\n}\n"],"mappings":"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"}
|