@tremolo-ui/react 0.0.3 → 0.0.5

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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/index.js +113 -119
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/components/AnimationCanvas/canvas.d.ts.map +1 -0
  5. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +20 -0
  6. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -0
  7. package/dist/{esm/types/packages/react/src → cjs/types}/components/Knob/index.d.ts +16 -4
  8. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -0
  9. package/dist/cjs/types/{packages/react/src/components → components}/NumberInput/index.d.ts +3 -5
  10. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -0
  11. package/dist/{esm/types/packages/react/src → cjs/types}/components/Slider/Thumb.d.ts +2 -2
  12. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -0
  13. package/dist/cjs/types/{packages/react/src/components → components}/Slider/Track.d.ts +1 -1
  14. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -0
  15. package/dist/cjs/types/{packages/react/src/components → components}/Slider/index.d.ts +5 -5
  16. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -0
  17. package/dist/cjs/types/components/Slider/type.d.ts +7 -0
  18. package/dist/cjs/types/components/Slider/type.d.ts.map +1 -0
  19. package/dist/cjs/types/hooks/useCallbackRef.d.ts.map +1 -0
  20. package/dist/cjs/types/hooks/useEventListener.d.ts.map +1 -0
  21. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts.map +1 -0
  22. package/dist/cjs/types/index.d.ts +5 -0
  23. package/dist/cjs/types/index.d.ts.map +1 -0
  24. package/dist/cjs/types/system/pseudo.d.ts.map +1 -0
  25. package/dist/esm/index.js +111 -109
  26. package/dist/esm/index.js.map +1 -1
  27. package/dist/esm/types/components/AnimationCanvas/canvas.d.ts.map +1 -0
  28. package/dist/esm/types/components/AnimationCanvas/index.d.ts +20 -0
  29. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -0
  30. package/dist/{cjs/types/packages/react/src → esm/types}/components/Knob/index.d.ts +16 -4
  31. package/dist/esm/types/components/Knob/index.d.ts.map +1 -0
  32. package/dist/esm/types/{packages/react/src/components → components}/NumberInput/index.d.ts +3 -5
  33. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -0
  34. package/dist/{cjs/types/packages/react/src → esm/types}/components/Slider/Thumb.d.ts +2 -2
  35. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -0
  36. package/dist/esm/types/{packages/react/src/components → components}/Slider/Track.d.ts +1 -1
  37. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -0
  38. package/dist/esm/types/{packages/react/src/components → components}/Slider/index.d.ts +5 -5
  39. package/dist/esm/types/components/Slider/index.d.ts.map +1 -0
  40. package/dist/esm/types/components/Slider/type.d.ts +7 -0
  41. package/dist/esm/types/components/Slider/type.d.ts.map +1 -0
  42. package/dist/esm/types/hooks/useCallbackRef.d.ts.map +1 -0
  43. package/dist/esm/types/hooks/useEventListener.d.ts.map +1 -0
  44. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts.map +1 -0
  45. package/dist/esm/types/index.d.ts +5 -0
  46. package/dist/esm/types/index.d.ts.map +1 -0
  47. package/dist/esm/types/system/pseudo.d.ts.map +1 -0
  48. package/dist/styles/variables.css +4 -0
  49. package/package.json +22 -11
  50. package/src/Globals.d.ts +2 -0
  51. package/src/components/AnimationCanvas/canvas.ts +30 -0
  52. package/src/components/AnimationCanvas/index.tsx +169 -0
  53. package/src/components/Knob/index.tsx +292 -0
  54. package/src/components/NumberInput/index.tsx +165 -0
  55. package/src/components/Slider/Thumb.tsx +54 -0
  56. package/src/components/Slider/Track.tsx +20 -0
  57. package/src/components/Slider/index.tsx +326 -0
  58. package/src/components/Slider/type.ts +16 -0
  59. package/src/hooks/useCallbackRef.ts +20 -0
  60. package/src/hooks/useEventListener.ts +49 -0
  61. package/src/hooks/useRefCallbackEvent.ts +32 -0
  62. package/src/index.ts +4 -0
  63. package/src/styles/variables.css +4 -0
  64. package/src/system/pseudo.ts +55 -0
  65. package/dist/cjs/index.d.ts +0 -140
  66. package/dist/cjs/packages/react/tsconfig.tsbuildinfo +0 -1
  67. package/dist/cjs/types/packages/functions/components/NumberInput/type.d.ts +0 -14
  68. package/dist/cjs/types/packages/functions/components/NumberInput/type.d.ts.map +0 -1
  69. package/dist/cjs/types/packages/functions/components/Slider/type.d.ts +0 -32
  70. package/dist/cjs/types/packages/functions/components/Slider/type.d.ts.map +0 -1
  71. package/dist/cjs/types/packages/functions/math.d.ts +0 -12
  72. package/dist/cjs/types/packages/functions/math.d.ts.map +0 -1
  73. package/dist/cjs/types/packages/functions/types.d.ts +0 -2
  74. package/dist/cjs/types/packages/functions/types.d.ts.map +0 -1
  75. package/dist/cjs/types/packages/functions/util.d.ts +0 -6
  76. package/dist/cjs/types/packages/functions/util.d.ts.map +0 -1
  77. package/dist/cjs/types/packages/react/src/components/AnimationCanvas/canvas.d.ts.map +0 -1
  78. package/dist/cjs/types/packages/react/src/components/AnimationCanvas/index.d.ts +0 -20
  79. package/dist/cjs/types/packages/react/src/components/AnimationCanvas/index.d.ts.map +0 -1
  80. package/dist/cjs/types/packages/react/src/components/Knob/index.d.ts.map +0 -1
  81. package/dist/cjs/types/packages/react/src/components/NumberInput/index.d.ts.map +0 -1
  82. package/dist/cjs/types/packages/react/src/components/Slider/Thumb.d.ts.map +0 -1
  83. package/dist/cjs/types/packages/react/src/components/Slider/Track.d.ts.map +0 -1
  84. package/dist/cjs/types/packages/react/src/components/Slider/index.d.ts.map +0 -1
  85. package/dist/cjs/types/packages/react/src/components/Slider/type.d.ts +0 -6
  86. package/dist/cjs/types/packages/react/src/components/Slider/type.d.ts.map +0 -1
  87. package/dist/cjs/types/packages/react/src/hooks/useCallbackRef.d.ts.map +0 -1
  88. package/dist/cjs/types/packages/react/src/hooks/useEventListener.d.ts.map +0 -1
  89. package/dist/cjs/types/packages/react/src/hooks/useRefCallbackEvent.d.ts.map +0 -1
  90. package/dist/cjs/types/packages/react/src/index.d.ts +0 -7
  91. package/dist/cjs/types/packages/react/src/index.d.ts.map +0 -1
  92. package/dist/cjs/types/packages/react/src/system/pseudo.d.ts.map +0 -1
  93. package/dist/esm/index.d.ts +0 -140
  94. package/dist/esm/packages/react/tsconfig.tsbuildinfo +0 -1
  95. package/dist/esm/types/packages/functions/components/NumberInput/type.d.ts +0 -14
  96. package/dist/esm/types/packages/functions/components/NumberInput/type.d.ts.map +0 -1
  97. package/dist/esm/types/packages/functions/components/Slider/type.d.ts +0 -32
  98. package/dist/esm/types/packages/functions/components/Slider/type.d.ts.map +0 -1
  99. package/dist/esm/types/packages/functions/math.d.ts +0 -12
  100. package/dist/esm/types/packages/functions/math.d.ts.map +0 -1
  101. package/dist/esm/types/packages/functions/types.d.ts +0 -2
  102. package/dist/esm/types/packages/functions/types.d.ts.map +0 -1
  103. package/dist/esm/types/packages/functions/util.d.ts +0 -6
  104. package/dist/esm/types/packages/functions/util.d.ts.map +0 -1
  105. package/dist/esm/types/packages/react/src/components/AnimationCanvas/canvas.d.ts.map +0 -1
  106. package/dist/esm/types/packages/react/src/components/AnimationCanvas/index.d.ts +0 -20
  107. package/dist/esm/types/packages/react/src/components/AnimationCanvas/index.d.ts.map +0 -1
  108. package/dist/esm/types/packages/react/src/components/Knob/index.d.ts.map +0 -1
  109. package/dist/esm/types/packages/react/src/components/NumberInput/index.d.ts.map +0 -1
  110. package/dist/esm/types/packages/react/src/components/Slider/Thumb.d.ts.map +0 -1
  111. package/dist/esm/types/packages/react/src/components/Slider/Track.d.ts.map +0 -1
  112. package/dist/esm/types/packages/react/src/components/Slider/index.d.ts.map +0 -1
  113. package/dist/esm/types/packages/react/src/components/Slider/type.d.ts +0 -6
  114. package/dist/esm/types/packages/react/src/components/Slider/type.d.ts.map +0 -1
  115. package/dist/esm/types/packages/react/src/hooks/useCallbackRef.d.ts.map +0 -1
  116. package/dist/esm/types/packages/react/src/hooks/useEventListener.d.ts.map +0 -1
  117. package/dist/esm/types/packages/react/src/hooks/useRefCallbackEvent.d.ts.map +0 -1
  118. package/dist/esm/types/packages/react/src/index.d.ts +0 -7
  119. package/dist/esm/types/packages/react/src/index.d.ts.map +0 -1
  120. package/dist/esm/types/packages/react/src/system/pseudo.d.ts.map +0 -1
  121. /package/dist/cjs/types/{packages/react/src/components → components}/AnimationCanvas/canvas.d.ts +0 -0
  122. /package/dist/cjs/types/{packages/react/src/hooks → hooks}/useCallbackRef.d.ts +0 -0
  123. /package/dist/cjs/types/{packages/react/src/hooks → hooks}/useEventListener.d.ts +0 -0
  124. /package/dist/cjs/types/{packages/react/src/hooks → hooks}/useRefCallbackEvent.d.ts +0 -0
  125. /package/dist/cjs/types/{packages/react/src/system → system}/pseudo.d.ts +0 -0
  126. /package/dist/esm/types/{packages/react/src/components → components}/AnimationCanvas/canvas.d.ts +0 -0
  127. /package/dist/esm/types/{packages/react/src/hooks → hooks}/useCallbackRef.d.ts +0 -0
  128. /package/dist/esm/types/{packages/react/src/hooks → hooks}/useEventListener.d.ts +0 -0
  129. /package/dist/esm/types/{packages/react/src/hooks → hooks}/useRefCallbackEvent.d.ts +0 -0
  130. /package/dist/esm/types/{packages/react/src/system → system}/pseudo.d.ts +0 -0
@@ -0,0 +1,20 @@
1
+ import { css, CSSObject } from '@emotion/react'
2
+ import { ReactElement } from 'react'
3
+
4
+ interface SliderTrackProps {
5
+ style?: CSSObject
6
+ children?: ReactElement
7
+ __css?: CSSObject
8
+ }
9
+
10
+ export function SliderTrack({
11
+ children,
12
+ style,
13
+ __css,
14
+ }: SliderTrackProps) {
15
+ return (
16
+ <div className="tremolo-slider-track" css={css({ ...__css, ...style })}>
17
+ {children}
18
+ </div>
19
+ )
20
+ }
@@ -0,0 +1,326 @@
1
+ import { css, CSSObject, Global } from '@emotion/react'
2
+ import {
3
+ Direction,
4
+ gradientDirection,
5
+ isHorizontal,
6
+ isReversed,
7
+ isVertical,
8
+ parseScaleOrderList,
9
+ ScaleOrderList,
10
+ ScaleType,
11
+ } from '@tremolo-ui/functions/Slider'
12
+ import { clamp, normalizeValue, rawValue, stepValue } from '@tremolo-ui/functions'
13
+ import { WheelOption } from '@tremolo-ui/functions'
14
+ import { styleHelper } from '@tremolo-ui/functions'
15
+ import React, { ReactElement, useRef } from 'react'
16
+ import clsx from 'clsx'
17
+
18
+ import { useEventListener } from '../../hooks/useEventListener'
19
+ import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
20
+ import { UserActionPseudoProps } from '../../system/pseudo'
21
+
22
+ import { SliderThumb } from './Thumb'
23
+ import { SliderTrack } from './Track'
24
+ import { ScaleOption } from './type'
25
+
26
+ interface SliderProps {
27
+ // required
28
+ value: number
29
+ min: number
30
+ max: number
31
+
32
+ // optional
33
+ step?: number
34
+ skew?: number // | SkewFunction
35
+ length?: number | string
36
+ thickness?: number | string
37
+ direction?: Direction
38
+ scale?: ['step', ScaleType] | [number, ScaleType] | ScaleOrderList[]
39
+ scaleOption?: ScaleOption
40
+ color?: string
41
+ bg?: string
42
+ bodyNoSelect?: boolean
43
+ enableWheel?: WheelOption
44
+ className?: string
45
+ style?: CSSObject
46
+ onChange?: (value: number) => void
47
+ children?: ReactElement | ReactElement[]
48
+ // ReactElement<typeof SliderThumb, typeof SliderTrack>[]
49
+ }
50
+
51
+ /**
52
+ * Customizable slider
53
+ */
54
+ export function Slider({
55
+ value,
56
+ min,
57
+ max,
58
+ step = 1,
59
+ skew = 1,
60
+ length = 140,
61
+ thickness = 10,
62
+ direction = 'right',
63
+ scale,
64
+ scaleOption,
65
+ color = '#4e76e6',
66
+ bg = '#eee',
67
+ className,
68
+ style,
69
+ bodyNoSelect = true,
70
+ enableWheel,
71
+ onChange,
72
+ children,
73
+ ...pseudo
74
+ }: SliderProps & UserActionPseudoProps) {
75
+ // -- state and ref ---
76
+ const trackElementRef = useRef<HTMLDivElement>(null)
77
+
78
+ // --- interpret props ---
79
+ const { _active, _focus, _hover } = pseudo
80
+ const percent = normalizeValue(value, min, max, skew) * 100
81
+ const percentRev = isReversed(direction) ? 100 - percent : percent
82
+
83
+ const scalesList = parseScaleOrderList(scale, min, max, step)
84
+ if (isReversed(direction)) scalesList.reverse()
85
+
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ let trackProps: any
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ let thumbProps: any
90
+ if (children != undefined) {
91
+ React.Children.forEach(children, (child) => {
92
+ if (React.isValidElement(child)) {
93
+ if (child.type == SliderThumb) {
94
+ thumbProps = child.props
95
+ } else if (child.type == SliderTrack) {
96
+ trackProps = child.props
97
+ } else {
98
+ throw new Error('only <SliderThumb> or <SliderTrack>')
99
+ }
100
+ } else {
101
+ throw new Error('children is an invalid element.')
102
+ }
103
+ })
104
+ }
105
+
106
+ const thumbDragged = useRef(false)
107
+ const handleValue = (
108
+ event: MouseEvent | React.PointerEvent<HTMLDivElement> | TouchEvent,
109
+ ) => {
110
+ if (!trackElementRef.current || !thumbDragged.current) return
111
+ const isTouch = event instanceof TouchEvent
112
+ if (isTouch && event.cancelable) event.preventDefault()
113
+ if (bodyNoSelect) document.body.classList.add('no-select')
114
+ const {
115
+ left: x1,
116
+ top: y1,
117
+ right: x2,
118
+ bottom: y2,
119
+ } = trackElementRef.current.getBoundingClientRect()
120
+ const mouseX = isTouch ? event.touches[0].clientX : event.clientX
121
+ const mouseY = isTouch ? event.touches[0].clientY : event.clientY
122
+ const n = isHorizontal(direction)
123
+ ? normalizeValue(mouseX, x1, x2)
124
+ : normalizeValue(mouseY, y1, y2)
125
+ const v = rawValue(isReversed(direction) ? 1 - n : n, min, max, skew)
126
+ const v2 = clamp(stepValue(v, step), min, max)
127
+ if (onChange) onChange(v2)
128
+ }
129
+
130
+ // --- hooks ---
131
+ const touchMoveRefCallback = useRefCallbackEvent(
132
+ 'touchmove',
133
+ handleValue,
134
+ { passive: false },
135
+ [min, max, skew, step, direction, onChange],
136
+ )
137
+
138
+ const wheelRefCallback = useRefCallbackEvent(
139
+ 'wheel',
140
+ (event) => {
141
+ if (!enableWheel) return
142
+ event.preventDefault()
143
+ let x = event.deltaY > 0 ? enableWheel[1] : -enableWheel[1]
144
+ if (isReversed(direction) || isHorizontal(direction)) x *= -1
145
+ let v
146
+ if (enableWheel[0] == 'normalized') {
147
+ const n = normalizeValue(value, min, max, skew)
148
+ v = rawValue(n + x, min, max, skew)
149
+ } else {
150
+ v = value + x
151
+ }
152
+ if (onChange) onChange(clamp(stepValue(v, step), min, max))
153
+ },
154
+ {
155
+ passive: false,
156
+ },
157
+ [enableWheel, value, min, max, skew, step],
158
+ )
159
+
160
+ useEventListener(window, 'mousemove', (event) => {
161
+ handleValue(event)
162
+ })
163
+
164
+ useEventListener(window, 'mouseup', () => {
165
+ thumbDragged.current = false
166
+ if (bodyNoSelect) document.body.classList.remove('no-select')
167
+ })
168
+
169
+ return (
170
+ <div
171
+ className={clsx('tremolo-slider', className)}
172
+ ref={(div) => {
173
+ wheelRefCallback(div)
174
+ touchMoveRefCallback(div)
175
+ }}
176
+ tabIndex={-1}
177
+ role="slider"
178
+ aria-valuenow={value}
179
+ aria-valuemax={max}
180
+ aria-valuemin={min}
181
+ aria-orientation={isHorizontal(direction) ? 'horizontal' : 'vertical'}
182
+ css={css({
183
+ display: 'inline-block',
184
+ boxSizing: 'border-box',
185
+ margin: '0.7rem',
186
+ padding: 0,
187
+ cursor: 'pointer',
188
+ ...style,
189
+ })}
190
+ onPointerDown={(event) => {
191
+ thumbDragged.current = true
192
+ handleValue(event)
193
+ }}
194
+ >
195
+ <Global
196
+ styles={{
197
+ '.no-select': {
198
+ userSelect: 'none',
199
+ },
200
+ }}
201
+ />
202
+ <div
203
+ css={css({
204
+ display: 'flex',
205
+ flexDirection: isHorizontal(direction) ? 'column' : 'row',
206
+ })}
207
+ >
208
+ {/* trackProps */}
209
+ <div
210
+ className="tremolo-slider-track-wrapper"
211
+ ref={trackElementRef}
212
+ css={css({ position: 'relative' })}
213
+ >
214
+ <SliderTrack
215
+ __css={{
216
+ background: `linear-gradient(to ${gradientDirection(direction)}, ${color} ${percent}%, ${bg} ${percent}%)`,
217
+ borderRadius: styleHelper(thickness, '/', 2),
218
+ borderStyle: 'solid',
219
+ borderColor: '#ccc',
220
+ borderWidth: 2,
221
+ width: isHorizontal(direction) ? length : thickness,
222
+ height: isHorizontal(direction) ? thickness : length,
223
+ zIndex: 1,
224
+ }}
225
+ {...trackProps}
226
+ />
227
+ <SliderThumb
228
+ color={color}
229
+ __css={{
230
+ top: isHorizontal(direction) ? '50%' : `${percentRev}%`,
231
+ left: isHorizontal(direction) ? `${percentRev}%` : '50%',
232
+ }}
233
+ {...thumbProps}
234
+ />
235
+ </div>
236
+ {scale && (
237
+ <div
238
+ className="tremolo-slider-scale-wrapper"
239
+ css={css({
240
+ position: 'relative',
241
+ width: isHorizontal(direction) ? length : undefined,
242
+ height: isVertical(direction) ? length : undefined,
243
+ marginLeft: isHorizontal(direction)
244
+ ? 2
245
+ : (scaleOption?.gap ??
246
+ `calc((1.4rem - ${styleHelper(thickness)}) / 2)`),
247
+ marginTop: isVertical(direction)
248
+ ? 2
249
+ : (scaleOption?.gap ??
250
+ `calc((1.4rem - ${styleHelper(thickness)}) / 2)`),
251
+ ...scaleOption?.style,
252
+ // zIndex: 10,
253
+ })}
254
+ >
255
+ {scalesList.map((item, index) => (
256
+ <div
257
+ key={index}
258
+ css={css({
259
+ display: 'flex',
260
+ flexDirection: isHorizontal(direction) ? 'column' : 'row',
261
+ justifyContent: 'center',
262
+ alignItems: 'center',
263
+ position: 'absolute',
264
+ left: isHorizontal(direction)
265
+ ? `${
266
+ isReversed(direction)
267
+ ? 100 - normalizeValue(item.at, min, max, skew) * 100
268
+ : normalizeValue(item.at, min, max, skew) * 100
269
+ }%`
270
+ : undefined,
271
+ top: isVertical(direction)
272
+ ? `${
273
+ isReversed(direction)
274
+ ? 100 - normalizeValue(item.at, min, max, skew) * 100
275
+ : normalizeValue(item.at, min, max, skew) * 100
276
+ }%`
277
+ : undefined,
278
+ translate: isHorizontal(direction) ? '-50% 0' : '0 -50%',
279
+ zIndex: 10,
280
+ })}
281
+ >
282
+ {(item.type ?? scaleOption?.defaultType ?? 'mark-number') !=
283
+ 'number' && (
284
+ <div
285
+ className="tremolo-slider-scale-mark"
286
+ css={css({
287
+ width: isHorizontal(direction)
288
+ ? (item.style?.thickness ?? 1)
289
+ : (item.style?.length ?? '0.5rem'),
290
+ height: isVertical(direction)
291
+ ? (item.style?.thickness ?? 1)
292
+ : (item.style?.length ?? '0.5rem'),
293
+ backgroundColor:
294
+ item.style?.markColor ??
295
+ scaleOption?.markColor ??
296
+ '#222',
297
+ marginBottom: isHorizontal(direction) ? 2 : undefined,
298
+ marginRight: isVertical(direction) ? 2 : undefined,
299
+ })}
300
+ ></div>
301
+ )}
302
+ {(item.type ?? scaleOption?.defaultType ?? 'mark-number') !=
303
+ 'mark' && (
304
+ <div
305
+ className="tremolo-slider-scale-number"
306
+ css={css({
307
+ color: item.style?.labelColor ?? scaleOption?.labelColor,
308
+ width: scaleOption?.labelWidth,
309
+ textAlign: 'right',
310
+ })}
311
+ >
312
+ {item.text ?? item.at}
313
+ </div>
314
+ )}
315
+ </div>
316
+ ))}
317
+ </div>
318
+ )}
319
+ </div>
320
+ </div>
321
+ )
322
+ }
323
+
324
+ export * from './Thumb'
325
+ export * from './Track'
326
+ export * from './type'
@@ -0,0 +1,16 @@
1
+ import { CSSObject } from '@emotion/react'
2
+
3
+ import type { ScaleOption as Opt } from '@tremolo-ui/functions/Slider'
4
+
5
+ export type ScaleOption = Opt & {
6
+ style?: CSSObject
7
+ }
8
+
9
+ export {
10
+ type Direction,
11
+ type Horizontal,
12
+ type ScaleOrderList,
13
+ type ScaleType,
14
+ type Vertical,
15
+ gradientDirection
16
+ } from '@tremolo-ui/functions/Slider'
@@ -0,0 +1,20 @@
1
+ import { useCallback, useInsertionEffect, useRef } from 'react'
2
+
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
6
+ */
7
+ export function useCallbackRef<Args extends unknown[], Return>(
8
+ callback: ((...args: Args) => Return) | undefined,
9
+ deps: React.DependencyList = [],
10
+ ) {
11
+ const callbackRef = useRef<typeof callback>(() => {
12
+ throw new Error('Cannot call an event handler while rendering.')
13
+ })
14
+
15
+ useInsertionEffect(() => {
16
+ callbackRef.current = callback
17
+ })
18
+
19
+ return useCallback((...args: Args) => callbackRef.current?.(...args), deps)
20
+ }
@@ -0,0 +1,49 @@
1
+ import { useEffect } from 'react'
2
+
3
+ import { useCallbackRef } from './useCallbackRef'
4
+
5
+ type Target = EventTarget | null | (() => EventTarget | null)
6
+ type Options = boolean | AddEventListenerOptions
7
+
8
+ export function useEventListener<K extends keyof DocumentEventMap>(
9
+ target: Target,
10
+ event: K,
11
+ handler?: (event: DocumentEventMap[K]) => void,
12
+ options?: Options,
13
+ ): VoidFunction
14
+ export function useEventListener<K extends keyof WindowEventMap>(
15
+ target: Target,
16
+ event: K,
17
+ handler?: (event: WindowEventMap[K]) => void,
18
+ options?: Options,
19
+ ): VoidFunction
20
+ export function useEventListener<K extends keyof GlobalEventHandlersEventMap>(
21
+ target: Target,
22
+ event: K,
23
+ handler?: (event: GlobalEventHandlersEventMap[K]) => void,
24
+ options?: Options,
25
+ ): VoidFunction
26
+ export function useEventListener(
27
+ target: Target,
28
+ event: string,
29
+ handler: ((event: Event) => void) | undefined,
30
+ options?: Options,
31
+ ) {
32
+ const listener = useCallbackRef(handler)
33
+
34
+ useEffect(() => {
35
+ const node = typeof target === 'function' ? target() : (target ?? document)
36
+
37
+ if (!handler || !node) return
38
+
39
+ node.addEventListener(event, listener, options)
40
+ return () => {
41
+ node.removeEventListener(event, listener, options)
42
+ }
43
+ }, [event, target, options, listener, handler])
44
+
45
+ return () => {
46
+ const node = typeof target === 'function' ? target() : (target ?? document)
47
+ node?.removeEventListener(event, listener, options)
48
+ }
49
+ }
@@ -0,0 +1,32 @@
1
+ import { useMemo } from 'react'
2
+
3
+ type Options = boolean | AddEventListenerOptions
4
+ type CallbackFunc = (div: EventTarget | null) => void
5
+
6
+ export function useRefCallbackEvent<K extends keyof DocumentEventMap>(
7
+ event: K,
8
+ handler: (event: DocumentEventMap[K]) => void,
9
+ options?: Options,
10
+ deps?: React.DependencyList,
11
+ ): CallbackFunc
12
+ export function useRefCallbackEvent(
13
+ event: string,
14
+ handler: (event: Event) => void,
15
+ options?: Options,
16
+ deps: React.DependencyList = [],
17
+ ): CallbackFunc {
18
+ return useMemo(() => {
19
+ let cleanup: (() => void) | undefined
20
+ return (node: EventTarget | null) => {
21
+ if (!node) {
22
+ cleanup?.()
23
+ return
24
+ }
25
+ node.addEventListener(event, handler, options)
26
+
27
+ cleanup = () => {
28
+ node.removeEventListener(event, handler, options)
29
+ }
30
+ }
31
+ }, deps)
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './components/AnimationCanvas'
2
+ export * from './components/Knob'
3
+ export * from './components/NumberInput'
4
+ export * from './components/Slider'
@@ -0,0 +1,4 @@
1
+ :root {
2
+ --tremolo-theme-color: #4e76e6;
3
+ --tremolo-theme-color-rgb: 78, 118, 230;
4
+ }
@@ -0,0 +1,55 @@
1
+ import { CSSObject } from '@emotion/react'
2
+
3
+ function _toPropName(str: string) {
4
+ return str.replace(/-\w/, (s) => s.toUpperCase()).replace(/^::?/, '_')
5
+ }
6
+
7
+ // ref. https://developer.mozilla.org/ja/docs/Web/CSS/Pseudo-classes
8
+
9
+ export const inputPseudoSelectors = [
10
+ '&:enabled',
11
+ '&:disabled',
12
+ '&:read-only',
13
+ '&:read-write',
14
+ '&:placeholder-shown',
15
+ '&:blank',
16
+ '&:valid',
17
+ '&:invalid',
18
+ '&:in-range',
19
+ '&:out-of-range',
20
+ ] as const
21
+
22
+ export const inputPseudoPropNames = [
23
+ '_enabled',
24
+ '_disabled',
25
+ '_readOnly',
26
+ '_readWrite',
27
+ '_placeholderShown',
28
+ '_blank',
29
+ '_valid',
30
+ '_invalid',
31
+ '_inRange',
32
+ '_outOfRange',
33
+ ] as const
34
+
35
+ export type InputPseudos = (typeof inputPseudoPropNames)[number]
36
+ export type InputPseudoProps = Partial<{
37
+ [key in InputPseudos]: CSSObject
38
+ }>
39
+
40
+ export const userActionPseudoSelectors = [
41
+ '&:hover',
42
+ '&:active',
43
+ '&:focus',
44
+ ] as const
45
+
46
+ export const userActionPseudoPropNames = [
47
+ '_hover',
48
+ '_active',
49
+ '_focus',
50
+ ] as const
51
+
52
+ export type UserActionPseudos = (typeof userActionPseudoPropNames)[number]
53
+ export type UserActionPseudoProps = Partial<{
54
+ [key in UserActionPseudos]: CSSObject
55
+ }>
@@ -1,140 +0,0 @@
1
- export * from '@tremolo-ui/functions/math';
2
- import { WheelOption } from '@tremolo-ui/functions/types';
3
- export * from '@tremolo-ui/functions/types';
4
- import * as _emotion_react_jsx_runtime from '@emotion/react/jsx-runtime';
5
- import { CSSObject } from '@emotion/react';
6
- import React$1, { MutableRefObject, ChangeEvent, ReactElement } from 'react';
7
- import { Units } from '@tremolo-ui/functions/components/NumberInput/type';
8
- import { ScaleOption as ScaleOption$1, Direction, ScaleType, ScaleOrderList } from '@tremolo-ui/functions/components/Slider/type';
9
-
10
- type DrawFunc = (context: CanvasRenderingContext2D, width: MutableRefObject<number>, height: MutableRefObject<number>, count: number) => void;
11
- interface AnimationCanvasProps {
12
- width?: number;
13
- height?: number;
14
- relativeSize?: boolean;
15
- /** only available relativeSize=true */
16
- reduceFlickering?: boolean;
17
- options?: CanvasRenderingContext2DSettings;
18
- style?: CSSObject;
19
- init?: DrawFunc;
20
- draw: DrawFunc;
21
- }
22
- /**
23
- * A simple animatable canvas with requestAnimationFrame()
24
- */
25
- declare function AnimationCanvas({ width, height, style, relativeSize, reduceFlickering, options, init, draw, ...props }: AnimationCanvasProps & Omit<React.ClassAttributes<HTMLCanvasElement> & React.CanvasHTMLAttributes<HTMLCanvasElement>, 'ref' | 'width' | 'height' | 'style'>): _emotion_react_jsx_runtime.JSX.Element;
26
-
27
- declare const inputPseudoPropNames: readonly ["_enabled", "_disabled", "_readOnly", "_readWrite", "_placeholderShown", "_blank", "_valid", "_invalid", "_inRange", "_outOfRange"];
28
- type InputPseudos = (typeof inputPseudoPropNames)[number];
29
- type InputPseudoProps = Partial<{
30
- [key in InputPseudos]: CSSObject;
31
- }>;
32
- declare const userActionPseudoPropNames: readonly ["_hover", "_active", "_focus"];
33
- type UserActionPseudos = (typeof userActionPseudoPropNames)[number];
34
- type UserActionPseudoProps = Partial<{
35
- [key in UserActionPseudos]: CSSObject;
36
- }>;
37
-
38
- interface KnobProps {
39
- value: number;
40
- min: number;
41
- max: number;
42
- defaultValue?: number;
43
- startValue?: number;
44
- step?: number;
45
- skew?: number;
46
- size?: number | `${number}%`;
47
- width?: number | `${number}%`;
48
- height?: number | `${number}%`;
49
- options?: {
50
- active?: string;
51
- inactive?: string;
52
- bg?: string;
53
- thumb?: string;
54
- lineWeight?: number;
55
- thumbWeight?: number;
56
- };
57
- cursor?: string;
58
- style?: CSSObject;
59
- bodyNoSelect?: boolean;
60
- enableWheel?: WheelOption;
61
- enableDoubleClickDefault?: boolean;
62
- onChange?: (value: number) => void;
63
- }
64
- /**
65
- * simple rotary Knob.
66
- */
67
- declare function Knob({ value, min, max, defaultValue, startValue, step, skew, size, width, height, options, cursor, style, bodyNoSelect, enableWheel, enableDoubleClickDefault, onChange, _active, _focus, _hover, ...props }: KnobProps & UserActionPseudoProps & Omit<React$1.ClassAttributes<HTMLDivElement> & React$1.HTMLAttributes<HTMLDivElement>, 'onChange'>): _emotion_react_jsx_runtime.JSX.Element;
68
-
69
- interface NumberInputProps {
70
- value: number | string;
71
- min?: number;
72
- max?: number;
73
- step?: number;
74
- disabled?: boolean;
75
- placeholder?: string;
76
- readOnly?: boolean;
77
- tabIndex?: number;
78
- /**
79
- * @example
80
- * units='Hz'
81
- * units={[['Hz', 1], ['kHz', 1000]]}
82
- * units={[['ms', 1], ['s', 1000]]}
83
- */
84
- units?: string | Units;
85
- /**
86
- * NOTE: If units is specified, it is forced to `false`
87
- */
88
- strict?: boolean;
89
- /**
90
- * @example
91
- * with units-{[['Hz', 1], ['kHz', 1000]]}
92
- * 3 ... 100Hz, 1.60Hz
93
- */
94
- digit?: number;
95
- selectWithFocus?: 'all' | 'number' | 'none';
96
- blurWithEnter?: boolean;
97
- className?: string;
98
- style?: CSSObject;
99
- onChange?: (value: number, event: ChangeEvent<HTMLInputElement>) => void;
100
- onFocus?: (value: number, event: React.FocusEvent<HTMLInputElement, Element>) => void;
101
- onBlur?: (value: number, event: React.FocusEvent<HTMLInputElement, Element>) => void;
102
- }
103
- /**
104
- * Input with some useful functions for entering numerical values.
105
- */
106
- declare function NumberInput({ value, min, // TODO
107
- max, // TODO
108
- step, // TODO
109
- units, disabled, placeholder, readOnly, tabIndex, strict, digit, selectWithFocus, blurWithEnter, className, style, onChange, onFocus, onBlur, ...pseudo }: NumberInputProps & UserActionPseudoProps & InputPseudoProps): _emotion_react_jsx_runtime.JSX.Element;
110
-
111
- type ScaleOption = ScaleOption$1 & {
112
- style?: CSSObject;
113
- };
114
-
115
- interface SliderProps {
116
- value: number;
117
- min: number;
118
- max: number;
119
- step?: number;
120
- skew?: number;
121
- length?: number | string;
122
- thickness?: number | string;
123
- direction?: Direction;
124
- scale?: ['step', ScaleType] | [number, ScaleType] | ScaleOrderList[];
125
- scaleOption?: ScaleOption;
126
- color?: string;
127
- bg?: string;
128
- bodyNoSelect?: boolean;
129
- enableWheel?: WheelOption;
130
- className?: string;
131
- style?: CSSObject;
132
- onChange?: (value: number) => void;
133
- children?: ReactElement | ReactElement[];
134
- }
135
- /**
136
- * Customizable slider
137
- */
138
- declare function Slider({ value, min, max, step, skew, length, thickness, direction, scale, scaleOption, color, bg, className, style, bodyNoSelect, enableWheel, onChange, children, ...pseudo }: SliderProps & UserActionPseudoProps): _emotion_react_jsx_runtime.JSX.Element;
139
-
140
- export { AnimationCanvas, Knob, NumberInput, Slider };