@tremolo-ui/react 0.0.3 → 0.0.4
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/cjs/index.js +113 -119
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AnimationCanvas/canvas.d.ts.map +1 -0
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts +20 -0
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -0
- package/dist/{esm/types/packages/react/src → cjs/types}/components/Knob/index.d.ts +16 -4
- package/dist/cjs/types/components/Knob/index.d.ts.map +1 -0
- package/dist/cjs/types/{packages/react/src/components → components}/NumberInput/index.d.ts +3 -5
- package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -0
- package/dist/{esm/types/packages/react/src → cjs/types}/components/Slider/Thumb.d.ts +2 -2
- package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -0
- package/dist/cjs/types/{packages/react/src/components → components}/Slider/Track.d.ts +1 -1
- package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -0
- package/dist/cjs/types/{packages/react/src/components → components}/Slider/index.d.ts +5 -5
- package/dist/cjs/types/components/Slider/index.d.ts.map +1 -0
- package/dist/cjs/types/components/Slider/type.d.ts +7 -0
- package/dist/cjs/types/components/Slider/type.d.ts.map +1 -0
- package/dist/cjs/types/hooks/useCallbackRef.d.ts.map +1 -0
- package/dist/cjs/types/hooks/useEventListener.d.ts.map +1 -0
- package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts.map +1 -0
- package/dist/cjs/types/index.d.ts +5 -0
- package/dist/cjs/types/index.d.ts.map +1 -0
- package/dist/cjs/types/system/pseudo.d.ts.map +1 -0
- package/dist/esm/index.js +111 -109
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AnimationCanvas/canvas.d.ts.map +1 -0
- package/dist/esm/types/components/AnimationCanvas/index.d.ts +20 -0
- package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -0
- package/dist/{cjs/types/packages/react/src → esm/types}/components/Knob/index.d.ts +16 -4
- package/dist/esm/types/components/Knob/index.d.ts.map +1 -0
- package/dist/esm/types/{packages/react/src/components → components}/NumberInput/index.d.ts +3 -5
- package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -0
- package/dist/{cjs/types/packages/react/src → esm/types}/components/Slider/Thumb.d.ts +2 -2
- package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -0
- package/dist/esm/types/{packages/react/src/components → components}/Slider/Track.d.ts +1 -1
- package/dist/esm/types/components/Slider/Track.d.ts.map +1 -0
- package/dist/esm/types/{packages/react/src/components → components}/Slider/index.d.ts +5 -5
- package/dist/esm/types/components/Slider/index.d.ts.map +1 -0
- package/dist/esm/types/components/Slider/type.d.ts +7 -0
- package/dist/esm/types/components/Slider/type.d.ts.map +1 -0
- package/dist/esm/types/hooks/useCallbackRef.d.ts.map +1 -0
- package/dist/esm/types/hooks/useEventListener.d.ts.map +1 -0
- package/dist/esm/types/hooks/useRefCallbackEvent.d.ts.map +1 -0
- package/dist/esm/types/index.d.ts +5 -0
- package/dist/esm/types/index.d.ts.map +1 -0
- package/dist/esm/types/system/pseudo.d.ts.map +1 -0
- package/dist/styles/variables.css +4 -0
- package/package.json +19 -4
- package/src/Globals.d.ts +2 -0
- package/src/components/AnimationCanvas/canvas.ts +30 -0
- package/src/components/AnimationCanvas/index.tsx +169 -0
- package/src/components/Knob/index.tsx +292 -0
- package/src/components/NumberInput/index.tsx +165 -0
- package/src/components/Slider/Thumb.tsx +54 -0
- package/src/components/Slider/Track.tsx +20 -0
- package/src/components/Slider/index.tsx +326 -0
- package/src/components/Slider/type.ts +16 -0
- package/src/hooks/useCallbackRef.ts +20 -0
- package/src/hooks/useEventListener.ts +49 -0
- package/src/hooks/useRefCallbackEvent.ts +32 -0
- package/src/index.ts +4 -0
- package/src/styles/variables.css +4 -0
- package/src/system/pseudo.ts +55 -0
- package/dist/cjs/index.d.ts +0 -140
- package/dist/cjs/packages/react/tsconfig.tsbuildinfo +0 -1
- package/dist/cjs/types/packages/functions/components/NumberInput/type.d.ts +0 -14
- package/dist/cjs/types/packages/functions/components/NumberInput/type.d.ts.map +0 -1
- package/dist/cjs/types/packages/functions/components/Slider/type.d.ts +0 -32
- package/dist/cjs/types/packages/functions/components/Slider/type.d.ts.map +0 -1
- package/dist/cjs/types/packages/functions/math.d.ts +0 -12
- package/dist/cjs/types/packages/functions/math.d.ts.map +0 -1
- package/dist/cjs/types/packages/functions/types.d.ts +0 -2
- package/dist/cjs/types/packages/functions/types.d.ts.map +0 -1
- package/dist/cjs/types/packages/functions/util.d.ts +0 -6
- package/dist/cjs/types/packages/functions/util.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/AnimationCanvas/canvas.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/AnimationCanvas/index.d.ts +0 -20
- package/dist/cjs/types/packages/react/src/components/AnimationCanvas/index.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/Knob/index.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/NumberInput/index.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/Slider/Thumb.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/Slider/Track.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/Slider/index.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/components/Slider/type.d.ts +0 -6
- package/dist/cjs/types/packages/react/src/components/Slider/type.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/hooks/useCallbackRef.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/hooks/useEventListener.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/hooks/useRefCallbackEvent.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/index.d.ts +0 -7
- package/dist/cjs/types/packages/react/src/index.d.ts.map +0 -1
- package/dist/cjs/types/packages/react/src/system/pseudo.d.ts.map +0 -1
- package/dist/esm/index.d.ts +0 -140
- package/dist/esm/packages/react/tsconfig.tsbuildinfo +0 -1
- package/dist/esm/types/packages/functions/components/NumberInput/type.d.ts +0 -14
- package/dist/esm/types/packages/functions/components/NumberInput/type.d.ts.map +0 -1
- package/dist/esm/types/packages/functions/components/Slider/type.d.ts +0 -32
- package/dist/esm/types/packages/functions/components/Slider/type.d.ts.map +0 -1
- package/dist/esm/types/packages/functions/math.d.ts +0 -12
- package/dist/esm/types/packages/functions/math.d.ts.map +0 -1
- package/dist/esm/types/packages/functions/types.d.ts +0 -2
- package/dist/esm/types/packages/functions/types.d.ts.map +0 -1
- package/dist/esm/types/packages/functions/util.d.ts +0 -6
- package/dist/esm/types/packages/functions/util.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/AnimationCanvas/canvas.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/AnimationCanvas/index.d.ts +0 -20
- package/dist/esm/types/packages/react/src/components/AnimationCanvas/index.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/Knob/index.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/NumberInput/index.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/Slider/Thumb.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/Slider/Track.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/Slider/index.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/components/Slider/type.d.ts +0 -6
- package/dist/esm/types/packages/react/src/components/Slider/type.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/hooks/useCallbackRef.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/hooks/useEventListener.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/hooks/useRefCallbackEvent.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/index.d.ts +0 -7
- package/dist/esm/types/packages/react/src/index.d.ts.map +0 -1
- package/dist/esm/types/packages/react/src/system/pseudo.d.ts.map +0 -1
- /package/dist/cjs/types/{packages/react/src/components → components}/AnimationCanvas/canvas.d.ts +0 -0
- /package/dist/cjs/types/{packages/react/src/hooks → hooks}/useCallbackRef.d.ts +0 -0
- /package/dist/cjs/types/{packages/react/src/hooks → hooks}/useEventListener.d.ts +0 -0
- /package/dist/cjs/types/{packages/react/src/hooks → hooks}/useRefCallbackEvent.d.ts +0 -0
- /package/dist/cjs/types/{packages/react/src/system → system}/pseudo.d.ts +0 -0
- /package/dist/esm/types/{packages/react/src/components → components}/AnimationCanvas/canvas.d.ts +0 -0
- /package/dist/esm/types/{packages/react/src/hooks → hooks}/useCallbackRef.d.ts +0 -0
- /package/dist/esm/types/{packages/react/src/hooks → hooks}/useEventListener.d.ts +0 -0
- /package/dist/esm/types/{packages/react/src/hooks → hooks}/useRefCallbackEvent.d.ts +0 -0
- /package/dist/esm/types/{packages/react/src/system → system}/pseudo.d.ts +0 -0
|
@@ -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,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
|
+
}>
|
package/dist/cjs/index.d.ts
DELETED
|
@@ -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 };
|