@tremolo-ui/react 0.1.6 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1329 -1152
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +238 -183
- package/dist/index.d.cts +367 -366
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +367 -366
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1313 -1125
- package/dist/index.js.map +1 -1
- package/package.json +17 -19
- package/src/components/AnimationCanvas/index.tsx +0 -7
- package/src/components/DragObserver/index.tsx +9 -7
- package/src/components/Knob/ActiveLine.tsx +29 -0
- package/src/components/Knob/InactiveLine.tsx +53 -0
- package/src/components/Knob/SVGRoot.tsx +39 -0
- package/src/components/Knob/Thumb.tsx +64 -0
- package/src/components/Knob/context.tsx +120 -0
- package/src/components/Knob/index.css +25 -27
- package/src/components/Knob/index.tsx +110 -164
- package/src/components/NumberInput/DecrementStepper.tsx +0 -2
- package/src/components/NumberInput/IncrementStepper.tsx +0 -2
- package/src/components/NumberInput/InternalInput.tsx +3 -1
- package/src/components/NumberInput/Stepper.tsx +0 -2
- package/src/components/NumberInput/context.tsx +0 -1
- package/src/components/NumberInput/index.css +31 -15
- package/src/components/NumberInput/index.tsx +21 -14
- package/src/components/Piano/KeyLabel.tsx +0 -2
- package/src/components/Piano/context.tsx +0 -2
- package/src/components/Piano/index.css +7 -14
- package/src/components/Piano/index.tsx +14 -15
- package/src/components/Piano/key.tsx +0 -10
- package/src/components/Piano/keyboardShortcuts.ts +0 -2
- package/src/components/PointsEditor/Background.tsx +17 -0
- package/src/components/PointsEditor/Container.tsx +26 -0
- package/src/components/PointsEditor/Point.tsx +137 -0
- package/src/components/PointsEditor/context.tsx +91 -0
- package/src/components/PointsEditor/index.css +30 -0
- package/src/components/PointsEditor/index.tsx +129 -0
- package/src/components/Slider/Scale.tsx +0 -2
- package/src/components/Slider/ScaleOption.tsx +0 -2
- package/src/components/Slider/Thumb.tsx +1 -5
- package/src/components/Slider/Track.tsx +1 -3
- package/src/components/Slider/context.tsx +0 -1
- package/src/components/Slider/index.css +33 -8
- package/src/components/Slider/index.tsx +61 -33
- package/src/components/WheelObserver/index.tsx +17 -19
- package/src/components/XYPad/Area.tsx +4 -5
- package/src/components/XYPad/Thumb.tsx +8 -7
- package/src/components/XYPad/index.css +18 -4
- package/src/components/XYPad/index.tsx +71 -38
- package/src/components/_util/composeRefs.tsx +63 -0
- package/src/components/_util/index.ts +23 -6
- package/src/components/_util/type.ts +1 -0
- package/src/hooks/useAnimationFrame.ts +0 -3
- package/src/hooks/useCallbackRef.ts +2 -2
- package/src/hooks/useDrag.ts +12 -11
- package/src/hooks/useDragWithElement.ts +12 -17
- package/src/hooks/useEventListener.ts +6 -9
- package/src/hooks/useInterval.ts +0 -3
- package/src/hooks/useLongPress.ts +0 -3
- package/src/hooks/useMIDIAccess.ts +0 -1
- package/src/hooks/useMIDIInput.ts +0 -1
- package/src/hooks/useMIDIMessage.ts +0 -1
- package/src/hooks/usePianoDrag.ts +75 -0
- package/src/index.ts +21 -30
- package/src/styles/global.css +16 -4
- package/dist/index.css.map +0 -1
- package/src/components/AnimationKnob/index.tsx +0 -314
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// ref:
|
|
2
|
+
// https://github.com/radix-ui/primitives/blob/2bab24a811e45c7a83198659272097f6cfa5a165/packages/react/compose-refs/src/compose-refs.tsx
|
|
3
|
+
|
|
4
|
+
import { useCallback } from 'react'
|
|
5
|
+
|
|
6
|
+
type PossibleRef<T> = React.Ref<T> | undefined
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Set a given ref to a given value
|
|
10
|
+
* This utility takes care of different types of refs: callback refs and RefObject(s)
|
|
11
|
+
*/
|
|
12
|
+
function setRef<T>(ref: PossibleRef<T>, value: T) {
|
|
13
|
+
if (typeof ref === 'function') {
|
|
14
|
+
return ref(value)
|
|
15
|
+
} else if (ref !== null && ref !== undefined) {
|
|
16
|
+
ref.current = value
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A utility to compose multiple refs together
|
|
22
|
+
* Accepts callback refs and RefObject(s)
|
|
23
|
+
*/
|
|
24
|
+
function composeRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
|
|
25
|
+
return (node) => {
|
|
26
|
+
let hasCleanup = false
|
|
27
|
+
const cleanups = refs.map((ref) => {
|
|
28
|
+
const cleanup = setRef(ref, node)
|
|
29
|
+
if (!hasCleanup && typeof cleanup == 'function') {
|
|
30
|
+
hasCleanup = true
|
|
31
|
+
}
|
|
32
|
+
return cleanup
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// React <19 will log an error to the console if a callback ref returns a
|
|
36
|
+
// value. We don't use ref cleanups internally so this will only happen if a
|
|
37
|
+
// user's ref callback returns a value, which we only expect if they are
|
|
38
|
+
// using the cleanup functionality added in React 19.
|
|
39
|
+
if (hasCleanup) {
|
|
40
|
+
return () => {
|
|
41
|
+
for (let i = 0; i < cleanups.length; i++) {
|
|
42
|
+
const cleanup = cleanups[i]
|
|
43
|
+
if (typeof cleanup == 'function') {
|
|
44
|
+
cleanup()
|
|
45
|
+
} else {
|
|
46
|
+
setRef(refs[i], null)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A custom hook that composes multiple refs
|
|
56
|
+
* Accepts callback refs and RefObject(s)
|
|
57
|
+
*/
|
|
58
|
+
function useComposedRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
|
|
59
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
|
+
return useCallback(composeRefs(...refs), refs)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { composeRefs, useComposedRefs }
|
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
export function
|
|
2
|
-
document.body.classList.add('tremolo-
|
|
1
|
+
export function addUserSelectNone() {
|
|
2
|
+
window.document.body.classList.add('tremolo-user-select-none')
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
export function
|
|
6
|
-
document.body.classList.remove('tremolo-
|
|
5
|
+
export function removeUserSelectNone() {
|
|
6
|
+
window.document.body.classList.remove('tremolo-user-select-none')
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const cursorStyles = {
|
|
10
|
+
grabbing: 'tremolo-cursor-grabbing',
|
|
11
|
+
grab: 'tremolo-cursor-grab',
|
|
12
|
+
pointer: 'tremolo-cursor-pointer',
|
|
13
|
+
move: 'tremolo-cursor-move',
|
|
14
|
+
none: 'tremolo-cursor-none',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Cursor = keyof typeof cursorStyles
|
|
18
|
+
|
|
19
|
+
export function setCursorStyle(type: Cursor) {
|
|
20
|
+
resetCursorStyle()
|
|
21
|
+
window.document.body.classList.add(cursorStyles[type])
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resetCursorStyle() {
|
|
25
|
+
Object.values(cursorStyles).forEach((s) => {
|
|
26
|
+
window.document.body.classList.remove(s)
|
|
27
|
+
})
|
|
11
28
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Override<T, U> = T & Omit<U, keyof T>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useInsertionEffect, useRef } from 'react'
|
|
1
|
+
import { DependencyList, useCallback, useInsertionEffect, useRef } from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Internal
|
|
@@ -6,7 +6,7 @@ import { useCallback, useInsertionEffect, useRef } from 'react'
|
|
|
6
6
|
*/
|
|
7
7
|
export function useCallbackRef<Args extends unknown[], Return>(
|
|
8
8
|
callback: ((...args: Args) => Return) | undefined,
|
|
9
|
-
deps:
|
|
9
|
+
deps: DependencyList = [],
|
|
10
10
|
) {
|
|
11
11
|
const callbackRef = useRef<typeof callback>(() => {
|
|
12
12
|
throw new Error('Cannot call an event handler while rendering.')
|
package/src/hooks/useDrag.ts
CHANGED
|
@@ -6,17 +6,16 @@ import { useRefCallbackEvent } from './useRefCallbackEvent'
|
|
|
6
6
|
interface UseDragProps {
|
|
7
7
|
threshold?: number
|
|
8
8
|
|
|
9
|
-
onDrag
|
|
9
|
+
onDrag?: (x: number, y: number, deltaX: number, deltaY: number) => void
|
|
10
10
|
onDragStart?: () => void
|
|
11
11
|
onDragEnd?: () => void
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @category hooks
|
|
16
15
|
* @returns [refCallback, pointerDownHandler]
|
|
17
16
|
*/
|
|
18
17
|
export function useDrag<T extends Element>({
|
|
19
|
-
threshold = 1,
|
|
18
|
+
threshold: _threshold = 1,
|
|
20
19
|
onDrag,
|
|
21
20
|
onDragStart,
|
|
22
21
|
onDragEnd,
|
|
@@ -29,6 +28,8 @@ export function useDrag<T extends Element>({
|
|
|
29
28
|
const dragStartX = useRef(0)
|
|
30
29
|
const dragStartY = useRef(0)
|
|
31
30
|
|
|
31
|
+
const threshold = Math.max(_threshold, 1)
|
|
32
|
+
|
|
32
33
|
const handleDrag = useCallback(
|
|
33
34
|
(
|
|
34
35
|
event: MouseEvent | React.MouseEvent<T, MouseEvent> | TouchEvent,
|
|
@@ -53,7 +54,7 @@ export function useDrag<T extends Element>({
|
|
|
53
54
|
dragOffsetY.current = screenY
|
|
54
55
|
}
|
|
55
56
|
if (Math.abs(deltaX) < threshold && Math.abs(deltaY) < threshold) return
|
|
56
|
-
onDrag(
|
|
57
|
+
onDrag?.(
|
|
57
58
|
screenX - dragStartX.current,
|
|
58
59
|
screenY - dragStartY.current,
|
|
59
60
|
deltaX,
|
|
@@ -63,13 +64,6 @@ export function useDrag<T extends Element>({
|
|
|
63
64
|
[threshold, onDrag],
|
|
64
65
|
)
|
|
65
66
|
|
|
66
|
-
const refHandler = useRefCallbackEvent(
|
|
67
|
-
'touchmove',
|
|
68
|
-
handleDrag,
|
|
69
|
-
{ passive: false },
|
|
70
|
-
[onDrag],
|
|
71
|
-
)
|
|
72
|
-
|
|
73
67
|
const pointerDownHandler = useCallback(
|
|
74
68
|
(event: React.PointerEvent<T>) => {
|
|
75
69
|
dragOffsetX.current = event.screenX
|
|
@@ -80,6 +74,13 @@ export function useDrag<T extends Element>({
|
|
|
80
74
|
[handleDrag, onDragStart],
|
|
81
75
|
)
|
|
82
76
|
|
|
77
|
+
const refHandler = useRefCallbackEvent(
|
|
78
|
+
'touchmove',
|
|
79
|
+
handleDrag,
|
|
80
|
+
{ passive: false },
|
|
81
|
+
[onDrag],
|
|
82
|
+
)
|
|
83
|
+
|
|
83
84
|
useEventListener(globalThis.window, 'mousemove', handleDrag)
|
|
84
85
|
|
|
85
86
|
useEventListener(globalThis.window, 'pointerup', () => {
|
|
@@ -1,37 +1,30 @@
|
|
|
1
|
-
import { useRef, useCallback, RefObject } from 'react'
|
|
1
|
+
import { useRef, useCallback, RefObject, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { normalizeValue } from '@tremolo-ui/functions'
|
|
4
4
|
|
|
5
5
|
import { useEventListener } from './useEventListener'
|
|
6
6
|
import { useRefCallbackEvent } from './useRefCallbackEvent'
|
|
7
7
|
|
|
8
|
-
interface
|
|
8
|
+
interface UseDragWithElement<T extends Element> {
|
|
9
9
|
baseElementRef: RefObject<T | null>
|
|
10
10
|
onDrag: (normalizedX: number, normalizedY: number) => void
|
|
11
11
|
onDragStart?: (normalizedX: number, normalizedY: number) => void
|
|
12
12
|
onDragEnd?: (normalizedX: number, normalizedY: number) => void
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* @category hooks
|
|
17
|
-
* @returns [refCallback, pointerDownHandler]
|
|
18
|
-
*/
|
|
19
15
|
export function useDragWithElement<T extends Element>({
|
|
20
16
|
baseElementRef,
|
|
21
17
|
onDrag,
|
|
22
18
|
onDragStart,
|
|
23
19
|
onDragEnd,
|
|
24
|
-
}:
|
|
25
|
-
|
|
26
|
-
(event: React.PointerEvent<T>) => void,
|
|
27
|
-
] {
|
|
28
|
-
const dragged = useRef(false)
|
|
20
|
+
}: UseDragWithElement<T>) {
|
|
21
|
+
const [dragging, setDragging] = useState(false)
|
|
29
22
|
const normalizedX = useRef(0)
|
|
30
23
|
const normalizedY = useRef(0)
|
|
31
24
|
|
|
32
25
|
const handleDrag = useCallback(
|
|
33
26
|
(event: MouseEvent | React.PointerEvent<T> | TouchEvent) => {
|
|
34
|
-
if (!baseElementRef.current || !
|
|
27
|
+
if (!baseElementRef.current || !dragging) {
|
|
35
28
|
return
|
|
36
29
|
}
|
|
37
30
|
const isTouch = event instanceof TouchEvent
|
|
@@ -46,7 +39,7 @@ export function useDragWithElement<T extends Element>({
|
|
|
46
39
|
normalizedY.current = ny
|
|
47
40
|
onDrag(nx, ny)
|
|
48
41
|
},
|
|
49
|
-
[onDrag, baseElementRef],
|
|
42
|
+
[onDrag, baseElementRef, dragging],
|
|
50
43
|
)
|
|
51
44
|
|
|
52
45
|
const refHandler = useRefCallbackEvent(
|
|
@@ -58,7 +51,8 @@ export function useDragWithElement<T extends Element>({
|
|
|
58
51
|
|
|
59
52
|
const pointerDownHandler = useCallback(
|
|
60
53
|
(event: React.PointerEvent<T>) => {
|
|
61
|
-
|
|
54
|
+
// dragging.current = true
|
|
55
|
+
setDragging(true)
|
|
62
56
|
handleDrag(event)
|
|
63
57
|
onDragStart?.(normalizedX.current, normalizedY.current)
|
|
64
58
|
},
|
|
@@ -68,10 +62,11 @@ export function useDragWithElement<T extends Element>({
|
|
|
68
62
|
useEventListener(globalThis.window, 'pointermove', handleDrag)
|
|
69
63
|
|
|
70
64
|
useEventListener(globalThis.window, 'pointerup', () => {
|
|
71
|
-
if (!
|
|
72
|
-
|
|
65
|
+
if (!dragging) return
|
|
66
|
+
// dragging.current = false
|
|
67
|
+
setDragging(false)
|
|
73
68
|
onDragEnd?.(normalizedX.current, normalizedY.current)
|
|
74
69
|
})
|
|
75
70
|
|
|
76
|
-
return
|
|
71
|
+
return { refHandler, pointerDownHandler, dragging }
|
|
77
72
|
}
|
|
@@ -5,31 +5,28 @@ import { useCallbackRef } from './useCallbackRef'
|
|
|
5
5
|
type Target = EventTarget | null | (() => EventTarget | null)
|
|
6
6
|
type Options = boolean | AddEventListenerOptions
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* @category hooks
|
|
10
|
-
*/
|
|
11
8
|
export function useEventListener<K extends keyof DocumentEventMap>(
|
|
12
9
|
target: Target,
|
|
13
10
|
event: K,
|
|
14
|
-
handler
|
|
11
|
+
handler: (event: DocumentEventMap[K]) => void,
|
|
15
12
|
options?: Options,
|
|
16
13
|
): VoidFunction
|
|
17
14
|
export function useEventListener<K extends keyof WindowEventMap>(
|
|
18
15
|
target: Target,
|
|
19
16
|
event: K,
|
|
20
|
-
handler
|
|
17
|
+
handler: (event: WindowEventMap[K]) => void,
|
|
21
18
|
options?: Options,
|
|
22
19
|
): VoidFunction
|
|
23
20
|
export function useEventListener<K extends keyof GlobalEventHandlersEventMap>(
|
|
24
21
|
target: Target,
|
|
25
22
|
event: K,
|
|
26
|
-
handler
|
|
23
|
+
handler: (event: GlobalEventHandlersEventMap[K]) => void,
|
|
27
24
|
options?: Options,
|
|
28
25
|
): VoidFunction
|
|
29
26
|
export function useEventListener(
|
|
30
27
|
target: Target,
|
|
31
28
|
event: string,
|
|
32
|
-
handler: (
|
|
29
|
+
handler: (event: Event) => void,
|
|
33
30
|
options?: Options,
|
|
34
31
|
) {
|
|
35
32
|
const listener = useCallbackRef(handler)
|
|
@@ -37,13 +34,13 @@ export function useEventListener(
|
|
|
37
34
|
useEffect(() => {
|
|
38
35
|
const node = typeof target === 'function' ? target() : (target ?? document)
|
|
39
36
|
|
|
40
|
-
if (!
|
|
37
|
+
if (!node) return
|
|
41
38
|
|
|
42
39
|
node.addEventListener(event, listener, options)
|
|
43
40
|
return () => {
|
|
44
41
|
node.removeEventListener(event, listener, options)
|
|
45
42
|
}
|
|
46
|
-
}, [event, target, options, listener
|
|
43
|
+
}, [event, target, options, listener])
|
|
47
44
|
|
|
48
45
|
return () => {
|
|
49
46
|
const node = typeof target === 'function' ? target() : (target ?? document)
|
package/src/hooks/useInterval.ts
CHANGED
|
@@ -10,7 +10,6 @@ export type MIDIAccessError = typeof PERMISSION_DENIED | typeof NOT_SUPPORTED
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Hooks for requesting MIDI access in the browser. The first argument allows you to choose whether to request access on mount.
|
|
13
|
-
* @category hooks
|
|
14
13
|
*/
|
|
15
14
|
export function useMIDIAccess(requestOnMount = true) {
|
|
16
15
|
const [midiAccess, setMidiAccess] = useState<MIDIAccess | null>(null)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useRef, useCallback, RefObject } from 'react'
|
|
2
|
+
|
|
3
|
+
import { normalizeValue } from '@tremolo-ui/functions'
|
|
4
|
+
|
|
5
|
+
import { useEventListener } from './useEventListener'
|
|
6
|
+
import { useRefCallbackEvent } from './useRefCallbackEvent'
|
|
7
|
+
|
|
8
|
+
interface UsePianoDrag<T extends Element> {
|
|
9
|
+
baseElementRef: RefObject<T | null>
|
|
10
|
+
onDrag: (normalizedX: number, normalizedY: number) => void
|
|
11
|
+
onDragStart?: (normalizedX: number, normalizedY: number) => void
|
|
12
|
+
onDragEnd?: (normalizedX: number, normalizedY: number) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Internal
|
|
17
|
+
* @returns [refCallback, pointerDownHandler]
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
export function usePianoDrag<T extends Element>({
|
|
21
|
+
baseElementRef,
|
|
22
|
+
onDrag,
|
|
23
|
+
onDragStart,
|
|
24
|
+
onDragEnd,
|
|
25
|
+
}: UsePianoDrag<T>) {
|
|
26
|
+
const dragged = useRef(false)
|
|
27
|
+
const normalizedX = useRef(0)
|
|
28
|
+
const normalizedY = useRef(0)
|
|
29
|
+
|
|
30
|
+
const handleDrag = useCallback(
|
|
31
|
+
(event: MouseEvent | React.PointerEvent<T> | TouchEvent) => {
|
|
32
|
+
if (!baseElementRef.current || !dragged.current) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
const isTouch = event instanceof TouchEvent
|
|
36
|
+
if (isTouch && event.cancelable) event.preventDefault()
|
|
37
|
+
const { left, top, right, bottom } =
|
|
38
|
+
baseElementRef.current.getBoundingClientRect()
|
|
39
|
+
const mouseX = isTouch ? event.touches[0].clientX : event.clientX
|
|
40
|
+
const mouseY = isTouch ? event.touches[0].clientY : event.clientY
|
|
41
|
+
const nx = normalizeValue(mouseX, left, right)
|
|
42
|
+
const ny = normalizeValue(mouseY, top, bottom)
|
|
43
|
+
normalizedX.current = nx
|
|
44
|
+
normalizedY.current = ny
|
|
45
|
+
onDrag(nx, ny)
|
|
46
|
+
},
|
|
47
|
+
[onDrag, baseElementRef],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const refHandler = useRefCallbackEvent(
|
|
51
|
+
'touchmove',
|
|
52
|
+
handleDrag,
|
|
53
|
+
{ passive: false },
|
|
54
|
+
[onDrag],
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const pointerDownHandler = useCallback(
|
|
58
|
+
(event: React.PointerEvent<T>) => {
|
|
59
|
+
dragged.current = true
|
|
60
|
+
handleDrag(event)
|
|
61
|
+
onDragStart?.(normalizedX.current, normalizedY.current)
|
|
62
|
+
},
|
|
63
|
+
[handleDrag, onDragStart],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
useEventListener(globalThis.window, 'pointermove', handleDrag)
|
|
67
|
+
|
|
68
|
+
useEventListener(globalThis.window, 'pointerup', () => {
|
|
69
|
+
if (!dragged.current) return
|
|
70
|
+
dragged.current = false
|
|
71
|
+
onDragEnd?.(normalizedX.current, normalizedY.current)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
return { refHandler, pointerDownHandler }
|
|
75
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,79 +3,70 @@ import './styles/global.css'
|
|
|
3
3
|
import './components/Knob/index.css'
|
|
4
4
|
import './components/NumberInput/index.css'
|
|
5
5
|
import './components/Piano/index.css'
|
|
6
|
+
import './components/PointsEditor/index.css'
|
|
6
7
|
import './components/Slider/index.css'
|
|
7
8
|
import './components/XYPad/index.css'
|
|
8
9
|
|
|
9
10
|
export {
|
|
10
|
-
type AbsoluteSizingProps,
|
|
11
11
|
AnimationCanvas,
|
|
12
|
+
type AbsoluteSizingProps,
|
|
12
13
|
type AnimationCanvasProps,
|
|
13
14
|
type CommonProps,
|
|
14
15
|
type DrawFunction,
|
|
15
16
|
type InitFunction,
|
|
16
17
|
type RelativeSizingProps,
|
|
17
18
|
} from './components/AnimationCanvas'
|
|
18
|
-
export {
|
|
19
|
-
AnimationKnob,
|
|
20
|
-
type AnimationKnobMethods,
|
|
21
|
-
type AnimationKnobProps,
|
|
22
|
-
} from './components/AnimationKnob'
|
|
23
19
|
export { DragObserver, type DragObserverProps } from './components/DragObserver'
|
|
24
|
-
export { Knob, type
|
|
20
|
+
export { Knob, type KnobProps, type KnobMethods } from './components/Knob'
|
|
25
21
|
export {
|
|
26
|
-
DecrementStepper,
|
|
27
|
-
type DecrementStepperProps,
|
|
28
|
-
IncrementStepper,
|
|
29
|
-
type IncrementStepperProps,
|
|
30
22
|
NumberInput,
|
|
31
|
-
type NumberInputMethods,
|
|
32
23
|
type NumberInputProps,
|
|
33
|
-
|
|
24
|
+
type NumberInputMethods,
|
|
34
25
|
type StepperProps,
|
|
26
|
+
type IncrementStepperProps,
|
|
27
|
+
type DecrementStepperProps,
|
|
35
28
|
} from './components/NumberInput'
|
|
36
29
|
export {
|
|
37
30
|
Piano,
|
|
31
|
+
getNoteRangeArray,
|
|
32
|
+
SHORTCUTS,
|
|
38
33
|
type PianoProps,
|
|
39
34
|
type PianoMethods,
|
|
40
|
-
getNoteRangeArray,
|
|
41
|
-
WhiteKey,
|
|
42
|
-
BlackKey,
|
|
43
35
|
type KeyProps,
|
|
44
36
|
type KeyMethods,
|
|
45
|
-
KeyLabel,
|
|
46
37
|
type KeyLabelProps,
|
|
47
|
-
SHORTCUTS,
|
|
48
38
|
type KeyboardShortcuts,
|
|
49
39
|
} from './components/Piano'
|
|
50
40
|
export {
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
PointsEditor,
|
|
42
|
+
clampPoint,
|
|
43
|
+
type PointsEditorProps,
|
|
44
|
+
type PointProps,
|
|
45
|
+
type PointBaseType,
|
|
46
|
+
} from './components/PointsEditor'
|
|
47
|
+
export {
|
|
48
|
+
Slider,
|
|
49
|
+
useSliderContext,
|
|
53
50
|
type ScaleOptionProps,
|
|
54
51
|
type ScaleProps,
|
|
55
|
-
Slider,
|
|
56
52
|
type SliderMethods,
|
|
57
53
|
type SliderProps,
|
|
58
|
-
SliderThumb,
|
|
59
54
|
type SliderThumbMethods,
|
|
60
55
|
type SliderThumbProps,
|
|
61
|
-
SliderTrack,
|
|
62
56
|
type SliderTrackProps,
|
|
63
|
-
useSliderContext,
|
|
64
57
|
} from './components/Slider'
|
|
65
58
|
export {
|
|
66
59
|
WheelObserver,
|
|
67
60
|
type WheelObserverProps,
|
|
68
61
|
} from './components/WheelObserver'
|
|
69
62
|
export {
|
|
70
|
-
type AreaProps,
|
|
71
|
-
type ThumbProps,
|
|
72
|
-
type ValueOptions,
|
|
73
63
|
XYPad,
|
|
74
|
-
XYPadArea,
|
|
75
|
-
type XYPadMethods,
|
|
76
64
|
type XYPadProps,
|
|
77
|
-
|
|
65
|
+
type XYPadMethods,
|
|
66
|
+
type XYPadAreaProps,
|
|
67
|
+
type XYPadThumbProps,
|
|
78
68
|
type XYPadThumbMethods,
|
|
69
|
+
type ValueOptions,
|
|
79
70
|
} from './components/XYPad'
|
|
80
71
|
|
|
81
72
|
// hooks
|
package/src/styles/global.css
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
.tremolo-user-select-none {
|
|
2
|
+
user-select: none;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
.tremolo-
|
|
6
|
-
|
|
5
|
+
.tremolo-cursor-pointer {
|
|
6
|
+
cursor: pointer;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.tremolo-cursor-move {
|
|
10
|
+
cursor: move;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.tremolo-cursor-grabbing {
|
|
14
|
+
cursor: grabbing;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tremolo-cursor-none {
|
|
18
|
+
cursor: none;
|
|
7
19
|
}
|
package/dist/index.css.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.css","names":[],"sources":["../src/styles/global.css","../src/components/Knob/index.css","../src/components/NumberInput/index.css","../src/components/Piano/index.css","../src/components/Slider/index.css","../src/components/XYPad/index.css"],"sourcesContent":[":root {\n --tremolo-theme-color: oklch(59.5% 0.17548 266.373);\n}\n\n.tremolo-no-select {\n user-select: none;\n}\n",".tremolo-knob {\n display: inline-block;\n cursor: pointer;\n overflow: visible;\n outline: 0;\n\n &[aria-readonly='true'] {\n cursor: not-allowed;\n }\n}\n\n.tremolo-knob-active-line {\n overflow: visible;\n color: oklch(69.2% 0.17548 266.373);\n\n :where(.tremolo-knob:focus, .tremolo-knob:hover) & {\n color: var(--tremolo-theme-color);\n }\n\n :where(.tremolo-knob[aria-disabled='true']) & {\n color: oklch(50.5% 0.03307 270.021);\n }\n}\n\n:where(.dark, [data-theme='dark']) {\n .tremolo-knob-active-line {\n color: var(--tremolo-theme-color);\n\n :where(.tremolo-knob:focus, .tremolo-knob:hover) & {\n color: oklch(65.2% 0.17548 266.373);\n }\n }\n}\n\n.tremolo-knob-inactive-line {\n color: oklch(95% 0 0);\n\n :where(.tremolo-knob:focus, .tremolo-knob:hover) & {\n color: oklch(90% 0 0);\n }\n}\n\n:where(.dark, [data-theme='dark']) {\n .tremolo-knob-inactive-line {\n color: oklch(41.7% 0 0);\n\n :where(.tremolo-knob:focus, .tremolo-knob:hover) & {\n color: oklch(44.59% 0 0);\n }\n }\n}\n\n.tremolo-knob-thumb {\n color: oklch(85.7% 0 0);\n\n :where(.tremolo-knob:focus, .tremolo-knob:hover) & {\n color: oklch(84.5% 0 0);\n }\n}\n\n:where(.dark, [data-theme='dark']) {\n .tremolo-knob-thumb {\n color: oklch(48.6% 0 0);\n\n :where(.tremolo-knob:focus, .tremolo-knob:hover) & {\n color: oklch(51.7% 0 0);\n }\n }\n}\n\n.tremolo-knob-thumb-line {\n color: oklch(94.2% 0 0);\n}\n\n:where(.dark, [data-theme='dark']) {\n .tremolo-knob-thumb-line {\n color: oklch(84.2% 0 0);\n }\n}\n",".tremolo-number-input-wrapper {\n --border-radius: 4px;\n --stepper-width: 20px;\n --active-color: var(--tremolo-theme-color);\n\n display: inline-flex;\n flex-direction: row;\n position: relative;\n width: 140px;\n height: min-content;\n border-style: solid;\n border-color: #c1c1c1;\n border-width: 0px;\n outline: none;\n transition: all 0.1s;\n\n &:not(:focus-within):has(> .tremolo-number-input[data-error='true']) {\n border-color: #f34343;\n }\n\n &[data-variant='outline'] {\n border-width: 1px;\n border-radius: var(--border-radius);\n\n &:hover {\n border-color: #909090;\n }\n\n &:focus-within {\n border-color: var(--active-color);\n box-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--active-color) 10%, transparent);\n }\n }\n\n &[data-variant='filled'] {\n border-width: 1px;\n border-radius: var(--border-radius);\n border-color: transparent;\n background-color: #edf2f7;\n\n &:hover {\n background-color: #e4e9ee;\n }\n\n &:focus-within {\n background-color: inherit;\n border-color: var(--active-color);\n box-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--active-color) 10%, transparent);\n }\n }\n\n &[data-variant='flushed'] {\n border-bottom-width: 1px;\n\n &:hover {\n border-color: #909090;\n }\n\n &:focus-within {\n border-color: var(--active-color);\n box-shadow: 0px 2px 0px 0px\n color-mix(in srgb, var(--active-color) 10%, transparent);\n }\n }\n\n &[data-stepper='false'] {\n --stepper-width: 0px;\n }\n}\n\n.tremolo-number-input {\n display: block;\n color: inherit;\n width: calc(100% - 20px - var(--stepper-width));\n background-color: inherit;\n font: inherit;\n padding: 6px 10px;\n\n margin: 0;\n border: none;\n outline: none;\n appearance: none;\n\n &[aria-readonly='true'] {\n cursor: not-allowed;\n }\n}\n\n.tremolo-number-input-stepper {\n display: flex;\n flex-direction: column;\n height: 100%;\n position: absolute;\n top: 0;\n right: 0;\n width: var(--stepper-width);\n transition: all 0.1s linear;\n\n &[data-dynamic='true'] {\n opacity: 0;\n transform: translateX(40%);\n }\n}\n\n:is(\n .tremolo-number-input-wrapper:hover,\n .tremolo-number-input-wrapper:focus-within\n )\n .tremolo-number-input-stepper {\n opacity: 1;\n transform: translateX(0);\n}\n\n.tremolo-number-input-increment-stepper {\n border-inline-start-width: 1px;\n border-inline-start-style: solid;\n border-inline-start-color: #ccc;\n font-size: calc(0.75rem);\n display: flex;\n justify-content: center;\n align-items: center;\n flex: 1 1 0%;\n max-height: 50%;\n user-select: none;\n cursor: pointer;\n border-top-right-radius: var(--border-radius);\n\n &[aria-disabled='false']:active {\n background-color: #3443560e;\n }\n\n &[aria-disabled='true'] {\n cursor: not-allowed;\n }\n\n &[aria-readonly='true'] {\n cursor: not-allowed;\n }\n}\n\n.tremolo-number-input-decrement-stepper {\n border-inline-start-width: 1px;\n border-inline-start-style: solid;\n border-inline-start-color: #ccc;\n border-top: 1px solid #ccc;\n font-size: calc(0.75rem);\n display: flex;\n justify-content: center;\n align-items: center;\n flex: 1 1 0%;\n max-height: 50%;\n user-select: none;\n cursor: pointer;\n border-bottom-right-radius: var(--border-radius);\n\n &[aria-disabled='false']:active {\n background-color: #3443560e;\n }\n\n &[aria-disabled='true'] {\n cursor: not-allowed;\n }\n\n &[aria-readonly='true'] {\n cursor: not-allowed;\n }\n}\n",".tremolo-piano {\n display: inline-block;\n box-sizing: border-box;\n user-select: none;\n touch-action: none;\n position: relative;\n}\n\n.tremolo-piano-white-key {\n --bg: oklch(100% 0 0);\n --color: oklch(0% 0 0);\n --active-bg: oklch(90% 0 0);\n --active-color: oklch(0% 0 0);\n\n box-sizing: border-box;\n position: absolute;\n background-color: var(--bg);\n -webkit-tap-highlight-color: transparent;\n color: var(--color);\n border: 1px solid #555;\n border-radius: 0px 0px 8px 8px;\n cursor: pointer;\n z-index: 1;\n\n &[data-active='true'] {\n background-color: var(--active-bg);\n color: var(--active-color);\n }\n\n &[aria-disabled='true'] {\n cursor: not-allowed;\n }\n}\n\n.tremolo-piano-black-key {\n --color: oklch(100% 0 0);\n --bg: oklch(32.109% 0.00004 271.152);\n --active-color: oklch(100% 0 0);\n --active-bg: oklch(47.836% 0.00005 271.152);\n\n box-sizing: border-box;\n position: absolute;\n background-color: var(--bg);\n -webkit-tap-highlight-color: transparent;\n color: var(--color);\n border: 1px solid #555;\n border-radius: 0px 0px 8px 8px;\n cursor: pointer;\n z-index: 2;\n\n &[data-active='true'] {\n background-color: var(--active-bg);\n color: var(--active-color);\n }\n\n &[aria-disabled='true'] {\n cursor: not-allowed;\n }\n}\n\n.tremolo-piano-key-label-wrapper {\n display: flex;\n justify-content: center;\n align-items: end;\n height: 100%;\n}\n\n.tremolo-piano-key-label {\n box-sizing: content-box;\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 0.6rem;\n height: 10px;\n margin-bottom: 10px;\n padding: 4px;\n border-radius: 4px;\n border: 1px solid #888;\n aspect-ratio: 1;\n max-width: calc(100% - 16px);\n}\n\n:where(.dark, [data-theme='dark']) {\n .tremolo-piano-white-key {\n --bg: oklch(48.193% 0.00005 271.152);\n --color: oklch(100% 0 0);\n --active-bg: oklch(52.78% 0.00006 271.152);\n --active-color: oklch(100% 0 0);\n }\n\n .tremolo-piano-black-key {\n --color: oklch(100% 0 0);\n --bg: oklch(32.109% 0 0);\n --active-color: oklch(100% 0 0);\n --active-bg: oklch(38.666% 0.00004 271.152);\n }\n}\n",".tremolo-slider {\n display: inline-block;\n cursor: pointer;\n outline: 0;\n -webkit-tap-highlight-color: transparent;\n\n &[aria-readonly='true'] {\n cursor: not-allowed;\n }\n}\n\n.tremolo-slider-thumb-wrapper {\n position: absolute;\n translate: -50% -50%;\n z-index: 100;\n}\n\n.tremolo-slider-thumb {\n --color: var(--tremolo-theme-color);\n\n background: var(--color);\n border-radius: 50%;\n outline: none;\n\n &[aria-disabled='true'] {\n background: #5d6478;\n }\n\n &[aria-readonly='false']:focus {\n box-shadow: 0px 0px 0px 3px\n color-mix(in srgb, var(--color) 20%, transparent);\n }\n}\n\n.tremolo-slider-track {\n --active: #7998ec;\n --inactive: #eee;\n\n position: relative;\n\n &[data-vertical='false'] {\n min-width: 50px;\n }\n\n &[data-vertical='true'] {\n min-height: 50px;\n }\n\n &:hover {\n --active: #6387e9;\n --inactive: #e0e0e0;\n }\n\n &[aria-disabled='true'] {\n --active: #858890;\n --inactive: #ddd;\n }\n}\n\n.tremolo-slider-scale {\n display: block;\n position: relative;\n}\n\n.tremolo-slider-scale-option {\n display: flex;\n color: #222;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n position: absolute;\n translate: -50% 0;\n z-index: 10;\n\n &[data-vertical='true'] {\n flex-direction: row;\n translate: 0 -50%;\n }\n}\n\n.tremolo-slider-scale-option-mark {\n background-color: currentColor;\n}\n\n.tremolo-slider-scale-option-label {\n text-align: right;\n}\n",".tremolo-xy-pad {\n display: inline-block;\n cursor: pointer;\n}\n\n.tremolo-xy-pad-area {\n --color: #eee;\n\n position: relative;\n background-color: var(--color);\n}\n\n.tremolo-xy-pad-thumb-wrapper {\n position: absolute;\n translate: -50% -50%;\n z-index: 100;\n}\n\n.tremolo-xy-pad-thumb {\n --color: var(--tremolo-theme-color);\n\n border-radius: 50%;\n outline: none;\n background-color: var(--color);\n\n &[aria-disabled='true'] {\n background-color: #5d6478;\n }\n\n &:focus {\n box-shadow: 0px 0px 0px 3px\n color-mix(in srgb, var(--color) 20%, transparent);\n }\n}\n"],"mappings":"AAAA;AACA;AACA;;AAEA;AACA;AACA;;ACNA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;ACxKA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AChGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;ACtFA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA"}
|