@tremolo-ui/react 0.1.5 → 0.2.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 (40) hide show
  1. package/dist/index.cjs +325 -239
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +149 -64
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.cts +229 -199
  6. package/dist/index.d.cts.map +1 -1
  7. package/dist/index.d.ts +229 -199
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +314 -223
  10. package/dist/index.js.map +1 -1
  11. package/package.json +2 -2
  12. package/src/components/Knob/index.css +50 -25
  13. package/src/components/Knob/index.tsx +37 -32
  14. package/src/components/NumberInput/index.css +31 -15
  15. package/src/components/NumberInput/index.tsx +22 -14
  16. package/src/components/Piano/context.tsx +1 -1
  17. package/src/components/Piano/index.css +17 -8
  18. package/src/components/Piano/index.tsx +259 -220
  19. package/src/components/Piano/key.tsx +3 -3
  20. package/src/components/Slider/Thumb.tsx +1 -1
  21. package/src/components/Slider/Track.tsx +3 -3
  22. package/src/components/Slider/index.css +33 -8
  23. package/src/components/Slider/index.tsx +25 -25
  24. package/src/components/XYPad/Area.tsx +4 -3
  25. package/src/components/XYPad/Thumb.tsx +8 -4
  26. package/src/components/XYPad/index.css +18 -4
  27. package/src/components/XYPad/index.tsx +25 -19
  28. package/src/hooks/useAnimationFrame.ts +3 -0
  29. package/src/hooks/useCallbackRef.ts +2 -2
  30. package/src/hooks/useDrag.ts +2 -1
  31. package/src/hooks/useDragWithElement.ts +2 -1
  32. package/src/hooks/useEventListener.ts +3 -0
  33. package/src/hooks/useInterval.ts +3 -0
  34. package/src/hooks/useLongPress.ts +3 -0
  35. package/src/hooks/useMIDIAccess.ts +40 -0
  36. package/src/hooks/useMIDIInput.ts +50 -0
  37. package/src/hooks/useMIDIMessage.ts +24 -0
  38. package/src/hooks/useRefCallbackEvent.ts +4 -0
  39. package/src/index.ts +30 -35
  40. package/src/styles/global.css +0 -4
@@ -27,8 +27,9 @@ import { addNoSelect, removeNoSelect } from '../_util'
27
27
 
28
28
  import { SliderProvider } from './context'
29
29
  import { Scale } from './Scale'
30
- import { SliderThumb, SliderThumbMethods, SliderThumbProps } from './Thumb'
31
- import { SliderTrack, SliderTrackProps } from './Track'
30
+ import { ScaleOption } from './ScaleOption'
31
+ import { Thumb, SliderThumbMethods, SliderThumbProps } from './Thumb'
32
+ import { Track, SliderTrackProps } from './Track'
32
33
 
33
34
  /** @category Slider */
34
35
  export interface SliderProps {
@@ -81,11 +82,7 @@ export interface SliderMethods {
81
82
  type Props = SliderProps &
82
83
  Omit<ComponentPropsWithoutRef<'div'>, keyof SliderProps>
83
84
 
84
- /**
85
- * Customizable slider
86
- * @category Slider
87
- */
88
- export const Slider = forwardRef<SliderMethods, Props>(
85
+ const SliderImpl = forwardRef<SliderMethods, Props>(
89
86
  (
90
87
  {
91
88
  value,
@@ -112,7 +109,7 @@ export const Slider = forwardRef<SliderMethods, Props>(
112
109
  onKeyDown,
113
110
  ...props
114
111
  }: Props,
115
- ref,
112
+ forwardedRef,
116
113
  ) => {
117
114
  // -- state and ref ---
118
115
  const trackElementRef = useRef<HTMLDivElement>(null)
@@ -138,9 +135,9 @@ export const Slider = forwardRef<SliderMethods, Props>(
138
135
  if (children != undefined) {
139
136
  React.Children.forEach(children, (child) => {
140
137
  if (React.isValidElement(child)) {
141
- if (child.type == SliderThumb) {
138
+ if (child.type == Thumb) {
142
139
  thumbProps = child.props as SliderThumbProps
143
- } else if (child.type == SliderTrack) {
140
+ } else if (child.type == Track) {
144
141
  trackProps = child.props as SliderTrackProps
145
142
  } else if (child.type == Scale) {
146
143
  scaleComponent = child
@@ -245,7 +242,7 @@ export const Slider = forwardRef<SliderMethods, Props>(
245
242
  [wheel, vertical, readonly, onChange, updateValueByEvent],
246
243
  )
247
244
 
248
- useImperativeHandle(ref, () => {
245
+ useImperativeHandle(forwardedRef, () => {
249
246
  return {
250
247
  focus() {
251
248
  thumbRef.current?.focus()
@@ -312,14 +309,10 @@ export const Slider = forwardRef<SliderMethods, Props>(
312
309
  }}
313
310
  >
314
311
  <div className="tremolo-slider-track-wrapper" ref={trackElementRef}>
315
- <SliderTrack
312
+ <Track
316
313
  __percent={percent}
317
314
  __thumb={
318
- <SliderThumb
319
- ref={thumbRef}
320
- __percent={percent}
321
- {...thumbProps}
322
- />
315
+ <Thumb ref={thumbRef} __percent={percent} {...thumbProps} />
323
316
  }
324
317
  {...trackProps}
325
318
  />
@@ -332,13 +325,20 @@ export const Slider = forwardRef<SliderMethods, Props>(
332
325
  },
333
326
  )
334
327
 
328
+ /**
329
+ * Customizable slider
330
+ * @category Slider
331
+ */
332
+ export const Slider = Object.assign(SliderImpl, {
333
+ Thumb,
334
+ Track,
335
+ Scale,
336
+ ScaleOption,
337
+ })
338
+
335
339
  export { useSliderContext } from './context'
336
- export {
337
- SliderThumb,
338
- type SliderThumbMethods,
339
- type SliderThumbProps,
340
- } from './Thumb'
341
- export { SliderTrack, type SliderTrackProps } from './Track'
342
- export { Scale, type ScaleProps } from './Scale'
343
- export { ScaleOption, type ScaleOptionProps } from './ScaleOption'
340
+ export { type SliderThumbMethods, type SliderThumbProps } from './Thumb'
341
+ export { type SliderTrackProps } from './Track'
342
+ export { type ScaleProps } from './Scale'
343
+ export { type ScaleOptionProps } from './ScaleOption'
344
344
  export { type ScaleOptions, type ScaleType } from './type'
@@ -2,7 +2,7 @@ import clsx from 'clsx'
2
2
  import { ComponentPropsWithoutRef, CSSProperties, ReactElement } from 'react'
3
3
 
4
4
  /** @category XYPad */
5
- export interface AreaProps {
5
+ export interface XYPadAreaProps {
6
6
  width?: number | string
7
7
  height?: number | string
8
8
  color?: string
@@ -15,7 +15,7 @@ export interface AreaProps {
15
15
  }
16
16
 
17
17
  /** @category XYPad */
18
- export function XYPadArea({
18
+ export function Area({
19
19
  width = 120,
20
20
  height = 120,
21
21
  color,
@@ -24,7 +24,8 @@ export function XYPadArea({
24
24
  style,
25
25
  __thumb,
26
26
  ...props
27
- }: AreaProps & Omit<ComponentPropsWithoutRef<'div'>, keyof AreaProps>) {
27
+ }: XYPadAreaProps &
28
+ Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadAreaProps>) {
28
29
  return (
29
30
  <div
30
31
  className={clsx('tremolo-xy-pad-area', className)}
@@ -9,7 +9,7 @@ import {
9
9
  } from 'react'
10
10
 
11
11
  /** @category XYPad */
12
- export interface ThumbProps {
12
+ export interface XYPadThumbProps {
13
13
  size?: number | string
14
14
  width?: number | string
15
15
  height?: number | string
@@ -24,6 +24,8 @@ export interface ThumbProps {
24
24
  /** @internal */
25
25
  __disabled?: boolean
26
26
  /** @internal */
27
+ __readonly?: boolean
28
+ /** @internal */
27
29
  __css?: CSSProperties
28
30
  }
29
31
 
@@ -33,11 +35,11 @@ export interface XYPadThumbMethods {
33
35
  blur: () => void
34
36
  }
35
37
 
36
- type Props = ThumbProps &
37
- Omit<ComponentPropsWithoutRef<'div'>, keyof ThumbProps>
38
+ type Props = XYPadThumbProps &
39
+ Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadThumbProps>
38
40
 
39
41
  /** @category XYPad */
40
- export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
42
+ export const Thumb = forwardRef<XYPadThumbMethods, Props>(
41
43
  (
42
44
  {
43
45
  size,
@@ -50,6 +52,7 @@ export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
50
52
  className,
51
53
  style,
52
54
  __disabled,
55
+ __readonly,
53
56
  __css,
54
57
  ...props
55
58
  }: Props,
@@ -87,6 +90,7 @@ export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
87
90
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
88
91
  tabIndex={0}
89
92
  aria-disabled={__disabled}
93
+ aria-readonly={__readonly}
90
94
  style={{
91
95
  ...{ '--color': color },
92
96
  width: size ?? width,
@@ -4,7 +4,7 @@
4
4
  }
5
5
 
6
6
  .tremolo-xy-pad-area {
7
- --color: #eee;
7
+ --color: oklch(95% 0 0);
8
8
 
9
9
  position: relative;
10
10
  background-color: var(--color);
@@ -17,18 +17,32 @@
17
17
  }
18
18
 
19
19
  .tremolo-xy-pad-thumb {
20
- --color: var(--tremolo-theme-color);
20
+ --color: oklch(59.5% 0.17548 266.373);
21
21
 
22
22
  border-radius: 50%;
23
23
  outline: none;
24
24
  background-color: var(--color);
25
25
 
26
26
  &[aria-disabled='true'] {
27
- background-color: #5d6478;
27
+ background-color: oklch(50.462% 0.03307 270.021);
28
28
  }
29
29
 
30
- &:focus {
30
+ &[aria-readonly='false']:focus {
31
31
  box-shadow: 0px 0px 0px 3px
32
32
  color-mix(in srgb, var(--color) 20%, transparent);
33
33
  }
34
34
  }
35
+
36
+ :where(.dark, [data-theme='dark']) {
37
+ .tremolo-xy-pad-area {
38
+ --color: oklch(41.7% 0 0);
39
+ }
40
+
41
+ .tremolo-xy-pad-thumb {
42
+ --color: oklch(64.5% 0.17548 266.373);
43
+
44
+ &:hover {
45
+ --color: oklch(67.5% 0.17548 266.373);
46
+ }
47
+ }
48
+ }
@@ -23,8 +23,8 @@ import { useDragWithElement } from '../../hooks/useDragWithElement'
23
23
  import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
24
24
  import { addNoSelect, removeNoSelect } from '../_util'
25
25
 
26
- import { XYPadArea, AreaProps } from './Area'
27
- import { XYPadThumb, XYPadThumbMethods, ThumbProps } from './Thumb'
26
+ import { Area, XYPadAreaProps } from './Area'
27
+ import { Thumb, XYPadThumbMethods, XYPadThumbProps } from './Thumb'
28
28
 
29
29
  /**
30
30
  * Two-dimensional slider component.
@@ -82,11 +82,7 @@ const defaultValueOptions = {
82
82
  type Props = XYPadProps &
83
83
  Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadProps>
84
84
 
85
- /**
86
- * Simple XYPad
87
- * @category XYPad
88
- */
89
- export const XYPad = forwardRef<XYPadMethods, Props>(
85
+ export const XYPadImpl = forwardRef<XYPadMethods, Props>(
90
86
  (
91
87
  {
92
88
  x: _x,
@@ -106,7 +102,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
106
102
  children,
107
103
  ...props
108
104
  }: Props,
109
- ref,
105
+ forwardedRef,
110
106
  ) => {
111
107
  const x = useMemo(() => {
112
108
  return { ...defaultValueOptions, ..._x }
@@ -125,15 +121,15 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
125
121
  const percentX = toFixed((x.reverse ? 1 - nx : nx) * 100)
126
122
  const percentY = toFixed((y.reverse ? 1 - ny : ny) * 100)
127
123
 
128
- let areaProps: AreaProps = {}
129
- let thumbProps: ThumbProps = {}
124
+ let areaProps: XYPadAreaProps = {}
125
+ let thumbProps: XYPadThumbProps = {}
130
126
  if (children != undefined) {
131
127
  React.Children.forEach(children, (child) => {
132
128
  if (React.isValidElement(child)) {
133
- if (child.type == XYPadThumb) {
134
- thumbProps = child.props as ThumbProps
135
- } else if (child.type == XYPadArea) {
136
- areaProps = child.props as AreaProps
129
+ if (child.type == Thumb) {
130
+ thumbProps = child.props as XYPadThumbProps
131
+ } else if (child.type == Area) {
132
+ areaProps = child.props as XYPadAreaProps
137
133
  } else {
138
134
  throw new Error('only <XYPadThumb> or <XYPadArea>')
139
135
  }
@@ -276,7 +272,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
276
272
  [x, y, onChange, readonly, updateValueByEvent],
277
273
  )
278
274
 
279
- useImperativeHandle(ref, () => {
275
+ useImperativeHandle(forwardedRef, () => {
280
276
  return {
281
277
  focus() {
282
278
  thumbRef.current?.focus()
@@ -323,11 +319,12 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
323
319
  {...props}
324
320
  >
325
321
  <div className="tremolo-xy-pad-area-wrapper" ref={areaElementRef}>
326
- <XYPadArea
322
+ <Area
327
323
  __thumb={
328
- <XYPadThumb
324
+ <Thumb
329
325
  ref={thumbRef}
330
326
  __disabled={disabled}
327
+ __readonly={readonly}
331
328
  __css={{
332
329
  top: `${percentY}%`,
333
330
  left: `${percentX}%`,
@@ -343,5 +340,14 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
343
340
  },
344
341
  )
345
342
 
346
- export * from './Thumb'
347
- export * from './Area'
343
+ /**
344
+ * Simple XYPad
345
+ * @category XYPad
346
+ */
347
+ export const XYPad = Object.assign(XYPadImpl, {
348
+ Thumb,
349
+ Area,
350
+ })
351
+
352
+ export { type XYPadThumbProps, type XYPadThumbMethods } from './Thumb'
353
+ export { type XYPadAreaProps } from './Area'
@@ -1,5 +1,8 @@
1
1
  import { DependencyList, useCallback, useEffect, useRef } from 'react'
2
2
 
3
+ /**
4
+ * @category hooks
5
+ */
3
6
  export function useAnimationFrame(
4
7
  callback = () => {},
5
8
  deps: DependencyList = [],
@@ -1,8 +1,8 @@
1
1
  import { useCallback, useInsertionEffect, useRef } from 'react'
2
2
 
3
3
  /**
4
- * This hook is user-land implementation of the experimental `useEffectEvent` hook.
5
- * React docs: https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event
4
+ * Internal
5
+ * @private
6
6
  */
7
7
  export function useCallbackRef<Args extends unknown[], Return>(
8
8
  callback: ((...args: Args) => Return) | undefined,
@@ -3,7 +3,7 @@ import { useRef, useCallback } from 'react'
3
3
  import { useEventListener } from './useEventListener'
4
4
  import { useRefCallbackEvent } from './useRefCallbackEvent'
5
5
 
6
- export interface UseDragProps {
6
+ interface UseDragProps {
7
7
  threshold?: number
8
8
 
9
9
  onDrag: (x: number, y: number, deltaX: number, deltaY: number) => void
@@ -12,6 +12,7 @@ export interface UseDragProps {
12
12
  }
13
13
 
14
14
  /**
15
+ * @category hooks
15
16
  * @returns [refCallback, pointerDownHandler]
16
17
  */
17
18
  export function useDrag<T extends Element>({
@@ -5,7 +5,7 @@ import { normalizeValue } from '@tremolo-ui/functions'
5
5
  import { useEventListener } from './useEventListener'
6
6
  import { useRefCallbackEvent } from './useRefCallbackEvent'
7
7
 
8
- export interface UseDragWithElementProps<T extends Element> {
8
+ interface UseDragWithElementProps<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
@@ -13,6 +13,7 @@ export interface UseDragWithElementProps<T extends Element> {
13
13
  }
14
14
 
15
15
  /**
16
+ * @category hooks
16
17
  * @returns [refCallback, pointerDownHandler]
17
18
  */
18
19
  export function useDragWithElement<T extends Element>({
@@ -5,6 +5,9 @@ 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
+ */
8
11
  export function useEventListener<K extends keyof DocumentEventMap>(
9
12
  target: Target,
10
13
  event: K,
@@ -1,5 +1,8 @@
1
1
  import { useEffect, useRef } from 'react'
2
2
 
3
+ /**
4
+ * @category hooks
5
+ */
3
6
  export function useInterval(callback: () => void, delay: number | null) {
4
7
  const savedCallback = useRef(callback)
5
8
 
@@ -3,6 +3,9 @@ import { useCallback, useState } from 'react'
3
3
  import { useEventListener } from './useEventListener'
4
4
  import { useInterval } from './useInterval'
5
5
 
6
+ /**
7
+ * @category hooks
8
+ */
6
9
  export function useLongPress(
7
10
  callback: () => void,
8
11
  initialDelay = 500,
@@ -0,0 +1,40 @@
1
+ import { useCallback, useEffect, useState } from 'react'
2
+
3
+ /** @private */
4
+ export const PERMISSION_DENIED = 'PERMISSION_DENIED'
5
+ /** @private */
6
+ export const NOT_SUPPORTED = 'NOT_SUPPORTED'
7
+
8
+ /** @private */
9
+ export type MIDIAccessError = typeof PERMISSION_DENIED | typeof NOT_SUPPORTED
10
+
11
+ /**
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
+ */
15
+ export function useMIDIAccess(requestOnMount = true) {
16
+ const [midiAccess, setMidiAccess] = useState<MIDIAccess | null>(null)
17
+ const [error, setError] = useState<MIDIAccessError | null>(null)
18
+
19
+ const request = useCallback(() => {
20
+ if (navigator.requestMIDIAccess) {
21
+ navigator
22
+ .requestMIDIAccess()
23
+ .then((access) => {
24
+ setMidiAccess(access)
25
+ setError(null)
26
+ })
27
+ .catch(() => {
28
+ setError(PERMISSION_DENIED)
29
+ })
30
+ } else {
31
+ setError(NOT_SUPPORTED)
32
+ }
33
+ }, [])
34
+
35
+ useEffect(() => {
36
+ if (requestOnMount) request()
37
+ }, [requestOnMount, request])
38
+
39
+ return { request, midiAccess, error }
40
+ }
@@ -0,0 +1,50 @@
1
+ import { useCallback } from 'react'
2
+
3
+ import { useMIDIMessage } from './useMIDIMessage'
4
+
5
+ const MIDI_EVENT_TO_NUMBER = {
6
+ NOTE_ON: 0x90,
7
+ NOTE_OFF: 0x80,
8
+ PITCH_BEND: 0xe0,
9
+ }
10
+
11
+ // const NUMBER_TO_MIDI_EVENT: Record<number, string> = {
12
+ // 0x90: 'NOTE_ON',
13
+ // 0x80: 'NOTE_OFF',
14
+ // 0xe0: 'PITCH_BEND',
15
+ // }
16
+
17
+ /**
18
+ * Hooks for handling note on/off events. To be used with useMIDIAccess. Internally uses useMIDIMessage.
19
+ * @category hooks
20
+ */
21
+ export function useMIDIInput(
22
+ midiAccess: MIDIAccess | null,
23
+ onNoteOnEvent?: (note: number, velocity: number) => void,
24
+ onNoteOffEvent?: (note: number) => void,
25
+ onPitchBendEvent?: (msb: number, lsb: number) => void,
26
+ ) {
27
+ const handleMIDIMessage = useCallback(
28
+ (event: MIDIMessageEvent) => {
29
+ if (!event.data) return
30
+ // event.data[0] ... command
31
+ // event.data[1] ... note, MSB (Most Significant Byte)
32
+ // event.data[2] ... velocity, LSB (Least Significant Byte)
33
+ const kind = event.data[0] & 0xf0
34
+
35
+ if (
36
+ kind == MIDI_EVENT_TO_NUMBER.NOTE_OFF ||
37
+ (kind == MIDI_EVENT_TO_NUMBER.NOTE_ON && event.data[2] == 0)
38
+ ) {
39
+ onNoteOffEvent?.(event.data[1])
40
+ } else if (kind == MIDI_EVENT_TO_NUMBER.NOTE_ON) {
41
+ onNoteOnEvent?.(event.data[1], event.data[2])
42
+ } else if (kind == MIDI_EVENT_TO_NUMBER.PITCH_BEND) {
43
+ onPitchBendEvent?.(event.data[1], event.data[2])
44
+ }
45
+ },
46
+ [onNoteOffEvent, onNoteOnEvent, onPitchBendEvent],
47
+ )
48
+
49
+ useMIDIMessage(midiAccess, handleMIDIMessage)
50
+ }
@@ -0,0 +1,24 @@
1
+ import { useEffect } from 'react'
2
+
3
+ /**
4
+ * Hooks for when you want to process MIDI events in more detail than useMIDIInput.
5
+ * @category hooks
6
+ */
7
+ export function useMIDIMessage(
8
+ midiAccess: MIDIAccess | null,
9
+ onMIDIMessage: (event: MIDIMessageEvent) => void,
10
+ ) {
11
+ useEffect(() => {
12
+ if (!midiAccess) return
13
+
14
+ for (const input of midiAccess.inputs.values()) {
15
+ input.addEventListener('midimessage', onMIDIMessage)
16
+ }
17
+
18
+ return () => {
19
+ for (const input of midiAccess.inputs.values()) {
20
+ input.removeEventListener('midimessage', onMIDIMessage)
21
+ }
22
+ }
23
+ }, [midiAccess, onMIDIMessage])
24
+ }
@@ -1,5 +1,9 @@
1
1
  import { useMemo } from 'react'
2
2
 
3
+ /**
4
+ * Internal
5
+ * @private
6
+ */
3
7
  export function useRefCallbackEvent<K extends keyof DocumentEventMap>(
4
8
  event: K,
5
9
  handler: (event: DocumentEventMap[K]) => void,
package/src/index.ts CHANGED
@@ -7,8 +7,8 @@ import './components/Slider/index.css'
7
7
  import './components/XYPad/index.css'
8
8
 
9
9
  export {
10
- type AbsoluteSizingProps,
11
10
  AnimationCanvas,
11
+ type AbsoluteSizingProps,
12
12
  type AnimationCanvasProps,
13
13
  type CommonProps,
14
14
  type DrawFunction,
@@ -17,72 +17,67 @@ export {
17
17
  } from './components/AnimationCanvas'
18
18
  export {
19
19
  AnimationKnob,
20
- type AnimationKnobMethods,
21
20
  type AnimationKnobProps,
21
+ type AnimationKnobMethods,
22
22
  } from './components/AnimationKnob'
23
23
  export { DragObserver, type DragObserverProps } from './components/DragObserver'
24
- export { Knob, type KnobMethods, type KnobProps } from './components/Knob'
24
+ export { Knob, type KnobProps, type KnobMethods } from './components/Knob'
25
25
  export {
26
- DecrementStepper,
27
- type DecrementStepperProps,
28
- IncrementStepper,
29
- type IncrementStepperProps,
30
26
  NumberInput,
31
- type NumberInputMethods,
32
27
  type NumberInputProps,
33
- Stepper,
28
+ type NumberInputMethods,
34
29
  type StepperProps,
30
+ type IncrementStepperProps,
31
+ type DecrementStepperProps,
35
32
  } from './components/NumberInput'
36
33
  export {
37
- BlackKey,
38
- KeyLabel,
39
- type KeyLabelProps,
40
- type KeyMethods,
41
- type KeyProps,
42
- type KeyboardShortcuts,
43
34
  Piano,
44
- type PianoProps,
45
- SHORTCUTS,
46
- WhiteKey,
47
35
  getNoteRangeArray,
36
+ SHORTCUTS,
37
+ type PianoProps,
38
+ type PianoMethods,
39
+ type KeyProps,
40
+ type KeyMethods,
41
+ type KeyLabelProps,
42
+ type KeyboardShortcuts,
48
43
  } from './components/Piano'
49
44
  export {
50
- Scale,
51
- ScaleOption,
45
+ Slider,
46
+ useSliderContext,
52
47
  type ScaleOptionProps,
53
48
  type ScaleProps,
54
- Slider,
55
49
  type SliderMethods,
56
50
  type SliderProps,
57
- SliderThumb,
58
51
  type SliderThumbMethods,
59
52
  type SliderThumbProps,
60
- SliderTrack,
61
53
  type SliderTrackProps,
62
- useSliderContext,
63
54
  } from './components/Slider'
64
55
  export {
65
56
  WheelObserver,
66
57
  type WheelObserverProps,
67
58
  } from './components/WheelObserver'
68
59
  export {
69
- type AreaProps,
70
- type ThumbProps,
71
- type ValueOptions,
72
60
  XYPad,
73
- XYPadArea,
74
- type XYPadMethods,
75
61
  type XYPadProps,
76
- XYPadThumb,
62
+ type XYPadMethods,
63
+ type XYPadAreaProps,
64
+ type XYPadThumbProps,
77
65
  type XYPadThumbMethods,
66
+ type ValueOptions,
78
67
  } from './components/XYPad'
79
68
 
69
+ // hooks
80
70
  export { useAnimationFrame } from './hooks/useAnimationFrame'
81
- export { useDrag, type UseDragProps } from './hooks/useDrag'
82
- export {
83
- useDragWithElement,
84
- type UseDragWithElementProps,
85
- } from './hooks/useDragWithElement'
71
+ export { useDrag } from './hooks/useDrag'
72
+ export { useDragWithElement } from './hooks/useDragWithElement'
86
73
  export { useEventListener } from './hooks/useEventListener'
87
74
  export { useInterval } from './hooks/useInterval'
88
75
  export { useLongPress } from './hooks/useLongPress'
76
+ export {
77
+ useMIDIAccess,
78
+ NOT_SUPPORTED,
79
+ PERMISSION_DENIED,
80
+ type MIDIAccessError,
81
+ } from './hooks/useMIDIAccess'
82
+ export { useMIDIInput } from './hooks/useMIDIInput'
83
+ export { useMIDIMessage } from './hooks/useMIDIMessage'
@@ -1,7 +1,3 @@
1
- :root {
2
- --tremolo-theme-color: #4e76e6;
3
- }
4
-
5
1
  .tremolo-no-select {
6
2
  user-select: none;
7
3
  }