@tremolo-ui/react 0.0.8 → 0.0.10

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 (148) hide show
  1. package/dist/cjs/index.js +439 -275
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +9 -4
  4. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
  5. package/dist/cjs/types/components/AnimationKnob/index.d.ts +2 -0
  6. package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -1
  7. package/dist/cjs/types/components/DragObserver/index.d.ts +3 -1
  8. package/dist/cjs/types/components/DragObserver/index.d.ts.map +1 -1
  9. package/dist/cjs/types/components/Knob/index.d.ts +2 -0
  10. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  11. package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts +7 -0
  12. package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts.map +1 -0
  13. package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts +7 -0
  14. package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts.map +1 -0
  15. package/dist/cjs/types/components/NumberInput/Stepper.d.ts +8 -0
  16. package/dist/cjs/types/components/NumberInput/Stepper.d.ts.map +1 -0
  17. package/dist/cjs/types/components/NumberInput/context.d.ts +27 -0
  18. package/dist/cjs/types/components/NumberInput/context.d.ts.map +1 -0
  19. package/dist/cjs/types/components/NumberInput/index.d.ts +31 -16
  20. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
  21. package/dist/cjs/types/components/Piano/BlackKey.d.ts +1 -0
  22. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -1
  23. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +2 -0
  24. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -1
  25. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +3 -0
  26. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -1
  27. package/dist/cjs/types/components/Piano/index.d.ts +6 -4
  28. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
  29. package/dist/cjs/types/components/Piano/key.d.ts +8 -2
  30. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
  31. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +2 -0
  32. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  33. package/dist/cjs/types/components/Slider/Scale.d.ts +2 -0
  34. package/dist/cjs/types/components/Slider/Scale.d.ts.map +1 -1
  35. package/dist/cjs/types/components/Slider/ScaleOption.d.ts +2 -0
  36. package/dist/cjs/types/components/Slider/ScaleOption.d.ts.map +1 -1
  37. package/dist/cjs/types/components/Slider/Thumb.d.ts +4 -0
  38. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
  39. package/dist/cjs/types/components/Slider/Track.d.ts +6 -1
  40. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
  41. package/dist/cjs/types/components/Slider/context.d.ts +15 -12
  42. package/dist/cjs/types/components/Slider/context.d.ts.map +1 -1
  43. package/dist/cjs/types/components/Slider/index.d.ts +8 -5
  44. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  45. package/dist/cjs/types/components/WheelObserver/index.d.ts +1 -0
  46. package/dist/cjs/types/components/WheelObserver/index.d.ts.map +1 -1
  47. package/dist/cjs/types/components/XYPad/Area.d.ts +2 -0
  48. package/dist/cjs/types/components/XYPad/Area.d.ts.map +1 -1
  49. package/dist/cjs/types/components/XYPad/Thumb.d.ts +3 -0
  50. package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +1 -1
  51. package/dist/cjs/types/components/XYPad/index.d.ts +4 -0
  52. package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -1
  53. package/dist/cjs/types/hooks/useAnimationFrame.d.ts +3 -0
  54. package/dist/cjs/types/hooks/useAnimationFrame.d.ts.map +1 -0
  55. package/dist/cjs/types/hooks/useDrag.d.ts +15 -0
  56. package/dist/cjs/types/hooks/useDrag.d.ts.map +1 -0
  57. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts +1 -4
  58. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts.map +1 -1
  59. package/dist/esm/index.js +437 -266
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/types/components/AnimationCanvas/index.d.ts +9 -4
  62. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
  63. package/dist/esm/types/components/AnimationKnob/index.d.ts +2 -0
  64. package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -1
  65. package/dist/esm/types/components/DragObserver/index.d.ts +3 -1
  66. package/dist/esm/types/components/DragObserver/index.d.ts.map +1 -1
  67. package/dist/esm/types/components/Knob/index.d.ts +2 -0
  68. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  69. package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts +7 -0
  70. package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts.map +1 -0
  71. package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts +7 -0
  72. package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts.map +1 -0
  73. package/dist/esm/types/components/NumberInput/Stepper.d.ts +8 -0
  74. package/dist/esm/types/components/NumberInput/Stepper.d.ts.map +1 -0
  75. package/dist/esm/types/components/NumberInput/context.d.ts +27 -0
  76. package/dist/esm/types/components/NumberInput/context.d.ts.map +1 -0
  77. package/dist/esm/types/components/NumberInput/index.d.ts +31 -16
  78. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
  79. package/dist/esm/types/components/Piano/BlackKey.d.ts +1 -0
  80. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -1
  81. package/dist/esm/types/components/Piano/KeyLabel.d.ts +2 -0
  82. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -1
  83. package/dist/esm/types/components/Piano/WhiteKey.d.ts +3 -0
  84. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -1
  85. package/dist/esm/types/components/Piano/index.d.ts +6 -4
  86. package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
  87. package/dist/esm/types/components/Piano/key.d.ts +8 -2
  88. package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
  89. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +2 -0
  90. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  91. package/dist/esm/types/components/Slider/Scale.d.ts +2 -0
  92. package/dist/esm/types/components/Slider/Scale.d.ts.map +1 -1
  93. package/dist/esm/types/components/Slider/ScaleOption.d.ts +2 -0
  94. package/dist/esm/types/components/Slider/ScaleOption.d.ts.map +1 -1
  95. package/dist/esm/types/components/Slider/Thumb.d.ts +4 -0
  96. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
  97. package/dist/esm/types/components/Slider/Track.d.ts +6 -1
  98. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
  99. package/dist/esm/types/components/Slider/context.d.ts +15 -12
  100. package/dist/esm/types/components/Slider/context.d.ts.map +1 -1
  101. package/dist/esm/types/components/Slider/index.d.ts +8 -5
  102. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  103. package/dist/esm/types/components/WheelObserver/index.d.ts +1 -0
  104. package/dist/esm/types/components/WheelObserver/index.d.ts.map +1 -1
  105. package/dist/esm/types/components/XYPad/Area.d.ts +2 -0
  106. package/dist/esm/types/components/XYPad/Area.d.ts.map +1 -1
  107. package/dist/esm/types/components/XYPad/Thumb.d.ts +3 -0
  108. package/dist/esm/types/components/XYPad/Thumb.d.ts.map +1 -1
  109. package/dist/esm/types/components/XYPad/index.d.ts +4 -0
  110. package/dist/esm/types/components/XYPad/index.d.ts.map +1 -1
  111. package/dist/esm/types/hooks/useAnimationFrame.d.ts +3 -0
  112. package/dist/esm/types/hooks/useAnimationFrame.d.ts.map +1 -0
  113. package/dist/esm/types/hooks/useDrag.d.ts +15 -0
  114. package/dist/esm/types/hooks/useDrag.d.ts.map +1 -0
  115. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts +1 -4
  116. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts.map +1 -1
  117. package/dist/styles/index.css +110 -13
  118. package/package.json +8 -5
  119. package/src/components/AnimationCanvas/index.tsx +13 -4
  120. package/src/components/AnimationKnob/index.tsx +24 -42
  121. package/src/components/DragObserver/index.tsx +14 -52
  122. package/src/components/Knob/index.tsx +23 -40
  123. package/src/components/NumberInput/DecrementStepper.tsx +52 -0
  124. package/src/components/NumberInput/IncrementStepper.tsx +52 -0
  125. package/src/components/NumberInput/Stepper.tsx +25 -0
  126. package/src/components/NumberInput/context.tsx +150 -0
  127. package/src/components/NumberInput/index.css +102 -13
  128. package/src/components/NumberInput/index.tsx +164 -55
  129. package/src/components/Piano/BlackKey.tsx +15 -11
  130. package/src/components/Piano/KeyLabel.tsx +2 -0
  131. package/src/components/Piano/WhiteKey.tsx +17 -11
  132. package/src/components/Piano/index.tsx +16 -14
  133. package/src/components/Piano/key.ts +8 -2
  134. package/src/components/Piano/keyboardShortcuts.ts +2 -0
  135. package/src/components/Slider/Scale.tsx +8 -6
  136. package/src/components/Slider/ScaleOption.tsx +8 -6
  137. package/src/components/Slider/Thumb.tsx +7 -3
  138. package/src/components/Slider/Track.tsx +27 -15
  139. package/src/components/Slider/context.tsx +65 -51
  140. package/src/components/Slider/index.css +8 -0
  141. package/src/components/Slider/index.tsx +19 -10
  142. package/src/components/WheelObserver/index.tsx +1 -0
  143. package/src/components/XYPad/Area.tsx +2 -0
  144. package/src/components/XYPad/Thumb.tsx +3 -0
  145. package/src/components/XYPad/index.tsx +6 -2
  146. package/src/hooks/useAnimationFrame.ts +18 -0
  147. package/src/hooks/useDrag.ts +92 -0
  148. package/src/hooks/useRefCallbackEvent.ts +4 -7
@@ -8,13 +8,15 @@ import React, {
8
8
 
9
9
  import { KeyMethods, KeyProps } from './key'
10
10
  import { KeyLabel, KeyLabelProps } from './KeyLabel'
11
+ import { defaultWhiteKeyWidth } from './WhiteKey'
11
12
 
12
13
  type Props = KeyProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KeyProps>
13
14
 
15
+ /** @category Piano */
14
16
  export const BlackKey = forwardRef<KeyMethods, Props>(
15
17
  (
16
18
  {
17
- width = 40 * 0.65,
19
+ width = defaultWhiteKeyWidth * 0.65,
18
20
  height = '60%',
19
21
  className,
20
22
  style,
@@ -26,8 +28,8 @@ export const BlackKey = forwardRef<KeyMethods, Props>(
26
28
  __index,
27
29
  __fill,
28
30
  __width,
29
- __playNote,
30
- __stopNote,
31
+ __onPlayNote,
32
+ __onStopNote,
31
33
  __label,
32
34
  ...props
33
35
  }: Props,
@@ -40,17 +42,17 @@ export const BlackKey = forwardRef<KeyMethods, Props>(
40
42
  play() {
41
43
  if (__disabled) return
42
44
  setPlayed(true)
43
- if (__playNote) __playNote(__note!)
45
+ if (__onPlayNote) __onPlayNote(__note!)
44
46
  },
45
47
  stop() {
46
48
  setPlayed(false)
47
- if (__stopNote) __stopNote(__note!)
49
+ if (__onStopNote) __onStopNote(__note!)
48
50
  },
49
51
  played() {
50
52
  return played
51
53
  },
52
54
  }
53
- }, [__disabled, __note, __playNote, __stopNote, played])
55
+ }, [__disabled, __note, __onPlayNote, __onStopNote, played])
54
56
 
55
57
  let keyLabelProps: KeyLabelProps = {}
56
58
  if (children != undefined) {
@@ -81,24 +83,26 @@ export const BlackKey = forwardRef<KeyMethods, Props>(
81
83
  onPointerDown={() => {
82
84
  if (__disabled) return
83
85
  setPlayed(true)
84
- if (__playNote) __playNote(__note!)
86
+ if (__onPlayNote) __onPlayNote(__note!)
85
87
  }}
86
88
  onPointerEnter={() => {
87
89
  if (__disabled) return
88
90
  if (__glissando) {
89
91
  setPlayed(true)
90
- if (__playNote) __playNote(__note!)
92
+ if (__onPlayNote) __onPlayNote(__note!)
91
93
  }
92
94
  }}
93
95
  onPointerUp={() => {
94
96
  if (__disabled) return
95
97
  setPlayed(false)
96
- if (__stopNote) __stopNote(__note!)
98
+ if (__onStopNote) __onStopNote(__note!)
97
99
  }}
98
100
  onPointerLeave={() => {
99
101
  if (__disabled) return
100
- setPlayed(false)
101
- if (__stopNote) __stopNote(__note!)
102
+ if (__glissando) {
103
+ setPlayed(false)
104
+ if (__onStopNote) __onStopNote(__note!)
105
+ }
102
106
  }}
103
107
  {...props}
104
108
  >
@@ -1,6 +1,7 @@
1
1
  import clsx from 'clsx'
2
2
  import { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react'
3
3
 
4
+ /** @category Piano */
4
5
  export interface KeyLabelProps {
5
6
  /**
6
7
  * override Piano.label
@@ -18,6 +19,7 @@ export interface KeyLabelProps {
18
19
  __label?: (note: number, index: number) => ReactNode
19
20
  }
20
21
 
22
+ /** @category Piano */
21
23
  export function KeyLabel({
22
24
  label,
23
25
  className,
@@ -11,10 +11,14 @@ import { KeyLabel, KeyLabelProps } from './KeyLabel'
11
11
 
12
12
  type Props = KeyProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KeyProps>
13
13
 
14
+ /** @category Piano */
15
+ export const defaultWhiteKeyWidth = 40
16
+
17
+ /** @category Piano */
14
18
  export const WhiteKey = forwardRef<KeyMethods, Props>(
15
19
  (
16
20
  {
17
- width = 40,
21
+ width = defaultWhiteKeyWidth,
18
22
  height = '100%',
19
23
  className,
20
24
  style,
@@ -26,8 +30,8 @@ export const WhiteKey = forwardRef<KeyMethods, Props>(
26
30
  __index,
27
31
  __fill,
28
32
  __width,
29
- __playNote,
30
- __stopNote,
33
+ __onPlayNote,
34
+ __onStopNote,
31
35
  __label,
32
36
  ...props
33
37
  }: Props,
@@ -40,17 +44,17 @@ export const WhiteKey = forwardRef<KeyMethods, Props>(
40
44
  play() {
41
45
  if (__disabled) return
42
46
  setPlayed(true)
43
- if (__playNote) __playNote(__note!)
47
+ if (__onPlayNote) __onPlayNote(__note!)
44
48
  },
45
49
  stop() {
46
50
  setPlayed(false)
47
- if (__stopNote) __stopNote(__note!)
51
+ if (__onStopNote) __onStopNote(__note!)
48
52
  },
49
53
  played() {
50
54
  return played
51
55
  },
52
56
  }
53
- }, [__disabled, __note, __playNote, __stopNote, played])
57
+ }, [__disabled, __note, __onPlayNote, __onStopNote, played])
54
58
 
55
59
  let keyLabelProps: KeyLabelProps = {}
56
60
  if (children != undefined) {
@@ -81,24 +85,26 @@ export const WhiteKey = forwardRef<KeyMethods, Props>(
81
85
  onPointerDown={() => {
82
86
  if (__disabled) return
83
87
  setPlayed(true)
84
- if (__playNote) __playNote(__note!)
88
+ if (__onPlayNote) __onPlayNote(__note!)
85
89
  }}
86
90
  onPointerEnter={() => {
87
91
  if (__disabled) return
88
92
  if (__glissando) {
89
93
  setPlayed(true)
90
- if (__playNote) __playNote(__note!)
94
+ if (__onPlayNote) __onPlayNote(__note!)
91
95
  }
92
96
  }}
93
97
  onPointerUp={() => {
94
98
  if (__disabled) return
95
99
  setPlayed(false)
96
- if (__stopNote) __stopNote(__note!)
100
+ if (__onStopNote) __onStopNote(__note!)
97
101
  }}
98
102
  onPointerLeave={() => {
99
103
  if (__disabled) return
100
- setPlayed(false)
101
- if (__stopNote) __stopNote(__note!)
104
+ if (__glissando) {
105
+ setPlayed(false)
106
+ if (__onStopNote) __onStopNote(__note!)
107
+ }
102
108
  }}
103
109
  {...props}
104
110
  >
@@ -24,7 +24,7 @@ import { useEventListener } from '../../hooks/useEventListener'
24
24
  import { BlackKey } from './BlackKey'
25
25
  import { KeyMethods, KeyProps } from './key'
26
26
  import { KeyBoardShortcuts } from './keyboardShortcuts'
27
- import { WhiteKey } from './WhiteKey'
27
+ import { defaultWhiteKeyWidth, WhiteKey } from './WhiteKey'
28
28
 
29
29
  /**
30
30
  * Piano component
@@ -33,6 +33,7 @@ import { WhiteKey } from './WhiteKey'
33
33
  * - add scale highlight
34
34
  */
35
35
 
36
+ /** @category Piano */
36
37
  export interface PianoProps {
37
38
  // required
38
39
  noteRange: { first: number; last: number }
@@ -47,8 +48,8 @@ export interface PianoProps {
47
48
 
48
49
  style?: CSSProperties
49
50
 
50
- playNote?: (noteNumber: number) => void
51
- stopNote?: (noteNumber: number) => void
51
+ onPlayNote?: (noteNumber: number) => void
52
+ onStopNote?: (noteNumber: number) => void
52
53
 
53
54
  label?: (note: number, index: number) => ReactNode
54
55
 
@@ -58,6 +59,7 @@ export interface PianoProps {
58
59
  children?: ReactElement | ReactElement[]
59
60
  }
60
61
 
62
+ /** @category Piano */
61
63
  export function Piano({
62
64
  noteRange,
63
65
  glissando = true,
@@ -67,8 +69,8 @@ export function Piano({
67
69
  height = fill ? '100%' : 160,
68
70
  style,
69
71
  className,
70
- playNote,
71
- stopNote,
72
+ onPlayNote,
73
+ onStopNote,
72
74
  label,
73
75
  children,
74
76
  ...props
@@ -149,11 +151,11 @@ export function Piano({
149
151
  })
150
152
  resizeObserver.observe(parent)
151
153
  } else {
152
- setWhiteNoteWidth(whiteKeyProps?.width || 40)
154
+ setWhiteNoteWidth(whiteKeyProps?.width || defaultWhiteKeyWidth)
153
155
  }
154
156
  }, [fill, whiteKeyProps?.width, whiteNoteCount])
155
157
 
156
- useEventListener(window, 'keydown', (e) => {
158
+ useEventListener(globalThis.window, 'keydown', (e) => {
157
159
  if (e.repeat) return
158
160
  if (!keyboardShortcuts) return
159
161
  const index = keyboardShortcuts.keys.indexOf(e.key)
@@ -164,7 +166,7 @@ export function Piano({
164
166
  }
165
167
  })
166
168
 
167
- useEventListener(window, 'keyup', (e) => {
169
+ useEventListener(globalThis.window, 'keyup', (e) => {
168
170
  if (e.repeat) return
169
171
  if (!keyboardShortcuts) return
170
172
  const index = keyboardShortcuts.keys.indexOf(e.key)
@@ -178,7 +180,7 @@ export function Piano({
178
180
  ref={pianoRef}
179
181
  className={clsx('tremolo-piano', className)}
180
182
  style={{
181
- width: fill ? '100%' : undefined,
183
+ width: fill ? '100%' : (whiteNoteWidth + 3) * whiteNoteCount,
182
184
  height: height,
183
185
  ...style,
184
186
  }}
@@ -204,8 +206,8 @@ export function Piano({
204
206
  __index={index}
205
207
  __fill={fill}
206
208
  __width={whiteNoteWidth}
207
- __playNote={playNote}
208
- __stopNote={stopNote}
209
+ __onPlayNote={onPlayNote}
210
+ __onStopNote={onStopNote}
209
211
  __label={label}
210
212
  {...whiteKeyProps}
211
213
  />
@@ -220,8 +222,8 @@ export function Piano({
220
222
  __index={index}
221
223
  __fill={fill}
222
224
  __width={whiteNoteWidth * 0.65}
223
- __playNote={playNote}
224
- __stopNote={stopNote}
225
+ __onPlayNote={onPlayNote}
226
+ __onStopNote={onStopNote}
225
227
  __label={label}
226
228
  {...blackKeyProps}
227
229
  />
@@ -236,4 +238,4 @@ export * from './keyboardShortcuts'
236
238
 
237
239
  export { WhiteKey } from './WhiteKey'
238
240
  export { BlackKey } from './BlackKey'
239
- export { KeyLabel } from './KeyLabel'
241
+ export { KeyLabel, type KeyLabelProps } from './KeyLabel'
@@ -1,5 +1,8 @@
1
1
  import { CSSProperties, ReactElement, ReactNode } from 'react'
2
2
 
3
+ /**
4
+ * @category Piano
5
+ */
3
6
  export interface KeyProps {
4
7
  width?: number
5
8
  height?: number | `${number}%`
@@ -26,13 +29,16 @@ export interface KeyProps {
26
29
  /** @internal */
27
30
  __width?: number
28
31
  /** @internal */
29
- __playNote?: (noteNumber: number) => void
32
+ __onPlayNote?: (noteNumber: number) => void
30
33
  /** @internal */
31
- __stopNote?: (noteNumber: number) => void
34
+ __onStopNote?: (noteNumber: number) => void
32
35
  /** @internal */
33
36
  __label?: (note: number, index: number) => ReactNode
34
37
  }
35
38
 
39
+ /**
40
+ * @category Piano
41
+ */
36
42
  export interface KeyMethods {
37
43
  play: () => void
38
44
  stop: () => void
@@ -1,3 +1,4 @@
1
+ /** @category Piano */
1
2
  export type KeyBoardShortcuts = {
2
3
  keys: string[]
3
4
  // TODO
@@ -6,6 +7,7 @@ export type KeyBoardShortcuts = {
6
7
  }
7
8
  }
8
9
 
10
+ /** @category Piano */
9
11
  export const Shortcuts = {
10
12
  HOME_ROW: {
11
13
  keys: [
@@ -4,9 +4,10 @@ import { ComponentPropsWithoutRef, ReactNode } from 'react'
4
4
  import { xor } from '@tremolo-ui/functions'
5
5
  import { generateOptionsList, ScaleOptions } from '@tremolo-ui/functions/Slider'
6
6
 
7
- import { useMax, useMin, useReverse, useStep, useVertical } from './context'
7
+ import { useSliderContext } from './context'
8
8
  import { ScaleOption } from './ScaleOption'
9
9
 
10
+ /** @category Slider */
10
11
  export interface ScaleProps {
11
12
  gap?: number | string
12
13
  options?: ScaleOptions
@@ -16,6 +17,7 @@ export interface ScaleProps {
16
17
  type Props = ScaleProps &
17
18
  Omit<ComponentPropsWithoutRef<'div'>, keyof ScaleProps>
18
19
 
20
+ /** @category Slider */
19
21
  export function Scale({
20
22
  gap = 6,
21
23
  options,
@@ -24,11 +26,11 @@ export function Scale({
24
26
  style,
25
27
  ...props
26
28
  }: Props) {
27
- const min = useMin()
28
- const max = useMax()
29
- const step = useStep()
30
- const vertical = useVertical()
31
- const reverse = useReverse()
29
+ const min = useSliderContext((s) => s.min)
30
+ const max = useSliderContext((s) => s.max)
31
+ const step = useSliderContext((s) => s.step)
32
+ const vertical = useSliderContext((s) => s.vertical)
33
+ const reverse = useSliderContext((s) => s.reverse)
32
34
 
33
35
  const optionsList = options
34
36
  ? generateOptionsList(options, min, max, step)
@@ -4,8 +4,9 @@ import { ComponentPropsWithoutRef, CSSProperties, useCallback } from 'react'
4
4
  import { toFixed, xor, normalizeValue } from '@tremolo-ui/functions'
5
5
  import { ScaleType } from '@tremolo-ui/functions/Slider'
6
6
 
7
- import { useMax, useMin, useReverse, useSkew, useVertical } from './context'
7
+ import { useSliderContext } from './context'
8
8
 
9
+ /** @category Slider */
9
10
  export interface ScaleOptionProps {
10
11
  // required
11
12
  value: number
@@ -31,6 +32,7 @@ export interface ScaleOptionProps {
31
32
  }
32
33
  }
33
34
 
35
+ /** @category Slider */
34
36
  export function ScaleOption({
35
37
  value,
36
38
  type = 'mark-number',
@@ -46,11 +48,11 @@ export function ScaleOption({
46
48
  ...props
47
49
  }: ScaleOptionProps &
48
50
  Omit<ComponentPropsWithoutRef<'div'>, keyof ScaleOptionProps>) {
49
- const min = useMin()
50
- const max = useMax()
51
- const skew = useSkew()
52
- const vertical = useVertical()
53
- const reverse = useReverse()
51
+ const min = useSliderContext((s) => s.min)
52
+ const max = useSliderContext((s) => s.max)
53
+ const skew = useSliderContext((s) => s.skew)
54
+ const vertical = useSliderContext((s) => s.vertical)
55
+ const reverse = useSliderContext((s) => s.reverse)
54
56
 
55
57
  const calcPercent = useCallback(
56
58
  (rawValue: number) => {
@@ -7,8 +7,9 @@ import {
7
7
  useRef,
8
8
  } from 'react'
9
9
 
10
- import { useDisabled, useVertical } from './context'
10
+ import { useSliderContext } from './context'
11
11
 
12
+ /** @category Slider */
12
13
  export interface SliderThumbProps {
13
14
  size?: number | string
14
15
  width?: number | string
@@ -22,13 +23,16 @@ export interface SliderThumbProps {
22
23
  __percent?: number
23
24
  }
24
25
 
26
+ /** @category Slider */
25
27
  export interface SliderThumbMethods {
26
28
  focus: () => void
27
29
  blur: () => void
28
30
  }
29
31
 
32
+ /** @category Slider */
30
33
  export const defaultThumbSize = 22
31
34
 
35
+ /** @category Slider */
32
36
  export const SliderThumb = forwardRef<SliderThumbMethods, SliderThumbProps>(
33
37
  (
34
38
  {
@@ -43,8 +47,8 @@ export const SliderThumb = forwardRef<SliderThumbMethods, SliderThumbProps>(
43
47
  ref,
44
48
  ) => {
45
49
  const wrapperRef = useRef<HTMLDivElement>(null)
46
- const vertical = useVertical()
47
- const disabled = useDisabled()
50
+ const vertical = useSliderContext((s) => s.vertical)
51
+ const disabled = useSliderContext((s) => s.disabled)
48
52
 
49
53
  useImperativeHandle(ref, () => {
50
54
  return {
@@ -3,11 +3,14 @@ import { CSSProperties, ReactElement } from 'react'
3
3
 
4
4
  import { styleHelper, xor } from '@tremolo-ui/functions'
5
5
 
6
- import { useDisabled, useReverse, useVertical } from './context'
6
+ import { useSliderContext } from './context'
7
7
 
8
+ /** @category Slider */
8
9
  export const defaultLength = 140
10
+ /** @category Slider */
9
11
  export const defaultThickness = 10
10
12
 
13
+ /** @category Slider */
11
14
  export interface SliderTrackProps {
12
15
  length?: number | string
13
16
  thickness?: number | string
@@ -15,6 +18,8 @@ export interface SliderTrackProps {
15
18
  active?: string
16
19
  inactive?: string
17
20
 
21
+ defaultStyle?: boolean
22
+
18
23
  className?: string
19
24
  style?: CSSProperties
20
25
  children?: ReactElement
@@ -25,6 +30,7 @@ export interface SliderTrackProps {
25
30
  __percent?: number
26
31
  }
27
32
 
33
+ /** @category Slider */
28
34
  export function SliderTrack({
29
35
  length = defaultLength,
30
36
  thickness = defaultThickness,
@@ -33,12 +39,13 @@ export function SliderTrack({
33
39
  children,
34
40
  className,
35
41
  style,
42
+ defaultStyle = true,
36
43
  __thumb,
37
- __percent,
44
+ __percent = 0,
38
45
  }: SliderTrackProps) {
39
- const vertical = useVertical()
40
- const reverse = useReverse()
41
- const disabled = useDisabled()
46
+ const vertical = useSliderContext((s) => s.vertical)
47
+ const reverse = useSliderContext((s) => s.reverse)
48
+ const disabled = useSliderContext((s) => s.disabled)
42
49
 
43
50
  const direction = vertical ? 'bottom' : 'right'
44
51
  const colors = {
@@ -50,16 +57,21 @@ export function SliderTrack({
50
57
  <div
51
58
  className={clsx('tremolo-slider-track', className)}
52
59
  aria-disabled={disabled}
53
- style={{
54
- ...colors,
55
- background: xor(vertical, reverse)
56
- ? `linear-gradient(to ${direction}, var(--inactive, #eee) ${__percent}%, var(--active, #7998ec) ${__percent}%)`
57
- : `linear-gradient(to ${direction}, var(--active, #7998ec) ${__percent}%, var(--inactive, #eee) ${__percent}%)`,
58
- borderRadius: styleHelper(thickness!, '/', 2),
59
- width: !vertical ? length : thickness,
60
- height: vertical ? length : thickness,
61
- ...style,
62
- }}
60
+ data-vertical={vertical}
61
+ style={
62
+ !defaultStyle
63
+ ? style
64
+ : {
65
+ ...colors,
66
+ background: xor(vertical, reverse)
67
+ ? `linear-gradient(to ${direction}, var(--inactive, #eee) ${__percent}%, var(--active, #7998ec) ${__percent}%)`
68
+ : `linear-gradient(to ${direction}, var(--active, #7998ec) ${__percent}%, var(--inactive, #eee) ${__percent}%)`,
69
+ borderRadius: styleHelper(thickness!, '/', 2),
70
+ width: !vertical ? length : thickness,
71
+ height: vertical ? length : thickness,
72
+ ...style,
73
+ }
74
+ }
63
75
  >
64
76
  {children}
65
77
  {__thumb}
@@ -1,14 +1,7 @@
1
- import { createContext, useState, useContext, ReactNode } from 'react'
1
+ import { createContext, useContext, useEffect, useRef } from 'react'
2
+ import { createStore, useStore } from 'zustand'
2
3
 
3
- const minContext = createContext(0)
4
- const maxContext = createContext(0)
5
- const stepContext = createContext(0)
6
- const skewContext = createContext(0)
7
- const verticalContext = createContext(false)
8
- const reverseContext = createContext(false)
9
- const disabledContext = createContext(false)
10
-
11
- interface Props {
4
+ type State = {
12
5
  min: number
13
6
  max: number
14
7
  step: number
@@ -16,51 +9,72 @@ interface Props {
16
9
  vertical: boolean
17
10
  reverse: boolean
18
11
  disabled: boolean
19
- children: ReactNode
20
12
  }
21
13
 
22
- export function SliderValuesProvider({
23
- min: _min,
24
- max: _max,
25
- step: _step,
26
- skew: _skew,
27
- vertical: _vertical,
28
- reverse: _reverse,
29
- disabled: _disabled,
30
- children,
31
- }: Props) {
32
- const [min] = useState(_min)
33
- const [max] = useState(_max)
34
- const [step] = useState(_step)
35
- const [skew] = useState(_skew)
36
- const [vertical] = useState(_vertical)
37
- const [reverse] = useState(_reverse)
38
- const [disabled] = useState(_disabled)
14
+ type Action = {
15
+ updateMin: (min: State['min']) => void
16
+ updateMax: (max: State['max']) => void
17
+ updateStep: (step: State['step']) => void
18
+ updateSkew: (skew: State['skew']) => void
19
+ updateVertical: (vertical: State['vertical']) => void
20
+ updateReverse: (reverse: State['reverse']) => void
21
+ updateDisabled: (disabled: State['disabled']) => void
22
+ }
23
+
24
+ type SliderStore = ReturnType<typeof createSliderStore>
25
+
26
+ const createSliderStore = (initProps?: Partial<State>) => {
27
+ const DEFAULT_PROPS: State = {
28
+ min: 0,
29
+ max: 0,
30
+ step: 0,
31
+ skew: 0,
32
+ vertical: false,
33
+ reverse: false,
34
+ disabled: false,
35
+ }
36
+
37
+ return createStore<State & Action>()((set) => ({
38
+ ...DEFAULT_PROPS,
39
+ ...initProps,
40
+ updateMin: (min) => set(() => ({ min: min })),
41
+ updateMax: (max) => set(() => ({ max: max })),
42
+ updateStep: (step) => set(() => ({ step: step })),
43
+ updateSkew: (skew) => set(() => ({ skew: skew })),
44
+ updateVertical: (vertical) => set(() => ({ vertical: vertical })),
45
+ updateReverse: (reverse) => set(() => ({ reverse: reverse })),
46
+ updateDisabled: (disabled) => set(() => ({ disabled: disabled })),
47
+ }))
48
+ }
49
+
50
+ const SliderContext = createContext<SliderStore | null>(null)
51
+
52
+ type SliderProviderProps = React.PropsWithChildren<Partial<State>>
53
+
54
+ export function SliderProvider({ children, ...props }: SliderProviderProps) {
55
+ const storeRef = useRef<SliderStore>()
56
+ if (!storeRef.current) {
57
+ storeRef.current = createSliderStore(props)
58
+ }
59
+
60
+ useEffect(() => {
61
+ if (storeRef.current) {
62
+ storeRef.current.setState(props)
63
+ } else {
64
+ storeRef.current = createSliderStore(props)
65
+ }
66
+ }, [props])
39
67
 
40
68
  return (
41
- <minContext.Provider value={min}>
42
- <maxContext.Provider value={max}>
43
- <stepContext.Provider value={step}>
44
- <skewContext.Provider value={skew}>
45
- <verticalContext.Provider value={vertical}>
46
- <reverseContext.Provider value={reverse}>
47
- <disabledContext.Provider value={disabled}>
48
- {children}
49
- </disabledContext.Provider>
50
- </reverseContext.Provider>
51
- </verticalContext.Provider>
52
- </skewContext.Provider>
53
- </stepContext.Provider>
54
- </maxContext.Provider>
55
- </minContext.Provider>
69
+ <SliderContext.Provider value={storeRef.current}>
70
+ {children}
71
+ </SliderContext.Provider>
56
72
  )
57
73
  }
58
74
 
59
- export const useMin = () => useContext(minContext)
60
- export const useMax = () => useContext(maxContext)
61
- export const useStep = () => useContext(stepContext)
62
- export const useSkew = () => useContext(skewContext)
63
- export const useVertical = () => useContext(verticalContext)
64
- // export const useSetVertical = () => useContext(setVerticalContext)
65
- export const useReverse = () => useContext(reverseContext)
66
- export const useDisabled = () => useContext(disabledContext)
75
+ /** @category Slider */
76
+ export function useSliderContext<T>(selector: (state: State & Action) => T): T {
77
+ const store = useContext(SliderContext)
78
+ if (!store) throw new Error('Missing SliderContext.Provider in the tree')
79
+ return useStore(store, selector)
80
+ }
@@ -35,6 +35,14 @@
35
35
 
36
36
  position: relative;
37
37
 
38
+ &[data-vertical='false'] {
39
+ min-width: 50px;
40
+ }
41
+
42
+ &[data-vertical='true'] {
43
+ min-height: 50px;
44
+ }
45
+
38
46
  &:hover {
39
47
  --active: #6387e9;
40
48
  --inactive: #e0e0e0;