@tremolo-ui/vue 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -0
  3. package/dist/index.cjs +2486 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1678 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.ts +1678 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +2444 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +78 -0
  12. package/src/components/AnimationCanvas/AnimationCanvas.ts +105 -0
  13. package/src/components/AnimationCanvas/index.ts +5 -0
  14. package/src/components/DropZone/DropZone.ts +43 -0
  15. package/src/components/DropZone/index.ts +1 -0
  16. package/src/components/FileInput/FileInput.ts +82 -0
  17. package/src/components/FileInput/FileInputTrigger.ts +24 -0
  18. package/src/components/FileInput/context.ts +18 -0
  19. package/src/components/FileInput/index.ts +3 -0
  20. package/src/components/Knob/Knob.ts +237 -0
  21. package/src/components/Knob/KnobActiveLine.ts +31 -0
  22. package/src/components/Knob/KnobInactiveLine.ts +36 -0
  23. package/src/components/Knob/KnobSVGRoot.ts +25 -0
  24. package/src/components/Knob/KnobThumb.ts +53 -0
  25. package/src/components/Knob/context.ts +30 -0
  26. package/src/components/Knob/index.ts +6 -0
  27. package/src/components/NumberInput/NumberInput.ts +258 -0
  28. package/src/components/NumberInput/NumberInputDecrementStepper.ts +7 -0
  29. package/src/components/NumberInput/NumberInputField.ts +128 -0
  30. package/src/components/NumberInput/NumberInputIncrementStepper.ts +7 -0
  31. package/src/components/NumberInput/NumberInputStepper.ts +54 -0
  32. package/src/components/NumberInput/context.ts +63 -0
  33. package/src/components/NumberInput/index.ts +6 -0
  34. package/src/components/NumberInput/stepper-button.ts +65 -0
  35. package/src/components/Piano/Piano.ts +243 -0
  36. package/src/components/Piano/index.ts +1 -0
  37. package/src/components/PointsEditor/PointsEditor.ts +146 -0
  38. package/src/components/PointsEditor/PointsEditorBackground.ts +17 -0
  39. package/src/components/PointsEditor/PointsEditorContainer.ts +73 -0
  40. package/src/components/PointsEditor/PointsEditorPoint.ts +253 -0
  41. package/src/components/PointsEditor/PointsEditorSelectionBox.ts +36 -0
  42. package/src/components/PointsEditor/context.ts +39 -0
  43. package/src/components/PointsEditor/index.ts +9 -0
  44. package/src/components/Slider/Slider.ts +224 -0
  45. package/src/components/Slider/SliderMarks.ts +57 -0
  46. package/src/components/Slider/SliderMarksOption.ts +85 -0
  47. package/src/components/Slider/SliderThumb.ts +92 -0
  48. package/src/components/Slider/SliderTrack.ts +50 -0
  49. package/src/components/Slider/context.ts +33 -0
  50. package/src/components/Slider/index.ts +6 -0
  51. package/src/components/XYPad/XYPad.ts +250 -0
  52. package/src/components/XYPad/XYPadArea.ts +20 -0
  53. package/src/components/XYPad/XYPadThumb.ts +105 -0
  54. package/src/components/XYPad/context.ts +33 -0
  55. package/src/components/XYPad/index.ts +4 -0
  56. package/src/components/_util/context.ts +8 -0
  57. package/src/components/_util/placement.ts +36 -0
  58. package/src/components/_util/props.ts +32 -0
  59. package/src/components/_util/useCheckSteps.ts +22 -0
  60. package/src/components/_util/visually-hidden-range-input.ts +16 -0
  61. package/src/composables/useDrag.ts +22 -0
  62. package/src/composables/useDragValue.ts +20 -0
  63. package/src/composables/useDropZone.ts +32 -0
  64. package/src/composables/useInstance.ts +52 -0
  65. package/src/composables/useLongPress.ts +20 -0
  66. package/src/composables/useMIDIAccess.ts +58 -0
  67. package/src/composables/useMIDIInput.ts +33 -0
  68. package/src/composables/useMIDIMessage.ts +30 -0
  69. package/src/composables/useWheel.ts +23 -0
  70. package/src/index.ts +67 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/components/AnimationCanvas/AnimationCanvas.ts","../src/composables/useInstance.ts","../src/composables/useDropZone.ts","../src/components/DropZone/DropZone.ts","../src/components/_util/context.ts","../src/components/FileInput/context.ts","../src/components/FileInput/FileInput.ts","../src/components/FileInput/FileInputTrigger.ts","../src/components/Knob/context.ts","../src/composables/useDragValue.ts","../src/composables/useWheel.ts","../src/components/_util/useCheckSteps.ts","../src/components/Knob/Knob.ts","../src/components/_util/placement.ts","../src/components/Knob/KnobActiveLine.ts","../src/components/Knob/KnobInactiveLine.ts","../src/components/Knob/KnobSVGRoot.ts","../src/components/Knob/KnobThumb.ts","../src/components/NumberInput/context.ts","../src/components/_util/props.ts","../src/components/NumberInput/NumberInput.ts","../src/composables/useLongPress.ts","../src/components/NumberInput/stepper-button.ts","../src/components/NumberInput/NumberInputDecrementStepper.ts","../src/components/NumberInput/NumberInputField.ts","../src/components/NumberInput/NumberInputIncrementStepper.ts","../src/components/NumberInput/NumberInputStepper.ts","../src/components/Piano/Piano.ts","../src/components/PointsEditor/context.ts","../src/components/PointsEditor/PointsEditor.ts","../src/components/PointsEditor/PointsEditorBackground.ts","../src/components/PointsEditor/PointsEditorContainer.ts","../src/components/_util/visually-hidden-range-input.ts","../src/components/PointsEditor/PointsEditorPoint.ts","../src/components/PointsEditor/PointsEditorSelectionBox.ts","../src/components/Slider/context.ts","../src/components/Slider/Slider.ts","../src/components/Slider/SliderMarksOption.ts","../src/components/Slider/SliderMarks.ts","../src/components/Slider/SliderThumb.ts","../src/components/Slider/SliderTrack.ts","../src/components/XYPad/context.ts","../src/components/XYPad/XYPad.ts","../src/components/XYPad/XYPadArea.ts","../src/components/XYPad/XYPadThumb.ts","../src/composables/useDrag.ts","../src/composables/useMIDIAccess.ts","../src/composables/useMIDIInput.ts","../src/composables/useMIDIMessage.ts"],"sourcesContent":["import {\n defineComponent,\n h,\n ref,\n shallowRef,\n watch,\n watchEffect,\n type PropType,\n} from 'vue'\n\nimport {\n createAnimationCanvas,\n type AnimationCanvasInstance,\n type AnimationFrame,\n} from '@tremolo-ui/dom'\n\n/** Called once the canvas is ready, and again whenever it is resized. */\nexport type InitFunction = (\n context: CanvasRenderingContext2D,\n size: { width: number; height: number },\n) => void\n\n/** Called on every frame while `animate` is on, and once otherwise. */\nexport type DrawFunction = (\n context: CanvasRenderingContext2D,\n frame: AnimationFrame,\n) => void\n\n/** A `<canvas>` drawn by `draw` on every animation frame. */\nexport const AnimationCanvas = /* @__PURE__ */ defineComponent({\n name: 'AnimationCanvas',\n inheritAttrs: false,\n props: {\n /** Draws a frame. */\n draw: { type: Function as PropType<DrawFunction>, required: true },\n /** Sets the canvas up before the first frame and after a resize. */\n init: Function as PropType<InitFunction>,\n /** Draw on every animation frame. @default true */\n animate: { type: Boolean, default: true },\n /** Settings for the 2D context. Read once, when the canvas is created. */\n options: Object as PropType<CanvasRenderingContext2DSettings>,\n /** Keep the drawing while the canvas is resized. @default true */\n reduceFlickering: { type: Boolean, default: true },\n /** Follow the size of the parent element; `width` and `height` are ignored. */\n resizable: Boolean,\n /** Width in CSS pixels, while not `resizable`. @default 100 */\n width: { type: Number, default: 100 },\n /** Height in CSS pixels, while not `resizable`. @default 100 */\n height: { type: Number, default: 100 },\n },\n setup(props, { attrs }) {\n const canvas = ref<HTMLCanvasElement | null>(null)\n const instance = shallowRef<AnimationCanvasInstance | null>(null)\n\n // Only `resizable` decides how the instance is wired, so it is the one\n // setting that rebuilds it. The handlers are read at call time, and the\n // rest is pushed with update().\n watch(\n [canvas, () => props.resizable],\n ([element, resizable], _, onCleanup) => {\n if (!element) return\n const current = createAnimationCanvas(element, {\n draw: (context, frame) => props.draw(context, frame),\n init: (context, size) => props.init?.(context, size),\n animate: props.animate,\n size: { width: props.width, height: props.height },\n reduceFlickering: props.reduceFlickering,\n resizable,\n contextAttributes: props.options,\n })\n instance.value = current\n onCleanup(() => {\n if (instance.value === current) instance.value = null\n current.destroy()\n })\n },\n { immediate: true, flush: 'post' },\n )\n // An effect rather than a watch: without a loop running, update() paints\n // a frame right away, calling `draw` — so whatever state `draw` reads is\n // tracked here, and a canvas driven by state rather than by time is\n // painted again when it changes. A new `draw` or `init` counts too.\n watchEffect(\n () => {\n void props.draw\n void props.init\n instance.value?.update({\n animate: props.animate,\n size: { width: props.width, height: props.height },\n reduceFlickering: props.reduceFlickering,\n })\n },\n { flush: 'post' },\n )\n\n // The context menu is suppressed unless the caller handles it: a\n // listener of their own replaces this one rather than running after it.\n return () =>\n h('canvas', {\n onContextmenu: (event: MouseEvent) => event.preventDefault(),\n ...attrs,\n ref: canvas,\n })\n },\n})\n","import { toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nimport { replaceOptions } from '@tremolo-ui/dom'\n\n/**\n * Create an instance for the element `target` holds, and destroy it when the\n * element goes away or changes. Options are pushed to the instance with\n * `update` as they change, so that changing them does not interrupt a drag in\n * progress.\n *\n * Call it during `setup`: the watchers stop with the component.\n */\nexport function useInstance<\n E extends Element,\n O extends object,\n I extends { destroy: () => void },\n>(\n target: MaybeRefOrGetter<E | null | undefined>,\n options: MaybeRefOrGetter<O>,\n create: (element: E, options: O) => I,\n update: (instance: I, options: Partial<O>) => void,\n): { current: () => I | null } {\n let instance: I | null = null\n\n watch(\n () => toValue(target),\n (element, _, onCleanup) => {\n if (!element) return\n const current = create(element, toValue(options))\n instance = current\n onCleanup(() => {\n current.destroy()\n if (instance === current) instance = null\n })\n },\n { immediate: true, flush: 'post' },\n )\n\n // A copy, so that the watch reads every property: a `reactive()` object\n // whose `requireFocus` changes is then seen, not only a new object. The\n // copy is what the instance is left with — what it no longer carries is\n // cleared rather than kept.\n watch(\n () => ({ ...toValue(options) }),\n (next, previous) => {\n if (instance) update(instance, replaceOptions(previous, next))\n },\n { flush: 'post' },\n )\n\n return { current: () => instance }\n}\n","import { shallowRef, toValue, type MaybeRefOrGetter } from 'vue'\n\nimport {\n createDropZone,\n type DropZoneOptions,\n type DropZoneState,\n} from '@tremolo-ui/dom'\n\nimport { useInstance } from './useInstance'\n\n/**\n * Take files dropped on an element. See `createDropZone` in\n * `@tremolo-ui/dom`. Returns whether files are over it, and whether they\n * would be refused, for styling it while they are.\n */\nexport function useDropZone(\n target: MaybeRefOrGetter<Element | null | undefined>,\n options: MaybeRefOrGetter<DropZoneOptions> = {},\n) {\n const state = shallowRef<DropZoneState>({ over: false, invalid: false })\n const withState = () => ({\n ...toValue(options),\n onStateChange: (next: DropZoneState) => {\n state.value = next\n toValue(options).onStateChange?.(next)\n },\n })\n useInstance(target, withState, createDropZone, (instance, next) =>\n instance.update(next),\n )\n return state\n}\n","import { defineComponent, h, ref } from 'vue'\n\nimport { useDropZone } from '../../composables/useDropZone'\n\n/** A region that takes dropped files. */\nexport const DropZone = /* @__PURE__ */ defineComponent({\n name: 'DropZone',\n props: {\n /** Which files to take, as the `accept` attribute of a file input. */\n accept: String,\n /** Take every file dropped, rather than the first. */\n multiple: Boolean,\n /** Ignore drops. The zone carries `data-disabled`. */\n disabled: Boolean,\n },\n emits: {\n /** The dropped files that satisfy `accept`. */\n drop: (files: File[], _event: DragEvent) => Array.isArray(files),\n /** The dropped files that do not satisfy `accept`, after `drop` for the same drop. */\n reject: (files: File[], _event: DragEvent) => Array.isArray(files),\n },\n setup(props, { slots, emit }) {\n const el = ref<HTMLDivElement | null>(null)\n const state = useDropZone(el, () => ({\n accept: props.accept,\n multiple: props.multiple,\n disabled: props.disabled,\n onDrop: (files, event) => emit('drop', files, event),\n onReject: (files, event) => emit('reject', files, event),\n }))\n return () =>\n h(\n 'div',\n {\n ref: el,\n 'data-dragover': state.value.over ? '' : undefined,\n 'data-invalid': state.value.invalid ? '' : undefined,\n 'data-disabled': props.disabled ? '' : undefined,\n },\n slots.default?.(),\n )\n },\n})\n","import { inject, type InjectionKey } from 'vue'\n\n/** Read a component's context, or explain which parent is missing. */\nexport function injectContext<T>(key: InjectionKey<T>, parent: string): T {\n const context = inject(key, null)\n if (!context) throw new Error(`Missing ${parent} in the tree`)\n return context\n}\n","import { type InjectionKey } from 'vue'\n\nimport { injectContext } from '../_util/context'\n\n/** What `FileInput` shares with `FileInputTrigger`. */\nexport interface FileInputContextValue {\n /** The id of the file input, for the trigger's `for`. */\n readonly inputId: string\n readonly disabled: boolean\n}\n\nexport const FileInputKey: InjectionKey<FileInputContextValue> =\n Symbol('FileInput')\n\n/** The context of the enclosing `FileInput`, for a part of your own. */\nexport function useFileInputContext(): FileInputContextValue {\n return injectContext(FileInputKey, 'FileInput')\n}\n","import { defineComponent, h, provide, useId } from 'vue'\n\nimport { partitionByAccept, visuallyHiddenStyle } from '@tremolo-ui/dom'\n\nimport { FileInputKey } from './context'\n\n/**\n * Picks files. The control is the native file input, out of sight but in the\n * tab order, with `FileInputTrigger` as its label.\n */\nexport const FileInput = /* @__PURE__ */ defineComponent({\n name: 'FileInput',\n inheritAttrs: false,\n props: {\n /**\n * Which files to take: extensions, MIME types and type groups. It is\n * checked again when the files arrive, since the picker only takes it as\n * a hint.\n */\n accept: String,\n /** Let several files be picked at once. */\n multiple: Boolean,\n /** Make the input unusable. The parts carry `data-disabled`. */\n disabled: Boolean,\n },\n emits: {\n /** The picked files that satisfy `accept`. */\n change: (files: File[]) => Array.isArray(files),\n /** The picked files that do not satisfy `accept`, after `change` for the same selection. */\n reject: (files: File[]) => Array.isArray(files),\n },\n setup(props, { slots, emit, attrs }) {\n const inputId = useId()\n provide(FileInputKey, {\n inputId,\n get disabled() {\n return props.disabled\n },\n })\n\n function onChange(event: Event) {\n const input = event.target as HTMLInputElement\n const { accepted, rejected } = partitionByAccept(\n Array.from(input.files ?? []),\n props.accept,\n )\n // Picking the same file twice fires no second change while the value\n // is still on the input, so it is cleared as soon as it is read.\n input.value = ''\n if (accepted.length > 0) emit('change', accepted)\n if (rejected.length > 0) emit('reject', rejected)\n }\n\n return () => {\n const {\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n ...rest\n } = attrs\n return h(\n 'div',\n { ...rest, 'data-disabled': props.disabled ? '' : undefined },\n [\n h('input', {\n id: inputId,\n type: 'file',\n accept: props.accept,\n multiple: props.multiple,\n disabled: props.disabled,\n style: visuallyHiddenStyle,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n onChange,\n }),\n slots.default?.(),\n ],\n )\n }\n },\n})\n","import { defineComponent, h } from 'vue'\n\nimport { useFileInputContext } from './context'\n\n/**\n * Opens the file picker and names the input. A `<label>` rather than a\n * button: the browser forwards the click, the input stays the one thing in\n * the tab order, and its name comes from this text.\n */\nexport const FileInputTrigger = /* @__PURE__ */ defineComponent({\n name: 'FileInputTrigger',\n setup(_, { slots }) {\n const fileInput = useFileInputContext()\n return () =>\n h(\n 'label',\n {\n for: fileInput.inputId,\n 'data-disabled': fileInput.disabled ? '' : undefined,\n },\n slots.default?.(),\n )\n },\n})\n","import { type InjectionKey } from 'vue'\n\nimport { type KnobAngles } from '@tremolo-ui/dom'\nimport { type Scale } from '@tremolo-ui/functions'\n\nimport { injectContext } from '../_util/context'\n\n/**\n * What `Knob` shares with its parts. The fields are getters, so reading one in\n * a render or a `computed` follows the value as it changes.\n */\nexport interface KnobContextValue {\n readonly value: number\n readonly min: number\n readonly max: number\n readonly step: number\n readonly scale: Scale\n readonly startValue: number\n /** How far the knob turns from `min` to `max`, in degrees. */\n readonly angleRange: number\n /** The angles the parts are drawn with. See `knobAngles` in `@tremolo-ui/dom`. */\n readonly angles: KnobAngles\n}\n\nexport const KnobKey: InjectionKey<KnobContextValue> = Symbol('Knob')\n\n/** The context of the enclosing `Knob`, for a part of your own. */\nexport function useKnobContext(): KnobContextValue {\n return injectContext(KnobKey, 'Knob')\n}\n","import { type MaybeRefOrGetter } from 'vue'\n\nimport { createDragValue, type DragValueOptions } from '@tremolo-ui/dom'\n\nimport { useInstance } from './useInstance'\n\n/**\n * Drive a value with a pointer drag. See `createDragValue` in\n * `@tremolo-ui/dom` for the options; `elementMapping` and `relativeMapping`\n * from there choose how the pointer becomes a value. `mapping` is read when\n * the element is attached.\n */\nexport function useDragValue(\n target: MaybeRefOrGetter<Element | null | undefined>,\n options: MaybeRefOrGetter<DragValueOptions>,\n) {\n useInstance(target, options, createDragValue, (instance, next) =>\n instance.update(next),\n )\n}\n","import { type MaybeRefOrGetter } from 'vue'\n\nimport { createWheel, type WheelOptions } from '@tremolo-ui/dom'\n\nimport { useInstance } from './useInstance'\n\n/**\n * Listen to the wheel on an element, as a non-passive listener so that\n * `preventDefault()` can keep the page from scrolling. See `createWheel` in\n * `@tremolo-ui/dom`.\n */\nexport function useWheel(\n target: MaybeRefOrGetter<Element | null | undefined>,\n onWheel: (event: WheelEvent) => void,\n options: MaybeRefOrGetter<WheelOptions> = {},\n) {\n useInstance(\n target,\n options,\n (element, opts) => createWheel(element, (event) => onWheel(event), opts),\n (instance, next) => instance.update(next),\n )\n}\n","import { watchEffect } from 'vue'\n\nimport { checkSteps, type CheckStepsOptions } from '@tremolo-ui/dom'\n\n/**\n * Warn, in development only, when a key press or a wheel notch cannot produce\n * a change the user can see. The probing is `checkSteps` in the core.\n *\n * Takes a getter, so that the check runs again when the settings change.\n */\nexport function useCheckSteps(options: () => CheckStepsOptions) {\n try {\n // Inline and first, so that a bundler folds the comparison and drops the\n // only call to `checkSteps`, which then falls out of the bundle too.\n if (process.env.NODE_ENV === 'production') return\n watchEffect(() => {\n for (const warning of checkSteps(options())) console.warn(warning)\n })\n } catch {\n // No bundler substituted NODE_ENV. Say nothing rather than break.\n }\n}\n","import { computed, defineComponent, h, provide, ref, type PropType } from 'vue'\n\nimport {\n applyDelta,\n arrowKeyDirection,\n cssLength,\n DEFAULT_DRAG_SENSITIVITY,\n DEFAULT_KEYBOARD_OPTIONS,\n DEFAULT_WHEEL_OPTIONS,\n knobAngles,\n relativeMapping,\n selectModifier,\n wheelDirection,\n type AxisOptions,\n type InputEventOption,\n type ModifierValue,\n type XY,\n} from '@tremolo-ui/dom'\nimport { linearScale, type Scale } from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../composables/useDragValue'\nimport { useWheel } from '../../composables/useWheel'\nimport { useCheckSteps } from '../_util/useCheckSteps'\n\nimport { KnobKey } from './context'\n\n/**\n * Interactive rotary knob, drawn in SVG by `KnobSVGRoot` and the parts inside\n * it. Bind the value with `v-model`.\n */\nexport const Knob = /* @__PURE__ */ defineComponent({\n name: 'Knob',\n props: {\n /** The current value. Bind it with `v-model`. */\n modelValue: { type: Number, required: true },\n /** The value with the knob turned all the way down. */\n min: { type: Number, required: true },\n /** The value with the knob turned all the way up. */\n max: { type: Number, required: true },\n /** Granularity of the value. @default 1 */\n step: { type: Number, default: 1 },\n /** How the value is distributed across the travel. @default linearScale */\n scale: { type: Object as PropType<Scale>, default: () => linearScale },\n /** The value a double click restores. @default min */\n defaultValue: Number,\n /** Where the active arc starts. @default min */\n startValue: Number,\n /** Width and height of the knob. Sets `--knob-size`. */\n size: [Number, String],\n /** The cursor to show while dragging. @default { cursor: 'grabbing' } */\n externalStyles: Object as PropType<{ cursor?: string }>,\n /** How much one notch of the wheel moves the value. `null` turns it off. */\n wheel: {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: () => DEFAULT_WHEEL_OPTIONS,\n },\n /** How much one arrow key press moves the value. `null` turns it off. */\n keyboard: {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: () => DEFAULT_KEYBOARD_OPTIONS,\n },\n /** How much a drag moves the value, per modifier key. */\n dragSensitivity: {\n type: [Number, Object] as PropType<ModifierValue<number>>,\n default: () => DEFAULT_DRAG_SENSITIVITY,\n },\n /** Hide the cursor while dragging and read the movement directly. */\n pointerLock: Boolean,\n /** Restore `defaultValue` on a double click. @default true */\n enableDoubleClickDefault: { type: Boolean, default: true },\n /** Make the knob unchangeable and remove it from the tab order. */\n disabled: Boolean,\n /** Make the knob unchangeable while leaving it focusable. */\n readonly: Boolean,\n /** How far the knob turns from `min` to `max`, in degrees. @default 270 */\n angleRange: { type: Number, default: 270 },\n },\n emits: {\n 'update:modelValue': (value: number) => typeof value === 'number',\n },\n setup(props, { slots, emit, expose }) {\n const root = ref<HTMLDivElement | null>(null)\n const dragging = ref(false)\n const inactive = computed(() => props.disabled || props.readonly)\n const range = computed(() => ({\n min: props.min,\n max: props.max,\n step: props.step,\n scale: props.scale,\n }))\n const angles = computed(() =>\n knobAngles({\n value: props.modelValue,\n min: props.min,\n max: props.max,\n scale: props.scale,\n startValue: props.startValue ?? props.min,\n angleRange: props.angleRange,\n }),\n )\n\n useCheckSteps(() => ({\n component: 'Knob',\n range: range.value,\n keyboard: props.keyboard,\n wheel: props.wheel,\n }))\n\n provide(KnobKey, {\n get value() {\n return props.modelValue\n },\n get min() {\n return props.min\n },\n get max() {\n return props.max\n },\n get step() {\n return props.step\n },\n get scale() {\n return props.scale\n },\n get startValue() {\n return props.startValue ?? props.min\n },\n get angleRange() {\n return props.angleRange\n },\n get angles() {\n return angles.value\n },\n })\n\n const change = (next: number) => emit('update:modelValue', next)\n\n // The knob has no travel of its own: 100px of movement spans the whole\n // range, and only the vertical axis carries a value, reversed so that\n // dragging up raises it.\n useDragValue(root, () => ({\n axis: [range.value, { ...range.value, reverse: true }] as XY<AxisOptions>,\n mapping: relativeMapping({\n pixelRange: 100,\n sensitivity: (state) =>\n selectModifier(props.dragSensitivity, state.event).value,\n }),\n getValue: (): XY<number> => [props.modelValue, props.modelValue],\n threshold: 1,\n cursor: inactive.value\n ? undefined\n : (props.externalStyles?.cursor ?? 'grabbing'),\n pointerLock: inactive.value ? false : props.pointerLock,\n shouldStart: () => !inactive.value,\n onChange: (v) => {\n if (!inactive.value) change(v[1])\n },\n onDragStart: () => {\n dragging.value = true\n },\n onDragEnd: () => {\n dragging.value = false\n },\n }))\n\n useWheel(\n root,\n (event) => {\n if (!props.wheel || inactive.value) return\n // A notch the knob does not read — a sideways scroll — is left to\n // the page rather than swallowed.\n const direction = wheelDirection(event)\n if (direction === null) return\n event.preventDefault()\n change(\n applyDelta(\n props.modelValue,\n direction,\n props.wheel,\n range.value,\n event,\n ),\n )\n },\n { requireFocus: true },\n )\n\n expose({\n /** Move the focus to the knob. */\n focus: () => {\n if (!props.disabled) root.value?.focus()\n },\n /** Take the focus away from the knob. */\n blur: () => root.value?.blur(),\n })\n\n return () =>\n h(\n 'div',\n {\n ref: root,\n role: 'slider',\n tabindex: props.disabled ? -1 : 0,\n 'aria-valuenow': props.modelValue,\n 'aria-valuemin': props.min,\n 'aria-valuemax': props.max,\n 'aria-disabled': props.disabled,\n 'aria-readonly': props.readonly,\n 'data-disabled': props.disabled ? '' : undefined,\n 'data-readonly': props.readonly ? '' : undefined,\n 'data-dragging': dragging.value ? '' : undefined,\n style: { '--knob-size': cssLength(props.size) },\n onKeydown: (event: KeyboardEvent) => {\n if (!props.keyboard || inactive.value) return\n const direction = arrowKeyDirection(event.key)\n if (direction === null) return\n event.preventDefault()\n change(\n applyDelta(\n props.modelValue,\n direction,\n props.keyboard,\n range.value,\n event,\n ),\n )\n },\n onDblclick: () => {\n if (!inactive.value && props.enableDoubleClickDefault) {\n change(props.defaultValue ?? props.min)\n }\n },\n },\n slots.default?.(),\n )\n },\n})\n","import { inject, provide, type InjectionKey } from 'vue'\n\nconst PLACEMENT: InjectionKey<string> = Symbol('tremolo-ui placement')\n\n/**\n * Mark the children of this component as being inside `name`, for\n * {@link checkPlacement}. Call it during `setup`.\n */\nexport function providePlacement(name: string) {\n provide(PLACEMENT, name)\n}\n\n/**\n * Warn, in development only, when `child` is rendered outside `parent`. A\n * part positioned against its parent still renders anywhere else, so nothing\n * fails when it is misplaced — its position just comes out wrong. The names\n * are the ones written in templates (`'KnobThumb'`), since they are what the\n * warning shows. Call it during `setup`.\n */\nexport function checkPlacement(child: string, parent: string) {\n try {\n // Inline and first, so that a bundler folds the comparison and drops the\n // message with it. Wrapped because `process` may not exist at all.\n if (process.env.NODE_ENV === 'production') return\n const found = inject(PLACEMENT, null)\n if (found === parent) return\n console.warn(\n `[tremolo-ui] ${child} has to be rendered inside ${parent}` +\n (found === null ? '.' : `, but it is inside ${found}.`) +\n ' It renders either way, so nothing fails — its position just' +\n ' comes out wrong.',\n )\n } catch {\n // No bundler substituted NODE_ENV. Say nothing rather than break.\n }\n}\n","import { defineComponent, h } from 'vue'\n\nimport { knobArcPath, knobArcRadius } from '@tremolo-ui/dom'\n\nimport { checkPlacement } from '../_util/placement'\n\nimport { useKnobContext } from './context'\n\n/** The arc between `startValue` and the value, as an SVG `<path>`. */\nexport const KnobActiveLine = /* @__PURE__ */ defineComponent({\n name: 'KnobActiveLine',\n props: {\n stroke: { type: String, default: 'currentColor' },\n strokeWidth: { type: [Number, String], default: 6 },\n },\n setup(props) {\n checkPlacement('KnobActiveLine', 'KnobSVGRoot')\n const knob = useKnobContext()\n return () =>\n h('path', {\n d: knobArcPath(\n knob.angles.r2,\n knob.angles.r3,\n knobArcRadius(props.strokeWidth),\n ),\n fill: 'none',\n stroke: props.stroke,\n 'stroke-width': props.strokeWidth,\n })\n },\n})\n","import { defineComponent, h } from 'vue'\n\nimport { knobArcPath, knobArcRadius } from '@tremolo-ui/dom'\n\nimport { checkPlacement } from '../_util/placement'\n\nimport { useKnobContext } from './context'\n\n/**\n * The travel outside the value, as SVG `<path>`s: one on each side of the\n * active arc that has any length.\n */\nexport const KnobInactiveLine = /* @__PURE__ */ defineComponent({\n name: 'KnobInactiveLine',\n inheritAttrs: false,\n props: {\n stroke: { type: String, default: 'currentColor' },\n strokeWidth: { type: [Number, String], default: 6 },\n },\n setup(props, { attrs }) {\n checkPlacement('KnobInactiveLine', 'KnobSVGRoot')\n const knob = useKnobContext()\n const path = (from: number, to: number) =>\n h('path', {\n ...attrs,\n d: knobArcPath(from, to, knobArcRadius(props.strokeWidth)),\n fill: 'none',\n stroke: props.stroke,\n 'stroke-width': props.strokeWidth,\n })\n return () => [\n knob.startValue > knob.min ? path(knob.angles.r1, knob.angles.r2) : null,\n knob.startValue < knob.max ? path(knob.angles.r3, knob.angles.r4) : null,\n ]\n },\n})\n","import { defineComponent, h } from 'vue'\n\nimport { KNOB_VIEWBOX_SIZE } from '@tremolo-ui/dom'\n\nimport { providePlacement } from '../_util/placement'\n\n/**\n * The `<svg>` the drawing parts go in, in the order you want them painted.\n * It sets the view box they are drawn against.\n */\nexport const KnobSVGRoot = /* @__PURE__ */ defineComponent({\n name: 'KnobSVGRoot',\n setup(_, { slots }) {\n providePlacement('KnobSVGRoot')\n return () =>\n h(\n 'svg',\n {\n viewBox: `0 0 ${KNOB_VIEWBOX_SIZE} ${KNOB_VIEWBOX_SIZE}`,\n style: { display: 'block' },\n },\n slots.default?.(),\n )\n },\n})\n","import { defineComponent, h, type PropType } from 'vue'\n\nimport { KNOB_VIEWBOX_SIZE } from '@tremolo-ui/dom'\nimport { clamp } from '@tremolo-ui/functions'\n\nimport { checkPlacement } from '../_util/placement'\n\nimport { useKnobContext } from './context'\n\n/** The circle that turns with the value, and the line on it that points at it. */\nexport const KnobThumb = /* @__PURE__ */ defineComponent({\n name: 'KnobThumb',\n props: {\n /** Fill colour of the circle. @default 'currentColor' */\n thumb: { type: String, default: 'currentColor' },\n /** Colour of the line that points at the value. @default 'currentColor' */\n thumbLine: { type: String, default: 'currentColor' },\n /** Diameter of the circle, as a percentage of the knob. @default 84 */\n thumbSize: { type: Number, default: 84 },\n /** Thickness of the line, as a percentage of the knob. @default 6 */\n thumbLineWeight: { type: Number, default: 6 },\n /** How far down the line reaches, as a percentage. @default 35 */\n thumbLineLength: { type: Number, default: 35 },\n /** Classes for the line that points at the value. */\n classes: Object as PropType<{ thumbLine?: string }>,\n },\n setup(props) {\n checkPlacement('KnobThumb', 'KnobSVGRoot')\n const knob = useKnobContext()\n return () =>\n h('svg', null, [\n h('circle', {\n cx: '50%',\n cy: '50%',\n r: `${props.thumbSize / 2}%`,\n fill: props.thumb,\n }),\n h('line', {\n class: props.classes?.thumbLine,\n x1: '50%',\n y1: `${(KNOB_VIEWBOX_SIZE - clamp(props.thumbSize, 0, 100)) / 2}%`,\n x2: '50%',\n y2: `${props.thumbLineLength}%`,\n stroke: props.thumbLine,\n 'stroke-width': `${props.thumbLineWeight}%`,\n style: {\n transform: `rotate(${knob.angles.r1 + knob.angles.p * knob.angleRange}deg)`,\n transformOrigin: '50% 50%',\n },\n }),\n ])\n },\n})\n","import { type InjectionKey } from 'vue'\n\nimport {\n type InputEventOption,\n type ModifierState,\n type ModifierValue,\n} from '@tremolo-ui/dom'\nimport { type ValueRange } from '@tremolo-ui/functions'\n\nimport { injectContext } from '../_util/context'\n\n/** What `NumberInput` shares with its parts. The fields are getters. */\nexport interface NumberInputContextValue {\n readonly value: number\n readonly min: number | undefined\n readonly max: number | undefined\n readonly step: number\n readonly disabled: boolean\n readonly readonly: boolean\n readonly keyboard: ModifierValue<InputEventOption> | null\n readonly drag: number | null\n readonly dragSensitivity: ModifierValue<number>\n readonly pointerLock: boolean\n readonly selectOnFocus: 'all' | 'number' | 'none'\n readonly unformatOnFocus: boolean\n readonly keepCaretOnStep: boolean\n readonly blurOnEnter: boolean\n /** The text the field shows: the draft while typing, else `format(value)`. */\n readonly text: string\n /** Whether the user has typed since the value was last committed. */\n readonly editing: boolean\n readonly outOfRange: boolean\n readonly atMin: boolean\n readonly atMax: boolean\n /** The range a raw amount moves across, for the stepper drag. */\n readonly rawRange: ValueRange\n /** Keep typed text as the draft, reporting the number in it. */\n setDraft: (text: string) => void\n /** Commit the draft, clamped, or drop it when it holds no number. */\n commitDraft: () => void\n /** Set the value, dropping any draft. */\n changeValue: (value: number) => void\n /** Move the value by one press of `option`. */\n nudge: (\n direction: number,\n option: ModifierValue<InputEventOption>,\n modifiers?: ModifierState,\n ) => void\n /** @internal `NumberInputField` registers the element focus() moves to. */\n setInput: (input: HTMLInputElement | null) => void\n}\n\nexport const NumberInputKey: InjectionKey<NumberInputContextValue> =\n Symbol('NumberInput')\n\n/** The context of the enclosing `NumberInput`, for a part of your own. */\nexport function useNumberInputContext(): NumberInputContextValue {\n return injectContext(NumberInputKey, 'NumberInput')\n}\n\n/** @internal Whether the drag on `NumberInputStepper` has moved the value. */\nexport const StepperKey: InjectionKey<{ moved: () => boolean }> =\n Symbol('NumberInputStepper')\n","import { type PropType } from 'vue'\n\nimport {\n DEFAULT_DRAG_SENSITIVITY,\n DEFAULT_KEYBOARD_OPTIONS,\n DEFAULT_WHEEL_OPTIONS,\n type InputEventOption,\n type ModifierValue,\n} from '@tremolo-ui/dom'\n\n// The input props every value control shares, with the core's defaults. One\n// constant each rather than an object to spread: a spread inside\n// `defineComponent(...)` counts as a possible side effect to a bundler, which\n// then keeps every component that uses it even when none is imported.\n\n/** How much one notch of the wheel moves the value. `null` turns it off. */\nexport const wheelProp = {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: () => DEFAULT_WHEEL_OPTIONS,\n}\n\n/** How much one arrow key press moves the value. `null` turns it off. */\nexport const keyboardProp = {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: () => DEFAULT_KEYBOARD_OPTIONS,\n}\n\n/** How much a drag moves the value, per modifier key. */\nexport const dragSensitivityProp = {\n type: [Number, Object] as PropType<ModifierValue<number>>,\n default: () => DEFAULT_DRAG_SENSITIVITY,\n}\n","import { computed, defineComponent, h, provide, ref, type PropType } from 'vue'\n\nimport {\n commitNumberInputText,\n numberInputBounds,\n numberInputRanges,\n nudgeNumberInput,\n parseNumberText,\n wheelDirection,\n} from '@tremolo-ui/dom'\nimport { linearScale, type Scale } from '@tremolo-ui/functions'\n\nimport { useWheel } from '../../composables/useWheel'\nimport { dragSensitivityProp, keyboardProp, wheelProp } from '../_util/props'\nimport { useCheckSteps } from '../_util/useCheckSteps'\n\nimport { NumberInputKey } from './context'\n\n/** Input with some useful functions for entering numbers. Bind it with `v-model`. */\nexport const NumberInput = /* @__PURE__ */ defineComponent({\n name: 'NumberInput',\n props: {\n /** The current value. Bind it with `v-model`. */\n modelValue: { type: Number, required: true },\n /** The lowest value. Leave it out for no lower end. */\n min: Number,\n /** The highest value. Leave it out for no upper end. */\n max: Number,\n /** Granularity of the value. @default 1 */\n step: { type: Number, default: 1 },\n /** How the value is distributed, for a `normalized` amount. */\n scale: { type: Object as PropType<Scale>, default: () => linearScale },\n /** The text shown for a value. @default String */\n format: {\n type: Function as PropType<(value: number) => string>,\n default: String,\n },\n /** Read a value back out of the text. Has to undo `format`. */\n parse: {\n type: Function as PropType<(text: string) => number>,\n default: parseNumberText,\n },\n /** Keep the value within `min` and `max` when committed or stepped. */\n clampValue: { type: Boolean, default: true },\n wheel: wheelProp,\n keyboard: keyboardProp,\n dragSensitivity: dragSensitivityProp,\n /** Pixels of vertical drag on the stepper per `step`. `null` turns it off. */\n drag: { type: Number as PropType<number | null>, default: 1 },\n /** Hide the cursor while dragging the stepper. */\n pointerLock: Boolean,\n /** Select the text when the field takes focus. @default 'none' */\n selectOnFocus: {\n type: String as PropType<'all' | 'number' | 'none'>,\n default: 'none',\n },\n /** Show the plain value while the field has focus. */\n unformatOnFocus: Boolean,\n /** Put the caret back at the same digit after an arrow key step. */\n keepCaretOnStep: Boolean,\n /** Commit and leave the field on Enter. @default true */\n blurOnEnter: { type: Boolean, default: true },\n /** Make the input unchangeable and remove it from the tab order. */\n disabled: Boolean,\n /** Make the value unchangeable while leaving the field focusable. */\n readonly: Boolean,\n },\n emits: {\n 'update:modelValue': (value: number) => typeof value === 'number',\n },\n setup(props, { slots, emit, expose }) {\n const root = ref<HTMLDivElement | null>(null)\n /**\n * The text being typed. The only state here: not a copy of the value, but\n * the half-finished entry that has no value to be derived from yet.\n */\n const draft = ref<string | null>(null)\n let input: HTMLInputElement | null = null\n\n const inactive = computed(() => props.disabled || props.readonly)\n const ranges = computed(() =>\n numberInputRanges({\n min: props.min,\n max: props.max,\n step: props.step,\n scale: props.scale,\n clampValue: props.clampValue,\n }),\n )\n const bounds = computed(() =>\n numberInputBounds(props.modelValue, {\n min: props.min,\n max: props.max,\n clampValue: props.clampValue,\n }),\n )\n const text = computed(() => draft.value ?? props.format(props.modelValue))\n\n // An open end has no travel to sample, so the check is skipped.\n useCheckSteps(() => ({\n component: 'NumberInput',\n range:\n props.min !== undefined &&\n props.max !== undefined &&\n props.min < props.max\n ? {\n min: props.min,\n max: props.max,\n step: props.step,\n scale: props.scale,\n }\n : null,\n keyboard: props.keyboard,\n wheel: props.wheel,\n format: props.format,\n }))\n\n function changeValue(next: number) {\n if (inactive.value) return\n draft.value = null\n if (next !== props.modelValue) emit('update:modelValue', next)\n }\n\n provide(NumberInputKey, {\n get value() {\n return props.modelValue\n },\n get min() {\n return props.min\n },\n get max() {\n return props.max\n },\n get step() {\n return props.step\n },\n get disabled() {\n return props.disabled\n },\n get readonly() {\n return props.readonly\n },\n get keyboard() {\n return props.keyboard\n },\n get drag() {\n return props.drag\n },\n get dragSensitivity() {\n return props.dragSensitivity\n },\n get pointerLock() {\n return props.pointerLock\n },\n get selectOnFocus() {\n return props.selectOnFocus\n },\n get unformatOnFocus() {\n return props.unformatOnFocus\n },\n get keepCaretOnStep() {\n return props.keepCaretOnStep\n },\n get blurOnEnter() {\n return props.blurOnEnter\n },\n get text() {\n return text.value\n },\n get editing() {\n return draft.value !== null\n },\n get outOfRange() {\n return draft.value === null && bounds.value.outOfRange\n },\n get atMin() {\n return bounds.value.atMin\n },\n get atMax() {\n return bounds.value.atMax\n },\n get rawRange() {\n return ranges.value.raw\n },\n setDraft: (next) => {\n if (inactive.value) return\n draft.value = next\n // Deliberately unclamped: clamping here would make \"1500\" impossible\n // to type into an input whose max is 100.\n const parsed = props.parse(next)\n if (Number.isFinite(parsed)) emit('update:modelValue', parsed)\n },\n commitDraft: () => {\n if (draft.value === null || inactive.value) return\n const committed = commitNumberInputText(draft.value, props.parse, {\n min: props.min,\n max: props.max,\n clampValue: props.clampValue,\n })\n // Text with no number is not a value: the field goes back to what it\n // was showing.\n if (committed === null) draft.value = null\n else changeValue(committed)\n },\n changeValue,\n nudge: (direction, option, modifiers) =>\n changeValue(\n nudgeNumberInput(\n props.modelValue,\n direction,\n option,\n ranges.value,\n modifiers,\n ),\n ),\n setInput: (element) => {\n input = element\n },\n })\n\n useWheel(\n root,\n (event) => {\n const direction = wheelDirection(event)\n if (!props.wheel || inactive.value || direction === null) return\n event.preventDefault()\n changeValue(\n nudgeNumberInput(\n props.modelValue,\n direction,\n props.wheel,\n ranges.value,\n event,\n ),\n )\n },\n { requireFocus: true },\n )\n\n expose({\n focus: () => {\n if (!props.disabled) input?.focus()\n },\n blur: () => input?.blur(),\n })\n\n return () =>\n h(\n 'div',\n {\n ref: root,\n 'data-disabled': props.disabled ? '' : undefined,\n 'data-readonly': props.readonly ? '' : undefined,\n },\n slots.default?.(),\n )\n },\n})\n","import { onScopeDispose, toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nimport { createLongPress, type LongPressOptions } from '@tremolo-ui/dom'\n\n/**\n * Repeat `onPress` while a pointer is held down: once on the press, then\n * every `interval` after `delay`. See `createLongPress` in `@tremolo-ui/dom`.\n *\n * Returns the function that starts a press, for `@pointerdown`.\n */\nexport function useLongPress(options: MaybeRefOrGetter<LongPressOptions>) {\n const instance = createLongPress(toValue(options))\n watch(\n () => toValue(options),\n (next) => instance.update(next),\n )\n onScopeDispose(() => instance.destroy())\n return (event?: Pick<PointerEvent, 'button' | 'pointerId'>) =>\n instance.start(event)\n}\n","import { computed, defineComponent, h, inject } from 'vue'\n\nimport { useLongPress } from '../../composables/useLongPress'\n\nimport { StepperKey, useNumberInputContext } from './context'\n\n/** The body of `NumberInputIncrementStepper` and `NumberInputDecrementStepper`. */\nexport function stepperButton(name: string, direction: 1 | -1) {\n return defineComponent({\n name,\n setup(_, { slots }) {\n const field = useNumberInputContext()\n const stepper = inject(StepperKey, null)\n const blocked = computed(\n () => field.disabled || (direction > 0 ? field.atMax : field.atMin),\n )\n const press = useLongPress({\n onPress: () => {\n if (field.disabled || field.readonly) return\n // Once the pointer has actually travelled, the drag on the stepper\n // owns the value; repeating on top of it would move it twice.\n if (stepper?.moved()) return\n field.nudge(direction, ['raw', field.step])\n },\n })\n // A bare arrow has no accessible name of its own. Overridable, since a\n // caller may need it in their own language. `role=\"button\"` does not\n // take aria-readonly, so that state reaches the styles through the data\n // attribute alone.\n return () =>\n h(\n 'div',\n {\n role: 'button',\n tabindex: -1,\n 'aria-label': direction > 0 ? 'Increment' : 'Decrement',\n 'aria-disabled': blocked.value,\n 'data-disabled': blocked.value ? '' : undefined,\n 'data-readonly': field.readonly ? '' : undefined,\n onPointerdown: (event: PointerEvent) => press(event),\n },\n slots.default\n ? slots.default()\n : h(\n 'svg',\n {\n style: {\n width: 'var(--stepper-icon-size)',\n height: 'var(--stepper-icon-size)',\n },\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n },\n h('polyline', {\n points: direction > 0 ? '18 15 12 9 6 15' : '6 9 12 15 18 9',\n }),\n ),\n )\n },\n })\n}\n","import { stepperButton } from './stepper-button'\n\n/** Lowers the value by one `step`, repeating while held. */\nexport const NumberInputDecrementStepper = /* @__PURE__ */ stepperButton(\n 'NumberInputDecrementStepper',\n -1,\n)\n","import {\n computed,\n defineComponent,\n h,\n nextTick,\n onBeforeUnmount,\n ref,\n watchEffect,\n} from 'vue'\n\nimport {\n caretAtDecimalOffset,\n caretDecimalOffset,\n numberSpan,\n} from '@tremolo-ui/dom'\n\nimport { useNumberInputContext } from './context'\n\n/**\n * The text field, and the only place the value can be typed. While the user\n * types, their own text stands rather than `format(value)`.\n */\nexport const NumberInputField = /* @__PURE__ */ defineComponent({\n name: 'NumberInputField',\n setup(_, { expose }) {\n const field = useNumberInputContext()\n const input = ref<HTMLInputElement | null>(null)\n const focused = ref(false)\n watchEffect(() => field.setInput(input.value))\n onBeforeUnmount(() => field.setInput(null))\n\n // Only until the first keystroke: from then on the draft is the user's\n // own text and stands on its own, formatted or not.\n const shown = computed(() =>\n field.unformatOnFocus && focused.value && !field.editing\n ? String(field.value)\n : field.text,\n )\n\n async function select() {\n if (field.selectOnFocus === 'none') return\n // Selecting has to wait for `unformatOnFocus` to swap the text in, or\n // it would cover the wrong characters.\n await nextTick()\n const element = input.value\n if (!element || !focused.value) return\n const span =\n field.selectOnFocus === 'all'\n ? { start: 0, end: element.value.length }\n : numberSpan(element.value)\n if (span) element.setSelectionRange(span.start, span.end)\n }\n\n async function step(direction: number, event: KeyboardEvent) {\n const element = event.currentTarget as HTMLInputElement\n const from = element.value\n const offset =\n field.keepCaretOnStep && element.selectionStart !== null\n ? caretDecimalOffset(from, element.selectionStart)\n : null\n field.nudge(direction, field.keyboard!, event)\n if (offset === null) return\n await nextTick()\n // The step may have been clamped away, leaving the text as it was.\n if (element.value === from) return\n const caret = caretAtDecimalOffset(element.value, offset)\n element.setSelectionRange(caret, caret)\n }\n\n expose({\n focus: () => input.value?.focus(),\n blur: () => input.value?.blur(),\n })\n\n // Not type=\"number\": that brings native spinners and a value the browser\n // parses itself, neither of which survives a unit suffix.\n return () =>\n h('input', {\n ref: input,\n type: 'text',\n inputmode: 'decimal',\n role: 'spinbutton',\n value: shown.value,\n disabled: field.disabled,\n readonly: field.readonly,\n 'aria-disabled': field.disabled,\n 'aria-readonly': field.readonly,\n 'aria-valuenow': field.value,\n 'aria-valuemin': field.min,\n 'aria-valuemax': field.max,\n // The formatted text even while the plain number is shown: it is the\n // one that says what the value means.\n 'aria-valuetext': field.text,\n step: field.step,\n 'data-disabled': field.disabled ? '' : undefined,\n 'data-readonly': field.readonly ? '' : undefined,\n 'data-out-of-range': field.outOfRange ? '' : undefined,\n onInput: (event: Event) =>\n field.setDraft((event.target as HTMLInputElement).value),\n onFocus: () => {\n focused.value = true\n select()\n },\n onBlur: () => {\n focused.value = false\n // Nothing was typed, so there is no draft and this returns at once.\n field.commitDraft()\n },\n onKeydown: (event: KeyboardEvent) => {\n const key = event.key\n if (key === 'Enter') {\n field.commitDraft()\n if (field.blurOnEnter) (event.target as HTMLInputElement).blur()\n } else if (\n field.keyboard &&\n !field.disabled &&\n !field.readonly &&\n (key === 'ArrowUp' || key === 'ArrowDown') &&\n // Arrow keys pick a candidate while an IME is converting.\n !event.isComposing\n ) {\n event.preventDefault()\n step(key === 'ArrowUp' ? 1 : -1, event)\n }\n },\n })\n },\n})\n","import { stepperButton } from './stepper-button'\n\n/** Raises the value by one `step`, repeating while held. */\nexport const NumberInputIncrementStepper = /* @__PURE__ */ stepperButton(\n 'NumberInputIncrementStepper',\n 1,\n)\n","import { computed, defineComponent, h, provide, ref, watch } from 'vue'\n\nimport { createStepperDrag, type StepperDragInstance } from '@tremolo-ui/dom'\n\nimport { StepperKey, useNumberInputContext } from './context'\n\n/**\n * The area the steppers sit in, and a drag handle in its own right: dragging\n * it up and down moves the value one `step` every `drag` pixels.\n */\nexport const NumberInputStepper = /* @__PURE__ */ defineComponent({\n name: 'NumberInputStepper',\n setup(_, { slots }) {\n const field = useNumberInputContext()\n const el = ref<HTMLDivElement | null>(null)\n let instance: StepperDragInstance | null = null\n\n // Only attached while it can do something: `createDrag` puts\n // `touch-action: none` on the element, and a stepper that cannot be\n // dragged should not stop the page scrolling under a finger.\n const enabled = computed(\n () => field.drag !== null && !field.disabled && !field.readonly,\n )\n const options = () => ({\n range: field.rawRange,\n pixels: field.drag ?? 1,\n sensitivity: field.dragSensitivity,\n pointerLock: field.pointerLock,\n })\n\n watch(\n [el, enabled],\n ([element, on], _, onCleanup) => {\n if (!element || !on) return\n const current = createStepperDrag(element, {\n ...options(),\n getValue: () => field.value,\n onChange: (next) => field.changeValue(next),\n })\n instance = current\n onCleanup(() => {\n current.destroy()\n if (instance === current) instance = null\n })\n },\n { immediate: true, flush: 'post' },\n )\n watch(options, (next) => instance?.update(next))\n\n provide(StepperKey, { moved: () => instance?.moved() ?? false })\n\n return () => h('div', { ref: el }, slots.default?.())\n },\n})\n","import {\n computed,\n defineComponent,\n h,\n ref,\n watch,\n type HTMLAttributes,\n type PropType,\n type SlotsType,\n} from 'vue'\n\nimport {\n blackKeyWidth,\n createPianoInput,\n fitWhiteKeyWidth,\n getNoteRangeArray,\n notePosition,\n pianoWidth,\n type KeyboardShortcuts,\n type KeyboardShortcutsScope,\n type NoteRange,\n type PianoInputInstance,\n type PianoLayout,\n} from '@tremolo-ui/dom'\nimport { isWhiteKey, noteKey } from '@tremolo-ui/functions'\n\n/** What a key is, when the `label` slot or `keyProps` is asked about it. */\nexport interface KeyState {\n /** Position in the note range, counting from `noteRange.first`. */\n index: number\n keyType: 'white' | 'black'\n /** Whether the note is currently sounding. */\n active: boolean\n /** Whether the note is above `midiMax` and cannot sound. */\n disabled: boolean\n}\n\n/** What `keyProps` may return for one key. */\nexport type KeyAttributes = HTMLAttributes &\n Record<`data-${string}`, string | number | boolean | undefined>\n\n/**\n * Customizable piano. The keys are drawn by the component; what goes inside\n * one is the `label` slot, which receives the note and its state.\n */\nexport const Piano = /* @__PURE__ */ defineComponent({\n name: 'Piano',\n props: {\n /** The notes drawn, from `first` to `last`. */\n noteRange: { type: Object as PropType<NoteRange>, required: true },\n /** Let a pointer slide from one key to the next. @default true */\n glissando: { type: Boolean, default: true },\n /** Highest note that can sound. @default 127 */\n midiMax: { type: Number, default: 127 },\n /** Play notes from the computer keyboard. See `SHORTCUTS` in `@tremolo-ui/dom`. */\n keyboardShortcuts: Object as PropType<KeyboardShortcuts>,\n /** Where keyboard shortcuts listen. @default 'root' */\n keyboardShortcutsScope: {\n type: String as PropType<KeyboardShortcutsScope>,\n default: 'root',\n },\n /** Follow the width of the parent element. */\n resizable: Boolean,\n /** Width of a white key in pixels. @default 40 */\n whiteKeyWidth: { type: Number, default: 40 },\n /** Space between two white keys, in pixels. @default 1 */\n keyGap: { type: Number, default: 1 },\n /** Width of a black key, as a fraction of a white one. @default 0.65 */\n blackKeyWidthRatio: { type: Number, default: 0.65 },\n /** Height of a black key, as a fraction of the keyboard. @default 0.6 */\n blackKeyHeightRatio: { type: Number, default: 0.6 },\n /** Classes for the label inside each key. */\n classes: Object as PropType<{\n keyLabelWrapper?: string\n keyLabel?: string\n }>,\n /**\n * Extra attributes for one key, by note. The geometry of the key is\n * applied after the returned style and cannot be overridden.\n */\n keyProps: Function as PropType<\n (note: number, state: KeyState) => KeyAttributes\n >,\n },\n emits: {\n /** A note started sounding. */\n playNote: (note: number, _velocity?: number) => typeof note === 'number',\n /** Everything holding a note let go of it. */\n stopNote: (note: number) => typeof note === 'number',\n },\n slots: Object as SlotsType<{\n label: { note: number; state: KeyState }\n }>,\n setup(props, { slots, emit, expose }) {\n const root = ref<HTMLDivElement | null>(null)\n const activeNotes = ref<number[]>([])\n /** Set while `resizable` is on, measured from the parent. */\n const resizedKeyWidth = ref<number | null>(null)\n\n const notes = computed(() => getNoteRangeArray(props.noteRange))\n const layout = computed((): PianoLayout => ({\n noteRange: props.noteRange,\n whiteKeyWidth: props.resizable\n ? (resizedKeyWidth.value ?? props.whiteKeyWidth)\n : props.whiteKeyWidth,\n keyGap: props.keyGap,\n blackKeyWidthRatio: props.blackKeyWidthRatio,\n blackKeyHeightRatio: props.blackKeyHeightRatio,\n }))\n const settings = () => ({\n layout: layout.value,\n glissando: props.glissando,\n midiMax: props.midiMax,\n keyboardShortcuts: props.keyboardShortcuts,\n keyboardShortcutsScope: props.keyboardShortcutsScope,\n })\n\n let instance: PianoInputInstance | null = null\n\n // Only the element decides how the instance is wired. Everything else is\n // pushed with update(), so that changing the layout mid-drag — the parent\n // being resized under `resizable`, say — does not abort the drag.\n watch(\n root,\n (element, _, onCleanup) => {\n if (!element) return\n const current = createPianoInput(element, {\n ...settings(),\n onPlayNote: (note, velocity) => emit('playNote', note, velocity),\n onStopNote: (note) => emit('stopNote', note),\n onActiveNotesChange: (next) => {\n activeNotes.value = next\n },\n })\n instance = current\n onCleanup(() => {\n instance = null\n current.destroy()\n })\n },\n { immediate: true, flush: 'post' },\n )\n watch(settings, (next) => instance?.update(next))\n\n watch(\n () =>\n [\n root.value,\n props.resizable,\n props.noteRange.first,\n props.noteRange.last,\n props.keyGap,\n props.blackKeyWidthRatio,\n ] as const,\n (\n [element, resizable, first, last, keyGap, blackKeyWidthRatio],\n _,\n onCleanup,\n ) => {\n if (!resizable || !element) return\n const parent = element.parentElement\n if (!parent) throw new Error(\"doesn't have a parent element.\")\n const observer = new ResizeObserver(() => {\n resizedKeyWidth.value = fitWhiteKeyWidth(element.clientWidth, {\n noteRange: { first, last },\n keyGap,\n blackKeyWidthRatio,\n })\n })\n observer.observe(parent)\n onCleanup(() => observer.disconnect())\n },\n { immediate: true, flush: 'post' },\n )\n\n expose({\n /** Start a note, as a key would. */\n playNote: (note: number, velocity?: number) =>\n instance?.noteOn(note, { source: 'api', velocity }),\n /** Release a note started with `playNote`. */\n stopNote: (note: number) => instance?.noteOff(note, { source: 'api' }),\n })\n\n // The group can own keyboard shortcuts and must receive focus. The width\n // is computed from the layout rather than chosen, so it stays inline.\n return () =>\n h(\n 'div',\n {\n ref: root,\n role: 'group',\n tabindex: 0,\n 'data-resizable': props.resizable ? '' : undefined,\n style: {\n position: 'relative',\n width: props.resizable ? '100%' : `${pianoWidth(layout.value)}px`,\n },\n },\n notes.value.map((note, index) => {\n const state: KeyState = {\n index,\n keyType: isWhiteKey(note) ? 'white' : 'black',\n active: activeNotes.value.includes(note),\n disabled: note > props.midiMax,\n }\n const { style: keyStyle, ...attributes } =\n props.keyProps?.(note, state) ?? {}\n const white = state.keyType === 'white'\n const label = slots.label?.({ note, state })\n // Placed and sized from the layout; the black keys sit over the\n // white ones whichever order they are drawn in. The geometry comes\n // after the caller's style.\n return h(\n 'div',\n {\n key: note,\n 'data-note': note,\n 'data-note-key': noteKey(note),\n 'data-active': state.active ? '' : undefined,\n 'data-disabled': state.disabled ? '' : undefined,\n ...attributes,\n style: [\n { position: 'absolute', zIndex: white ? 1 : 2 },\n keyStyle,\n {\n left: `${notePosition(note, layout.value)}px`,\n width: `${white ? layout.value.whiteKeyWidth : blackKeyWidth(layout.value)}px`,\n height: white\n ? '100%'\n : `${props.blackKeyHeightRatio * 100}%`,\n },\n ],\n },\n label\n ? h('div', { class: props.classes?.keyLabelWrapper }, [\n h('div', { class: props.classes?.keyLabel }, label),\n ])\n : undefined,\n )\n }),\n )\n },\n})\n","import { type InjectionKey } from 'vue'\n\nimport {\n type InputEventOption,\n type ModifierValue,\n type PointsEditorInstance,\n type SelectionBoxRect,\n} from '@tremolo-ui/dom'\n\nimport { injectContext } from '../_util/context'\n\n/** What `PointsEditor` shares with its parts. The fields are getters. */\nexport interface PointsEditorContextValue {\n readonly disabled: boolean\n readonly readonly: boolean\n readonly wheel: ModifierValue<InputEventOption> | null\n readonly keyboard: ModifierValue<InputEventOption> | null\n readonly dragSensitivity: ModifierValue<number>\n readonly cursor: string\n readonly selectable: boolean\n /** Ids of the selected points. Always empty while `selectable` is off. */\n readonly selection: readonly string[]\n /** The selection box, while one is being dragged. */\n readonly selectionBox: SelectionBoxRect | null\n /** The element points are placed in and measured against. */\n readonly container: HTMLElement | null\n /** The selection and the moves, from `createPointsEditor` in `@tremolo-ui/dom`. */\n readonly editor: PointsEditorInstance\n /** @internal `PointsEditorContainer` registers its element. */\n setContainer: (element: HTMLElement | null) => void\n}\n\nexport const PointsEditorKey: InjectionKey<PointsEditorContextValue> =\n Symbol('PointsEditor')\n\n/** The context of the enclosing `PointsEditor`, for a part of your own. */\nexport function usePointsEditorContext(): PointsEditorContextValue {\n return injectContext(PointsEditorKey, 'PointsEditor')\n}\n","import {\n computed,\n defineComponent,\n h,\n onScopeDispose,\n provide,\n shallowRef,\n watchEffect,\n type PropType,\n} from 'vue'\n\nimport {\n createPointsEditor,\n DEFAULT_DRAG_SENSITIVITY,\n POINTS_EDITOR_DEFAULT_KEYBOARD,\n POINTS_EDITOR_DEFAULT_WHEEL,\n type InputEventOption,\n type ModifierValue,\n type SelectionBoxRect,\n} from '@tremolo-ui/dom'\n\nimport { PointsEditorKey } from './context'\n\nconst EMPTY: readonly string[] = []\n\n/**\n * Multiple point controller. Bind the selection with `v-model:selection` to\n * hold it yourself; the editor keeps its own otherwise.\n */\nexport const PointsEditor = /* @__PURE__ */ defineComponent({\n name: 'PointsEditor',\n props: {\n /** Make the points unchangeable and remove them from the tab order. */\n disabled: Boolean,\n /** Make the points unmovable. */\n readonly: Boolean,\n /** The cursor to show while dragging a point. @default { cursor: 'grabbing' } */\n externalStyles: Object as PropType<{ cursor?: string }>,\n /** How much one wheel notch moves the focused point. */\n wheel: {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: () => POINTS_EDITOR_DEFAULT_WHEEL,\n },\n /** How much one arrow key press moves a point. */\n keyboard: {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: () => POINTS_EDITOR_DEFAULT_KEYBOARD,\n },\n /** How much a drag moves a point, per modifier key. */\n dragSensitivity: {\n type: [Number, Object] as PropType<ModifierValue<number>>,\n default: () => DEFAULT_DRAG_SENSITIVITY,\n },\n /**\n * Let points be selected, and a selection be moved as one. A selection\n * updates several points in the same tick.\n */\n selectable: Boolean,\n /** Ids of the selected points. Bind it with `v-model:selection`. */\n selection: Array as PropType<string[]>,\n },\n emits: {\n 'update:selection': (selection: string[]) => Array.isArray(selection),\n },\n setup(props, { slots, emit }) {\n const ownSelection = shallowRef<string[]>(props.selection ?? [])\n const selectionBox = shallowRef<SelectionBoxRect | null>(null)\n const container = shallowRef<HTMLElement | null>(null)\n\n // Nothing is selected while selection is off, so a drag picks up only\n // the point it started on.\n const current = computed(() =>\n props.selectable ? (props.selection ?? ownSelection.value) : EMPTY,\n )\n\n // The selection lives here, where Vue state can hold it; which points a\n // press or a box selects, and how a selection moves, is the core's.\n const editor = createPointsEditor({\n onSelectionBoxChange: (rect) => {\n selectionBox.value = rect\n },\n onSelectionChange: (next) => {\n ownSelection.value = next\n emit('update:selection', next)\n },\n })\n watchEffect(\n () =>\n editor.update({\n selectable: props.selectable,\n selection: current.value,\n }),\n { flush: 'sync' },\n )\n onScopeDispose(() => editor.destroy())\n\n provide(PointsEditorKey, {\n get disabled() {\n return props.disabled\n },\n get readonly() {\n return props.readonly\n },\n get wheel() {\n return props.wheel\n },\n get keyboard() {\n return props.keyboard\n },\n get dragSensitivity() {\n return props.dragSensitivity\n },\n get cursor() {\n return props.externalStyles?.cursor ?? 'grabbing'\n },\n get selectable() {\n return props.selectable\n },\n get selection() {\n return current.value\n },\n get selectionBox() {\n return selectionBox.value\n },\n get container() {\n return container.value\n },\n editor,\n setContainer: (element) => {\n container.value = element\n },\n })\n\n // The layers inside are placed against this box.\n return () =>\n h(\n 'div',\n {\n 'data-disabled': props.disabled ? '' : undefined,\n 'data-readonly': props.readonly ? '' : undefined,\n style: { position: 'relative' },\n },\n slots.default?.(),\n )\n },\n})\n","import { defineComponent, h } from 'vue'\n\n/**\n * Behind the points, filling the editor. The order of the layers holds\n * whichever way they are written, so the z-index is part of the mechanics.\n */\nexport const PointsEditorBackground = /* @__PURE__ */ defineComponent({\n name: 'PointsEditorBackground',\n setup(_, { slots }) {\n return () =>\n h(\n 'div',\n { style: { position: 'absolute', inset: 0, zIndex: 0 } },\n slots.default?.(),\n )\n },\n})\n","import { computed, defineComponent, h, ref, watch, watchEffect } from 'vue'\n\nimport {\n createDragValue,\n elementMapping,\n POINT_AXIS,\n wheelMove,\n} from '@tremolo-ui/dom'\n\nimport { useWheel } from '../../composables/useWheel'\nimport { providePlacement } from '../_util/placement'\n\nimport { usePointsEditorContext } from './context'\n\n/** The layer the points are placed in, over the background. */\nexport const PointsEditorContainer = /* @__PURE__ */ defineComponent({\n name: 'PointsEditorContainer',\n setup(_, { slots }) {\n const points = usePointsEditorContext()\n providePlacement('PointsEditorContainer')\n const el = ref<HTMLDivElement | null>(null)\n watchEffect(() => points.setContainer(el.value))\n\n // A drag on empty space draws a selection box. It is only attached while\n // there is a selection to draw: `createDrag` puts `touch-action: none` on\n // what it holds, and an editor that cannot select should not stop the\n // page scrolling under a finger.\n const selecting = computed(() => points.selectable && !points.disabled)\n watch(\n [el, selecting],\n ([element, on], _, onCleanup) => {\n if (!element || !on) return\n const drag = createDragValue(element, {\n axis: POINT_AXIS,\n mapping: elementMapping(() => element),\n // A press that landed on a point belongs to that point. Declining\n // here rather than later matters: by then the container would\n // already have taken the pointer capture away from the point.\n shouldStart: (event) =>\n !points.editor.isPointElement(event.target as Element | null),\n onDragStart: ([x, y], state) =>\n points.editor.beginSelectionBox({ x, y }, state.event),\n onChange: ([x, y]) => points.editor.moveSelectionBox({ x, y }),\n onDragEnd: () => points.editor.endSelectionBox(),\n })\n onCleanup(() => drag.destroy())\n },\n { immediate: true, flush: 'post' },\n )\n\n // One listener for the whole editor rather than one per point: a wheel\n // event only reaches what the cursor is over.\n useWheel(el, (event) => {\n // Scrolling up moves the point towards y = 0; shift switches to x.\n const move = wheelMove(event)\n if (!move) return\n const axis = move.axis === 0 ? 'x' : 'y'\n if (points.editor.nudgeFocusedPoint(axis, move.direction, event)) {\n event.preventDefault()\n }\n })\n\n return () =>\n h(\n 'div',\n {\n ref: el,\n style: { position: 'absolute', inset: 0, zIndex: 10 },\n },\n slots.default?.(),\n )\n },\n})\n","import { h, type VNodeProps } from 'vue'\n\nimport { visuallyHiddenStyle } from '@tremolo-ui/dom'\n\n/**\n * The control underneath a headless part: out of sight, but in the\n * accessibility tree and the tab order, carrying the ARIA and the keyboard.\n *\n * A plain element rather than a component, so that a `ref` on it reaches the\n * `<input>` itself.\n */\nexport function visuallyHiddenRangeInput(\n props: VNodeProps & Record<string, unknown>,\n) {\n return h('input', { ...props, type: 'range', style: visuallyHiddenStyle })\n}\n","import {\n computed,\n defineComponent,\n h,\n mergeProps,\n ref,\n useId,\n watch,\n type PropType,\n} from 'vue'\n\nimport {\n arrowKeyMove,\n clampPoint,\n createDragValue,\n elementMapping,\n POINT_AXIS,\n selectModifier,\n type InputEventOption,\n type ModifierValue,\n type PointPosition,\n type PointsEditorPoint as PointRegistration,\n} from '@tremolo-ui/dom'\n\nimport { checkPlacement } from '../_util/placement'\nimport { visuallyHiddenRangeInput } from '../_util/visually-hidden-range-input'\n\nimport { usePointsEditorContext } from './context'\n\ntype PerAxis = string | Partial<Record<'x' | 'y', string>>\n\nconst perAxis = (setting: PerAxis | undefined, axis: 'x' | 'y') =>\n typeof setting === 'string' ? setting : setting?.[axis]\n\n/** One point, bound with `v-model` as `{ x, y }` from 0 to 1. */\nexport const PointsEditorPoint = /* @__PURE__ */ defineComponent({\n name: 'PointsEditorPoint',\n inheritAttrs: false,\n props: {\n /** Where the point is, with `y` growing downwards. Bind it with `v-model`. */\n modelValue: { type: Object as PropType<PointPosition>, required: true },\n /** How the selection refers to this point. One is generated when left out. */\n id: String,\n /** The lowest position the point can take, per axis. */\n min: Object as PropType<Partial<PointPosition>>,\n /** The highest position the point can take, per axis. */\n max: Object as PropType<Partial<PointPosition>>,\n /** Sets `--color`, for the theme to colour the point with. */\n color: String,\n /** Overrides the `disabled` of `PointsEditor`. */\n disabled: { type: Boolean, default: undefined },\n /** Overrides the `readonly` of `PointsEditor`. */\n readonly: { type: Boolean, default: undefined },\n /** Overrides the `wheel` of `PointsEditor`; `null` turns it off. */\n wheel: {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: undefined,\n },\n /** Overrides the `keyboard` of `PointsEditor`; `null` turns it off. */\n keyboard: {\n type: [Array, Object] as PropType<ModifierValue<InputEventOption> | null>,\n default: undefined,\n },\n /** The accessible name of each axis, or one for both. */\n ariaLabel: [String, Object] as PropType<PerAxis>,\n /** What the value of each axis means, or one for both. */\n ariaValuetext: [String, Object] as PropType<PerAxis>,\n },\n emits: {\n 'update:modelValue': (value: PointPosition) => typeof value === 'object',\n dragStart: (value: PointPosition) => typeof value === 'object',\n dragEnd: (value: PointPosition) => typeof value === 'object',\n },\n setup(props, { slots, attrs, emit }) {\n const points = usePointsEditorContext()\n checkPlacement('PointsEditorPoint', 'PointsEditorContainer')\n\n const generatedId = useId()\n const id = computed(() => props.id ?? generatedId)\n const disabled = computed(() => props.disabled ?? points.disabled)\n const readonly = computed(() => props.readonly ?? points.readonly)\n const inactive = computed(() => disabled.value || readonly.value)\n const wheel = computed(() =>\n props.wheel === undefined ? points.wheel : props.wheel,\n )\n const keyboard = computed(() =>\n props.keyboard === undefined ? points.keyboard : props.keyboard,\n )\n const current = computed(() =>\n clampPoint(props.modelValue, props.min, props.max),\n )\n\n const el = ref<HTMLDivElement | null>(null)\n const x = ref<HTMLInputElement | null>(null)\n const dragging = ref(false)\n\n // Read by the editor whenever it moves the selection, so the value can\n // change on every frame of a drag without registering again.\n const read = (): PointRegistration => ({\n value: props.modelValue,\n min: props.min,\n max: props.max,\n readonly: inactive.value,\n onChange: (next) => emit('update:modelValue', next),\n element: el.value,\n wheel: wheel.value,\n })\n watch(\n id,\n (key, _, onCleanup) => onCleanup(points.editor.registerPoint(key, read)),\n { immediate: true },\n )\n\n /** Where the pointer was when the drag started. */\n let origin: PointPosition | null = null\n\n watch(\n el,\n (element, _, onCleanup) => {\n if (!element) return\n // The value is the position itself: no scaling, and no rounding.\n const drag = createDragValue(element, {\n axis: POINT_AXIS,\n mapping: elementMapping(() => points.container, {\n sensitivity: (state) =>\n selectModifier(points.dragSensitivity, state.event).value,\n }),\n cursor: inactive.value ? undefined : points.cursor,\n shouldStart: () => !disabled.value,\n // A move rather than a position: the point keeps the offset it was\n // grabbed at, and everything else selected moves with it.\n onChange: ([px, py]) => {\n if (origin) {\n points.editor.movePointDrag({\n x: px - origin.x,\n y: py - origin.y,\n })\n }\n },\n onDragStart: ([px, py], state) => {\n points.editor.beginPointDrag(id.value, state.event)\n origin = { x: px, y: py }\n dragging.value = true\n x.value?.focus()\n if (!inactive.value) emit('dragStart', current.value)\n },\n onDragEnd: () => {\n origin = null\n dragging.value = false\n if (!inactive.value) emit('dragEnd', current.value)\n },\n })\n const stop = watch(\n () => (inactive.value ? undefined : points.cursor),\n (cursor) => drag.update({ cursor }),\n )\n onCleanup(() => {\n stop()\n drag.destroy()\n })\n },\n { immediate: true, flush: 'post' },\n )\n\n function onInput(axis: 'x' | 'y', target: HTMLInputElement) {\n if (readonly.value) {\n target.value = String(current.value[axis])\n return\n }\n const delta = target.valueAsNumber - props.modelValue[axis]\n points.editor.nudgeSelection(id.value, {\n x: axis === 'x' ? delta : 0,\n y: axis === 'y' ? delta : 0,\n })\n }\n\n const input = (axis: 'x' | 'y') =>\n visuallyHiddenRangeInput({\n ref: axis === 'x' ? x : undefined,\n 'data-axis': axis,\n value: current.value[axis],\n min: props.min?.[axis] ?? 0,\n max: props.max?.[axis] ?? 1,\n step: 'any',\n disabled: disabled.value,\n 'aria-readonly': readonly.value,\n 'aria-orientation': axis === 'x' ? 'horizontal' : 'vertical',\n 'aria-label': perAxis(props.ariaLabel, axis) ?? axis,\n 'aria-valuetext': perAxis(props.ariaValuetext, axis),\n onInput: (event: Event) =>\n onInput(axis, event.target as HTMLInputElement),\n })\n\n // The visual point has two values, so its semantics live on the two\n // range inputs inside it. tabindex -1 keeps the focus inside when a press\n // lands on the point itself.\n return () => {\n const { style, onFocus, onKeydown, ...rest } = attrs\n return h(\n 'div',\n {\n ref: el,\n tabindex: -1,\n 'data-disabled': disabled.value ? '' : undefined,\n 'data-readonly': readonly.value ? '' : undefined,\n 'data-dragging': dragging.value ? '' : undefined,\n 'data-selected': points.selection.includes(id.value) ? '' : undefined,\n ...rest,\n style: [\n {\n position: 'absolute',\n translate: 'var(--translate, -50% -50%)',\n '--color': props.color,\n },\n style,\n {\n left: `${props.modelValue.x * 100}%`,\n top: `${props.modelValue.y * 100}%`,\n },\n ],\n // Merged with the caller's own, which run after these.\n ...mergeProps(\n {\n onFocus: (event: FocusEvent) => {\n // The point is not the control: what reaches it goes to the input.\n if (!disabled.value && event.target === event.currentTarget) {\n x.value?.focus()\n }\n },\n onKeydown: (event: KeyboardEvent) => {\n // The key picks the axis, whichever input holds the focus. y grows\n // downwards, so ArrowUp moves the point towards 0.\n const move = arrowKeyMove(event.key)\n if (!move) return\n event.preventDefault()\n if (inactive.value || !keyboard.value) return\n points.editor.nudgePoint(\n id.value,\n move.axis === 0 ? 'x' : 'y',\n move.direction,\n keyboard.value,\n event,\n )\n },\n },\n { onFocus, onKeydown },\n ),\n },\n [input('x'), input('y'), slots.default?.()],\n )\n }\n },\n})\n","import { defineComponent, h } from 'vue'\n\nimport { checkPlacement } from '../_util/placement'\n\nimport { usePointsEditorContext } from './context'\n\n/**\n * The box a drag on empty space draws. Nothing is rendered while no drag is\n * running, and it takes none of the pointer.\n */\nexport const PointsEditorSelectionBox = /* @__PURE__ */ defineComponent({\n name: 'PointsEditorSelectionBox',\n setup(_, { slots }) {\n const points = usePointsEditorContext()\n checkPlacement('PointsEditorSelectionBox', 'PointsEditorContainer')\n return () => {\n const box = points.selectionBox\n if (!box) return null\n return h(\n 'div',\n {\n style: {\n position: 'absolute',\n zIndex: 20,\n pointerEvents: 'none',\n left: `${box.x * 100}%`,\n top: `${box.y * 100}%`,\n width: `${box.width * 100}%`,\n height: `${box.height * 100}%`,\n },\n },\n slots.default?.(),\n )\n }\n },\n})\n","import { type InjectionKey } from 'vue'\n\nimport { type Scale } from '@tremolo-ui/functions'\n\nimport { injectContext } from '../_util/context'\n\n/** What `Slider` shares with its parts. The fields are getters. */\nexport interface SliderContextValue {\n readonly value: number\n readonly min: number\n readonly max: number\n readonly step: number\n readonly scale: Scale\n readonly vertical: boolean\n readonly reverse: boolean\n readonly disabled: boolean\n readonly readonly: boolean\n /** Where the value sits along the track, as a percentage from the top or left. */\n readonly percent: number\n /** Set the value, as an input on the slider would. */\n change: (value: number) => void\n /** @internal `SliderTrack` registers the element the pointer is measured against. */\n setTrack: (element: HTMLElement | null) => void\n /** @internal `SliderThumb` registers the input the focus goes to. */\n setThumb: (input: HTMLInputElement | null) => void\n}\n\nexport const SliderKey: InjectionKey<SliderContextValue> = Symbol('Slider')\n\n/** The context of the enclosing `Slider`, for a part of your own. */\nexport function useSliderContext(): SliderContextValue {\n return injectContext(SliderKey, 'Slider')\n}\n","import { computed, defineComponent, h, provide, ref, type PropType } from 'vue'\n\nimport {\n applyDelta,\n arrowKeyDirection,\n elementMapping,\n selectModifier,\n valuePercent,\n wheelDirection,\n type AxisOptions,\n type XY,\n} from '@tremolo-ui/dom'\nimport { linearScale, type Scale } from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../composables/useDragValue'\nimport { useWheel } from '../../composables/useWheel'\nimport { dragSensitivityProp, keyboardProp, wheelProp } from '../_util/props'\nimport { useCheckSteps } from '../_util/useCheckSteps'\n\nimport { SliderKey } from './context'\n\n/** Customizable slider. Bind the value with `v-model`. */\nexport const Slider = /* @__PURE__ */ defineComponent({\n name: 'Slider',\n props: {\n /** The current value. Bind it with `v-model`. */\n modelValue: { type: Number, required: true },\n /** The value at the start of the travel. */\n min: { type: Number, required: true },\n /** The value at the end of the travel. */\n max: { type: Number, required: true },\n /** Granularity of the value. @default 1 */\n step: { type: Number, default: 1 },\n /** How the value is distributed across the travel. @default linearScale */\n scale: { type: Object as PropType<Scale>, default: () => linearScale },\n /** Run the slider vertically, with the value growing upwards. */\n vertical: Boolean,\n /** Grow the value the other way. */\n reverse: Boolean,\n /** The cursor to show while dragging. @default { cursor: 'pointer' } */\n externalStyles: Object as PropType<{ cursor?: string }>,\n wheel: wheelProp,\n keyboard: keyboardProp,\n dragSensitivity: dragSensitivityProp,\n /** Make the slider unchangeable and remove it from the tab order. */\n disabled: Boolean,\n /** Make the value unchangeable. */\n readonly: Boolean,\n },\n emits: {\n 'update:modelValue': (value: number) => typeof value === 'number',\n /** A drag started, with the value where the track was pressed. */\n dragStart: (value: number) => typeof value === 'number',\n /** The drag ended, with the value it ended on. */\n dragEnd: (value: number) => typeof value === 'number',\n },\n setup(props, { slots, emit, expose }) {\n const root = ref<HTMLDivElement | null>(null)\n let track: HTMLElement | null = null\n let thumb: HTMLInputElement | null = null\n\n const inactive = computed(() => props.disabled || props.readonly)\n // Measured from the left or the top, as CSS places things: vertical and\n // reverse each flip it, and together they cancel out.\n const displayReversed = computed(() => props.vertical !== props.reverse)\n const percent = computed(() =>\n valuePercent(\n props.modelValue,\n { min: props.min, max: props.max, scale: props.scale },\n displayReversed.value,\n ),\n )\n const axis = computed((): AxisOptions => ({\n min: props.min,\n max: props.max,\n step: props.step,\n scale: props.scale,\n reverse: displayReversed.value,\n }))\n\n useCheckSteps(() => ({\n component: 'Slider',\n range: axis.value,\n keyboard: props.keyboard,\n wheel: props.wheel,\n }))\n\n const change = (next: number) => emit('update:modelValue', next)\n\n provide(SliderKey, {\n get value() {\n return props.modelValue\n },\n get min() {\n return props.min\n },\n get max() {\n return props.max\n },\n get step() {\n return props.step\n },\n get scale() {\n return props.scale\n },\n get vertical() {\n return props.vertical\n },\n get reverse() {\n return props.reverse\n },\n get disabled() {\n return props.disabled\n },\n get readonly() {\n return props.readonly\n },\n get percent() {\n return percent.value\n },\n change,\n setTrack: (element) => {\n track = element\n },\n setThumb: (input) => {\n thumb = input\n },\n })\n\n const valueOf = (v: XY<number>) => v[props.vertical ? 1 : 0]\n\n useDragValue(root, () => ({\n axis: axis.value,\n mapping: elementMapping(() => track, {\n sensitivity: (state) =>\n selectModifier(props.dragSensitivity, state.event).value,\n }),\n cursor: inactive.value\n ? undefined\n : (props.externalStyles?.cursor ?? 'pointer'),\n shouldStart: () => !inactive.value,\n updateOnPointerDown: true,\n onChange: (v) => {\n if (!inactive.value) change(valueOf(v))\n },\n onDragStart: (v) => {\n if (inactive.value) return\n thumb?.focus()\n emit('dragStart', valueOf(v))\n },\n onDragEnd: (v) => {\n if (!inactive.value) emit('dragEnd', valueOf(v))\n },\n }))\n\n useWheel(\n root,\n (event) => {\n if (!props.wheel || inactive.value) return\n // A notch the slider does not read — a sideways scroll on a vertical\n // slider — is left to the page rather than swallowed.\n const direction = wheelDirection(event, { horizontal: !props.vertical })\n if (direction === null) return\n event.preventDefault()\n change(\n applyDelta(\n props.modelValue,\n props.reverse ? -direction : direction,\n props.wheel,\n axis.value,\n event,\n ),\n )\n },\n { requireFocus: true },\n )\n\n expose({\n /** Move the focus to the thumb. */\n focus: () => {\n if (!props.disabled) thumb?.focus()\n },\n /** Take the focus away from the thumb. */\n blur: () => thumb?.blur(),\n })\n\n // The group is the pointer and keyboard event area; the range input in\n // the thumb carries the control semantics. A press lands on the track or\n // the thumb, neither of which can hold focus, and the browser answers that\n // by clearing the focus — tabindex -1 keeps it inside.\n return () =>\n h(\n 'div',\n {\n ref: root,\n role: 'group',\n tabindex: -1,\n 'data-orientation': props.vertical ? 'vertical' : 'horizontal',\n 'data-disabled': props.disabled ? '' : undefined,\n 'data-readonly': props.readonly ? '' : undefined,\n onKeydown: (event: KeyboardEvent) => {\n const direction = arrowKeyDirection(event.key)\n if (direction === null) return\n event.preventDefault()\n if (!props.keyboard || inactive.value) return\n change(\n applyDelta(\n props.modelValue,\n props.reverse ? -direction : direction,\n props.keyboard,\n axis.value,\n event,\n ),\n )\n },\n onFocus: () => {\n if (!props.disabled) thumb?.focus()\n },\n onBlur: () => thumb?.blur(),\n },\n slots.default?.(),\n )\n },\n})\n","import { computed, defineComponent, h, type PropType } from 'vue'\n\nimport { cssLength, valuePercent } from '@tremolo-ui/dom'\n\nimport { checkPlacement } from '../_util/placement'\n\nimport { useSliderContext } from './context'\n\n/** One mark along the slider, and its label. */\nexport const SliderMarksOption = /* @__PURE__ */ defineComponent({\n name: 'SliderMarksOption',\n props: {\n /** Where the mark sits, on the same scale as the thumb. */\n value: { type: Number, required: true },\n /** Draw the mark itself. @default true */\n mark: { type: Boolean, default: true },\n /**\n * Text shown next to the mark. Leave it out to show the value; `null`\n * leaves the label out.\n */\n label: {\n type: [Number, String, null] as PropType<number | string | null>,\n default: undefined,\n },\n /** Thickness of the mark. Sets `--thickness`. */\n thickness: [Number, String],\n /** Length of the mark. Sets `--length`. */\n length: [Number, String],\n /** Space between the mark and the label. Sets `--gap`. */\n gap: [Number, String],\n /** Classes for the mark and the label inside the option. */\n classes: Object as PropType<{ mark?: string; label?: string }>,\n /** Styles for the mark and the label inside the option. */\n styles: Object as PropType<{ mark?: string; label?: string }>,\n },\n setup(props) {\n const slider = useSliderContext()\n checkPlacement('SliderMarksOption', 'SliderMarks')\n // The marks sit on the same curve the thumb runs along.\n const percent = computed(() =>\n valuePercent(\n props.value,\n { min: slider.min, max: slider.max, scale: slider.scale },\n slider.vertical !== slider.reverse,\n ),\n )\n return () => {\n const orientation = slider.vertical ? 'vertical' : 'horizontal'\n return h(\n 'div',\n {\n 'data-orientation': orientation,\n style: {\n '--thickness': cssLength(props.thickness),\n '--length': cssLength(props.length),\n '--gap': cssLength(props.gap),\n position: 'absolute',\n translate: slider.vertical\n ? 'var(--translate, 0 -50%)'\n : 'var(--translate, -50% 0)',\n zIndex: 10,\n left: slider.vertical ? undefined : `${percent.value}%`,\n top: slider.vertical ? `${percent.value}%` : undefined,\n },\n },\n [\n props.mark\n ? h('div', {\n class: props.classes?.mark,\n style: props.styles?.mark,\n 'data-orientation': orientation,\n })\n : null,\n props.label !== null\n ? h(\n 'div',\n { class: props.classes?.label, style: props.styles?.label },\n String(props.label ?? props.value),\n )\n : null,\n ],\n )\n }\n },\n})\n","import { computed, defineComponent, h, type PropType } from 'vue'\n\nimport { cssLength, sliderMarks, type MarksOptions } from '@tremolo-ui/dom'\n\nimport { providePlacement } from '../_util/placement'\n\nimport { useSliderContext } from './context'\nimport { SliderMarksOption } from './SliderMarksOption'\n\n/** The marks along the slider: written out as options, or built from `options`. */\nexport const SliderMarks = /* @__PURE__ */ defineComponent({\n name: 'SliderMarks',\n props: {\n /** Space between the marks and the track. Sets `--gap`. */\n gap: [Number, String],\n /**\n * Build the marks instead of writing `SliderMarksOption` out: a number\n * puts one every that many, `'step'` one every `step`. The default slot\n * is ignored while it is set.\n */\n options: [String, Number, Object] as PropType<MarksOptions>,\n },\n setup(props, { slots }) {\n const slider = useSliderContext()\n providePlacement('SliderMarks')\n const marks = computed(() => {\n if (props.options === undefined) return []\n const list = sliderMarks(\n props.options,\n slider.min,\n slider.max,\n slider.step,\n )\n // In the order they are on screen.\n return slider.vertical !== slider.reverse ? list.reverse() : list\n })\n // Each option inside is placed against this box.\n return () =>\n h(\n 'div',\n {\n 'data-orientation': slider.vertical ? 'vertical' : 'horizontal',\n style: { '--gap': cssLength(props.gap), position: 'relative' },\n },\n props.options !== undefined\n ? marks.value.map(({ value, mark, label }) =>\n h(SliderMarksOption, {\n key: value,\n value,\n mark,\n label: label ? undefined : null,\n }),\n )\n : slots.default?.(),\n )\n },\n})\n","import { defineComponent, h, onBeforeUnmount, ref, watchEffect } from 'vue'\n\nimport { checkPlacement } from '../_util/placement'\nimport { visuallyHiddenRangeInput } from '../_util/visually-hidden-range-input'\n\nimport { useSliderContext } from './context'\n\n/**\n * The thumb, placed at the value. The ARIA (`aria-label` and friends) lands\n * on the range input inside it, which is the control and takes the focus.\n */\nexport const SliderThumb = /* @__PURE__ */ defineComponent({\n name: 'SliderThumb',\n inheritAttrs: false,\n props: {\n /** Sets `--color`, for the theme to colour the thumb with. */\n color: String,\n },\n setup(props, { slots, attrs, expose }) {\n const slider = useSliderContext()\n checkPlacement('SliderThumb', 'SliderTrack')\n const input = ref<HTMLInputElement | null>(null)\n watchEffect(() => slider.setThumb(input.value))\n onBeforeUnmount(() => slider.setThumb(null))\n\n expose({\n focus: () => {\n if (!slider.disabled) input.value?.focus()\n },\n blur: () => input.value?.blur(),\n })\n\n return () => {\n const {\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n 'aria-valuetext': ariaValuetext,\n style,\n ...rest\n } = attrs\n return h(\n 'div',\n {\n 'data-disabled': slider.disabled ? '' : undefined,\n 'data-readonly': slider.readonly ? '' : undefined,\n ...rest,\n // Placed by a percentage of the track, measured from its own\n // centre; where it sits comes after the caller's style.\n style: [\n {\n position: 'absolute',\n translate: 'var(--translate, -50% -50%)',\n zIndex: 100,\n '--color': props.color,\n },\n style,\n {\n top: slider.vertical ? `${slider.percent}%` : '50%',\n left: slider.vertical ? '50%' : `${slider.percent}%`,\n },\n ],\n },\n [\n visuallyHiddenRangeInput({\n ref: input,\n value: slider.value,\n min: slider.min,\n max: slider.max,\n step: slider.step,\n disabled: slider.disabled,\n 'aria-readonly': slider.readonly,\n 'aria-orientation': slider.vertical ? 'vertical' : 'horizontal',\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n 'aria-valuetext': ariaValuetext,\n onInput: (event: Event) => {\n const target = event.target as HTMLInputElement\n if (slider.readonly) {\n target.value = String(slider.value)\n return\n }\n slider.change(target.valueAsNumber)\n },\n }),\n slots.default?.(),\n ],\n )\n }\n },\n})\n","import { defineComponent, h, onBeforeUnmount, ref, watchEffect } from 'vue'\n\nimport { cssLength } from '@tremolo-ui/dom'\n\nimport { providePlacement } from '../_util/placement'\n\nimport { useSliderContext } from './context'\n\n/** The track the thumb runs along, and what the pointer is measured against. */\nexport const SliderTrack = /* @__PURE__ */ defineComponent({\n name: 'SliderTrack',\n props: {\n /** How long the track is along the axis the slider runs. Sets `--length`. */\n length: [Number, String],\n /** How thick the track is across that axis. Sets `--thickness`. */\n thickness: [Number, String],\n /** Colour of the part from `min` to the value. Sets `--active`. */\n active: String,\n /** Colour of the rest of the track. Sets `--inactive`. */\n inactive: String,\n },\n setup(props, { slots }) {\n const slider = useSliderContext()\n providePlacement('SliderTrack')\n const el = ref<HTMLDivElement | null>(null)\n watchEffect(() => slider.setTrack(el.value))\n onBeforeUnmount(() => slider.setTrack(null))\n // `--percent` is where the value sits, for the theme to paint the fill\n // with: the one number CSS cannot work out on its own.\n return () =>\n h(\n 'div',\n {\n ref: el,\n 'data-disabled': slider.disabled ? '' : undefined,\n 'data-orientation': slider.vertical ? 'vertical' : 'horizontal',\n 'data-flipped': slider.vertical !== slider.reverse ? '' : undefined,\n style: {\n '--active': props.active,\n '--inactive': props.inactive,\n '--length': cssLength(props.length),\n '--thickness': cssLength(props.thickness),\n '--percent': `${slider.percent}%`,\n position: 'relative',\n },\n },\n slots.default?.(),\n )\n },\n})\n","import { type InjectionKey } from 'vue'\n\nimport { type XY } from '@tremolo-ui/dom'\nimport { type Scale } from '@tremolo-ui/functions'\n\nimport { injectContext } from '../_util/context'\n\n/** What `XYPad` shares with its parts. The fields are getters. */\nexport interface XYPadContextValue {\n readonly value: XY<number>\n readonly min: XY<number>\n readonly max: XY<number>\n readonly step: XY<number>\n readonly scale: XY<Scale>\n readonly reverse: XY<boolean>\n readonly disabled: boolean\n readonly readonly: boolean\n /** Where the value sits in the area, as percentages from the left and top. */\n readonly percent: XY<number>\n /** Set the value, as an input on the pad would. */\n change: (value: XY<number>) => void\n /** @internal `XYPadArea` registers the element the pointer is measured against. */\n setArea: (element: HTMLElement | null) => void\n /** @internal `XYPadThumb` registers the input the focus goes to. */\n setThumb: (input: HTMLInputElement | null) => void\n}\n\nexport const XYPadKey: InjectionKey<XYPadContextValue> = Symbol('XYPad')\n\n/** The context of the enclosing `XYPad`, for a part of your own. */\nexport function useXYPadContext(): XYPadContextValue {\n return injectContext(XYPadKey, 'XYPad')\n}\n","import { computed, defineComponent, h, provide, ref, type PropType } from 'vue'\n\nimport {\n applyDelta,\n arrowKeyMove,\n elementMapping,\n selectModifier,\n toXY,\n valuePercent,\n wheelMove,\n type AxisMove,\n type AxisOptions,\n type InputEventOption,\n type ModifierState,\n type ModifierValue,\n type XY,\n type XYInput,\n} from '@tremolo-ui/dom'\nimport { linearScale, type Scale } from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../composables/useDragValue'\nimport { useWheel } from '../../composables/useWheel'\nimport { dragSensitivityProp, keyboardProp, wheelProp } from '../_util/props'\nimport { useCheckSteps } from '../_util/useCheckSteps'\n\nimport { XYPadKey } from './context'\n\n/**\n * Two-dimensional slider. The per-axis settings are `[x, y]` tuples, and a\n * plain value applies to both axes. Bind the value with `v-model`.\n */\nexport const XYPad = /* @__PURE__ */ defineComponent({\n name: 'XYPad',\n props: {\n /** The current value as `[x, y]`. Bind it with `v-model`. */\n modelValue: {\n type: Array as unknown as PropType<XY<number>>,\n required: true,\n },\n /** The value at the start of the travel, per axis. */\n min: {\n type: [Number, Array] as PropType<XYInput<number>>,\n required: true,\n },\n /** The value at the end of the travel, per axis. */\n max: {\n type: [Number, Array] as PropType<XYInput<number>>,\n required: true,\n },\n /** Granularity of the value, per axis. @default 1 */\n step: { type: [Number, Array] as PropType<XYInput<number>>, default: 1 },\n /** How the value is distributed, per axis. @default linearScale */\n scale: {\n type: [Object, Array] as PropType<XYInput<Scale>>,\n default: () => linearScale,\n },\n /** Grow the value the other way, per axis. `y` grows downwards unless reversed. */\n reverse: {\n type: [Boolean, Array] as PropType<XYInput<boolean>>,\n default: false,\n },\n /** The cursor to show while dragging. @default { cursor: 'pointer' } */\n externalStyles: Object as PropType<{ cursor?: string }>,\n wheel: wheelProp,\n keyboard: keyboardProp,\n dragSensitivity: dragSensitivityProp,\n /** Make the pad unchangeable and remove it from the tab order. */\n disabled: Boolean,\n /** Make the value unchangeable. */\n readonly: Boolean,\n },\n emits: {\n 'update:modelValue': (value: XY<number>) => Array.isArray(value),\n dragStart: (value: XY<number>) => Array.isArray(value),\n dragEnd: (value: XY<number>) => Array.isArray(value),\n },\n setup(props, { slots, emit, expose }) {\n const root = ref<HTMLDivElement | null>(null)\n let area: HTMLElement | null = null\n let thumb: HTMLInputElement | null = null\n\n const inactive = computed(() => props.disabled || props.readonly)\n const min = computed(() => toXY(props.min))\n const max = computed(() => toXY(props.max))\n const step = computed(() => toXY(props.step))\n const scale = computed(() => toXY(props.scale))\n const reverse = computed(() => toXY(props.reverse))\n const percent = computed(\n () =>\n [0, 1].map((i) =>\n valuePercent(\n props.modelValue[i],\n { min: min.value[i], max: max.value[i], scale: scale.value[i] },\n reverse.value[i],\n ),\n ) as XY<number>,\n )\n // `reverse` only concerns the drag, where positions follow the screen; the\n // key and wheel handlers flip the direction themselves.\n const axis = computed(\n () =>\n [0, 1].map((i) => ({\n min: min.value[i],\n max: max.value[i],\n step: step.value[i],\n scale: scale.value[i],\n reverse: reverse.value[i],\n })) as XY<AxisOptions>,\n )\n\n for (const [i, name] of [\n [0, 'x'],\n [1, 'y'],\n ] as const) {\n useCheckSteps(() => ({\n component: 'XYPad',\n axis: name,\n range: axis.value[i],\n keyboard: props.keyboard,\n wheel: props.wheel,\n }))\n }\n\n const change = (next: XY<number>) => emit('update:modelValue', next)\n\n /** Move one axis by one press of `option`, in screen coordinates. */\n function nudge(\n { axis: i, direction }: AxisMove,\n option: ModifierValue<InputEventOption>,\n modifiers: ModifierState,\n ) {\n const value = props.modelValue\n const next = applyDelta(\n value[i],\n reverse.value[i] ? -direction : direction,\n option,\n axis.value[i],\n modifiers,\n )\n change(i === 0 ? [next, value[1]] : [value[0], next])\n }\n\n provide(XYPadKey, {\n get value() {\n return props.modelValue\n },\n get min() {\n return min.value\n },\n get max() {\n return max.value\n },\n get step() {\n return step.value\n },\n get scale() {\n return scale.value\n },\n get reverse() {\n return reverse.value\n },\n get disabled() {\n return props.disabled\n },\n get readonly() {\n return props.readonly\n },\n get percent() {\n return percent.value\n },\n change,\n setArea: (element) => {\n area = element\n },\n setThumb: (input) => {\n thumb = input\n },\n })\n\n useDragValue(root, () => ({\n axis: axis.value,\n mapping: elementMapping(() => area, {\n sensitivity: (state) =>\n selectModifier(props.dragSensitivity, state.event).value,\n }),\n updateOnPointerDown: true,\n cursor: inactive.value\n ? undefined\n : (props.externalStyles?.cursor ?? 'pointer'),\n shouldStart: () => !inactive.value,\n onChange: (v) => {\n if (!inactive.value) change(v)\n },\n onDragStart: (v) => {\n if (inactive.value) return\n thumb?.focus()\n emit('dragStart', v)\n },\n onDragEnd: (v) => {\n if (!inactive.value) emit('dragEnd', v)\n },\n }))\n\n useWheel(\n root,\n (event) => {\n if (!props.wheel || inactive.value) return\n const move = wheelMove(event)\n if (!move) return\n event.preventDefault()\n nudge(move, props.wheel, event)\n },\n { requireFocus: true },\n )\n\n expose({\n focus: () => {\n if (!props.disabled) thumb?.focus()\n },\n blur: () => thumb?.blur(),\n })\n\n return () =>\n h(\n 'div',\n {\n ref: root,\n role: 'group',\n tabindex: -1,\n 'data-disabled': props.disabled ? '' : undefined,\n 'data-readonly': props.readonly ? '' : undefined,\n onKeydown: (event: KeyboardEvent) => {\n // The key picks the axis, whichever of the two inputs holds the\n // focus: the focus lands on the x input.\n const move = arrowKeyMove(event.key)\n if (!move) return\n event.preventDefault()\n if (props.keyboard && !inactive.value) {\n nudge(move, props.keyboard, event)\n }\n },\n onFocus: () => {\n if (!props.disabled) thumb?.focus()\n },\n onBlur: () => thumb?.blur(),\n },\n slots.default?.(),\n )\n },\n})\n","import { defineComponent, h, onBeforeUnmount, ref, watchEffect } from 'vue'\n\nimport { providePlacement } from '../_util/placement'\n\nimport { useXYPadContext } from './context'\n\n/** The area the thumb moves in, and what the pointer is measured against. */\nexport const XYPadArea = /* @__PURE__ */ defineComponent({\n name: 'XYPadArea',\n setup(_, { slots }) {\n const pad = useXYPadContext()\n providePlacement('XYPadArea')\n const el = ref<HTMLDivElement | null>(null)\n watchEffect(() => pad.setArea(el.value))\n onBeforeUnmount(() => pad.setArea(null))\n // The thumb inside is placed against this box.\n return () =>\n h('div', { ref: el, style: { position: 'relative' } }, slots.default?.())\n },\n})\n","import {\n defineComponent,\n h,\n onBeforeUnmount,\n ref,\n watchEffect,\n type PropType,\n} from 'vue'\n\nimport { toXY, type XYInput } from '@tremolo-ui/dom'\n\nimport { checkPlacement } from '../_util/placement'\nimport { visuallyHiddenRangeInput } from '../_util/visually-hidden-range-input'\n\nimport { useXYPadContext } from './context'\n\ntype PerAxis = XYInput<string | undefined>\n\n/** The thumb, placed at the value, with one range input per axis inside. */\nexport const XYPadThumb = /* @__PURE__ */ defineComponent({\n name: 'XYPadThumb',\n inheritAttrs: false,\n props: {\n /** Sets `--color`, for the theme to colour the thumb with. */\n color: String,\n /** The accessible name of each axis, as `[x, y]`. */\n ariaLabel: [String, Array] as PropType<PerAxis>,\n /** The ids of what labels each axis, as `[x, y]` or one for both. */\n ariaLabelledby: [String, Array] as PropType<PerAxis>,\n /** The ids of what describes each axis, as `[x, y]` or one for both. */\n ariaDescribedby: [String, Array] as PropType<PerAxis>,\n /** What the value of each axis means, as `[x, y]` or one for both. */\n ariaValuetext: [String, Array] as PropType<PerAxis>,\n },\n setup(props, { slots, attrs, expose }) {\n const pad = useXYPadContext()\n checkPlacement('XYPadThumb', 'XYPadArea')\n const x = ref<HTMLInputElement | null>(null)\n const y = ref<HTMLInputElement | null>(null)\n watchEffect(() => pad.setThumb(x.value))\n onBeforeUnmount(() => pad.setThumb(null))\n\n expose({\n focus: () => {\n if (!pad.disabled) x.value?.focus()\n },\n blur: () => {\n x.value?.blur()\n y.value?.blur()\n },\n })\n\n function input(axis: 0 | 1) {\n const labels = toXY(props.ariaLabel)\n return visuallyHiddenRangeInput({\n ref: axis === 0 ? x : y,\n 'data-axis': axis === 0 ? 'x' : 'y',\n value: pad.value[axis],\n min: pad.min[axis],\n max: pad.max[axis],\n step: pad.step[axis],\n disabled: pad.disabled,\n 'aria-readonly': pad.readonly,\n 'aria-orientation': axis === 0 ? 'horizontal' : 'vertical',\n 'aria-label': labels[axis] ?? (axis === 0 ? 'x' : 'y'),\n 'aria-labelledby': toXY(props.ariaLabelledby)[axis],\n 'aria-describedby': toXY(props.ariaDescribedby)[axis],\n 'aria-valuetext': toXY(props.ariaValuetext)[axis],\n onInput: (event: Event) => {\n const target = event.target as HTMLInputElement\n if (pad.readonly) {\n target.value = String(pad.value[axis])\n return\n }\n const next = [...pad.value] as [number, number]\n next[axis] = target.valueAsNumber\n pad.change(next)\n },\n })\n }\n\n return () => {\n const { style, ...rest } = attrs\n return h(\n 'div',\n {\n 'data-disabled': pad.disabled ? '' : undefined,\n 'data-readonly': pad.readonly ? '' : undefined,\n ...rest,\n style: [\n {\n position: 'absolute',\n translate: 'var(--translate, -50% -50%)',\n zIndex: 100,\n '--color': props.color,\n },\n style,\n { left: `${pad.percent[0]}%`, top: `${pad.percent[1]}%` },\n ],\n },\n [input(0), input(1), slots.default?.()],\n )\n }\n },\n})\n","import { type MaybeRefOrGetter } from 'vue'\n\nimport { createDrag, type DragOptions } from '@tremolo-ui/dom'\n\nimport { useInstance } from './useInstance'\n\n/**\n * Track a pointer drag on an element. See `createDrag` in `@tremolo-ui/dom`\n * for the options.\n *\n * @example\n * const el = useTemplateRef('el')\n * useDrag(el, { onDrag: (state) => (x.value += state.deltaX) })\n */\nexport function useDrag(\n target: MaybeRefOrGetter<Element | null | undefined>,\n options: MaybeRefOrGetter<DragOptions> = {},\n) {\n useInstance(target, options, createDrag, (instance, next) =>\n instance.update(next),\n )\n}\n","import {\n computed,\n onMounted,\n onScopeDispose,\n shallowRef,\n toValue,\n watch,\n type MaybeRefOrGetter,\n} from 'vue'\n\nimport {\n createMIDIAccess,\n type MIDIAccessOptions,\n type MIDIAccessState,\n} from '@tremolo-ui/dom'\n\n/**\n * Request MIDI access in the browser. Call it during `setup`.\n *\n * `state` holds the access, the error and the connected inputs, and follows\n * devices as they are plugged in and unplugged.\n *\n * @param requestOnMount ask for access once the component is mounted — never\n * during server rendering, where there is no MIDI to ask for. Leave it off to\n * ask from a click instead, so that opening a page does not bring up a\n * permission prompt. A ref or a getter asks once it turns true.\n */\nexport function useMIDIAccess(\n requestOnMount: MaybeRefOrGetter<boolean> = true,\n) {\n const instance = createMIDIAccess()\n const state = shallowRef<MIDIAccessState>(instance.getState())\n const unsubscribe = instance.subscribe(() => {\n state.value = instance.getState()\n })\n onMounted(() => {\n watch(\n () => toValue(requestOnMount),\n (request) => {\n if (request) instance.request()\n },\n { immediate: true },\n )\n })\n onScopeDispose(() => {\n unsubscribe()\n instance.destroy()\n })\n return {\n // Read-only, and without wrapping MIDIAccess in a proxy.\n state: computed(() => state.value),\n /**\n * Ask for access. Takes `{ sysex: true }` when the app needs system\n * exclusive messages, which browsers treat as a separate permission.\n */\n request: (options?: MIDIAccessOptions) => instance.request(options),\n }\n}\n","import { toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nimport { createMIDIInput, type MIDIInputHandlers } from '@tremolo-ui/dom'\n\n/**\n * Handle the channel voice messages of every connected input. Call it during\n * `setup`. See `createMIDIInput` in `@tremolo-ui/dom` for the handlers.\n *\n * The listeners follow `midiAccess` as it is granted, and new handlers\n * replace the old ones without re-subscribing.\n */\nexport function useMIDIInput(\n midiAccess: MaybeRefOrGetter<MIDIAccess | null>,\n handlers: MaybeRefOrGetter<MIDIInputHandlers>,\n) {\n let instance: ReturnType<typeof createMIDIInput> | null = null\n watch(\n () => toValue(midiAccess),\n (access, _, onCleanup) => {\n const current = createMIDIInput(access, toValue(handlers))\n instance = current\n onCleanup(() => {\n current.destroy()\n if (instance === current) instance = null\n })\n },\n { immediate: true },\n )\n watch(\n () => toValue(handlers),\n (next) => instance?.update(next),\n )\n}\n","import { toValue, watch, type MaybeRefOrGetter } from 'vue'\n\nimport { createMIDIMessage } from '@tremolo-ui/dom'\n\n/**\n * Listen to raw `midimessage` events on every input. Call it during `setup`.\n * For note and controller events, `useMIDIInput` decodes the message for you.\n */\nexport function useMIDIMessage(\n midiAccess: MaybeRefOrGetter<MIDIAccess | null>,\n onMIDIMessage: MaybeRefOrGetter<(event: MIDIMessageEvent) => void>,\n) {\n let instance: ReturnType<typeof createMIDIMessage> | null = null\n watch(\n () => toValue(midiAccess),\n (access, _, onCleanup) => {\n const current = createMIDIMessage(access, toValue(onMIDIMessage))\n instance = current\n onCleanup(() => {\n current.destroy()\n if (instance === current) instance = null\n })\n },\n { immediate: true },\n )\n watch(\n () => toValue(onMIDIMessage),\n (next) => instance?.update(next),\n )\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@tremolo-ui/vue",
3
+ "version": "0.7.0",
4
+ "description": "Vue component library for audio app",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "dist/index.cjs",
8
+ "module": "dist/index.js",
9
+ "types": "dist/index.d.cts",
10
+ "scripts": {
11
+ "sb": "storybook dev",
12
+ "build:sb": "storybook build -o storybook-static/i/storybook-vue && cp .storybook/_headers storybook-static/_headers",
13
+ "typecheck": "tsc && vue-tsc --noEmit -p ../../site/examples/vue/tsconfig.json",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "build:package": "npm run typecheck && tsdown",
17
+ "clean": "npm run clean:build && npm run clean:sb",
18
+ "clean:build": "rimraf ./dist",
19
+ "clean:sb": "rimraf ./storybook-static"
20
+ },
21
+ "devDependencies": {
22
+ "@storybook/addon-a11y": "10.6.0",
23
+ "@storybook/addon-docs": "10.6.0",
24
+ "@storybook/vue3-vite": "10.6.0",
25
+ "@testing-library/jest-dom": "7.0.1",
26
+ "@testing-library/vue": "8.1.0",
27
+ "@vitejs/plugin-vue": "6.0.9",
28
+ "@vue/test-utils": "2.5.1",
29
+ "esbuild": "0.28.1",
30
+ "storybook": "10.6.0",
31
+ "vue-tsc": "3.3.11",
32
+ "vue": "3.5.43"
33
+ },
34
+ "peerDependencies": {
35
+ "vue": "^3.5.0"
36
+ },
37
+ "dependencies": {
38
+ "@tremolo-ui/dom": "^0.7.0",
39
+ "@tremolo-ui/functions": "^0.7.0"
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "src"
44
+ ],
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "author": {
49
+ "name": "mimoz",
50
+ "email": "contact.m1m0zzz@gmail.com"
51
+ },
52
+ "license": "MIT",
53
+ "homepage": "https://github.com/m1m0zzz/tremolo-ui",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "git+https://github.com/m1m0zzz/tremolo-ui.git",
57
+ "directory": "packages/vue"
58
+ },
59
+ "keywords": [
60
+ "vue",
61
+ "vue-components",
62
+ "ui",
63
+ "components",
64
+ "web-audio"
65
+ ],
66
+ "exports": {
67
+ ".": {
68
+ "require": {
69
+ "types": "./dist/index.d.cts",
70
+ "default": "./dist/index.cjs"
71
+ },
72
+ "import": {
73
+ "types": "./dist/index.d.ts",
74
+ "default": "./dist/index.js"
75
+ }
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,105 @@
1
+ import {
2
+ defineComponent,
3
+ h,
4
+ ref,
5
+ shallowRef,
6
+ watch,
7
+ watchEffect,
8
+ type PropType,
9
+ } from 'vue'
10
+
11
+ import {
12
+ createAnimationCanvas,
13
+ type AnimationCanvasInstance,
14
+ type AnimationFrame,
15
+ } from '@tremolo-ui/dom'
16
+
17
+ /** Called once the canvas is ready, and again whenever it is resized. */
18
+ export type InitFunction = (
19
+ context: CanvasRenderingContext2D,
20
+ size: { width: number; height: number },
21
+ ) => void
22
+
23
+ /** Called on every frame while `animate` is on, and once otherwise. */
24
+ export type DrawFunction = (
25
+ context: CanvasRenderingContext2D,
26
+ frame: AnimationFrame,
27
+ ) => void
28
+
29
+ /** A `<canvas>` drawn by `draw` on every animation frame. */
30
+ export const AnimationCanvas = /* @__PURE__ */ defineComponent({
31
+ name: 'AnimationCanvas',
32
+ inheritAttrs: false,
33
+ props: {
34
+ /** Draws a frame. */
35
+ draw: { type: Function as PropType<DrawFunction>, required: true },
36
+ /** Sets the canvas up before the first frame and after a resize. */
37
+ init: Function as PropType<InitFunction>,
38
+ /** Draw on every animation frame. @default true */
39
+ animate: { type: Boolean, default: true },
40
+ /** Settings for the 2D context. Read once, when the canvas is created. */
41
+ options: Object as PropType<CanvasRenderingContext2DSettings>,
42
+ /** Keep the drawing while the canvas is resized. @default true */
43
+ reduceFlickering: { type: Boolean, default: true },
44
+ /** Follow the size of the parent element; `width` and `height` are ignored. */
45
+ resizable: Boolean,
46
+ /** Width in CSS pixels, while not `resizable`. @default 100 */
47
+ width: { type: Number, default: 100 },
48
+ /** Height in CSS pixels, while not `resizable`. @default 100 */
49
+ height: { type: Number, default: 100 },
50
+ },
51
+ setup(props, { attrs }) {
52
+ const canvas = ref<HTMLCanvasElement | null>(null)
53
+ const instance = shallowRef<AnimationCanvasInstance | null>(null)
54
+
55
+ // Only `resizable` decides how the instance is wired, so it is the one
56
+ // setting that rebuilds it. The handlers are read at call time, and the
57
+ // rest is pushed with update().
58
+ watch(
59
+ [canvas, () => props.resizable],
60
+ ([element, resizable], _, onCleanup) => {
61
+ if (!element) return
62
+ const current = createAnimationCanvas(element, {
63
+ draw: (context, frame) => props.draw(context, frame),
64
+ init: (context, size) => props.init?.(context, size),
65
+ animate: props.animate,
66
+ size: { width: props.width, height: props.height },
67
+ reduceFlickering: props.reduceFlickering,
68
+ resizable,
69
+ contextAttributes: props.options,
70
+ })
71
+ instance.value = current
72
+ onCleanup(() => {
73
+ if (instance.value === current) instance.value = null
74
+ current.destroy()
75
+ })
76
+ },
77
+ { immediate: true, flush: 'post' },
78
+ )
79
+ // An effect rather than a watch: without a loop running, update() paints
80
+ // a frame right away, calling `draw` — so whatever state `draw` reads is
81
+ // tracked here, and a canvas driven by state rather than by time is
82
+ // painted again when it changes. A new `draw` or `init` counts too.
83
+ watchEffect(
84
+ () => {
85
+ void props.draw
86
+ void props.init
87
+ instance.value?.update({
88
+ animate: props.animate,
89
+ size: { width: props.width, height: props.height },
90
+ reduceFlickering: props.reduceFlickering,
91
+ })
92
+ },
93
+ { flush: 'post' },
94
+ )
95
+
96
+ // The context menu is suppressed unless the caller handles it: a
97
+ // listener of their own replaces this one rather than running after it.
98
+ return () =>
99
+ h('canvas', {
100
+ onContextmenu: (event: MouseEvent) => event.preventDefault(),
101
+ ...attrs,
102
+ ref: canvas,
103
+ })
104
+ },
105
+ })
@@ -0,0 +1,5 @@
1
+ export {
2
+ AnimationCanvas,
3
+ type DrawFunction,
4
+ type InitFunction,
5
+ } from './AnimationCanvas'
@@ -0,0 +1,43 @@
1
+ import { defineComponent, h, ref } from 'vue'
2
+
3
+ import { useDropZone } from '../../composables/useDropZone'
4
+
5
+ /** A region that takes dropped files. */
6
+ export const DropZone = /* @__PURE__ */ defineComponent({
7
+ name: 'DropZone',
8
+ props: {
9
+ /** Which files to take, as the `accept` attribute of a file input. */
10
+ accept: String,
11
+ /** Take every file dropped, rather than the first. */
12
+ multiple: Boolean,
13
+ /** Ignore drops. The zone carries `data-disabled`. */
14
+ disabled: Boolean,
15
+ },
16
+ emits: {
17
+ /** The dropped files that satisfy `accept`. */
18
+ drop: (files: File[], _event: DragEvent) => Array.isArray(files),
19
+ /** The dropped files that do not satisfy `accept`, after `drop` for the same drop. */
20
+ reject: (files: File[], _event: DragEvent) => Array.isArray(files),
21
+ },
22
+ setup(props, { slots, emit }) {
23
+ const el = ref<HTMLDivElement | null>(null)
24
+ const state = useDropZone(el, () => ({
25
+ accept: props.accept,
26
+ multiple: props.multiple,
27
+ disabled: props.disabled,
28
+ onDrop: (files, event) => emit('drop', files, event),
29
+ onReject: (files, event) => emit('reject', files, event),
30
+ }))
31
+ return () =>
32
+ h(
33
+ 'div',
34
+ {
35
+ ref: el,
36
+ 'data-dragover': state.value.over ? '' : undefined,
37
+ 'data-invalid': state.value.invalid ? '' : undefined,
38
+ 'data-disabled': props.disabled ? '' : undefined,
39
+ },
40
+ slots.default?.(),
41
+ )
42
+ },
43
+ })
@@ -0,0 +1 @@
1
+ export { DropZone } from './DropZone'