@xsynaptic/sonic-ui 0.19.0 → 0.21.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 +37 -0
- package/README.md +27 -112
- package/dist/default/elements/button.js +2 -1
- package/dist/default/elements/field-gesture.js +3 -0
- package/dist/default/elements/sonic-element.js +1 -1
- package/dist/default/elements/split.js +3 -1
- package/dist/default/elements/switch.js +5 -3
- package/dist/default/elements/toggle.js +10 -5
- package/dist/default/elements/value-entry.js +5 -18
- package/dist/default/elements/waveform.js +15 -4
- package/dist/default/elements/xy.js +33 -5
- package/dist/default/lib/canvas-surface.js +5 -1
- package/dist/default/lib/double-press.js +30 -0
- package/dist/dev/elements/button.js +5 -11
- package/dist/dev/elements/button.js.map +1 -1
- package/dist/dev/elements/dial.js +2 -12
- package/dist/dev/elements/dial.js.map +1 -1
- package/dist/dev/elements/display-element.js +1 -5
- package/dist/dev/elements/display-element.js.map +1 -1
- package/dist/dev/elements/envelope.js +2 -15
- package/dist/dev/elements/envelope.js.map +1 -1
- package/dist/dev/elements/field-gesture.js +3 -0
- package/dist/dev/elements/field-gesture.js.map +1 -1
- package/dist/dev/elements/meter.js +1 -1
- package/dist/dev/elements/meter.js.map +1 -1
- package/dist/dev/elements/number.js +1 -13
- package/dist/dev/elements/number.js.map +1 -1
- package/dist/dev/elements/segmented.js +3 -10
- package/dist/dev/elements/segmented.js.map +1 -1
- package/dist/dev/elements/slider.js +2 -12
- package/dist/dev/elements/slider.js.map +1 -1
- package/dist/dev/elements/sonic-element.d.ts +1 -22
- package/dist/dev/elements/sonic-element.js +7 -34
- package/dist/dev/elements/sonic-element.js.map +1 -1
- package/dist/dev/elements/split.js +3 -1
- package/dist/dev/elements/split.js.map +1 -1
- package/dist/dev/elements/switch.js +7 -8
- package/dist/dev/elements/switch.js.map +1 -1
- package/dist/dev/elements/toggle.js +13 -15
- package/dist/dev/elements/toggle.js.map +1 -1
- package/dist/dev/elements/value-entry.js +5 -18
- package/dist/dev/elements/value-entry.js.map +1 -1
- package/dist/dev/elements/wave-element.js +2 -12
- package/dist/dev/elements/wave-element.js.map +1 -1
- package/dist/dev/elements/waveform.d.ts +2 -0
- package/dist/dev/elements/waveform.js +15 -4
- package/dist/dev/elements/waveform.js.map +1 -1
- package/dist/dev/elements/xy.d.ts +4 -0
- package/dist/dev/elements/xy.js +35 -17
- package/dist/dev/elements/xy.js.map +1 -1
- package/dist/dev/lib/canvas-surface.js +5 -1
- package/dist/dev/lib/canvas-surface.js.map +1 -1
- package/dist/dev/lib/double-press.js +31 -0
- package/dist/dev/lib/double-press.js.map +1 -0
- package/dist/skins/amber.css +0 -1
- package/dist/skins/ivory.css +0 -1
- package/dist/skins/lime.css +0 -1
- package/dist/skins/slate.css +0 -1
- package/dist/styles/button.css +1 -0
- package/dist/styles/dial.css +1 -1
- package/dist/styles/envelope.css +16 -14
- package/dist/styles/led.css +7 -19
- package/dist/styles/material/bracket.css +1 -1
- package/dist/styles/material/cap.css +27 -4
- package/dist/styles/material/core.css +9 -1
- package/dist/styles/material/glass.css +1 -7
- package/dist/styles/material/lens.css +18 -1
- package/dist/styles/material/pane.css +2 -12
- package/dist/styles/material/readout.css +7 -1
- package/dist/styles/material/well.css +8 -12
- package/dist/styles/meter.css +6 -4
- package/dist/styles/number.css +8 -9
- package/dist/styles/screen.css +1 -3
- package/dist/styles/spectrum.css +8 -22
- package/dist/styles/toggle.css +4 -0
- package/dist/styles/waveform.css +12 -24
- package/dist/styles/wavestrip.css +12 -33
- package/dist/styles/xy.css +30 -28
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-surface.js","names":["named"],"sources":["../../../src/lib/canvas-surface.ts"],"sourcesContent":["import { readPxProperty } from '#lib/read-px-property.ts';\n\ntype PrivateProperty = `--_sonic-${string}`;\n\nexport interface SurfaceSize {\n\tdpr: number;\n\theight: number;\n\twidth: number;\n}\n\nexport interface SurfaceLook<\n\tColour extends string,\n\tLength extends string = never,\n\tNumeric extends string = never,\n> {\n\tcolours: Record<Colour, string>;\n\tisReducedMotion: boolean;\n\tlengths: Record<Length, number>;\n\tnumbers: Record<Numeric, number>;\n}\n\nexport interface SurfaceFrame<\n\tColour extends string,\n\tLength extends string = never,\n\tNumeric extends string = never,\n> {\n\tframeMs: number;\n\tisDirty: boolean;\n\tisRebuilt: boolean;\n\tlook: SurfaceLook<Colour, Length, Numeric>;\n\tsize: SurfaceSize;\n}\n\nexport interface Surface {\n\tinvalidate: () => void;\n\treadonly isVisible: boolean;\n\trebuild: () => void;\n\trequestFrame: () => void;\n\tsetFill: (isFilling: boolean) => void;\n\treadonly size: SurfaceSize;\n}\n\ninterface SurfaceOptions<Colour extends string, Length extends string, Numeric extends string> {\n\tcanvas: HTMLCanvasElement;\n\tcolours: Record<Colour, PrivateProperty>;\n\tfill?: { control: HTMLElement; sizeProperty: PrivateProperty };\n\tlengths?: Record<Length, PrivateProperty>;\n\tnumbers?: Record<Numeric, PrivateProperty>;\n\tpaint: (context: CanvasRenderingContext2D, frame: SurfaceFrame<Colour, Length, Numeric>) => void;\n\tresize?: (size: SurfaceSize) => void;\n\tsignal: AbortSignal;\n}\n\nfunction deviceRatio(): number {\n\treturn globalThis.devicePixelRatio || 1;\n}\n\n// WebKit reports none, and an emulated device scale reports it in CSS px, so it counts only where it agrees\nfunction deviceBox(\n\tentry: ResizeObserverEntry,\n\tcss: ResizeObserverSize,\n): ResizeObserverSize | undefined {\n\tconst device =\n\t\t'devicePixelContentBoxSize' in entry ? entry.devicePixelContentBoxSize[0] : undefined;\n\tconst dpr = deviceRatio();\n\tif (!device || Math.abs(device.inlineSize - css.inlineSize * dpr) > 1) return undefined;\n\n\treturn Math.abs(device.blockSize - css.blockSize * dpr) > 1 ? undefined : device;\n}\n\n// `Object.fromEntries` widens the keys to `string`\nfunction readEach<Name extends string, Value>(\n\tproperties: Partial<Record<Name, PrivateProperty>>,\n\tread: (property: PrivateProperty) => Value,\n): Record<Name, Value> {\n\tconst named: Readonly<Record<string, PrivateProperty | undefined>> = properties;\n\n\treturn Object.fromEntries(\n\t\tObject.entries(named).flatMap(([name, property]) =>\n\t\t\tproperty === undefined ? [] : [[name, read(property)]],\n\t\t),\n\t) as Record<Name, Value>;\n}\n\nclass CanvasSurface<\n\tColour extends string,\n\tLength extends string,\n\tNumeric extends string,\n> implements Surface {\n\tget isVisible(): boolean {\n\t\treturn this.#isVisible;\n\t}\n\n\tget size(): SurfaceSize {\n\t\treturn this.#size;\n\t}\n\n\t// happy-dom has no canvas context\n\treadonly #context: CanvasRenderingContext2D | undefined;\n\n\t#cssBox: undefined | { height: number; width: number };\n\n\t#fillWatch: ResizeObserver | undefined;\n\n\t#frame: number | undefined;\n\n\t#isDirty = true;\n\n\t#isRebuildWanted = true;\n\n\t#isVisible = true;\n\n\t#look: SurfaceLook<Colour, Length, Numeric> | undefined;\n\n\treadonly #options: SurfaceOptions<Colour, Length, Numeric>;\n\n\treadonly #reducedMotion = matchMedia('(prefers-reduced-motion: reduce)');\n\n\t#size: SurfaceSize = { dpr: deviceRatio(), height: 0, width: 0 };\n\n\tconstructor(options: SurfaceOptions<Colour, Length, Numeric>) {\n\t\tconst { canvas, signal } = options;\n\n\t\tthis.#options = options;\n\t\tthis.#context = canvas.getContext('2d') ?? undefined;\n\t\tthis.#armTransitions();\n\t\tthis.#observeSize();\n\t\tthis.#observeView();\n\t\tthis.#watchResolution();\n\t\tthis.#reducedMotion.addEventListener(\n\t\t\t'change',\n\t\t\t() => {\n\t\t\t\tthis.rebuild();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\t// `transitionstart` drops events when a change replaces a pending transition in WebKit\n\t\tcanvas.addEventListener(\n\t\t\t'transitionrun',\n\t\t\t() => {\n\t\t\t\tthis.rebuild();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tif (this.#frame !== undefined) cancelAnimationFrame(this.#frame);\n\t\t\t\tthis.#frame = undefined;\n\t\t\t\tthis.#stopFill();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t\tthis.#schedule();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.#isDirty = true;\n\t\tthis.#schedule();\n\t}\n\n\trebuild(): void {\n\t\tthis.#isRebuildWanted = true;\n\t\tthis.invalidate();\n\t}\n\n\trequestFrame(): void {\n\t\tthis.#schedule();\n\t}\n\n\tsetFill(isFilling: boolean): void {\n\t\tconst { fill, signal } = this.#options;\n\t\tif (!fill || signal.aborted || isFilling === (this.#fillWatch !== undefined)) return;\n\n\t\tconst { style } = fill.control;\n\n\t\tthis.#stopFill();\n\t\tif (!isFilling) {\n\t\t\tstyle.removeProperty(fill.sizeProperty);\n\t\t\treturn;\n\t\t}\n\n\t\tconst started = new ResizeObserver((entries) => {\n\t\t\tconst box = entries.at(-1)?.borderBoxSize[0];\n\t\t\tif (!box) return;\n\n\t\t\t// Written a frame on, or the canvas resizes inside this delivery and WebKit reports a loop\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tif (this.#fillWatch === started) {\n\t\t\t\t\tstyle.setProperty(fill.sizeProperty, `${String(box.blockSize)}px`);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tthis.#fillWatch = started;\n\t\tstarted.observe(fill.control);\n\t}\n\n\t#armTransitions(): void {\n\t\tconst { canvas, colours, numbers = {} } = this.#options;\n\t\tconst { style } = canvas;\n\t\tconst watched = [...Object.values(colours), ...Object.values(numbers)];\n\n\t\tstyle.setProperty('transition-property', watched.join(', '));\n\t\tstyle.setProperty('transition-duration', '0.001ms');\n\t\tstyle.setProperty('transition-timing-function', 'step-start');\n\t\tstyle.setProperty('transition-behavior', 'allow-discrete');\n\t}\n\n\t#current(): { isRebuilt: boolean; look: SurfaceLook<Colour, Length, Numeric> } {\n\t\tif (this.#look && !this.#isRebuildWanted) return { isRebuilt: false, look: this.#look };\n\n\t\treturn { isRebuilt: true, look: this.#read() };\n\t}\n\n\t#draw(frameMs: number): void {\n\t\tthis.#frame = undefined;\n\n\t\tconst size = this.#size;\n\t\tif (size.width === 0 || size.height === 0) return;\n\n\t\tconst { canvas, paint } = this.#options;\n\t\tconst { isRebuilt, look } = this.#current();\n\t\tconst isDirty = this.#isDirty;\n\n\t\tthis.#look = look;\n\t\tthis.#isDirty = false;\n\t\tthis.#isRebuildWanted = false;\n\t\t// Assigning either clears the canvas and its state\n\t\tif (canvas.width !== size.width) canvas.width = size.width;\n\t\tif (canvas.height !== size.height) canvas.height = size.height;\n\t\tif (this.#context) paint(this.#context, { frameMs, isDirty, isRebuilt, look, size });\n\t}\n\n\t#measure(entry: ResizeObserverEntry): void {\n\t\tconst [box] = entry.contentBoxSize;\n\t\tif (!box) return;\n\n\t\tconst device = deviceBox(entry, box);\n\n\t\tif (device) {\n\t\t\tthis.#cssBox = undefined;\n\t\t\tthis.#resize(device.inlineSize, device.blockSize);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#cssBox = { height: box.blockSize, width: box.inlineSize };\n\t\tthis.#rescale();\n\t}\n\n\t#observeSize(): void {\n\t\tconst { canvas, signal } = this.#options;\n\t\tconst observer = new ResizeObserver((entries) => {\n\t\t\tconst entry = entries.at(-1);\n\n\t\t\tif (entry) this.#measure(entry);\n\t\t});\n\n\t\ttry {\n\t\t\tobserver.observe(canvas, { box: 'device-pixel-content-box' });\n\t\t} catch {\n\t\t\t// WebKit throws a TypeError on the option\n\t\t\tobserver.observe(canvas, { box: 'content-box' });\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},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#observeView(): void {\n\t\tconst { canvas, signal } = this.#options;\n\t\tconst observer = new IntersectionObserver((entries) => {\n\t\t\tconst entry = entries.at(-1);\n\t\t\tif (!entry) return;\n\n\t\t\tconst wasVisible = this.#isVisible;\n\n\t\t\tthis.#isVisible = entry.isIntersecting;\n\t\t\tif (!entry.isIntersecting && this.#frame !== undefined) {\n\t\t\t\tcancelAnimationFrame(this.#frame);\n\t\t\t\tthis.#frame = undefined;\n\t\t\t}\n\n\t\t\t// Chromium fires no transition inside a skipped `content-visibility` subtree\n\t\t\tif (!wasVisible && entry.isIntersecting) this.rebuild();\n\t\t});\n\n\t\tobserver.observe(canvas);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tobserver.disconnect();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#read(): SurfaceLook<Colour, Length, Numeric> {\n\t\tconst { canvas, colours, lengths = {}, numbers = {} } = this.#options;\n\t\tconst styles = getComputedStyle(canvas);\n\n\t\treturn {\n\t\t\tcolours: readEach(colours, (property) =>\n\t\t\t\tstyles\n\t\t\t\t\t.getPropertyValue(property)\n\t\t\t\t\t.trim()\n\t\t\t\t\t.replaceAll('currentcolor', () => styles.color),\n\t\t\t),\n\t\t\tisReducedMotion: this.#reducedMotion.matches,\n\t\t\tlengths: readEach<Length, number>(lengths, (property) => readPxProperty(styles, property, 0)),\n\t\t\tnumbers: readEach<Numeric, number>(numbers, (property) =>\n\t\t\t\treadPxProperty(styles, property, 0),\n\t\t\t),\n\t\t};\n\t}\n\n\t#rescale(): void {\n\t\tconst box = this.#cssBox;\n\t\tif (!box) {\n\t\t\tthis.#resize(this.#size.width, this.#size.height);\n\t\t\treturn;\n\t\t}\n\n\t\tconst dpr = deviceRatio();\n\n\t\tthis.#resize(Math.round(box.width * dpr), Math.round(box.height * dpr));\n\t}\n\n\t#resize(width: number, height: number): void {\n\t\tconst previous = this.#size;\n\t\tconst dpr = deviceRatio();\n\t\tif (previous.width === width && previous.height === height && previous.dpr === dpr) return;\n\n\t\tthis.#size = { dpr, height, width };\n\t\tthis.#options.resize?.(this.#size);\n\t\tif (previous.width === 0 || previous.height === 0) this.rebuild();\n\t\telse this.invalidate();\n\t}\n\n\t#schedule(): void {\n\t\tif (this.#options.signal.aborted || this.#frame !== undefined || !this.#isVisible) return;\n\n\t\tthis.#frame = requestAnimationFrame((frameMs) => {\n\t\t\tthis.#draw(frameMs);\n\t\t});\n\t}\n\n\t#stopFill(): void {\n\t\tthis.#fillWatch?.disconnect();\n\t\tthis.#fillWatch = undefined;\n\t}\n\n\t#watchResolution(): void {\n\t\tconst { signal } = this.#options;\n\n\t\tmatchMedia(`(resolution: ${String(deviceRatio())}dppx)`).addEventListener(\n\t\t\t'change',\n\t\t\t() => {\n\t\t\t\tthis.#watchResolution();\n\t\t\t\tthis.#rescale();\n\t\t\t},\n\t\t\t{ once: true, signal },\n\t\t);\n\t}\n}\n\nexport function bindSurface<\n\tColour extends string,\n\tLength extends string = never,\n\tNumeric extends string = never,\n>(options: SurfaceOptions<Colour, Length, Numeric>): Surface {\n\treturn new CanvasSurface(options);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"canvas-surface.js","names":["named"],"sources":["../../../src/lib/canvas-surface.ts"],"sourcesContent":["import { readPxProperty } from '#lib/read-px-property.ts';\n\ntype PrivateProperty = `--_sonic-${string}`;\n\nexport interface SurfaceSize {\n\tdpr: number;\n\theight: number;\n\twidth: number;\n}\n\nexport interface SurfaceLook<\n\tColour extends string,\n\tLength extends string = never,\n\tNumeric extends string = never,\n> {\n\tcolours: Record<Colour, string>;\n\tisReducedMotion: boolean;\n\tlengths: Record<Length, number>;\n\tnumbers: Record<Numeric, number>;\n}\n\nexport interface SurfaceFrame<\n\tColour extends string,\n\tLength extends string = never,\n\tNumeric extends string = never,\n> {\n\tframeMs: number;\n\tisDirty: boolean;\n\tisRebuilt: boolean;\n\tlook: SurfaceLook<Colour, Length, Numeric>;\n\tsize: SurfaceSize;\n}\n\nexport interface Surface {\n\tinvalidate: () => void;\n\treadonly isVisible: boolean;\n\trebuild: () => void;\n\trequestFrame: () => void;\n\tsetFill: (isFilling: boolean) => void;\n\treadonly size: SurfaceSize;\n}\n\ninterface SurfaceOptions<Colour extends string, Length extends string, Numeric extends string> {\n\tcanvas: HTMLCanvasElement;\n\tcolours: Record<Colour, PrivateProperty>;\n\tfill?: { control: HTMLElement; sizeProperty: PrivateProperty };\n\tlengths?: Record<Length, PrivateProperty>;\n\tnumbers?: Record<Numeric, PrivateProperty>;\n\tpaint: (context: CanvasRenderingContext2D, frame: SurfaceFrame<Colour, Length, Numeric>) => void;\n\tresize?: (size: SurfaceSize) => void;\n\tsignal: AbortSignal;\n}\n\nfunction deviceRatio(): number {\n\treturn globalThis.devicePixelRatio || 1;\n}\n\n// WebKit reports none, and an emulated device scale reports it in CSS px, so it counts only where it agrees\nfunction deviceBox(\n\tentry: ResizeObserverEntry,\n\tcss: ResizeObserverSize,\n): ResizeObserverSize | undefined {\n\tconst device =\n\t\t'devicePixelContentBoxSize' in entry ? entry.devicePixelContentBoxSize[0] : undefined;\n\tconst dpr = deviceRatio();\n\tif (!device || Math.abs(device.inlineSize - css.inlineSize * dpr) > 1) return undefined;\n\n\treturn Math.abs(device.blockSize - css.blockSize * dpr) > 1 ? undefined : device;\n}\n\n// `Object.fromEntries` widens the keys to `string`\nfunction readEach<Name extends string, Value>(\n\tproperties: Partial<Record<Name, PrivateProperty>>,\n\tread: (property: PrivateProperty) => Value,\n): Record<Name, Value> {\n\tconst named: Readonly<Record<string, PrivateProperty | undefined>> = properties;\n\n\treturn Object.fromEntries(\n\t\tObject.entries(named).flatMap(([name, property]) =>\n\t\t\tproperty === undefined ? [] : [[name, read(property)]],\n\t\t),\n\t) as Record<Name, Value>;\n}\n\nclass CanvasSurface<\n\tColour extends string,\n\tLength extends string,\n\tNumeric extends string,\n> implements Surface {\n\tget isVisible(): boolean {\n\t\treturn this.#isVisible;\n\t}\n\n\tget size(): SurfaceSize {\n\t\treturn this.#size;\n\t}\n\n\t// happy-dom has no canvas context\n\treadonly #context: CanvasRenderingContext2D | undefined;\n\n\t#cssBox: undefined | { height: number; width: number };\n\n\t#fillWatch: ResizeObserver | undefined;\n\n\t#frame: number | undefined;\n\n\t#isDirty = true;\n\n\t#isRebuildWanted = true;\n\n\t#isVisible = true;\n\n\t#look: SurfaceLook<Colour, Length, Numeric> | undefined;\n\n\treadonly #options: SurfaceOptions<Colour, Length, Numeric>;\n\n\treadonly #reducedMotion = matchMedia('(prefers-reduced-motion: reduce)');\n\n\t#size: SurfaceSize = { dpr: deviceRatio(), height: 0, width: 0 };\n\n\tconstructor(options: SurfaceOptions<Colour, Length, Numeric>) {\n\t\tconst { canvas, signal } = options;\n\n\t\tthis.#options = options;\n\t\tthis.#context = canvas.getContext('2d') ?? undefined;\n\t\tthis.#armTransitions();\n\t\tthis.#observeSize();\n\t\tthis.#observeView();\n\t\tthis.#watchResolution();\n\t\tthis.#reducedMotion.addEventListener(\n\t\t\t'change',\n\t\t\t() => {\n\t\t\t\tthis.rebuild();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\t// `transitionstart` drops events when a change replaces a pending transition in WebKit\n\t\tcanvas.addEventListener(\n\t\t\t'transitionrun',\n\t\t\t() => {\n\t\t\t\tthis.rebuild();\n\t\t\t},\n\t\t\t{ signal },\n\t\t);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tif (this.#frame !== undefined) cancelAnimationFrame(this.#frame);\n\t\t\t\tthis.#frame = undefined;\n\t\t\t\tthis.#stopFill();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t\tthis.#schedule();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.#isDirty = true;\n\t\tthis.#schedule();\n\t}\n\n\trebuild(): void {\n\t\tthis.#isRebuildWanted = true;\n\t\tthis.invalidate();\n\t}\n\n\trequestFrame(): void {\n\t\tthis.#schedule();\n\t}\n\n\tsetFill(isFilling: boolean): void {\n\t\tconst { fill, signal } = this.#options;\n\t\tif (!fill || signal.aborted || isFilling === (this.#fillWatch !== undefined)) return;\n\n\t\tconst { style } = fill.control;\n\n\t\tthis.#stopFill();\n\t\tif (!isFilling) {\n\t\t\tstyle.removeProperty(fill.sizeProperty);\n\t\t\treturn;\n\t\t}\n\n\t\tconst started = new ResizeObserver((entries) => {\n\t\t\tconst box = entries.at(-1)?.borderBoxSize[0];\n\t\t\tif (!box) return;\n\n\t\t\t// Written a frame on, or the canvas resizes inside this delivery and WebKit reports a loop\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tif (this.#fillWatch === started) {\n\t\t\t\t\tstyle.setProperty(fill.sizeProperty, `${String(box.blockSize)}px`);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tthis.#fillWatch = started;\n\t\tstarted.observe(fill.control);\n\t}\n\n\t#armTransitions(): void {\n\t\tconst { canvas, colours, numbers = {} } = this.#options;\n\t\tconst { style } = canvas;\n\t\t// A colour mixed from `currentcolor` computes to the same text whatever `color` is\n\t\tconst watched = ['color', ...Object.values(colours), ...Object.values(numbers)];\n\n\t\tstyle.setProperty('transition-property', watched.join(', '));\n\t\tstyle.setProperty('transition-duration', '0.001ms');\n\t\tstyle.setProperty('transition-timing-function', 'step-start');\n\t\tstyle.setProperty('transition-behavior', 'allow-discrete');\n\t}\n\n\t#current(): { isRebuilt: boolean; look: SurfaceLook<Colour, Length, Numeric> } {\n\t\tif (this.#look && !this.#isRebuildWanted) return { isRebuilt: false, look: this.#look };\n\n\t\treturn { isRebuilt: true, look: this.#read() };\n\t}\n\n\t#draw(frameMs: number): void {\n\t\tthis.#frame = undefined;\n\n\t\tconst size = this.#size;\n\t\tif (size.width === 0 || size.height === 0) return;\n\n\t\tconst { canvas, paint } = this.#options;\n\t\tconst { isRebuilt, look } = this.#current();\n\t\tconst isDirty = this.#isDirty;\n\n\t\tthis.#look = look;\n\t\tthis.#isDirty = false;\n\t\tthis.#isRebuildWanted = false;\n\t\t// Assigning either clears the canvas and its state\n\t\tif (canvas.width !== size.width) canvas.width = size.width;\n\t\tif (canvas.height !== size.height) canvas.height = size.height;\n\t\tif (this.#context) paint(this.#context, { frameMs, isDirty, isRebuilt, look, size });\n\t}\n\n\t#measure(entry: ResizeObserverEntry): void {\n\t\tconst [box] = entry.contentBoxSize;\n\t\tif (!box) return;\n\n\t\tconst device = deviceBox(entry, box);\n\n\t\tif (device) {\n\t\t\tthis.#cssBox = undefined;\n\t\t\tthis.#resize(device.inlineSize, device.blockSize);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#cssBox = { height: box.blockSize, width: box.inlineSize };\n\t\tthis.#rescale();\n\t}\n\n\t#observeSize(): void {\n\t\tconst { canvas, signal } = this.#options;\n\t\tconst observer = new ResizeObserver((entries) => {\n\t\t\tconst entry = entries.at(-1);\n\n\t\t\tif (entry) this.#measure(entry);\n\t\t});\n\n\t\ttry {\n\t\t\tobserver.observe(canvas, { box: 'device-pixel-content-box' });\n\t\t} catch {\n\t\t\t// WebKit throws a TypeError on the option\n\t\t\tobserver.observe(canvas, { box: 'content-box' });\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},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#observeView(): void {\n\t\tconst { canvas, signal } = this.#options;\n\t\tconst observer = new IntersectionObserver((entries) => {\n\t\t\tconst entry = entries.at(-1);\n\t\t\tif (!entry) return;\n\n\t\t\tconst wasVisible = this.#isVisible;\n\n\t\t\tthis.#isVisible = entry.isIntersecting;\n\t\t\tif (!entry.isIntersecting && this.#frame !== undefined) {\n\t\t\t\tcancelAnimationFrame(this.#frame);\n\t\t\t\tthis.#frame = undefined;\n\t\t\t}\n\n\t\t\t// Chromium fires no transition inside a skipped `content-visibility` subtree\n\t\t\tif (!wasVisible && entry.isIntersecting) this.rebuild();\n\t\t});\n\n\t\tobserver.observe(canvas);\n\t\tsignal.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tobserver.disconnect();\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t}\n\n\t#read(): SurfaceLook<Colour, Length, Numeric> {\n\t\tconst { canvas, colours, lengths = {}, numbers = {} } = this.#options;\n\t\tconst styles = getComputedStyle(canvas);\n\n\t\treturn {\n\t\t\tcolours: readEach(colours, (property) =>\n\t\t\t\tstyles\n\t\t\t\t\t.getPropertyValue(property)\n\t\t\t\t\t.trim()\n\t\t\t\t\t.replaceAll('currentcolor', () => styles.color),\n\t\t\t),\n\t\t\tisReducedMotion: this.#reducedMotion.matches,\n\t\t\tlengths: readEach<Length, number>(lengths, (property) => readPxProperty(styles, property, 0)),\n\t\t\tnumbers: readEach<Numeric, number>(numbers, (property) =>\n\t\t\t\treadPxProperty(styles, property, 0),\n\t\t\t),\n\t\t};\n\t}\n\n\t#rescale(): void {\n\t\tconst box = this.#cssBox;\n\t\tif (!box) {\n\t\t\tthis.#resize(this.#size.width, this.#size.height);\n\t\t\treturn;\n\t\t}\n\n\t\tconst dpr = deviceRatio();\n\n\t\tthis.#resize(Math.round(box.width * dpr), Math.round(box.height * dpr));\n\t}\n\n\t#resize(width: number, height: number): void {\n\t\tconst previous = this.#size;\n\t\tconst dpr = deviceRatio();\n\t\tif (previous.width === width && previous.height === height && previous.dpr === dpr) return;\n\n\t\tthis.#size = { dpr, height, width };\n\t\tthis.#options.resize?.(this.#size);\n\t\tif (previous.width === 0 || previous.height === 0) this.rebuild();\n\t\telse this.invalidate();\n\t}\n\n\t#schedule(): void {\n\t\tif (this.#options.signal.aborted || this.#frame !== undefined || !this.#isVisible) return;\n\n\t\tthis.#frame = requestAnimationFrame((frameMs) => {\n\t\t\tthis.#draw(frameMs);\n\t\t});\n\t}\n\n\t#stopFill(): void {\n\t\tthis.#fillWatch?.disconnect();\n\t\tthis.#fillWatch = undefined;\n\t}\n\n\t#watchResolution(): void {\n\t\tconst { signal } = this.#options;\n\n\t\tmatchMedia(`(resolution: ${String(deviceRatio())}dppx)`).addEventListener(\n\t\t\t'change',\n\t\t\t() => {\n\t\t\t\tthis.#watchResolution();\n\t\t\t\tthis.#rescale();\n\t\t\t},\n\t\t\t{ once: true, signal },\n\t\t);\n\t}\n}\n\nexport function bindSurface<\n\tColour extends string,\n\tLength extends string = never,\n\tNumeric extends string = never,\n>(options: SurfaceOptions<Colour, Length, Numeric>): Surface {\n\treturn new CanvasSurface(options);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/lib/double-press.ts
|
|
2
|
+
const doublePressMs = 500;
|
|
3
|
+
const doublePressPx = 4;
|
|
4
|
+
function isDoublePress(previous, next) {
|
|
5
|
+
if (!previous) return false;
|
|
6
|
+
return next.time - previous.time < doublePressMs && Math.hypot(next.x - previous.x, next.y - previous.y) < doublePressPx;
|
|
7
|
+
}
|
|
8
|
+
function createDoublePress() {
|
|
9
|
+
let last;
|
|
10
|
+
return {
|
|
11
|
+
forget() {
|
|
12
|
+
last = void 0;
|
|
13
|
+
},
|
|
14
|
+
press(event) {
|
|
15
|
+
const press = {
|
|
16
|
+
time: event.timeStamp,
|
|
17
|
+
x: event.clientX,
|
|
18
|
+
y: event.clientY
|
|
19
|
+
};
|
|
20
|
+
const previous = last;
|
|
21
|
+
last = press;
|
|
22
|
+
if (!isDoublePress(previous, press)) return false;
|
|
23
|
+
last = void 0;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createDoublePress };
|
|
31
|
+
//# sourceMappingURL=double-press.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"double-press.js","names":[],"sources":["../../../src/lib/double-press.ts"],"sourcesContent":["interface Press {\n\ttime: number;\n\tx: number;\n\ty: number;\n}\n\nexport interface DoublePress {\n\tforget(): void;\n\tpress(event: PointerEvent): boolean;\n}\n\n// Not `dblclick`, which iOS may not deliver under `touch-action: none`\nconst doublePressMs = 500;\nconst doublePressPx = 4;\n\nfunction isDoublePress(previous: Press | undefined, next: Press): boolean {\n\tif (!previous) return false;\n\n\treturn (\n\t\tnext.time - previous.time < doublePressMs &&\n\t\tMath.hypot(next.x - previous.x, next.y - previous.y) < doublePressPx\n\t);\n}\n\nexport function createDoublePress(): DoublePress {\n\tlet last: Press | undefined;\n\n\treturn {\n\t\tforget() {\n\t\t\tlast = undefined;\n\t\t},\n\t\tpress(event) {\n\t\t\tconst press = { time: event.timeStamp, x: event.clientX, y: event.clientY };\n\t\t\tconst previous = last;\n\n\t\t\tlast = press;\n\t\t\tif (!isDoublePress(previous, press)) return false;\n\n\t\t\tlast = undefined;\n\n\t\t\treturn true;\n\t\t},\n\t};\n}\n"],"mappings":";AAYA,MAAM,gBAAgB;AACtB,MAAM,gBAAgB;AAEtB,SAAS,cAAc,UAA6B,MAAsB;CACzE,IAAI,CAAC,UAAU,OAAO;CAEtB,OACC,KAAK,OAAO,SAAS,OAAO,iBAC5B,KAAK,MAAM,KAAK,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,CAAC,IAAI;AAEzD;AAEA,SAAgB,oBAAiC;CAChD,IAAI;CAEJ,OAAO;EACN,SAAS;GACR,OAAO;EACR;EACA,MAAM,OAAO;GACZ,MAAM,QAAQ;IAAE,MAAM,MAAM;IAAW,GAAG,MAAM;IAAS,GAAG,MAAM;GAAQ;GAC1E,MAAM,WAAW;GAEjB,OAAO;GACP,IAAI,CAAC,cAAc,UAAU,KAAK,GAAG,OAAO;GAE5C,OAAO;GAEP,OAAO;EACR;CACD;AACD"}
|
package/dist/skins/amber.css
CHANGED
package/dist/skins/ivory.css
CHANGED
package/dist/skins/lime.css
CHANGED
package/dist/skins/slate.css
CHANGED
package/dist/styles/button.css
CHANGED
package/dist/styles/dial.css
CHANGED
package/dist/styles/envelope.css
CHANGED
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.sonic-envelope {
|
|
27
|
-
--_sonic-envelope-radius-ratio: var(--sonic-envelope-radius-ratio, 0.08);
|
|
28
27
|
--_sonic-envelope-inset-ratio: var(--sonic-envelope-inset-ratio, 0.1);
|
|
29
28
|
--_sonic-envelope-handle-ratio: var(--sonic-envelope-handle-ratio, 0.14);
|
|
30
29
|
--_sonic-envelope-handle-stroke-ratio: var(--sonic-envelope-handle-stroke-ratio, 0.025);
|
|
@@ -32,18 +31,16 @@
|
|
|
32
31
|
--_sonic-envelope-curve-ratio: var(--sonic-envelope-curve-ratio, 0.08);
|
|
33
32
|
--_sonic-unit: calc(var(--_sonic-envelope-size) / 64);
|
|
34
33
|
--_sonic-envelope-inset: calc(var(--_sonic-envelope-size) * var(--_sonic-envelope-inset-ratio));
|
|
35
|
-
--_sonic-envelope-radius-own: calc(
|
|
36
|
-
var(--_sonic-envelope-size) * var(--sonic-envelope-radius-ratio)
|
|
37
|
-
);
|
|
38
|
-
--_sonic-glass-radius: var(
|
|
39
|
-
--_sonic-envelope-radius-own,
|
|
40
|
-
var(--sonic-radius, calc(var(--_sonic-envelope-size) * var(--_sonic-envelope-radius-ratio)))
|
|
41
|
-
);
|
|
42
34
|
|
|
35
|
+
/* fallow-ignore-next-line code-duplication -- a plain box restated, since sheets never import each other */
|
|
36
|
+
position: relative;
|
|
37
|
+
display: grid;
|
|
38
|
+
flex-shrink: 0;
|
|
39
|
+
grid-template: minmax(0, 1fr) / minmax(0, 1fr);
|
|
43
40
|
inline-size: calc(var(--_sonic-envelope-size) * var(--_sonic-envelope-aspect-ratio));
|
|
44
41
|
block-size: var(--_sonic-envelope-size);
|
|
45
42
|
container-type: size;
|
|
46
|
-
|
|
43
|
+
user-select: none;
|
|
47
44
|
isolation: isolate;
|
|
48
45
|
}
|
|
49
46
|
|
|
@@ -68,7 +65,6 @@
|
|
|
68
65
|
inset: 0;
|
|
69
66
|
overflow: clip;
|
|
70
67
|
pointer-events: none;
|
|
71
|
-
border-radius: inherit;
|
|
72
68
|
|
|
73
69
|
&[data-sonic-part='curve'] {
|
|
74
70
|
--_sonic-point-size: calc(
|
|
@@ -160,8 +156,8 @@
|
|
|
160
156
|
}
|
|
161
157
|
|
|
162
158
|
:is(.sonic-envelope-curve, .sonic-envelope-handle)[data-sonic-disabled] {
|
|
163
|
-
--_sonic-point-ring: var(--_sonic-unlit);
|
|
164
|
-
--_sonic-point-core: var(--_sonic-
|
|
159
|
+
--_sonic-point-ring: var(--_sonic-unlit-solid);
|
|
160
|
+
--_sonic-point-core: var(--_sonic-point-ring);
|
|
165
161
|
|
|
166
162
|
cursor: default;
|
|
167
163
|
}
|
|
@@ -175,7 +171,7 @@
|
|
|
175
171
|
|
|
176
172
|
:is(.sonic-envelope-curve, .sonic-envelope-handle):not([data-sonic-disabled]):active {
|
|
177
173
|
--_sonic-point-ring: var(--_sonic-lit);
|
|
178
|
-
--_sonic-point-core: var(--_sonic-
|
|
174
|
+
--_sonic-point-core: var(--_sonic-point-ring);
|
|
179
175
|
--_sonic-point-halo: color-mix(
|
|
180
176
|
in oklab,
|
|
181
177
|
var(--_sonic-lit) calc(50% * var(--_sonic-relief)),
|
|
@@ -187,7 +183,7 @@
|
|
|
187
183
|
.sonic-envelope {
|
|
188
184
|
--_sonic-lit: Highlight;
|
|
189
185
|
--_sonic-unlit: GrayText;
|
|
190
|
-
--_sonic-
|
|
186
|
+
--_sonic-unlit-solid: GrayText;
|
|
191
187
|
}
|
|
192
188
|
|
|
193
189
|
.sonic-envelope-graph {
|
|
@@ -205,6 +201,12 @@
|
|
|
205
201
|
--_sonic-point-core: Canvas;
|
|
206
202
|
}
|
|
207
203
|
|
|
204
|
+
/* Spelt as the rules above are, to outrank them */
|
|
205
|
+
:is(.sonic-envelope-curve, .sonic-envelope-handle)[data-sonic-disabled],
|
|
206
|
+
:is(.sonic-envelope-curve, .sonic-envelope-handle):not([data-sonic-disabled]):active {
|
|
207
|
+
--_sonic-point-core: Canvas;
|
|
208
|
+
}
|
|
209
|
+
|
|
208
210
|
.sonic-envelope-fill {
|
|
209
211
|
fill: none;
|
|
210
212
|
}
|
package/dist/styles/led.css
CHANGED
|
@@ -11,30 +11,13 @@
|
|
|
11
11
|
--_sonic-led-size: var(--sonic-led-size, 0.5rem);
|
|
12
12
|
--_sonic-led-lens-ratio: var(--sonic-led-lens-ratio, calc(0.8 - 0.175 * var(--_sonic-relief)));
|
|
13
13
|
--_sonic-unit: calc(var(--_sonic-led-size) / 8);
|
|
14
|
-
--_sonic-led-modelled: calc(100% * var(--_sonic-relief));
|
|
15
|
-
--_sonic-led-bezel: var(
|
|
16
|
-
--sonic-bezel,
|
|
17
|
-
color-mix(
|
|
18
|
-
in oklab,
|
|
19
|
-
color-mix(in oklab, var(--_sonic-unlit) 55%, #000) var(--_sonic-led-modelled),
|
|
20
|
-
transparent
|
|
21
|
-
)
|
|
22
|
-
);
|
|
23
|
-
--_sonic-lens-glass: var(
|
|
24
|
-
--sonic-lens,
|
|
25
|
-
color-mix(
|
|
26
|
-
in oklab,
|
|
27
|
-
color-mix(in oklab, var(--_sonic-unlit) 60%, #000) var(--_sonic-led-modelled),
|
|
28
|
-
color-mix(in oklab, currentcolor 30%, transparent)
|
|
29
|
-
)
|
|
30
|
-
);
|
|
31
14
|
|
|
32
15
|
position: relative;
|
|
33
16
|
display: inline-block;
|
|
34
17
|
flex-shrink: 0;
|
|
35
18
|
inline-size: var(--_sonic-led-size);
|
|
36
19
|
block-size: var(--_sonic-led-size);
|
|
37
|
-
background: var(--_sonic-
|
|
20
|
+
background: var(--_sonic-lens-bezel);
|
|
38
21
|
border-radius: 50%;
|
|
39
22
|
|
|
40
23
|
&::after {
|
|
@@ -112,7 +95,7 @@
|
|
|
112
95
|
calc(var(--_sonic-led-lens-ratio) * 100%),
|
|
113
96
|
transparent
|
|
114
97
|
),
|
|
115
|
-
var(--_sonic-
|
|
98
|
+
var(--_sonic-lens-bezel);
|
|
116
99
|
|
|
117
100
|
&::after {
|
|
118
101
|
background: radial-gradient(
|
|
@@ -135,4 +118,9 @@
|
|
|
135
118
|
}
|
|
136
119
|
}
|
|
137
120
|
}
|
|
121
|
+
|
|
122
|
+
:is(.sonic-button:is(:disabled, [aria-disabled='true']), .sonic-segmented-option:disabled)
|
|
123
|
+
.sonic-led {
|
|
124
|
+
--_sonic-lit: inherit;
|
|
125
|
+
}
|
|
138
126
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
pointer-events: none;
|
|
8
8
|
content: '';
|
|
9
9
|
border: max(1px, 0.06 * var(--_sonic-bracket-size)) solid
|
|
10
|
-
color-mix(in oklab,
|
|
10
|
+
color-mix(in oklab, currentcolor 45%, transparent);
|
|
11
11
|
border-radius: 50%;
|
|
12
12
|
opacity: 0;
|
|
13
13
|
mask: conic-gradient(
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
)
|
|
49
49
|
);
|
|
50
50
|
--_sonic-sheen: linear-gradient(
|
|
51
|
-
|
|
51
|
+
calc(var(--_sonic-light-fall) - 58deg),
|
|
52
52
|
transparent 20%,
|
|
53
53
|
rgb(from var(--_sonic-shine) r g b / calc(0.1 * var(--_sonic-relief))) 45%,
|
|
54
54
|
transparent 55%,
|
|
@@ -80,7 +80,12 @@
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
:is(.sonic-number, .sonic-waveform, .sonic-wavestrip, .sonic-xy) {
|
|
83
|
-
--_sonic-ink:
|
|
83
|
+
--_sonic-ink: currentcolor;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* A plain box has no corner of its own, so its focus outline and glow take this one */
|
|
87
|
+
:is(.sonic-number, .sonic-slider, .sonic-switch-position, .sonic-waveform, .sonic-wavestrip) {
|
|
88
|
+
border-radius: var(--sonic-focus-radius, 0);
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
:is(.sonic-dial, .sonic-slider, .sonic-waveform, .sonic-wavestrip) {
|
|
@@ -143,13 +148,31 @@
|
|
|
143
148
|
outline-offset: var(--sonic-focus-outline-offset, -2px);
|
|
144
149
|
|
|
145
150
|
&:not([data-sonic-pointer-focus]) {
|
|
146
|
-
outline: var(--sonic-focus-outline, 2px solid transparent);
|
|
147
|
-
|
|
148
151
|
--_sonic-cap: var(--_sonic-cap-hover);
|
|
149
152
|
--_sonic-focus-shadow: var(--_sonic-focus-glow);
|
|
150
153
|
}
|
|
151
154
|
}
|
|
152
155
|
|
|
156
|
+
:is(
|
|
157
|
+
.sonic-number,
|
|
158
|
+
.sonic-slider,
|
|
159
|
+
.sonic-waveform,
|
|
160
|
+
.sonic-wavestrip,
|
|
161
|
+
.sonic-xy-axis
|
|
162
|
+
):focus-visible:not([data-sonic-pointer-focus]) {
|
|
163
|
+
outline: var(--sonic-focus-outline, 2px solid transparent);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@media not (forced-colors: active) {
|
|
167
|
+
:is(.sonic-dial, .sonic-button, .sonic-segmented-option):focus-visible:not(
|
|
168
|
+
[data-sonic-pointer-focus]
|
|
169
|
+
)
|
|
170
|
+
> :is(.sonic-dial-cap, .sonic-button-cap, .sonic-segmented-cap) {
|
|
171
|
+
outline: var(--sonic-focus-outline, 2px solid transparent);
|
|
172
|
+
outline-offset: var(--sonic-focus-outline-offset, -2px);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
153
176
|
:state(editing)
|
|
154
177
|
> :is(.sonic-dial, .sonic-number, .sonic-slider, .sonic-waveform, .sonic-wavestrip) {
|
|
155
178
|
--_sonic-cap: var(--_sonic-cap-hover);
|
|
@@ -30,8 +30,16 @@
|
|
|
30
30
|
.sonic-xy,
|
|
31
31
|
.sonic-xy-readout
|
|
32
32
|
) {
|
|
33
|
-
--_sonic-unlit: var(--sonic-unlit, oklch(27.4% 0.005 286deg));
|
|
34
33
|
--_sonic-relief: var(--sonic-relief, 0);
|
|
34
|
+
--_sonic-unlit-solid: var(--sonic-unlit, oklch(27.4% 0.005 286deg));
|
|
35
|
+
--_sonic-unlit: var(
|
|
36
|
+
--sonic-unlit,
|
|
37
|
+
color-mix(
|
|
38
|
+
in oklab,
|
|
39
|
+
oklch(27.4% 0.005 286deg) calc(100% * var(--_sonic-relief)),
|
|
40
|
+
color-mix(in oklab, currentcolor 30%, transparent)
|
|
41
|
+
)
|
|
42
|
+
);
|
|
35
43
|
--_sonic-shade: var(--sonic-shade, #000);
|
|
36
44
|
--_sonic-shine: var(--sonic-shine, #fff);
|
|
37
45
|
--_sonic-press-duration: var(--sonic-press-duration, 60ms);
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
@layer sonic.material {
|
|
2
2
|
:is(
|
|
3
3
|
.sonic-dial-readout,
|
|
4
|
-
.sonic-envelope,
|
|
5
4
|
.sonic-envelope-readout,
|
|
6
|
-
.sonic-number,
|
|
7
5
|
.sonic-screen,
|
|
8
6
|
.sonic-slider-readout,
|
|
9
|
-
.sonic-spectrum,
|
|
10
|
-
.sonic-waveform,
|
|
11
7
|
.sonic-waveform-readout,
|
|
12
|
-
.sonic-wavestrip,
|
|
13
8
|
.sonic-wavestrip-readout,
|
|
14
|
-
.sonic-xy,
|
|
15
9
|
.sonic-xy-readout
|
|
16
10
|
) {
|
|
17
|
-
--_sonic-glass-slab: color-mix(in oklab, var(--_sonic-unlit) 45%, #000);
|
|
11
|
+
--_sonic-glass-slab: color-mix(in oklab, var(--_sonic-unlit-solid) 45%, #000);
|
|
18
12
|
--_sonic-glass-base: var(
|
|
19
13
|
--sonic-glass,
|
|
20
14
|
color-mix(
|
|
@@ -5,7 +5,24 @@
|
|
|
5
5
|
rgb(from var(--_sonic-shine) r g b / calc(0.1 * var(--_sonic-relief))),
|
|
6
6
|
transparent 60%
|
|
7
7
|
);
|
|
8
|
-
--_sonic-lens-
|
|
8
|
+
--_sonic-lens-modelled: calc(100% * var(--_sonic-relief));
|
|
9
|
+
--_sonic-lens-tint: color-mix(in oklab, currentcolor 30%, transparent);
|
|
10
|
+
--_sonic-lens-bezel: var(
|
|
11
|
+
--sonic-bezel,
|
|
12
|
+
color-mix(
|
|
13
|
+
in oklab,
|
|
14
|
+
color-mix(in oklab, var(--_sonic-unlit) 55%, #000) var(--_sonic-lens-modelled),
|
|
15
|
+
transparent
|
|
16
|
+
)
|
|
17
|
+
);
|
|
18
|
+
--_sonic-lens-glass: var(
|
|
19
|
+
--sonic-lens,
|
|
20
|
+
color-mix(
|
|
21
|
+
in oklab,
|
|
22
|
+
color-mix(in oklab, var(--_sonic-unlit) 60%, #000) var(--_sonic-lens-modelled),
|
|
23
|
+
var(--_sonic-lens-tint)
|
|
24
|
+
)
|
|
25
|
+
);
|
|
9
26
|
--_sonic-lens: var(--_sonic-lens-glint), var(--_sonic-lens-glass);
|
|
10
27
|
}
|
|
11
28
|
}
|
|
@@ -7,15 +7,7 @@
|
|
|
7
7
|
@layer sonic.material {
|
|
8
8
|
/* A definite cell, so percentage-sized content fills the glass; a canvas sized to its own box would feed back */
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
.sonic-envelope,
|
|
12
|
-
.sonic-number,
|
|
13
|
-
.sonic-screen,
|
|
14
|
-
.sonic-spectrum,
|
|
15
|
-
.sonic-waveform,
|
|
16
|
-
.sonic-wavestrip,
|
|
17
|
-
.sonic-xy
|
|
18
|
-
) {
|
|
10
|
+
.sonic-screen {
|
|
19
11
|
--_sonic-glass-depth: var(--sonic-glass-depth, var(--_sonic-relief));
|
|
20
12
|
--_sonic-glass-texture: var(--sonic-glass-texture, var(--_sonic-relief));
|
|
21
13
|
--_sonic-glass-pitch: max(2px, round(2 * var(--_sonic-unit), 1px));
|
|
@@ -23,12 +15,10 @@
|
|
|
23
15
|
position: relative;
|
|
24
16
|
box-sizing: border-box;
|
|
25
17
|
display: grid;
|
|
26
|
-
flex-shrink: 0;
|
|
27
18
|
grid-template: minmax(0, 1fr) / minmax(0, 1fr);
|
|
28
19
|
place-items: center;
|
|
29
20
|
font-family: var(--sonic-glass-font, inherit);
|
|
30
21
|
color: var(--_sonic-glass-text);
|
|
31
|
-
user-select: none;
|
|
32
22
|
background: var(--_sonic-glass-fill);
|
|
33
23
|
border: var(--_sonic-glass-edge);
|
|
34
24
|
|
|
@@ -83,7 +73,7 @@
|
|
|
83
73
|
|
|
84
74
|
@media (prefers-reduced-motion: no-preference) {
|
|
85
75
|
&:is(:focus-visible, :focus-within)::before,
|
|
86
|
-
:state(dragging)
|
|
76
|
+
&:has(:state(dragging))::before {
|
|
87
77
|
animation: sonic-glass-breathe 3s ease-in-out infinite alternate;
|
|
88
78
|
}
|
|
89
79
|
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
.sonic-xy-readout
|
|
19
19
|
) {
|
|
20
20
|
--_sonic-unit: calc(var(--_sonic-readout-size) / 32);
|
|
21
|
+
--_sonic-readout-radius-own: calc(
|
|
22
|
+
var(--_sonic-readout-size) * var(--sonic-readout-radius-ratio)
|
|
23
|
+
);
|
|
21
24
|
--_sonic-glass-own: var(--sonic-readout-glass);
|
|
22
25
|
--_sonic-glass-edge-colour-own: var(--sonic-readout-edge);
|
|
23
26
|
--_sonic-glass-edge-width-own: var(--sonic-readout-edge-width);
|
|
@@ -43,7 +46,10 @@
|
|
|
43
46
|
user-select: none;
|
|
44
47
|
background: var(--_sonic-glass-fill);
|
|
45
48
|
border: var(--_sonic-glass-edge);
|
|
46
|
-
border-radius:
|
|
49
|
+
border-radius: var(
|
|
50
|
+
--_sonic-readout-radius-own,
|
|
51
|
+
var(--sonic-radius, calc(0.25 * var(--_sonic-readout-size)))
|
|
52
|
+
);
|
|
47
53
|
box-shadow:
|
|
48
54
|
calc(2 * var(--_sonic-cast-x)) calc(2 * var(--_sonic-cast-y)) calc(6 * var(--_sonic-unit))
|
|
49
55
|
rgb(from var(--_sonic-shade) r g b / calc(0.55 * var(--_sonic-relief))),
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
@layer sonic.material {
|
|
2
|
-
:is(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.sonic-segmented,
|
|
8
|
-
.sonic-spectrum,
|
|
9
|
-
.sonic-toggle,
|
|
10
|
-
.sonic-waveform,
|
|
11
|
-
.sonic-wavestrip,
|
|
12
|
-
.sonic-xy
|
|
13
|
-
) {
|
|
2
|
+
:is(.sonic-button, .sonic-segmented, .sonic-toggle) {
|
|
3
|
+
--_sonic-well-depth: 1;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.sonic-screen {
|
|
14
7
|
--_sonic-well-depth: var(--_sonic-glass-depth, 1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
:is(.sonic-button, .sonic-screen, .sonic-segmented, .sonic-toggle) {
|
|
15
11
|
--_sonic-well:
|
|
16
12
|
inset calc(var(--_sonic-well-depth) * var(--_sonic-cast-x))
|
|
17
13
|
calc(var(--_sonic-well-depth) * var(--_sonic-cast-y))
|
package/dist/styles/meter.css
CHANGED
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
--_sonic-meter-clip-from: var(--sonic-meter-clip-from, -3);
|
|
50
50
|
--_sonic-unit: calc(var(--_sonic-meter-size) / 8);
|
|
51
51
|
--_sonic-meter-toward: to top;
|
|
52
|
+
--_sonic-meter-unlit: var(--_sonic-unlit);
|
|
52
53
|
--_sonic-meter-inset: calc(var(--_sonic-meter-size) * 0.125);
|
|
53
54
|
--_sonic-meter-lens: calc(var(--_sonic-meter-size) - 2 * var(--_sonic-meter-inset));
|
|
54
55
|
--_sonic-meter-clip-space: calc(var(--_sonic-meter-inset) + var(--_sonic-meter-lens));
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
inline-size: var(--_sonic-meter-size);
|
|
64
65
|
block-size: var(--_sonic-meter-length);
|
|
65
66
|
container-type: size;
|
|
66
|
-
background: var(--
|
|
67
|
+
background: var(--_sonic-lens-bezel);
|
|
67
68
|
border-radius: calc(var(--_sonic-meter-size) * var(--_sonic-meter-radius-ratio));
|
|
68
69
|
|
|
69
70
|
&::after {
|
|
@@ -286,10 +287,11 @@
|
|
|
286
287
|
.sonic-meter-segments {
|
|
287
288
|
background: linear-gradient(
|
|
288
289
|
var(--_sonic-meter-toward),
|
|
289
|
-
color-mix(in oklab, var(--_sonic-lit) 12%, var(--_sonic-unlit)) 0
|
|
290
|
-
|
|
290
|
+
color-mix(in oklab, var(--_sonic-lit) 12%, var(--_sonic-meter-unlit)) 0
|
|
291
|
+
var(--_sonic-meter-hot-at),
|
|
292
|
+
color-mix(in oklab, var(--_sonic-lit-warning) 12%, var(--_sonic-meter-unlit)) 0
|
|
291
293
|
var(--_sonic-meter-clip-at),
|
|
292
|
-
color-mix(in oklab, var(--_sonic-lit-danger) 12%, var(--_sonic-unlit)) 0
|
|
294
|
+
color-mix(in oklab, var(--_sonic-lit-danger) 12%, var(--_sonic-meter-unlit)) 0
|
|
293
295
|
);
|
|
294
296
|
}
|
|
295
297
|
|
package/dist/styles/number.css
CHANGED
|
@@ -30,25 +30,24 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
.sonic-number {
|
|
33
|
-
--_sonic-number-radius-ratio: var(--sonic-number-radius-ratio, 0.15);
|
|
34
|
-
--_sonic-number-radius-own: calc(var(--_sonic-number-size) * var(--sonic-number-radius-ratio));
|
|
35
|
-
--_sonic-number-inset-ratio: var(--sonic-number-inset-ratio, 0.2);
|
|
36
33
|
--_sonic-number-text-ratio: var(--sonic-number-text-ratio, 0.45);
|
|
37
34
|
--_sonic-number-travel: var(--sonic-number-travel, 160px);
|
|
38
35
|
--_sonic-unit: calc(var(--_sonic-number-size) / 32);
|
|
39
36
|
|
|
37
|
+
/* fallow-ignore-next-line code-duplication -- a plain box restated, since sheets never import each other */
|
|
38
|
+
position: relative;
|
|
39
|
+
display: grid;
|
|
40
|
+
flex-shrink: 0;
|
|
41
|
+
grid-template: minmax(0, 1fr) / minmax(0, 1fr);
|
|
42
|
+
place-items: center;
|
|
40
43
|
inline-size: calc(var(--_sonic-number-size) * var(--_sonic-number-aspect-ratio));
|
|
41
44
|
block-size: var(--_sonic-number-size);
|
|
42
|
-
padding: 0 calc(var(--_sonic-number-size) * var(--_sonic-number-inset-ratio));
|
|
43
45
|
font-size: calc(var(--_sonic-number-size) * var(--_sonic-number-text-ratio));
|
|
44
46
|
font-variant-numeric: tabular-nums;
|
|
45
47
|
line-height: 1;
|
|
46
|
-
touch-action: pan-x;
|
|
48
|
+
touch-action: var(--sonic-touch-action, pan-x);
|
|
47
49
|
cursor: ns-resize;
|
|
48
|
-
|
|
49
|
-
--_sonic-number-radius-own,
|
|
50
|
-
var(--sonic-radius, calc(var(--_sonic-number-size) * var(--_sonic-number-radius-ratio)))
|
|
51
|
-
);
|
|
50
|
+
user-select: none;
|
|
52
51
|
box-shadow: var(--_sonic-focus-shadow);
|
|
53
52
|
}
|
|
54
53
|
|
package/dist/styles/screen.css
CHANGED
|
@@ -9,14 +9,12 @@
|
|
|
9
9
|
@layer sonic.control {
|
|
10
10
|
.sonic-screen {
|
|
11
11
|
--_sonic-screen-size: var(--sonic-screen-size, 2.5rem);
|
|
12
|
-
--_sonic-screen-aspect-ratio: var(--sonic-screen-aspect-ratio, 3);
|
|
13
12
|
--_sonic-screen-radius-ratio: var(--sonic-screen-radius-ratio, 0.15);
|
|
14
13
|
--_sonic-screen-radius-own: calc(var(--_sonic-screen-size) * var(--sonic-screen-radius-ratio));
|
|
15
14
|
--_sonic-screen-inset-ratio: var(--sonic-screen-inset-ratio, 0.1);
|
|
16
15
|
--_sonic-unit: calc(var(--_sonic-screen-size) / 32);
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
block-size: var(--_sonic-screen-size);
|
|
17
|
+
min-block-size: var(--_sonic-screen-size);
|
|
20
18
|
padding: calc(var(--_sonic-screen-size) * var(--_sonic-screen-inset-ratio));
|
|
21
19
|
border-radius: var(
|
|
22
20
|
--_sonic-screen-radius-own,
|
package/dist/styles/spectrum.css
CHANGED
|
@@ -71,34 +71,21 @@
|
|
|
71
71
|
--_sonic-spectrum-lit: var(--_sonic-lit);
|
|
72
72
|
--_sonic-spectrum-hot: var(--_sonic-lit-warning);
|
|
73
73
|
--_sonic-spectrum-clip: var(--_sonic-lit-danger);
|
|
74
|
-
--_sonic-spectrum-grid: color-mix(in oklab,
|
|
74
|
+
--_sonic-spectrum-grid: color-mix(in oklab, currentcolor 20%, transparent);
|
|
75
75
|
--_sonic-spectrum-hot-from: var(--sonic-spectrum-hot-from, -12);
|
|
76
76
|
--_sonic-spectrum-clip-from: var(--sonic-spectrum-clip-from, -3);
|
|
77
77
|
|
|
78
|
+
/* fallow-ignore-next-line code-duplication -- a plain box restated, since sheets never import each other */
|
|
79
|
+
position: relative;
|
|
80
|
+
display: grid;
|
|
81
|
+
flex-shrink: 0;
|
|
82
|
+
grid-template: minmax(0, 1fr) / minmax(0, 1fr);
|
|
78
83
|
inline-size: var(--_sonic-spectrum-length);
|
|
79
84
|
block-size: var(--_sonic-spectrum-size);
|
|
80
85
|
|
|
81
|
-
--_sonic-spectrum-inset: calc(
|
|
82
|
-
var(--_sonic-spectrum-size) * var(--sonic-spectrum-inset-ratio, 0.06)
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
padding: var(--_sonic-spectrum-inset);
|
|
86
|
-
|
|
87
86
|
/* The canvas's backing size would otherwise feed an intrinsically sized parent */
|
|
88
87
|
contain: size;
|
|
89
|
-
|
|
90
|
-
--_sonic-spectrum-radius-own: calc(
|
|
91
|
-
var(--_sonic-spectrum-size) * var(--sonic-spectrum-radius-ratio)
|
|
92
|
-
);
|
|
93
|
-
--_sonic-glass-radius: var(
|
|
94
|
-
--_sonic-spectrum-radius-own,
|
|
95
|
-
var(
|
|
96
|
-
--sonic-radius,
|
|
97
|
-
calc(var(--_sonic-spectrum-size) * var(--sonic-spectrum-radius-ratio, 0.08))
|
|
98
|
-
)
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
border-radius: var(--_sonic-glass-radius);
|
|
88
|
+
user-select: none;
|
|
102
89
|
}
|
|
103
90
|
|
|
104
91
|
[fill] > .sonic-spectrum,
|
|
@@ -110,10 +97,9 @@
|
|
|
110
97
|
display: block;
|
|
111
98
|
inline-size: 100%;
|
|
112
99
|
block-size: 100%;
|
|
113
|
-
border-radius: max(0px, var(--_sonic-glass-radius) - var(--_sonic-spectrum-inset));
|
|
114
100
|
}
|
|
115
101
|
|
|
116
|
-
/* Opaque, since a system highlight carries alpha that would blend the bars into
|
|
102
|
+
/* Opaque, since a system highlight carries alpha that would blend the bars into what is behind them */
|
|
117
103
|
@media (forced-colors: active) {
|
|
118
104
|
.sonic-spectrum {
|
|
119
105
|
--_sonic-spectrum-lit: rgb(from CanvasText r g b / 100%);
|