@tremolo-ui/react 0.5.0 → 0.6.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 (76) hide show
  1. package/dist/compose-refs.cjs +72 -0
  2. package/dist/compose-refs.cjs.map +1 -0
  3. package/dist/compose-refs.d.cts +43 -0
  4. package/dist/compose-refs.d.cts.map +1 -0
  5. package/dist/compose-refs.d.ts +43 -0
  6. package/dist/compose-refs.d.ts.map +1 -0
  7. package/dist/compose-refs.js +70 -0
  8. package/dist/compose-refs.js.map +1 -0
  9. package/dist/index.cjs +1468 -534
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +1103 -435
  12. package/dist/index.d.cts.map +1 -1
  13. package/dist/index.d.ts +1103 -435
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1457 -534
  16. package/dist/index.js.map +1 -1
  17. package/package.json +28 -26
  18. package/src/components/AnimationCanvas/index.tsx +115 -76
  19. package/src/components/Knob/ActiveLine.tsx +7 -6
  20. package/src/components/Knob/InactiveLine.tsx +9 -10
  21. package/src/components/Knob/SVGRoot.tsx +5 -3
  22. package/src/components/Knob/Thumb.tsx +33 -11
  23. package/src/components/Knob/context.tsx +17 -1
  24. package/src/components/Knob/index.tsx +148 -55
  25. package/src/components/NumberInput/DecrementStepper.tsx +8 -4
  26. package/src/components/NumberInput/IncrementStepper.tsx +9 -4
  27. package/src/components/NumberInput/InputField.tsx +188 -105
  28. package/src/components/NumberInput/Stepper.tsx +123 -72
  29. package/src/components/NumberInput/{stepperButton.tsx → StepperButton.tsx} +27 -22
  30. package/src/components/NumberInput/context.tsx +35 -8
  31. package/src/components/NumberInput/index.tsx +272 -75
  32. package/src/components/Piano/index.tsx +354 -188
  33. package/src/components/PointsEditor/Background.tsx +11 -2
  34. package/src/components/PointsEditor/Container.tsx +87 -27
  35. package/src/components/PointsEditor/Point.tsx +239 -79
  36. package/src/components/PointsEditor/SelectionBox.tsx +54 -0
  37. package/src/components/PointsEditor/context.tsx +78 -10
  38. package/src/components/PointsEditor/index.tsx +440 -39
  39. package/src/components/Slider/Marks.tsx +48 -16
  40. package/src/components/Slider/MarksOption.tsx +57 -43
  41. package/src/components/Slider/Thumb.tsx +108 -50
  42. package/src/components/Slider/Track.tsx +69 -58
  43. package/src/components/Slider/context.tsx +4 -2
  44. package/src/components/Slider/index.tsx +131 -65
  45. package/src/components/Slider/type.ts +26 -8
  46. package/src/components/XYPad/Area.tsx +45 -35
  47. package/src/components/XYPad/Thumb.tsx +135 -62
  48. package/src/components/XYPad/context.tsx +4 -1
  49. package/src/components/XYPad/index.tsx +180 -48
  50. package/src/components/_util/Placement.tsx +68 -0
  51. package/src/components/_util/VisuallyHiddenRangeInput.tsx +24 -0
  52. package/src/components/_util/css-length.ts +13 -0
  53. package/src/{components/_util/composeRefs.tsx → compose-refs/index.tsx} +33 -5
  54. package/src/hooks/_internal/useCallbackRef.ts +3 -1
  55. package/src/hooks/_internal/useCheckSteps.ts +170 -0
  56. package/src/hooks/useAnimationFrame.ts +17 -7
  57. package/src/hooks/useDrag.ts +38 -8
  58. package/src/hooks/useDragValue.ts +54 -9
  59. package/src/hooks/useEventListener.ts +10 -6
  60. package/src/hooks/useLongPress.ts +42 -8
  61. package/src/hooks/useMIDIAccess.ts +82 -11
  62. package/src/hooks/useMIDIInput.ts +45 -13
  63. package/src/hooks/useMIDIMessage.ts +23 -5
  64. package/src/index.ts +38 -21
  65. package/src/input-event.ts +32 -0
  66. package/dist/index.css +0 -501
  67. package/src/Globals.d.ts +0 -3
  68. package/src/components/Knob/index.css +0 -81
  69. package/src/components/NumberInput/index.css +0 -121
  70. package/src/components/Piano/index.css +0 -90
  71. package/src/components/PointsEditor/index.css +0 -35
  72. package/src/components/Slider/index.css +0 -125
  73. package/src/components/XYPad/index.css +0 -60
  74. package/src/components/_util/index.ts +0 -28
  75. package/src/styles/global.css +0 -19
  76. /package/src/components/Piano/{keyboardShortcuts.ts → keyboard-shortcuts.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["Thumb","defaultExternalStyles","WHEEL_OPTIONS","Root","linearScale","Root","linearScale","Root","isWhiteKey","Root","Thumb","defaultExternalStyles","WHEEL_OPTIONS","Root","linearScale","linearScale"],"sources":["../src/components/AnimationCanvas/index.tsx","../src/hooks/_internal/useCallbackRef.ts","../src/hooks/useDragValue.ts","../src/hooks/useWheel.ts","../src/components/_util/index.ts","../src/components/_util/composeRefs.tsx","../src/components/Knob/context.tsx","../src/components/Knob/ActiveLine.tsx","../src/components/Knob/InactiveLine.tsx","../src/components/Knob/SVGRoot.tsx","../src/components/Knob/Thumb.tsx","../src/components/Knob/index.tsx","../src/components/NumberInput/context.tsx","../src/hooks/useEventListener.ts","../src/hooks/useInterval.ts","../src/hooks/useLongPress.ts","../src/components/NumberInput/stepperButton.tsx","../src/components/NumberInput/DecrementStepper.tsx","../src/components/NumberInput/IncrementStepper.tsx","../src/components/NumberInput/InputField.tsx","../src/hooks/useDrag.ts","../src/components/NumberInput/Stepper.tsx","../src/components/NumberInput/index.tsx","../src/components/Piano/keyboardShortcuts.ts","../src/components/Piano/index.tsx","../src/components/PointsEditor/Background.tsx","../src/components/PointsEditor/context.tsx","../src/components/PointsEditor/Container.tsx","../src/components/PointsEditor/Point.tsx","../src/components/PointsEditor/index.tsx","../src/components/Slider/context.tsx","../src/components/Slider/MarksOption.tsx","../src/components/Slider/type.ts","../src/components/Slider/Marks.tsx","../src/components/Slider/Thumb.tsx","../src/components/Slider/Track.tsx","../src/components/Slider/index.tsx","../src/components/XYPad/context.tsx","../src/components/XYPad/Area.tsx","../src/components/XYPad/Thumb.tsx","../src/components/XYPad/index.tsx","../src/hooks/useAnimationFrame.ts","../src/hooks/useMIDIAccess.ts","../src/hooks/useMIDIInput.ts","../src/hooks/useMIDIMessage.ts"],"sourcesContent":["import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n ReactElement,\n useEffect,\n useRef,\n useState,\n} from 'react'\n\nimport {\n createAnimationCanvas,\n type AnimationCanvasInstance,\n type AnimationFrame,\n} from '@tremolo-ui/dom'\n\nexport type InitFunction = (\n context: CanvasRenderingContext2D,\n option: {\n /** current canvas width */\n width: number\n /** current canvas height */\n height: number\n },\n) => void\n\nexport type DrawFunction = (\n context: CanvasRenderingContext2D,\n option: AnimationFrame,\n) => void\n\nexport interface CommonProps {\n draw: DrawFunction\n init?: InitFunction\n animate?: boolean\n /**\n * Read once, when the 2D context is created, so changing it later has no\n * effect. Passing a fresh object on every render is therefore harmless.\n *\n * @see https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement/getContext#contextattributes\n */\n options?: CanvasRenderingContext2DSettings\n}\n\nexport interface AbsoluteSizingProps {\n width?: number\n height?: number\n}\n\nexport interface RelativeSizingProps {\n relativeSize?: boolean\n reduceFlickering?: boolean\n}\n\nexport type AnimationCanvasProps = CommonProps &\n AbsoluteSizingProps &\n RelativeSizingProps\n\n/**\n * A simple animatable canvas with requestAnimationFrame()\n */\nexport function AnimationCanvas(\n props: CommonProps &\n AbsoluteSizingProps &\n Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>,\n): ReactElement\nexport function AnimationCanvas(\n pros: CommonProps &\n RelativeSizingProps &\n Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>,\n): ReactElement\nexport function AnimationCanvas({\n // common\n draw,\n init,\n animate = true,\n options,\n // absolute\n width = 100,\n height = 100,\n // relative\n relativeSize = false,\n reduceFlickering = true,\n // canvas props\n className,\n onContextMenu = (event) => event.preventDefault(),\n ...props\n}: AnimationCanvasProps &\n Omit<\n ComponentPropsWithoutRef<'canvas'>,\n keyof AnimationCanvasProps\n >): ReactElement {\n // See useDrag for why the node is held in state rather than a ref: an inline\n // ref would be re-attached on every render and tear the instance down.\n const [node, setNode] = useState<HTMLCanvasElement | null>(null)\n\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale handler is replaced within the same commit.\n const latest = useRef({\n draw,\n init,\n animate,\n width,\n height,\n reduceFlickering,\n options,\n })\n const instanceRef = useRef<AnimationCanvasInstance | null>(null)\n /** Set while the instance below is newer than the effect that pushes into it. */\n const justCreated = useRef(false)\n\n useEffect(() => {\n if (!node) return\n\n const current = latest.current\n const instance = createAnimationCanvas(node, {\n draw: (context, frame) => latest.current.draw(context, frame),\n init: (context, size) => latest.current.init?.(context, size),\n animate: current.animate,\n size: { width: current.width, height: current.height },\n reduceFlickering: current.reduceFlickering,\n relativeSize,\n contextAttributes: current.options,\n })\n instanceRef.current = instance\n justCreated.current = true\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n // Only `relativeSize` decides how the instance is wired, so it is the one\n // setting that rebuilds it. `options` is read from the ref above rather\n // than depended on: it is almost always written inline, and depending on\n // it would tear the canvas down on every render.\n }, [node, relativeSize])\n\n // Runs after every render: the handlers come from props and are cheap to\n // push, and updating in place keeps the frame count and elapsed time going.\n useEffect(() => {\n latest.current = {\n draw,\n init,\n animate,\n width,\n height,\n reduceFlickering,\n options,\n }\n // The instance was built from `latest` a moment ago, so there is nothing\n // to push yet. Skipping matters with `animate` off, where `update()` draws\n // a frame and would otherwise paint the same one twice on mount.\n if (justCreated.current) {\n justCreated.current = false\n return\n }\n instanceRef.current?.update({\n animate,\n size: { width, height },\n reduceFlickering,\n })\n })\n\n return (\n <canvas\n className={clsx('tremolo-animation-canvas', className)}\n ref={setNode}\n onContextMenu={onContextMenu}\n {...props}\n />\n )\n}\n","import { DependencyList, useCallback, useInsertionEffect, useRef } from 'react'\n\n/**\n * Internal\n * @private\n */\nexport function useCallbackRef<Args extends unknown[], Return>(\n callback: ((...args: Args) => Return) | undefined,\n deps: DependencyList = [],\n) {\n const callbackRef = useRef<typeof callback>(() => {\n throw new Error('Cannot call an event handler while rendering.')\n })\n\n useInsertionEffect(() => {\n callbackRef.current = callback\n })\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useCallback((...args: Args) => callbackRef.current?.(...args), deps)\n}\n","import { RefObject, useEffect, useRef, useState } from 'react'\n\nimport {\n createDragValue,\n elementMapping,\n relativeMapping,\n type AxisOptions,\n type DragValueInstance,\n type XY,\n type XYInput,\n} from '@tremolo-ui/dom'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\nexport interface UseDragValueOptions {\n /** Scaling of each axis; a single value applies to both. */\n axis: XYInput<AxisOptions>\n\n /**\n * Normalize the pointer against the bounding rect of this element, so that\n * the value *is* the position pointed at.\n *\n * Give either this or `getValue`.\n */\n baseElementRef?: RefObject<Element | null>\n\n /**\n * Move the value away from where it stood when the drag started, by the\n * distance dragged. The pointer position itself carries no meaning.\n *\n * Give either this or `baseElementRef`.\n */\n getValue?: () => XY<number>\n /**\n * Pixels of movement that span the whole range, with `getValue`.\n * @default 100\n */\n pixelRange?: XYInput<number>\n\n /** @see DragValueOptions.updateOnPointerDown */\n updateOnPointerDown?: boolean\n /** @default 0 */\n threshold?: number\n /** CSS cursor to show while dragging. Applied to the element itself. */\n cursor?: string\n\n onChange?: (value: XY<number>) => void\n onDragStart?: (value: XY<number>) => void\n onDragEnd?: (value: XY<number>) => void\n}\n\n/**\n * Drive a value with a pointer drag.\n *\n * @returns a ref callback for the element that starts the drag, and whether a drag is in progress\n */\nexport function useDragValue<T extends Element>(\n options: UseDragValueOptions,\n): { refCallback: (node: T | null) => void; dragging: boolean } {\n const {\n axis,\n baseElementRef,\n pixelRange,\n updateOnPointerDown,\n threshold,\n cursor,\n } = options\n\n if (!baseElementRef && !options.getValue) {\n throw new Error(\n 'useDragValue: give either baseElementRef or getValue, so that the drag has something to move',\n )\n }\n\n const [dragging, setDragging] = useState(false)\n\n const valueGetter = useCallbackRef(options.getValue)\n const changeHandler = useCallbackRef(options.onChange)\n const dragStartHandler = useCallbackRef(options.onDragStart)\n const dragEndHandler = useCallbackRef(options.onDragEnd)\n\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale setting is replaced within the same commit.\n const latest = useRef(options)\n\n const instanceRef = useRef<DragValueInstance | null>(null)\n\n // See useDrag for why the node is held in state.\n const [node, setNode] = useState<T | null>(null)\n\n const [pixelRangeX, pixelRangeY] = Array.isArray(pixelRange)\n ? pixelRange\n : [pixelRange, pixelRange]\n\n useEffect(() => {\n if (!node) return\n\n const instance = createDragValue(node, {\n axis: latest.current.axis,\n mapping: baseElementRef\n ? elementMapping(() => baseElementRef.current)\n : relativeMapping({\n pixelRange: [pixelRangeX ?? 100, pixelRangeY ?? 100],\n }),\n getValue: () => valueGetter() ?? [0, 0],\n updateOnPointerDown: latest.current.updateOnPointerDown,\n threshold: latest.current.threshold,\n cursor: latest.current.cursor,\n onChange: (value) => changeHandler(value),\n onDragStart: (value) => {\n setDragging(true)\n dragStartHandler(value)\n },\n onDragEnd: (value) => {\n setDragging(false)\n dragEndHandler(value)\n },\n })\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n }, [\n node,\n baseElementRef,\n pixelRangeX,\n pixelRangeY,\n valueGetter,\n changeHandler,\n dragStartHandler,\n dragEndHandler,\n ])\n\n // Runs after every render: the settings come from props and are cheap to\n // push, and updating in place leaves a drag in progress untouched.\n useEffect(() => {\n latest.current = options\n instanceRef.current?.update({\n axis,\n updateOnPointerDown,\n threshold,\n cursor,\n })\n })\n\n return { refCallback: setNode, dragging }\n}\n","import { RefObject, useEffect, useState } from 'react'\n\nimport { createWheel, type WheelOptions } from '@tremolo-ui/dom'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\nexport interface UseWheelOptions extends WheelOptions {\n /**\n * Listen on this element rather than on the one the returned ref callback is\n * attached to, and ignore that callback.\n *\n * For a control made of several movable parts: a wheel event only reaches\n * what the cursor is over, so a listener per part responds only while the\n * cursor is over that same part. Listening on the element they share lets\n * every part see the event, and each one decide whether it is the one to act.\n *\n * The element is read when the listener is attached, so a ref filled in by a\n * parent is fine as long as the parent is above in the tree.\n */\n target?: RefObject<Element | null>\n}\n\n/**\n * Listen to wheel events on an element.\n *\n * The listener is not passive, so the handler may call `preventDefault()`.\n *\n * @returns a ref callback to attach to the element, unused when `target` is given\n */\nexport function useWheel<T extends Element>(\n onWheel: (event: WheelEvent) => void,\n { requireFocus = false, target }: UseWheelOptions = {},\n): (node: T | null) => void {\n const wheelHandler = useCallbackRef(onWheel)\n\n // See useDrag for why the node is held in state.\n const [node, setNode] = useState<T | null>(null)\n\n useEffect(() => {\n const element = target ? target.current : node\n if (!element) return\n\n const instance = createWheel(element, (event) => wheelHandler(event), {\n requireFocus,\n })\n\n return () => instance.destroy()\n }, [node, target, wheelHandler, requireFocus])\n\n return setNode\n}\n","export function addUserSelectNone() {\n window.document.body.classList.add('tremolo-user-select-none')\n}\n\nexport function removeUserSelectNone() {\n window.document.body.classList.remove('tremolo-user-select-none')\n}\n\nconst cursorStyles = {\n grabbing: 'tremolo-cursor-grabbing',\n grab: 'tremolo-cursor-grab',\n pointer: 'tremolo-cursor-pointer',\n move: 'tremolo-cursor-move',\n none: 'tremolo-cursor-none',\n}\n\nexport type Cursor = keyof typeof cursorStyles\n\nexport function setCursorStyle(type: Cursor) {\n resetCursorStyle()\n window.document.body.classList.add(cursorStyles[type])\n}\n\nexport function resetCursorStyle() {\n Object.values(cursorStyles).forEach((s) => {\n window.document.body.classList.remove(s)\n })\n}\n","// ref:\n// https://github.com/radix-ui/primitives/blob/2bab24a811e45c7a83198659272097f6cfa5a165/packages/react/compose-refs/src/compose-refs.tsx\n\nimport { useCallback } from 'react'\n\ntype PossibleRef<T> = React.Ref<T> | undefined\n\n/**\n * Set a given ref to a given value\n * This utility takes care of different types of refs: callback refs and RefObject(s)\n */\nfunction setRef<T>(ref: PossibleRef<T>, value: T) {\n if (typeof ref === 'function') {\n return ref(value)\n } else if (ref !== null && ref !== undefined) {\n ref.current = value\n }\n}\n\n/**\n * A utility to compose multiple refs together\n * Accepts callback refs and RefObject(s)\n */\nfunction composeRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {\n return (node) => {\n let hasCleanup = false\n const cleanups = refs.map((ref) => {\n const cleanup = setRef(ref, node)\n if (!hasCleanup && typeof cleanup == 'function') {\n hasCleanup = true\n }\n return cleanup\n })\n\n // React <19 will log an error to the console if a callback ref returns a\n // value. We don't use ref cleanups internally so this will only happen if a\n // user's ref callback returns a value, which we only expect if they are\n // using the cleanup functionality added in React 19.\n if (hasCleanup) {\n return () => {\n for (let i = 0; i < cleanups.length; i++) {\n const cleanup = cleanups[i]\n if (typeof cleanup == 'function') {\n cleanup()\n } else {\n setRef(refs[i], null)\n }\n }\n }\n }\n }\n}\n\n/**\n * A custom hook that composes multiple refs\n * Accepts callback refs and RefObject(s)\n */\nfunction useComposedRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useCallback(composeRefs(...refs), refs)\n}\n\nexport { composeRefs, useComposedRefs }\n","import { createContext, useContext } from 'react'\n\nimport { radian, type Scale } from '@tremolo-ui/functions'\n\nexport const viewBoxSize = 100\nexport const center = viewBoxSize / 2\n\nexport type KnobConfig = {\n value: number\n min: number\n max: number\n step: number\n scale: Scale\n startValue: number\n /** angle range [degree] */\n angleRange: number\n}\n\nexport type KnobContextValue = KnobConfig & {\n /** normalized value */\n p: number\n /** ロータリー開始位置 */\n r1: number\n /** activeLine の開始位置 */\n r2: number\n /** activeLine の終了位置 */\n r3: number\n /** ロータリー終了位置 */\n r4: number\n}\n\n/**\n * 角度から円弧上の点を求める。\n *\n * 半径は線の太さの分だけ内側に取る必要があるが、太さは ActiveLine / InactiveLine が\n * それぞれ持つため、座標はストアで先に計算せず各コンポーネント側で求める。\n */\nexport function pointOnArc(angle: number, radius: number) {\n return {\n x: center + radius * Math.cos(radian(angle - 90)),\n y: center + radius * Math.sin(radian(angle - 90)),\n }\n}\n\n/** 線の太さが viewBox からはみ出さないようにした半径 */\nexport function arcRadius(strokeWidth: number | string | undefined) {\n const width =\n typeof strokeWidth === 'number'\n ? strokeWidth\n : Number.parseFloat(String(strokeWidth))\n return Number.isFinite(width) ? center - width / 2 : center\n}\n\n/** 設定から描画に必要な角度を導出する。レンダー中に呼ぶ。 */\nexport function calcAngles({\n value,\n min,\n max,\n scale,\n startValue,\n angleRange,\n}: KnobConfig) {\n const p = scale.normalize(value, min, max)\n const s = scale.normalize(startValue, min, max)\n\n const r1 = -angleRange / 2\n const r2 = r1 + Math.min(p, s) * angleRange\n const r3 = r1 + Math.max(p, s) * angleRange\n const r4 = angleRange / 2\n\n return { p, r1, r2, r3, r4 }\n}\n\nconst KnobContext = createContext<KnobContextValue | null>(null)\n\nexport const KnobProvider = KnobContext.Provider\n\n/**\n * Everything here is derived during render, so there is no state to keep in\n * sync: `value` comes from the props of `Root` and the rest follows from it.\n */\nexport function useKnobContext(): KnobContextValue\nexport function useKnobContext<T>(selector: (state: KnobContextValue) => T): T\nexport function useKnobContext<T>(selector?: (state: KnobContextValue) => T) {\n const context = useContext(KnobContext)\n if (!context) throw new Error('Missing KnobContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import clsx from 'clsx'\nimport { SVGProps } from 'react'\n\nimport { arcRadius, pointOnArc, useKnobContext } from './context'\n\nexport function ActiveLine({\n stroke = 'currentColor',\n strokeWidth = 6,\n className,\n ...props\n}: Omit<SVGProps<SVGPathElement>, 'd'>) {\n const r2 = useKnobContext((s) => s.r2)\n const r3 = useKnobContext((s) => s.r3)\n\n const radius = arcRadius(strokeWidth)\n const start = pointOnArc(r2, radius)\n const end = pointOnArc(r3, radius)\n\n return (\n <path\n className={clsx('tremolo-knob-active-line', className)}\n d={`M ${start.x} ${start.y} A ${radius} ${radius} -135 ${r3 - r2 > 180 ? 1 : 0} 1 ${end.x} ${end.y}`}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n {...props}\n />\n )\n}\n","import clsx from 'clsx'\nimport { SVGProps } from 'react'\n\nimport { arcRadius, pointOnArc, useKnobContext } from './context'\n\nexport function InactiveLine({\n stroke = 'currentColor',\n strokeWidth = 6,\n className,\n ...props\n}: Omit<SVGProps<SVGPathElement>, 'd'>) {\n const min = useKnobContext((s) => s.min)\n const max = useKnobContext((s) => s.max)\n const startValue = useKnobContext((s) => s.startValue)\n\n const r1 = useKnobContext((s) => s.r1)\n const r2 = useKnobContext((s) => s.r2)\n const r3 = useKnobContext((s) => s.r3)\n const r4 = useKnobContext((s) => s.r4)\n\n const radius = arcRadius(strokeWidth)\n const p1 = pointOnArc(r1, radius)\n const p2 = pointOnArc(r2, radius)\n const p3 = pointOnArc(r3, radius)\n const p4 = pointOnArc(r4, radius)\n\n return (\n <>\n {startValue > min && (\n <path\n className={clsx('tremolo-knob-inactive-line', className)}\n d={`M ${p1.x} ${p1.y} A ${radius} ${radius} -135 ${r2 - r1 > 180 ? 1 : 0} 1 ${p2.x} ${p2.y}`}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n {...props}\n />\n )}\n {startValue < max && (\n <path\n className={clsx('tremolo-knob-inactive-line', className)}\n d={`M ${p3.x} ${p3.y} A ${radius} ${radius} -135 ${r4 - r3 > 180 ? 1 : 0} 1 ${p4.x} ${p4.y}`}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n {...props}\n />\n )}\n </>\n )\n}\n","import { ReactNode, SVGProps } from 'react'\n\nimport { viewBoxSize } from './context'\n\nexport interface SVGRootProps {\n /**\n * `<Knob.InactiveLine />`, `<Knob.ActiveLine />` and `<Knob.Thumb />` go\n * here, in the order you want them painted.\n */\n children: ReactNode\n}\n\nexport function SVGRoot({\n children,\n style,\n ...props\n}: SVGRootProps & Omit<SVGProps<SVGSVGElement>, keyof SVGRootProps>) {\n return (\n <svg\n viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}\n style={{\n display: 'block',\n ...style,\n }}\n {...props}\n >\n {children}\n </svg>\n )\n}\n","import clsx from 'clsx'\nimport { SVGProps } from 'react'\n\nimport { clamp } from '@tremolo-ui/functions'\n\nimport { useKnobContext, viewBoxSize } from './context'\n\ninterface Props {\n /** color */\n thumb?: string\n /** color */\n thumbLine?: string\n /** percent (0-100) */\n thumbSize?: number\n /** percent (0-100) */\n thumbLineWeight?: number\n /** percent (0-100) */\n thumbLineLength?: number\n\n classes?: {\n thumb?: string\n thumbLine?: string\n }\n}\n\nexport function Thumb({\n className,\n\n thumb = 'currentColor',\n thumbLine = 'currentColor',\n thumbSize = 84,\n thumbLineWeight = 6,\n thumbLineLength = 35,\n classes,\n\n ...props\n}: Props & Omit<SVGProps<SVGSVGElement>, 'd' | keyof Props>) {\n const angleRange = useKnobContext((s) => s.angleRange)\n\n const p = useKnobContext((s) => s.p)\n const r1 = useKnobContext((s) => s.r1)\n\n return (\n <svg className={clsx('tremolo-knob-thumb', classes?.thumb)} {...props}>\n <circle cx=\"50%\" cy=\"50%\" r={`${thumbSize / 2}%`} fill={thumb} />\n <line\n className={clsx('tremolo-knob-thumb-line', classes?.thumbLine)}\n x1=\"50%\"\n y1={`${(viewBoxSize - clamp(thumbSize, 0, 100)) / 2}%`}\n x2=\"50%\"\n y2={`${thumbLineLength}%`}\n stroke={thumbLine}\n strokeWidth={`${thumbLineWeight}%`}\n // NOTE\n // https://bugs.webkit.org/show_bug.cgi?id=201854\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform-origin#browser_compatibility\n style={{\n transform: `rotate(${r1 + p * angleRange}deg)`,\n transformOrigin: '50% 50%',\n }}\n />\n </svg>\n )\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n forwardRef,\n ReactNode,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react'\n\nimport type { AxisOptions, XY } from '@tremolo-ui/dom'\nimport {\n applyDelta,\n InputEventOption,\n linearScale,\n type Scale,\n type ValueRange,\n} from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport { addUserSelectNone, Cursor, removeUserSelectNone } from '../_util'\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { ActiveLine } from './ActiveLine'\nimport { calcAngles, KnobProvider } from './context'\nimport { InactiveLine } from './InactiveLine'\nimport { SVGRoot } from './SVGRoot'\nimport { Thumb } from './Thumb'\n\nconst defaultExternalStyles: KnobProps['externalStyles'] = {\n userSelectNone: true,\n cursor: 'grabbing',\n}\n\nexport interface KnobProps {\n // required\n value: number\n min: number\n max: number\n\n // optional\n step?: number\n /**\n * How the value is distributed across the travel.\n *\n * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,\n * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or\n * `skewScale(n)` for a value that has to match a JUCE parameter.\n *\n * @default linearScale\n */\n scale?: Scale\n /**\n * value set when double-clicking\n * restriction: enableDoubleClickDefault = true\n * @default min\n * @see enableDoubleClickDefault\n */\n defaultValue?: number\n\n /**\n * Value to be used as the starting point of the line when drawing.\n * @default min\n */\n startValue?: number\n\n /** width and height */\n /**\n * Width and height of the knob.\n * Defaults to the `--knob-size` CSS variable (50px).\n */\n size?: number | string\n\n /**\n * Global style to apply when dragged\n * @default defaultExternalStyles\n */\n externalStyles?: {\n userSelectNone?: boolean\n cursor?: Cursor\n }\n /**\n * wheel control option\n * If null, no event will be triggered\n */\n wheel?: InputEventOption | null\n /**\n * keyboard control option\n * If null, no event will be triggered\n */\n keyboard?: InputEventOption | null\n enableDoubleClickDefault?: boolean\n\n disabled?: boolean\n readonly?: boolean\n\n /** angle range [degree] */\n angleRange?: number\n\n onChange?: (value: number) => void\n\n /**\n * The knob renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <Knob.Root value={value} min={0} max={100} onChange={setValue}>\n * <Knob.SVGRoot>\n * <Knob.InactiveLine />\n * <Knob.ActiveLine />\n * <Knob.Thumb />\n * </Knob.SVGRoot>\n * </Knob.Root>\n */\n children: ReactNode\n}\n\nexport interface KnobMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = KnobProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KnobProps>\n\n/**\n * The wheel only acts while the focus is inside, so that scrolling a page past\n * the control does not change its value.\n */\nconst WHEEL_OPTIONS = { requireFocus: true }\n\nexport const Root = forwardRef<KnobMethods, Props>(\n (\n {\n value,\n min,\n max,\n step = 1,\n scale = linearScale,\n defaultValue = min,\n startValue = min,\n size,\n externalStyles: _externalStyles,\n wheel = ['raw', 1],\n keyboard = ['raw', 1],\n enableDoubleClickDefault = true,\n disabled = false,\n readonly = false,\n angleRange = 270,\n onChange,\n onKeyDown,\n onPointerDown,\n onDoubleClick,\n className,\n style,\n children,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n const elmRef = useRef<HTMLElement | SVGElement>(null)\n\n const externalStyles = { ...defaultExternalStyles, ..._externalStyles }\n\n // --- internal functions ---\n const range: ValueRange = useMemo(\n () => ({ min, max, step, scale }),\n [min, max, step, scale],\n )\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLOrSVGElement>) => {\n if (!keyboard || !onChange || readonly) return\n const key = event.key\n if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {\n event.preventDefault()\n const direction = key == 'ArrowRight' || key == 'ArrowUp' ? 1 : -1\n onChange(applyDelta(value, direction, keyboard, range))\n }\n },\n [keyboard, onChange, readonly, value, range],\n )\n\n // --- hooks ---\n // The knob has no travel of its own: the value moves away from where it\n // stood when the drag started, 100px of movement spanning the whole range.\n // Only the vertical axis carries a value, reversed so that dragging up\n // raises it.\n const axis = useMemo(\n (): XY<AxisOptions> => [range, { ...range, reverse: true }],\n [range],\n )\n\n const { refCallback: dragRefCallback, dragging } = useDragValue<\n HTMLElement | SVGElement\n >({\n axis,\n getValue: () => [value, value],\n threshold: 1,\n cursor: readonly ? undefined : externalStyles.cursor,\n onChange: (v) => {\n if (readonly) return\n onChange?.(v[1])\n },\n onDragStart: () => {\n if (externalStyles.userSelectNone) addUserSelectNone()\n },\n onDragEnd: () => {\n if (externalStyles.userSelectNone) removeUserSelectNone()\n },\n })\n\n const wheelRefCallback = useWheel<HTMLElement>((event) => {\n if (!wheel || readonly) return\n event.preventDefault()\n if (!onChange || event.deltaY == 0) return\n onChange(applyDelta(value, -Math.sign(event.deltaY), wheel, range))\n }, WHEEL_OPTIONS)\n\n // Composed once, so React attaches the refs a single time instead of\n // detaching and re-attaching on every render.\n const rootRefCallback = useComposedRefs<HTMLElement | SVGElement>(\n elmRef,\n dragRefCallback,\n wheelRefCallback,\n )\n\n const context = useMemo(() => {\n const config = { value, min, max, step, scale, startValue, angleRange }\n return { ...config, ...calcAngles(config) }\n }, [value, min, max, step, scale, startValue, angleRange])\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n elmRef.current?.focus()\n },\n blur() {\n elmRef.current?.blur()\n },\n }\n }, [])\n\n return (\n <KnobProvider value={context}>\n <div\n ref={rootRefCallback}\n className={clsx('tremolo-knob', className)}\n tabIndex={0}\n role=\"slider\"\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-disabled={disabled}\n aria-readonly={readonly}\n data-dragging={dragging}\n style={{\n width: size,\n height: size,\n ...style,\n }}\n onPointerDown={onPointerDown}\n onDoubleClick={(event) => {\n if (enableDoubleClickDefault && onChange) {\n onChange(defaultValue)\n }\n onDoubleClick?.(event)\n }}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n {...props}\n >\n {children}\n </div>\n </KnobProvider>\n )\n },\n)\n\n/**\n * Interactive rotary knob component implemented in SVG.\n */\nexport const Knob = {\n Root,\n SVGRoot,\n InactiveLine,\n ActiveLine,\n Thumb,\n}\n\nexport { useKnobContext } from './context'\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type { InputEventOption, Scale, ValueRange } from '@tremolo-ui/functions'\n\nexport type NumberInputContextValue = {\n value: number\n\n /**\n * The range the caller asked for. Left undefined when unbounded, which is\n * what `aria-valuemin` / `aria-valuemax` and the steppers need to tell apart\n * from a range that happens to sit at the edge of the safe integers.\n */\n min?: number\n max?: number\n step: number\n /** How the value is distributed across the travel. */\n scale: Scale\n\n disabled: boolean\n readonly: boolean\n clampValue: boolean\n\n /**\n * The effective scaling for `applyDelta` and for clamping on commit, with the\n * unbounded ends filled in. Ignores `min` / `max` when `clampValue` is off.\n */\n range: ValueRange\n\n keyboard: InputEventOption | null\n /** Pixels of vertical drag on `Stepper` that move the value by one `step`. */\n drag: number | null\n\n /** What the input shows: the draft while editing, the formatted value otherwise. */\n text: string\n editing: boolean\n /** Whether the value sits outside `min` / `max`. Not judged while editing. */\n outOfRange: boolean\n /** Whether a stepper would have no effect, for `aria-disabled`. */\n atMin: boolean\n atMax: boolean\n\n format: (value: number) => string\n parse: (text: string) => number\n\n /** Typing. Replaces the draft and reports the parsed value, unclamped. */\n setDraft: (text: string) => void\n /** Blur or Enter. Clamps the draft, reports it, and drops the draft. */\n commitDraft: () => void\n /** Drops the draft and replaces the value: steppers, wheel, keyboard, drag. */\n changeValue: (next: number) => void\n /** Moves the value by one `option` in `direction`, normally +1 or -1. */\n nudge: (direction: number, option: InputEventOption) => void\n\n /** `InputField` registers itself here; `Root` focuses it through its methods. */\n inputRef: RefObject<HTMLInputElement | null>\n}\n\nconst NumberInputContext = createContext<NumberInputContextValue | null>(null)\n\nexport const NumberInputProvider = NumberInputContext.Provider\n\n/**\n * The only state behind this is the editing draft; `value` comes from the props\n * of `Root` and everything else is derived during render.\n */\nexport function useNumberInputContext(): NumberInputContextValue\nexport function useNumberInputContext<T>(\n selector: (state: NumberInputContextValue) => T,\n): T\nexport function useNumberInputContext<T>(\n selector?: (state: NumberInputContextValue) => T,\n) {\n const context = useContext(NumberInputContext)\n if (!context)\n throw new Error('Missing NumberInputContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n\n/** Set by `Stepper` once a drag has actually moved, so the steppers stand down. */\nexport type StepperContextValue = {\n draggingRef: RefObject<boolean>\n}\n\nconst StepperContext = createContext<StepperContextValue | null>(null)\n\nexport const StepperProvider = StepperContext.Provider\n\nexport function useStepperContext(): StepperContextValue | null {\n return useContext(StepperContext)\n}\n","import { useEffect } from 'react'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\ntype Target = EventTarget | null | (() => EventTarget | null)\ntype Options = boolean | AddEventListenerOptions\n\nexport function useEventListener<K extends keyof DocumentEventMap>(\n target: Target,\n event: K,\n handler: (event: DocumentEventMap[K]) => void,\n options?: Options,\n): VoidFunction\nexport function useEventListener<K extends keyof WindowEventMap>(\n target: Target,\n event: K,\n handler: (event: WindowEventMap[K]) => void,\n options?: Options,\n): VoidFunction\nexport function useEventListener<K extends keyof GlobalEventHandlersEventMap>(\n target: Target,\n event: K,\n handler: (event: GlobalEventHandlersEventMap[K]) => void,\n options?: Options,\n): VoidFunction\nexport function useEventListener(\n target: Target,\n event: string,\n handler: (event: Event) => void,\n options?: Options,\n) {\n const listener = useCallbackRef(handler)\n\n useEffect(() => {\n const node = typeof target === 'function' ? target() : (target ?? document)\n\n if (!node) return\n\n node.addEventListener(event, listener, options)\n return () => {\n node.removeEventListener(event, listener, options)\n }\n }, [event, target, options, listener])\n\n return () => {\n const node = typeof target === 'function' ? target() : (target ?? document)\n node?.removeEventListener(event, listener, options)\n }\n}\n","import { useEffect, useRef } from 'react'\n\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback)\n\n // Remember the latest callback if it changes.\n useEffect(() => {\n savedCallback.current = callback\n }, [callback])\n\n // Set up the interval.\n useEffect(() => {\n // Don't schedule if no delay is specified.\n // Note: 0 is a valid value for delay.\n if (delay === null) {\n return\n }\n\n const id = setInterval(() => {\n savedCallback.current()\n }, delay)\n\n return () => {\n clearInterval(id)\n }\n }, [delay])\n}\n","import { useCallback, useState } from 'react'\n\nimport { useEventListener } from './useEventListener'\nimport { useInterval } from './useInterval'\n\nexport function useLongPress(\n callback: () => void,\n initialDelay = 500,\n interval = 40,\n) {\n const [pressed, setPressed] = useState(false)\n const [delay, setDelay] = useState(initialDelay)\n\n useInterval(\n () => {\n callback()\n setDelay(interval)\n },\n pressed ? delay : null,\n )\n\n useEventListener(globalThis.window, 'pointerup', () => {\n setPressed(false)\n setDelay(initialDelay)\n })\n\n return useCallback(() => {\n callback()\n setPressed(true)\n }, [callback])\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n CSSProperties,\n ReactNode,\n useCallback,\n} from 'react'\n\nimport { useLongPress } from '../../hooks/useLongPress'\n\nimport { useNumberInputContext, useStepperContext } from './context'\n\nexport interface StepperButtonProps {\n className?: string\n style?: CSSProperties\n /** Replaces the default arrow. Size it with the `--stepper-icon-size` variable. */\n children?: ReactNode\n}\n\ntype Props = StepperButtonProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof StepperButtonProps>\n\n/**\n * Shared body of `IncrementStepper` and `DecrementStepper`: the two differ only\n * in which way they move the value and which arrow they draw.\n */\nexport function StepperButton({\n direction,\n variant,\n icon,\n className,\n style,\n children,\n onPointerDown,\n ...props\n}: Props & {\n direction: 1 | -1\n variant: 'increment' | 'decrement'\n icon: ReactNode\n}) {\n const { step, readonly, atMin, atMax, nudge } = useNumberInputContext()\n const stepper = useStepperContext()\n\n const press = useLongPress(\n useCallback(() => {\n // Once the pointer has actually travelled, the drag on `Stepper` owns the\n // value; repeating on top of it would move it twice.\n if (stepper?.draggingRef.current) return\n nudge(direction, ['raw', step])\n }, [stepper, nudge, direction, step]),\n )\n\n return (\n // eslint-disable-next-line jsx-a11y/role-supports-aria-props\n <div\n className={clsx(`tremolo-number-input-${variant}-stepper`, className)}\n role=\"button\"\n tabIndex={-1}\n // A bare arrow has no accessible name of its own. Overridable, since a\n // caller may need it in their own language.\n aria-label={direction > 0 ? 'Increment' : 'Decrement'}\n aria-disabled={direction > 0 ? atMax : atMin}\n aria-readonly={readonly}\n style={style}\n onPointerDown={(event) => {\n if (!readonly) press()\n onPointerDown?.(event)\n }}\n {...props}\n >\n {children ?? icon}\n </div>\n )\n}\n\nexport function StepperArrow({ up }: { up: boolean }) {\n return (\n <svg\n className=\"tremolo-number-input-stepper-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points={up ? '18 15 12 9 6 15' : '6 9 12 15 18 9'} />\n </svg>\n )\n}\n","import { ComponentPropsWithoutRef } from 'react'\n\nimport {\n StepperArrow,\n StepperButton,\n StepperButtonProps,\n} from './stepperButton'\n\nexport type DecrementStepperProps = StepperButtonProps\n\n/** Lowers the value by one `step`, repeating while held. */\nexport function DecrementStepper(\n props: DecrementStepperProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof DecrementStepperProps>,\n) {\n return (\n <StepperButton\n direction={-1}\n variant=\"decrement\"\n icon={<StepperArrow up={false} />}\n {...props}\n />\n )\n}\n","import { ComponentPropsWithoutRef } from 'react'\n\nimport {\n StepperArrow,\n StepperButton,\n StepperButtonProps,\n} from './stepperButton'\n\nexport type IncrementStepperProps = StepperButtonProps\n\n/** Raises the value by one `step`, repeating while held. */\nexport function IncrementStepper(\n props: IncrementStepperProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof IncrementStepperProps>,\n) {\n return (\n <StepperButton\n direction={1}\n variant=\"increment\"\n icon={<StepperArrow up />}\n {...props}\n />\n )\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, CSSProperties, Ref } from 'react'\n\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { useNumberInputContext } from './context'\n\nexport interface NumberInputFieldProps {\n /**\n * Select the text when the input takes focus. `'number'` selects the leading\n * number, leaving whatever the format appended to it.\n * @default 'none'\n */\n selectOnFocus?: 'all' | 'number' | 'none'\n /**\n * Commit and leave the input when Enter is pressed. Enter commits either way.\n * @default true\n */\n blurOnEnter?: boolean\n\n className?: string\n style?: CSSProperties\n ref?: Ref<HTMLInputElement>\n}\n\n/** The leading number of the displayed text, whatever the format put around it. */\nconst NUMBER_PREFIX = /^\\s*-?[\\d.,]*/\n\n/**\n * The text field of a `NumberInput`, and the only place the value can be typed.\n *\n * While the user types, their own text stands rather than `format(value)`, so\n * that a half-finished entry is not rewritten under the caret.\n */\nexport function InputField({\n selectOnFocus = 'none',\n blurOnEnter = true,\n className,\n style,\n ref,\n onFocus,\n onBlur,\n onKeyDown,\n ...props\n}: NumberInputFieldProps &\n Omit<\n ComponentPropsWithoutRef<'input'>,\n keyof NumberInputFieldProps | 'type' | 'value' | 'defaultValue'\n >) {\n const {\n value,\n min,\n max,\n step,\n disabled,\n readonly,\n keyboard,\n text,\n outOfRange,\n setDraft,\n commitDraft,\n nudge,\n inputRef,\n } = useNumberInputContext()\n\n const composedRef = useComposedRefs<HTMLInputElement>(ref, inputRef)\n\n return (\n <input\n ref={composedRef}\n className={clsx('tremolo-number-input-field', className)}\n // Not type=\"number\": that brings native spinners and a value the browser\n // parses itself, neither of which survives a unit suffix.\n type=\"text\"\n inputMode=\"decimal\"\n role=\"spinbutton\"\n value={text}\n readOnly={readonly}\n aria-disabled={disabled}\n aria-readonly={readonly}\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuetext={text}\n step={step}\n data-out-of-range={outOfRange}\n style={style}\n onChange={(event) => setDraft(event.currentTarget.value)}\n onFocus={(event) => {\n const input = event.currentTarget\n if (selectOnFocus == 'all') {\n input.setSelectionRange(0, input.value.length)\n } else if (selectOnFocus == 'number') {\n input.setSelectionRange(\n 0,\n input.value.match(NUMBER_PREFIX)?.[0].length ?? 0,\n )\n }\n onFocus?.(event)\n }}\n onBlur={(event) => {\n commitDraft()\n onBlur?.(event)\n }}\n onKeyDown={(event) => {\n const key = event.key\n if (key == 'Enter') {\n commitDraft()\n if (blurOnEnter) event.currentTarget.blur()\n } else if (\n keyboard &&\n !readonly &&\n (key == 'ArrowUp' || key == 'ArrowDown')\n ) {\n event.preventDefault()\n nudge(key == 'ArrowUp' ? 1 : -1, keyboard)\n }\n onKeyDown?.(event)\n }}\n {...props}\n />\n )\n}\n","import { useEffect, useState } from 'react'\n\nimport { createDrag } from '@tremolo-ui/dom'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\ninterface UseDragProps {\n /**\n * Threshold at which the onDrag event fires.\n * Prevents onDrag events from firing, for example, when double-clicking.\n */\n threshold?: number\n\n /** CSS cursor to show while dragging. Applied to the element itself. */\n cursor?: string\n\n onDrag?: (x: number, y: number, deltaX: number, deltaY: number) => void\n onDragStart?: () => void\n onDragEnd?: () => void\n}\n\n/**\n * Track a pointer drag on an element.\n *\n * @returns a ref callback to attach to the element being dragged\n */\nexport function useDrag<T extends Element>({\n threshold = 1,\n cursor,\n onDrag,\n onDragStart,\n onDragEnd,\n}: UseDragProps): (node: T | null) => void {\n const dragHandler = useCallbackRef(onDrag)\n const dragStartHandler = useCallbackRef(onDragStart)\n const dragEndHandler = useCallbackRef(onDragEnd)\n\n // The node is held in state rather than bound in the ref callback itself, so\n // that re-attaching the ref with the same node does not restart the drag.\n // React re-attaches on every render when the caller passes an inline ref.\n const [node, setNode] = useState<T | null>(null)\n\n useEffect(() => {\n if (!node) return\n\n const instance = createDrag(node, {\n threshold,\n cursor,\n onDragStart: () => dragStartHandler(),\n onDrag: ({ x, y, deltaX, deltaY }) => dragHandler(x, y, deltaX, deltaY),\n onDragEnd: () => dragEndHandler(),\n })\n\n return () => instance.destroy()\n }, [node, threshold, cursor, dragHandler, dragStartHandler, dragEndHandler])\n\n return setNode\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n CSSProperties,\n ReactNode,\n Ref,\n useMemo,\n useRef,\n} from 'react'\n\nimport { applyDelta } from '@tremolo-ui/functions'\n\nimport { useDrag } from '../../hooks/useDrag'\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { StepperProvider, useNumberInputContext } from './context'\n\nexport interface StepperProps {\n className?: string\n style?: CSSProperties\n /** `<NumberInput.IncrementStepper />` and `<NumberInput.DecrementStepper />` go here. */\n children?: ReactNode\n ref?: Ref<HTMLDivElement>\n}\n\n/**\n * The area the steppers sit in, and a drag handle in its own right: dragging it\n * up and down moves the value one `step` every `drag` pixels.\n *\n * The drag lives here rather than on `InputField` because `createDrag` turns\n * off text selection on whatever element it is attached to.\n */\nexport function Stepper({\n className,\n style,\n children,\n ref,\n ...props\n}: StepperProps & Omit<ComponentPropsWithoutRef<'div'>, keyof StepperProps>) {\n const { value, step, readonly, drag, range, changeValue } =\n useNumberInputContext()\n\n /**\n * Set once the drag has actually moved the value, so that the press-and-hold\n * repeat of a stepper stands down and leaves the value to the drag. A ref,\n * because it is read from inside the repeat rather than rendered.\n */\n const draggingRef = useRef(false)\n /**\n * Where the drag started, taken on the first move rather than on pointer\n * down: the steppers act on pointer down, so by then the value may already\n * have been nudged once, and the drag should carry on from there.\n */\n const originRef = useRef<{ y: number; value: number } | null>(null)\n\n const dragRefCallback = useDrag<HTMLDivElement>({\n threshold: 1,\n cursor: readonly ? undefined : 'ns-resize',\n onDragStart: () => {\n originRef.current = null\n draggingRef.current = false\n },\n onDrag: (_x, y) => {\n if (readonly || drag == null) return\n if (!originRef.current) {\n originRef.current = { y, value }\n return\n }\n // Dragging up raises the value, as on a knob.\n const steps = Math.round(-(y - originRef.current.y) / drag)\n if (steps == 0) return\n draggingRef.current = true\n // The same pipeline the wheel and the arrow keys use. Counting from where\n // the drag started keeps it from accumulating a rounding error.\n changeValue(\n applyDelta(originRef.current.value, steps, ['raw', step], range),\n )\n },\n onDragEnd: () => {\n draggingRef.current = false\n },\n })\n\n const composedRef = useComposedRefs<HTMLDivElement>(\n ref,\n drag != null && !readonly ? dragRefCallback : undefined,\n )\n\n const context = useMemo(() => ({ draggingRef }), [])\n\n return (\n <StepperProvider value={context}>\n <div\n ref={composedRef}\n className={clsx('tremolo-number-input-stepper', className)}\n style={style}\n {...props}\n >\n {children}\n </div>\n </StepperProvider>\n )\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport {\n applyDelta,\n clamp,\n formatValue,\n InputEventOption,\n linearScale,\n parseValue,\n type Scale,\n type Units,\n type ValueRange,\n} from '@tremolo-ui/functions'\n\nimport { useWheel } from '../../hooks/useWheel'\n\nimport { NumberInputProvider } from './context'\nimport { DecrementStepper } from './DecrementStepper'\nimport { IncrementStepper } from './IncrementStepper'\nimport { InputField } from './InputField'\nimport { Stepper } from './Stepper'\n\nexport interface NumberInputProps {\n /**\n * The value. What the input shows is `format(value)`, except while the user\n * is typing, when their own text stands until it is committed.\n */\n value: number\n\n min?: number\n max?: number\n step?: number\n /**\n * How the value is distributed across the travel of a drag or a\n * `'normalized'` wheel / keyboard nudge.\n *\n * @default linearScale\n */\n scale?: Scale\n\n /**\n * Unit to display the value in, or a list to pick from by magnitude.\n * Builds the default `format` and `parse`.\n *\n * @example\n * units='Hz'\n * units={[['Hz', 1], ['kHz', 1000]]}\n * units={[['ms', 1], ['s', 1000]]}\n */\n units?: string | Units\n /**\n * Digits after the decimal point, for the default `format`.\n *\n * @example\n * // units={[['Hz', 1], ['kHz', 1000]]} digit={2}\n * // 100 -> 100.00Hz, 1600 -> 1.60kHz\n */\n digit?: number\n /** Render the value as text. Takes precedence over `units` / `digit`. */\n format?: (value: number) => string\n /** Read a value back out of the text. Takes precedence over `units`. */\n parse?: (text: string) => number\n\n /**\n * Keep the value within `min` and `max` when it is committed or stepped.\n * Typing is never clamped, so that a value can be entered digit by digit.\n * @default true\n */\n clampValue?: boolean\n\n /**\n * Wheel control option. Only applies while the focus is inside, so that\n * scrolling past the input does not change it.\n * If null, no event will be triggered\n */\n wheel?: InputEventOption | null\n /**\n * keyboard control option\n * If null, no event will be triggered\n */\n keyboard?: InputEventOption | null\n /**\n * Pixels of vertical drag on `Stepper` that move the value by one `step`.\n * If null, no event will be triggered\n * @default 1\n */\n drag?: number | null\n\n /**\n * Only the appearance will change.\n * Please consider using with readonly.\n * aria-disabled property is also applied.\n */\n disabled?: boolean\n /**\n * Make the value unchangeable.\n * aria-readonly property is also applied.\n */\n readonly?: boolean\n\n className?: string\n style?: CSSProperties\n onChange?: (value: number) => void\n\n /**\n * The input renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <NumberInput.Root value={value} min={0} max={100} onChange={setValue}>\n * <NumberInput.InputField />\n * <NumberInput.Stepper>\n * <NumberInput.IncrementStepper />\n * <NumberInput.DecrementStepper />\n * </NumberInput.Stepper>\n * </NumberInput.Root>\n */\n children: ReactNode\n}\n\nexport interface NumberInputMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = NumberInputProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof NumberInputProps>\n\nexport const Root = forwardRef<NumberInputMethods, Props>(\n (\n {\n value,\n min,\n max,\n step = 1,\n scale = linearScale,\n units,\n digit,\n format: formatProp,\n parse: parseProp,\n clampValue = true,\n wheel = ['raw', 1],\n keyboard = ['raw', 1],\n drag = 1,\n disabled = false,\n readonly = false,\n className,\n style,\n onChange,\n children,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n // --- state and ref ---\n const inputRef = useRef<HTMLInputElement>(null)\n /**\n * The text being typed. The only state here: it is not a copy of `value`,\n * but the half-finished entry that has no value to be derived from yet.\n */\n const [draft, setDraft] = useState<string | null>(null)\n\n // --- interpret props ---\n const format = useCallback(\n (v: number) =>\n formatProp ? formatProp(v) : formatValue(v, units, digit),\n [formatProp, units, digit],\n )\n const parse = useCallback(\n (t: string) => (parseProp ? parseProp(t) : parseValue(t, units)),\n [parseProp, units],\n )\n\n // An unbounded end, and a range the caller opted out of enforcing, both\n // become the widest range the value pipeline can express.\n const range: ValueRange = useMemo(\n () => ({\n min: (clampValue ? min : undefined) ?? Number.MIN_SAFE_INTEGER,\n max: (clampValue ? max : undefined) ?? Number.MAX_SAFE_INTEGER,\n step,\n scale,\n }),\n [clampValue, min, max, step, scale],\n )\n\n const text = draft ?? format(value)\n const editing = draft != null\n const outOfRange =\n !editing &&\n ((min != undefined && value < min) || (max != undefined && value > max))\n\n // --- internal functions ---\n const handleDraft = useCallback(\n (next: string) => {\n if (readonly) return\n setDraft(next)\n // Deliberately unclamped: clamping here would make \"1500\" impossible\n // to type into an input whose max is 100.\n const parsed = parse(next)\n if (Number.isFinite(parsed)) onChange?.(parsed)\n },\n [readonly, parse, onChange],\n )\n\n const changeValue = useCallback(\n (next: number) => {\n if (readonly) return\n setDraft(null)\n if (next != value) onChange?.(next)\n },\n [readonly, value, onChange],\n )\n\n const commitDraft = useCallback(() => {\n if (draft == null || readonly) return\n // `range` is already the widest possible range when clampValue is off.\n changeValue(clamp(parse(draft), range.min, range.max))\n }, [draft, readonly, parse, range, changeValue])\n\n const nudge = useCallback(\n (direction: number, option: InputEventOption) => {\n changeValue(applyDelta(value, direction, option, range))\n },\n [changeValue, value, range],\n )\n\n // --- hooks ---\n const wheelRefCallback = useWheel<HTMLDivElement>(\n (event) => {\n if (!wheel || readonly || event.deltaY == 0) return\n event.preventDefault()\n nudge(-Math.sign(event.deltaY), wheel)\n },\n { requireFocus: true },\n )\n\n const context = useMemo(\n () => ({\n value,\n min,\n max,\n step,\n scale,\n disabled,\n readonly,\n clampValue,\n range,\n keyboard,\n text,\n editing,\n outOfRange,\n atMin: clampValue && min != undefined && value <= min,\n atMax: clampValue && max != undefined && value >= max,\n drag,\n format,\n parse,\n setDraft: handleDraft,\n commitDraft,\n changeValue,\n nudge,\n inputRef,\n }),\n [\n value,\n min,\n max,\n step,\n scale,\n disabled,\n readonly,\n clampValue,\n range,\n keyboard,\n text,\n editing,\n outOfRange,\n drag,\n format,\n parse,\n handleDraft,\n commitDraft,\n changeValue,\n nudge,\n ],\n )\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n inputRef.current?.focus()\n },\n blur() {\n inputRef.current?.blur()\n },\n }\n }, [])\n\n return (\n <NumberInputProvider value={context}>\n <div\n ref={wheelRefCallback}\n className={clsx('tremolo-number-input', className)}\n aria-disabled={disabled}\n aria-readonly={readonly}\n style={style}\n {...props}\n >\n {children}\n </div>\n </NumberInputProvider>\n )\n },\n)\n\n/**\n * Input with some useful functions for entering numerical values.\n */\nexport const NumberInput = {\n Root,\n InputField,\n Stepper,\n IncrementStepper,\n DecrementStepper,\n}\n\nexport { useNumberInputContext } from './context'\nexport { type NumberInputFieldProps } from './InputField'\nexport { type StepperProps } from './Stepper'\nexport { type IncrementStepperProps } from './IncrementStepper'\nexport { type DecrementStepperProps } from './DecrementStepper'\n","export type KeyboardShortcuts = {\n /**\n * Keys laid out from `noteRange.first`, one entry per semitone.\n *\n * An empty string leaves that note without a shortcut: `KeyboardEvent.key` is\n * never empty, so the entry can never match. Use it to skip the black keys\n * (see {@link SHORTCUTS.HOME_ROW_NATURAL}) and keep the remaining entries\n * lined up with the notes.\n */\n keys: string[]\n}\n\n/**\n * Ready-made keyboard layouts. Both assume `noteRange.first` is a C.\n */\nexport const SHORTCUTS = {\n /** Every semitone from C, over the two rows of a QWERTY keyboard. */\n HOME_ROW: {\n keys: [\n 'a',\n 'w',\n 's',\n 'e',\n 'd',\n 'f',\n 't',\n 'g',\n 'y',\n 'h',\n 'u',\n 'j',\n 'k',\n 'o',\n 'l',\n 'p',\n ';',\n ],\n },\n /** The white keys only, on the home row. Black keys have no shortcut. */\n HOME_ROW_NATURAL: {\n keys: [\n 'a',\n '',\n 's',\n '',\n 'd',\n 'f',\n '',\n 'g',\n '',\n 'h',\n '',\n 'j',\n 'k',\n '',\n 'l',\n '',\n ';',\n ],\n },\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport { createPianoInput, type PianoInputInstance } from '@tremolo-ui/dom'\nimport {\n blackKeyWidth,\n getNoteRangeArray,\n isWhiteKey,\n noteKey,\n notePosition,\n pianoWidth,\n type NoteRange,\n type PianoLayout,\n} from '@tremolo-ui/functions'\n\nimport { useEventListener } from '../../hooks/useEventListener'\n\nimport { KeyboardShortcuts } from './keyboardShortcuts'\n\n/**\n * `style` that also takes CSS custom properties, which is how a key's colours\n * are set: see `index.css` for the ones each key type reads.\n */\nexport type CSSVariables = Record<`--${string}`, string | number | undefined>\n\n/**\n * What {@link PianoProps.keyProps} may return for one key.\n *\n * `data-*` attributes are spelled out because TypeScript only allows them on\n * JSX syntax, not on an object type, and selecting on one is the usual way to\n * mark a key out.\n */\nexport type KeyAttributes = Omit<ComponentPropsWithoutRef<'div'>, 'style'> & {\n style?: CSSProperties & CSSVariables\n} & Record<`data-${string}`, string | number | boolean | undefined>\n\n/** What a key is, when {@link PianoProps.label} 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 {@link PianoProps.midiMax} and cannot sound. */\n disabled: boolean\n}\n\nexport interface PianoProps {\n noteRange: NoteRange\n\n /**\n * Let a pointer slide from one key to the next while it is down.\n *\n * @default true\n */\n glissando?: boolean\n\n /**\n * Highest note that can sound. Keys above it are drawn `aria-disabled`.\n *\n * @default 127\n */\n midiMax?: number\n\n keyboardShortcuts?: KeyboardShortcuts\n\n /**\n * Fill the parent element, deriving the width of a white key from it.\n * {@link PianoProps.whiteKeyWidth} is ignored.\n *\n * @default false\n */\n fill?: boolean\n\n /** @default 40 */\n whiteKeyWidth?: number\n /**\n * Space between two white keys.\n * @default 1\n */\n keyGap?: number\n /**\n * Width of a black key, as a fraction of {@link PianoProps.whiteKeyWidth}.\n * @default 0.65\n */\n blackKeyWidthRatio?: number\n /**\n * Height of a black key, as a fraction of the height of the keyboard.\n * @default 0.6\n */\n blackKeyHeightRatio?: number\n\n /** @default `fill ? '100%' : 160` */\n height?: number | string\n\n style?: CSSProperties & CSSVariables\n\n /**\n * What to draw inside a key. `''`, `null` and `undefined` leave it bare, so\n * a layout with gaps — {@link SHORTCUTS.HOME_ROW_NATURAL}, say — needs no\n * special casing.\n */\n label?: (note: number, state: KeyState) => ReactNode\n\n /**\n * Extra props for one key, by note: a class, a style, a `data-*` attribute\n * to select on.\n *\n * The geometry of the key (`left`, `width`, `height`) is applied after the\n * returned `style` and cannot be overridden, so a key cannot be drawn\n * somewhere other than where it responds.\n *\n * @example highlight the notes of a scale\n * ```tsx\n * keyProps={(note) => ({ 'data-in-scale': inScale(note, root, 'major') })}\n * ```\n */\n keyProps?: (note: number, state: KeyState) => KeyAttributes\n\n onPlayNote?: (note: number, velocity?: number) => void\n onStopNote?: (note: number) => void\n}\n\nexport interface PianoMethods {\n playNote: (note: number, velocity?: number) => void\n stopNote: (note: number) => void\n}\n\ntype Props = PianoProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PianoProps>\n\nexport const Root = forwardRef<PianoMethods, Props>(function Root(\n {\n noteRange,\n glissando = true,\n midiMax = 127,\n keyboardShortcuts,\n fill = false,\n whiteKeyWidth = 40,\n keyGap = 1,\n blackKeyWidthRatio = 0.65,\n blackKeyHeightRatio = 0.6,\n height = fill ? '100%' : 160,\n style,\n className,\n label,\n keyProps,\n onPlayNote,\n onStopNote,\n ...props\n },\n forwardedRef,\n) {\n // See useDrag for why the node is held in state rather than a ref: an inline\n // ref would be re-attached on every render and tear the instance down.\n const [node, setNode] = useState<HTMLDivElement | null>(null)\n const [activeNotes, setActiveNotes] = useState<number[]>([])\n /** Set while `fill` is on, measured from the parent. */\n const [filledKeyWidth, setFilledKeyWidth] = useState(whiteKeyWidth)\n\n const notes = useMemo(() => getNoteRangeArray(noteRange), [noteRange])\n const whiteKeyCount = useMemo(() => notes.filter(isWhiteKey).length, [notes])\n\n const layout: PianoLayout = useMemo(\n () => ({\n noteRange,\n whiteKeyWidth: fill ? filledKeyWidth : whiteKeyWidth,\n keyGap,\n blackKeyWidthRatio,\n blackKeyHeightRatio,\n }),\n [\n noteRange,\n fill,\n filledKeyWidth,\n whiteKeyWidth,\n keyGap,\n blackKeyWidthRatio,\n blackKeyHeightRatio,\n ],\n )\n\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale handler is replaced within the same commit.\n const latest = useRef({ layout, glissando, midiMax, onPlayNote, onStopNote })\n const instanceRef = useRef<PianoInputInstance | null>(null)\n\n useEffect(() => {\n if (!node) return\n\n const instance = createPianoInput(node, {\n layout: latest.current.layout,\n glissando: latest.current.glissando,\n midiMax: latest.current.midiMax,\n onPlayNote: (note, velocity) =>\n latest.current.onPlayNote?.(note, velocity),\n onStopNote: (note) => latest.current.onStopNote?.(note),\n onActiveNotesChange: setActiveNotes,\n })\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n // Only the element decides how the instance is wired. Everything else is\n // pushed with update() below, so that changing the layout mid-drag — the\n // parent being resized under `fill`, say — does not abort the drag.\n }, [node])\n\n // Runs after every render.\n useEffect(() => {\n latest.current = { layout, glissando, midiMax, onPlayNote, onStopNote }\n instanceRef.current?.update({ layout, glissando, midiMax })\n })\n\n useEffect(() => {\n if (!fill || !node) return\n const parent = node.parentElement\n if (!parent) throw new Error(\"doesn't have a parent element.\")\n\n const resizeObserver = new ResizeObserver(() => {\n setFilledKeyWidth(node.clientWidth / whiteKeyCount - keyGap)\n })\n resizeObserver.observe(parent)\n return () => resizeObserver.disconnect()\n }, [fill, node, whiteKeyCount, keyGap])\n\n /** The note a shortcut key plays, or null when it has none. */\n function shortcutNote(key: string) {\n if (!keyboardShortcuts || key === '') return null\n const index = keyboardShortcuts.keys.indexOf(key)\n return index === -1 ? null : noteRange.first + index\n }\n\n useEventListener(globalThis.window, 'keydown', (e) => {\n if (e.repeat) return\n const note = shortcutNote(e.key)\n if (note !== null) instanceRef.current?.noteOn(note, { source: 'keyboard' })\n })\n\n useEventListener(globalThis.window, 'keyup', (e) => {\n const note = shortcutNote(e.key)\n if (note !== null)\n instanceRef.current?.noteOff(note, { source: 'keyboard' })\n })\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n playNote: (note, velocity) =>\n instanceRef.current?.noteOn(note, { source: 'api', velocity }),\n stopNote: (note) => instanceRef.current?.noteOff(note, { source: 'api' }),\n }),\n [],\n )\n\n return (\n <div\n ref={setNode}\n className={clsx('tremolo-piano', className)}\n style={{\n width: fill ? '100%' : pianoWidth(layout),\n height,\n ...style,\n }}\n {...props}\n >\n {notes.map((note, index) => {\n const keyType = isWhiteKey(note) ? 'white' : 'black'\n const state: KeyState = {\n index,\n keyType,\n active: activeNotes.includes(note),\n disabled: note > midiMax,\n }\n\n const {\n className: keyClassName,\n style: keyStyle,\n ...rest\n } = keyProps?.(note, state) ?? {}\n\n const content = label?.(note, state)\n\n return (\n <div\n key={note}\n className={clsx(`tremolo-piano-${keyType}-key`, keyClassName)}\n data-note={note}\n data-note-key={noteKey(note)}\n data-active={state.active}\n aria-disabled={state.disabled}\n {...rest}\n style={{\n ...keyStyle,\n left: notePosition(note, layout),\n width:\n keyType === 'white'\n ? layout.whiteKeyWidth\n : blackKeyWidth(layout),\n height:\n keyType === 'white' ? '100%' : `${blackKeyHeightRatio * 100}%`,\n }}\n >\n {content !== '' && content !== null && content !== undefined && (\n <div className=\"tremolo-piano-key-label-wrapper\">\n <div className=\"tremolo-piano-key-label\">{content}</div>\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n})\n\n/**\n * Customizable piano component.\n */\nexport const Piano = { Root }\n\nexport { type KeyboardShortcuts, SHORTCUTS } from './keyboardShortcuts'\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, ReactNode } from 'react'\n\nexport interface PointsEditorBackgroundProps {\n /** Whatever the points are placed over: a graph, a canvas, an image. */\n children?: ReactNode\n}\n\nexport function Background({\n className,\n children,\n ...props\n}: PointsEditorBackgroundProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorBackgroundProps>) {\n return (\n <div\n className={clsx('tremolo-points-editor-background', className)}\n {...props}\n >\n {children}\n </div>\n )\n}\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type { InputEventOption } from '@tremolo-ui/functions'\n\nimport { Cursor } from '../_util'\n\nexport type PointsEditorContextValue = {\n disabled: boolean\n readonly: boolean\n /** Inherited by every `Point`; `null` turns the wheel off. */\n wheel: InputEventOption | null\n /** Inherited by every `Point`; `null` turns the keyboard off. */\n keyboard: InputEventOption | null\n externalStyles: {\n userSelectNone?: boolean\n cursor?: Cursor\n }\n\n /**\n * `Container` registers its element here; `Point` normalizes the pointer\n * against it, so a point is placed by its position within the container.\n */\n containerRef: RefObject<HTMLDivElement | null>\n}\n\nconst PointsEditorContext = createContext<PointsEditorContextValue | null>(null)\n\nexport const PointsEditorProvider = PointsEditorContext.Provider\n\n/**\n * The settings `Root` was given, for the subcomponents to read. There is no\n * state to keep in sync: a point's value belongs to the `Point` that draws it.\n */\nexport function usePointsEditorContext(): PointsEditorContextValue\nexport function usePointsEditorContext<T>(\n selector: (state: PointsEditorContextValue) => T,\n): T\nexport function usePointsEditorContext<T>(\n selector?: (state: PointsEditorContextValue) => T,\n) {\n const context = useContext(PointsEditorContext)\n if (!context)\n throw new Error('Missing PointsEditorContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, ReactNode, Ref } from 'react'\n\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { usePointsEditorContext } from './context'\n\nexport interface PointsEditorContainerProps {\n /** `<PointsEditor.Point />` goes here. */\n children?: ReactNode\n ref?: Ref<HTMLDivElement>\n}\n\nexport function Container({\n children,\n className,\n ref,\n ...props\n}: PointsEditorContainerProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorContainerProps>) {\n const containerRef = usePointsEditorContext((s) => s.containerRef)\n\n // The container is what the pointer position is normalized against, so the\n // context ref is composed with any ref the caller passed.\n const composedRef = useComposedRefs<HTMLDivElement>(ref, containerRef)\n\n return (\n <div\n ref={composedRef}\n className={clsx('tremolo-points-editor-container', className)}\n {...props}\n >\n {children}\n </div>\n )\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, useCallback, useState } from 'react'\n\nimport { applyDelta, clamp, InputEventOption } from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport { addUserSelectNone, removeUserSelectNone } from '../_util'\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { usePointsEditorContext } from './context'\n\nexport type PointBaseType = { x: number; y: number }\n\nexport function clampPoint(\n point: PointBaseType,\n min?: Partial<PointBaseType>,\n max?: Partial<PointBaseType>,\n) {\n const { x, y } = point\n const newX = clamp(x, min?.x ?? 0, max?.x ?? 1)\n const newY = clamp(y, min?.y ?? 0, max?.y ?? 1)\n return { x: newX, y: newY }\n}\n\nexport interface PointProps<T extends PointBaseType> {\n value: T\n min?: Partial<PointBaseType>\n max?: Partial<PointBaseType>\n\n size?: number | string\n width?: number | string\n height?: number | string\n color?: string\n\n /** Overrides the `disabled` of `PointsEditor.Root`. */\n disabled?: boolean\n /** Overrides the `readonly` of `PointsEditor.Root`. */\n readonly?: boolean\n\n /** Overrides the `wheel` of `PointsEditor.Root`. */\n wheel?: InputEventOption | null\n /** Overrides the `keyboard` of `PointsEditor.Root`. */\n keyboard?: InputEventOption | null\n\n onChange?: (value: PointBaseType) => void\n onDragStart?: (value: PointBaseType) => void\n onDragEnd?: (value: PointBaseType) => void\n}\n\n/**\n * A point is placed by its position within the container, so its value is a\n * position: 0..1 on each axis, with y growing downwards.\n */\nconst AXIS = { min: 0, max: 1 }\n\nexport function Point<T extends PointBaseType>({\n value,\n min,\n max,\n size,\n width = 16,\n height = 16,\n color,\n\n disabled: _disabled,\n readonly: _readonly,\n wheel: _wheel,\n keyboard: _keyboard,\n\n onChange,\n onDragStart,\n onDragEnd,\n\n className,\n style,\n onPointerDown,\n onKeyDown,\n ...props\n}: PointProps<T> & Omit<ComponentPropsWithoutRef<'div'>, keyof PointProps<T>>) {\n const {\n containerRef,\n externalStyles,\n disabled: rootDisabled,\n readonly: rootReadonly,\n wheel: rootWheel,\n keyboard: rootKeyboard,\n } = usePointsEditorContext()\n\n const disabled = _disabled ?? rootDisabled\n const readonly = _readonly ?? rootReadonly\n // `null` means \"no event\" and has to survive the fallback, so `??` is not\n // enough: only an omitted prop inherits from the root.\n const wheel = _wheel === undefined ? rootWheel : _wheel\n const keyboard = _keyboard === undefined ? rootKeyboard : _keyboard\n\n // Compared against the focus below, so the point needs its own element.\n const [element, setElement] = useState<HTMLDivElement | null>(null)\n\n // The value is the position itself: no scaling, and no rounding to a step.\n const { refCallback: dragRefCallback, dragging } =\n useDragValue<HTMLDivElement>({\n axis: AXIS,\n baseElementRef: containerRef,\n cursor: readonly ? undefined : externalStyles.cursor,\n onChange: ([x, y]) => {\n if (readonly) return\n\n onChange?.(clampPoint({ x, y }, min, max))\n },\n onDragStart: ([x, y]) => {\n if (readonly) return\n if (externalStyles.userSelectNone) addUserSelectNone()\n\n onDragStart?.(clampPoint({ x, y }, min, max))\n },\n onDragEnd: ([x, y]) => {\n if (readonly) return\n if (externalStyles.userSelectNone) removeUserSelectNone()\n\n onDragEnd?.(clampPoint({ x, y }, min, max))\n },\n })\n\n const nudge = useCallback(\n (axis: 'x' | 'y', direction: number, option: InputEventOption) => {\n const next = applyDelta(value[axis], direction, option, AXIS)\n onChange?.(clampPoint({ ...value, [axis]: next }, min, max))\n },\n [value, min, max, onChange],\n )\n\n // The listener sits on the container rather than on the point: a wheel event\n // only reaches what the cursor is over, and a point is a 16px target. Every\n // point sees the event and the focused one acts, so the wheel works anywhere\n // over the editor, the way it does for Slider and XYPad.\n //\n // The focus test is an identity check, not `contains`: with `contains` every\n // point would match the container's focus and they would all move at once.\n useWheel(\n (event) => {\n if (!onChange || readonly || !wheel) return\n if (!element || element.ownerDocument.activeElement !== element) return\n event.preventDefault()\n // Scrolling up moves the point towards y = 0; shift switches to x.\n const axis = event.shiftKey ? 'x' : 'y'\n const direction = event.deltaY < 0 ? -1 : 1\n nudge(axis, direction, wheel)\n },\n { target: containerRef },\n )\n\n const refCallback = useComposedRefs<HTMLDivElement>(\n dragRefCallback,\n setElement,\n )\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!onChange || readonly || !keyboard) return\n const key = event.key\n if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {\n event.preventDefault()\n // y grows downwards, so ArrowUp moves the point towards 0.\n const axis = key === 'ArrowRight' || key === 'ArrowLeft' ? 'x' : 'y'\n const direction = key === 'ArrowLeft' || key === 'ArrowUp' ? -1 : 1\n nudge(axis, direction, keyboard)\n }\n }\n\n const colors: Record<string, string | undefined> = {\n '--color': color,\n }\n\n return (\n // The point is a drag handle rather than a control of a known kind: it has\n // no single value to announce, so there is no role that fits it.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n ref={refCallback}\n className={clsx('tremolo-points-editor-point', className)}\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n aria-disabled={disabled}\n aria-readonly={readonly}\n data-dragging={dragging}\n style={{\n ...colors,\n width: size ?? width,\n height: size ?? height,\n left: `${value.x * 100}%`,\n top: `${value.y * 100}%`,\n ...style,\n }}\n onPointerDown={onPointerDown}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n {...props}\n />\n )\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n forwardRef,\n ReactNode,\n useMemo,\n useRef,\n} from 'react'\n\nimport { InputEventOption } from '@tremolo-ui/functions'\n\nimport { Cursor } from '../_util'\n\nimport { Background } from './Background'\nimport { Container } from './Container'\nimport { PointsEditorProvider } from './context'\nimport { Point } from './Point'\n\n/*\nTODO:\n\n- 複数選択\n- modifier\n- grid\n*/\n\n/**\n * A point moves over 0..1 in both axes, so a nudge of 0.01 crosses the editor\n * in a hundred steps whatever its pixel size.\n */\nconst DEFAULT_INPUT_EVENT_OPTION: InputEventOption = ['normalized', 0.01]\n\nexport interface PointsEditorProps {\n width?: number | string\n height?: number | string\n\n /**\n * Only the appearance will change.\n * Please consider using with readonly.\n * aria-disabled property is also applied.\n */\n disabled?: boolean\n /**\n * Make the points unmovable.\n * aria-readonly property is also applied.\n */\n readonly?: boolean\n\n externalStyles?: {\n userSelectNone?: boolean\n cursor?: Cursor\n }\n\n /**\n * wheel control option for every `Point`. Shift selects the x axis.\n * If null, no event will be triggered\n *\n * A `Point` can override it with a `wheel` of its own.\n */\n wheel?: InputEventOption | null\n /**\n * keyboard control option for every `Point`, on the arrow keys.\n * If null, no event will be triggered\n *\n * A `Point` can override it with a `keyboard` of its own.\n */\n keyboard?: InputEventOption | null\n\n /**\n * The editor renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <PointsEditor.Root>\n * <PointsEditor.Background>\n * <svg viewBox=\"0 0 200 100\">...</svg>\n * </PointsEditor.Background>\n * <PointsEditor.Container>\n * {points.map((point, i) => (\n * <PointsEditor.Point key={i} value={point} onChange={...} />\n * ))}\n * </PointsEditor.Container>\n * </PointsEditor.Root>\n */\n children: ReactNode\n}\n\ntype Props = PointsEditorProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorProps>\n\nexport const Root = forwardRef<HTMLDivElement, Props>(\n (\n {\n width = 200,\n height = 100,\n disabled = false,\n readonly = false,\n wheel = DEFAULT_INPUT_EVENT_OPTION,\n keyboard = DEFAULT_INPUT_EVENT_OPTION,\n externalStyles,\n style,\n className,\n children,\n ...props\n },\n forwardedRef,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Picked apart so that the memo below depends on values rather than on the\n // object literal a caller writes inline, which is new on every render.\n const { userSelectNone = true, cursor = 'grabbing' } = externalStyles ?? {}\n\n const context = useMemo(\n () => ({\n disabled,\n readonly,\n wheel,\n keyboard,\n externalStyles: { userSelectNone, cursor },\n containerRef,\n }),\n [disabled, readonly, wheel, keyboard, userSelectNone, cursor],\n )\n\n return (\n <PointsEditorProvider value={context}>\n <div\n ref={forwardedRef}\n className={clsx('tremolo-points-editor', className)}\n aria-disabled={disabled}\n aria-readonly={readonly}\n style={{\n width,\n height,\n ...style,\n }}\n {...props}\n >\n {children}\n </div>\n </PointsEditorProvider>\n )\n },\n)\n\n/**\n * Multiple Point Controller\n */\nexport const PointsEditor = {\n Root,\n Background,\n Container,\n Point,\n}\n\nexport {\n usePointsEditorContext,\n type PointsEditorContextValue,\n} from './context'\nexport { type PointsEditorBackgroundProps } from './Background'\nexport { type PointsEditorContainerProps } from './Container'\nexport { clampPoint, type PointBaseType, type PointProps } from './Point'\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type { Scale } from '@tremolo-ui/functions'\n\nimport type { SliderThumbMethods } from './Thumb'\n\nexport type SliderContextValue = {\n value: number\n min: number\n max: number\n step: number\n /** How the value is distributed across the travel. */\n scale: Scale\n vertical: boolean\n reverse: boolean\n disabled: boolean\n readonly: boolean\n\n /**\n * Position of the thumb, 0-100, already accounting for the display direction\n * implied by `vertical` and `reverse`.\n */\n percent: number\n\n /** `Track` registers its element here; `Root` normalizes the pointer against it. */\n trackRef: RefObject<HTMLDivElement | null>\n /** `Thumb` registers itself here; `Root` focuses it when a drag starts. */\n thumbRef: RefObject<SliderThumbMethods | null>\n}\n\nconst SliderContext = createContext<SliderContextValue | null>(null)\n\nexport const SliderProvider = SliderContext.Provider\n\n/**\n * Everything here is derived during render, so there is no state to keep in\n * sync: `value` comes from the props of `Root` and the rest follows from it.\n */\nexport function useSliderContext(): SliderContextValue\nexport function useSliderContext<T>(\n selector: (state: SliderContextValue) => T,\n): T\nexport function useSliderContext<T>(\n selector?: (state: SliderContextValue) => T,\n) {\n const context = useContext(SliderContext)\n if (!context) throw new Error('Missing SliderContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, CSSProperties, useCallback } from 'react'\n\nimport { toFixed, xor } from '@tremolo-ui/functions'\n\nimport { useSliderContext } from './context'\nimport { MarksType } from './type'\n\nexport interface MarksOptionProps {\n // required\n value: number\n\n // optional\n type?: MarksType\n /** Display text instead of value. */\n label?: string\n /** mark thickness */\n thickness?: number | string\n /** mark length */\n length?: number | string\n /** Gap between mark and label. */\n gap?: number | string\n labelWidth?: number | string\n classes?: {\n mark?: string\n label?: string\n }\n styles?: {\n mark?: CSSProperties\n label?: CSSProperties\n }\n}\n\nexport function MarksOption({\n value,\n type = 'mark-number',\n label,\n thickness = 1,\n length = '0.5rem',\n gap = 2,\n labelWidth,\n classes,\n styles,\n className,\n style,\n ...props\n}: MarksOptionProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof MarksOptionProps>) {\n const min = useSliderContext((s) => s.min)\n const max = useSliderContext((s) => s.max)\n const scale = useSliderContext((s) => s.scale)\n const vertical = useSliderContext((s) => s.vertical)\n const reverse = useSliderContext((s) => s.reverse)\n\n const calcPercent = useCallback(\n (value: number) => {\n // The marks have to sit on the same curve the thumb runs along.\n const percent = scale.normalize(value, min, max) * 100\n return toFixed(xor(vertical, reverse) ? 100 - percent : percent)\n },\n [vertical, reverse, max, min, scale],\n )\n\n return (\n <div\n className={clsx('tremolo-slider-marks-option', className)}\n style={{\n left: !vertical ? `${calcPercent(value)}%` : undefined,\n top: vertical ? `${calcPercent(value)}%` : undefined,\n ...style,\n }}\n data-vertical={vertical}\n {...props}\n >\n {type != 'number' && (\n <div\n className={clsx('tremolo-slider-marks-option-mark', classes?.mark)}\n style={{\n width: !vertical ? thickness : length,\n height: vertical ? thickness : length,\n marginBottom: !vertical ? gap : undefined,\n marginRight: vertical ? gap : undefined,\n ...styles?.mark,\n }}\n data-vertical={vertical}\n ></div>\n )}\n {type != 'mark' && (\n <div\n className={clsx('tremolo-slider-marks-option-label', classes?.label)}\n style={{\n width: labelWidth,\n ...styles?.label,\n }}\n >\n {label || value}\n </div>\n )}\n </div>\n )\n}\n","import { decimalPart, toFixed } from '@tremolo-ui/functions'\n\nexport type MarksType = 'mark' | 'mark-number' | 'number'\nexport type MarksOptions = ['step', MarksType] | [number, MarksType]\n\nexport function generateOptionsList(\n options: MarksOptions,\n min: number,\n max: number,\n step: number,\n) {\n const optionsList: {\n value: number\n type: MarksType\n }[] = []\n const per = options[0] == 'step' ? step : options[0]\n const count = Math.floor(max / per) - Math.ceil(min / per) + 1\n for (let i = 0; i < count; i++) {\n const value = toFixed(\n per * (Math.ceil(min / per) + i),\n decimalPart(per)?.length,\n )\n optionsList.push({ value: value, type: options[1] })\n }\n return optionsList\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, ReactNode } from 'react'\n\nimport { xor } from '@tremolo-ui/functions'\n\nimport { useSliderContext } from './context'\nimport { MarksOption } from './MarksOption'\nimport { generateOptionsList, MarksOptions } from './type'\n\nexport interface MarksProps {\n gap?: number | string\n options?: MarksOptions\n children?: ReactNode\n}\n\nexport function Marks({\n gap = 6,\n options,\n children,\n className,\n style,\n ...props\n}: MarksProps & Omit<ComponentPropsWithoutRef<'div'>, keyof MarksProps>) {\n const min = useSliderContext((s) => s.min)\n const max = useSliderContext((s) => s.max)\n const step = useSliderContext((s) => s.step)\n const vertical = useSliderContext((s) => s.vertical)\n const reverse = useSliderContext((s) => s.reverse)\n\n const optionsList = options\n ? generateOptionsList(options, min, max, step)\n : []\n if (xor(vertical, reverse)) optionsList.reverse()\n\n return (\n <div\n className={clsx('tremolo-slider-marks', className)}\n style={{\n marginLeft: vertical ? gap : undefined,\n marginTop: !vertical ? gap : undefined,\n ...style,\n }}\n {...props}\n >\n {options\n ? optionsList.map(({ value, type }, index) => {\n return <MarksOption key={index} value={value} type={type} />\n })\n : children}\n </div>\n )\n}\n","import clsx from 'clsx'\nimport {\n CSSProperties,\n ReactNode,\n Ref,\n useImperativeHandle,\n useRef,\n} from 'react'\n\nimport { useSliderContext } from './context'\n\nexport interface SliderThumbProps {\n /**\n * Size comes from the `--thumb-size` CSS variable on `Slider.Root`, so that\n * the root can reserve the matching amount of space around the track.\n */\n color?: string\n\n className?: string\n style?: CSSProperties\n children?: ReactNode\n ref?: Ref<SliderThumbMethods>\n}\n\nexport interface SliderThumbMethods {\n focus: () => void\n blur: () => void\n}\n\nexport function Thumb({\n color,\n children,\n className,\n style,\n ref,\n}: SliderThumbProps) {\n const elementRef = useRef<HTMLDivElement>(null)\n const { vertical, disabled, readonly, percent, thumbRef } = useSliderContext()\n\n const methods = () => ({\n focus() {\n elementRef.current?.focus()\n },\n blur() {\n elementRef.current?.blur()\n },\n })\n\n useImperativeHandle(ref, methods, [])\n // Root focuses the thumb when a drag starts, wherever the user placed it.\n\n useImperativeHandle(thumbRef, methods, [])\n\n return (\n <div\n className=\"tremolo-slider-thumb-wrapper\"\n style={{\n top: vertical ? `${percent}%` : '50%',\n left: !vertical ? `${percent}%` : '50%',\n }}\n >\n {children ? (\n children\n ) : (\n // default slider thumb\n <div\n ref={elementRef}\n className={clsx('tremolo-slider-thumb', className)}\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n aria-disabled={disabled}\n aria-readonly={readonly}\n style={{\n ...{ '--color': color },\n ...style,\n }}\n ></div>\n )}\n </div>\n )\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, CSSProperties, ReactNode, Ref } from 'react'\n\nimport { styleHelper, xor } from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { useSliderContext } from './context'\n\nexport const defaultLength = 140\nexport const defaultThickness = 10\n\nexport interface SliderTrackProps {\n length?: number | string\n thickness?: number | string\n\n active?: string\n inactive?: string\n\n defaultStyle?: boolean\n\n className?: string\n style?: CSSProperties\n /** `<Slider.Thumb />` goes here. */\n children?: ReactNode\n ref?: Ref<HTMLDivElement>\n}\n\nexport function Track({\n length = defaultLength,\n thickness = defaultThickness,\n active,\n inactive,\n children,\n className,\n style,\n defaultStyle = true,\n ref,\n ...props\n}: SliderTrackProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderTrackProps>) {\n const { vertical, reverse, disabled, percent, trackRef } = useSliderContext()\n\n // The track is what the pointer position is normalized against, so the\n // context ref is composed with any ref the caller passed.\n const composedRef = useComposedRefs<HTMLDivElement>(ref, trackRef)\n\n const direction = vertical ? 'bottom' : 'right'\n const colors = {\n '--active': active,\n '--inactive': inactive,\n }\n\n return (\n <div\n ref={composedRef}\n className={clsx('tremolo-slider-track', className)}\n aria-disabled={disabled}\n data-vertical={vertical}\n style={\n !defaultStyle\n ? style\n : {\n ...colors,\n background: xor(vertical, reverse)\n ? `linear-gradient(to ${direction}, var(--inactive) ${percent}%, var(--active) ${percent}%)`\n : `linear-gradient(to ${direction}, var(--active) ${percent}%, var(--inactive) ${percent}%)`,\n borderRadius: styleHelper(thickness!, '/', 2),\n width: !vertical ? length : thickness,\n height: vertical ? length : thickness,\n ...style,\n }\n }\n {...props}\n >\n {children}\n </div>\n )\n}\n","import clsx from 'clsx'\nimport React, {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react'\n\nimport type { AxisOptions, XY } from '@tremolo-ui/dom'\nimport {\n applyDelta,\n linearScale,\n toFixed,\n InputEventOption,\n xor,\n type Scale,\n} from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport { addUserSelectNone, Cursor, removeUserSelectNone } from '../_util'\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { SliderProvider } from './context'\nimport { Marks } from './Marks'\nimport { MarksOption } from './MarksOption'\nimport { Thumb, SliderThumbMethods } from './Thumb'\nimport { Track } from './Track'\n\nconst defaultExternalStyles: SliderProps['externalStyles'] = {\n userSelectNone: true,\n cursor: 'pointer',\n}\n\nexport interface SliderProps {\n // required\n value: number\n min: number\n max: number\n\n // optional\n step?: number\n /**\n * How the value is distributed across the travel.\n *\n * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,\n * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or\n * `skewScale(n)` for a value that has to match a JUCE parameter.\n *\n * @default linearScale\n */\n scale?: Scale\n /**\n * slider orientation\n * aria-orientation property is also applied.\n */\n vertical?: boolean\n reverse?: boolean\n\n /** Global style to apply when dragged */\n externalStyles?: {\n userSelectNone?: boolean\n cursor?: Cursor\n }\n /**\n * wheel control option\n * If null, no event will be triggered\n */\n wheel?: InputEventOption | null\n /**\n * keyboard control option\n * If null, no event will be triggered\n */\n keyboard?: InputEventOption | null\n\n /**\n * Only the appearance will change.\n * Please consider using with readonly.\n * aria-disabled property is also applied.\n */\n disabled?: boolean\n /**\n * Make the value unchangeable.\n * aria-readonly property is also applied.\n */\n readonly?: boolean\n className?: string\n style?: CSSProperties\n onChange?: (value: number) => void\n onDragStart?: (value: number) => void\n onDragEnd?: (value: number) => void\n /**\n * The slider renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <Slider.Root value={value} min={0} max={100} onChange={setValue}>\n * <Slider.Track>\n * <Slider.Thumb />\n * </Slider.Track>\n * </Slider.Root>\n */\n children: ReactNode\n}\n\nexport interface SliderMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = SliderProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderProps>\n\n/**\n * The wheel only acts while the focus is inside, so that scrolling a page past\n * the control does not change its value.\n */\nconst WHEEL_OPTIONS = { requireFocus: true }\n\nexport const Root = forwardRef<SliderMethods, Props>(\n (\n {\n value,\n min,\n max,\n step = 1,\n scale = linearScale,\n vertical = false,\n reverse = false,\n externalStyles: _externalStyles,\n wheel = ['raw', 1],\n keyboard = ['raw', 1],\n disabled = false,\n readonly = false,\n onChange,\n onDragStart,\n onDragEnd,\n className,\n style,\n children,\n onFocus,\n onBlur,\n onPointerDown,\n onKeyDown,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n // -- state and ref ---\n const trackRef = useRef<HTMLDivElement>(null)\n const thumbRef = useRef<SliderThumbMethods>(null)\n\n // --- interpret props ---\n const externalStyles = { ...defaultExternalStyles, ..._externalStyles }\n\n const p = toFixed(scale.normalize(value, min, max) * 100)\n const rev = toFixed(100 - p)\n // NOTE\n // normal -> normal (right)\n // vertical -> rev (up)\n // reverse -> rev (left)\n // vertical & reverse -> normal (down)\n const displayReversed = useMemo(\n () => xor(vertical, reverse),\n [vertical, reverse],\n )\n const percent = displayReversed ? rev : p\n\n // --- internal functions ---\n // The pointer is normalized against the track on both axes; only the one\n // the slider runs along is read back. `AxisOptions` extends `ValueRange`,\n // so the same object also describes the scaling for `applyDelta`.\n const axis: AxisOptions = useMemo(\n () => ({ min, max, step, scale, reverse: displayReversed }),\n [min, max, step, scale, displayReversed],\n )\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!keyboard || !onChange || readonly) return\n const key = event.key\n if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {\n event.preventDefault()\n let direction = key == 'ArrowRight' || key == 'ArrowUp' ? 1 : -1\n if (reverse) direction *= -1\n onChange(applyDelta(value, direction, keyboard, axis))\n }\n },\n [keyboard, onChange, readonly, reverse, value, axis],\n )\n\n // --- hooks ---\n const valueOf = (v: XY<number>) => v[vertical ? 1 : 0]\n\n const { refCallback: dragRefCallback } = useDragValue<HTMLDivElement>({\n axis,\n baseElementRef: trackRef,\n cursor: readonly ? undefined : externalStyles.cursor,\n updateOnPointerDown: true,\n onChange: (v) => {\n if (readonly) return\n onChange?.(valueOf(v))\n },\n onDragStart: (v) => {\n if (readonly) return\n if (externalStyles.userSelectNone) addUserSelectNone()\n\n thumbRef.current?.focus()\n onDragStart?.(valueOf(v))\n },\n onDragEnd: (v) => {\n if (readonly) return\n\n if (externalStyles.userSelectNone) removeUserSelectNone()\n\n onDragEnd?.(valueOf(v))\n },\n })\n\n const wheelRefCallback = useWheel<HTMLDivElement>((event) => {\n if (!wheel || !onChange || readonly) return\n event.preventDefault()\n let direction\n if (!vertical && event.deltaX != 0) {\n direction = event.deltaX > 0 ? 1 : -1\n } else {\n if (event.deltaY == 0) return\n direction = event.deltaY > 0 ? -1 : 1\n }\n if (vertical && reverse) direction *= -1\n onChange(applyDelta(value, direction, wheel, axis))\n }, WHEEL_OPTIONS)\n\n // Composed once, so React attaches the refs a single time instead of\n // detaching and re-attaching on every render.\n const rootRefCallback = useComposedRefs<HTMLDivElement>(\n dragRefCallback,\n wheelRefCallback,\n )\n\n const context = useMemo(\n () => ({\n value,\n min,\n max,\n step,\n scale,\n vertical,\n reverse,\n disabled,\n readonly,\n percent,\n trackRef,\n thumbRef,\n }),\n [\n value,\n min,\n max,\n step,\n scale,\n vertical,\n reverse,\n disabled,\n readonly,\n percent,\n ],\n )\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n thumbRef.current?.focus()\n },\n blur() {\n thumbRef.current?.blur()\n },\n }\n }, [])\n\n return (\n <SliderProvider value={context}>\n <div\n className={clsx('tremolo-slider', className)}\n ref={rootRefCallback}\n tabIndex={-1}\n role=\"slider\"\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-orientation={vertical ? 'vertical' : 'horizontal'}\n aria-disabled={disabled}\n aria-readonly={readonly}\n data-vertical={vertical}\n style={style}\n onPointerDown={onPointerDown}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n onFocus={(event) => {\n thumbRef.current?.focus()\n onFocus?.(event)\n }}\n onBlur={(event) => {\n thumbRef.current?.blur()\n onBlur?.(event)\n }}\n {...props}\n >\n {children}\n </div>\n </SliderProvider>\n )\n },\n)\n\n/**\n * Customizable slider\n */\nexport const Slider = {\n Root,\n Thumb,\n Track,\n Marks,\n MarksOption,\n}\n\nexport { useSliderContext } from './context'\nexport { type SliderThumbMethods, type SliderThumbProps } from './Thumb'\nexport { type SliderTrackProps } from './Track'\nexport { type MarksProps } from './Marks'\nexport { type MarksOptionProps } from './MarksOption'\nexport { type MarksOptions, type MarksType } from './type'\n","import { createContext, RefObject, useContext } from 'react'\n\nimport { toXY, type XY, type XYInput } from '@tremolo-ui/dom'\nimport type { Scale } from '@tremolo-ui/functions'\n\nimport type { XYPadThumbMethods } from './Thumb'\n\nexport { toXY, type XY, type XYInput }\n\nexport type XYPadContextValue = {\n value: XY<number>\n min: XY<number>\n max: XY<number>\n step: XY<number>\n /** How the value of each axis is distributed across the travel. */\n scale: XY<Scale>\n reverse: XY<boolean>\n disabled: boolean\n readonly: boolean\n\n /**\n * Position of the thumb, 0-100 per axis, already accounting for `reverse`.\n */\n percent: XY<number>\n\n /** `Area` registers its element here; `Root` normalizes the pointer against it. */\n areaRef: RefObject<HTMLDivElement | null>\n /** `Thumb` registers itself here; `Root` focuses it when a drag starts. */\n thumbRef: RefObject<XYPadThumbMethods | null>\n}\n\nconst XYPadContext = createContext<XYPadContextValue | null>(null)\n\nexport const XYPadProvider = XYPadContext.Provider\n\n/**\n * Everything here is derived during render, so there is no state to keep in\n * sync: `value` comes from the props of `Root` and the rest follows from it.\n */\nexport function useXYPadContext(): XYPadContextValue\nexport function useXYPadContext<T>(selector: (state: XYPadContextValue) => T): T\nexport function useXYPadContext<T>(selector?: (state: XYPadContextValue) => T) {\n const context = useContext(XYPadContext)\n if (!context) throw new Error('Missing XYPadContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import clsx from 'clsx'\nimport { ComponentPropsWithoutRef, CSSProperties, ReactNode, Ref } from 'react'\n\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { useXYPadContext } from './context'\n\nexport interface XYPadAreaProps {\n width?: number | string\n height?: number | string\n color?: string\n className?: string\n style?: CSSProperties\n /** `<XYPad.Thumb />` goes here. */\n children?: ReactNode\n ref?: Ref<HTMLDivElement>\n}\n\nexport function Area({\n width = 120,\n height = 120,\n color,\n children,\n className,\n style,\n ref,\n ...props\n}: XYPadAreaProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadAreaProps>) {\n const { areaRef } = useXYPadContext()\n\n // The area is what the pointer position is normalized against, so the\n // context ref is composed with any ref the caller passed.\n const composedRef = useComposedRefs<HTMLDivElement>(ref, areaRef)\n\n return (\n <div\n ref={composedRef}\n className={clsx('tremolo-xy-pad-area', className)}\n style={{\n ...{ '--color': color },\n width: width,\n height: height,\n ...style,\n }}\n {...props}\n >\n {children}\n </div>\n )\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n CSSProperties,\n ReactNode,\n Ref,\n useImperativeHandle,\n useRef,\n} from 'react'\n\nimport { useXYPadContext } from './context'\n\nexport interface XYPadThumbProps {\n /**\n * Size comes from the `--thumb-size` CSS variable on `XYPad.Root`, so that\n * the root can reserve the matching amount of space around the area.\n */\n color?: string\n\n wrapperClassName?: string\n wrapperStyle?: CSSProperties\n\n children?: ReactNode\n ref?: Ref<XYPadThumbMethods>\n}\n\nexport interface XYPadThumbMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = XYPadThumbProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadThumbProps>\n\nexport function Thumb({\n color,\n children,\n wrapperClassName,\n wrapperStyle,\n className,\n style,\n ref,\n ...props\n}: Props) {\n const elementRef = useRef<HTMLDivElement>(null)\n const { disabled, readonly, percent, thumbRef } = useXYPadContext()\n\n const methods = () => ({\n focus() {\n elementRef.current?.focus()\n },\n blur() {\n elementRef.current?.blur()\n },\n })\n\n useImperativeHandle(ref, methods, [])\n // Root focuses the thumb when a drag starts, wherever the user placed it.\n useImperativeHandle(thumbRef, methods, [])\n\n return (\n <div\n className={clsx('tremolo-xy-pad-thumb-wrapper', wrapperClassName)}\n style={{\n left: `${percent[0]}%`,\n top: `${percent[1]}%`,\n ...wrapperStyle,\n }}\n {...props}\n >\n {children ? (\n children\n ) : (\n // default thumb\n <div\n ref={elementRef}\n className={clsx('tremolo-xy-pad-thumb', className)}\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n aria-disabled={disabled}\n aria-readonly={readonly}\n style={{\n ...{ '--color': color },\n ...style,\n }}\n ></div>\n )}\n </div>\n )\n}\n","import clsx from 'clsx'\nimport {\n ComponentPropsWithoutRef,\n forwardRef,\n ReactNode,\n Ref,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react'\n\nimport type { AxisOptions } from '@tremolo-ui/dom'\nimport {\n applyDelta,\n linearScale,\n toFixed,\n InputEventOption,\n type Scale,\n} from '@tremolo-ui/functions'\n\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport { addUserSelectNone, Cursor, removeUserSelectNone } from '../_util'\nimport { useComposedRefs } from '../_util/composeRefs'\n\nimport { Area } from './Area'\nimport { toXY, XY, XYInput, XYPadProvider } from './context'\nimport { Thumb, XYPadThumbMethods } from './Thumb'\n\nconst defaultExternalStyles: XYPadProps['externalStyles'] = {\n userSelectNone: true,\n cursor: 'pointer',\n}\n\n/**\n * Two-dimensional slider component.\n *\n * The per-axis settings mirror `Slider`, given as `[x, y]` tuples. A plain\n * value applies to both axes.\n */\nexport interface XYPadProps {\n value: XY<number>\n min: XYInput<number>\n max: XYInput<number>\n\n step?: XYInput<number>\n /**\n * How the value of each axis is distributed across the travel.\n *\n * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,\n * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or\n * `skewScale(n)` for a value that has to match a JUCE parameter.\n *\n * @default linearScale\n */\n scale?: XYInput<Scale>\n reverse?: XYInput<boolean>\n\n /**\n * wheel control option. Shift selects the x axis.\n * If null, no event will be triggered\n */\n wheel?: InputEventOption | null\n /**\n * keyboard control option\n * If null, no event will be triggered\n */\n keyboard?: InputEventOption | null\n\n externalStyles?: {\n userSelectNone?: boolean\n cursor?: Cursor\n }\n\n disabled?: boolean\n readonly?: boolean\n\n onChange?: (value: XY<number>) => void\n onDragStart?: (value: XY<number>) => void\n onDragEnd?: (value: XY<number>) => void\n\n /**\n * The pad renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <XYPad.Root value={[x, y]} min={0} max={100} onChange={setValue}>\n * <XYPad.Area>\n * <XYPad.Thumb />\n * </XYPad.Area>\n * </XYPad.Root>\n */\n children: ReactNode\n}\n\nexport interface XYPadMethods {\n focus: () => void\n blur: () => void\n original: Ref<HTMLDivElement>\n}\n\ntype Props = XYPadProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadProps>\n\n/**\n * The wheel only acts while the focus is inside, so that scrolling a page past\n * the control does not change its value.\n */\nconst WHEEL_OPTIONS = { requireFocus: true }\n\nexport const Root = forwardRef<XYPadMethods, Props>(\n (\n {\n value,\n min: _min,\n max: _max,\n step: _step = 1,\n scale: _scale = linearScale,\n reverse: _reverse = false,\n wheel = ['raw', 1],\n keyboard = ['raw', 1],\n className,\n style,\n externalStyles: _externalStyles,\n disabled = false,\n readonly = false,\n onChange,\n onDragStart,\n onDragEnd,\n onPointerDown,\n onKeyDown,\n onFocus,\n onBlur,\n children,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n // -- state and ref ---\n const rootRef = useRef<HTMLDivElement>(null)\n const areaRef = useRef<HTMLDivElement>(null)\n const thumbRef = useRef<XYPadThumbMethods>(null)\n\n // --- interpret props ---\n const externalStyles = { ...defaultExternalStyles, ..._externalStyles }\n\n const min = useMemo(() => toXY(_min), [_min])\n const max = useMemo(() => toXY(_max), [_max])\n const step = useMemo(() => toXY(_step), [_step])\n const scale = useMemo(() => toXY(_scale), [_scale])\n const reverse = useMemo(() => toXY(_reverse), [_reverse])\n\n const percent = useMemo((): XY<number> => {\n const normalized = [0, 1].map((i) =>\n scale[i].normalize(value[i], min[i], max[i]),\n )\n return [0, 1].map((i) =>\n toFixed((reverse[i] ? 1 - normalized[i] : normalized[i]) * 100),\n ) as XY<number>\n }, [value, min, max, scale, reverse])\n\n // --- internal functions ---\n // `AxisOptions` extends `ValueRange`, so the same pair also describes the\n // scaling for `applyDelta`. Its `reverse` only concerns the drag, where\n // positions follow the screen; the key and wheel handlers below flip the\n // direction themselves.\n const axis = useMemo(\n (): XY<AxisOptions> =>\n [0, 1].map((i) => ({\n min: min[i],\n max: max[i],\n step: step[i],\n scale: scale[i],\n reverse: reverse[i],\n })) as XY<AxisOptions>,\n [min, max, step, scale, reverse],\n )\n\n const withAxis = useCallback(\n (axis: 0 | 1, next: number): XY<number> =>\n axis == 0 ? [next, value[1]] : [value[0], next],\n [value],\n )\n\n /** @param i 0 = x, 1 = y */\n const nudge = useCallback(\n (i: 0 | 1, direction: number, option: InputEventOption): XY<number> =>\n withAxis(i, applyDelta(value[i], direction, option, axis[i])),\n [value, axis, withAxis],\n )\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!onChange || readonly || !keyboard) return\n const key = event.key\n if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {\n const i: 0 | 1 = key == 'ArrowRight' || key == 'ArrowLeft' ? 0 : 1\n event.preventDefault()\n let direction = 1\n if (key == 'ArrowLeft' || key == 'ArrowUp') direction *= -1\n if (reverse[i]) direction *= -1\n onChange(nudge(i, direction, keyboard))\n }\n },\n [onChange, readonly, keyboard, reverse, nudge],\n )\n\n // --- hooks ---\n\n const { refCallback: dragRefCallback } = useDragValue<HTMLDivElement>({\n axis,\n baseElementRef: areaRef,\n updateOnPointerDown: true,\n cursor: readonly ? undefined : externalStyles.cursor,\n onChange: (v) => {\n if (readonly) return\n onChange?.(v)\n },\n onDragStart: (v) => {\n if (readonly) return\n if (externalStyles.userSelectNone) addUserSelectNone()\n thumbRef.current?.focus()\n onDragStart?.(v)\n },\n onDragEnd: (v) => {\n if (readonly) return\n if (externalStyles.userSelectNone) removeUserSelectNone()\n onDragEnd?.(v)\n },\n })\n\n const wheelRefCallback = useWheel<HTMLDivElement>((event) => {\n if (!onChange || readonly || !wheel) return\n const i: 0 | 1 = event.shiftKey ? 0 : 1\n event.preventDefault()\n let direction = 1\n if (event.deltaY < 0) direction *= -1\n if (reverse[i]) direction *= -1\n onChange(nudge(i, direction, wheel))\n }, WHEEL_OPTIONS)\n\n // Composed once, so React attaches the refs a single time instead of\n // detaching and re-attaching on every render.\n const rootRefCallback = useComposedRefs<HTMLDivElement>(\n rootRef,\n dragRefCallback,\n wheelRefCallback,\n )\n\n const context = useMemo(\n () => ({\n value,\n min,\n max,\n step,\n scale,\n reverse,\n disabled,\n readonly,\n percent,\n areaRef,\n thumbRef,\n }),\n [value, min, max, step, scale, reverse, disabled, readonly, percent],\n )\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n thumbRef.current?.focus()\n },\n blur() {\n thumbRef.current?.blur()\n },\n original: rootRef,\n }\n }, [])\n\n return (\n <XYPadProvider value={context}>\n {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}\n <div\n className={clsx('tremolo-xy-pad', className)}\n ref={rootRefCallback}\n tabIndex={-1}\n aria-disabled={disabled}\n aria-readonly={readonly}\n style={style}\n onPointerDown={onPointerDown}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n onFocus={(event) => {\n thumbRef.current?.focus()\n onFocus?.(event)\n }}\n onBlur={(event) => {\n thumbRef.current?.blur()\n onBlur?.(event)\n }}\n {...props}\n >\n {children}\n </div>\n </XYPadProvider>\n )\n },\n)\n\n/**\n * Simple XYPad\n */\nexport const XYPad = {\n Root,\n Thumb,\n Area,\n}\n\nexport { type XYPadThumbProps, type XYPadThumbMethods } from './Thumb'\nexport { type XYPadAreaProps } from './Area'\nexport { useXYPadContext, type XY, type XYInput } from './context'\n","import { DependencyList, useCallback, useEffect, useRef } from 'react'\n\nexport function useAnimationFrame(\n callback = () => {},\n deps: DependencyList = [],\n) {\n const reqIdRef = useRef(-1)\n const loop = useCallback(() => {\n reqIdRef.current = requestAnimationFrame(loop)\n callback()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [callback, ...deps])\n\n useEffect(() => {\n reqIdRef.current = requestAnimationFrame(loop)\n return () => cancelAnimationFrame(reqIdRef.current)\n }, [loop])\n}\n","import { useEffect, useMemo, useSyncExternalStore } from 'react'\n\nimport { createMIDIAccess } from '@tremolo-ui/dom'\n\nexport {\n NOT_SUPPORTED,\n PERMISSION_DENIED,\n type MIDIAccessError,\n} from '@tremolo-ui/dom'\n\n/**\n * Hooks for requesting MIDI access in the browser. The first argument allows you to choose whether to request access on mount.\n */\nexport function useMIDIAccess(requestOnMount = true) {\n const instance = useMemo(() => createMIDIAccess(), [])\n\n const { midiAccess, error } = useSyncExternalStore(\n instance.subscribe,\n instance.getState,\n instance.getServerState,\n )\n\n useEffect(() => {\n if (requestOnMount) instance.request()\n }, [instance, requestOnMount])\n\n useEffect(() => {\n return () => instance.destroy()\n }, [instance])\n\n return { request: instance.request, midiAccess, error }\n}\n","import { useEffect } from 'react'\n\nimport { createMIDIInput } from '@tremolo-ui/dom'\n\n/**\n * Hooks for handling note on/off events. To be used with useMIDIAccess. Internally uses useMIDIMessage.\n */\nexport function useMIDIInput(\n midiAccess: MIDIAccess | null,\n onNoteOnEvent?: (note: number, velocity: number) => void,\n onNoteOffEvent?: (note: number) => void,\n onPitchBendEvent?: (msb: number, lsb: number) => void,\n) {\n useEffect(() => {\n const instance = createMIDIInput(midiAccess, {\n onNoteOnEvent,\n onNoteOffEvent,\n onPitchBendEvent,\n })\n return () => instance.destroy()\n }, [midiAccess, onNoteOnEvent, onNoteOffEvent, onPitchBendEvent])\n}\n","import { useEffect } from 'react'\n\nimport { createMIDIMessage } from '@tremolo-ui/dom'\n\n/**\n * Hooks for when you want to process MIDI events in more detail than useMIDIInput.\n */\nexport function useMIDIMessage(\n midiAccess: MIDIAccess | null,\n onMIDIMessage: (event: MIDIMessageEvent) => void,\n) {\n useEffect(() => {\n const instance = createMIDIMessage(midiAccess, onMIDIMessage)\n return () => instance.destroy()\n }, [midiAccess, onMIDIMessage])\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["useState","useComposedRefs","useRef","createAnimationCanvas","linearScale","applyDelta","useRef","useCallback","useState","useRef","createDragValue","elementMapping","relativeMapping","useState","createWheel","useContext","radian","useContext","Thumb","clamp","defaultExternalStyles","WHEEL_OPTIONS","Root","linearScale","useRef","useMemo","useCallback","applyDelta","selectModifier","useComposedRefs","useContext","useRef","useCallback","useRef","useState","useRef","useCallback","useState","useRef","useComposedRefs","useState","createDrag","useMemo","mapModifier","useRef","selectModifier","applyDelta","useComposedRefs","Root","linearScale","useRef","useState","useMemo","useCallback","selectInputEvent","applyDelta","Root","useState","useMemo","getNoteRangeArray","isWhiteKey","useRef","useCallback","createPianoInput","pianoWidth","noteKey","notePosition","blackKeyWidth","useContext","clamp","useId","useState","useRef","selectModifier","useCallback","applyDelta","useComposedRefs","useComposedRefs","clamp","Root","useRef","useState","useCallback","toPrecision","applyDelta","createSelectionBox","useMemo","useContext","useCallback","toFixed","xor","toFixed","decimalPart","xor","Thumb","useRef","useComposedRefs","xor","defaultExternalStyles","WHEEL_OPTIONS","Root","linearScale","useRef","toFixed","useMemo","xor","useCallback","applyDelta","selectModifier","useComposedRefs","useContext","useComposedRefs","useRef","toXY","linearScale","useRef","useMemo","toXY","toFixed","useCallback","applyDelta","selectModifier","useComposedRefs","useRef","createMIDIAccess","useMemo","useSyncExternalStore","useRef","createMIDIInput","useRef","createMIDIMessage"],"sources":["../src/components/AnimationCanvas/index.tsx","../src/hooks/_internal/useCheckSteps.ts","../src/hooks/_internal/useCallbackRef.ts","../src/hooks/useDragValue.ts","../src/hooks/useWheel.ts","../src/input-event.ts","../src/components/_util/css-length.ts","../src/components/_util/Placement.tsx","../src/components/Knob/context.tsx","../src/components/Knob/ActiveLine.tsx","../src/components/Knob/InactiveLine.tsx","../src/components/Knob/SVGRoot.tsx","../src/components/Knob/Thumb.tsx","../src/components/Knob/index.tsx","../src/components/NumberInput/context.tsx","../src/hooks/useEventListener.ts","../src/hooks/useInterval.ts","../src/hooks/useLongPress.ts","../src/components/NumberInput/StepperButton.tsx","../src/components/NumberInput/DecrementStepper.tsx","../src/components/NumberInput/IncrementStepper.tsx","../src/components/NumberInput/InputField.tsx","../src/hooks/useDrag.ts","../src/components/NumberInput/Stepper.tsx","../src/components/NumberInput/index.tsx","../src/components/Piano/keyboard-shortcuts.ts","../src/components/Piano/index.tsx","../src/components/PointsEditor/Background.tsx","../src/components/PointsEditor/context.tsx","../src/components/_util/VisuallyHiddenRangeInput.tsx","../src/components/PointsEditor/Point.tsx","../src/components/PointsEditor/Container.tsx","../src/components/PointsEditor/SelectionBox.tsx","../src/components/PointsEditor/index.tsx","../src/components/Slider/context.tsx","../src/components/Slider/MarksOption.tsx","../src/components/Slider/type.ts","../src/components/Slider/Marks.tsx","../src/components/Slider/Thumb.tsx","../src/components/Slider/Track.tsx","../src/components/Slider/index.tsx","../src/components/XYPad/context.tsx","../src/components/XYPad/Area.tsx","../src/components/XYPad/Thumb.tsx","../src/components/XYPad/index.tsx","../src/hooks/useAnimationFrame.ts","../src/hooks/useMIDIAccess.ts","../src/hooks/useMIDIInput.ts","../src/hooks/useMIDIMessage.ts"],"sourcesContent":["import {\n ComponentPropsWithoutRef,\n forwardRef,\n useEffect,\n useRef,\n useState,\n} from 'react'\n\nimport {\n createAnimationCanvas,\n type AnimationCanvasInstance,\n type AnimationFrame,\n} from '@tremolo-ui/dom'\n\nimport { useComposedRefs } from '../../compose-refs'\n\nexport type InitFunction = (\n context: CanvasRenderingContext2D,\n option: {\n /** current canvas width */\n width: number\n /** current canvas height */\n height: number\n },\n) => void\n\nexport type DrawFunction = (\n context: CanvasRenderingContext2D,\n option: AnimationFrame,\n) => void\n\nexport interface AnimationCanvasCommonProps {\n /**\n * Draw one frame. It is given the 2D context and the frame: the size in CSS\n * pixels, `count`, `deltaTime`, `elapsedTime` and `fps`.\n *\n * A new function replaces the old one in place, so writing it inline does\n * not restart anything.\n */\n draw: DrawFunction\n /**\n * Called once before the first frame, with the context and the size in CSS\n * pixels. Set up what every frame shares here.\n */\n init?: InitFunction\n /**\n * Redraw on every animation frame. Turn it off to draw only when there is a\n * reason to: when the canvas mounts, when it is resized, and when the\n * component re-renders.\n *\n * @default true\n */\n animate?: boolean\n /**\n * Read once, when the 2D context is created, so changing it later has no\n * effect. Passing a fresh object on every render is therefore harmless.\n *\n * @see https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement/getContext#contextattributes\n */\n options?: CanvasRenderingContext2DSettings\n /**\n * Carry the drawing across a resize, so that the canvas does not blank for a\n * frame while the new size is drawn. A fixed canvas is resized too, when its\n * `width` or `height` changes.\n *\n * @default true\n */\n reduceFlickering?: boolean\n}\n\n/** A canvas of the size given in CSS pixels. This is the default. */\nexport interface AnimationCanvasFixedProps {\n /** Leave it out, or pass `false`, for a canvas of the size below. */\n resizable?: false\n /**\n * Width of the canvas in CSS pixels.\n * @default 100\n */\n width?: number\n /**\n * Height of the canvas in CSS pixels.\n * @default 100\n */\n height?: number\n}\n\n/**\n * A canvas that follows the size of its parent element, so the parent needs a\n * size of its own.\n */\nexport interface AnimationCanvasResizableProps {\n /**\n * Follow the size of the parent element instead of `width` and `height`.\n * Switching it rebuilds the canvas.\n */\n resizable: true\n /** Not accepted: the size comes from the parent element. */\n width?: never\n /** Not accepted: the size comes from the parent element. */\n height?: never\n}\n\nexport type AnimationCanvasProps = AnimationCanvasCommonProps &\n (AnimationCanvasFixedProps | AnimationCanvasResizableProps)\n\ntype Props = AnimationCanvasProps &\n Omit<\n ComponentPropsWithoutRef<'canvas'>,\n keyof AnimationCanvasCommonProps | 'resizable' | 'width' | 'height'\n >\n\n/**\n * A simple animatable canvas with requestAnimationFrame()\n */\nexport const AnimationCanvas = /* @__PURE__ */ forwardRef<\n HTMLCanvasElement,\n Props\n>(function AnimationCanvas(\n {\n // common\n draw,\n init,\n animate = true,\n options,\n reduceFlickering = true,\n // fixed\n width = 100,\n height = 100,\n // resizable\n resizable = false,\n // canvas props\n className,\n onContextMenu = (event) => event.preventDefault(),\n ...props\n },\n forwardedRef,\n) {\n // See useDrag for why the node is held in state rather than a ref: an inline\n // ref would be re-attached on every render and tear the instance down.\n const [node, setNode] = useState<HTMLCanvasElement | null>(null)\n // The caller's ref gets the same element.\n const composedRef = useComposedRefs<HTMLCanvasElement>(forwardedRef, setNode)\n\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale handler is replaced within the same commit.\n const latest = useRef({\n draw,\n init,\n animate,\n width,\n height,\n reduceFlickering,\n options,\n })\n const instanceRef = useRef<AnimationCanvasInstance | null>(null)\n\n // Runs before the creation effect below. This keeps a rebuilt instance on\n // the current render's size and handlers while updating an existing one in\n // place on ordinary renders.\n useEffect(() => {\n latest.current = {\n draw,\n init,\n animate,\n width,\n height,\n reduceFlickering,\n options,\n }\n instanceRef.current?.update({\n animate,\n size: { width, height },\n reduceFlickering,\n })\n })\n\n useEffect(() => {\n if (!node) return\n\n const current = latest.current\n const instance = createAnimationCanvas(node, {\n draw: (context, frame) => latest.current.draw(context, frame),\n init: (context, size) => latest.current.init?.(context, size),\n animate: current.animate,\n size: { width: current.width, height: current.height },\n reduceFlickering: current.reduceFlickering,\n resizable,\n contextAttributes: current.options,\n })\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n // Only `resizable` decides how the instance is wired, so it is the one\n // setting that rebuilds it. `options` is read from the ref above rather\n // than depended on: it is almost always written inline, and depending on\n // it would tear the canvas down on every render.\n }, [node, resizable])\n\n return (\n <canvas\n className={className}\n ref={composedRef}\n onContextMenu={onContextMenu}\n {...props}\n />\n )\n})\n","import { useEffect } from 'react'\n\nimport {\n applyDelta,\n linearScale,\n type InputEventOption,\n type ModifierState,\n type ModifierValue,\n type ValueRange,\n} from '@tremolo-ui/functions'\n\n/** Positions probed across the travel. The ends are left out so that the\n * clamp at `min` and `max` cannot be mistaken for a press that does nothing. */\nconst PROBES = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]\n\nconst NONE: ModifierState = {\n shiftKey: false,\n altKey: false,\n ctrlKey: false,\n metaKey: false,\n}\n\nconst MODIFIER_STATE: Record<string, ModifierState> = {\n shift: { ...NONE, shiftKey: true },\n alt: { ...NONE, altKey: true },\n ctrl: { ...NONE, ctrlKey: true },\n meta: { ...NONE, metaKey: true },\n}\n\n/** Each entry of a modifier-aware input option, as a name and held keys. */\nfunction entries(\n options: ModifierValue<InputEventOption>,\n): { name: string; modifiers: ModifierState }[] {\n if (Array.isArray(options)) return [{ name: '', modifiers: NONE }]\n return Object.keys(options).map((key) => ({\n name: key === 'default' ? '' : key,\n modifiers: MODIFIER_STATE[key] ?? NONE,\n }))\n}\n\ninterface Outcome {\n /** The press changed the value at least once across the travel. */\n moved: boolean\n /** The change reached the displayed text at least once. */\n visible: boolean\n}\n\n/**\n * Press every entry of `options` at nine points along the travel and report\n * whether anything came of it.\n *\n * Run against `applyDelta` itself rather than against a reading of `step`:\n * the whole point is that the amount, the step and the scale interact, and\n * the pipeline is the only thing that knows how.\n */\nfunction probe(\n options: ModifierValue<InputEventOption>,\n range: ValueRange,\n format?: (value: number) => string,\n): Outcome {\n const { min, max, scale = linearScale } = range\n const outcome: Outcome = { moved: false, visible: false }\n\n for (const { modifiers } of entries(options)) {\n for (const position of PROBES) {\n const value = scale.denormalize(position, min, max)\n const up = applyDelta(value, 1, options, range, modifiers)\n const down = applyDelta(value, -1, options, range, modifiers)\n if (up !== value || down !== value) outcome.moved = true\n if (!format) continue\n const shown = format(value)\n if (format(up) !== shown || format(down) !== shown) outcome.visible = true\n }\n }\n\n return outcome\n}\n\nexport interface CheckStepsOptions {\n /** The component, for the message. */\n component: string\n /** The axis, for a component that has more than one. */\n axis?: string\n /**\n * The range to probe, or `null` to check nothing. An unbounded input has no\n * travel to sample, so `NumberInput` passes `null` when `min` and `max` are\n * not both there.\n */\n range: ValueRange | null\n keyboard?: ModifierValue<InputEventOption> | null\n wheel?: ModifierValue<InputEventOption> | null\n /**\n * How the value is displayed, where the component shows one. Called with\n * probe values only, and only in development.\n */\n format?: (value: number) => string\n}\n\n/**\n * Warn, in development only, when a key press or a wheel notch cannot produce\n * a change the user can see.\n *\n * Two settings that are each fine on their own can cancel out, and nothing\n * fails when they do — the control simply sits there:\n *\n * - **`step` coarser than the amount.** `keyboard={['raw', 0.1]}` with\n * `step={1}` rounds every press straight back to where it started\n * - **the display coarser than the amount.** A `format` showing two decimals\n * of a kHz value cannot show a press worth 1 Hz\n *\n * The second is only reported when the press is invisible at *every* point\n * along the travel. A display that rounds is a deliberate choice and is\n * normally right — it is being too coarse everywhere that makes it a mistake.\n *\n * @internal\n */\nexport function useCheckSteps({\n component,\n axis,\n range,\n keyboard,\n wheel,\n format,\n}: CheckStepsOptions) {\n const { min, max, step, scale } = range ?? {}\n const where = axis ? `${component} (${axis})` : component\n\n useEffect(() => {\n try {\n // Inline and first, so a bundler folds the comparison and drops the\n // whole block — the probing and the message strings with it. See\n // `useCheckPlacement` for why it cannot go through a helper, and why\n // it is wrapped.\n if (process.env.NODE_ENV === 'production') return\n if (!range || min === undefined || max === undefined || !(min < max)) {\n return\n }\n\n for (const [name, options] of [\n ['keyboard', keyboard],\n ['wheel', wheel],\n ] as const) {\n if (!options) continue\n const { moved, visible } = probe(options, range, format)\n if (!moved) {\n console.warn(\n `[tremolo-ui] ${where}: \\`${name}\\` cannot move the value.` +\n (step !== undefined\n ? ` Each press is smaller than \\`step\\` (${step}), so it rounds`\n : ' Each press rounds') +\n ' straight back to where it started.',\n )\n } else if (format && !visible) {\n console.warn(\n `[tremolo-ui] ${where}: \\`${name}\\` moves the value, but \\`format\\`` +\n ' shows the same text before and after, everywhere in the range.' +\n ' The display is too coarse for it to be seen.',\n )\n }\n }\n } catch {\n // No bundler substituted NODE_ENV, so a production build cannot be told\n // from a development one. Say nothing rather than break.\n }\n // `range` and `format` are rebuilt on most renders, so the effect is keyed\n // on what actually decides the outcome. `format` is left out on purpose:\n // an inline arrow function would make this run every render.\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [where, min, max, step, scale, keyboard, wheel])\n}\n","import { DependencyList, useCallback, useInsertionEffect, useRef } from 'react'\n\n/**\n * Internal\n * @private\n */\nexport function useCallbackRef<Args extends unknown[], Return>(\n callback: ((...args: Args) => Return) | undefined,\n deps: DependencyList = [],\n) {\n const callbackRef = useRef<typeof callback>(() => {\n throw new Error('Cannot call an event handler while rendering.')\n })\n\n useInsertionEffect(() => {\n callbackRef.current = callback\n })\n\n // `deps` comes from the caller, so it cannot be the array literal the\n // compiler rules expect.\n // oxlint-disable-next-line react-hooks/exhaustive-deps, react/use-memo\n return useCallback((...args: Args) => callbackRef.current?.(...args), deps)\n}\n","import { RefObject, useEffect, useRef, useState } from 'react'\n\nimport {\n createDragValue,\n elementMapping,\n relativeMapping,\n type AxisOptions,\n type DragState,\n type DragValueInstance,\n type XY,\n type XYInput,\n} from '@tremolo-ui/dom'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\nexport interface UseDragValueOptions {\n /** Scaling of each axis; a single value applies to both. */\n axis: XYInput<AxisOptions>\n\n /**\n * Normalize the pointer against the bounding rect of this element, so that\n * the value *is* the position pointed at.\n *\n * Give either this or `getValue`.\n */\n baseElementRef?: RefObject<Element | null>\n\n /**\n * Move the value away from where it stood when the drag started, by the\n * distance dragged. The pointer position itself carries no meaning.\n *\n * Give either this or `baseElementRef`.\n */\n getValue?: () => XY<number>\n /**\n * Pixels of movement that span the whole range, with `getValue`.\n * @default 100\n */\n pixelRange?: XYInput<number>\n /**\n * How much the movement counts, read on every move. `0.1` makes the same\n * movement cover a tenth of the range, which is what a fine-adjustment\n * modifier wants.\n *\n * With `baseElementRef` the value is normally the position pointed at, so\n * anything but `1` turns the mapping relative and leaves the pointer and the\n * value apart for the rest of the drag.\n *\n * @see relativeMapping\n * @see elementMapping\n */\n sensitivity?: (state: DragState) => number\n\n /** @see DragValueOptions.updateOnPointerDown */\n updateOnPointerDown?: boolean\n /** @default 0 */\n threshold?: number\n /** CSS cursor to show while dragging. Applied to the element itself. */\n cursor?: string\n /**\n * Hide the pointer and read its movement directly, instead of following it\n * around the screen. Only with `getValue`: there is no pointer position to\n * normalize against a `baseElementRef` while the pointer is locked.\n *\n * @see DragOptions.pointerLock\n * @default false\n */\n pointerLock?: boolean\n /**\n * Decide whether a pointerdown starts a drag at all, before the pointer is\n * captured.\n *\n * @see DragOptions.shouldStart\n */\n shouldStart?: (event: PointerEvent) => boolean\n\n /**\n * @param state the whole drag, for anything the value leaves out — the\n * pointer event and its modifier keys, most of all.\n */\n onChange?: (value: XY<number>, state: DragState) => void\n onDragStart?: (value: XY<number>, state: DragState) => void\n onDragEnd?: (value: XY<number>, state: DragState) => void\n}\n\n/**\n * Drive a value with a pointer drag.\n *\n * @returns a ref callback for the element that starts the drag, and whether a drag is in progress\n */\nexport function useDragValue<T extends Element>(\n options: UseDragValueOptions,\n): { refCallback: (node: T | null) => void; dragging: boolean } {\n const {\n axis,\n baseElementRef,\n pixelRange,\n updateOnPointerDown,\n threshold,\n cursor,\n pointerLock,\n } = options\n\n if (!baseElementRef && !options.getValue) {\n throw new Error(\n 'useDragValue: give either baseElementRef or getValue, so that the drag has something to move',\n )\n }\n\n const [dragging, setDragging] = useState(false)\n\n const valueGetter = useCallbackRef(options.getValue)\n const changeHandler = useCallbackRef(options.onChange)\n const dragStartHandler = useCallbackRef(options.onDragStart)\n const dragEndHandler = useCallbackRef(options.onDragEnd)\n\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale setting is replaced within the same commit.\n const latest = useRef(options)\n\n const instanceRef = useRef<DragValueInstance | null>(null)\n\n // See useDrag for why the node is held in state.\n const [node, setNode] = useState<T | null>(null)\n\n const [pixelRangeX, pixelRangeY] = Array.isArray(pixelRange)\n ? pixelRange\n : [pixelRange, pixelRange]\n\n useEffect(() => {\n if (!node) return\n\n const instance = createDragValue(node, {\n axis: latest.current.axis,\n mapping: baseElementRef\n ? elementMapping(() => baseElementRef.current, {\n // Read through the ref so that a changed setting reaches a drag\n // already in progress.\n sensitivity: (state) => latest.current.sensitivity?.(state) ?? 1,\n })\n : relativeMapping({\n pixelRange: [pixelRangeX ?? 100, pixelRangeY ?? 100],\n // Read through the ref so that a changed setting reaches a drag\n // already in progress.\n sensitivity: (state) => latest.current.sensitivity?.(state) ?? 1,\n }),\n getValue: () => valueGetter() ?? [0, 0],\n updateOnPointerDown: latest.current.updateOnPointerDown,\n threshold: latest.current.threshold,\n cursor: latest.current.cursor,\n pointerLock: latest.current.pointerLock,\n shouldStart: (event) => latest.current.shouldStart?.(event) ?? true,\n onChange: (value, state) => changeHandler(value, state),\n onDragStart: (value, state) => {\n setDragging(true)\n dragStartHandler(value, state)\n },\n onDragEnd: (value, state) => {\n setDragging(false)\n dragEndHandler(value, state)\n },\n })\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n }, [\n node,\n baseElementRef,\n pixelRangeX,\n pixelRangeY,\n valueGetter,\n changeHandler,\n dragStartHandler,\n dragEndHandler,\n ])\n\n // Runs after every render: the settings come from props and are cheap to\n // push, and updating in place leaves a drag in progress untouched.\n useEffect(() => {\n latest.current = options\n instanceRef.current?.update({\n axis,\n updateOnPointerDown,\n threshold,\n cursor,\n pointerLock,\n })\n })\n\n return { refCallback: setNode, dragging }\n}\n","import { RefObject, useEffect, useState } from 'react'\n\nimport { createWheel, type WheelOptions } from '@tremolo-ui/dom'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\nexport interface UseWheelOptions extends WheelOptions {\n /**\n * Listen on this element rather than on the one the returned ref callback is\n * attached to, and ignore that callback.\n *\n * For a control made of several movable parts: a wheel event only reaches\n * what the cursor is over, so a listener per part responds only while the\n * cursor is over that same part. Listening on the element they share lets\n * every part see the event, and each one decide whether it is the one to act.\n *\n * The element is read when the listener is attached, so a ref filled in by a\n * parent is fine as long as the parent is above in the tree.\n */\n target?: RefObject<Element | null>\n}\n\n/**\n * Listen to wheel events on an element.\n *\n * The listener is not passive, so the handler may call `preventDefault()`.\n *\n * @returns a ref callback to attach to the element, unused when `target` is given\n */\nexport function useWheel<T extends Element>(\n onWheel: (event: WheelEvent) => void,\n { requireFocus = false, target }: UseWheelOptions = {},\n): (node: T | null) => void {\n const wheelHandler = useCallbackRef(onWheel)\n\n // See useDrag for why the node is held in state.\n const [node, setNode] = useState<T | null>(null)\n\n useEffect(() => {\n const element = target ? target.current : node\n if (!element) return\n\n const instance = createWheel(element, (event) => wheelHandler(event), {\n requireFocus,\n })\n\n return () => instance.destroy()\n }, [node, target, wheelHandler, requireFocus])\n\n return setNode\n}\n","import type { InputEventOption, ModifierValue } from '@tremolo-ui/functions'\n\n/**\n * The keyboard amount used by Knob, NumberInput, Slider, and XYPad by default:\n * 1 per press in the units of the value, and 0.1 with shift held. That is one\n * `step` only while `step` is 1; a coarser `step` rounds 1 straight back, which\n * `useCheckSteps` warns about.\n *\n * A modifier entry is not snapped to `step`, which is what lets the finer\n * amount move at all — see `applyDelta` in `@tremolo-ui/functions`.\n */\nexport const DEFAULT_KEYBOARD_OPTIONS: ModifierValue<InputEventOption> = {\n default: ['raw', 1],\n shift: ['raw', 0.1],\n}\n\n/**\n * The wheel amount used by Knob, NumberInput, Slider, and XYPad by default.\n *\n * Browsers turn shift+wheel into horizontal scrolling, which empties `deltaY`\n * and fills `deltaX`, so no modifier is bound here.\n */\nexport const DEFAULT_WHEEL_OPTIONS: ModifierValue<InputEventOption> = ['raw', 1]\n\n/**\n * The drag sensitivity used by value controls by default. Shift makes the\n * same movement cover a tenth of the range, matching the arrow keys.\n */\nexport const DEFAULT_DRAG_SENSITIVITY: ModifierValue<number> = {\n default: 1,\n shift: 0.1,\n}\n","/**\n * A number as a CSS length, for a custom property.\n *\n * React appends `px` to a bare number for the properties it knows take a\n * length, and a custom property is never one of them: `--size: 50` would come\n * out as the invalid `50`. Anything already a string is passed through, so\n * `'3rem'` and `'100%'` still work.\n */\nexport function cssLength(\n value: number | string | undefined,\n): string | undefined {\n return typeof value === 'number' ? `${value}px` : value\n}\n","import { createContext, ReactNode, useContext, useEffect } from 'react'\n\n/**\n * The subcomponent that established the current placement, if any.\n *\n * @internal\n */\nconst PlacementContext = /* @__PURE__ */ createContext<string | null>(null)\n\n/**\n * Marks its children as being inside `name`, for {@link useCheckPlacement}.\n *\n * @internal\n */\nexport function Placement({\n name,\n children,\n}: {\n name: string\n children: ReactNode\n}) {\n return (\n <PlacementContext.Provider value={name}>\n {children}\n </PlacementContext.Provider>\n )\n}\n\n/**\n * Warn, in development only, when `child` is not rendered inside `parent`.\n *\n * A compound component renders its children exactly as they are composed, so a\n * subcomponent put at the wrong level still renders — it only loses whatever\n * its layout depended on, and does so silently. `Slider.Thumb` outside\n * `Slider.Track` keeps its `position: absolute` but resolves it against the\n * page rather than the track, and neither the build nor the tests notice.\n *\n * @internal\n */\nexport function useCheckPlacement(child: string, parent: string) {\n const found = useContext(PlacementContext)\n\n useEffect(() => {\n try {\n // `process.env.NODE_ENV` is written out here, inline and first, so that a\n // bundler substituting it folds the comparison and drops this whole\n // block — the message strings with it. Reading the flag through a helper\n // or a module constant leaves the branch in the bundle instead: neither\n // folds, which was measured with esbuild rather than assumed.\n //\n // The read is wrapped because `process` may not exist at all. The\n // package is built with `platform: 'neutral'`, so a page loading the ESM\n // straight from a CDN has no bundler to substitute it, and a bare\n // reference would throw a `ReferenceError` mid-effect.\n if (process.env.NODE_ENV !== 'production' && found !== parent) {\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 }\n } catch {\n // No bundler substituted NODE_ENV, so there is no way to tell a\n // production build from a development one. Say nothing rather than break.\n }\n }, [found, child, parent])\n}\n","import { createContext, useContext } from 'react'\n\nimport { radian, type Scale } from '@tremolo-ui/functions'\n\nexport const viewBoxSize = 100\nexport const center = viewBoxSize / 2\n\nexport type KnobConfig = {\n value: number\n min: number\n max: number\n step: number\n scale: Scale\n startValue: number\n /** angle range [degree] */\n angleRange: number\n}\n\nexport type KnobContextValue = KnobConfig & {\n /** normalized value */\n p: number\n /** ロータリー開始位置 */\n r1: number\n /** activeLine の開始位置 */\n r2: number\n /** activeLine の終了位置 */\n r3: number\n /** ロータリー終了位置 */\n r4: number\n}\n\n/**\n * 角度から円弧上の点を求める。\n *\n * 半径は線の太さの分だけ内側に取る必要があるが、太さは ActiveLine / InactiveLine が\n * それぞれ持つため、座標はストアで先に計算せず各コンポーネント側で求める。\n */\nexport function pointOnArc(angle: number, radius: number) {\n return {\n x: center + radius * Math.cos(radian(angle - 90)),\n y: center + radius * Math.sin(radian(angle - 90)),\n }\n}\n\n/** 線の太さが viewBox からはみ出さないようにした半径 */\nexport function arcRadius(strokeWidth: number | string | undefined) {\n const width =\n typeof strokeWidth === 'number'\n ? strokeWidth\n : Number.parseFloat(String(strokeWidth))\n return Number.isFinite(width) ? center - width / 2 : center\n}\n\n/** Build an SVG path for an arc, splitting full turns into drawable segments. */\nexport function arcPath(startAngle: number, endAngle: number, radius: number) {\n const start = pointOnArc(startAngle, radius)\n const sweep = endAngle - startAngle\n const segmentCount = Math.max(1, Math.ceil(Math.abs(sweep) / 180))\n const segmentSweep = sweep / segmentCount\n let path = `M ${start.x} ${start.y}`\n\n for (let i = 1; i <= segmentCount; i += 1) {\n const end = pointOnArc(startAngle + segmentSweep * i, radius)\n path += ` A ${radius} ${radius} 0 0 ${segmentSweep >= 0 ? 1 : 0} ${end.x} ${end.y}`\n }\n\n return path\n}\n\n/** 設定から描画に必要な角度を導出する。レンダー中に呼ぶ。 */\nexport function calcAngles({\n value,\n min,\n max,\n scale,\n startValue,\n angleRange,\n}: KnobConfig) {\n const p = scale.normalize(value, min, max)\n const s = scale.normalize(startValue, min, max)\n\n const r1 = -angleRange / 2\n const r2 = r1 + Math.min(p, s) * angleRange\n const r3 = r1 + Math.max(p, s) * angleRange\n const r4 = angleRange / 2\n\n return { p, r1, r2, r3, r4 }\n}\n\nconst KnobContext = /* @__PURE__ */ createContext<KnobContextValue | null>(null)\n\nexport const KnobProvider = KnobContext.Provider\n\n/**\n * Everything here is derived during render, so there is no state to keep in\n * sync: `value` comes from the props of `Root` and the rest follows from it.\n */\nexport function useKnobContext(): KnobContextValue\nexport function useKnobContext<T>(selector: (state: KnobContextValue) => T): T\nexport function useKnobContext<T>(selector?: (state: KnobContextValue) => T) {\n const context = useContext(KnobContext)\n if (!context) throw new Error('Missing KnobContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import { SVGProps } from 'react'\n\nimport { useCheckPlacement } from '../_util/Placement'\n\nimport { arcPath, arcRadius, useKnobContext } from './context'\n\nexport function ActiveLine({\n stroke = 'currentColor',\n strokeWidth = 6,\n className,\n ...props\n}: Omit<SVGProps<SVGPathElement>, 'd'>) {\n useCheckPlacement('Knob.ActiveLine', 'Knob.SVGRoot')\n\n const r2 = useKnobContext((s) => s.r2)\n const r3 = useKnobContext((s) => s.r3)\n\n const radius = arcRadius(strokeWidth)\n\n return (\n <path\n className={className}\n d={arcPath(r2, r3, radius)}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n {...props}\n />\n )\n}\n","import { SVGProps } from 'react'\n\nimport { useCheckPlacement } from '../_util/Placement'\n\nimport { arcPath, arcRadius, useKnobContext } from './context'\n\nexport function InactiveLine({\n stroke = 'currentColor',\n strokeWidth = 6,\n className,\n ...props\n}: Omit<SVGProps<SVGPathElement>, 'd'>) {\n useCheckPlacement('Knob.InactiveLine', 'Knob.SVGRoot')\n\n const min = useKnobContext((s) => s.min)\n const max = useKnobContext((s) => s.max)\n const startValue = useKnobContext((s) => s.startValue)\n\n const r1 = useKnobContext((s) => s.r1)\n const r2 = useKnobContext((s) => s.r2)\n const r3 = useKnobContext((s) => s.r3)\n const r4 = useKnobContext((s) => s.r4)\n\n const radius = arcRadius(strokeWidth)\n\n return (\n <>\n {startValue > min && (\n <path\n className={className}\n d={arcPath(r1, r2, radius)}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n {...props}\n />\n )}\n {startValue < max && (\n <path\n className={className}\n d={arcPath(r3, r4, radius)}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n {...props}\n />\n )}\n </>\n )\n}\n","import { ReactNode, SVGProps } from 'react'\n\nimport { Placement } from '../_util/Placement'\n\nimport { viewBoxSize } from './context'\n\nexport interface KnobSVGRootProps {\n /**\n * `<Knob.InactiveLine />`, `<Knob.ActiveLine />` and `<Knob.Thumb />` go\n * here, in the order you want them painted.\n */\n children: ReactNode\n}\n\nexport function SVGRoot({\n children,\n style,\n ...props\n}: KnobSVGRootProps & Omit<SVGProps<SVGSVGElement>, keyof KnobSVGRootProps>) {\n return (\n <svg\n viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}\n style={{\n display: 'block',\n ...style,\n }}\n {...props}\n >\n <Placement name=\"Knob.SVGRoot\">{children}</Placement>\n </svg>\n )\n}\n","import { SVGProps } from 'react'\n\nimport { clamp } from '@tremolo-ui/functions'\n\nimport { useCheckPlacement } from '../_util/Placement'\n\nimport { useKnobContext, viewBoxSize } from './context'\n\nexport interface KnobThumbProps {\n /**\n * Fill colour of the circle.\n * @default 'currentColor'\n */\n thumb?: string\n /**\n * Colour of the line that points at the value.\n * @default 'currentColor'\n */\n thumbLine?: string\n /**\n * Diameter of the circle, as a percentage of the knob.\n * @default 84\n */\n thumbSize?: number\n /**\n * Thickness of the line, as a percentage of the knob.\n * @default 6\n */\n thumbLineWeight?: number\n /**\n * How far down the line reaches, as a percentage of the knob from its top.\n * The line starts at the edge of the circle.\n * @default 35\n */\n thumbLineLength?: number\n\n /**\n * Classes for what the thumb draws inside itself: `thumbLine` is the line\n * that points at the value.\n */\n classes?: {\n thumbLine?: string\n }\n}\n\nexport function Thumb({\n className,\n\n thumb = 'currentColor',\n thumbLine = 'currentColor',\n thumbSize = 84,\n thumbLineWeight = 6,\n thumbLineLength = 35,\n classes,\n\n ...props\n}: KnobThumbProps & Omit<SVGProps<SVGSVGElement>, 'd' | keyof KnobThumbProps>) {\n useCheckPlacement('Knob.Thumb', 'Knob.SVGRoot')\n\n const angleRange = useKnobContext((s) => s.angleRange)\n\n const p = useKnobContext((s) => s.p)\n const r1 = useKnobContext((s) => s.r1)\n\n return (\n <svg className={className} {...props}>\n <circle cx=\"50%\" cy=\"50%\" r={`${thumbSize / 2}%`} fill={thumb} />\n <line\n className={classes?.thumbLine}\n x1=\"50%\"\n y1={`${(viewBoxSize - clamp(thumbSize, 0, 100)) / 2}%`}\n x2=\"50%\"\n y2={`${thumbLineLength}%`}\n stroke={thumbLine}\n strokeWidth={`${thumbLineWeight}%`}\n // NOTE\n // https://bugs.webkit.org/show_bug.cgi?id=201854\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform-origin#browser_compatibility\n style={{\n transform: `rotate(${r1 + p * angleRange}deg)`,\n transformOrigin: '50% 50%',\n }}\n />\n </svg>\n )\n}\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react'\n\nimport type { AxisOptions, XY } from '@tremolo-ui/dom'\nimport {\n applyDelta,\n type InputEventOption,\n type ModifierValue,\n selectModifier,\n linearScale,\n type Scale,\n type ValueRange,\n} from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { useCheckSteps } from '../../hooks/_internal/useCheckSteps'\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport {\n DEFAULT_DRAG_SENSITIVITY,\n DEFAULT_KEYBOARD_OPTIONS,\n DEFAULT_WHEEL_OPTIONS,\n} from '../../input-event'\nimport { cssLength } from '../_util/css-length'\n\nimport { ActiveLine } from './ActiveLine'\nimport { calcAngles, KnobProvider } from './context'\nimport { InactiveLine } from './InactiveLine'\nimport { SVGRoot } from './SVGRoot'\nimport { Thumb } from './Thumb'\n\nconst defaultExternalStyles: KnobProps['externalStyles'] = {\n cursor: 'grabbing',\n}\n\nexport interface KnobProps {\n /** The current value. The knob shows only this, so update it from `onChange`. */\n value: number\n /** The value with the knob turned all the way down. */\n min: number\n /** The value with the knob turned all the way up. */\n max: number\n\n /**\n * Granularity of the value. A drag, the wheel and the arrow keys snap it to\n * multiples of `step`.\n *\n * @default 1\n */\n step?: number\n /**\n * How the value is distributed across the travel.\n *\n * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,\n * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or\n * `skewScale(n)` for a value that has to match a JUCE parameter.\n *\n * @default linearScale\n */\n scale?: Scale\n /**\n * The value a double click restores, while `enableDoubleClickDefault` is on.\n * @default min\n */\n defaultValue?: number\n\n /**\n * Where the active arc starts. Put it at the centre of a bipolar control,\n * such as a pan knob, so that the arc grows from there either way.\n * @default min\n */\n startValue?: number\n\n /**\n * Width and height of the knob. Sets `--knob-size`; the size the theme\n * gives it stands when this is omitted.\n */\n size?: number | string\n\n /**\n * The cursor to show while dragging. It is set on the dragged element, so it\n * stays while the pointer is outside the knob.\n *\n * @default { cursor: 'grabbing' }\n */\n externalStyles?: {\n cursor?: CSSProperties['cursor']\n }\n /**\n * How much one notch of the wheel moves the value. It only acts while the\n * focus is inside, so that scrolling the page past the knob leaves it alone.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range between `min` and `max`. The result is snapped to `step`, except for\n * an amount set on a modifier key (`{ default: …, shift: … }`). `null` turns\n * the wheel off.\n *\n * @default ['raw', 1]\n */\n wheel?: ModifierValue<InputEventOption> | null\n /**\n * How much a drag moves the value, per modifier key.\n *\n * `1` is the normal travel of 100px for the whole range; `0.1` makes the\n * same movement cover a tenth of it. Shift is bound to `0.1` by default, to\n * match what it does on the arrow keys.\n *\n * Pressing or releasing the key mid-drag does not disturb the value: the\n * travel so far is kept and the new sensitivity applies from there. It takes\n * effect on the next movement, since a key on its own produces no pointer\n * event.\n *\n * @default { default: 1, shift: 0.1 }\n */\n dragSensitivity?: ModifierValue<number>\n\n /**\n * Hide the cursor while dragging and read the pointer movement directly,\n * rather than letting it wander off across the screen.\n *\n * A knob does not care where the pointer is, only how far it moved, and\n * letting it wander costs twice: the cursor ends up far from the knob it is\n * holding, and **the drag stops at the edge of the screen**, where the\n * operating system pins the pointer and the coordinates stop changing. A\n * `dragSensitivity` below 1 reaches that edge quickly.\n *\n * Off by default because it is not free: the browser shows its own notice,\n * Esc takes the lock back, and the request needs a user gesture and can be\n * refused. A refused request is not an error — the drag simply carries on as\n * an ordinary one.\n *\n * @default false\n */\n pointerLock?: boolean\n\n /**\n * How much one arrow key press moves the value.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range between `min` and `max`. The result is snapped to `step`, except for\n * an amount set on a modifier key, which is what lets shift move off the\n * grid. `null` turns the arrow keys off.\n *\n * The default moves by 1, and by 0.1 with shift. With a `step` above 1, raise\n * the amount to match: 1 would round straight back to where it started, and\n * a development build warns about it.\n *\n * @default { default: ['raw', 1], shift: ['raw', 0.1] }\n */\n keyboard?: ModifierValue<InputEventOption> | null\n /**\n * Restore `defaultValue` on a double click.\n * @default true\n */\n enableDoubleClickDefault?: boolean\n\n /**\n * Make the knob unchangeable and remove it from the tab order.\n * The parts carry `data-disabled` while it is set.\n */\n disabled?: boolean\n /**\n * Make the knob unchangeable while leaving it focusable.\n * The parts carry `data-readonly` while it is set.\n */\n readonly?: boolean\n\n /**\n * How far the knob turns from `min` to `max`, in degrees, centred on the\n * top.\n * @default 270\n */\n angleRange?: number\n\n /**\n * Called with the new value when a drag, the wheel, an arrow key or a double\n * click moves it.\n */\n onChange?: (value: number) => void\n\n /**\n * The knob renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <Knob.Root value={value} min={0} max={100} onChange={setValue}>\n * <Knob.SVGRoot>\n * <Knob.InactiveLine />\n * <Knob.ActiveLine />\n * <Knob.Thumb />\n * </Knob.SVGRoot>\n * </Knob.Root>\n */\n children: ReactNode\n}\n\nexport interface KnobMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = KnobProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KnobProps>\n\n/**\n * The wheel only acts while the focus is inside, so that scrolling a page past\n * the control does not change its value.\n */\nconst WHEEL_OPTIONS = { requireFocus: true }\n\nexport const Root = /* @__PURE__ */ forwardRef<KnobMethods, Props>(\n (\n {\n value,\n min,\n max,\n step = 1,\n scale = linearScale,\n defaultValue = min,\n startValue = min,\n size,\n externalStyles: _externalStyles,\n wheel = DEFAULT_WHEEL_OPTIONS,\n keyboard = DEFAULT_KEYBOARD_OPTIONS,\n dragSensitivity = DEFAULT_DRAG_SENSITIVITY,\n pointerLock = false,\n enableDoubleClickDefault = true,\n disabled = false,\n readonly = false,\n angleRange = 270,\n onChange,\n onKeyDown,\n onPointerDown,\n onDoubleClick,\n className,\n style,\n children,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n const elmRef = useRef<HTMLElement | SVGElement>(null)\n\n const externalStyles = { ...defaultExternalStyles, ..._externalStyles }\n const inactive = disabled || readonly\n\n // --- internal functions ---\n const range: ValueRange = useMemo(\n () => ({ min, max, step, scale }),\n [min, max, step, scale],\n )\n\n useCheckSteps({ component: 'Knob', range, keyboard, wheel })\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLOrSVGElement>) => {\n if (!keyboard || !onChange || inactive) return\n const key = event.key\n if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {\n event.preventDefault()\n const direction = key === 'ArrowRight' || key === 'ArrowUp' ? 1 : -1\n onChange(applyDelta(value, direction, keyboard, range, event))\n }\n },\n [keyboard, onChange, inactive, value, range],\n )\n\n // --- hooks ---\n // The knob has no travel of its own: the value moves away from where it\n // stood when the drag started, 100px of movement spanning the whole range.\n // Only the vertical axis carries a value, reversed so that dragging up\n // raises it.\n const axis = useMemo(\n (): XY<AxisOptions> => [range, { ...range, reverse: true }],\n [range],\n )\n\n const { refCallback: dragRefCallback, dragging } = useDragValue<\n HTMLElement | SVGElement\n >({\n axis,\n getValue: () => [value, value],\n sensitivity: (state) =>\n selectModifier(dragSensitivity, state.event).value,\n threshold: 1,\n cursor: inactive ? undefined : externalStyles.cursor,\n pointerLock: inactive ? false : pointerLock,\n shouldStart: () => !inactive,\n onChange: (v) => {\n if (inactive) return\n onChange?.(v[1])\n },\n })\n\n const wheelRefCallback = useWheel<HTMLElement>((event) => {\n if (!wheel || inactive) return\n event.preventDefault()\n if (!onChange || event.deltaY === 0) return\n onChange(applyDelta(value, -Math.sign(event.deltaY), wheel, range, event))\n }, WHEEL_OPTIONS)\n\n // Composed once, so React attaches the refs a single time instead of\n // detaching and re-attaching on every render.\n const rootRefCallback = useComposedRefs<HTMLElement | SVGElement>(\n elmRef,\n dragRefCallback,\n wheelRefCallback,\n )\n\n const context = useMemo(() => {\n const config = { value, min, max, step, scale, startValue, angleRange }\n return { ...config, ...calcAngles(config) }\n }, [value, min, max, step, scale, startValue, angleRange])\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n if (!disabled) elmRef.current?.focus()\n },\n blur() {\n elmRef.current?.blur()\n },\n }\n }, [disabled])\n\n return (\n <KnobProvider value={context}>\n <div\n ref={rootRefCallback}\n className={className}\n tabIndex={disabled ? -1 : 0}\n role=\"slider\"\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-disabled={disabled}\n aria-readonly={readonly}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n data-dragging={dragging ? '' : undefined}\n style={\n {\n '--knob-size': cssLength(size),\n ...style,\n } as CSSProperties\n }\n onPointerDown={onPointerDown}\n onDoubleClick={(event) => {\n if (!inactive && enableDoubleClickDefault && onChange) {\n onChange(defaultValue)\n }\n onDoubleClick?.(event)\n }}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n {...props}\n >\n {children}\n </div>\n </KnobProvider>\n )\n },\n)\n\n/**\n * Interactive rotary knob component implemented in SVG.\n */\nexport const Knob = {\n Root,\n SVGRoot,\n InactiveLine,\n ActiveLine,\n Thumb,\n}\n\nexport { useKnobContext, type KnobContextValue } from './context'\nexport { type KnobSVGRootProps } from './SVGRoot'\nexport { type KnobThumbProps } from './Thumb'\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type {\n InputEventOption,\n ModifierState,\n ModifierValue,\n Scale,\n ValueRange,\n} from '@tremolo-ui/functions'\n\nexport type NumberInputContextValue = {\n value: number\n\n /**\n * The range the caller asked for. Left undefined when unbounded, which is\n * what `aria-valuemin` / `aria-valuemax` and the steppers need to tell apart\n * from a range that happens to sit at the edge of the safe integers.\n */\n min?: number\n max?: number\n step: number\n /** How the value is distributed across the travel. */\n scale: Scale\n\n disabled: boolean\n readonly: boolean\n clampValue: boolean\n\n /**\n * The effective scaling for `applyDelta`, with unbounded ends filled in.\n * Ignores `min` / `max` when `clampValue` is off.\n */\n range: ValueRange\n /** The effective range for raw input, whose open ends cover finite numbers. */\n rawRange: ValueRange\n\n keyboard: ModifierValue<InputEventOption> | null\n /** Pixels of vertical drag on `Stepper` that move the value by one `step`. */\n drag: number | null\n /** How much a `Stepper` drag counts, per modifier key. */\n dragSensitivity: ModifierValue<number>\n /** Whether a `Stepper` drag hides the pointer and reads its movement. */\n pointerLock: boolean\n\n /** What `InputField` selects when it takes focus. */\n selectOnFocus: 'all' | 'number' | 'none'\n /** Whether `InputField` shows the plain value while it has focus. */\n unformatOnFocus: boolean\n /** Whether `InputField` puts the caret back after an arrow key steps the value. */\n keepCaretOnStep: boolean\n /** Whether Enter leaves `InputField` as well as committing. */\n blurOnEnter: boolean\n\n /** What the input shows: the draft while editing, the formatted value otherwise. */\n text: string\n editing: boolean\n /** Whether the value sits outside `min` / `max`. Not judged while editing. */\n outOfRange: boolean\n /** Whether a stepper would have no effect, for `aria-disabled`. */\n atMin: boolean\n atMax: boolean\n\n format: (value: number) => string\n parse: (text: string) => number\n\n /** Typing. Replaces the draft and reports the parsed value, unclamped. */\n setDraft: (text: string) => void\n /** Blur or Enter. Optionally clamps the draft, reports it, and drops it. */\n commitDraft: () => void\n /** Drops the draft and replaces the value: steppers, wheel, keyboard, drag. */\n changeValue: (next: number) => void\n /** Moves the value by one `option` in `direction`, normally +1 or -1. */\n nudge: (\n direction: number,\n option: ModifierValue<InputEventOption>,\n modifiers?: ModifierState,\n ) => void\n\n /** `InputField` registers itself here; `Root` focuses it through its methods. */\n inputRef: RefObject<HTMLInputElement | null>\n}\n\nconst NumberInputContext =\n /* @__PURE__ */ createContext<NumberInputContextValue | null>(null)\n\nexport const NumberInputProvider = NumberInputContext.Provider\n\n/**\n * The only state behind this is the editing draft; `value` comes from the props\n * of `Root` and everything else is derived during render.\n */\nexport function useNumberInputContext(): NumberInputContextValue\nexport function useNumberInputContext<T>(\n selector: (state: NumberInputContextValue) => T,\n): T\nexport function useNumberInputContext<T>(\n selector?: (state: NumberInputContextValue) => T,\n) {\n const context = useContext(NumberInputContext)\n if (!context)\n throw new Error('Missing NumberInputContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n\n/** Set by `Stepper` once a drag has actually moved, so the steppers stand down. */\nexport type StepperContextValue = {\n draggingRef: RefObject<boolean>\n}\n\nconst StepperContext =\n /* @__PURE__ */ createContext<StepperContextValue | null>(null)\n\nexport const StepperProvider = StepperContext.Provider\n\nexport function useStepperContext(): StepperContextValue | null {\n return useContext(StepperContext)\n}\n","import { useCallback, useEffect, useRef } from 'react'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\ntype Target = EventTarget | null | (() => EventTarget | null)\ntype Options = boolean | AddEventListenerOptions\n\nexport function useEventListener<K extends keyof DocumentEventMap>(\n target: Target,\n event: K,\n handler: (event: DocumentEventMap[K]) => void,\n options?: Options,\n): VoidFunction\nexport function useEventListener<K extends keyof WindowEventMap>(\n target: Target,\n event: K,\n handler: (event: WindowEventMap[K]) => void,\n options?: Options,\n): VoidFunction\nexport function useEventListener<K extends keyof GlobalEventHandlersEventMap>(\n target: Target,\n event: K,\n handler: (event: GlobalEventHandlersEventMap[K]) => void,\n options?: Options,\n): VoidFunction\nexport function useEventListener(\n target: Target,\n event: string,\n handler: (event: Event) => void,\n options?: Options,\n) {\n const listener = useCallbackRef(handler)\n const cleanupRef = useRef<VoidFunction>(() => {})\n\n useEffect(() => {\n const node = typeof target === 'function' ? target() : (target ?? document)\n\n if (!node) return\n\n node.addEventListener(event, listener, options)\n const cleanup = () => {\n node.removeEventListener(event, listener, options)\n }\n cleanupRef.current = cleanup\n\n return () => {\n cleanup()\n if (cleanupRef.current === cleanup) cleanupRef.current = () => {}\n }\n }, [event, target, options, listener])\n\n return useCallback(() => cleanupRef.current(), [])\n}\n","import { useEffect, useRef } from 'react'\n\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback)\n\n // Remember the latest callback if it changes.\n useEffect(() => {\n savedCallback.current = callback\n }, [callback])\n\n // Set up the interval.\n useEffect(() => {\n // Don't schedule if no delay is specified.\n // Note: 0 is a valid value for delay.\n if (delay === null) {\n return\n }\n\n const id = setInterval(() => {\n savedCallback.current()\n }, delay)\n\n return () => {\n clearInterval(id)\n }\n }, [delay])\n}\n","import { useCallback, useRef, useState } from 'react'\n\nimport { useEventListener } from './useEventListener'\nimport { useInterval } from './useInterval'\n\nexport function useLongPress(\n callback: () => void,\n initialDelay = 500,\n interval = 40,\n) {\n const [pressed, setPressed] = useState(false)\n const [delay, setDelay] = useState(initialDelay)\n const activePointerId = useRef<number | null>(null)\n const isPressed = useRef(false)\n\n useInterval(\n () => {\n callback()\n setDelay(interval)\n },\n pressed ? delay : null,\n )\n\n const stop = useCallback(\n (pointerId?: number) => {\n if (!isPressed.current) return\n if (\n pointerId !== undefined &&\n activePointerId.current !== null &&\n activePointerId.current !== pointerId\n )\n return\n\n isPressed.current = false\n activePointerId.current = null\n setPressed(false)\n setDelay(initialDelay)\n },\n [initialDelay],\n )\n\n useEventListener(globalThis.window, 'pointerup', (event) => {\n stop(event.pointerId)\n })\n\n useEventListener(globalThis.window, 'pointercancel', (event) => {\n stop(event.pointerId)\n })\n\n useEventListener(globalThis.window, 'blur', () => {\n stop()\n })\n\n return useCallback(\n (event?: Pick<PointerEvent, 'button' | 'pointerId'>) => {\n if (isPressed.current || (event && event.button !== 0)) return\n\n isPressed.current = true\n activePointerId.current = event?.pointerId ?? null\n callback()\n setPressed(true)\n },\n [callback],\n )\n}\n","import { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react'\n\nimport { useLongPress } from '../../hooks/useLongPress'\n\nimport { useNumberInputContext, useStepperContext } from './context'\n\nexport interface StepperButtonProps {\n className?: string\n style?: CSSProperties\n /** Replaces the default arrow. Size it with the `--stepper-icon-size` variable. */\n children?: ReactNode\n}\n\ntype Props = StepperButtonProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof StepperButtonProps>\n\n/**\n * Shared body of `IncrementStepper` and `DecrementStepper`: the two differ only\n * in which way they move the value and which arrow they draw.\n */\nexport function StepperButton({\n direction,\n variant,\n icon,\n className,\n style,\n children,\n onPointerDown,\n ...props\n}: Props & {\n direction: 1 | -1\n variant: 'increment' | 'decrement'\n icon: ReactNode\n}) {\n const { step, disabled, readonly, atMin, atMax, nudge } =\n useNumberInputContext()\n const stepper = useStepperContext()\n\n // Not memoized: the callback reads `draggingRef.current`, which the compiler\n // cannot line up with a manual dependency list. `useLongPress` only ever\n // calls it through a ref, so a fresh identity per render costs nothing.\n const press = useLongPress(() => {\n // Once the pointer has actually travelled, the drag on `Stepper` owns the\n // value; repeating on top of it would move it twice.\n if (stepper?.draggingRef.current) return\n nudge(direction, ['raw', step])\n })\n\n return (\n <div\n className={className}\n role=\"button\"\n tabIndex={-1}\n // A bare arrow has no accessible name of its own. Overridable, since a\n // caller may need it in their own language.\n aria-label={direction > 0 ? 'Increment' : 'Decrement'}\n aria-disabled={disabled || (direction > 0 ? atMax : atMin)}\n // `role=\"button\"` does not take aria-readonly, so the state reaches the\n // styles through the data attribute alone.\n data-disabled={\n disabled || (direction > 0 ? atMax : atMin) ? '' : undefined\n }\n data-readonly={readonly ? '' : undefined}\n style={style}\n onPointerDown={(event) => {\n if (!disabled && !readonly) press(event)\n onPointerDown?.(event)\n }}\n {...props}\n >\n {children ?? icon}\n </div>\n )\n}\n\nexport function StepperArrow({ up }: { up: boolean }) {\n return (\n <svg\n // The arrow the component draws when no children are given, so it sizes\n // itself rather than asking a stylesheet to.\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 strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points={up ? '18 15 12 9 6 15' : '6 9 12 15 18 9'} />\n </svg>\n )\n}\n","import { ComponentPropsWithoutRef } from 'react'\n\nimport {\n StepperArrow,\n StepperButton,\n StepperButtonProps,\n} from './StepperButton'\n\n// An interface rather than an alias; see `NumberInputIncrementStepperProps`.\nexport interface NumberInputDecrementStepperProps extends StepperButtonProps {}\n\n/** Lowers the value by one `step`, repeating while held. */\nexport function DecrementStepper(\n props: NumberInputDecrementStepperProps &\n Omit<\n ComponentPropsWithoutRef<'div'>,\n keyof NumberInputDecrementStepperProps\n >,\n) {\n return (\n <StepperButton\n direction={-1}\n variant=\"decrement\"\n icon={<StepperArrow up={false} />}\n {...props}\n />\n )\n}\n","import { ComponentPropsWithoutRef } from 'react'\n\nimport {\n StepperArrow,\n StepperButton,\n StepperButtonProps,\n} from './StepperButton'\n\n// An interface rather than an alias, so that typedoc lists the props: the\n// shared `StepperButtonProps` is not exported for it to follow.\nexport interface NumberInputIncrementStepperProps extends StepperButtonProps {}\n\n/** Raises the value by one `step`, repeating while held. */\nexport function IncrementStepper(\n props: NumberInputIncrementStepperProps &\n Omit<\n ComponentPropsWithoutRef<'div'>,\n keyof NumberInputIncrementStepperProps\n >,\n) {\n return (\n <StepperButton\n direction={1}\n variant=\"increment\"\n icon={<StepperArrow up />}\n {...props}\n />\n )\n}\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react'\n\nimport { useComposedRefs } from '../../compose-refs'\n\nimport { useNumberInputContext } from './context'\n\nexport interface NumberInputInputFieldProps {\n className?: string\n style?: CSSProperties\n}\n\ntype Props = NumberInputInputFieldProps &\n Omit<\n ComponentPropsWithoutRef<'input'>,\n keyof NumberInputInputFieldProps | 'type' | 'value' | 'defaultValue'\n >\n\n/** The leading number of the displayed text, whatever the format put around it. */\nconst NUMBER_PREFIX = /^\\s*-?[\\d.,]*/\n\nconst numberEnd = (text: string) =>\n text.match(NUMBER_PREFIX)?.[0].length ?? text.length\n\n/**\n * The index the caret is measured against: the decimal point, or where one\n * would go if the number has none.\n *\n * Measuring from an end instead would slide the caret across a digit whenever\n * the number changed length — `9.9` to `10.0` gains a character in front, `10`\n * to `9` loses one — which is exactly what stepping does.\n */\nconst decimalAnchor = (text: string) => {\n const dot = text.indexOf('.')\n return dot === -1 ? numberEnd(text) : dot\n}\n\n/**\n * The text field of a `NumberInput`, and the only place the value can be typed.\n *\n * While the user types, their own text stands rather than `format(value)`, so\n * that a half-finished entry is not rewritten under the caret.\n *\n * How it behaves on focus, Enter and the arrow keys is set on `Root`\n * (`selectOnFocus`, `unformatOnFocus`, `keepCaretOnStep`, `blurOnEnter`).\n */\nexport const InputField = /* @__PURE__ */ forwardRef<HTMLInputElement, Props>(\n function InputField(\n { className, style, onFocus, onBlur, onKeyDown, ...props },\n forwardedRef,\n ) {\n const {\n value,\n min,\n max,\n step,\n disabled,\n readonly,\n keyboard,\n selectOnFocus,\n unformatOnFocus,\n keepCaretOnStep,\n blurOnEnter,\n text,\n editing,\n outOfRange,\n setDraft,\n commitDraft,\n nudge,\n inputRef,\n } = useNumberInputContext()\n\n const [focused, setFocused] = useState(false)\n\n // Only until the first keystroke: from then on the draft is the user's own\n // text and stands on its own, formatted or not.\n const shown = unformatOnFocus && focused && !editing ? String(value) : text\n\n // Selecting has to wait for that swap. Called from the focus handler it\n // would run against the formatted text still in the input and cover the\n // wrong characters.\n useEffect(() => {\n if (!focused || selectOnFocus === 'none') return\n const input = inputRef.current\n if (!input) return\n if (selectOnFocus === 'all') {\n input.setSelectionRange(0, input.value.length)\n } else {\n input.setSelectionRange(\n 0,\n input.value.match(NUMBER_PREFIX)?.[0].length ?? 0,\n )\n }\n // Deliberately not re-run as the text changes: that would drag the\n // selection back over what the user is typing.\n }, [focused, selectOnFocus, inputRef])\n\n /**\n * Where to put the caret once the stepped value has been rendered, and the\n * text it was measured against.\n */\n const caretAfterStep = useRef<{ offset: number; from: string } | null>(null)\n\n // A layout effect rather than a plain one: the caret is moved before the\n // browser paints, so it is never seen at the end of the text first.\n useLayoutEffect(() => {\n const pending = caretAfterStep.current\n if (!pending) return\n caretAfterStep.current = null\n\n const input = inputRef.current\n // The step may have been clamped away, leaving the text as it was. The\n // caret has not moved either, since the key press was prevented.\n if (!input || input.value === pending.from) return\n\n const place = decimalAnchor(input.value) + pending.offset\n const caret = Math.max(0, Math.min(place, numberEnd(input.value)))\n input.setSelectionRange(caret, caret)\n })\n\n const composedRef = useComposedRefs<HTMLInputElement>(\n forwardedRef,\n inputRef,\n )\n\n return (\n <input\n ref={composedRef}\n className={className}\n // Not type=\"number\": that brings native spinners and a value the browser\n // parses itself, neither of which survives a unit suffix.\n type=\"text\"\n inputMode=\"decimal\"\n role=\"spinbutton\"\n value={shown}\n disabled={disabled}\n readOnly={readonly}\n aria-disabled={disabled}\n aria-readonly={readonly}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n // The formatted text, even while the field shows the plain number: it is\n // the one that says what the value means.\n aria-valuetext={text}\n step={step}\n data-out-of-range={outOfRange ? '' : undefined}\n style={style}\n onChange={(event) => {\n // The text is the user's own now, so a caret measured against the\n // stepped one no longer means anything.\n caretAfterStep.current = null\n setDraft(event.currentTarget.value)\n }}\n onFocus={(event) => {\n setFocused(true)\n onFocus?.(event)\n }}\n onBlur={(event) => {\n setFocused(false)\n // Nothing was typed, so there is no draft and this returns at once —\n // taking focus and leaving again never commits anything.\n commitDraft()\n onBlur?.(event)\n }}\n onKeyDown={(event) => {\n const key = event.key\n if (key === 'Enter') {\n commitDraft()\n if (blurOnEnter) event.currentTarget.blur()\n } else if (\n keyboard &&\n !disabled &&\n !readonly &&\n (key === 'ArrowUp' || key === 'ArrowDown') &&\n // Arrow keys pick a candidate while an IME is converting. Stepping\n // the value there would fight the conversion, and moving the caret\n // would break it outright.\n !event.nativeEvent.isComposing\n ) {\n event.preventDefault()\n const input = event.currentTarget\n if (keepCaretOnStep && input.selectionStart !== null) {\n caretAfterStep.current = {\n offset: input.selectionStart - decimalAnchor(input.value),\n from: input.value,\n }\n }\n nudge(key === 'ArrowUp' ? 1 : -1, keyboard, event)\n }\n onKeyDown?.(event)\n }}\n {...props}\n />\n )\n },\n)\n","import { useEffect, useState } from 'react'\n\nimport { createDrag, type DragState } from '@tremolo-ui/dom'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\ninterface UseDragProps {\n /**\n * Threshold at which the onDrag event fires.\n * Prevents onDrag events from firing, for example, when double-clicking.\n */\n threshold?: number\n\n /** CSS cursor to show while dragging. Applied to the element itself. */\n cursor?: string\n\n /**\n * Hide the pointer and read its movement directly, instead of following it\n * around the screen.\n *\n * @see DragOptions.pointerLock\n * @default false\n */\n pointerLock?: boolean\n\n /**\n * @param state the whole drag, for anything the four numbers leave out —\n * the pointer event and its modifier keys, most of all.\n */\n onDrag?: (\n x: number,\n y: number,\n deltaX: number,\n deltaY: number,\n state: DragState,\n ) => void\n onDragStart?: (state: DragState) => void\n onDragEnd?: (state: DragState) => void\n}\n\n/**\n * Track a pointer drag on an element.\n *\n * @returns a ref callback to attach to the element being dragged\n */\nexport function useDrag<T extends Element>({\n threshold = 1,\n cursor,\n pointerLock,\n onDrag,\n onDragStart,\n onDragEnd,\n}: UseDragProps): (node: T | null) => void {\n const dragHandler = useCallbackRef(onDrag)\n const dragStartHandler = useCallbackRef(onDragStart)\n const dragEndHandler = useCallbackRef(onDragEnd)\n\n // The node is held in state rather than bound in the ref callback itself, so\n // that re-attaching the ref with the same node does not restart the drag.\n // React re-attaches on every render when the caller passes an inline ref.\n const [node, setNode] = useState<T | null>(null)\n\n useEffect(() => {\n if (!node) return\n\n const instance = createDrag(node, {\n threshold,\n cursor,\n pointerLock,\n onDragStart: (state) => dragStartHandler(state),\n onDrag: (state) =>\n dragHandler(state.x, state.y, state.deltaX, state.deltaY, state),\n onDragEnd: (state) => dragEndHandler(state),\n })\n\n return () => instance.destroy()\n }, [\n node,\n threshold,\n cursor,\n pointerLock,\n dragHandler,\n dragStartHandler,\n dragEndHandler,\n ])\n\n return setNode\n}\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useMemo,\n useRef,\n} from 'react'\n\nimport {\n applyDelta,\n mapModifier,\n selectModifier,\n type InputEventOption,\n} from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { useDrag } from '../../hooks/useDrag'\n\nimport { StepperProvider, useNumberInputContext } from './context'\n\nexport interface NumberInputStepperProps {\n className?: string\n style?: CSSProperties\n /** `<NumberInput.IncrementStepper />` and `<NumberInput.DecrementStepper />` go here. */\n children?: ReactNode\n}\n\ntype Props = NumberInputStepperProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof NumberInputStepperProps>\n\n/**\n * The area the steppers sit in, and a drag handle in its own right: dragging it\n * up and down moves the value one `step` every `drag` pixels.\n *\n * The drag lives here rather than on `InputField` because `createDrag` turns\n * off text selection on whatever element it is attached to.\n */\nexport const Stepper = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(\n function Stepper({ className, style, children, ...props }, forwardedRef) {\n const {\n value,\n step,\n disabled,\n readonly,\n drag,\n dragSensitivity,\n pointerLock,\n rawRange,\n changeValue,\n } = useNumberInputContext()\n const inactive = disabled || readonly\n\n /**\n * The sensitivity as an amount per `drag` pixels, so that the drag goes\n * through the same `applyDelta` the wheel and the arrow keys do. Carrying\n * the modifier map over rather than resolving it here is what keeps `step`\n * out of the pipeline for a modifier entry — naming one is a request to move\n * off the grid.\n */\n const dragOptions = useMemo(\n () =>\n mapModifier(dragSensitivity, (factor): InputEventOption => [\n 'raw',\n step * factor,\n ]),\n [dragSensitivity, step],\n )\n\n /**\n * Set once the drag has actually moved the value, so that the press-and-hold\n * repeat of a stepper stands down and leaves the value to the drag. A ref,\n * because it is read from inside the repeat rather than rendered.\n */\n const draggingRef = useRef(false)\n /**\n * Where the drag started, taken on the first move rather than on pointer\n * down: the steppers act on pointer down, so by then the value may already\n * have been nudged once, and the drag should carry on from there.\n */\n const originRef = useRef<{ y: number; value: number } | null>(null)\n /**\n * Which modifier the drag is currently counting at, and where the previous\n * event was — a key produces no pointer event of its own, so a change is\n * only seen on the next move and has to be dated back to the one before it.\n */\n const factorRef = useRef<number>(1)\n const previousYRef = useRef(0)\n\n const dragRefCallback = useDrag<HTMLDivElement>({\n threshold: 1,\n cursor: inactive ? undefined : 'ns-resize',\n pointerLock: inactive ? false : pointerLock,\n onDragStart: (state) => {\n originRef.current = null\n draggingRef.current = false\n factorRef.current = selectModifier(dragSensitivity, state.event).value\n },\n onDrag: (_x, y, _dx, _dy, state) => {\n if (inactive || drag === null) return\n if (!originRef.current) {\n originRef.current = { y, value }\n previousYRef.current = y\n return\n }\n\n // Pressing or releasing the key mid-drag must not move the value, so the\n // travel so far is folded into the origin and measuring starts again\n // from the previous event: that event's own distance belongs to the new\n // sensitivity.\n const factor = selectModifier(dragSensitivity, state.event).value\n if (factor !== factorRef.current) {\n originRef.current = { y: previousYRef.current, value }\n factorRef.current = factor\n }\n previousYRef.current = y\n\n // Dragging up raises the value, as on a knob.\n const steps = Math.round(-(y - originRef.current.y) / drag)\n if (steps === 0) return\n draggingRef.current = true\n // The same pipeline the wheel and the arrow keys use. Counting from where\n // the drag started keeps it from accumulating a rounding error.\n changeValue(\n applyDelta(\n originRef.current.value,\n steps,\n dragOptions,\n rawRange,\n state.event,\n ),\n )\n },\n onDragEnd: () => {\n draggingRef.current = false\n },\n })\n\n const composedRef = useComposedRefs<HTMLDivElement>(\n forwardedRef,\n drag !== null && !inactive ? dragRefCallback : undefined,\n )\n\n const context = useMemo(() => ({ draggingRef }), [])\n\n return (\n <StepperProvider value={context}>\n <div ref={composedRef} className={className} style={style} {...props}>\n {children}\n </div>\n </StepperProvider>\n )\n },\n)\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport {\n applyDelta,\n InputEventOption,\n ModifierState,\n type ModifierValue,\n linearScale,\n selectInputEvent,\n type Scale,\n type ValueRange,\n} from '@tremolo-ui/functions'\n\nimport { useCheckSteps } from '../../hooks/_internal/useCheckSteps'\nimport { useWheel } from '../../hooks/useWheel'\nimport {\n DEFAULT_DRAG_SENSITIVITY,\n DEFAULT_KEYBOARD_OPTIONS,\n DEFAULT_WHEEL_OPTIONS,\n} from '../../input-event'\n\nimport { NumberInputProvider } from './context'\nimport { DecrementStepper } from './DecrementStepper'\nimport { IncrementStepper } from './IncrementStepper'\nimport { InputField } from './InputField'\nimport { Stepper } from './Stepper'\n\nexport interface NumberInputProps {\n /**\n * The value. What the input shows is `format(value)`, except while the user\n * is typing, when their own text stands until it is committed.\n */\n value: number\n\n /**\n * Lowest value. Leave it out for no lower bound.\n *\n * It is enforced when a value is committed or stepped, while `clampValue` is\n * on. A value below it carries `data-out-of-range` on `InputField`.\n */\n min?: number\n /**\n * Highest value. Leave it out for no upper bound.\n *\n * It is enforced when a value is committed or stepped, while `clampValue` is\n * on. A value above it carries `data-out-of-range` on `InputField`.\n */\n max?: number\n /**\n * Granularity of the value. The steppers, a drag on `Stepper`, the wheel and\n * the arrow keys snap it to multiples of `step`; a typed value is left as it\n * is.\n *\n * @default 1\n */\n step?: number\n /**\n * How the value is distributed across the travel of a drag or a\n * `'normalized'` wheel / keyboard nudge.\n *\n * @default linearScale\n */\n scale?: Scale\n\n /**\n * Render the value as text. Plain digits by default.\n *\n * `unitFormat` from `@tremolo-ui/functions` builds this and `parse` together\n * for a unit, as a pair to spread into the root.\n *\n * @example\n * <NumberInput.Root {...unitFormat('Hz', { digits: 2 })} value={v} />\n */\n format?: (value: number) => string\n /**\n * Read a value back out of the text. Has to undo `format`.\n *\n * Text with no number in it reads as `NaN`, which leaves the value alone.\n */\n parse?: (text: string) => number\n\n /**\n * Keep the value within `min` and `max` when it is committed or stepped.\n * Typing is never clamped, so that a value can be entered digit by digit.\n * @default true\n */\n clampValue?: boolean\n\n /**\n * How much one notch of the wheel moves the value. It only acts while the\n * focus is inside, so that scrolling the page past the input leaves it\n * alone.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range between `min` and `max`. The result is snapped to `step`, except for\n * an amount set on a modifier key (`{ default: …, shift: … }`). `null` turns\n * the wheel off.\n *\n * @default ['raw', 1]\n */\n wheel?: ModifierValue<InputEventOption> | null\n /**\n * How much one arrow key press moves the value.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range between `min` and `max`. The result is snapped to `step`, except for\n * an amount set on a modifier key, which is what lets shift move off the\n * grid. `null` turns the arrow keys off.\n *\n * The default moves by 1, and by 0.1 with shift. With a `step` above 1, raise\n * the amount to match: 1 would round straight back to where it started, and\n * a development build warns about it.\n *\n * @default { default: ['raw', 1], shift: ['raw', 0.1] }\n */\n keyboard?: ModifierValue<InputEventOption> | null\n /**\n * Pixels of vertical drag on `Stepper` that move the value by one `step`.\n * `null` turns the drag off.\n * @default 1\n */\n drag?: number | null\n\n /**\n * How much a `Stepper` drag counts, per modifier key.\n *\n * `1` is `drag` pixels per `step`; `0.1` makes the same movement cover a\n * tenth of that. Shift is bound to `0.1` by default, to match what it does\n * on the arrow keys.\n *\n * A modifier entry is not snapped to `step`, which is what lets a finer\n * amount move at all.\n *\n * @default { default: 1, shift: 0.1 }\n */\n dragSensitivity?: ModifierValue<number>\n\n /**\n * Hide the cursor while dragging a `Stepper` and read the pointer movement\n * directly, rather than letting it wander off across the screen.\n *\n * The drag is already relative, so the pointer position carries nothing —\n * but it still runs into the edge of the screen, where the operating system\n * pins it and the coordinates stop changing.\n *\n * Off by default: the browser shows its own notice, Esc takes the lock back,\n * and the request can be refused. A refused request is not an error, and the\n * drag carries on as an ordinary one.\n *\n * @default false\n */\n pointerLock?: boolean\n\n /**\n * Select the text when `InputField` takes focus: `'all'` selects all of it,\n * `'number'` only the leading number, leaving whatever the format appended,\n * and `'none'` leaves the caret where the click put it.\n * @default 'none'\n */\n selectOnFocus?: 'all' | 'number' | 'none'\n /**\n * Show the plain value while `InputField` has focus, dropping whatever\n * `format` put around it: an input reading `1.23kHz` shows `1230` to be\n * typed over.\n *\n * The number shown is the value itself, not the number inside the formatted\n * text. Those differ whenever the format scales — `1.23` out of `1.23kHz`\n * would read back as 1.23 and lose a factor of a thousand — and it is also\n * why a rounded display no longer becomes the value: `1.6` shown as `2Hz`\n * offers `1.6` for editing, not `2`.\n *\n * @default false\n */\n unformatOnFocus?: boolean\n /**\n * Put the caret in `InputField` back where it was after an arrow key steps\n * the value.\n *\n * A controlled input whose `value` is replaced drops the caret at the end,\n * so without this the second press of a repeated step always acts on the\n * last digit. With it, the digit under the caret stays under the caret and\n * a column can be held while stepping.\n *\n * The position is measured from the decimal point rather than from either\n * end, so it survives the number growing or shrinking: the caret between\n * `9` and `.9` is still between `10` and `.0`.\n *\n * It only restores the caret. Which digit it sits on does not change the\n * size of the step — that is `keyboard`'s to say.\n *\n * @default false\n */\n keepCaretOnStep?: boolean\n /**\n * Commit and leave `InputField` when Enter is pressed. Enter commits either\n * way.\n * @default true\n */\n blurOnEnter?: boolean\n\n /**\n * Make the input unchangeable and remove it from the tab order.\n * The parts carry `data-disabled` while it is set.\n */\n disabled?: boolean\n /**\n * Make the value unchangeable.\n * The parts carry `data-readonly` while it is set.\n */\n readonly?: boolean\n\n className?: string\n style?: CSSProperties\n /**\n * Called with the new value. While the user types, it is called for every\n * entry that reads as a number, unclamped; committing the entry calls it\n * again if clamping changes the value.\n */\n onChange?: (value: number) => void\n\n /**\n * The input renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <NumberInput.Root value={value} min={0} max={100} onChange={setValue}>\n * <NumberInput.InputField />\n * <NumberInput.Stepper>\n * <NumberInput.IncrementStepper />\n * <NumberInput.DecrementStepper />\n * </NumberInput.Stepper>\n * </NumberInput.Root>\n */\n children: ReactNode\n}\n\nexport interface NumberInputMethods {\n focus: () => void\n blur: () => void\n}\n\n/**\n * A number at the start of the text, and nothing read after it. A half-typed\n * entry still yields the number in front of it, but text with no number is\n * `NaN` rather than 0, so that \"unreadable\" and \"the user typed 0\" stay apart.\n */\nconst LEADING_NUMBER = /^\\s*([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?)/\n\nconst defaultFormat = (value: number) => String(value)\n\nconst defaultParse = (text: string) => {\n const match = text.match(LEADING_NUMBER)\n return match ? Number(match[1]) : NaN\n}\n\ntype Props = NumberInputProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof NumberInputProps>\n\nexport const Root = /* @__PURE__ */ forwardRef<NumberInputMethods, Props>(\n (\n {\n value,\n min,\n max,\n step = 1,\n scale = linearScale,\n format: formatProp,\n parse: parseProp,\n clampValue = true,\n wheel = DEFAULT_WHEEL_OPTIONS,\n keyboard = DEFAULT_KEYBOARD_OPTIONS,\n drag = 1,\n dragSensitivity = DEFAULT_DRAG_SENSITIVITY,\n pointerLock = false,\n selectOnFocus = 'none',\n unformatOnFocus = false,\n keepCaretOnStep = false,\n blurOnEnter = true,\n disabled = false,\n readonly = false,\n className,\n style,\n onChange,\n children,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n // --- state and ref ---\n const inputRef = useRef<HTMLInputElement>(null)\n /**\n * The text being typed. The only state here: it is not a copy of `value`,\n * but the half-finished entry that has no value to be derived from yet.\n */\n const [draft, setDraft] = useState<string | null>(null)\n const inactive = disabled || readonly\n\n // --- interpret props ---\n const format = formatProp ?? defaultFormat\n const parse = parseProp ?? defaultParse\n\n // Normalized input needs a finite span even when an end is unbounded or\n // the caller opted out of clamping. Safe integers provide one without\n // overflowing the span calculation used by a scale.\n const range: ValueRange = useMemo(\n () => ({\n min: (clampValue ? min : undefined) ?? Number.MIN_SAFE_INTEGER,\n max: (clampValue ? max : undefined) ?? Number.MAX_SAFE_INTEGER,\n step,\n scale,\n }),\n [clampValue, min, max, step, scale],\n )\n\n // Raw input does not need a finite span for normalization, so its open\n // ends can cover every finite JavaScript number instead of stopping at the\n // safe-integer range.\n const rawRange: ValueRange = useMemo(\n () => ({\n min: (clampValue ? min : undefined) ?? -Number.MAX_VALUE,\n max: (clampValue ? max : undefined) ?? Number.MAX_VALUE,\n step,\n scale,\n }),\n [clampValue, min, max, step, scale],\n )\n\n // The pipeline range stands in the safe-integer range when an end is\n // open, and there is no travel to sample across that. Probing is skipped\n // rather than run against a range nobody set.\n const probeRange = useMemo(\n () =>\n min !== undefined && max !== undefined && min < max\n ? { min, max, step, scale }\n : null,\n [min, max, step, scale],\n )\n\n useCheckSteps({\n component: 'NumberInput',\n range: probeRange,\n keyboard,\n wheel,\n format,\n })\n\n const text = draft ?? format(value)\n const editing = draft !== null\n const outOfRange =\n !editing &&\n ((min !== undefined && value < min) || (max !== undefined && value > max))\n\n // --- internal functions ---\n const handleDraft = useCallback(\n (next: string) => {\n if (inactive) return\n setDraft(next)\n // Deliberately unclamped: clamping here would make \"1500\" impossible\n // to type into an input whose max is 100.\n const parsed = parse(next)\n if (Number.isFinite(parsed)) onChange?.(parsed)\n },\n [inactive, parse, onChange],\n )\n\n const changeValue = useCallback(\n (next: number) => {\n if (inactive) return\n setDraft(null)\n if (next !== value) onChange?.(next)\n },\n [inactive, value, onChange],\n )\n\n const commitDraft = useCallback(() => {\n if (draft === null || inactive) return\n const parsed = parse(draft)\n // Text with no number in it is not a value. Dropping the draft puts the\n // input back to what it was showing, rather than committing a zero the\n // user never typed.\n if (!Number.isFinite(parsed)) {\n setDraft(null)\n return\n }\n let committed = parsed\n if (clampValue && min !== undefined) committed = Math.max(committed, min)\n if (clampValue && max !== undefined) committed = Math.min(committed, max)\n changeValue(committed)\n }, [draft, inactive, parse, clampValue, min, max, changeValue])\n\n const nudge = useCallback(\n (\n direction: number,\n option: ModifierValue<InputEventOption>,\n modifiers?: ModifierState,\n ) => {\n const [mode] = selectInputEvent(option, modifiers).option\n changeValue(\n applyDelta(\n value,\n direction,\n option,\n mode === 'raw' ? rawRange : range,\n modifiers,\n ),\n )\n },\n [changeValue, value, rawRange, range],\n )\n\n // --- hooks ---\n const wheelRefCallback = useWheel<HTMLDivElement>(\n (event) => {\n if (!wheel || inactive || event.deltaY === 0) return\n event.preventDefault()\n nudge(-Math.sign(event.deltaY), wheel, event)\n },\n { requireFocus: true },\n )\n\n const context = useMemo(\n () => ({\n value,\n min,\n max,\n step,\n scale,\n disabled,\n readonly,\n clampValue,\n range,\n rawRange,\n keyboard,\n text,\n editing,\n outOfRange,\n dragSensitivity,\n pointerLock,\n selectOnFocus,\n unformatOnFocus,\n keepCaretOnStep,\n blurOnEnter,\n atMin: clampValue && min !== undefined && value <= min,\n atMax: clampValue && max !== undefined && value >= max,\n drag,\n format,\n parse,\n setDraft: handleDraft,\n commitDraft,\n changeValue,\n nudge,\n inputRef,\n }),\n [\n value,\n min,\n max,\n step,\n scale,\n disabled,\n readonly,\n clampValue,\n range,\n rawRange,\n keyboard,\n text,\n editing,\n outOfRange,\n drag,\n dragSensitivity,\n pointerLock,\n selectOnFocus,\n unformatOnFocus,\n keepCaretOnStep,\n blurOnEnter,\n format,\n parse,\n handleDraft,\n commitDraft,\n changeValue,\n nudge,\n ],\n )\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n if (!disabled) inputRef.current?.focus()\n },\n blur() {\n inputRef.current?.blur()\n },\n }\n }, [disabled])\n\n return (\n <NumberInputProvider value={context}>\n <div\n ref={wheelRefCallback}\n className={className}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n style={style}\n {...props}\n >\n {children}\n </div>\n </NumberInputProvider>\n )\n },\n)\n\n/**\n * Input with some useful functions for entering numerical values.\n */\nexport const NumberInput = {\n Root,\n InputField,\n Stepper,\n IncrementStepper,\n DecrementStepper,\n}\n\nexport { useNumberInputContext, type NumberInputContextValue } from './context'\nexport { type NumberInputInputFieldProps } from './InputField'\nexport { type NumberInputStepperProps } from './Stepper'\nexport { type NumberInputIncrementStepperProps } from './IncrementStepper'\nexport { type NumberInputDecrementStepperProps } from './DecrementStepper'\n","export type KeyboardShortcuts = {\n /**\n * Keys laid out from `noteRange.first`, one entry per semitone.\n *\n * An empty string leaves that note without a shortcut: `KeyboardEvent.key` is\n * never empty, so the entry can never match. Use it to skip the black keys\n * (see {@link SHORTCUTS.HOME_ROW_NATURAL}) and keep the remaining entries\n * lined up with the notes.\n */\n keys: string[]\n}\n\n/**\n * Ready-made keyboard layouts. Both assume `noteRange.first` is a C.\n */\nexport const SHORTCUTS = {\n /** Every semitone from C, over the two rows of a QWERTY keyboard. */\n HOME_ROW: {\n keys: [\n 'a',\n 'w',\n 's',\n 'e',\n 'd',\n 'f',\n 't',\n 'g',\n 'y',\n 'h',\n 'u',\n 'j',\n 'k',\n 'o',\n 'l',\n 'p',\n ';',\n ],\n },\n /** The white keys only, on the home row. Black keys have no shortcut. */\n HOME_ROW_NATURAL: {\n keys: [\n 'a',\n '',\n 's',\n '',\n 'd',\n 'f',\n '',\n 'g',\n '',\n 'h',\n '',\n 'j',\n 'k',\n '',\n 'l',\n '',\n ';',\n ],\n },\n}\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport { createPianoInput, type PianoInputInstance } from '@tremolo-ui/dom'\nimport {\n blackKeyWidth,\n getNoteRangeArray,\n isWhiteKey,\n noteKey,\n notePosition,\n pianoWidth,\n type NoteRange,\n type PianoLayout,\n} from '@tremolo-ui/functions'\n\nimport { useEventListener } from '../../hooks/useEventListener'\nimport { cssLength } from '../_util/css-length'\n\nimport { KeyboardShortcuts } from './keyboard-shortcuts'\n\ntype KeyboardShortcutsScope = 'root' | 'window'\n\nfunction isEditableTarget(target: EventTarget | null) {\n if (!(target instanceof HTMLElement)) return false\n if (target.matches('input, textarea, select')) return true\n\n for (let element: HTMLElement | null = target; element;) {\n const contentEditable = element.getAttribute('contenteditable')\n if (contentEditable !== null)\n return contentEditable.toLowerCase() !== 'false'\n element = element.parentElement\n }\n\n return false\n}\n\nfunction shortcutKey(event: KeyboardEvent) {\n return event.code || event.key\n}\n\n/**\n * `style` that also takes CSS custom properties, which is how a key's colours\n * are set: see `index.css` for the ones each key type reads.\n */\nexport type CSSVariables = Record<`--${string}`, string | number | undefined>\n\n/**\n * What {@link PianoProps.keyProps} may return for one key.\n *\n * `data-*` attributes are spelled out because TypeScript only allows them on\n * JSX syntax, not on an object type, and selecting on one is the usual way to\n * mark a key out.\n */\nexport type KeyAttributes = Omit<ComponentPropsWithoutRef<'div'>, 'style'> & {\n style?: CSSProperties & CSSVariables\n} & Record<`data-${string}`, string | number | boolean | undefined>\n\n/** What a key is, when {@link PianoProps.label} 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 {@link PianoProps.midiMax} and cannot sound. */\n disabled: boolean\n}\n\nexport interface PianoProps {\n /**\n * Classes for what a key draws inside itself: `keyLabelWrapper`, and\n * `keyLabel` around what `label` returns. The key itself takes a class\n * through `keyProps`, which is also where the note and its state are.\n */\n classes?: {\n keyLabelWrapper?: string\n keyLabel?: string\n }\n\n /**\n * The notes to draw keys for, as MIDI note numbers from `first` to `last`,\n * both included.\n */\n noteRange: NoteRange\n\n /**\n * Let a pointer slide from one key to the next while it is down. With it\n * off, the key that was pressed sounds until the pointer is released.\n *\n * @default true\n */\n glissando?: boolean\n\n /**\n * Highest note that can sound. Keys above it carry `data-disabled`.\n *\n * @default 127\n */\n midiMax?: number\n\n /**\n * Play notes from the computer keyboard: `keys[i]` plays\n * `noteRange.first + i`. `SHORTCUTS` has ready-made layouts, which assume\n * `noteRange.first` is a C. Where they listen is `keyboardShortcutsScope`.\n */\n keyboardShortcuts?: KeyboardShortcuts\n\n /**\n * Where keyboard shortcuts listen. `root` handles keys only while the Piano\n * root or one of its descendants has focus; `window` handles them anywhere\n * on the page except in editable elements.\n *\n * @default 'root'\n */\n keyboardShortcutsScope?: KeyboardShortcutsScope\n\n /**\n * Follow the width of the parent element, deriving the width of a white key\n * from it. {@link PianoProps.whiteKeyWidth} is ignored.\n *\n * @default false\n */\n resizable?: boolean\n\n /**\n * Width of a white key in pixels, not counting `keyGap`. Ignored while\n * `resizable` is on.\n * @default 40\n */\n whiteKeyWidth?: number\n /**\n * Space between two white keys, in pixels.\n * @default 1\n */\n keyGap?: number\n /**\n * Width of a black key, as a fraction of {@link PianoProps.whiteKeyWidth}.\n * @default 0.65\n */\n blackKeyWidthRatio?: number\n /**\n * Height of a black key, as a fraction of the height of the keyboard.\n * @default 0.6\n */\n blackKeyHeightRatio?: number\n\n /**\n * Height of the keyboard. Sets `--height`; when it is omitted, the height\n * the theme gives stands, and the theme can tell `resizable` apart through\n * `data-resizable`.\n */\n height?: number | string\n\n style?: CSSProperties & CSSVariables\n\n /**\n * What to draw inside a key. `''`, `null` and `undefined` leave it bare, so\n * a layout with gaps — {@link SHORTCUTS.HOME_ROW_NATURAL}, say — needs no\n * special casing.\n */\n label?: (note: number, state: KeyState) => ReactNode\n\n /**\n * Extra props for one key, by note: a class, a style, a `data-*` attribute\n * to select on.\n *\n * The geometry of the key (`left`, `width`, `height`) is applied after the\n * returned `style` and cannot be overridden, so a key cannot be drawn\n * somewhere other than where it responds.\n *\n * @example highlight the notes of a scale\n * ```tsx\n * keyProps={(note) => ({ 'data-in-scale': inScale(note, root, 'major') ? '' : undefined })}\n * ```\n */\n keyProps?: (note: number, state: KeyState) => KeyAttributes\n\n /**\n * Called when a note starts sounding, whether a pointer, a keyboard shortcut\n * or `playNote` asked for it. A note held by several of them at once is\n * reported once. `velocity` is what `playNote` was given, and `undefined`\n * otherwise.\n */\n onPlayNote?: (note: number, velocity?: number) => void\n /** Called once everything holding a note has let go of it. */\n onStopNote?: (note: number) => void\n}\n\nexport interface PianoMethods {\n playNote: (note: number, velocity?: number) => void\n stopNote: (note: number) => void\n}\n\ntype Props = PianoProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PianoProps>\n\nexport const Root = /* @__PURE__ */ forwardRef<PianoMethods, Props>(\n function Root(\n {\n noteRange,\n glissando = true,\n midiMax = 127,\n keyboardShortcuts,\n keyboardShortcutsScope = 'root',\n resizable = false,\n whiteKeyWidth = 40,\n keyGap = 1,\n blackKeyWidthRatio = 0.65,\n blackKeyHeightRatio = 0.6,\n height,\n style,\n className,\n label,\n keyProps,\n classes,\n onPlayNote,\n onStopNote,\n ...props\n },\n forwardedRef,\n ) {\n // See useDrag for why the node is held in state rather than a ref: an inline\n // ref would be re-attached on every render and tear the instance down.\n const [node, setNode] = useState<HTMLDivElement | null>(null)\n const [activeNotes, setActiveNotes] = useState<number[]>([])\n /** Set while `resizable` is on, measured from the parent. */\n const [resizedKeyWidth, setResizedKeyWidth] = useState(whiteKeyWidth)\n\n const notes = useMemo(() => getNoteRangeArray(noteRange), [noteRange])\n const whiteKeyCount = useMemo(\n () => notes.filter(isWhiteKey).length,\n [notes],\n )\n\n const layout: PianoLayout = useMemo(\n () => ({\n noteRange,\n whiteKeyWidth: resizable ? resizedKeyWidth : whiteKeyWidth,\n keyGap,\n blackKeyWidthRatio,\n blackKeyHeightRatio,\n }),\n [\n noteRange,\n resizable,\n resizedKeyWidth,\n whiteKeyWidth,\n keyGap,\n blackKeyWidthRatio,\n blackKeyHeightRatio,\n ],\n )\n\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale handler is replaced within the same commit.\n const latest = useRef({\n layout,\n glissando,\n midiMax,\n onPlayNote,\n onStopNote,\n })\n const instanceRef = useRef<PianoInputInstance | null>(null)\n const shortcutNotes = useRef(\n new Map<string, { note: number; source: string }>(),\n )\n\n const releaseShortcutNotes = useCallback(() => {\n for (const { note, source } of shortcutNotes.current.values()) {\n instanceRef.current?.noteOff(note, { source })\n }\n shortcutNotes.current.clear()\n }, [])\n\n useEffect(() => {\n if (!node) return\n\n const instance = createPianoInput(node, {\n layout: latest.current.layout,\n glissando: latest.current.glissando,\n midiMax: latest.current.midiMax,\n onPlayNote: (note, velocity) =>\n latest.current.onPlayNote?.(note, velocity),\n onStopNote: (note) => latest.current.onStopNote?.(note),\n onActiveNotesChange: setActiveNotes,\n })\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n // Only the element decides how the instance is wired. Everything else is\n // pushed with update() below, so that changing the layout mid-drag — the\n // parent being resized under `resizable`, say — does not abort the drag.\n }, [node])\n\n // Runs after every render.\n useEffect(() => {\n latest.current = { layout, glissando, midiMax, onPlayNote, onStopNote }\n instanceRef.current?.update({ layout, glissando, midiMax })\n })\n\n useEffect(() => {\n if (!resizable || !node) return\n const parent = node.parentElement\n if (!parent) throw new Error(\"doesn't have a parent element.\")\n\n const resizeObserver = new ResizeObserver(() => {\n setResizedKeyWidth(\n node.clientWidth / Math.max(whiteKeyCount, 1) - keyGap,\n )\n })\n resizeObserver.observe(parent)\n return () => resizeObserver.disconnect()\n }, [resizable, node, whiteKeyCount, keyGap])\n\n const shortcutKeys = keyboardShortcuts?.keys\n const hasShortcuts = shortcutKeys !== undefined\n // What the held keys were started against, as a value rather than the\n // identity of the array: a caller who writes the keys inline hands over a\n // new array on every render, and releasing on that would stop a note as\n // soon as anything else re-renders — including the state change that\n // playing the note caused.\n const shortcutMapping = shortcutKeys?.join('\\u0000')\n\n useEffect(\n () => releaseShortcutNotes,\n [\n releaseShortcutNotes,\n shortcutMapping,\n keyboardShortcutsScope,\n noteRange.first,\n noteRange.last,\n ],\n )\n\n /** The note a shortcut key plays, or null when it has none. */\n function shortcutNote(key: string) {\n if (!shortcutKeys || key === '') return null\n const index = shortcutKeys.indexOf(key)\n const note = noteRange.first + index\n return index === -1 || note > noteRange.last ? null : note\n }\n\n const shortcutTarget = useMemo(\n () => () => {\n if (!hasShortcuts) return null\n return keyboardShortcutsScope === 'window' ? globalThis.window : node\n },\n [hasShortcuts, keyboardShortcutsScope, node],\n )\n\n const focusOutTarget = useMemo(\n () => () =>\n hasShortcuts && keyboardShortcutsScope === 'root' ? node : null,\n [hasShortcuts, keyboardShortcutsScope, node],\n )\n\n const windowBlurTarget = useMemo(\n () => () => (hasShortcuts ? globalThis.window : null),\n [hasShortcuts],\n )\n\n useEventListener(shortcutTarget, 'keydown', (e) => {\n const key = shortcutKey(e)\n if (e.repeat || shortcutNotes.current.has(key)) return\n if (isEditableTarget(e.target)) return\n\n const note = shortcutNote(e.key)\n if (note === null) return\n\n const source = `keyboard:${key}`\n shortcutNotes.current.set(key, { note, source })\n instanceRef.current?.noteOn(note, { source })\n })\n\n useEventListener(shortcutTarget, 'keyup', (e) => {\n const key = shortcutKey(e)\n const shortcut = shortcutNotes.current.get(key)\n if (!shortcut) return\n\n shortcutNotes.current.delete(key)\n instanceRef.current?.noteOff(shortcut.note, { source: shortcut.source })\n })\n\n useEventListener(focusOutTarget, 'focusout', (e) => {\n if (e.relatedTarget instanceof Node && node?.contains(e.relatedTarget))\n return\n releaseShortcutNotes()\n })\n\n useEventListener(windowBlurTarget, 'blur', releaseShortcutNotes)\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n playNote: (note, velocity) =>\n instanceRef.current?.noteOn(note, { source: 'api', velocity }),\n stopNote: (note) =>\n instanceRef.current?.noteOff(note, { source: 'api' }),\n }),\n [],\n )\n\n return (\n <div\n ref={setNode}\n className={className}\n data-resizable={resizable ? '' : undefined}\n role=\"group\"\n // The group can own keyboard shortcuts and must receive focus.\n // oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n style={\n {\n // Computed from the layout rather than chosen, so it stays inline.\n width: resizable ? '100%' : pianoWidth(layout),\n '--height': cssLength(height),\n // The keys inside are placed against this box.\n position: 'relative',\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {notes.map((note, index) => {\n const keyType = isWhiteKey(note) ? 'white' : 'black'\n const state: KeyState = {\n index,\n keyType,\n active: activeNotes.includes(note),\n disabled: note > midiMax,\n }\n\n const {\n className: keyClassName,\n style: keyStyle,\n ...rest\n } = keyProps?.(note, state) ?? {}\n\n const content = label?.(note, state)\n\n return (\n <div\n key={note}\n className={keyClassName}\n data-note={note}\n data-note-key={noteKey(note)}\n data-active={state.active ? '' : undefined}\n data-disabled={state.disabled ? '' : undefined}\n {...rest}\n style={{\n // The key is placed and sized from the layout below, which\n // needs it out of flow; the black keys sit over the white\n // ones whichever order they are drawn in.\n position: 'absolute',\n zIndex: keyType === 'white' ? 1 : 2,\n ...keyStyle,\n left: notePosition(note, layout),\n width:\n keyType === 'white'\n ? layout.whiteKeyWidth\n : blackKeyWidth(layout),\n height:\n keyType === 'white'\n ? '100%'\n : `${blackKeyHeightRatio * 100}%`,\n }}\n >\n {content !== '' && content !== null && content !== undefined && (\n <div className={classes?.keyLabelWrapper}>\n <div className={classes?.keyLabel}>{content}</div>\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n },\n)\n\n/**\n * Customizable piano component.\n */\nexport const Piano = { Root }\n\nexport { type KeyboardShortcuts, SHORTCUTS } from './keyboard-shortcuts'\n","import { ComponentPropsWithoutRef, ReactNode } from 'react'\n\nexport interface PointsEditorBackgroundProps {\n /** Whatever the points are placed over: a graph, a canvas, an image. */\n children?: ReactNode\n}\n\nexport function Background({\n className,\n children,\n style,\n ...props\n}: PointsEditorBackgroundProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorBackgroundProps>) {\n return (\n <div\n className={className}\n style={{\n // Behind the points, filling the editor: what it is for, rather than\n // a look. The order of the layers holds whichever way they are\n // written, so the z-index is part of the same mechanics.\n position: 'absolute',\n inset: 0,\n zIndex: 0,\n ...style,\n }}\n {...props}\n >\n {children}\n </div>\n )\n}\n","import { createContext, CSSProperties, RefObject, useContext } from 'react'\n\nimport type { SelectionBoxRect } from '@tremolo-ui/dom'\nimport type {\n InputEventOption,\n ModifierState,\n ModifierValue,\n} from '@tremolo-ui/functions'\n\nimport type { PointBaseType } from './Point'\n\n/**\n * What a `Point` tells the editor about itself, so that a selection can be\n * moved without the editor knowing how the points are stored.\n *\n * Held behind a ref and rewritten on every render: the value changes on every\n * frame of a drag, and a registry keyed on it would be rebuilt just as often.\n */\nexport interface PointRegistration {\n value: PointBaseType\n min?: Partial<PointBaseType>\n max?: Partial<PointBaseType>\n readonly: boolean\n onChange?: (value: PointBaseType) => void\n /** The point's own element, to match the focus against. */\n element: HTMLElement | null\n /** The wheel option this point resolved, root inheritance applied. */\n wheel: ModifierValue<InputEventOption> | null\n}\n\nexport type PointsEditorContextValue = {\n disabled: boolean\n readonly: boolean\n /** Inherited by every `Point`; `null` turns the wheel off. */\n wheel: ModifierValue<InputEventOption> | null\n /** Inherited by every `Point`; `null` turns the keyboard off. */\n keyboard: ModifierValue<InputEventOption> | null\n /** Inherited by every `Point`. See `PointsEditorProps.dragSensitivity`. */\n dragSensitivity: ModifierValue<number>\n externalStyles: {\n cursor?: CSSProperties['cursor']\n }\n\n /**\n * `Container` registers its element here; `Point` normalizes the pointer\n * against it, so a point is placed by its position within the container.\n */\n containerRef: RefObject<HTMLDivElement | null>\n\n /** Whether points can be selected at all. See `PointsEditorProps.selectable`. */\n selectable: boolean\n /** Ids of the points currently selected. Always empty while `selectable` is off. */\n selection: readonly string[]\n /** Register a point so that a selection can move it with the rest. */\n registerPoint: (id: string, entry: RefObject<PointRegistration>) => () => void\n /**\n * Whether the element is a point, or inside one. The registry knows which\n * elements the points are, so nothing has to be recognised by a class name.\n */\n isPointElement: (element: Element | null | undefined) => boolean\n /**\n * A pointer went down on a point: works out the new selection and takes the\n * snapshot the move will be measured against.\n */\n beginPointDrag: (id: string, modifiers: ModifierState) => void\n /** Move everything the drag picked up, by one amount, clamped as one. */\n movePointDrag: (delta: PointBaseType) => void\n /**\n * Move the selection by an amount that did not come from a drag — an arrow\n * key or a wheel notch. The current values are the starting point.\n */\n nudgeSelection: (id: string, delta: PointBaseType) => void\n /**\n * Move the point that currently holds focus by one notch. The wheel listener\n * belongs to `Container` rather than to every `Point`, so the lookup of who\n * has focus happens here, where the registry is. Returns whether a point\n * took it, so the caller knows whether to consume the event.\n */\n nudgeFocusedPoint: (\n axis: 'x' | 'y',\n direction: number,\n modifiers: ModifierState,\n ) => boolean\n\n /** The selection box, while one is being dragged. */\n selectionBox: SelectionBoxRect | null\n beginSelectionBox: (at: PointBaseType, modifiers: ModifierState) => void\n moveSelectionBox: (to: PointBaseType) => void\n endSelectionBox: () => void\n}\n\nconst PointsEditorContext =\n /* @__PURE__ */ createContext<PointsEditorContextValue | null>(null)\n\nexport const PointsEditorProvider = PointsEditorContext.Provider\n\n/**\n * The settings `Root` was given, for the subcomponents to read. A point's\n * value still belongs to the `Point` that draws it; what the root keeps is\n * which points are selected, and a registry of who they are.\n */\nexport function usePointsEditorContext(): PointsEditorContextValue\nexport function usePointsEditorContext<T>(\n selector: (state: PointsEditorContextValue) => T,\n): T\nexport function usePointsEditorContext<T>(\n selector?: (state: PointsEditorContextValue) => T,\n) {\n const context = useContext(PointsEditorContext)\n if (!context)\n throw new Error('Missing PointsEditorContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import { ComponentPropsWithoutRef, CSSProperties, forwardRef } from 'react'\n\nconst hiddenStyle: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n pointerEvents: 'none',\n}\n\ntype Props = Omit<ComponentPropsWithoutRef<'input'>, 'type' | 'style'>\n\nexport const VisuallyHiddenRangeInput = /* @__PURE__ */ forwardRef<\n HTMLInputElement,\n Props\n>((props, ref) => (\n <input {...props} ref={ref} type=\"range\" style={hiddenStyle} />\n))\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react'\n\nimport {\n applyDelta,\n clamp,\n type InputEventOption,\n type ModifierState,\n type ModifierValue,\n selectModifier,\n} from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { cssLength } from '../_util/css-length'\nimport { useCheckPlacement } from '../_util/Placement'\nimport { VisuallyHiddenRangeInput } from '../_util/VisuallyHiddenRangeInput'\n\nimport { type PointRegistration, usePointsEditorContext } from './context'\n\nexport type PointBaseType = { x: number; y: number }\n\nexport function clampPoint(\n point: PointBaseType,\n min?: Partial<PointBaseType>,\n max?: Partial<PointBaseType>,\n) {\n const { x, y } = point\n const newX = clamp(x, min?.x ?? 0, max?.x ?? 1)\n const newY = clamp(y, min?.y ?? 0, max?.y ?? 1)\n return { x: newX, y: newY }\n}\n\nexport interface PointsEditorPointProps<T extends PointBaseType> {\n /**\n * Where the point is, as `{ x, y }` from 0 to 1 on each axis, with `y`\n * growing downwards.\n */\n value: T\n /** Drawn inside the point: the theme's own dot stands when it is left out. */\n children?: ReactNode\n /**\n * How the selection refers to this point. One is generated when it is left\n * out, which lasts as long as the point is mounted — give your own if the\n * selection has to survive a remount, or be recognised in your own state.\n */\n id?: string\n /** The lowest position the point can take, per axis. An axis left out is 0. */\n min?: Partial<PointBaseType>\n /** The highest position the point can take, per axis. An axis left out is 1. */\n max?: Partial<PointBaseType>\n\n /** Width and height at once. Sets both `--width` and `--height`. */\n size?: number | string\n /** Sets `--width`; the size the theme gives it stands when omitted. */\n width?: number | string\n /** Sets `--height`; the size the theme gives it stands when omitted. */\n height?: number | string\n /** Sets `--color`, for the theme to colour the point with. */\n color?: string\n\n /** Overrides the `disabled` of `PointsEditor.Root`. */\n disabled?: boolean\n /** Overrides the `readonly` of `PointsEditor.Root`. */\n readonly?: boolean\n\n /** Overrides the `wheel` of `PointsEditor.Root`. */\n wheel?: ModifierValue<InputEventOption> | null\n /** Overrides the `keyboard` of `PointsEditor.Root`. */\n keyboard?: ModifierValue<InputEventOption> | null\n\n /**\n * The accessible name of each axis. There are two range inputs inside the\n * point, so this takes one name per axis; a single string names them both.\n */\n 'aria-label'?: string | Partial<Record<'x' | 'y', string>>\n /** What the value of each axis means, when the number does not say it. */\n 'aria-valuetext'?: string | Partial<Record<'x' | 'y', string>>\n\n /**\n * Called with the new position when the point is dragged or moved by the\n * arrow keys or the wheel, including when it moves along with a selection.\n */\n onChange?: (value: PointBaseType) => void\n /** Called when a drag on this point starts, with where the point is. */\n onDragStart?: (value: PointBaseType) => void\n /** Called when that drag ends, with where the point is. */\n onDragEnd?: (value: PointBaseType) => void\n}\n\n/**\n * A point is placed by its position within the container, so its value is a\n * position: 0..1 on each axis, with y growing downwards.\n */\nexport const AXIS = { min: 0, max: 1 }\n\n/**\n * One setting for both axes, or one per axis. The point holds a range input\n * for each, so anything that names or describes it comes in a pair.\n */\nfunction perAxis(\n value: string | Partial<Record<'x' | 'y', string>> | undefined,\n axis: 'x' | 'y',\n) {\n return typeof value === 'string' ? value : value?.[axis]\n}\n\nexport function Point<T extends PointBaseType>({\n value,\n children,\n id: idProp,\n min,\n max,\n size,\n width,\n height,\n color,\n\n disabled: _disabled,\n readonly: _readonly,\n wheel: _wheel,\n keyboard: _keyboard,\n 'aria-label': ariaLabel,\n 'aria-valuetext': ariaValuetext,\n\n onChange,\n onDragStart,\n onDragEnd,\n\n className,\n style,\n onPointerDown,\n onKeyDown,\n onFocus,\n ...props\n}: PointsEditorPointProps<T> &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorPointProps<T>>) {\n const {\n containerRef,\n externalStyles,\n disabled: rootDisabled,\n readonly: rootReadonly,\n wheel: rootWheel,\n keyboard: rootKeyboard,\n dragSensitivity,\n selection,\n registerPoint,\n beginPointDrag,\n movePointDrag,\n nudgeSelection,\n } = usePointsEditorContext()\n\n const generatedId = useId()\n const id = idProp ?? generatedId\n const selected = selection.includes(id)\n\n const disabled = _disabled ?? rootDisabled\n const readonly = _readonly ?? rootReadonly\n const inactive = disabled || readonly\n // `null` means \"no event\" and has to survive the fallback, so `??` is not\n // enough: only an omitted prop inherits from the root.\n const wheel = _wheel === undefined ? rootWheel : _wheel\n const keyboard = _keyboard === undefined ? rootKeyboard : _keyboard\n\n useCheckPlacement('PointsEditor.Point', 'PointsEditor.Container')\n\n // Compared against the focus below, so the point needs its own element.\n const [element, setElement] = useState<HTMLDivElement | null>(null)\n const xInputRef = useRef<HTMLInputElement>(null)\n const yInputRef = useRef<HTMLInputElement>(null)\n\n // What the editor needs to move this point along with the rest of a\n // selection. Rewritten after every render rather than kept in the registry\n // itself: the value changes on every frame of a drag.\n const registration = useRef<PointRegistration>({\n value,\n min,\n max,\n readonly: inactive,\n onChange,\n element,\n wheel,\n })\n useEffect(() => {\n registration.current = {\n value,\n min,\n max,\n readonly: inactive,\n onChange,\n element,\n wheel,\n }\n })\n\n useEffect(() => registerPoint(id, registration), [id, registerPoint])\n\n /** Where the pointer was when the drag started, to measure the move from. */\n const pointerOrigin = useRef<PointBaseType | null>(null)\n\n // The value is the position itself: no scaling, and no rounding to a step.\n const { refCallback: dragRefCallback, dragging } =\n useDragValue<HTMLDivElement>({\n axis: AXIS,\n baseElementRef: containerRef,\n sensitivity: (state) =>\n selectModifier(dragSensitivity, state.event).value,\n cursor: inactive ? undefined : externalStyles.cursor,\n shouldStart: () => !disabled,\n // The value is a move rather than a position: the point keeps the offset\n // it was grabbed at, and everything else selected moves with it by the\n // same amount.\n onChange: ([x, y]) => {\n const origin = pointerOrigin.current\n if (!origin) return\n movePointDrag({ x: x - origin.x, y: y - origin.y })\n },\n onDragStart: ([x, y], state) => {\n // The press decides the selection before the snapshot is taken, so it\n // happens here rather than in an onPointerDown: a native listener on\n // the element runs before React's, and the two would disagree.\n beginPointDrag(id, state.event)\n pointerOrigin.current = { x, y }\n xInputRef.current?.focus()\n\n if (inactive) return\n onDragStart?.(clampPoint(value, min, max))\n },\n onDragEnd: () => {\n pointerOrigin.current = null\n\n if (inactive) return\n onDragEnd?.(clampPoint(value, min, max))\n },\n })\n\n const nudge = useCallback(\n (\n axis: 'x' | 'y',\n direction: number,\n option: ModifierValue<InputEventOption>,\n modifiers: ModifierState,\n ) => {\n const next = applyDelta(value[axis], direction, option, AXIS, modifiers)\n // As a move, so that the rest of the selection comes along and the whole\n // group stops together at the edge.\n nudgeSelection(id, {\n x: axis === 'x' ? next - value.x : 0,\n y: axis === 'y' ? next - value.y : 0,\n })\n },\n [value, id, nudgeSelection],\n )\n\n const refCallback = useComposedRefs<HTMLDivElement>(\n dragRefCallback,\n setElement,\n )\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n const key = event.key\n if (!['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key))\n return\n // The key picks the axis, whichever of the two inputs holds the focus: a\n // point is one control to the person moving it, and the focus lands on the\n // x input, so reading the axis off the input would leave the y axis with\n // no keys at all.\n const axis = key === 'ArrowRight' || key === 'ArrowLeft' ? 'x' : 'y'\n event.preventDefault()\n if (!onChange || inactive || !keyboard) return\n // y grows downwards, so ArrowUp moves the point towards 0.\n const direction = key === 'ArrowLeft' || key === 'ArrowUp' ? -1 : 1\n nudge(axis, direction, keyboard, event)\n }\n\n const current = clampPoint(value, min, max)\n\n return (\n // The visual point has two values, so its semantics live on the two range\n // inputs nested inside it rather than on this drag handle.\n // oxlint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n ref={refCallback}\n className={className}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n // A press lands on the point, which cannot hold focus, and the browser\n // answers that by clearing the focus to the body — undoing the focus the\n // drag just gave the input. Taking the focus here keeps it inside, and\n // it is passed on to the input below.\n tabIndex={-1}\n data-dragging={dragging ? '' : undefined}\n data-selected={selected ? '' : undefined}\n style={\n {\n '--color': color,\n '--width': cssLength(size ?? width),\n '--height': cssLength(size ?? height),\n // The mechanics of the position below: a point is placed by its\n // position in the container, measured from its own centre.\n position: 'absolute',\n translate: 'var(--translate, -50% -50%)',\n ...style,\n // Where the point is: the value, not a style.\n left: `${value.x * 100}%`,\n top: `${value.y * 100}%`,\n } as CSSProperties\n }\n onPointerDown={onPointerDown}\n onFocus={(event) => {\n // The point itself is not the control: its semantics live on the\n // inputs, so whatever reaches it is handed to the first of them.\n if (!disabled && event.target === event.currentTarget) {\n xInputRef.current?.focus()\n }\n onFocus?.(event)\n }}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n {...props}\n >\n {(['x', 'y'] as const).map((axis) => (\n <VisuallyHiddenRangeInput\n key={axis}\n ref={axis === 'x' ? xInputRef : yInputRef}\n data-axis={axis}\n value={current[axis]}\n min={min?.[axis] ?? 0}\n max={max?.[axis] ?? 1}\n step=\"any\"\n disabled={disabled}\n aria-readonly={readonly}\n aria-orientation={axis === 'x' ? 'horizontal' : 'vertical'}\n aria-label={perAxis(ariaLabel, axis) ?? axis}\n aria-valuetext={perAxis(ariaValuetext, axis)}\n onChange={(event) => {\n if (readonly) {\n event.currentTarget.value = String(current[axis])\n return\n }\n const delta = event.currentTarget.valueAsNumber - value[axis]\n nudgeSelection(id, {\n x: axis === 'x' ? delta : 0,\n y: axis === 'y' ? delta : 0,\n })\n }}\n />\n ))}\n {children}\n </div>\n )\n}\n","import { ComponentPropsWithoutRef, forwardRef, ReactNode } from 'react'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport { Placement } from '../_util/Placement'\n\nimport { usePointsEditorContext } from './context'\nimport { AXIS } from './Point'\n\nexport interface PointsEditorContainerProps {\n /** `<PointsEditor.Point />` goes here. */\n children?: ReactNode\n}\n\ntype Props = PointsEditorContainerProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorContainerProps>\n\nexport const Container = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(\n function Container({ children, className, style, ...props }, forwardedRef) {\n const {\n containerRef,\n disabled,\n selectable,\n isPointElement,\n nudgeFocusedPoint,\n beginSelectionBox,\n moveSelectionBox,\n endSelectionBox,\n } = usePointsEditorContext()\n const { refCallback: dragRefCallback } = useDragValue<HTMLDivElement>({\n axis: AXIS,\n baseElementRef: containerRef,\n // A press that landed on a point belongs to that point. Declining here\n // rather than in onDragStart matters: by then the container would already\n // have taken the pointer capture away from the point.\n shouldStart: (event) =>\n !disabled && !isPointElement(event.target as Element | null),\n onDragStart: ([x, y], state) => {\n beginSelectionBox({ x, y }, state.event)\n },\n onChange: ([x, y]) => moveSelectionBox({ x, y }),\n onDragEnd: endSelectionBox,\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, and a point is a 16px\n // target, so the focused point takes it from anywhere over the editor —\n // the way it does for Slider and XYPad.\n useWheel(\n (event) => {\n // Scrolling up moves the point towards y = 0; shift switches to x.\n // Browsers turn shift+wheel into horizontal scrolling: `deltaY` comes\n // out empty and `deltaX` carries the movement. Reading whichever axis\n // moved keeps shift working as the x-axis modifier — and picks up a\n // trackpad's own horizontal gesture, which never had a modifier.\n const horizontal = event.deltaX !== 0\n const delta = horizontal ? event.deltaX : event.deltaY\n if (delta === 0) return\n const axis = horizontal || event.shiftKey ? 'x' : 'y'\n const direction = delta < 0 ? -1 : 1\n if (nudgeFocusedPoint(axis, direction, event)) event.preventDefault()\n },\n { target: containerRef },\n )\n\n // The container is what the pointer position is normalized against, so the\n // context ref is composed with any ref the caller passed.\n // Only attached when there is a selection to draw: `createDrag` puts\n // `touch-action: none` on whatever it holds, and an editor that cannot\n // select has no reason to stop the page scrolling under a finger.\n const composedRef = useComposedRefs<HTMLDivElement>(\n forwardedRef,\n containerRef,\n selectable && !disabled ? dragRefCallback : undefined,\n )\n\n return (\n <div\n ref={composedRef}\n className={className}\n style={{\n // The points inside are placed against this box, over the\n // background and under the selection box.\n position: 'absolute',\n inset: 0,\n zIndex: 10,\n ...style,\n }}\n {...props}\n >\n <Placement name=\"PointsEditor.Container\">{children}</Placement>\n </div>\n )\n },\n)\n","import { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react'\n\nimport { useCheckPlacement } from '../_util/Placement'\n\nimport { usePointsEditorContext } from './context'\n\nexport interface PointsEditorSelectionBoxProps {\n /** Drawn inside the box, which is only there while a drag is running. */\n children?: ReactNode\n}\n\n/**\n * The box a drag on empty space draws, and what it covers is selected.\n *\n * Nothing is rendered while no drag is running, and leaving it out leaves the\n * editor without one — the selection still works, it just cannot be seen.\n */\nexport function SelectionBox({\n children,\n className,\n style,\n ...props\n}: PointsEditorSelectionBoxProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorSelectionBoxProps>) {\n useCheckPlacement('PointsEditor.SelectionBox', 'PointsEditor.Container')\n\n const selectionBox = usePointsEditorContext((s) => s.selectionBox)\n if (!selectionBox) return null\n\n return (\n <div\n className={className}\n {...props}\n style={\n {\n // Drawn over the points while a drag runs, and taking none of the\n // pointer: the drag underneath is what it is reporting on.\n position: 'absolute',\n zIndex: 20,\n pointerEvents: 'none',\n ...style,\n // Where the box is and how big it is: the drag, not a style, so it\n // is written after whatever the caller passed.\n left: `${selectionBox.x * 100}%`,\n top: `${selectionBox.y * 100}%`,\n width: `${selectionBox.width * 100}%`,\n height: `${selectionBox.height * 100}%`,\n } as CSSProperties\n }\n >\n {children}\n </div>\n )\n}\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport {\n createSelectionBox,\n type SelectionBoxInstance,\n type SelectionBoxRect,\n type XY,\n} from '@tremolo-ui/dom'\nimport {\n applyDelta,\n clamp,\n type InputEventOption,\n type ModifierState,\n type ModifierValue,\n toPrecision,\n} from '@tremolo-ui/functions'\n\nimport { DEFAULT_DRAG_SENSITIVITY } from '../../input-event'\nimport { cssLength } from '../_util/css-length'\n\nimport { Background } from './Background'\nimport { Container } from './Container'\nimport { type PointRegistration, PointsEditorProvider } from './context'\nimport { AXIS, Point, type PointBaseType } from './Point'\nimport { SelectionBox } from './SelectionBox'\n\n/** One array for every editor with selection turned off, so memos hold still. */\nconst EMPTY: readonly string[] = []\n\n/**\n * How far a point may move before something in the selection leaves its range.\n *\n * Clamping each point on its own would break the shape of the selection: the\n * one that reached the edge would stop while the rest carried on. One amount\n * for all of them means the whole selection stops together.\n */\nfunction allowedDelta(\n delta: PointBaseType,\n entries: { start: PointBaseType; registration: PointRegistration }[],\n): PointBaseType {\n let loX = -Infinity\n let hiX = Infinity\n let loY = -Infinity\n let hiY = Infinity\n\n for (const { start, registration } of entries) {\n loX = Math.max(loX, (registration.min?.x ?? 0) - start.x)\n hiX = Math.min(hiX, (registration.max?.x ?? 1) - start.x)\n loY = Math.max(loY, (registration.min?.y ?? 0) - start.y)\n hiY = Math.min(hiY, (registration.max?.y ?? 1) - start.y)\n }\n\n // A point that started outside its own range leaves nothing to move within.\n return {\n x: hiX < loX ? 0 : clamp(delta.x, loX, hiX),\n y: hiY < loY ? 0 : clamp(delta.y, loY, hiY),\n }\n}\n\n/*\nTODO:\n\n- grid\n*/\n\n/**\n * A point moves over 0..1 in both axes, so a nudge of 0.01 crosses the editor\n * in a hundred steps whatever its pixel size.\n */\nconst DEFAULT_WHEEL: ModifierValue<InputEventOption> = ['normalized', 0.01]\n\n/**\n * Shift is the fine-adjustment key everywhere else, so it is bound here too\n * — but only on the keyboard. On the wheel it already means the x axis, and\n * browsers hand shift+wheel over as horizontal scrolling anyway.\n */\nconst DEFAULT_KEYBOARD: ModifierValue<InputEventOption> = {\n default: ['normalized', 0.01],\n shift: ['normalized', 0.001],\n}\n\nexport interface PointsEditorProps {\n /** Sets `--width`; the size the theme gives it stands when omitted. */\n width?: number | string\n /** Sets `--height`; the size the theme gives it stands when omitted. */\n height?: number | string\n\n /**\n * Make the points unchangeable and remove them from the tab order.\n * The parts carry `data-disabled` while it is set.\n */\n disabled?: boolean\n /**\n * Make the points unmovable.\n * The parts carry `data-readonly` while it is set.\n */\n readonly?: boolean\n\n /**\n * The cursor to show while dragging a point. It is set on the dragged\n * point, so it stays while the pointer is outside it.\n *\n * @default { cursor: 'grabbing' }\n */\n externalStyles?: {\n cursor?: CSSProperties['cursor']\n }\n\n /**\n * How much one notch of the wheel moves the focused `Point`. Scrolling\n * sideways, or with shift held, moves x; otherwise it moves y.\n *\n * A position runs from 0 to 1, so `['normalized', n]` and `['raw', n]` both\n * move it by `n` of the editor. `null` turns the wheel off, and a `Point`\n * can override it with a `wheel` of its own.\n *\n * @default ['normalized', 0.01]\n */\n wheel?: ModifierValue<InputEventOption> | null\n /**\n * How much one arrow key press moves a `Point`. Left and right move x, up\n * and down move y.\n *\n * A position runs from 0 to 1, so `['normalized', n]` and `['raw', n]` both\n * move it by `n` of the editor; give a map to set an amount per modifier\n * key. `null` turns the arrow keys off, and a `Point` can override it with a\n * `keyboard` of its own.\n *\n * @default { default: ['normalized', 0.01], shift: ['normalized', 0.001] }\n */\n keyboard?: ModifierValue<InputEventOption> | null\n\n /**\n * How much a drag moves a `Point`, per modifier key.\n *\n * `1` is the pointer position itself, which is what dragging a point\n * normally is. **Anything else turns the drag relative**: `0.1` makes the\n * same movement cover a tenth of the editor, so the point stops following\n * the pointer and starts moving a tenth as fast. Shift is bound to `0.1` by\n * default, to match what it does on the arrow keys.\n *\n * Pressing or releasing the key mid-drag does not disturb the point: the\n * travel so far is kept and the new sensitivity applies from there. **The\n * pointer and the point stay apart for the rest of the drag** — snapping\n * them back together on release would move the point nobody asked to move.\n *\n * @default { default: 1, shift: 0.1 }\n */\n dragSensitivity?: ModifierValue<number>\n\n /**\n * Let points be selected, and a selection be moved as one.\n *\n * Off by default, because it changes what a press and a drag mean: a press\n * on empty space starts a selection box rather than doing nothing, and a drag\n * on a point moves everything else that is selected. An editor whose points\n * each mean something different — the four handles of an ADSR envelope, say\n * — has nothing to gain from moving them together.\n *\n * **A selection calls `onChange` on several points in the same tick**, so\n * each of them has to update from the previous state rather than from a\n * value captured in the render:\n *\n * ```jsx\n * onChange={(v) => setPoints((prev) => ({ ...prev, [id]: v }))}\n * ```\n *\n * Written the other way round — `setPoints({ ...points, [id]: v })` — every\n * call but the last is thrown away, and only one point appears to move.\n *\n * @default false\n */\n selectable?: boolean\n\n /**\n * Ids of the selected points, to hold the selection yourself. Leave it out\n * and the editor keeps its own.\n *\n * A `Point` takes its id from its `id` prop, or generates one that lasts as\n * long as it is mounted.\n */\n selection?: string[]\n /** The selection to start with, when the editor keeps its own. */\n defaultSelection?: string[]\n /** Called whenever the selection changes, controlled or not. */\n onSelectionChange?: (selection: string[]) => void\n\n /**\n * The editor renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <PointsEditor.Root>\n * <PointsEditor.Background>\n * <svg viewBox=\"0 0 200 100\">...</svg>\n * </PointsEditor.Background>\n * <PointsEditor.Container>\n * {points.map((point, i) => (\n * <PointsEditor.Point key={i} value={point} onChange={...} />\n * ))}\n * </PointsEditor.Container>\n * </PointsEditor.Root>\n */\n children: ReactNode\n}\n\ntype Props = PointsEditorProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorProps>\n\nexport const Root = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(\n (\n {\n width,\n height,\n disabled = false,\n readonly = false,\n wheel = DEFAULT_WHEEL,\n keyboard = DEFAULT_KEYBOARD,\n dragSensitivity = DEFAULT_DRAG_SENSITIVITY,\n selectable = false,\n selection: selectionProp,\n defaultSelection,\n onSelectionChange,\n externalStyles,\n style,\n className,\n children,\n ...props\n },\n forwardedRef,\n ) => {\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Picked apart so that the memo below depends on values rather than on the\n // object literal a caller writes inline, which is new on every render.\n const { cursor = 'grabbing' } = externalStyles ?? {}\n\n // --- selection ---\n const controlled = selectionProp !== undefined\n const [ownSelection, setOwnSelection] = useState<string[]>(\n defaultSelection ?? [],\n )\n // Nothing is selected while selection is off, so a drag picks up only the\n // point it started on and `data-selected` never turns on.\n const selection = selectable ? (selectionProp ?? ownSelection) : EMPTY\n\n // Drags read the selection from a native event handler, which runs after\n // the commit, so a ref is current by the time it matters.\n const selectionRef = useRef(selection)\n const changeHandlerRef = useRef(onSelectionChange)\n useEffect(() => {\n selectionRef.current = selection\n changeHandlerRef.current = onSelectionChange\n })\n\n const changeSelection = useCallback(\n (next: string[]) => {\n selectionRef.current = next\n if (!controlled) setOwnSelection(next)\n changeHandlerRef.current?.(next)\n },\n [controlled],\n )\n\n /**\n * Every mounted point, by id. A registration is a ref rather than a value:\n * the value inside changes on every frame of a drag, and a registry keyed\n * on it would be rebuilt just as often.\n */\n const points = useRef(new Map<string, RefObject<PointRegistration>>())\n\n const registerPoint = useCallback(\n (id: string, entry: RefObject<PointRegistration>) => {\n points.current.set(id, entry)\n return () => {\n points.current.delete(id)\n }\n },\n [],\n )\n\n /** What the current drag picked up, and where those points started. */\n const dragRef = useRef<{ id: string; start: PointBaseType }[]>([])\n\n const snapshot = useCallback((ids: readonly string[]) => {\n return ids.flatMap((id) => {\n const registration = points.current.get(id)?.current\n return registration ? [{ id, start: { ...registration.value } }] : []\n })\n }, [])\n\n const applyDeltaTo = useCallback(\n (\n entries: { id: string; start: PointBaseType }[],\n delta: PointBaseType,\n ) => {\n const withRegistration = entries.flatMap((entry) => {\n const registration = points.current.get(entry.id)?.current\n return registration ? [{ ...entry, registration }] : []\n })\n const allowed = allowedDelta(delta, withRegistration)\n for (const { start, registration } of withRegistration) {\n if (registration.readonly) continue\n // Rounded here as well as in the pipeline: a move is a subtraction\n // and an addition of its own, and that is enough to put the binary\n // artefact back (0.2 + 0.1 lands on 0.30000000000000004).\n registration.onChange?.({\n x: toPrecision(start.x + allowed.x),\n y: toPrecision(start.y + allowed.y),\n })\n }\n },\n [],\n )\n\n const beginPointDrag = useCallback(\n (id: string, modifiers: ModifierState) => {\n if (!selectable) {\n dragRef.current = snapshot([id])\n return\n }\n const current = selectionRef.current\n // Ctrl / meta rather than shift: shift is the fine-adjustment key on\n // every control here, and it cannot be both.\n const additive = modifiers.ctrlKey || modifiers.metaKey\n let next: readonly string[]\n if (additive) {\n next = current.includes(id)\n ? current.filter((x) => x !== id)\n : [...current, id]\n } else if (current.includes(id)) {\n // Already part of a group: keep it, so the group can be dragged.\n next = current\n } else {\n next = [id]\n }\n changeSelection([...next])\n // A press that took the point out of the selection was a deselect, not\n // the start of a move, so there is nothing to drag.\n dragRef.current = next.includes(id) ? snapshot(next) : []\n },\n [selectable, changeSelection, snapshot],\n )\n\n const movePointDrag = useCallback(\n (delta: PointBaseType) => applyDeltaTo(dragRef.current, delta),\n [applyDeltaTo],\n )\n\n const nudgeSelection = useCallback(\n (id: string, delta: PointBaseType) => {\n // From wherever the points are now: a key press is not a drag, so\n // there is no earlier position to measure against.\n const ids = selectionRef.current.includes(id)\n ? selectionRef.current\n : [id]\n applyDeltaTo(snapshot(ids), delta)\n },\n [applyDeltaTo, snapshot],\n )\n\n const isPointElement = useCallback(\n (element: Element | null | undefined) => {\n if (!element) return false\n for (const [, entry] of points.current) {\n if (entry.current.element?.contains(element)) return true\n }\n return false\n },\n [],\n )\n\n const nudgeFocusedPoint = useCallback(\n (axis: 'x' | 'y', direction: number, modifiers: ModifierState) => {\n const container = containerRef.current\n const active = container?.ownerDocument.activeElement\n if (!container || !active || !container.contains(active)) return false\n for (const [id, entry] of points.current) {\n const { element, wheel, readonly, onChange, value } = entry.current\n // A point answers only for the focus inside its own inputs, so both\n // axes stay part of the same interaction.\n if (!element?.contains(active)) continue\n if (!wheel || readonly || !onChange) return false\n const next = applyDelta(\n value[axis],\n direction,\n wheel,\n AXIS,\n modifiers,\n )\n // As a move, so that the rest of the selection comes along and the\n // whole group stops together at the edge.\n nudgeSelection(id, {\n x: axis === 'x' ? next - value.x : 0,\n y: axis === 'y' ? next - value.y : 0,\n })\n return true\n }\n return false\n },\n [nudgeSelection],\n )\n\n // --- selection box ---\n // The box itself lives in the core: which items a rectangle covers, and\n // what a press adds to or replaces, are not React's to decide. What is\n // left here is the registry it reads and the state the box is drawn from.\n const [selectionBox, setSelectionBox] = useState<SelectionBoxRect | null>(\n null,\n )\n const selectionBoxRef = useRef<SelectionBoxInstance<string> | null>(null)\n selectionBoxRef.current ??= createSelectionBox<string>({\n *items(): Generator<readonly [string, XY<number>]> {\n for (const [id, entry] of points.current) {\n const { x, y } = entry.current.value\n yield [id, [x, y]]\n }\n },\n onBoxChange: setSelectionBox,\n })\n\n // The selection is reported to whoever owns it, and that handler is a new\n // function whenever the caller's is, so it is handed over rather than\n // closed over.\n useEffect(() => {\n selectionBoxRef.current?.update({ onSelectionChange: changeSelection })\n }, [changeSelection])\n\n useEffect(() => {\n const box = selectionBoxRef.current\n return () => box?.destroy()\n }, [])\n\n const beginSelectionBox = useCallback(\n (at: PointBaseType, modifiers: ModifierState) => {\n if (!selectable) return\n selectionBoxRef.current?.begin([at.x, at.y], {\n // Ctrl / meta rather than shift: shift is the fine-adjustment key on\n // every control here, and it cannot be both.\n additive: modifiers.ctrlKey || modifiers.metaKey,\n selection: selectionRef.current,\n })\n },\n [selectable],\n )\n\n const moveSelectionBox = useCallback((to: PointBaseType) => {\n selectionBoxRef.current?.move([to.x, to.y])\n }, [])\n\n const endSelectionBox = useCallback(() => {\n if (!selectionBoxRef.current?.end()) return\n // A selection box is drawn on the container, which is not a control and\n // cannot hold focus, so the press that started it left the focus on\n // nothing. The arrow keys and the wheel reach a point only through the\n // focus, so it is handed to one of the points the box selected —\n // whichever point takes it moves the whole selection.\n const [first] = selectionRef.current\n if (first) points.current.get(first)?.current.element?.focus()\n }, [])\n\n const context = useMemo(\n () => ({\n disabled,\n readonly,\n wheel,\n keyboard,\n dragSensitivity,\n externalStyles: { cursor },\n containerRef,\n selectable,\n selection,\n registerPoint,\n isPointElement,\n beginPointDrag,\n movePointDrag,\n nudgeSelection,\n nudgeFocusedPoint,\n selectionBox,\n beginSelectionBox,\n moveSelectionBox,\n endSelectionBox,\n }),\n [\n disabled,\n readonly,\n wheel,\n keyboard,\n dragSensitivity,\n cursor,\n selectable,\n selection,\n registerPoint,\n isPointElement,\n beginPointDrag,\n movePointDrag,\n nudgeSelection,\n nudgeFocusedPoint,\n selectionBox,\n beginSelectionBox,\n moveSelectionBox,\n endSelectionBox,\n ],\n )\n\n return (\n <PointsEditorProvider value={context}>\n <div\n ref={forwardedRef}\n className={className}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n style={\n {\n '--width': cssLength(width),\n '--height': cssLength(height),\n // The layers inside are placed against this box.\n position: 'relative',\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {children}\n </div>\n </PointsEditorProvider>\n )\n },\n)\n\n/**\n * Multiple Point Controller\n */\nexport const PointsEditor = {\n Root,\n Background,\n Container,\n Point,\n SelectionBox,\n}\n\nexport {\n usePointsEditorContext,\n type PointsEditorContextValue,\n} from './context'\nexport { type PointsEditorBackgroundProps } from './Background'\nexport { type PointsEditorContainerProps } from './Container'\nexport { type PointsEditorSelectionBoxProps } from './SelectionBox'\nexport {\n clampPoint,\n type PointBaseType,\n type PointsEditorPointProps,\n} from './Point'\n","import { createContext, RefObject, useContext } from 'react'\n\nimport type { Scale } from '@tremolo-ui/functions'\n\nimport type { SliderThumbMethods } from './Thumb'\n\nexport type SliderContextValue = {\n value: number\n min: number\n max: number\n step: number\n /** How the value is distributed across the travel. */\n scale: Scale\n vertical: boolean\n reverse: boolean\n disabled: boolean\n readonly: boolean\n onChange?: (value: number) => void\n /**\n * Position of the thumb, 0-100, already accounting for the display direction\n * implied by `vertical` and `reverse`.\n */\n percent: number\n\n /** `Track` registers its element here; `Root` normalizes the pointer against it. */\n trackRef: RefObject<HTMLDivElement | null>\n /** `Thumb` registers itself here; `Root` focuses it when a drag starts. */\n thumbRef: RefObject<SliderThumbMethods | null>\n}\n\nconst SliderContext = /* @__PURE__ */ createContext<SliderContextValue | null>(\n null,\n)\n\nexport const SliderProvider = SliderContext.Provider\n\n/**\n * Everything here is derived during render, so there is no state to keep in\n * sync: `value` comes from the props of `Root` and the rest follows from it.\n */\nexport function useSliderContext(): SliderContextValue\nexport function useSliderContext<T>(\n selector: (state: SliderContextValue) => T,\n): T\nexport function useSliderContext<T>(\n selector?: (state: SliderContextValue) => T,\n) {\n const context = useContext(SliderContext)\n if (!context) throw new Error('Missing SliderContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import { ComponentPropsWithoutRef, CSSProperties, useCallback } from 'react'\n\nimport { toFixed, xor } from '@tremolo-ui/functions'\n\nimport { cssLength } from '../_util/css-length'\nimport { useCheckPlacement } from '../_util/Placement'\n\nimport { useSliderContext } from './context'\n\nexport interface SliderMarksOptionProps {\n /** Where the mark sits, on the same scale as the thumb. */\n value: number\n\n /**\n * Draw the mark itself. Turn it off to show the label alone.\n * @default true\n */\n mark?: boolean\n /**\n * Text shown next to the mark. Leave it out to show the value; `null` leaves\n * the label out, and an empty string draws an empty one.\n */\n label?: number | string | null\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 /** Width of the label. Sets `--label-width`. */\n labelWidth?: number | string\n /** Classes for the mark and the label inside the option. */\n classes?: {\n mark?: string\n label?: string\n }\n /** Styles for the mark and the label inside the option. */\n styles?: {\n mark?: CSSProperties\n label?: CSSProperties\n }\n}\n\nexport function MarksOption({\n value,\n mark = true,\n label,\n thickness,\n length,\n gap,\n labelWidth,\n classes,\n styles,\n className,\n style,\n ...props\n}: SliderMarksOptionProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderMarksOptionProps>) {\n useCheckPlacement('Slider.MarksOption', 'Slider.Marks')\n\n const min = useSliderContext((s) => s.min)\n const max = useSliderContext((s) => s.max)\n const scale = useSliderContext((s) => s.scale)\n const vertical = useSliderContext((s) => s.vertical)\n const reverse = useSliderContext((s) => s.reverse)\n\n const calcPercent = useCallback(\n (value: number) => {\n // The marks have to sit on the same curve the thumb runs along.\n const percent = scale.normalize(value, min, max) * 100\n return toFixed(xor(vertical, reverse) ? 100 - percent : percent)\n },\n [vertical, reverse, max, min, scale],\n )\n\n return (\n <div\n className={className}\n style={\n {\n // The mark and the label read these, so they are set once here.\n '--thickness': cssLength(thickness),\n '--length': cssLength(length),\n '--gap': cssLength(gap),\n '--label-width': cssLength(labelWidth),\n // The mechanics of the position below, as on the thumb.\n position: 'absolute',\n translate: vertical\n ? 'var(--translate, 0 -50%)'\n : 'var(--translate, -50% 0)',\n zIndex: 10,\n ...style,\n // Where the mark belongs on the track: the value, not a style.\n left: !vertical ? `${calcPercent(value)}%` : undefined,\n top: vertical ? `${calcPercent(value)}%` : undefined,\n } as CSSProperties\n }\n data-orientation={vertical ? 'vertical' : 'horizontal'}\n {...props}\n >\n {mark && (\n <div\n className={classes?.mark}\n style={styles?.mark}\n data-orientation={vertical ? 'vertical' : 'horizontal'}\n ></div>\n )}\n {label !== null && (\n <div className={classes?.label} style={styles?.label}>\n {label ?? value}\n </div>\n )}\n </div>\n )\n}\n","import { decimalPart, toFixed } from '@tremolo-ui/functions'\n\n/**\n * How `Slider.Marks` fills itself in when it is given no children: one option\n * every `per`, or every `step` of the slider. The object form turns off the\n * mark or the label for the whole set; a single option is customized by\n * writing `Slider.MarksOption` out instead.\n */\nexport type MarksOptions =\n | 'step'\n | number\n | {\n per: 'step' | number\n mark?: boolean\n label?: boolean\n }\n\nexport function generateOptionsList(\n options: MarksOptions,\n min: number,\n max: number,\n step: number,\n) {\n const {\n per,\n mark = true,\n label = true,\n } = typeof options === 'object' ? options : { per: options }\n const optionsList: {\n value: number\n mark: boolean\n label: boolean\n }[] = []\n const interval = per === 'step' ? step : per\n const count = Math.floor(max / interval) - Math.ceil(min / interval) + 1\n for (let i = 0; i < count; i++) {\n const value = toFixed(\n interval * (Math.ceil(min / interval) + i),\n decimalPart(interval)?.length,\n )\n optionsList.push({ value: value, mark: mark, label: label })\n }\n return optionsList\n}\n","import { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react'\n\nimport { xor } from '@tremolo-ui/functions'\n\nimport { cssLength } from '../_util/css-length'\nimport { Placement } from '../_util/Placement'\n\nimport { useSliderContext } from './context'\nimport { MarksOption } from './MarksOption'\nimport { generateOptionsList, MarksOptions } from './type'\n\nexport interface SliderMarksProps {\n /**\n * Space between the marks and the track. Sets `--gap`; the theme's own\n * spacing stands when this is omitted.\n */\n gap?: number | string\n /**\n * Build the marks instead of writing `Slider.MarksOption` out: a number puts\n * one every that many, `'step'` one every `step`, and `{ per, mark, label }`\n * also turns the mark or the label off for all of them. `children` is\n * ignored while it is set.\n *\n * `'step'` makes one per step, which is a great many for a fine `step`.\n */\n options?: MarksOptions\n /**\n * `<Slider.MarksOption />` goes here, one per mark. Ignored while `options`\n * is set.\n */\n children?: ReactNode\n}\n\nexport function Marks({\n gap,\n options,\n children,\n className,\n style,\n ...props\n}: SliderMarksProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderMarksProps>) {\n const min = useSliderContext((s) => s.min)\n const max = useSliderContext((s) => s.max)\n const step = useSliderContext((s) => s.step)\n const vertical = useSliderContext((s) => s.vertical)\n const reverse = useSliderContext((s) => s.reverse)\n\n const optionsList = options\n ? generateOptionsList(options, min, max, step)\n : []\n if (xor(vertical, reverse)) optionsList.reverse()\n\n return (\n <div\n className={className}\n data-orientation={vertical ? 'vertical' : 'horizontal'}\n style={\n {\n '--gap': cssLength(gap),\n // Each option inside is placed against this box.\n position: 'relative',\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n <Placement name=\"Slider.Marks\">\n {options\n ? optionsList.map(({ value, mark, label }, index) => {\n return (\n <MarksOption\n key={index}\n value={value}\n mark={mark}\n label={label ? undefined : null}\n />\n )\n })\n : children}\n </Placement>\n </div>\n )\n}\n","import {\n AriaAttributes,\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useImperativeHandle,\n useRef,\n} from 'react'\n\nimport { useCheckPlacement } from '../_util/Placement'\nimport { VisuallyHiddenRangeInput } from '../_util/VisuallyHiddenRangeInput'\n\nimport { useSliderContext } from './context'\n\nexport interface SliderThumbProps {\n /**\n * Sets `--color`, for the theme to colour the thumb with. The size is not\n * set here but by `--thumb-size` on `Slider.Root`, so that the root can\n * leave the matching room around the track.\n */\n color?: string\n\n className?: string\n style?: CSSProperties\n /**\n * Rendered inside the thumb. The thumb is one element either way, so what\n * is passed here is decoration on top of it rather than a replacement for\n * it — `className` and `style` are how its own appearance is changed.\n */\n children?: ReactNode\n 'aria-label'?: AriaAttributes['aria-label']\n 'aria-labelledby'?: AriaAttributes['aria-labelledby']\n 'aria-describedby'?: AriaAttributes['aria-describedby']\n 'aria-valuetext'?: AriaAttributes['aria-valuetext']\n}\n\nexport interface SliderThumbMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = SliderThumbProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderThumbProps>\n\nexport const Thumb = /* @__PURE__ */ forwardRef<SliderThumbMethods, Props>(\n function Thumb(\n {\n color,\n children,\n className,\n style,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n 'aria-valuetext': ariaValuetext,\n ...props\n },\n forwardedRef,\n ) {\n const inputRef = useRef<HTMLInputElement>(null)\n const {\n value,\n min,\n max,\n step,\n vertical,\n disabled,\n readonly,\n onChange,\n percent,\n thumbRef,\n } = useSliderContext()\n\n // The thumb is positioned against the track.\n useCheckPlacement('Slider.Thumb', 'Slider.Track')\n\n const methods = () => ({\n focus() {\n if (!disabled) inputRef.current?.focus()\n },\n blur() {\n inputRef.current?.blur()\n },\n })\n\n useImperativeHandle(forwardedRef, methods, [disabled])\n // Root focuses the thumb when a drag starts, wherever the user placed it.\n useImperativeHandle(thumbRef, methods, [disabled])\n\n return (\n <div\n className={className}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n {...props}\n style={{\n ...{ '--color': color },\n // Not a style but the mechanics of the position below: the thumb is\n // placed by a percentage of the track, which needs it out of flow\n // and measured from its own centre. `--translate` is there for a\n // thumb that should hang off its edge instead.\n position: 'absolute',\n translate: 'var(--translate, -50% -50%)',\n zIndex: 100,\n ...style,\n // Where the thumb sits is the component's decision, not a style: a\n // `left` from the caller would take it off the track, so it is\n // written after theirs.\n top: vertical ? `${percent}%` : '50%',\n left: !vertical ? `${percent}%` : '50%',\n }}\n >\n <VisuallyHiddenRangeInput\n ref={inputRef}\n value={value}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n aria-readonly={readonly}\n aria-orientation={vertical ? 'vertical' : 'horizontal'}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n aria-describedby={ariaDescribedby}\n aria-valuetext={ariaValuetext}\n onChange={(event) => {\n if (readonly) {\n event.currentTarget.value = String(value)\n return\n }\n onChange?.(event.currentTarget.valueAsNumber)\n }}\n />\n {children}\n </div>\n )\n },\n)\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n} from 'react'\n\nimport { xor } from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { cssLength } from '../_util/css-length'\nimport { Placement } from '../_util/Placement'\n\nimport { useSliderContext } from './context'\n\nexport interface SliderTrackProps {\n /**\n * How long the track is along the axis the slider runs. Sets `--length`;\n * the size the theme gives it stands when this is omitted.\n */\n length?: number | string\n /** How thick the track is across that axis. Sets `--thickness`. */\n thickness?: number | string\n\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 className?: string\n style?: CSSProperties\n /** `<Slider.Thumb />` goes here. */\n children?: ReactNode\n}\n\ntype Props = SliderTrackProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderTrackProps>\n\nexport const Track = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(\n function Track(\n {\n length,\n thickness,\n active,\n inactive,\n children,\n className,\n style,\n ...props\n },\n forwardedRef,\n ) {\n const { vertical, reverse, disabled, percent, trackRef } =\n useSliderContext()\n\n // The track is what the pointer position is normalized against, so the\n // context ref is composed with any ref the caller passed.\n const composedRef = useComposedRefs<HTMLDivElement>(forwardedRef, trackRef)\n\n return (\n <div\n ref={composedRef}\n className={className}\n data-disabled={disabled ? '' : undefined}\n data-orientation={vertical ? 'vertical' : 'horizontal'}\n // Which end the value grows from. `percent` is already the position on\n // screen, so this only says which side of it is the filled one.\n data-flipped={xor(vertical, reverse) ? '' : undefined}\n style={\n {\n '--active': active,\n '--inactive': inactive,\n '--length': cssLength(length),\n '--thickness': cssLength(thickness),\n // Where the value sits, for the theme to paint the fill with. The\n // component draws nothing itself: this is the one number CSS cannot\n // work out on its own.\n '--percent': `${percent}%`,\n // The thumb inside is placed against this box.\n position: 'relative',\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n <Placement name=\"Slider.Track\">{children}</Placement>\n </div>\n )\n },\n)\n","import React, {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react'\n\nimport type { AxisOptions, XY } from '@tremolo-ui/dom'\nimport {\n applyDelta,\n linearScale,\n toFixed,\n type InputEventOption,\n type ModifierValue,\n selectModifier,\n xor,\n type Scale,\n} from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { useCheckSteps } from '../../hooks/_internal/useCheckSteps'\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport {\n DEFAULT_DRAG_SENSITIVITY,\n DEFAULT_KEYBOARD_OPTIONS,\n DEFAULT_WHEEL_OPTIONS,\n} from '../../input-event'\n\nimport { SliderProvider } from './context'\nimport { Marks } from './Marks'\nimport { MarksOption } from './MarksOption'\nimport { Thumb, SliderThumbMethods } from './Thumb'\nimport { Track } from './Track'\n\nconst defaultExternalStyles: SliderProps['externalStyles'] = {\n cursor: 'pointer',\n}\n\nexport interface SliderProps {\n /** The current value. The slider shows only this, so update it from `onChange`. */\n value: number\n /** The value at the start of the travel. */\n min: number\n /** The value at the end of the travel. */\n max: number\n\n /**\n * Granularity of the value. A drag, the wheel and the arrow keys snap it to\n * multiples of `step`.\n *\n * @default 1\n */\n step?: number\n /**\n * How the value is distributed across the travel.\n *\n * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,\n * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or\n * `skewScale(n)` for a value that has to match a JUCE parameter.\n *\n * @default linearScale\n */\n scale?: Scale\n /**\n * Run the slider vertically, with the value growing upwards. The range input\n * inside the thumb takes its `aria-orientation` from this.\n *\n * @default false\n */\n vertical?: boolean\n /**\n * Grow the value the other way: leftwards, or downwards when `vertical`.\n * The arrow keys follow the direction on screen.\n *\n * @default false\n */\n reverse?: boolean\n\n /**\n * The cursor to show while dragging. It is set on the dragged element, so it\n * stays while the pointer is outside the slider.\n *\n * @default { cursor: 'pointer' }\n */\n externalStyles?: {\n cursor?: CSSProperties['cursor']\n }\n /**\n * How much one notch of the wheel moves the value. It only acts while the\n * focus is inside, so that scrolling the page past the slider leaves it\n * alone.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range between `min` and `max`. The result is snapped to `step`, except for\n * an amount set on a modifier key (`{ default: …, shift: … }`). `null` turns\n * the wheel off.\n *\n * @default ['raw', 1]\n */\n wheel?: ModifierValue<InputEventOption> | null\n /**\n * How much a drag moves the value, per modifier key.\n *\n * `1` is the pointer position itself, which is what a drag normally is here.\n * **Anything else turns the drag relative**: `0.1` makes the same movement\n * cover a tenth of the travel, so the value stops following the pointer and\n * starts moving a tenth as fast. Shift is bound to `0.1` by default, to\n * match what it does on the arrow keys.\n *\n * Pressing or releasing the key mid-drag does not disturb the value: the\n * travel so far is kept and the new sensitivity applies from there. **The\n * pointer and the value stay apart for the rest of the drag** — snapping\n * them back together on release would move the value nobody asked to move.\n *\n * @default { default: 1, shift: 0.1 }\n */\n dragSensitivity?: ModifierValue<number>\n\n /**\n * How much one arrow key press moves the value.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range between `min` and `max`. The result is snapped to `step`, except for\n * an amount set on a modifier key, which is what lets shift move off the\n * grid. `null` turns the arrow keys off.\n *\n * The default moves by 1, and by 0.1 with shift. With a `step` above 1, raise\n * the amount to match: 1 would round straight back to where it started, and\n * a development build warns about it.\n *\n * @default { default: ['raw', 1], shift: ['raw', 0.1] }\n */\n keyboard?: ModifierValue<InputEventOption> | null\n\n /**\n * Make the slider unchangeable and remove it from the tab order.\n * The parts carry `data-disabled` while it is set.\n */\n disabled?: boolean\n /**\n * Make the value unchangeable.\n * The parts carry `data-readonly` while it is set.\n */\n readonly?: boolean\n className?: string\n style?: CSSProperties\n /** Called with the new value when a drag, the wheel or an arrow key moves it. */\n onChange?: (value: number) => void\n /** Called when a drag starts, with the value where the track was pressed. */\n onDragStart?: (value: number) => void\n /** Called when the drag ends, with the value it ended on. */\n onDragEnd?: (value: number) => void\n /**\n * The slider renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <Slider.Root value={value} min={0} max={100} onChange={setValue}>\n * <Slider.Track>\n * <Slider.Thumb aria-label=\"Level\" />\n * </Slider.Track>\n * </Slider.Root>\n */\n children: ReactNode\n}\n\nexport interface SliderMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = SliderProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof SliderProps>\n\n/**\n * The wheel only acts while the focus is inside, so that scrolling a page past\n * the control does not change its value.\n */\nconst WHEEL_OPTIONS = { requireFocus: true }\n\nexport const Root = /* @__PURE__ */ forwardRef<SliderMethods, Props>(\n (\n {\n value,\n min,\n max,\n step = 1,\n scale = linearScale,\n vertical = false,\n reverse = false,\n externalStyles: _externalStyles,\n wheel = DEFAULT_WHEEL_OPTIONS,\n keyboard = DEFAULT_KEYBOARD_OPTIONS,\n dragSensitivity = DEFAULT_DRAG_SENSITIVITY,\n disabled = false,\n readonly = false,\n onChange,\n onDragStart,\n onDragEnd,\n className,\n style,\n children,\n onFocus,\n onBlur,\n onPointerDown,\n onKeyDown,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n // -- state and ref ---\n const trackRef = useRef<HTMLDivElement>(null)\n const thumbRef = useRef<SliderThumbMethods>(null)\n // --- interpret props ---\n const externalStyles = { ...defaultExternalStyles, ..._externalStyles }\n const inactive = disabled || readonly\n\n const p = toFixed(scale.normalize(value, min, max) * 100)\n const rev = toFixed(100 - p)\n // NOTE\n // normal -> normal (right)\n // vertical -> rev (up)\n // reverse -> rev (left)\n // vertical & reverse -> normal (down)\n const displayReversed = useMemo(\n () => xor(vertical, reverse),\n [vertical, reverse],\n )\n const percent = displayReversed ? rev : p\n\n // --- internal functions ---\n // The pointer is normalized against the track on both axes; only the one\n // the slider runs along is read back. `AxisOptions` extends `ValueRange`,\n // so the same object also describes the scaling for `applyDelta`.\n const axis: AxisOptions = useMemo(\n () => ({ min, max, step, scale, reverse: displayReversed }),\n [min, max, step, scale, displayReversed],\n )\n\n useCheckSteps({ component: 'Slider', range: axis, keyboard, wheel })\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n const key = event.key\n if (!['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key))\n return\n event.preventDefault()\n if (!keyboard || !onChange || inactive) return\n let direction = key === 'ArrowRight' || key === 'ArrowUp' ? 1 : -1\n if (reverse) direction *= -1\n onChange(applyDelta(value, direction, keyboard, axis, event))\n },\n [keyboard, onChange, inactive, reverse, value, axis],\n )\n\n // --- hooks ---\n const valueOf = (v: XY<number>) => v[vertical ? 1 : 0]\n\n const { refCallback: dragRefCallback } = useDragValue<HTMLDivElement>({\n axis,\n baseElementRef: trackRef,\n cursor: inactive ? undefined : externalStyles.cursor,\n shouldStart: () => !inactive,\n sensitivity: (state) =>\n selectModifier(dragSensitivity, state.event).value,\n updateOnPointerDown: true,\n onChange: (v) => {\n if (inactive) return\n onChange?.(valueOf(v))\n },\n onDragStart: (v) => {\n if (inactive) return\n thumbRef.current?.focus()\n onDragStart?.(valueOf(v))\n },\n onDragEnd: (v) => {\n if (inactive) return\n onDragEnd?.(valueOf(v))\n },\n })\n\n const wheelRefCallback = useWheel<HTMLDivElement>((event) => {\n if (!wheel || !onChange || inactive) return\n event.preventDefault()\n let direction\n if (!vertical && event.deltaX !== 0) {\n direction = event.deltaX > 0 ? 1 : -1\n } else {\n if (event.deltaY === 0) return\n direction = event.deltaY > 0 ? -1 : 1\n }\n if (reverse) direction *= -1\n onChange(applyDelta(value, direction, wheel, axis, event))\n }, WHEEL_OPTIONS)\n\n // Composed once, so React attaches the refs a single time instead of\n // detaching and re-attaching on every render.\n const rootRefCallback = useComposedRefs<HTMLDivElement>(\n dragRefCallback,\n wheelRefCallback,\n )\n\n const context = useMemo(\n () => ({\n value,\n min,\n max,\n step,\n scale,\n vertical,\n reverse,\n disabled,\n readonly,\n onChange,\n percent,\n trackRef,\n thumbRef,\n }),\n [\n value,\n min,\n max,\n step,\n scale,\n vertical,\n reverse,\n disabled,\n readonly,\n onChange,\n percent,\n ],\n )\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n if (!disabled) thumbRef.current?.focus()\n },\n blur() {\n thumbRef.current?.blur()\n },\n }\n }, [disabled])\n\n return (\n <SliderProvider value={context}>\n {/* oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- the group is the pointer and keyboard event area, while the nested range input carries its control semantics */}\n <div\n className={className}\n ref={rootRefCallback}\n role=\"group\"\n // A press lands on the track or the thumb, neither of which can hold\n // focus, and the browser answers that by clearing the focus to the\n // body — undoing the focus the drag just gave the input. Taking the\n // focus here keeps it inside, and `onFocus` passes it to the input.\n tabIndex={-1}\n data-orientation={vertical ? 'vertical' : 'horizontal'}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n style={style}\n onPointerDown={onPointerDown}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n onFocus={(event) => {\n if (!disabled) thumbRef.current?.focus()\n onFocus?.(event)\n }}\n onBlur={(event) => {\n thumbRef.current?.blur()\n onBlur?.(event)\n }}\n {...props}\n >\n {children}\n </div>\n </SliderProvider>\n )\n },\n)\n\n/**\n * Customizable slider\n */\nexport const Slider = {\n Root,\n Thumb,\n Track,\n Marks,\n MarksOption,\n}\n\nexport { useSliderContext, type SliderContextValue } from './context'\nexport { type SliderThumbMethods, type SliderThumbProps } from './Thumb'\nexport { type SliderTrackProps } from './Track'\nexport { type SliderMarksProps } from './Marks'\nexport { type SliderMarksOptionProps } from './MarksOption'\nexport { type MarksOptions } from './type'\n","import { createContext, RefObject, useContext } from 'react'\n\nimport { toXY, type XY, type XYInput } from '@tremolo-ui/dom'\nimport type { Scale } from '@tremolo-ui/functions'\n\nimport type { XYPadThumbMethods } from './Thumb'\n\nexport { toXY, type XY, type XYInput }\n\nexport type XYPadContextValue = {\n value: XY<number>\n min: XY<number>\n max: XY<number>\n step: XY<number>\n /** How the value of each axis is distributed across the travel. */\n scale: XY<Scale>\n reverse: XY<boolean>\n disabled: boolean\n readonly: boolean\n onChange?: (value: XY<number>) => void\n\n /**\n * Position of the thumb, 0-100 per axis, already accounting for `reverse`.\n */\n percent: XY<number>\n\n /** `Area` registers its element here; `Root` normalizes the pointer against it. */\n areaRef: RefObject<HTMLDivElement | null>\n /** `Thumb` registers itself here; `Root` focuses it when a drag starts. */\n thumbRef: RefObject<XYPadThumbMethods | null>\n}\n\nconst XYPadContext = /* @__PURE__ */ createContext<XYPadContextValue | null>(\n null,\n)\n\nexport const XYPadProvider = XYPadContext.Provider\n\n/**\n * Everything here is derived during render, so there is no state to keep in\n * sync: `value` comes from the props of `Root` and the rest follows from it.\n */\nexport function useXYPadContext(): XYPadContextValue\nexport function useXYPadContext<T>(selector: (state: XYPadContextValue) => T): T\nexport function useXYPadContext<T>(selector?: (state: XYPadContextValue) => T) {\n const context = useContext(XYPadContext)\n if (!context) throw new Error('Missing XYPadContext.Provider in the tree')\n return selector ? selector(context) : context\n}\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n} from 'react'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { cssLength } from '../_util/css-length'\nimport { Placement } from '../_util/Placement'\n\nimport { useXYPadContext } from './context'\n\nexport interface XYPadAreaProps {\n /** Sets `--width`; the size the theme gives it stands when omitted. */\n width?: number | string\n /** Sets `--height`; the size the theme gives it stands when omitted. */\n height?: number | string\n /** Sets `--color`, for the theme to colour the area with. */\n color?: string\n className?: string\n style?: CSSProperties\n /** `<XYPad.Thumb />` goes here. */\n children?: ReactNode\n}\n\ntype Props = XYPadAreaProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadAreaProps>\n\nexport const Area = /* @__PURE__ */ forwardRef<HTMLDivElement, Props>(\n function Area(\n { width, height, color, children, className, style, ...props },\n forwardedRef,\n ) {\n const { areaRef } = useXYPadContext()\n\n // The area is what the pointer position is normalized against, so the\n // context ref is composed with any ref the caller passed.\n const composedRef = useComposedRefs<HTMLDivElement>(forwardedRef, areaRef)\n\n return (\n <div\n ref={composedRef}\n className={className}\n style={\n {\n '--color': color,\n '--width': cssLength(width),\n '--height': cssLength(height),\n // The thumb inside is placed against this box.\n position: 'relative',\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n <Placement name=\"XYPad.Area\">{children}</Placement>\n </div>\n )\n },\n)\n","import {\n AriaAttributes,\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n useImperativeHandle,\n useRef,\n} from 'react'\n\nimport { useCheckPlacement } from '../_util/Placement'\nimport { VisuallyHiddenRangeInput } from '../_util/VisuallyHiddenRangeInput'\n\nimport { toXY, useXYPadContext, type XYInput } from './context'\n\nexport interface XYPadThumbProps {\n /**\n * Sets `--color`, for the theme to colour the thumb with. The size is not\n * set here but by `--thumb-size` on `XYPad.Root`, so that the root can leave\n * the matching room around the area.\n */\n color?: string\n\n className?: string\n style?: CSSProperties\n /**\n * Rendered inside the thumb. The thumb is one element either way, so what\n * is passed here is decoration on top of it rather than a replacement for\n * it — `className` and `style` are how its own appearance is changed.\n */\n children?: ReactNode\n\n /**\n * The accessible name of each axis, as `[x, y]`. There are two range inputs\n * inside the thumb, so each takes a name of its own; a single string names\n * them both, which is rarely what you want.\n */\n 'aria-label'?: XYInput<AriaAttributes['aria-label']>\n /** The ids of what labels each axis, as `[x, y]` or one for both. */\n 'aria-labelledby'?: XYInput<AriaAttributes['aria-labelledby']>\n /** The ids of what describes each axis, as `[x, y]` or one for both. */\n 'aria-describedby'?: XYInput<AriaAttributes['aria-describedby']>\n /**\n * What the value of each axis means, when the number does not say it, as\n * `[x, y]` or one for both.\n */\n 'aria-valuetext'?: XYInput<AriaAttributes['aria-valuetext']>\n}\n\nexport interface XYPadThumbMethods {\n focus: () => void\n blur: () => void\n}\n\ntype Props = XYPadThumbProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadThumbProps>\n\nexport const Thumb = /* @__PURE__ */ forwardRef<XYPadThumbMethods, Props>(\n function Thumb(\n {\n color,\n children,\n className,\n style,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n 'aria-valuetext': ariaValuetext,\n ...props\n },\n forwardedRef,\n ) {\n const xInputRef = useRef<HTMLInputElement>(null)\n const yInputRef = useRef<HTMLInputElement>(null)\n const {\n value,\n min,\n max,\n step,\n disabled,\n readonly,\n onChange,\n percent,\n thumbRef,\n } = useXYPadContext()\n\n // The thumb is positioned against the area.\n useCheckPlacement('XYPad.Thumb', 'XYPad.Area')\n\n // Per axis, since the thumb holds one input for each.\n const labels = toXY(ariaLabel)\n const labelledby = toXY(ariaLabelledby)\n const describedby = toXY(ariaDescribedby)\n const valueText = toXY(ariaValuetext)\n\n const methods = () => ({\n focus() {\n if (!disabled) xInputRef.current?.focus()\n },\n blur() {\n xInputRef.current?.blur()\n yInputRef.current?.blur()\n },\n })\n\n useImperativeHandle(forwardedRef, methods, [disabled])\n // Root focuses the thumb when a drag starts, wherever the user placed it.\n useImperativeHandle(thumbRef, methods, [disabled])\n\n return (\n <div\n className={className}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n {...props}\n style={{\n ...{ '--color': color },\n // Not a style but the mechanics of the position below: the thumb is\n // placed by a percentage of the area, which needs it out of flow and\n // measured from its own centre.\n position: 'absolute',\n translate: 'var(--translate, -50% -50%)',\n zIndex: 100,\n ...style,\n // Where the thumb sits is the component's decision, not a style: a\n // `left` from the caller would take it off the area, so it is written\n // after theirs.\n left: `${percent[0]}%`,\n top: `${percent[1]}%`,\n }}\n >\n {([0, 1] as const).map((axis) => (\n <VisuallyHiddenRangeInput\n key={axis}\n ref={axis === 0 ? xInputRef : yInputRef}\n data-axis={axis === 0 ? 'x' : 'y'}\n value={value[axis]}\n min={min[axis]}\n max={max[axis]}\n step={step[axis]}\n disabled={disabled}\n aria-readonly={readonly}\n aria-orientation={axis === 0 ? 'horizontal' : 'vertical'}\n aria-label={labels[axis] ?? (axis === 0 ? 'x' : 'y')}\n aria-labelledby={labelledby[axis]}\n aria-describedby={describedby[axis]}\n aria-valuetext={valueText[axis]}\n onChange={(event) => {\n if (readonly) {\n event.currentTarget.value = String(value[axis])\n return\n }\n const next = [...value] as [number, number]\n next[axis] = event.currentTarget.valueAsNumber\n onChange?.(next)\n }}\n />\n ))}\n {children}\n </div>\n )\n },\n)\n","import {\n ComponentPropsWithoutRef,\n CSSProperties,\n forwardRef,\n ReactNode,\n Ref,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n} from 'react'\n\nimport type { AxisOptions } from '@tremolo-ui/dom'\nimport {\n applyDelta,\n linearScale,\n toFixed,\n InputEventOption,\n ModifierState,\n type ModifierValue,\n selectModifier,\n type Scale,\n} from '@tremolo-ui/functions'\n\nimport { useComposedRefs } from '../../compose-refs'\nimport { useCheckSteps } from '../../hooks/_internal/useCheckSteps'\nimport { useDragValue } from '../../hooks/useDragValue'\nimport { useWheel } from '../../hooks/useWheel'\nimport {\n DEFAULT_DRAG_SENSITIVITY,\n DEFAULT_KEYBOARD_OPTIONS,\n DEFAULT_WHEEL_OPTIONS,\n} from '../../input-event'\n\nimport { Area } from './Area'\nimport { toXY, XY, XYInput, XYPadProvider } from './context'\nimport { Thumb, XYPadThumbMethods } from './Thumb'\n\nconst defaultExternalStyles: XYPadProps['externalStyles'] = {\n cursor: 'pointer',\n}\n\n/**\n * Two-dimensional slider component.\n *\n * The per-axis settings mirror `Slider`, given as `[x, y]` tuples. A plain\n * value applies to both axes.\n */\nexport interface XYPadProps {\n /** The current value as `[x, y]`. The pad shows only this, so update it from `onChange`. */\n value: XY<number>\n /** The value at the start of each axis, as `[x, y]` or one number for both. */\n min: XYInput<number>\n /** The value at the end of each axis, as `[x, y]` or one number for both. */\n max: XYInput<number>\n\n /**\n * Granularity of each axis, as `[x, y]` or one number for both. A drag, the\n * wheel and the arrow keys snap the value to multiples of it.\n *\n * @default 1\n */\n step?: XYInput<number>\n /**\n * How the value of each axis is distributed across the travel, as `[x, y]`\n * or one scale for both.\n *\n * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,\n * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or\n * `skewScale(n)` for a value that has to match a JUCE parameter.\n *\n * @default linearScale\n */\n scale?: XYInput<Scale>\n /**\n * Grow an axis the other way, as `[x, y]` or one for both. By default x grows\n * rightwards and y downwards. The arrow keys follow the direction on screen.\n *\n * @default false\n */\n reverse?: XYInput<boolean>\n\n /**\n * How much one notch of the wheel moves the value. It only acts while the\n * focus is inside, so that scrolling the page past the pad leaves it alone.\n * Scrolling sideways, or with shift held, moves x; otherwise it moves y.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range of that axis. The result is snapped to `step`, except for an amount\n * set on a modifier key (`{ default: …, alt: … }`). `null` turns the wheel\n * off.\n *\n * @default ['raw', 1]\n */\n wheel?: ModifierValue<InputEventOption> | null\n /**\n * How much a drag moves the value, per modifier key.\n *\n * `1` is the pointer position itself, which is what a drag normally is here.\n * **Anything else turns the drag relative**: `0.1` makes the same movement\n * cover a tenth of the travel, so the value stops following the pointer and\n * starts moving a tenth as fast. Shift is bound to `0.1` by default, to\n * match what it does on the arrow keys.\n *\n * Pressing or releasing the key mid-drag does not disturb the value: the\n * travel so far is kept and the new sensitivity applies from there. **The\n * pointer and the value stay apart for the rest of the drag** — snapping\n * them back together on release would move the value nobody asked to move.\n *\n * @default { default: 1, shift: 0.1 }\n */\n dragSensitivity?: ModifierValue<number>\n\n /**\n * How much one arrow key press moves the value. Left and right move x, up\n * and down move y.\n *\n * `['raw', n]` moves the value by `n`, and `['normalized', n]` by `n` of the\n * range of that axis. The result is snapped to `step`, except for an amount\n * set on a modifier key, which is what lets shift move off the grid. `null`\n * turns the arrow keys off.\n *\n * The default moves by 1, and by 0.1 with shift. With a `step` above 1, raise\n * the amount to match: 1 would round straight back to where it started, and\n * a development build warns about it.\n *\n * @default { default: ['raw', 1], shift: ['raw', 0.1] }\n */\n keyboard?: ModifierValue<InputEventOption> | null\n\n /**\n * The cursor to show while dragging. It is set on the dragged element, so it\n * stays while the pointer is outside the pad.\n *\n * @default { cursor: 'pointer' }\n */\n externalStyles?: {\n cursor?: CSSProperties['cursor']\n }\n\n /**\n * Make the pad unchangeable and remove its thumb from the tab order.\n * The parts carry `data-disabled` while it is set.\n */\n disabled?: boolean\n /**\n * Make the pad unchangeable while leaving its thumb focusable.\n * The parts carry `data-readonly` while it is set.\n */\n readonly?: boolean\n\n /** Called with the new value when a drag, the wheel or an arrow key moves it. */\n onChange?: (value: XY<number>) => void\n /** Called when a drag starts, with the value where the area was pressed. */\n onDragStart?: (value: XY<number>) => void\n /** Called when the drag ends, with the value it ended on. */\n onDragEnd?: (value: XY<number>) => void\n\n /**\n * The pad renders exactly what you compose here; there is no default\n * markup to fall back to.\n *\n * @example\n * <XYPad.Root value={[x, y]} min={0} max={100} onChange={setValue}>\n * <XYPad.Area>\n * <XYPad.Thumb />\n * </XYPad.Area>\n * </XYPad.Root>\n */\n children: ReactNode\n}\n\nexport interface XYPadMethods {\n focus: () => void\n blur: () => void\n original: Ref<HTMLDivElement>\n}\n\ntype Props = XYPadProps &\n Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadProps>\n\n/**\n * The wheel only acts while the focus is inside, so that scrolling a page past\n * the control does not change its value.\n */\nconst WHEEL_OPTIONS = { requireFocus: true }\n\nexport const Root = /* @__PURE__ */ forwardRef<XYPadMethods, Props>(\n (\n {\n value,\n min: _min,\n max: _max,\n step: _step = 1,\n scale: _scale = linearScale,\n reverse: _reverse = false,\n wheel = DEFAULT_WHEEL_OPTIONS,\n keyboard = DEFAULT_KEYBOARD_OPTIONS,\n dragSensitivity = DEFAULT_DRAG_SENSITIVITY,\n className,\n style,\n externalStyles: _externalStyles,\n disabled = false,\n readonly = false,\n onChange,\n onDragStart,\n onDragEnd,\n onPointerDown,\n onKeyDown,\n onFocus,\n onBlur,\n children,\n ...props\n }: Props,\n forwardedRef,\n ) => {\n // -- state and ref ---\n const rootRef = useRef<HTMLDivElement>(null)\n const areaRef = useRef<HTMLDivElement>(null)\n const thumbRef = useRef<XYPadThumbMethods>(null)\n\n // --- interpret props ---\n const externalStyles = { ...defaultExternalStyles, ..._externalStyles }\n const inactive = disabled || readonly\n\n const min = useMemo(() => toXY(_min), [_min])\n const max = useMemo(() => toXY(_max), [_max])\n const step = useMemo(() => toXY(_step), [_step])\n const scale = useMemo(() => toXY(_scale), [_scale])\n const reverse = useMemo(() => toXY(_reverse), [_reverse])\n\n const percent = useMemo((): XY<number> => {\n const normalized = [0, 1].map((i) =>\n scale[i].normalize(value[i], min[i], max[i]),\n )\n return [0, 1].map((i) =>\n toFixed((reverse[i] ? 1 - normalized[i] : normalized[i]) * 100),\n ) as XY<number>\n }, [value, min, max, scale, reverse])\n\n // --- internal functions ---\n // `AxisOptions` extends `ValueRange`, so the same pair also describes the\n // scaling for `applyDelta`. Its `reverse` only concerns the drag, where\n // positions follow the screen; the key and wheel handlers below flip the\n // direction themselves.\n const axis = useMemo(\n (): XY<AxisOptions> =>\n [0, 1].map((i) => ({\n min: min[i],\n max: max[i],\n step: step[i],\n scale: scale[i],\n reverse: reverse[i],\n })) as XY<AxisOptions>,\n [min, max, step, scale, reverse],\n )\n\n useCheckSteps({\n component: 'XYPad',\n axis: 'x',\n range: axis[0],\n keyboard,\n wheel,\n })\n useCheckSteps({\n component: 'XYPad',\n axis: 'y',\n range: axis[1],\n keyboard,\n wheel,\n })\n\n const withAxis = useCallback(\n (axis: 0 | 1, next: number): XY<number> =>\n axis === 0 ? [next, value[1]] : [value[0], next],\n [value],\n )\n\n /** @param i 0 = x, 1 = y */\n const nudge = useCallback(\n (\n i: 0 | 1,\n direction: number,\n option: ModifierValue<InputEventOption>,\n modifiers: ModifierState,\n ): XY<number> =>\n withAxis(\n i,\n applyDelta(value[i], direction, option, axis[i], modifiers),\n ),\n [value, axis, withAxis],\n )\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n const key = event.key\n if (!['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key))\n return\n\n // The key picks the axis, whichever of the two inputs holds the\n // focus: the pad is one control to the person moving it, and the focus\n // lands on the x input, so reading the axis off the input would leave\n // the y axis with no keys at all.\n const i: 0 | 1 = key === 'ArrowRight' || key === 'ArrowLeft' ? 0 : 1\n event.preventDefault()\n if (!onChange || inactive || !keyboard) return\n let direction = 1\n if (key === 'ArrowLeft' || key === 'ArrowUp') direction *= -1\n if (reverse[i]) direction *= -1\n onChange(nudge(i, direction, keyboard, event))\n },\n [onChange, inactive, keyboard, reverse, nudge],\n )\n\n // --- hooks ---\n\n const { refCallback: dragRefCallback } = useDragValue<HTMLDivElement>({\n axis,\n baseElementRef: areaRef,\n sensitivity: (state) =>\n selectModifier(dragSensitivity, state.event).value,\n updateOnPointerDown: true,\n cursor: inactive ? undefined : externalStyles.cursor,\n shouldStart: () => !inactive,\n onChange: (v) => {\n if (inactive) return\n onChange?.(v)\n },\n onDragStart: (v) => {\n if (inactive) return\n thumbRef.current?.focus()\n onDragStart?.(v)\n },\n onDragEnd: (v) => {\n if (inactive) return\n onDragEnd?.(v)\n },\n })\n\n const wheelRefCallback = useWheel<HTMLDivElement>((event) => {\n if (!onChange || inactive || !wheel) return\n // Browsers turn shift+wheel into horizontal scrolling: `deltaY` comes\n // out empty and `deltaX` carries the movement. Reading whichever axis\n // moved keeps shift working as the x-axis modifier — and picks up a\n // trackpad's own horizontal gesture, which never had a modifier.\n const horizontal = event.deltaX !== 0\n const delta = horizontal ? event.deltaX : event.deltaY\n if (delta === 0) return\n const i: 0 | 1 = horizontal || event.shiftKey ? 0 : 1\n event.preventDefault()\n let direction = 1\n if (delta < 0) direction *= -1\n if (reverse[i]) direction *= -1\n onChange(nudge(i, direction, wheel, event))\n }, WHEEL_OPTIONS)\n\n // Composed once, so React attaches the refs a single time instead of\n // detaching and re-attaching on every render.\n const rootRefCallback = useComposedRefs<HTMLDivElement>(\n rootRef,\n dragRefCallback,\n wheelRefCallback,\n )\n\n const context = useMemo(\n () => ({\n value,\n min,\n max,\n step,\n scale,\n reverse,\n disabled,\n readonly,\n onChange,\n percent,\n areaRef,\n thumbRef,\n }),\n [\n value,\n min,\n max,\n step,\n scale,\n reverse,\n disabled,\n readonly,\n onChange,\n percent,\n ],\n )\n\n useImperativeHandle(forwardedRef, () => {\n return {\n focus() {\n if (!disabled) thumbRef.current?.focus()\n },\n blur() {\n thumbRef.current?.blur()\n },\n original: rootRef,\n }\n }, [disabled])\n\n return (\n <XYPadProvider value={context}>\n {/* oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- the group handles pointer and keyboard input shared by its two range controls */}\n <div\n className={className}\n ref={rootRefCallback}\n role=\"group\"\n tabIndex={-1}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readonly ? '' : undefined}\n style={style}\n onPointerDown={onPointerDown}\n onKeyDown={(event) => {\n handleKeyDown(event)\n onKeyDown?.(event)\n }}\n onFocus={(event) => {\n if (!disabled) thumbRef.current?.focus()\n onFocus?.(event)\n }}\n onBlur={(event) => {\n thumbRef.current?.blur()\n onBlur?.(event)\n }}\n {...props}\n >\n {children}\n </div>\n </XYPadProvider>\n )\n },\n)\n\n/**\n * Simple XYPad\n */\nexport const XYPad = {\n Root,\n Thumb,\n Area,\n}\n\nexport { type XYPadThumbProps, type XYPadThumbMethods } from './Thumb'\nexport { type XYPadAreaProps } from './Area'\nexport {\n useXYPadContext,\n type XYPadContextValue,\n type XY,\n type XYInput,\n} from './context'\n","import { DependencyList, useEffect, useRef } from 'react'\n\nimport { useCallbackRef } from './_internal/useCallbackRef'\n\nexport function useAnimationFrame(\n callback = () => {},\n deps: DependencyList = [],\n) {\n const reqIdRef = useRef(-1)\n // Read through a ref rather than depended on: `useAnimationFrame(() => ...)`\n // is a new function on every render, and a callback that renders would then\n // cancel and re-schedule its own loop on every frame. What restarts the loop\n // is the caller's `deps`, and nothing else.\n const runCallback = useCallbackRef(callback)\n\n useEffect(() => {\n // Kept inside the effect: as a `useCallback` the loop would have to\n // reference itself before it is declared, which the compiler rules reject.\n const loop = () => {\n reqIdRef.current = requestAnimationFrame(loop)\n runCallback()\n }\n\n reqIdRef.current = requestAnimationFrame(loop)\n return () => cancelAnimationFrame(reqIdRef.current)\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [runCallback, ...deps])\n}\n","import { useEffect, useMemo, useSyncExternalStore } from 'react'\n\nimport {\n createMIDIAccess,\n type MIDIAccessInstance,\n type MIDIAccessOptions,\n type MIDIAccessState,\n} from '@tremolo-ui/dom'\n\nexport {\n NOT_SUPPORTED,\n PERMISSION_DENIED,\n UNAVAILABLE,\n type MIDIAccessError,\n type MIDIAccessOptions,\n} from '@tremolo-ui/dom'\n\nconst INITIAL_STATE: MIDIAccessState = {\n midiAccess: null,\n error: null,\n inputs: [],\n}\n\nfunction createMIDIAccessStore() {\n let instance: MIDIAccessInstance | null = null\n let unsubscribe: VoidFunction | null = null\n let state = INITIAL_STATE\n const listeners = new Set<VoidFunction>()\n\n function emit() {\n for (const listener of listeners) listener()\n }\n\n function connect() {\n const nextInstance = createMIDIAccess()\n instance = nextInstance\n state = nextInstance.getState()\n unsubscribe = nextInstance.subscribe(() => {\n state = nextInstance.getState()\n emit()\n })\n emit()\n return nextInstance\n }\n\n function disconnect(currentInstance: MIDIAccessInstance) {\n if (instance !== currentInstance) return\n\n unsubscribe?.()\n unsubscribe = null\n instance = null\n state = INITIAL_STATE\n currentInstance.destroy()\n emit()\n }\n\n function request(options?: MIDIAccessOptions) {\n instance?.request(options)\n }\n\n return {\n connect,\n disconnect,\n request,\n getState: () => state,\n getServerState: () => INITIAL_STATE,\n subscribe: (listener: VoidFunction) => {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n }\n}\n\n/**\n * Hooks for requesting MIDI access in the browser. The first argument allows you to choose whether to request access on mount.\n *\n * `inputs` follows the devices: it changes as one is plugged in or unplugged,\n * so a list of devices needs no `statechange` listener of its own.\n *\n * `request` takes `{ sysex: true }` when the app needs system exclusive\n * messages. Browsers treat that as a separate, more sensitive permission, so\n * ask for it only when it is actually used.\n */\nexport function useMIDIAccess(requestOnMount = true) {\n const store = useMemo(() => createMIDIAccessStore(), [])\n\n const { midiAccess, error, inputs } = useSyncExternalStore(\n store.subscribe,\n store.getState,\n store.getServerState,\n )\n\n useEffect(() => {\n const instance = store.connect()\n return () => store.disconnect(instance)\n }, [store])\n\n useEffect(() => {\n if (requestOnMount) store.request()\n }, [store, requestOnMount])\n\n return { request: store.request, midiAccess, error, inputs }\n}\n","import { useEffect, useRef } from 'react'\n\nimport {\n createMIDIInput,\n PITCH_BEND_CENTER,\n type MIDIInputHandlers,\n type MIDIInputInstance,\n} from '@tremolo-ui/dom'\n\nexport { PITCH_BEND_CENTER, type MIDIInputHandlers }\n\n/**\n * Handle MIDI input events. To be used with {@link useMIDIAccess}.\n *\n * The handlers are read fresh on every event, so writing them inline is fine:\n * the listeners are attached once per `midiAccess` and stay attached. Devices\n * plugged in later are picked up without anything having to be rebuilt.\n *\n * @example\n * const { midiAccess } = useMIDIAccess()\n * useMIDIInput(midiAccess, {\n * onNoteOnEvent: (note, velocity) => play(note, velocity / 127),\n * onNoteOffEvent: (note) => stop(note),\n * onControlChangeEvent: (controller, value) => {\n * if (controller === 1) setModulation(value / 127)\n * },\n * })\n */\nexport function useMIDIInput(\n midiAccess: MIDIAccess | null,\n handlers: MIDIInputHandlers,\n) {\n // Read when the instance is created. The effect below keeps it current, and\n // runs right after, so a stale handler is replaced within the same commit.\n const latest = useRef(handlers)\n const instanceRef = useRef<MIDIInputInstance | null>(null)\n\n useEffect(() => {\n const instance = createMIDIInput(midiAccess, latest.current)\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n }, [midiAccess])\n\n // Runs after every render: handlers come from props and are cheap to push,\n // and updating in place leaves the listeners untouched.\n useEffect(() => {\n latest.current = handlers\n instanceRef.current?.update(handlers)\n })\n}\n","import { useEffect, useRef } from 'react'\n\nimport { createMIDIMessage, type MIDIMessageInstance } from '@tremolo-ui/dom'\n\n/**\n * Hooks for when you want to process MIDI events in more detail than useMIDIInput.\n *\n * The handler is read fresh on every event, so writing it inline is fine: the\n * listeners are attached once per `midiAccess` and stay attached, and devices\n * plugged in later are picked up.\n */\nexport function useMIDIMessage(\n midiAccess: MIDIAccess | null,\n onMIDIMessage: (event: MIDIMessageEvent) => void,\n) {\n const latest = useRef(onMIDIMessage)\n const instanceRef = useRef<MIDIMessageInstance | null>(null)\n\n useEffect(() => {\n const instance = createMIDIMessage(midiAccess, (event) =>\n latest.current(event),\n )\n instanceRef.current = instance\n\n return () => {\n instanceRef.current = null\n instance.destroy()\n }\n }, [midiAccess])\n\n useEffect(() => {\n latest.current = onMIDIMessage\n })\n}\n"],"mappings":"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"}