@xsynaptic/sonic-ui 0.24.1 → 0.25.1
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 +28 -2
- package/README.md +5 -3
- package/dist/default/define/region.js +7 -0
- package/dist/default/define.js +1 -0
- package/dist/default/elements/envelope.js +11 -11
- package/dist/default/elements/form-element.js +10 -0
- package/dist/default/elements/readout.js +1 -1
- package/dist/default/elements/region-layer.js +251 -0
- package/dist/default/elements/region.js +157 -0
- package/dist/default/elements/sonic-element.js +3 -0
- package/dist/default/elements/split.js +2 -2
- package/dist/default/elements/toggle.js +2 -2
- package/dist/default/elements/value-element.js +7 -3
- package/dist/default/elements/value-gestures.js +7 -5
- package/dist/default/elements/wave-element.js +12 -3
- package/dist/default/elements/waveform.js +38 -2
- package/dist/default/elements/wavestrip.js +90 -17
- package/dist/default/elements/xy.js +3 -11
- package/dist/default/index.js +2 -1
- package/dist/default/lib/clock.js +1 -0
- package/dist/default/lib/drag-step.js +1 -1
- package/dist/default/lib/marker-band.js +40 -29
- package/dist/default/lib/region-drag.js +48 -0
- package/dist/dev/define/region.d.ts +2 -0
- package/dist/dev/define/region.js +8 -0
- package/dist/dev/define/region.js.map +1 -0
- package/dist/dev/define.d.ts +3 -1
- package/dist/dev/define.js +1 -0
- package/dist/dev/elements/envelope.js +11 -11
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/form-element.d.ts +1 -0
- package/dist/dev/elements/form-element.js +10 -0
- package/dist/dev/elements/form-element.js.map +1 -1
- package/dist/dev/elements/readout.js +1 -1
- package/dist/dev/elements/readout.js.map +1 -1
- package/dist/dev/elements/region-layer.js +252 -0
- package/dist/dev/elements/region-layer.js.map +1 -0
- package/dist/dev/elements/region.d.ts +29 -0
- package/dist/dev/elements/region.js +165 -0
- package/dist/dev/elements/region.js.map +1 -0
- package/dist/dev/elements/sonic-element.d.ts +1 -0
- package/dist/dev/elements/sonic-element.js +4 -1
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/split.js +2 -2
- package/dist/dev/elements/split.js.map +1 -1
- package/dist/dev/elements/toggle.js +2 -2
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-element.d.ts +3 -1
- package/dist/dev/elements/value-element.js +7 -3
- package/dist/dev/elements/value-element.js.map +1 -1
- package/dist/dev/elements/value-gestures.js +7 -5
- package/dist/dev/elements/value-gestures.js.map +1 -1
- package/dist/dev/elements/wave-element.d.ts +7 -1
- package/dist/dev/elements/wave-element.js +12 -3
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +7 -0
- package/dist/dev/elements/waveform.js +38 -2
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/wavestrip.d.ts +17 -1
- package/dist/dev/elements/wavestrip.js +90 -17
- package/dist/dev/elements/wavestrip.js.map +1 -1
- package/dist/dev/elements/xy.js +3 -11
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/index.d.ts +3 -2
- package/dist/dev/index.js +2 -1
- package/dist/dev/lib/clock.js +1 -0
- package/dist/dev/lib/clock.js.map +1 -1
- package/dist/dev/lib/drag-step.js +1 -1
- package/dist/dev/lib/drag-step.js.map +1 -1
- package/dist/dev/lib/marker-band.d.ts +7 -0
- package/dist/dev/lib/marker-band.js +40 -29
- package/dist/dev/lib/marker-band.js.map +1 -1
- package/dist/dev/lib/region-drag.js +49 -0
- package/dist/dev/lib/region-drag.js.map +1 -0
- package/dist/styles/button.css +12 -4
- package/dist/styles/controls.css +1 -0
- package/dist/styles/dial.css +35 -18
- package/dist/styles/envelope.css +6 -5
- package/dist/styles/material/arc.css +2 -2
- package/dist/styles/material/cap.css +21 -11
- package/dist/styles/material/glass.css +1 -1
- package/dist/styles/material/groove.css +3 -3
- package/dist/styles/material/keycap.css +2 -2
- package/dist/styles/material/lens.css +1 -1
- package/dist/styles/material/pane.css +13 -5
- package/dist/styles/material/readout.css +4 -3
- package/dist/styles/material/{bracket.css → reticle.css} +15 -8
- package/dist/styles/material/well.css +2 -2
- package/dist/styles/material.css +1 -1
- package/dist/styles/meter.css +18 -5
- package/dist/styles/number.css +2 -1
- package/dist/styles/panel.css +3 -3
- package/dist/styles/region.css +88 -0
- package/dist/styles/ring.css +2 -1
- package/dist/styles/screen.css +7 -5
- package/dist/styles/segmented.css +2 -1
- package/dist/styles/slider.css +12 -3
- package/dist/styles/spectrum.css +9 -1
- package/dist/styles/switch.css +3 -2
- package/dist/styles/toggle.css +2 -1
- package/dist/styles/waveform.css +3 -2
- package/dist/styles/wavestrip.css +11 -8
- package/dist/styles/xy.css +9 -8
- package/package.json +3 -2
package/dist/dev/define.js
CHANGED
|
@@ -36,7 +36,7 @@ function stageParts(envelope, hook, stages) {
|
|
|
36
36
|
}
|
|
37
37
|
const renderEnvelope = template(`
|
|
38
38
|
<div class="sonic-envelope" aria-hidden="true">
|
|
39
|
-
<div class="sonic-envelope-
|
|
39
|
+
<div class="sonic-envelope-reticle"></div>
|
|
40
40
|
<svg class="sonic-envelope-graph" preserveAspectRatio="none" viewBox="0 0 1 1">
|
|
41
41
|
<path class="sonic-envelope-fill" />
|
|
42
42
|
<rect class="sonic-envelope-fill sonic-envelope-floor" y="1" />
|
|
@@ -123,11 +123,10 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
123
123
|
this.reflect("sustain", id);
|
|
124
124
|
}
|
|
125
125
|
#bindings = /* @__PURE__ */ new Map();
|
|
126
|
-
#envelope = renderEnvelope();
|
|
127
|
-
#bracket = requireChild(this.#envelope, ".sonic-envelope-bracket", HTMLDivElement);
|
|
128
126
|
#claim = new ReadoutClaim(() => {
|
|
129
127
|
this.#renderReadout();
|
|
130
128
|
});
|
|
129
|
+
#envelope = renderEnvelope();
|
|
131
130
|
#curveHandles = stageParts(this.#envelope, "sonic-envelope-curve", curveStages);
|
|
132
131
|
#fill = requireChild(this.#envelope, ".sonic-envelope-fill", SVGElement);
|
|
133
132
|
#floor = requireChild(this.#envelope, ".sonic-envelope-floor", SVGElement);
|
|
@@ -138,6 +137,7 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
138
137
|
#isDriving = false;
|
|
139
138
|
#line = requireChild(this.#envelope, ".sonic-envelope-line", SVGElement);
|
|
140
139
|
#readout = new Readout(requireChild(this.#envelope, ".sonic-envelope-readout", HTMLDivElement));
|
|
140
|
+
#reticle = requireChild(this.#envelope, ".sonic-envelope-reticle", HTMLDivElement);
|
|
141
141
|
#shape = adsrShape({});
|
|
142
142
|
#waiting = /* @__PURE__ */ new Set();
|
|
143
143
|
#warned = /* @__PURE__ */ new Set();
|
|
@@ -233,15 +233,9 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
233
233
|
at: shape.curveHandles.find((point) => point.stage === stage),
|
|
234
234
|
drives: this.#curveDrives(stage)
|
|
235
235
|
});
|
|
236
|
-
this.#
|
|
236
|
+
this.#drawReticle();
|
|
237
237
|
this.#renderReadout();
|
|
238
238
|
}
|
|
239
|
-
#drawBracket() {
|
|
240
|
-
const part = this.#held;
|
|
241
|
-
if (!part) return;
|
|
242
|
-
for (const name of ["--_sonic-envelope-x", "--_sonic-envelope-y"]) this.#bracket.style.setProperty(name, part.style.getPropertyValue(name));
|
|
243
|
-
writeAttribute(this.#bracket, "data-sonic-part", part.classList.contains("sonic-envelope-curve") ? "curve" : void 0);
|
|
244
|
-
}
|
|
245
239
|
#drawPoint(part, point) {
|
|
246
240
|
const { at, drives } = point;
|
|
247
241
|
writeAttribute(part, "hidden", at ? void 0 : "");
|
|
@@ -252,6 +246,12 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
252
246
|
writeAttribute(part, "data-sonic-axes", drives.map(({ axis }) => axis).join(""));
|
|
253
247
|
writeAttribute(part, "data-sonic-disabled", isStill ? "" : void 0);
|
|
254
248
|
}
|
|
249
|
+
#drawReticle() {
|
|
250
|
+
const part = this.#held;
|
|
251
|
+
if (!part) return;
|
|
252
|
+
for (const name of ["--_sonic-envelope-x", "--_sonic-envelope-y"]) this.#reticle.style.setProperty(name, part.style.getPropertyValue(name));
|
|
253
|
+
writeAttribute(this.#reticle, "data-sonic-part", part.classList.contains("sonic-envelope-curve") ? "curve" : void 0);
|
|
254
|
+
}
|
|
255
255
|
#drives(stage) {
|
|
256
256
|
const x = this.#bindings.get(stage);
|
|
257
257
|
const y = stage === "decay" ? this.#bindings.get("sustain") : void 0;
|
|
@@ -267,7 +267,7 @@ var SonicEnvelope = class extends SonicElement {
|
|
|
267
267
|
const pressed = this.#pressed(event);
|
|
268
268
|
if (!pressed || pressed.drives.length === 0) return void 0;
|
|
269
269
|
this.#held = pressed.part;
|
|
270
|
-
this.#
|
|
270
|
+
this.#drawReticle();
|
|
271
271
|
const box = this.#graph.getBoundingClientRect();
|
|
272
272
|
const travel = {
|
|
273
273
|
x: Math.max(1, box.width * this.#shape.share),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.js","names":[],"sources":["../../../src/elements/envelope.ts"],"sourcesContent":["import type { FieldGesture, FieldHold } from '#elements/field-gesture.ts';\nimport type { ValueLink } from '#elements/value-element.ts';\nimport type { AdsrCurves, AdsrProportions, AdsrShape } from '#lib/adsr-shape.ts';\nimport type { FieldAxis, FieldPoint } from '#lib/field.ts';\n\nimport { bindFieldGesture } from '#elements/field-gesture.ts';\nimport { ReadoutClaim } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { SonicElement } from '#elements/sonic-element.ts';\nimport { linkValue, SonicValueElement } from '#elements/value-element.ts';\nimport { adsrPath, adsrShape, adsrStages, timeStages } from '#lib/adsr-shape.ts';\nimport { requireChild, template } from '#lib/render.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-envelope': SonicEnvelope;\n\t}\n}\n\ninterface Binding {\n\telement: SonicValueElement;\n\tlink: ValueLink;\n\tunwatch: () => void;\n}\n\ninterface Drive {\n\taxis: FieldAxis;\n\tbinding: Binding;\n}\n\ninterface HandleHold extends FieldHold {\n\tdrives: Array<Drive>;\n\tisFlipped: boolean;\n\tpart: HTMLElement;\n}\n\nconst curveStages = ['attack', 'decay', 'release'] as const;\n\nconst bindable = [...adsrStages, 'attack-curve', 'decay-curve', 'release-curve'] as const;\n\nconst bindableNames = new Set<string>(bindable);\n\nfunction isParent(node: Node): node is Node & ParentNode {\n\treturn 'querySelector' in node;\n}\n\nconst emptyPath = { fill: '', floor: { from: 0, to: 0 }, stroke: '' };\n\nfunction stageParts<Stage extends string>(\n\tenvelope: Element,\n\thook: string,\n\tstages: ReadonlyArray<Stage>,\n): Map<Stage, HTMLDivElement> {\n\treturn new Map(\n\t\tstages.map((stage) => [\n\t\t\tstage,\n\t\t\trequireChild(envelope, `.${hook}[data-sonic-stage=\"${stage}\"]`, HTMLDivElement),\n\t\t]),\n\t);\n}\n\nconst renderEnvelope = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-envelope\" aria-hidden=\"true\">\n\t\t\t<div class=\"sonic-envelope-bracket\"></div>\n\t\t\t<svg class=\"sonic-envelope-graph\" preserveAspectRatio=\"none\" viewBox=\"0 0 1 1\">\n\t\t\t\t<path class=\"sonic-envelope-fill\" />\n\t\t\t\t<rect class=\"sonic-envelope-fill sonic-envelope-floor\" y=\"1\" />\n\t\t\t\t<path class=\"sonic-envelope-line\" />\n\t\t\t</svg>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"delay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"attack\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"hold\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"decay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"release\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"attack\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"decay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"release\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-readout\" popover=\"manual\"><span></span></div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nexport class SonicEnvelope extends SonicElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicElement.observedAttributes,\n\t\t...bindable,\n\t\t'readout',\n\t];\n\n\tget attack(): string {\n\t\treturn this.getAttribute('attack') ?? '';\n\t}\n\n\tset attack(id: string | undefined) {\n\t\tthis.reflect('attack', id);\n\t}\n\n\tget attackCurve(): string {\n\t\treturn this.getAttribute('attack-curve') ?? '';\n\t}\n\n\tset attackCurve(id: string | undefined) {\n\t\tthis.reflect('attack-curve', id);\n\t}\n\n\tget decay(): string {\n\t\treturn this.getAttribute('decay') ?? '';\n\t}\n\n\tset decay(id: string | undefined) {\n\t\tthis.reflect('decay', id);\n\t}\n\n\tget decayCurve(): string {\n\t\treturn this.getAttribute('decay-curve') ?? '';\n\t}\n\n\tset decayCurve(id: string | undefined) {\n\t\tthis.reflect('decay-curve', id);\n\t}\n\n\tget delay(): string {\n\t\treturn this.getAttribute('delay') ?? '';\n\t}\n\n\tset delay(id: string | undefined) {\n\t\tthis.reflect('delay', id);\n\t}\n\n\tget hold(): string {\n\t\treturn this.getAttribute('hold') ?? '';\n\t}\n\n\tset hold(id: string | undefined) {\n\t\tthis.reflect('hold', id);\n\t}\n\n\t// fallow-ignore-next-line code-duplication -- one accessor pair per property\n\tget pointerType(): string | undefined {\n\t\treturn this.#gesture?.pointerType();\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isOn: boolean) {\n\t\tthis.reflect('readout', isOn);\n\t}\n\n\tget release(): string {\n\t\treturn this.getAttribute('release') ?? '';\n\t}\n\n\tset release(id: string | undefined) {\n\t\tthis.reflect('release', id);\n\t}\n\n\tget releaseCurve(): string {\n\t\treturn this.getAttribute('release-curve') ?? '';\n\t}\n\n\tset releaseCurve(id: string | undefined) {\n\t\tthis.reflect('release-curve', id);\n\t}\n\n\tget sustain(): string {\n\t\treturn this.getAttribute('sustain') ?? '';\n\t}\n\n\tset sustain(id: string | undefined) {\n\t\tthis.reflect('sustain', id);\n\t}\n\n\treadonly #bindings = new Map<string, Binding>();\n\n\treadonly #envelope = renderEnvelope();\n\n\treadonly #bracket = requireChild(this.#envelope, '.sonic-envelope-bracket', HTMLDivElement);\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderReadout();\n\t});\n\n\treadonly #curveHandles = stageParts(this.#envelope, 'sonic-envelope-curve', curveStages);\n\n\treadonly #fill = requireChild(this.#envelope, '.sonic-envelope-fill', SVGElement);\n\n\treadonly #floor = requireChild(this.#envelope, '.sonic-envelope-floor', SVGElement);\n\n\t#gesture: FieldGesture<HandleHold> | undefined;\n\n\treadonly #graph = requireChild(this.#envelope, '.sonic-envelope-graph', SVGElement);\n\n\treadonly #handles = stageParts(this.#envelope, 'sonic-envelope-handle', timeStages);\n\n\t#held: HTMLElement | undefined;\n\n\t#isDriving = false;\n\n\treadonly #line = requireChild(this.#envelope, '.sonic-envelope-line', SVGElement);\n\n\treadonly #readout = new Readout(\n\t\trequireChild(this.#envelope, '.sonic-envelope-readout', HTMLDivElement),\n\t);\n\n\t#shape: AdsrShape = adsrShape({});\n\n\treadonly #waiting = new Set<unknown>();\n\n\treadonly #warned = new Set<string>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (!this.isBound()) return;\n\t\tif (name === 'disabled') {\n\t\t\tthis.#gesture?.end();\n\t\t\tthis.#draw();\n\t\t\treturn;\n\t\t}\n\t\tif (bindableNames.has(name)) this.#bind();\n\t\telse this.#renderReadout();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(...adsrStages, 'attackCurve', 'decayCurve', 'readout', 'releaseCurve');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst envelope = this.#envelope;\n\n\t\tthis.keepControl(envelope, signal);\n\t\tthis.#bind();\n\t\tif (__DEV__)\n\t\t\tthis.checkStyles(envelope, 'envelope.css', {\n\t\t\t\tproperty: 'margin-bottom',\n\t\t\t\tselector: '[popover]',\n\t\t\t});\n\t\tthis.#bindPointer(envelope, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#unbind();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#bind(): void {\n\t\tthis.#gesture?.end();\n\t\tthis.#unbind();\n\t\tfor (const name of bindable) {\n\t\t\tconst element = this.#resolve(name);\n\t\t\tif (!element) continue;\n\n\t\t\tconst link = linkValue(element);\n\t\t\tconst unwatch = link.model.watch(() => {\n\t\t\t\tif (!this.#isDriving) this.#draw();\n\t\t\t});\n\n\t\t\tthis.#bindings.set(name, { element, link, unwatch });\n\t\t}\n\t\tthis.#draw();\n\t}\n\n\t#bindPointer(envelope: HTMLElement, signal: AbortSignal): void {\n\t\tthis.#gesture = bindFieldGesture(\n\t\t\tenvelope,\n\t\t\t{\n\t\t\t\tclaim: this.#claim,\n\t\t\t\tgrab: (event) => this.#grab(event),\n\t\t\t\tinput: ({ drives }, next) => {\n\t\t\t\t\tthis.#isDriving = true;\n\t\t\t\t\tfor (const { axis, binding } of drives) {\n\t\t\t\t\t\tconst value = next[axis];\n\n\t\t\t\t\t\tif (value !== undefined) binding.link.input(value);\n\t\t\t\t\t}\n\t\t\t\t\tthis.#isDriving = false;\n\t\t\t\t\tthis.#draw();\n\t\t\t\t},\n\t\t\t\trelease: ({ drives }, moved) => {\n\t\t\t\t\tfor (const { axis, binding } of drives) {\n\t\t\t\t\t\tif (!moved.includes(axis)) continue;\n\n\t\t\t\t\t\tbinding.link.change();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\ttoggle: (isDragging) => {\n\t\t\t\t\tthis.toggleState('dragging', isDragging);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#curveDrives(stage: string): Array<Drive> {\n\t\tconst binding = this.#bindings.get(`${stage}-curve`);\n\n\t\treturn binding ? [{ axis: 'y', binding }] : [];\n\t}\n\n\t#draw(): void {\n\t\tconst shape = this.#readShape();\n\t\tconst path = this.#bindings.size === 0 ? emptyPath : adsrPath(shape);\n\n\t\tthis.#shape = shape;\n\t\twriteAttribute(this.#line, 'd', path.stroke);\n\t\twriteAttribute(this.#fill, 'd', path.fill);\n\t\twriteAttribute(this.#floor, 'x', String(path.floor.from));\n\t\twriteAttribute(this.#floor, 'width', String(path.floor.to - path.floor.from));\n\t\tfor (const [stage, part] of this.#handles) {\n\t\t\tthis.#drawPoint(part, {\n\t\t\t\tat: shape.handles.find((point) => point.stage === stage),\n\t\t\t\tdrives: this.#drives(stage),\n\t\t\t});\n\t\t}\n\t\tfor (const [stage, part] of this.#curveHandles) {\n\t\t\tthis.#drawPoint(part, {\n\t\t\t\tat: shape.curveHandles.find((point) => point.stage === stage),\n\t\t\t\tdrives: this.#curveDrives(stage),\n\t\t\t});\n\t\t}\n\t\tthis.#drawBracket();\n\t\tthis.#renderReadout();\n\t}\n\n\t#drawBracket(): void {\n\t\tconst part = this.#held;\n\t\tif (!part) return;\n\n\t\tfor (const name of ['--_sonic-envelope-x', '--_sonic-envelope-y']) {\n\t\t\tthis.#bracket.style.setProperty(name, part.style.getPropertyValue(name));\n\t\t}\n\t\twriteAttribute(\n\t\t\tthis.#bracket,\n\t\t\t'data-sonic-part',\n\t\t\tpart.classList.contains('sonic-envelope-curve') ? 'curve' : undefined,\n\t\t);\n\t}\n\n\t#drawPoint(\n\t\tpart: HTMLDivElement,\n\t\tpoint: { at: FieldPoint | undefined; drives: Array<Drive> },\n\t): void {\n\t\tconst { at, drives } = point;\n\n\t\twriteAttribute(part, 'hidden', at ? undefined : '');\n\t\tif (!at) return;\n\n\t\tconst isStill = this.isDisabled() || drives.every(({ binding }) => binding.link.isDisabled());\n\n\t\tpart.style.setProperty('--_sonic-envelope-x', String(at.x));\n\t\tpart.style.setProperty('--_sonic-envelope-y', String(at.y));\n\t\twriteAttribute(part, 'data-sonic-axes', drives.map(({ axis }) => axis).join(''));\n\t\twriteAttribute(part, 'data-sonic-disabled', isStill ? '' : undefined);\n\t}\n\n\t#drives(stage: string): Array<Drive> {\n\t\tconst x = this.#bindings.get(stage);\n\t\tconst y = stage === 'decay' ? this.#bindings.get('sustain') : undefined;\n\n\t\treturn [\n\t\t\t...(x ? [{ axis: 'x' as const, binding: x }] : []),\n\t\t\t...(y ? [{ axis: 'y' as const, binding: y }] : []),\n\t\t];\n\t}\n\n\t#grab(event: PointerEvent): HandleHold | undefined {\n\t\tconst pressed = this.#pressed(event);\n\t\tif (!pressed || pressed.drives.length === 0) return undefined;\n\n\t\tthis.#held = pressed.part;\n\t\tthis.#drawBracket();\n\n\t\tconst box = this.#graph.getBoundingClientRect();\n\t\tconst travel = { x: Math.max(1, box.width * this.#shape.share), y: Math.max(1, box.height) };\n\t\tconst axes: HandleHold['axes'] = {};\n\n\t\tfor (const { axis, binding } of pressed.drives) {\n\t\t\taxes[axis] = { model: binding.link.model, travelPx: travel[axis] };\n\t\t}\n\n\t\treturn { ...pressed, axes };\n\t}\n\n\t#pressed(event: PointerEvent): Omit<HandleHold, 'axes'> | undefined {\n\t\tconst part =\n\t\t\tevent.target instanceof Element\n\t\t\t\t? event.target.closest<HTMLElement>('.sonic-envelope-handle, .sonic-envelope-curve')\n\t\t\t\t: undefined;\n\t\tconst stage = part?.dataset.sonicStage;\n\t\tif (!part || stage === undefined || this.isDisabled()) return undefined;\n\n\t\tconst isCurveHandle = part.classList.contains('sonic-envelope-curve');\n\t\tconst drives = isCurveHandle ? this.#curveDrives(stage) : this.#drives(stage);\n\n\t\treturn {\n\t\t\tdrives: drives.filter(({ binding }) => !binding.link.isDisabled()),\n\t\t\tisFlipped: isCurveHandle && stage === 'attack',\n\t\t\tpart,\n\t\t};\n\t}\n\n\t#readShape(): AdsrShape {\n\t\tconst proportions: AdsrProportions = {};\n\t\tconst curves: AdsrCurves = {};\n\n\t\tfor (const stage of adsrStages) {\n\t\t\tconst model = this.#bindings.get(stage)?.link.model;\n\n\t\t\tproportions[stage] = model?.mapping().proportionOf(model.value);\n\t\t}\n\t\tfor (const stage of curveStages) {\n\t\t\tcurves[stage] = this.#bindings.get(`${stage}-curve`)?.link.model.value;\n\t\t}\n\n\t\treturn adsrShape(proportions, curves);\n\t}\n\n\t#rebindOnce(key: unknown, arrives: (rebind: () => void) => void): void {\n\t\tif (this.#waiting.has(key)) return;\n\n\t\tthis.#waiting.add(key);\n\t\tarrives(() => {\n\t\t\tthis.#waiting.delete(key);\n\t\t\tif (this.isBound()) this.#bind();\n\t\t});\n\t}\n\n\t#renderReadout(): void {\n\t\tconst drag = this.#gesture?.current();\n\n\t\tif (!drag) {\n\t\t\tthis.#readout.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#readout.show({\n\t\t\tanchor: drag.part,\n\t\t\tisOpen: this.#claim.isRevealed && this.readout,\n\t\t\ttext: drag.drives.map(({ binding }) => binding.element.valueText).join(', '),\n\t\t});\n\t}\n\n\t#resolve(name: string): SonicValueElement | undefined {\n\t\tconst id = this.getAttribute(name);\n\t\tconst root = this.getRootNode();\n\t\tif (!id || !isParent(root)) return undefined;\n\n\t\tconst found = root.querySelector(`#${CSS.escape(id)}`);\n\t\tif (found instanceof SonicValueElement) return found;\n\n\t\tthis.#wait(id, found);\n\n\t\treturn undefined;\n\t}\n\n\t#unbind(): void {\n\t\tfor (const { unwatch } of this.#bindings.values()) unwatch();\n\n\t\tthis.#bindings.clear();\n\t}\n\n\t#wait(id: string, found: Element | null): void {\n\t\tconst tag = found?.localName;\n\t\tconst { ownerDocument } = this;\n\n\t\tif (tag?.includes('-') && !customElements.get(tag)) {\n\t\t\tthis.#rebindOnce(tag, (rebind) => {\n\t\t\t\tvoid customElements.whenDefined(tag).then(rebind);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (!found && ownerDocument.readyState === 'loading') {\n\t\t\tthis.#rebindOnce(ownerDocument, (rebind) => {\n\t\t\t\townerDocument.addEventListener('DOMContentLoaded', rebind, { once: true });\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#warn(id);\n\t}\n\n\t#warn(id: string): void {\n\t\tif (!__DEV__) return;\n\t\tif (this.#warned.has(id)) return;\n\n\t\tthis.#warned.add(id);\n\t\tconsole.warn(`<sonic-envelope> found no dial, slider or number box with the id \"${id}\"`);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"envelope.js","names":[],"sources":["../../../src/elements/envelope.ts"],"sourcesContent":["import type { FieldGesture, FieldHold } from '#elements/field-gesture.ts';\nimport type { ValueLink } from '#elements/value-element.ts';\nimport type { AdsrCurves, AdsrProportions, AdsrShape } from '#lib/adsr-shape.ts';\nimport type { FieldAxis, FieldPoint } from '#lib/field.ts';\n\nimport { bindFieldGesture } from '#elements/field-gesture.ts';\nimport { ReadoutClaim } from '#elements/readout-claim.ts';\nimport { Readout } from '#elements/readout.ts';\nimport { SonicElement } from '#elements/sonic-element.ts';\nimport { linkValue, SonicValueElement } from '#elements/value-element.ts';\nimport { adsrPath, adsrShape, adsrStages, timeStages } from '#lib/adsr-shape.ts';\nimport { requireChild, template } from '#lib/render.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\ndeclare const __DEV__: boolean;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sonic-envelope': SonicEnvelope;\n\t}\n}\n\ninterface Binding {\n\telement: SonicValueElement;\n\tlink: ValueLink;\n\tunwatch: () => void;\n}\n\ninterface Drive {\n\taxis: FieldAxis;\n\tbinding: Binding;\n}\n\ninterface HandleHold extends FieldHold {\n\tdrives: Array<Drive>;\n\tisFlipped: boolean;\n\tpart: HTMLElement;\n}\n\nconst curveStages = ['attack', 'decay', 'release'] as const;\n\nconst bindable = [...adsrStages, 'attack-curve', 'decay-curve', 'release-curve'] as const;\n\nconst bindableNames = new Set<string>(bindable);\n\nfunction isParent(node: Node): node is Node & ParentNode {\n\treturn 'querySelector' in node;\n}\n\nconst emptyPath = { fill: '', floor: { from: 0, to: 0 }, stroke: '' };\n\nfunction stageParts<Stage extends string>(\n\tenvelope: Element,\n\thook: string,\n\tstages: ReadonlyArray<Stage>,\n): Map<Stage, HTMLDivElement> {\n\treturn new Map(\n\t\tstages.map((stage) => [\n\t\t\tstage,\n\t\t\trequireChild(envelope, `.${hook}[data-sonic-stage=\"${stage}\"]`, HTMLDivElement),\n\t\t]),\n\t);\n}\n\nconst renderEnvelope = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-envelope\" aria-hidden=\"true\">\n\t\t\t<div class=\"sonic-envelope-reticle\"></div>\n\t\t\t<svg class=\"sonic-envelope-graph\" preserveAspectRatio=\"none\" viewBox=\"0 0 1 1\">\n\t\t\t\t<path class=\"sonic-envelope-fill\" />\n\t\t\t\t<rect class=\"sonic-envelope-fill sonic-envelope-floor\" y=\"1\" />\n\t\t\t\t<path class=\"sonic-envelope-line\" />\n\t\t\t</svg>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"delay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"attack\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"hold\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"decay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-handle\" data-sonic-stage=\"release\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"attack\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"decay\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-curve\" data-sonic-stage=\"release\" hidden></div>\n\t\t\t<div class=\"sonic-envelope-readout\" popover=\"manual\"><span></span></div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nexport class SonicEnvelope extends SonicElement {\n\tstatic override readonly observedAttributes = [\n\t\t...SonicElement.observedAttributes,\n\t\t...bindable,\n\t\t'readout',\n\t];\n\n\tget attack(): string {\n\t\treturn this.getAttribute('attack') ?? '';\n\t}\n\n\tset attack(id: string | undefined) {\n\t\tthis.reflect('attack', id);\n\t}\n\n\tget attackCurve(): string {\n\t\treturn this.getAttribute('attack-curve') ?? '';\n\t}\n\n\tset attackCurve(id: string | undefined) {\n\t\tthis.reflect('attack-curve', id);\n\t}\n\n\tget decay(): string {\n\t\treturn this.getAttribute('decay') ?? '';\n\t}\n\n\tset decay(id: string | undefined) {\n\t\tthis.reflect('decay', id);\n\t}\n\n\tget decayCurve(): string {\n\t\treturn this.getAttribute('decay-curve') ?? '';\n\t}\n\n\tset decayCurve(id: string | undefined) {\n\t\tthis.reflect('decay-curve', id);\n\t}\n\n\tget delay(): string {\n\t\treturn this.getAttribute('delay') ?? '';\n\t}\n\n\tset delay(id: string | undefined) {\n\t\tthis.reflect('delay', id);\n\t}\n\n\tget hold(): string {\n\t\treturn this.getAttribute('hold') ?? '';\n\t}\n\n\tset hold(id: string | undefined) {\n\t\tthis.reflect('hold', id);\n\t}\n\n\t// fallow-ignore-next-line code-duplication -- one accessor pair per property\n\tget pointerType(): string | undefined {\n\t\treturn this.#gesture?.pointerType();\n\t}\n\n\tget readout(): boolean {\n\t\treturn this.hasAttribute('readout');\n\t}\n\n\tset readout(isOn: boolean) {\n\t\tthis.reflect('readout', isOn);\n\t}\n\n\tget release(): string {\n\t\treturn this.getAttribute('release') ?? '';\n\t}\n\n\tset release(id: string | undefined) {\n\t\tthis.reflect('release', id);\n\t}\n\n\tget releaseCurve(): string {\n\t\treturn this.getAttribute('release-curve') ?? '';\n\t}\n\n\tset releaseCurve(id: string | undefined) {\n\t\tthis.reflect('release-curve', id);\n\t}\n\n\tget sustain(): string {\n\t\treturn this.getAttribute('sustain') ?? '';\n\t}\n\n\tset sustain(id: string | undefined) {\n\t\tthis.reflect('sustain', id);\n\t}\n\n\treadonly #bindings = new Map<string, Binding>();\n\n\treadonly #claim = new ReadoutClaim(() => {\n\t\tthis.#renderReadout();\n\t});\n\n\treadonly #envelope = renderEnvelope();\n\n\treadonly #curveHandles = stageParts(this.#envelope, 'sonic-envelope-curve', curveStages);\n\n\treadonly #fill = requireChild(this.#envelope, '.sonic-envelope-fill', SVGElement);\n\n\treadonly #floor = requireChild(this.#envelope, '.sonic-envelope-floor', SVGElement);\n\n\t#gesture: FieldGesture<HandleHold> | undefined;\n\n\treadonly #graph = requireChild(this.#envelope, '.sonic-envelope-graph', SVGElement);\n\n\treadonly #handles = stageParts(this.#envelope, 'sonic-envelope-handle', timeStages);\n\n\t#held: HTMLElement | undefined;\n\n\t#isDriving = false;\n\n\treadonly #line = requireChild(this.#envelope, '.sonic-envelope-line', SVGElement);\n\n\treadonly #readout = new Readout(\n\t\trequireChild(this.#envelope, '.sonic-envelope-readout', HTMLDivElement),\n\t);\n\n\treadonly #reticle = requireChild(this.#envelope, '.sonic-envelope-reticle', HTMLDivElement);\n\n\t#shape: AdsrShape = adsrShape({});\n\n\treadonly #waiting = new Set<unknown>();\n\n\treadonly #warned = new Set<string>();\n\n\tattributeChangedCallback(name: string): void {\n\t\tif (!this.isBound()) return;\n\t\tif (name === 'disabled') {\n\t\t\tthis.#gesture?.end();\n\t\t\tthis.#draw();\n\t\t\treturn;\n\t\t}\n\t\tif (bindableNames.has(name)) this.#bind();\n\t\telse this.#renderReadout();\n\t}\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties(...adsrStages, 'attackCurve', 'decayCurve', 'readout', 'releaseCurve');\n\t\tsuper.connectedCallback();\n\t}\n\n\tprotected connect(signal: AbortSignal): void {\n\t\tconst envelope = this.#envelope;\n\n\t\tthis.keepControl(envelope, signal);\n\t\tthis.#bind();\n\t\tif (__DEV__)\n\t\t\tthis.checkStyles(envelope, 'envelope.css', {\n\t\t\t\tproperty: 'margin-bottom',\n\t\t\t\tselector: '[popover]',\n\t\t\t});\n\t\tthis.#bindPointer(envelope, signal);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tthis.#unbind();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#bind(): void {\n\t\tthis.#gesture?.end();\n\t\tthis.#unbind();\n\t\tfor (const name of bindable) {\n\t\t\tconst element = this.#resolve(name);\n\t\t\tif (!element) continue;\n\n\t\t\tconst link = linkValue(element);\n\t\t\tconst unwatch = link.model.watch(() => {\n\t\t\t\tif (!this.#isDriving) this.#draw();\n\t\t\t});\n\n\t\t\tthis.#bindings.set(name, { element, link, unwatch });\n\t\t}\n\t\tthis.#draw();\n\t}\n\n\t#bindPointer(envelope: HTMLElement, signal: AbortSignal): void {\n\t\tthis.#gesture = bindFieldGesture(\n\t\t\tenvelope,\n\t\t\t{\n\t\t\t\tclaim: this.#claim,\n\t\t\t\tgrab: (event) => this.#grab(event),\n\t\t\t\tinput: ({ drives }, next) => {\n\t\t\t\t\tthis.#isDriving = true;\n\t\t\t\t\tfor (const { axis, binding } of drives) {\n\t\t\t\t\t\tconst value = next[axis];\n\n\t\t\t\t\t\tif (value !== undefined) binding.link.input(value);\n\t\t\t\t\t}\n\t\t\t\t\tthis.#isDriving = false;\n\t\t\t\t\tthis.#draw();\n\t\t\t\t},\n\t\t\t\trelease: ({ drives }, moved) => {\n\t\t\t\t\tfor (const { axis, binding } of drives) {\n\t\t\t\t\t\tif (!moved.includes(axis)) continue;\n\n\t\t\t\t\t\tbinding.link.change();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\ttoggle: (isDragging) => {\n\t\t\t\t\tthis.toggleState('dragging', isDragging);\n\t\t\t\t},\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t#curveDrives(stage: string): Array<Drive> {\n\t\tconst binding = this.#bindings.get(`${stage}-curve`);\n\n\t\treturn binding ? [{ axis: 'y', binding }] : [];\n\t}\n\n\t#draw(): void {\n\t\tconst shape = this.#readShape();\n\t\tconst path = this.#bindings.size === 0 ? emptyPath : adsrPath(shape);\n\n\t\tthis.#shape = shape;\n\t\twriteAttribute(this.#line, 'd', path.stroke);\n\t\twriteAttribute(this.#fill, 'd', path.fill);\n\t\twriteAttribute(this.#floor, 'x', String(path.floor.from));\n\t\twriteAttribute(this.#floor, 'width', String(path.floor.to - path.floor.from));\n\t\tfor (const [stage, part] of this.#handles) {\n\t\t\tthis.#drawPoint(part, {\n\t\t\t\tat: shape.handles.find((point) => point.stage === stage),\n\t\t\t\tdrives: this.#drives(stage),\n\t\t\t});\n\t\t}\n\t\tfor (const [stage, part] of this.#curveHandles) {\n\t\t\tthis.#drawPoint(part, {\n\t\t\t\tat: shape.curveHandles.find((point) => point.stage === stage),\n\t\t\t\tdrives: this.#curveDrives(stage),\n\t\t\t});\n\t\t}\n\t\tthis.#drawReticle();\n\t\tthis.#renderReadout();\n\t}\n\n\t#drawPoint(\n\t\tpart: HTMLDivElement,\n\t\tpoint: { at: FieldPoint | undefined; drives: Array<Drive> },\n\t): void {\n\t\tconst { at, drives } = point;\n\n\t\twriteAttribute(part, 'hidden', at ? undefined : '');\n\t\tif (!at) return;\n\n\t\tconst isStill = this.isDisabled() || drives.every(({ binding }) => binding.link.isDisabled());\n\n\t\tpart.style.setProperty('--_sonic-envelope-x', String(at.x));\n\t\tpart.style.setProperty('--_sonic-envelope-y', String(at.y));\n\t\twriteAttribute(part, 'data-sonic-axes', drives.map(({ axis }) => axis).join(''));\n\t\twriteAttribute(part, 'data-sonic-disabled', isStill ? '' : undefined);\n\t}\n\n\t#drawReticle(): void {\n\t\tconst part = this.#held;\n\t\tif (!part) return;\n\n\t\tfor (const name of ['--_sonic-envelope-x', '--_sonic-envelope-y']) {\n\t\t\tthis.#reticle.style.setProperty(name, part.style.getPropertyValue(name));\n\t\t}\n\t\twriteAttribute(\n\t\t\tthis.#reticle,\n\t\t\t'data-sonic-part',\n\t\t\tpart.classList.contains('sonic-envelope-curve') ? 'curve' : undefined,\n\t\t);\n\t}\n\n\t#drives(stage: string): Array<Drive> {\n\t\tconst x = this.#bindings.get(stage);\n\t\tconst y = stage === 'decay' ? this.#bindings.get('sustain') : undefined;\n\n\t\treturn [\n\t\t\t...(x ? [{ axis: 'x' as const, binding: x }] : []),\n\t\t\t...(y ? [{ axis: 'y' as const, binding: y }] : []),\n\t\t];\n\t}\n\n\t#grab(event: PointerEvent): HandleHold | undefined {\n\t\tconst pressed = this.#pressed(event);\n\t\tif (!pressed || pressed.drives.length === 0) return undefined;\n\n\t\tthis.#held = pressed.part;\n\t\tthis.#drawReticle();\n\n\t\tconst box = this.#graph.getBoundingClientRect();\n\t\tconst travel = { x: Math.max(1, box.width * this.#shape.share), y: Math.max(1, box.height) };\n\t\tconst axes: HandleHold['axes'] = {};\n\n\t\tfor (const { axis, binding } of pressed.drives) {\n\t\t\taxes[axis] = { model: binding.link.model, travelPx: travel[axis] };\n\t\t}\n\n\t\treturn { ...pressed, axes };\n\t}\n\n\t#pressed(event: PointerEvent): Omit<HandleHold, 'axes'> | undefined {\n\t\tconst part =\n\t\t\tevent.target instanceof Element\n\t\t\t\t? event.target.closest<HTMLElement>('.sonic-envelope-handle, .sonic-envelope-curve')\n\t\t\t\t: undefined;\n\t\tconst stage = part?.dataset.sonicStage;\n\t\tif (!part || stage === undefined || this.isDisabled()) return undefined;\n\n\t\tconst isCurveHandle = part.classList.contains('sonic-envelope-curve');\n\t\tconst drives = isCurveHandle ? this.#curveDrives(stage) : this.#drives(stage);\n\n\t\treturn {\n\t\t\tdrives: drives.filter(({ binding }) => !binding.link.isDisabled()),\n\t\t\tisFlipped: isCurveHandle && stage === 'attack',\n\t\t\tpart,\n\t\t};\n\t}\n\n\t#readShape(): AdsrShape {\n\t\tconst proportions: AdsrProportions = {};\n\t\tconst curves: AdsrCurves = {};\n\n\t\tfor (const stage of adsrStages) {\n\t\t\tconst model = this.#bindings.get(stage)?.link.model;\n\n\t\t\tproportions[stage] = model?.mapping().proportionOf(model.value);\n\t\t}\n\t\tfor (const stage of curveStages) {\n\t\t\tcurves[stage] = this.#bindings.get(`${stage}-curve`)?.link.model.value;\n\t\t}\n\n\t\treturn adsrShape(proportions, curves);\n\t}\n\n\t#rebindOnce(key: unknown, arrives: (rebind: () => void) => void): void {\n\t\tif (this.#waiting.has(key)) return;\n\n\t\tthis.#waiting.add(key);\n\t\tarrives(() => {\n\t\t\tthis.#waiting.delete(key);\n\t\t\tif (this.isBound()) this.#bind();\n\t\t});\n\t}\n\n\t#renderReadout(): void {\n\t\tconst drag = this.#gesture?.current();\n\n\t\tif (!drag) {\n\t\t\tthis.#readout.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#readout.show({\n\t\t\tanchor: drag.part,\n\t\t\tisOpen: this.#claim.isRevealed && this.readout,\n\t\t\ttext: drag.drives.map(({ binding }) => binding.element.valueText).join(', '),\n\t\t});\n\t}\n\n\t#resolve(name: string): SonicValueElement | undefined {\n\t\tconst id = this.getAttribute(name);\n\t\tconst root = this.getRootNode();\n\t\tif (!id || !isParent(root)) return undefined;\n\n\t\tconst found = root.querySelector(`#${CSS.escape(id)}`);\n\t\tif (found instanceof SonicValueElement) return found;\n\n\t\tthis.#wait(id, found);\n\n\t\treturn undefined;\n\t}\n\n\t#unbind(): void {\n\t\tfor (const { unwatch } of this.#bindings.values()) unwatch();\n\n\t\tthis.#bindings.clear();\n\t}\n\n\t#wait(id: string, found: Element | null): void {\n\t\tconst tag = found?.localName;\n\t\tconst { ownerDocument } = this;\n\n\t\tif (tag?.includes('-') && !customElements.get(tag)) {\n\t\t\tthis.#rebindOnce(tag, (rebind) => {\n\t\t\t\tvoid customElements.whenDefined(tag).then(rebind);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (!found && ownerDocument.readyState === 'loading') {\n\t\t\tthis.#rebindOnce(ownerDocument, (rebind) => {\n\t\t\t\townerDocument.addEventListener('DOMContentLoaded', rebind, { once: true });\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#warn(id);\n\t}\n\n\t#warn(id: string): void {\n\t\tif (!__DEV__) return;\n\t\tif (this.#warned.has(id)) return;\n\n\t\tthis.#warned.add(id);\n\t\tconsole.warn(`<sonic-envelope> found no dial, slider or number box with the id \"${id}\"`);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ export declare abstract class SonicFormElement extends SonicElement {
|
|
|
16
16
|
protected namingLabels(): Array<Element>;
|
|
17
17
|
protected abstract render(): void;
|
|
18
18
|
protected abstract restoreState(state: string): void;
|
|
19
|
+
protected writeFormFields(fields: ReadonlyArray<[string, number]>, state: string): void;
|
|
19
20
|
protected writeFormValue(value: FormData | null | string, state: string): void;
|
|
20
21
|
}
|
|
21
22
|
//#endregion
|
|
@@ -47,6 +47,16 @@ var SonicFormElement = class extends SonicElement {
|
|
|
47
47
|
if (!internals || this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby")) return [];
|
|
48
48
|
return [...internals.labels].filter((label) => label instanceof Element);
|
|
49
49
|
}
|
|
50
|
+
writeFormFields(fields, state) {
|
|
51
|
+
const { name } = this;
|
|
52
|
+
if (name === "") {
|
|
53
|
+
this.writeFormValue(null, state);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const data = new FormData();
|
|
57
|
+
for (const [field, value] of fields) data.set(`${name}.${field}`, String(value));
|
|
58
|
+
this.writeFormValue(data, state);
|
|
59
|
+
}
|
|
50
60
|
writeFormValue(value, state) {
|
|
51
61
|
this.internals?.setFormValue(value, `${this.localName}:${state}`);
|
|
52
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-element.js","names":[],"sources":["../../../src/elements/form-element.ts"],"sourcesContent":["import { SonicElement } from '#elements/sonic-element.ts';\n\nexport abstract class SonicFormElement extends SonicElement {\n\tstatic readonly formAssociated = true;\n\n\tget form(): HTMLFormElement | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.form ?? null;\n\t}\n\n\tget labels(): NodeList | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.labels ?? null;\n\t}\n\n\tget name(): string {\n\t\treturn this.getAttribute('name') ?? '';\n\t}\n\n\tset name(value: string | undefined) {\n\t\tthis.reflect('name', value);\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\n\t\t// Otherwise the host takes the label's name and shows as a named generic beside the control\n\t\tif (this.internals) this.internals.role = 'none';\n\n\t\t// A click inside the control bubbles here with its own target; only a label's click targets the host\n\t\tthis.addEventListener('click', (event) => {\n\t\t\tif (event.target === this) this.activate();\n\t\t});\n\n\t\t// No event fires when a label arrives, so focus picks it up\n\t\tthis.addEventListener('focusin', () => {\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tabstract attributeChangedCallback(name: string): void;\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('name');\n\t\tsuper.connectedCallback();\n\t}\n\n\t// Never writes the attribute, or re-enabling the fieldset would leave the control disabled\n\tformDisabledCallback(): void {\n\t\tthis.attributeChangedCallback('disabled');\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.attributeChangedCallback('value');\n\t}\n\n\t// Firefox hands a restored state to the wrong control when tags upgrade out of document order\n\tformStateRestoreCallback(state: File | FormData | null | string): void {\n\t\tconst prefix = `${this.localName}:`;\n\n\t\tif (typeof state === 'string' && state.startsWith(prefix)) {\n\t\t\tthis.restoreState(state.slice(prefix.length));\n\t\t}\n\t}\n\n\tprotected activate(): void {\n\t\tthis.focus();\n\t}\n\n\tprotected override namingLabels(): Array<Element> {\n\t\tconst internals = this.internals;\n\t\tif (!internals || this.hasAttribute('aria-label') || this.hasAttribute('aria-labelledby')) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn [...internals.labels].filter((label) => label instanceof Element);\n\t}\n\n\tprotected abstract render(): void;\n\n\tprotected abstract restoreState(state: string): void;\n\n\tprotected writeFormValue(value: FormData | null | string, state: string): void {\n\t\tthis.internals?.setFormValue(value, `${this.localName}:${state}`);\n\t}\n}\n"],"mappings":";;;AAEA,IAAsB,mBAAtB,cAA+C,aAAa;CAC3D,OAAgB,iBAAiB;CAEjC,IAAI,OAA+B;EAElC,OAAO,KAAK,WAAW,QAAQ;CAChC;CAEA,IAAI,SAA0B;EAE7B,OAAO,KAAK,WAAW,UAAU;CAClC;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK,aAAa,MAAM,KAAK;CACrC;CAEA,IAAI,KAAK,OAA2B;EACnC,KAAK,QAAQ,QAAQ,KAAK;CAC3B;CAEA,cAAc;EACb,MAAM;EAGN,IAAI,KAAK,WAAW,KAAK,UAAU,OAAO;EAG1C,KAAK,iBAAiB,UAAU,UAAU;GACzC,IAAI,MAAM,WAAW,MAAM,KAAK,SAAS;EAC1C,CAAC;EAGD,KAAK,iBAAiB,iBAAiB;GACtC,KAAK,OAAO;EACb,CAAC;CACF;CAIA,AAAS,oBAA0B;EAClC,KAAK,kBAAkB,MAAM;EAC7B,MAAM,kBAAkB;CACzB;CAGA,uBAA6B;EAC5B,KAAK,yBAAyB,UAAU;CACzC;CAEA,oBAA0B;EACzB,KAAK,yBAAyB,OAAO;CACtC;CAGA,yBAAyB,OAA8C;EACtE,MAAM,SAAS,GAAG,KAAK,UAAU;EAEjC,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,MAAM,GACvD,KAAK,aAAa,MAAM,MAAM,OAAO,MAAM,CAAC;CAE9C;CAEA,AAAU,WAAiB;EAC1B,KAAK,MAAM;CACZ;CAEA,AAAmB,eAA+B;EACjD,MAAM,YAAY,KAAK;EACvB,IAAI,CAAC,aAAa,KAAK,aAAa,YAAY,KAAK,KAAK,aAAa,iBAAiB,GACvF,OAAO,CAAC;EAGT,OAAO,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,QAAQ,UAAU,iBAAiB,OAAO;CACxE;CAMA,AAAU,eAAe,OAAiC,OAAqB;EAC9E,KAAK,WAAW,aAAa,OAAO,GAAG,KAAK,UAAU,GAAG,OAAO;CACjE;AACD"}
|
|
1
|
+
{"version":3,"file":"form-element.js","names":[],"sources":["../../../src/elements/form-element.ts"],"sourcesContent":["import { SonicElement } from '#elements/sonic-element.ts';\n\nexport abstract class SonicFormElement extends SonicElement {\n\tstatic readonly formAssociated = true;\n\n\tget form(): HTMLFormElement | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.form ?? null;\n\t}\n\n\tget labels(): NodeList | null {\n\t\t// eslint-disable-next-line unicorn/no-null -- as on native inputs\n\t\treturn this.internals?.labels ?? null;\n\t}\n\n\tget name(): string {\n\t\treturn this.getAttribute('name') ?? '';\n\t}\n\n\tset name(value: string | undefined) {\n\t\tthis.reflect('name', value);\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\n\t\t// Otherwise the host takes the label's name and shows as a named generic beside the control\n\t\tif (this.internals) this.internals.role = 'none';\n\n\t\t// A click inside the control bubbles here with its own target; only a label's click targets the host\n\t\tthis.addEventListener('click', (event) => {\n\t\t\tif (event.target === this) this.activate();\n\t\t});\n\n\t\t// No event fires when a label arrives, so focus picks it up\n\t\tthis.addEventListener('focusin', () => {\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tabstract attributeChangedCallback(name: string): void;\n\n\toverride connectedCallback(): void {\n\t\tthis.upgradeProperties('name');\n\t\tsuper.connectedCallback();\n\t}\n\n\t// Never writes the attribute, or re-enabling the fieldset would leave the control disabled\n\tformDisabledCallback(): void {\n\t\tthis.attributeChangedCallback('disabled');\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.attributeChangedCallback('value');\n\t}\n\n\t// Firefox hands a restored state to the wrong control when tags upgrade out of document order\n\tformStateRestoreCallback(state: File | FormData | null | string): void {\n\t\tconst prefix = `${this.localName}:`;\n\n\t\tif (typeof state === 'string' && state.startsWith(prefix)) {\n\t\t\tthis.restoreState(state.slice(prefix.length));\n\t\t}\n\t}\n\n\tprotected activate(): void {\n\t\tthis.focus();\n\t}\n\n\tprotected override namingLabels(): Array<Element> {\n\t\tconst internals = this.internals;\n\t\tif (!internals || this.hasAttribute('aria-label') || this.hasAttribute('aria-labelledby')) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn [...internals.labels].filter((label) => label instanceof Element);\n\t}\n\n\tprotected abstract render(): void;\n\n\tprotected abstract restoreState(state: string): void;\n\n\tprotected writeFormFields(fields: ReadonlyArray<[string, number]>, state: string): void {\n\t\tconst { name } = this;\n\n\t\tif (name === '') {\n\t\t\t// eslint-disable-next-line unicorn/no-null -- `null` submits nothing\n\t\t\tthis.writeFormValue(null, state);\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = new FormData();\n\n\t\tfor (const [field, value] of fields) {\n\t\t\tdata.set(`${name}.${field}`, String(value));\n\t\t}\n\t\tthis.writeFormValue(data, state);\n\t}\n\n\tprotected writeFormValue(value: FormData | null | string, state: string): void {\n\t\tthis.internals?.setFormValue(value, `${this.localName}:${state}`);\n\t}\n}\n"],"mappings":";;;AAEA,IAAsB,mBAAtB,cAA+C,aAAa;CAC3D,OAAgB,iBAAiB;CAEjC,IAAI,OAA+B;EAElC,OAAO,KAAK,WAAW,QAAQ;CAChC;CAEA,IAAI,SAA0B;EAE7B,OAAO,KAAK,WAAW,UAAU;CAClC;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK,aAAa,MAAM,KAAK;CACrC;CAEA,IAAI,KAAK,OAA2B;EACnC,KAAK,QAAQ,QAAQ,KAAK;CAC3B;CAEA,cAAc;EACb,MAAM;EAGN,IAAI,KAAK,WAAW,KAAK,UAAU,OAAO;EAG1C,KAAK,iBAAiB,UAAU,UAAU;GACzC,IAAI,MAAM,WAAW,MAAM,KAAK,SAAS;EAC1C,CAAC;EAGD,KAAK,iBAAiB,iBAAiB;GACtC,KAAK,OAAO;EACb,CAAC;CACF;CAIA,AAAS,oBAA0B;EAClC,KAAK,kBAAkB,MAAM;EAC7B,MAAM,kBAAkB;CACzB;CAGA,uBAA6B;EAC5B,KAAK,yBAAyB,UAAU;CACzC;CAEA,oBAA0B;EACzB,KAAK,yBAAyB,OAAO;CACtC;CAGA,yBAAyB,OAA8C;EACtE,MAAM,SAAS,GAAG,KAAK,UAAU;EAEjC,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,MAAM,GACvD,KAAK,aAAa,MAAM,MAAM,OAAO,MAAM,CAAC;CAE9C;CAEA,AAAU,WAAiB;EAC1B,KAAK,MAAM;CACZ;CAEA,AAAmB,eAA+B;EACjD,MAAM,YAAY,KAAK;EACvB,IAAI,CAAC,aAAa,KAAK,aAAa,YAAY,KAAK,KAAK,aAAa,iBAAiB,GACvF,OAAO,CAAC;EAGT,OAAO,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,QAAQ,UAAU,iBAAiB,OAAO;CACxE;CAMA,AAAU,gBAAgB,QAAyC,OAAqB;EACvF,MAAM,EAAE,SAAS;EAEjB,IAAI,SAAS,IAAI;GAEhB,KAAK,eAAe,MAAM,KAAK;GAC/B;EACD;EAEA,MAAM,OAAO,IAAI,SAAS;EAE1B,KAAK,MAAM,CAAC,OAAO,UAAU,QAC5B,KAAK,IAAI,GAAG,KAAK,GAAG,SAAS,OAAO,KAAK,CAAC;EAE3C,KAAK,eAAe,MAAM,KAAK;CAChC;CAEA,AAAU,eAAe,OAAiC,OAAqB;EAC9E,KAAK,WAAW,aAAa,OAAO,GAAG,KAAK,UAAU,GAAG,OAAO;CACjE;AACD"}
|
|
@@ -2,7 +2,7 @@ import { requireChild } from "../lib/render.js";
|
|
|
2
2
|
|
|
3
3
|
//#region src/elements/readout.ts
|
|
4
4
|
const canPopover = "togglePopover" in HTMLElement.prototype;
|
|
5
|
-
const isUnanchored =
|
|
5
|
+
const isUnanchored = !CSS.supports("anchor-name", "--a");
|
|
6
6
|
let readoutCount = 0;
|
|
7
7
|
var Readout = class {
|
|
8
8
|
#anchor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readout.js","names":[],"sources":["../../../src/elements/readout.ts"],"sourcesContent":["import { requireChild } from '#lib/render.ts';\n\ninterface ReadoutView {\n\tanchor: HTMLElement;\n\tisOpen: boolean;\n\ttext: string | undefined;\n}\n\n// happy-dom has no popover API\nconst canPopover = 'togglePopover' in HTMLElement.prototype;\n\n// Without anchor positioning the bubble opens away from its control\nexport const isUnanchored =
|
|
1
|
+
{"version":3,"file":"readout.js","names":[],"sources":["../../../src/elements/readout.ts"],"sourcesContent":["import { requireChild } from '#lib/render.ts';\n\ninterface ReadoutView {\n\tanchor: HTMLElement;\n\tisOpen: boolean;\n\ttext: string | undefined;\n}\n\n// happy-dom has no popover API\nconst canPopover = 'togglePopover' in HTMLElement.prototype;\n\n// Without anchor positioning the bubble opens away from its control\nexport const isUnanchored = !CSS.supports('anchor-name', '--a');\n\nlet readoutCount = 0;\n\nexport class Readout {\n\t#anchor: HTMLElement | undefined;\n\n\treadonly #bubble: HTMLElement;\n\n\treadonly #name = `--sonic-readout-${String((readoutCount += 1))}`;\n\n\treadonly #text: HTMLElement;\n\n\tconstructor(bubble: HTMLElement) {\n\t\tthis.#bubble = bubble;\n\t\tthis.#text = requireChild(bubble, 'span', HTMLElement);\n\t\tbubble.style.setProperty('position-anchor', this.#name);\n\t}\n\n\tclose(): void {\n\t\tthis.#toggle(false);\n\t}\n\n\tshow({ anchor, isOpen, text }: ReadoutView): void {\n\t\tif (anchor !== this.#anchor) {\n\t\t\tthis.#anchor?.style.removeProperty('anchor-name');\n\t\t\tanchor.style.setProperty('anchor-name', this.#name);\n\t\t\tthis.#anchor = anchor;\n\t\t}\n\n\t\tthis.#text.hidden = text === undefined;\n\t\tif (isOpen && text !== undefined && this.#text.textContent !== text) {\n\t\t\tthis.#text.textContent = text;\n\t\t}\n\t\tthis.#toggle(isOpen);\n\t}\n\n\t#toggle(isOpen: boolean): void {\n\t\tif (canPopover && !isUnanchored && this.#bubble.isConnected) this.#bubble.togglePopover(isOpen);\n\t}\n}\n"],"mappings":";;;AASA,MAAM,aAAa,mBAAmB,YAAY;AAGlD,MAAa,eAAe,CAAC,IAAI,SAAS,eAAe,KAAK;AAE9D,IAAI,eAAe;AAEnB,IAAa,UAAb,MAAqB;CACpB;CAEA,AAAS;CAET,AAAS,QAAQ,mBAAmB,OAAQ,gBAAgB,CAAE;CAE9D,AAAS;CAET,YAAY,QAAqB;EAChC,KAAK,UAAU;EACf,KAAK,QAAQ,aAAa,QAAQ,QAAQ,WAAW;EACrD,OAAO,MAAM,YAAY,mBAAmB,KAAK,KAAK;CACvD;CAEA,QAAc;EACb,KAAK,QAAQ,KAAK;CACnB;CAEA,KAAK,EAAE,QAAQ,QAAQ,QAA2B;EACjD,IAAI,WAAW,KAAK,SAAS;GAC5B,KAAK,SAAS,MAAM,eAAe,aAAa;GAChD,OAAO,MAAM,YAAY,eAAe,KAAK,KAAK;GAClD,KAAK,UAAU;EAChB;EAEA,KAAK,MAAM,SAAS,SAAS;EAC7B,IAAI,UAAU,SAAS,UAAa,KAAK,MAAM,gBAAgB,MAC9D,KAAK,MAAM,cAAc;EAE1B,KAAK,QAAQ,MAAM;CACpB;CAEA,QAAQ,QAAuB;EAC9B,IAAI,cAAc,CAAC,gBAAgB,KAAK,QAAQ,aAAa,KAAK,QAAQ,cAAc,MAAM;CAC/F;AACD"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { writeAttribute } from "../lib/write-attribute.js";
|
|
2
|
+
import { placeChildren, template } from "../lib/render.js";
|
|
3
|
+
import { capturePointer } from "../lib/pointer-drag.js";
|
|
4
|
+
import { dragThresholdPx } from "../lib/drag-step.js";
|
|
5
|
+
import { focusByPointer } from "../lib/focus-by-pointer.js";
|
|
6
|
+
import { SonicRegion, linkRegion, ownRegions } from "./region.js";
|
|
7
|
+
import { writeKind } from "../lib/marker-band.js";
|
|
8
|
+
import { moveRegionTo, regionAt, regionTravel, startRegionDrag, stepRegionDrag } from "../lib/region-drag.js";
|
|
9
|
+
|
|
10
|
+
//#region src/elements/region-layer.ts
|
|
11
|
+
const renderPart = template(`
|
|
12
|
+
<div class="sonic-region" role="slider" aria-orientation="horizontal">
|
|
13
|
+
<div class="sonic-region-bracket"></div>
|
|
14
|
+
</div>
|
|
15
|
+
`, HTMLDivElement);
|
|
16
|
+
function hasMoved(from, to) {
|
|
17
|
+
return from.start !== to.start || from.end !== to.end;
|
|
18
|
+
}
|
|
19
|
+
function clippedEnds(region, [low, high]) {
|
|
20
|
+
const ends = [...Math.min(region.start, region.end) < low ? ["start"] : [], ...Math.max(region.start, region.end) > high ? ["end"] : []];
|
|
21
|
+
return ends.length > 0 ? ends.join(" ") : void 0;
|
|
22
|
+
}
|
|
23
|
+
function writeProperty(part, name, value) {
|
|
24
|
+
if (part.style.getPropertyValue(name) !== value) part.style.setProperty(name, value);
|
|
25
|
+
}
|
|
26
|
+
var RegionLayer = class {
|
|
27
|
+
#drawn = [];
|
|
28
|
+
#held;
|
|
29
|
+
#host;
|
|
30
|
+
#key;
|
|
31
|
+
#keyScrub;
|
|
32
|
+
constructor(host, signal) {
|
|
33
|
+
const render = () => {
|
|
34
|
+
this.render();
|
|
35
|
+
};
|
|
36
|
+
const observer = new MutationObserver(render);
|
|
37
|
+
this.#host = host;
|
|
38
|
+
this.#bindPointer(signal);
|
|
39
|
+
this.#bindKeys(signal);
|
|
40
|
+
observer.observe(host.element, { childList: true });
|
|
41
|
+
ownRegions(host.element, (region) => {
|
|
42
|
+
this.#redraw(region);
|
|
43
|
+
}, signal);
|
|
44
|
+
signal.addEventListener("abort", () => {
|
|
45
|
+
observer.disconnect();
|
|
46
|
+
this.#release();
|
|
47
|
+
this.#endKeyScrub();
|
|
48
|
+
}, { once: true });
|
|
49
|
+
}
|
|
50
|
+
abandon() {
|
|
51
|
+
this.#release(true);
|
|
52
|
+
}
|
|
53
|
+
follow() {
|
|
54
|
+
if (this.#stripKey() !== this.#key) this.render();
|
|
55
|
+
}
|
|
56
|
+
isHeld() {
|
|
57
|
+
return this.#held !== void 0;
|
|
58
|
+
}
|
|
59
|
+
render() {
|
|
60
|
+
const host = this.#host;
|
|
61
|
+
const drawn = [...host.element.children].filter((child) => child instanceof SonicRegion).map((region) => this.#draw(region));
|
|
62
|
+
this.#drawn = drawn;
|
|
63
|
+
this.#key = this.#stripKey();
|
|
64
|
+
placeChildren(host.layer, drawn.map(({ part }) => part));
|
|
65
|
+
this.#dropGone();
|
|
66
|
+
}
|
|
67
|
+
take(event) {
|
|
68
|
+
const host = this.#host;
|
|
69
|
+
const { startPx, travelPx } = host.axis();
|
|
70
|
+
const mapping = host.mapping();
|
|
71
|
+
const index = regionAt(this.#drawn.map((entry) => {
|
|
72
|
+
if (!this.#isEnabled(entry)) return;
|
|
73
|
+
const { end, start } = entry.link.span();
|
|
74
|
+
return [mapping.proportionOf(start) * travelPx, mapping.proportionOf(end) * travelPx];
|
|
75
|
+
}), event.clientX - startPx);
|
|
76
|
+
const pressed = index === void 0 ? void 0 : this.#drawn[index];
|
|
77
|
+
if (!pressed) return false;
|
|
78
|
+
this.#endKeyScrub();
|
|
79
|
+
const from = pressed.link.span();
|
|
80
|
+
this.#held = {
|
|
81
|
+
drawn: pressed,
|
|
82
|
+
from,
|
|
83
|
+
outside: host.outside(),
|
|
84
|
+
pointerId: event.pointerId,
|
|
85
|
+
press: event,
|
|
86
|
+
state: startRegionDrag({
|
|
87
|
+
from,
|
|
88
|
+
position: event.clientX,
|
|
89
|
+
thresholdPx: dragThresholdPx(event.pointerType),
|
|
90
|
+
widthPx: travelPx
|
|
91
|
+
})
|
|
92
|
+
};
|
|
93
|
+
pressed.link.hold("pointer");
|
|
94
|
+
capturePointer(host.control, event.pointerId);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
#bindKeys(signal) {
|
|
98
|
+
const { layer } = this.#host;
|
|
99
|
+
layer.addEventListener("keydown", (event) => {
|
|
100
|
+
const entry = this.#drawn.find(({ part }) => part === event.target);
|
|
101
|
+
if (!entry || event.defaultPrevented || this.#held) return;
|
|
102
|
+
if (this.#isEnabled(entry)) this.#keyTo(entry, event);
|
|
103
|
+
}, { signal });
|
|
104
|
+
layer.addEventListener("keyup", (event) => {
|
|
105
|
+
if (event.key === "Meta" || event.key === this.#keyScrub?.key) this.#endKeyScrub();
|
|
106
|
+
}, { signal });
|
|
107
|
+
layer.addEventListener("focusin", () => {
|
|
108
|
+
this.render();
|
|
109
|
+
}, { signal });
|
|
110
|
+
layer.addEventListener("focusout", () => {
|
|
111
|
+
this.#endKeyScrub();
|
|
112
|
+
}, { signal });
|
|
113
|
+
}
|
|
114
|
+
#bindPointer(signal) {
|
|
115
|
+
const whileHeld = (type, handle) => {
|
|
116
|
+
this.#host.control.addEventListener(type, (event) => {
|
|
117
|
+
const held = this.#held;
|
|
118
|
+
if (held && event instanceof PointerEvent && held.pointerId === event.pointerId) handle(held, event);
|
|
119
|
+
}, { signal });
|
|
120
|
+
};
|
|
121
|
+
whileHeld("pointermove", (hold, event) => {
|
|
122
|
+
this.#dragTo(hold, event);
|
|
123
|
+
});
|
|
124
|
+
whileHeld("pointerup", (hold) => {
|
|
125
|
+
const isPress = !hold.state.isEngaged;
|
|
126
|
+
this.#release();
|
|
127
|
+
if (isPress) this.#host.seek(hold.press);
|
|
128
|
+
});
|
|
129
|
+
whileHeld("pointercancel", () => {
|
|
130
|
+
this.#release(true);
|
|
131
|
+
});
|
|
132
|
+
whileHeld("lostpointercapture", () => {
|
|
133
|
+
this.#release();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
#dragTo(hold, event) {
|
|
137
|
+
const wasEngaged = hold.state.isEngaged;
|
|
138
|
+
const { span, state } = stepRegionDrag(this.#host.mapping(), hold.state, {
|
|
139
|
+
isFine: event.shiftKey,
|
|
140
|
+
position: event.clientX
|
|
141
|
+
});
|
|
142
|
+
hold.state = state;
|
|
143
|
+
if (!span) return;
|
|
144
|
+
if (!wasEngaged) focusByPointer(hold.drawn.part);
|
|
145
|
+
hold.drawn.link.input(hold.outside?.(event) === true ? hold.from : span);
|
|
146
|
+
}
|
|
147
|
+
#draw(region) {
|
|
148
|
+
const host = this.#host;
|
|
149
|
+
const known = this.#drawn.find((entry) => entry.region === region);
|
|
150
|
+
const entry = known ?? {
|
|
151
|
+
kind: void 0,
|
|
152
|
+
link: linkRegion(region),
|
|
153
|
+
part: renderPart(),
|
|
154
|
+
region
|
|
155
|
+
};
|
|
156
|
+
const { link, part } = entry;
|
|
157
|
+
const mapping = host.mapping();
|
|
158
|
+
const span = link.span();
|
|
159
|
+
const [low, high] = regionTravel(span, mapping.bounds);
|
|
160
|
+
const canMove = this.#isEnabled(entry);
|
|
161
|
+
writeProperty(part, "--_sonic-region-from", String(mapping.proportionOf(span.start)));
|
|
162
|
+
writeProperty(part, "--_sonic-region-to", String(mapping.proportionOf(span.end)));
|
|
163
|
+
if (!known || entry.kind !== region.kind) {
|
|
164
|
+
entry.kind = region.kind;
|
|
165
|
+
writeKind(part, region.kind, "--_sonic-ink");
|
|
166
|
+
}
|
|
167
|
+
writeAttribute(part, "data-sonic-clipped", clippedEnds(region, mapping.bounds));
|
|
168
|
+
writeAttribute(part, "aria-valuemin", String(low));
|
|
169
|
+
writeAttribute(part, "aria-valuemax", String(high));
|
|
170
|
+
writeAttribute(part, "aria-valuenow", String(span.start));
|
|
171
|
+
writeAttribute(part, "aria-valuetext", host.speak(span));
|
|
172
|
+
writeAttribute(part, "aria-disabled", canMove ? void 0 : "true");
|
|
173
|
+
writeAttribute(part, "tabindex", canMove ? "0" : void 0);
|
|
174
|
+
link.draw(part);
|
|
175
|
+
return entry;
|
|
176
|
+
}
|
|
177
|
+
#dropGone() {
|
|
178
|
+
const isGone = (entry) => !this.#drawn.includes(entry) || !this.#isEnabled(entry);
|
|
179
|
+
if (this.#held && isGone(this.#held.drawn)) this.#release();
|
|
180
|
+
if (this.#keyScrub && isGone(this.#keyScrub.drawn)) this.#endKeyScrub();
|
|
181
|
+
}
|
|
182
|
+
#endKeyScrub() {
|
|
183
|
+
const scrub = this.#keyScrub;
|
|
184
|
+
if (!scrub) return;
|
|
185
|
+
const { link } = scrub.drawn;
|
|
186
|
+
this.#keyScrub = void 0;
|
|
187
|
+
link.hold(void 0);
|
|
188
|
+
if (hasMoved(scrub.from, link.span())) link.change();
|
|
189
|
+
}
|
|
190
|
+
#isEnabled({ link }) {
|
|
191
|
+
return !this.#host.isDisabled() && !link.isDisabled();
|
|
192
|
+
}
|
|
193
|
+
#keyTo(entry, event) {
|
|
194
|
+
const mapping = this.#host.mapping();
|
|
195
|
+
const from = entry.link.span();
|
|
196
|
+
const start = mapping.keyTarget(event.key, from.start);
|
|
197
|
+
if (start === void 0) return;
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
const next = moveRegionTo(mapping, from, start);
|
|
200
|
+
if (!event.repeat) {
|
|
201
|
+
this.#endKeyScrub();
|
|
202
|
+
if (entry.link.input(next)) entry.link.change();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (this.#keyScrub?.drawn !== entry || this.#keyScrub.key !== event.key) {
|
|
206
|
+
this.#endKeyScrub();
|
|
207
|
+
this.#keyScrub = {
|
|
208
|
+
drawn: entry,
|
|
209
|
+
from,
|
|
210
|
+
key: event.key
|
|
211
|
+
};
|
|
212
|
+
entry.link.hold("keys");
|
|
213
|
+
}
|
|
214
|
+
entry.link.input(next);
|
|
215
|
+
}
|
|
216
|
+
#redraw(region) {
|
|
217
|
+
if (this.#drawn.every((entry) => entry.region !== region)) {
|
|
218
|
+
this.render();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
this.#draw(region);
|
|
222
|
+
this.#dropGone();
|
|
223
|
+
}
|
|
224
|
+
#release(isRestored = false) {
|
|
225
|
+
const hold = this.#held;
|
|
226
|
+
if (!hold) return;
|
|
227
|
+
const { link } = hold.drawn;
|
|
228
|
+
this.#held = void 0;
|
|
229
|
+
if (isRestored) link.input(hold.from);
|
|
230
|
+
link.hold(void 0);
|
|
231
|
+
if (hasMoved(hold.from, link.span())) link.change();
|
|
232
|
+
}
|
|
233
|
+
#stripKey() {
|
|
234
|
+
const host = this.#host;
|
|
235
|
+
const mapping = host.mapping();
|
|
236
|
+
const [low, high] = mapping.bounds;
|
|
237
|
+
return [
|
|
238
|
+
low,
|
|
239
|
+
high,
|
|
240
|
+
mapping.proportionOf((low + high) / 2),
|
|
241
|
+
host.isDisabled(),
|
|
242
|
+
host.speak({
|
|
243
|
+
end: high,
|
|
244
|
+
start: high
|
|
245
|
+
})
|
|
246
|
+
].join("|");
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
export { RegionLayer };
|
|
252
|
+
//# sourceMappingURL=region-layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"region-layer.js","names":[],"sources":["../../../src/elements/region-layer.ts"],"sourcesContent":["import type { RegionLink } from '#elements/region.ts';\nimport type { RegionDragState, RegionSpan } from '#lib/region-drag.ts';\nimport type { ValueMapping } from '#lib/value-mapping.ts';\n\nimport { linkRegion, ownRegions, SonicRegion } from '#elements/region.ts';\nimport { dragThresholdPx } from '#lib/drag-step.ts';\nimport { focusByPointer } from '#lib/focus-by-pointer.ts';\nimport { writeKind } from '#lib/marker-band.ts';\nimport { capturePointer } from '#lib/pointer-drag.ts';\nimport {\n\tmoveRegionTo,\n\tregionAt,\n\tregionTravel,\n\tstartRegionDrag,\n\tstepRegionDrag,\n} from '#lib/region-drag.ts';\nimport { placeChildren, template } from '#lib/render.ts';\nimport { writeAttribute } from '#lib/write-attribute.ts';\n\ninterface LayerHost {\n\taxis: () => { startPx: number; travelPx: number };\n\tcontrol: HTMLElement;\n\telement: HTMLElement;\n\tisDisabled: () => boolean;\n\tlayer: HTMLElement;\n\tmapping: () => ValueMapping;\n\toutside: () => ((event: PointerEvent) => boolean) | undefined;\n\tseek: (event: PointerEvent) => void;\n\tspeak: (span: RegionSpan) => string;\n}\n\ninterface Drawn {\n\tkind: string | undefined;\n\tlink: RegionLink;\n\tpart: HTMLElement;\n\tregion: SonicRegion;\n}\n\ninterface KeyScrub {\n\tdrawn: Drawn;\n\tfrom: RegionSpan;\n\tkey: string;\n}\n\ninterface PointerHold {\n\tdrawn: Drawn;\n\tfrom: RegionSpan;\n\toutside: ((event: PointerEvent) => boolean) | undefined;\n\tpointerId: number;\n\tpress: PointerEvent;\n\tstate: RegionDragState;\n}\n\nconst renderPart = template(\n\t/* HTML */ `\n\t\t<div class=\"sonic-region\" role=\"slider\" aria-orientation=\"horizontal\">\n\t\t\t<div class=\"sonic-region-bracket\"></div>\n\t\t</div>\n\t`,\n\tHTMLDivElement,\n);\n\nfunction hasMoved(from: RegionSpan, to: RegionSpan): boolean {\n\treturn from.start !== to.start || from.end !== to.end;\n}\n\nfunction clippedEnds(region: SonicRegion, [low, high]: [number, number]): string | undefined {\n\tconst ends = [\n\t\t...(Math.min(region.start, region.end) < low ? ['start'] : []),\n\t\t...(Math.max(region.start, region.end) > high ? ['end'] : []),\n\t];\n\n\treturn ends.length > 0 ? ends.join(' ') : undefined;\n}\n\nfunction writeProperty(part: HTMLElement, name: string, value: string): void {\n\tif (part.style.getPropertyValue(name) !== value) part.style.setProperty(name, value);\n}\n\nexport class RegionLayer {\n\t#drawn: Array<Drawn> = [];\n\n\t#held: PointerHold | undefined;\n\n\treadonly #host: LayerHost;\n\n\t#key: string | undefined;\n\n\t#keyScrub: KeyScrub | undefined;\n\n\tconstructor(host: LayerHost, signal: AbortSignal) {\n\t\tconst render = (): void => {\n\t\t\tthis.render();\n\t\t};\n\t\tconst observer = new MutationObserver(render);\n\n\t\tthis.#host = host;\n\t\tthis.#bindPointer(signal);\n\t\tthis.#bindKeys(signal);\n\t\tobserver.observe(host.element, { childList: true });\n\t\townRegions(\n\t\t\thost.element,\n\t\t\t(region) => {\n\t\t\t\tthis.#redraw(region);\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tobserver.disconnect();\n\t\t\t\tthis.#release();\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\tabandon(): void {\n\t\tthis.#release(true);\n\t}\n\n\tfollow(): void {\n\t\tif (this.#stripKey() !== this.#key) this.render();\n\t}\n\n\tisHeld(): boolean {\n\t\treturn this.#held !== undefined;\n\t}\n\n\trender(): void {\n\t\tconst host = this.#host;\n\t\tconst regions = [...host.element.children].filter((child) => child instanceof SonicRegion);\n\t\tconst drawn = regions.map((region) => this.#draw(region));\n\n\t\tthis.#drawn = drawn;\n\t\tthis.#key = this.#stripKey();\n\t\tplaceChildren(\n\t\t\thost.layer,\n\t\t\tdrawn.map(({ part }) => part),\n\t\t);\n\t\tthis.#dropGone();\n\t}\n\n\ttake(event: PointerEvent): boolean {\n\t\tconst host = this.#host;\n\t\tconst { startPx, travelPx } = host.axis();\n\t\tconst mapping = host.mapping();\n\t\tconst index = regionAt(\n\t\t\tthis.#drawn.map((entry) => {\n\t\t\t\tif (!this.#isEnabled(entry)) return;\n\n\t\t\t\tconst { end, start } = entry.link.span();\n\n\t\t\t\treturn [mapping.proportionOf(start) * travelPx, mapping.proportionOf(end) * travelPx];\n\t\t\t}),\n\t\t\tevent.clientX - startPx,\n\t\t);\n\t\tconst pressed = index === undefined ? undefined : this.#drawn[index];\n\t\tif (!pressed) return false;\n\n\t\tthis.#endKeyScrub();\n\n\t\tconst from = pressed.link.span();\n\n\t\tthis.#held = {\n\t\t\tdrawn: pressed,\n\t\t\tfrom,\n\t\t\toutside: host.outside(),\n\t\t\tpointerId: event.pointerId,\n\t\t\tpress: event,\n\t\t\tstate: startRegionDrag({\n\t\t\t\tfrom,\n\t\t\t\tposition: event.clientX,\n\t\t\t\tthresholdPx: dragThresholdPx(event.pointerType),\n\t\t\t\twidthPx: travelPx,\n\t\t\t}),\n\t\t};\n\t\tpressed.link.hold('pointer');\n\t\tcapturePointer(host.control, event.pointerId);\n\n\t\treturn true;\n\t}\n\n\t#bindKeys(signal: AbortSignal): void {\n\t\tconst { layer } = this.#host;\n\n\t\tlayer.addEventListener(\n\t\t\t'keydown',\n\t\t\t(event) => {\n\t\t\t\tconst entry = this.#drawn.find(({ part }) => part === event.target);\n\t\t\t\tif (!entry || event.defaultPrevented || this.#held) return;\n\n\t\t\t\tif (this.#isEnabled(entry)) this.#keyTo(entry, event);\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tlayer.addEventListener(\n\t\t\t'keyup',\n\t\t\t(event) => {\n\t\t\t\t// macOS sends no `keyup` for a key let go while Cmd is down\n\t\t\t\tif (event.key === 'Meta' || event.key === this.#keyScrub?.key) this.#endKeyScrub();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\t// No event fires when a label arrives, so focus picks it up\n\t\tlayer.addEventListener(\n\t\t\t'focusin',\n\t\t\t() => {\n\t\t\t\tthis.render();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tlayer.addEventListener(\n\t\t\t'focusout',\n\t\t\t() => {\n\t\t\t\tthis.#endKeyScrub();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t}\n\n\t#bindPointer(signal: AbortSignal): void {\n\t\tconst whileHeld = (\n\t\t\ttype: string,\n\t\t\thandle: (hold: PointerHold, event: PointerEvent) => void,\n\t\t): void => {\n\t\t\tthis.#host.control.addEventListener(\n\t\t\t\ttype,\n\t\t\t\t(event) => {\n\t\t\t\t\tconst held = this.#held;\n\n\t\t\t\t\tif (held && event instanceof PointerEvent && held.pointerId === event.pointerId) {\n\t\t\t\t\t\thandle(held, event);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t};\n\n\t\twhileHeld('pointermove', (hold, event) => {\n\t\t\tthis.#dragTo(hold, event);\n\t\t});\n\t\twhileHeld('pointerup', (hold) => {\n\t\t\tconst isPress = !hold.state.isEngaged;\n\n\t\t\tthis.#release();\n\t\t\tif (isPress) this.#host.seek(hold.press);\n\t\t});\n\t\twhileHeld('pointercancel', () => {\n\t\t\tthis.#release(true);\n\t\t});\n\t\twhileHeld('lostpointercapture', () => {\n\t\t\tthis.#release();\n\t\t});\n\t}\n\n\t#dragTo(hold: PointerHold, event: PointerEvent): void {\n\t\tconst wasEngaged = hold.state.isEngaged;\n\t\tconst { span, state } = stepRegionDrag(this.#host.mapping(), hold.state, {\n\t\t\tisFine: event.shiftKey,\n\t\t\tposition: event.clientX,\n\t\t});\n\n\t\thold.state = state;\n\t\tif (!span) return;\n\n\t\tif (!wasEngaged) focusByPointer(hold.drawn.part);\n\t\thold.drawn.link.input(hold.outside?.(event) === true ? hold.from : span);\n\t}\n\n\t#draw(region: SonicRegion): Drawn {\n\t\tconst host = this.#host;\n\t\tconst known = this.#drawn.find((entry) => entry.region === region);\n\t\tconst entry = known ?? {\n\t\t\tkind: undefined,\n\t\t\tlink: linkRegion(region),\n\t\t\tpart: renderPart(),\n\t\t\tregion,\n\t\t};\n\t\tconst { link, part } = entry;\n\t\tconst mapping = host.mapping();\n\t\tconst span = link.span();\n\t\tconst [low, high] = regionTravel(span, mapping.bounds);\n\t\tconst canMove = this.#isEnabled(entry);\n\n\t\twriteProperty(part, '--_sonic-region-from', String(mapping.proportionOf(span.start)));\n\t\twriteProperty(part, '--_sonic-region-to', String(mapping.proportionOf(span.end)));\n\t\tif (!known || entry.kind !== region.kind) {\n\t\t\tentry.kind = region.kind;\n\t\t\twriteKind(part, region.kind, '--_sonic-ink');\n\t\t}\n\t\twriteAttribute(part, 'data-sonic-clipped', clippedEnds(region, mapping.bounds));\n\t\twriteAttribute(part, 'aria-valuemin', String(low));\n\t\twriteAttribute(part, 'aria-valuemax', String(high));\n\t\twriteAttribute(part, 'aria-valuenow', String(span.start));\n\t\twriteAttribute(part, 'aria-valuetext', host.speak(span));\n\t\twriteAttribute(part, 'aria-disabled', canMove ? undefined : 'true');\n\t\twriteAttribute(part, 'tabindex', canMove ? '0' : undefined);\n\t\tlink.draw(part);\n\n\t\treturn entry;\n\t}\n\n\t#dropGone(): void {\n\t\tconst isGone = (entry: Drawn): boolean =>\n\t\t\t!this.#drawn.includes(entry) || !this.#isEnabled(entry);\n\n\t\tif (this.#held && isGone(this.#held.drawn)) this.#release();\n\t\tif (this.#keyScrub && isGone(this.#keyScrub.drawn)) this.#endKeyScrub();\n\t}\n\n\t#endKeyScrub(): void {\n\t\tconst scrub = this.#keyScrub;\n\t\tif (!scrub) return;\n\n\t\tconst { link } = scrub.drawn;\n\n\t\tthis.#keyScrub = undefined;\n\t\tlink.hold(undefined);\n\t\tif (hasMoved(scrub.from, link.span())) link.change();\n\t}\n\n\t#isEnabled({ link }: Drawn): boolean {\n\t\treturn !this.#host.isDisabled() && !link.isDisabled();\n\t}\n\n\t#keyTo(entry: Drawn, event: KeyboardEvent): void {\n\t\tconst mapping = this.#host.mapping();\n\t\tconst from = entry.link.span();\n\t\tconst start = mapping.keyTarget(event.key, from.start);\n\t\tif (start === undefined) return;\n\n\t\tevent.preventDefault();\n\n\t\tconst next = moveRegionTo(mapping, from, start);\n\n\t\tif (!event.repeat) {\n\t\t\tthis.#endKeyScrub();\n\t\t\tif (entry.link.input(next)) entry.link.change();\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.#keyScrub?.drawn !== entry || this.#keyScrub.key !== event.key) {\n\t\t\tthis.#endKeyScrub();\n\t\t\tthis.#keyScrub = { drawn: entry, from, key: event.key };\n\t\t\tentry.link.hold('keys');\n\t\t}\n\t\tentry.link.input(next);\n\t}\n\n\t#redraw(region: SonicRegion): void {\n\t\tif (this.#drawn.every((entry) => entry.region !== region)) {\n\t\t\tthis.render();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#draw(region);\n\t\tthis.#dropGone();\n\t}\n\n\t#release(isRestored = false): void {\n\t\tconst hold = this.#held;\n\t\tif (!hold) return;\n\n\t\tconst { link } = hold.drawn;\n\n\t\tthis.#held = undefined;\n\t\tif (isRestored) link.input(hold.from);\n\t\tlink.hold(undefined);\n\t\tif (hasMoved(hold.from, link.span())) link.change();\n\t}\n\n\t// A changed value formatter is told by what it says of one time\n\t#stripKey(): string {\n\t\tconst host = this.#host;\n\t\tconst mapping = host.mapping();\n\t\tconst [low, high] = mapping.bounds;\n\n\t\treturn [\n\t\t\tlow,\n\t\t\thigh,\n\t\t\tmapping.proportionOf((low + high) / 2),\n\t\t\thost.isDisabled(),\n\t\t\thost.speak({ end: high, start: high }),\n\t\t].join('|');\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SonicFormElement } from "./form-element.js";
|
|
2
|
+
import { Seconds } from "../lib/units.js";
|
|
3
|
+
//#region src/elements/region.d.ts
|
|
4
|
+
declare global {
|
|
5
|
+
interface HTMLElementTagNameMap {
|
|
6
|
+
'sonic-region': SonicRegion;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export declare class SonicRegion extends SonicFormElement {
|
|
10
|
+
#private;
|
|
11
|
+
static readonly observedAttributes: string[];
|
|
12
|
+
get dragging(): boolean;
|
|
13
|
+
get end(): Seconds;
|
|
14
|
+
set end(next: null | Seconds | undefined);
|
|
15
|
+
/** Lowercase letters, digits and hyphens; colours the region through `--sonic-marker-<kind>` */
|
|
16
|
+
get kind(): string | undefined;
|
|
17
|
+
set kind(kind: string | undefined);
|
|
18
|
+
get start(): Seconds;
|
|
19
|
+
set start(next: null | Seconds | undefined);
|
|
20
|
+
attributeChangedCallback(name: string): void;
|
|
21
|
+
connectedCallback(): void;
|
|
22
|
+
formResetCallback(): void;
|
|
23
|
+
protected connect(): void;
|
|
24
|
+
protected focusTarget(): HTMLElement | undefined;
|
|
25
|
+
protected render(): void;
|
|
26
|
+
protected restoreState(state: string): void;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//# sourceMappingURL=region.d.ts.map
|