@tremolo-ui/react 0.4.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.
- package/dist/compose-refs.cjs +72 -0
- package/dist/compose-refs.cjs.map +1 -0
- package/dist/compose-refs.d.cts +43 -0
- package/dist/compose-refs.d.cts.map +1 -0
- package/dist/compose-refs.d.ts +43 -0
- package/dist/compose-refs.d.ts.map +1 -0
- package/dist/compose-refs.js +70 -0
- package/dist/compose-refs.js.map +1 -0
- package/dist/index.cjs +2272 -1650
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1461 -475
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +1461 -475
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2258 -1648
- package/dist/index.js.map +1 -1
- package/package.json +32 -31
- package/src/components/AnimationCanvas/index.tsx +162 -194
- package/src/components/Knob/ActiveLine.tsx +9 -8
- package/src/components/Knob/InactiveLine.tsx +11 -14
- package/src/components/Knob/SVGRoot.tsx +10 -17
- package/src/components/Knob/Thumb.tsx +33 -11
- package/src/components/Knob/context.tsx +73 -89
- package/src/components/Knob/index.tsx +227 -105
- package/src/components/NumberInput/DecrementStepper.tsx +21 -50
- package/src/components/NumberInput/IncrementStepper.tsx +22 -50
- package/src/components/NumberInput/InputField.tsx +206 -0
- package/src/components/NumberInput/Stepper.tsx +150 -21
- package/src/components/NumberInput/StepperButton.tsx +95 -0
- package/src/components/NumberInput/context.tsx +104 -149
- package/src/components/NumberInput/index.tsx +461 -110
- package/src/components/Piano/index.tsx +413 -263
- package/src/components/Piano/keyboard-shortcuts.ts +61 -0
- package/src/components/PointsEditor/Background.tsx +19 -4
- package/src/components/PointsEditor/Container.tsx +92 -22
- package/src/components/PointsEditor/Point.tsx +293 -53
- package/src/components/PointsEditor/SelectionBox.tsx +54 -0
- package/src/components/PointsEditor/context.tsx +97 -75
- package/src/components/PointsEditor/index.tsx +497 -62
- package/src/components/Slider/Marks.tsx +84 -0
- package/src/components/Slider/MarksOption.tsx +115 -0
- package/src/components/Slider/Thumb.tsx +99 -54
- package/src/components/Slider/Track.tsx +73 -62
- package/src/components/Slider/context.tsx +40 -53
- package/src/components/Slider/index.tsx +237 -190
- package/src/components/Slider/type.ts +27 -9
- package/src/components/XYPad/Area.tsx +52 -33
- package/src/components/XYPad/Thumb.tsx +121 -60
- package/src/components/XYPad/context.tsx +49 -0
- package/src/components/XYPad/index.tsx +338 -246
- package/src/components/_util/Placement.tsx +68 -0
- package/src/components/_util/VisuallyHiddenRangeInput.tsx +24 -0
- package/src/components/_util/css-length.ts +13 -0
- package/src/{components/_util/composeRefs.tsx → compose-refs/index.tsx} +33 -5
- package/src/hooks/{useCallbackRef.ts → _internal/useCallbackRef.ts} +3 -1
- package/src/hooks/_internal/useCheckSteps.ts +170 -0
- package/src/hooks/useAnimationFrame.ts +17 -7
- package/src/hooks/useDrag.ts +39 -9
- package/src/hooks/useDragValue.ts +194 -0
- package/src/hooks/useEventListener.ts +11 -7
- package/src/hooks/useLongPress.ts +42 -8
- package/src/hooks/useMIDIAccess.ts +82 -11
- package/src/hooks/useMIDIInput.ts +45 -13
- package/src/hooks/useMIDIMessage.ts +23 -5
- package/src/hooks/useWheel.ts +29 -9
- package/src/index.ts +50 -27
- package/src/input-event.ts +32 -0
- package/dist/index.css +0 -536
- package/src/Globals.d.ts +0 -3
- package/src/components/AnimationCanvas/canvas.ts +0 -46
- package/src/components/Knob/index.css +0 -77
- package/src/components/NumberInput/InternalInput.tsx +0 -216
- package/src/components/NumberInput/index.css +0 -185
- package/src/components/NumberInput/type.ts +0 -58
- package/src/components/Piano/KeyLabel.tsx +0 -51
- package/src/components/Piano/context.tsx +0 -73
- package/src/components/Piano/index.css +0 -90
- package/src/components/Piano/key.tsx +0 -205
- package/src/components/Piano/keyboardShortcuts.ts +0 -31
- package/src/components/PointsEditor/index.css +0 -30
- package/src/components/Slider/Scale.tsx +0 -52
- package/src/components/Slider/ScaleOption.tsx +0 -103
- package/src/components/Slider/index.css +0 -112
- package/src/components/XYPad/index.css +0 -48
- package/src/components/_util/index.ts +0 -28
- package/src/components/_util/type.ts +0 -1
- package/src/hooks/useDragWithElement.ts +0 -100
- package/src/hooks/usePianoDrag.ts +0 -75
- package/src/hooks/useRefCallbackEvent.ts +0 -34
- package/src/styles/global.css +0 -19
|
@@ -1,91 +1,113 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext,
|
|
3
|
-
createRef,
|
|
4
|
-
RefObject,
|
|
5
|
-
useContext,
|
|
6
|
-
useEffect,
|
|
7
|
-
useRef,
|
|
8
|
-
} from 'react'
|
|
9
|
-
import { createStore, useStore } from 'zustand'
|
|
1
|
+
import { createContext, CSSProperties, RefObject, useContext } from 'react'
|
|
10
2
|
|
|
11
|
-
import {
|
|
3
|
+
import type { SelectionBoxRect } from '@tremolo-ui/dom'
|
|
4
|
+
import type {
|
|
5
|
+
InputEventOption,
|
|
6
|
+
ModifierState,
|
|
7
|
+
ModifierValue,
|
|
8
|
+
} from '@tremolo-ui/functions'
|
|
12
9
|
|
|
13
|
-
type
|
|
14
|
-
|
|
10
|
+
import type { PointBaseType } from './Point'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* What a `Point` tells the editor about itself, so that a selection can be
|
|
14
|
+
* moved without the editor knowing how the points are stored.
|
|
15
|
+
*
|
|
16
|
+
* Held behind a ref and rewritten on every render: the value changes on every
|
|
17
|
+
* frame of a drag, and a registry keyed on it would be rebuilt just as often.
|
|
18
|
+
*/
|
|
19
|
+
export interface PointRegistration {
|
|
20
|
+
value: PointBaseType
|
|
21
|
+
min?: Partial<PointBaseType>
|
|
22
|
+
max?: Partial<PointBaseType>
|
|
23
|
+
readonly: boolean
|
|
24
|
+
onChange?: (value: PointBaseType) => void
|
|
25
|
+
/** The point's own element, to match the focus against. */
|
|
26
|
+
element: HTMLElement | null
|
|
27
|
+
/** The wheel option this point resolved, root inheritance applied. */
|
|
28
|
+
wheel: ModifierValue<InputEventOption> | null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type PointsEditorContextValue = {
|
|
15
32
|
disabled: boolean
|
|
16
33
|
readonly: boolean
|
|
34
|
+
/** Inherited by every `Point`; `null` turns the wheel off. */
|
|
35
|
+
wheel: ModifierValue<InputEventOption> | null
|
|
36
|
+
/** Inherited by every `Point`; `null` turns the keyboard off. */
|
|
37
|
+
keyboard: ModifierValue<InputEventOption> | null
|
|
38
|
+
/** Inherited by every `Point`. See `PointsEditorProps.dragSensitivity`. */
|
|
39
|
+
dragSensitivity: ModifierValue<number>
|
|
17
40
|
externalStyles: {
|
|
18
|
-
|
|
19
|
-
cursor?: Cursor
|
|
41
|
+
cursor?: CSSProperties['cursor']
|
|
20
42
|
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
type Action = {
|
|
24
|
-
setContainerElementRef: (
|
|
25
|
-
containerElementRef: RefObject<HTMLDivElement | null>,
|
|
26
|
-
) => void
|
|
27
|
-
}
|
|
28
43
|
|
|
29
|
-
|
|
44
|
+
/**
|
|
45
|
+
* `Container` registers its element here; `Point` normalizes the pointer
|
|
46
|
+
* against it, so a point is placed by its position within the container.
|
|
47
|
+
*/
|
|
48
|
+
containerRef: RefObject<HTMLDivElement | null>
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
/** Whether points can be selected at all. See `PointsEditorProps.selectable`. */
|
|
51
|
+
selectable: boolean
|
|
52
|
+
/** Ids of the points currently selected. Always empty while `selectable` is off. */
|
|
53
|
+
selection: readonly string[]
|
|
54
|
+
/** Register a point so that a selection can move it with the rest. */
|
|
55
|
+
registerPoint: (id: string, entry: RefObject<PointRegistration>) => () => void
|
|
56
|
+
/**
|
|
57
|
+
* Whether the element is a point, or inside one. The registry knows which
|
|
58
|
+
* elements the points are, so nothing has to be recognised by a class name.
|
|
59
|
+
*/
|
|
60
|
+
isPointElement: (element: Element | null | undefined) => boolean
|
|
61
|
+
/**
|
|
62
|
+
* A pointer went down on a point: works out the new selection and takes the
|
|
63
|
+
* snapshot the move will be measured against.
|
|
64
|
+
*/
|
|
65
|
+
beginPointDrag: (id: string, modifiers: ModifierState) => void
|
|
66
|
+
/** Move everything the drag picked up, by one amount, clamped as one. */
|
|
67
|
+
movePointDrag: (delta: PointBaseType) => void
|
|
68
|
+
/**
|
|
69
|
+
* Move the selection by an amount that did not come from a drag — an arrow
|
|
70
|
+
* key or a wheel notch. The current values are the starting point.
|
|
71
|
+
*/
|
|
72
|
+
nudgeSelection: (id: string, delta: PointBaseType) => void
|
|
73
|
+
/**
|
|
74
|
+
* Move the point that currently holds focus by one notch. The wheel listener
|
|
75
|
+
* belongs to `Container` rather than to every `Point`, so the lookup of who
|
|
76
|
+
* has focus happens here, where the registry is. Returns whether a point
|
|
77
|
+
* took it, so the caller knows whether to consume the event.
|
|
78
|
+
*/
|
|
79
|
+
nudgeFocusedPoint: (
|
|
80
|
+
axis: 'x' | 'y',
|
|
81
|
+
direction: number,
|
|
82
|
+
modifiers: ModifierState,
|
|
83
|
+
) => boolean
|
|
42
84
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
containerElementRef,
|
|
49
|
-
}))
|
|
50
|
-
},
|
|
51
|
-
}))
|
|
85
|
+
/** The selection box, while one is being dragged. */
|
|
86
|
+
selectionBox: SelectionBoxRect | null
|
|
87
|
+
beginSelectionBox: (at: PointBaseType, modifiers: ModifierState) => void
|
|
88
|
+
moveSelectionBox: (to: PointBaseType) => void
|
|
89
|
+
endSelectionBox: () => void
|
|
52
90
|
}
|
|
53
91
|
|
|
54
|
-
const PointsEditorContext =
|
|
55
|
-
|
|
56
|
-
type PointsEditorProviderProps = React.PropsWithChildren<
|
|
57
|
-
Partial<State & Action>
|
|
58
|
-
>
|
|
59
|
-
|
|
60
|
-
export function PointsEditorProvider({
|
|
61
|
-
children,
|
|
62
|
-
...props
|
|
63
|
-
}: PointsEditorProviderProps) {
|
|
64
|
-
const storeRef = useRef<PointsEditorStore>(null)
|
|
65
|
-
if (!storeRef.current) {
|
|
66
|
-
storeRef.current = createPointsEditorStore(props)
|
|
67
|
-
}
|
|
92
|
+
const PointsEditorContext =
|
|
93
|
+
/* @__PURE__ */ createContext<PointsEditorContextValue | null>(null)
|
|
68
94
|
|
|
69
|
-
|
|
70
|
-
if (storeRef.current) {
|
|
71
|
-
storeRef.current.setState(props)
|
|
72
|
-
} else {
|
|
73
|
-
storeRef.current = createPointsEditorStore(props)
|
|
74
|
-
}
|
|
75
|
-
}, [props])
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<PointsEditorContext.Provider value={storeRef.current}>
|
|
79
|
-
{children}
|
|
80
|
-
</PointsEditorContext.Provider>
|
|
81
|
-
)
|
|
82
|
-
}
|
|
95
|
+
export const PointsEditorProvider = PointsEditorContext.Provider
|
|
83
96
|
|
|
97
|
+
/**
|
|
98
|
+
* The settings `Root` was given, for the subcomponents to read. A point's
|
|
99
|
+
* value still belongs to the `Point` that draws it; what the root keeps is
|
|
100
|
+
* which points are selected, and a registry of who they are.
|
|
101
|
+
*/
|
|
102
|
+
export function usePointsEditorContext(): PointsEditorContextValue
|
|
103
|
+
export function usePointsEditorContext<T>(
|
|
104
|
+
selector: (state: PointsEditorContextValue) => T,
|
|
105
|
+
): T
|
|
84
106
|
export function usePointsEditorContext<T>(
|
|
85
|
-
selector
|
|
86
|
-
)
|
|
87
|
-
const
|
|
88
|
-
if (!
|
|
107
|
+
selector?: (state: PointsEditorContextValue) => T,
|
|
108
|
+
) {
|
|
109
|
+
const context = useContext(PointsEditorContext)
|
|
110
|
+
if (!context)
|
|
89
111
|
throw new Error('Missing PointsEditorContext.Provider in the tree')
|
|
90
|
-
return
|
|
112
|
+
return selector ? selector(context) : context
|
|
91
113
|
}
|