@tremolo-ui/react 0.0.7 → 0.0.8

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 (133) hide show
  1. package/dist/cjs/index.js +674 -253
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +16 -9
  4. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
  5. package/dist/cjs/types/components/AnimationKnob/index.d.ts +53 -0
  6. package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -0
  7. package/dist/cjs/types/components/DragObserver/index.d.ts +19 -0
  8. package/dist/cjs/types/components/DragObserver/index.d.ts.map +1 -0
  9. package/dist/cjs/types/components/Knob/index.d.ts +26 -26
  10. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  11. package/dist/cjs/types/components/NumberInput/index.d.ts +2 -5
  12. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
  13. package/dist/cjs/types/components/Piano/BlackKey.d.ts +3 -3
  14. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -1
  15. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +5 -8
  16. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -1
  17. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +3 -3
  18. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -1
  19. package/dist/cjs/types/components/Piano/index.d.ts +3 -4
  20. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
  21. package/dist/cjs/types/components/Piano/key.d.ts +4 -7
  22. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
  23. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  24. package/dist/cjs/types/components/Slider/Scale.d.ts +11 -0
  25. package/dist/cjs/types/components/Slider/Scale.d.ts.map +1 -0
  26. package/dist/cjs/types/components/Slider/ScaleOption.d.ts +25 -0
  27. package/dist/cjs/types/components/Slider/ScaleOption.d.ts.map +1 -0
  28. package/dist/cjs/types/components/Slider/Thumb.d.ts +5 -13
  29. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
  30. package/dist/cjs/types/components/Slider/Track.d.ts +10 -21
  31. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
  32. package/dist/cjs/types/components/Slider/context.d.ts +21 -0
  33. package/dist/cjs/types/components/Slider/context.d.ts.map +1 -0
  34. package/dist/cjs/types/components/Slider/index.d.ts +18 -12
  35. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  36. package/dist/cjs/types/components/WheelObserver/index.d.ts +24 -0
  37. package/dist/cjs/types/components/WheelObserver/index.d.ts.map +1 -0
  38. package/dist/cjs/types/components/XYPad/Area.d.ts +13 -0
  39. package/dist/cjs/types/components/XYPad/Area.d.ts.map +1 -0
  40. package/dist/cjs/types/components/XYPad/Thumb.d.ts +19 -0
  41. package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +1 -0
  42. package/dist/cjs/types/components/XYPad/index.d.ts +39 -0
  43. package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -0
  44. package/dist/cjs/types/hooks/useCallbackRef.d.ts.map +1 -1
  45. package/dist/cjs/types/index.d.ts +10 -0
  46. package/dist/cjs/types/index.d.ts.map +1 -1
  47. package/dist/esm/index.js +657 -254
  48. package/dist/esm/index.js.map +1 -1
  49. package/dist/esm/types/components/AnimationCanvas/index.d.ts +16 -9
  50. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
  51. package/dist/esm/types/components/AnimationKnob/index.d.ts +53 -0
  52. package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -0
  53. package/dist/esm/types/components/DragObserver/index.d.ts +19 -0
  54. package/dist/esm/types/components/DragObserver/index.d.ts.map +1 -0
  55. package/dist/esm/types/components/Knob/index.d.ts +26 -26
  56. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  57. package/dist/esm/types/components/NumberInput/index.d.ts +2 -5
  58. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
  59. package/dist/esm/types/components/Piano/BlackKey.d.ts +3 -3
  60. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -1
  61. package/dist/esm/types/components/Piano/KeyLabel.d.ts +5 -8
  62. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -1
  63. package/dist/esm/types/components/Piano/WhiteKey.d.ts +3 -3
  64. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -1
  65. package/dist/esm/types/components/Piano/index.d.ts +3 -4
  66. package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
  67. package/dist/esm/types/components/Piano/key.d.ts +4 -7
  68. package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
  69. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  70. package/dist/esm/types/components/Slider/Scale.d.ts +11 -0
  71. package/dist/esm/types/components/Slider/Scale.d.ts.map +1 -0
  72. package/dist/esm/types/components/Slider/ScaleOption.d.ts +25 -0
  73. package/dist/esm/types/components/Slider/ScaleOption.d.ts.map +1 -0
  74. package/dist/esm/types/components/Slider/Thumb.d.ts +5 -13
  75. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
  76. package/dist/esm/types/components/Slider/Track.d.ts +10 -21
  77. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
  78. package/dist/esm/types/components/Slider/context.d.ts +21 -0
  79. package/dist/esm/types/components/Slider/context.d.ts.map +1 -0
  80. package/dist/esm/types/components/Slider/index.d.ts +18 -12
  81. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  82. package/dist/esm/types/components/WheelObserver/index.d.ts +24 -0
  83. package/dist/esm/types/components/WheelObserver/index.d.ts.map +1 -0
  84. package/dist/esm/types/components/XYPad/Area.d.ts +13 -0
  85. package/dist/esm/types/components/XYPad/Area.d.ts.map +1 -0
  86. package/dist/esm/types/components/XYPad/Thumb.d.ts +19 -0
  87. package/dist/esm/types/components/XYPad/Thumb.d.ts.map +1 -0
  88. package/dist/esm/types/components/XYPad/index.d.ts +39 -0
  89. package/dist/esm/types/components/XYPad/index.d.ts.map +1 -0
  90. package/dist/esm/types/hooks/useCallbackRef.d.ts.map +1 -1
  91. package/dist/esm/types/index.d.ts +10 -0
  92. package/dist/esm/types/index.d.ts.map +1 -1
  93. package/dist/styles/index.css +241 -0
  94. package/package.json +2 -5
  95. package/src/components/AnimationCanvas/index.tsx +87 -57
  96. package/src/components/AnimationKnob/index.tsx +305 -0
  97. package/src/components/DragObserver/index.tsx +94 -0
  98. package/src/components/Knob/index.css +48 -0
  99. package/src/components/Knob/index.tsx +152 -165
  100. package/src/components/NumberInput/index.css +25 -0
  101. package/src/components/NumberInput/index.tsx +8 -41
  102. package/src/components/Piano/BlackKey.tsx +104 -98
  103. package/src/components/Piano/KeyLabel.tsx +18 -40
  104. package/src/components/Piano/WhiteKey.tsx +92 -87
  105. package/src/components/Piano/index.css +63 -0
  106. package/src/components/Piano/index.tsx +76 -59
  107. package/src/components/Piano/key.ts +4 -7
  108. package/src/components/Piano/keyboardShortcuts.ts +23 -4
  109. package/src/components/Slider/Scale.tsx +55 -0
  110. package/src/components/Slider/ScaleOption.tsx +103 -0
  111. package/src/components/Slider/Thumb.tsx +69 -76
  112. package/src/components/Slider/Track.tsx +37 -48
  113. package/src/components/Slider/context.tsx +66 -0
  114. package/src/components/Slider/index.css +76 -0
  115. package/src/components/Slider/index.tsx +256 -298
  116. package/src/components/WheelObserver/index.tsx +47 -0
  117. package/src/components/XYPad/Area.tsx +40 -0
  118. package/src/components/XYPad/Thumb.tsx +92 -0
  119. package/src/components/XYPad/index.css +24 -0
  120. package/src/components/XYPad/index.tsx +317 -0
  121. package/src/hooks/useCallbackRef.ts +1 -0
  122. package/src/hooks/useRefCallbackEvent.ts +1 -0
  123. package/src/index.ts +11 -0
  124. package/dist/cjs/types/components/Slider/type.d.ts +0 -7
  125. package/dist/cjs/types/components/Slider/type.d.ts.map +0 -1
  126. package/dist/cjs/types/system/pseudo.d.ts +0 -14
  127. package/dist/cjs/types/system/pseudo.d.ts.map +0 -1
  128. package/dist/esm/types/components/Slider/type.d.ts +0 -7
  129. package/dist/esm/types/components/Slider/type.d.ts.map +0 -1
  130. package/dist/esm/types/system/pseudo.d.ts +0 -14
  131. package/dist/esm/types/system/pseudo.d.ts.map +0 -1
  132. package/src/components/Slider/type.ts +0 -16
  133. package/src/system/pseudo.ts +0 -55
@@ -1,12 +1,17 @@
1
- import { css, CSSObject, Global } from '@emotion/react'
2
- import { clamp, normalizeValue, radian, rawValue, stepValue, InputEventOption } from '@tremolo-ui/functions'
3
- import React, { ComponentPropsWithRef, useRef } from 'react'
4
1
  import clsx from 'clsx'
2
+ import { ComponentPropsWithoutRef, useCallback, useRef } from 'react'
3
+
4
+ import {
5
+ clamp,
6
+ InputEventOption,
7
+ normalizeValue,
8
+ radian,
9
+ rawValue,
10
+ stepValue,
11
+ } from '@tremolo-ui/functions'
5
12
 
6
13
  import { useEventListener } from '../../hooks/useEventListener'
7
14
  import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
8
- import { UserActionPseudoProps } from '../../system/pseudo'
9
- import { AnimationCanvas, DrawFunction } from '../AnimationCanvas'
10
15
  import { addNoSelect, removeNoSelect } from '../_util'
11
16
 
12
17
  export interface KnobProps {
@@ -16,8 +21,11 @@ export interface KnobProps {
16
21
  max: number
17
22
 
18
23
  // optional
24
+ step?: number
25
+ skew?: number // | SkewFunction
19
26
  /**
20
27
  * value set when double-clicking
28
+ * @default min
21
29
  * @see enableDoubleClickDefault
22
30
  */
23
31
  defaultValue?: number
@@ -28,111 +36,118 @@ export interface KnobProps {
28
36
  */
29
37
  startValue?: number
30
38
 
31
- step?: number
32
- skew?: number // | SkewFunction
39
+ // TODO: relative size (Lower priority)
40
+ size?: number
33
41
 
34
- /** Priority over width or height */
35
- size?: number | `${number}%`
36
-
37
- width?: number | `${number}%`
38
- height?: number | `${number}%`
42
+ /** Whether to apply `{use-select: none}` when dragging */
43
+ bodyNoSelect?: boolean
44
+ /**
45
+ * wheel control option
46
+ */
47
+ wheel?: InputEventOption | null
48
+ /**
49
+ * keyboard control option
50
+ */
51
+ keyboard?: InputEventOption | null
52
+ enableDoubleClickDefault?: boolean
39
53
 
40
- /** drawing options */
41
- options?: {
42
- active?: string // active line color
43
- inactive?: string // inactive line color
44
- bg?: string // background color
45
- thumb?: string // thumb color
46
- lineWeight?: number // line color
47
- thumbWeight?: number // thumb weight
48
- }
54
+ disabled?: boolean
55
+ readonly?: boolean
49
56
 
50
- draw?: DrawFunction
57
+ activeLine?: string
58
+ inactiveLine?: string
59
+ thumb?: string
60
+ thumbLine?: string
51
61
 
52
- /** Whether to apply `{use-select: none}` when dragging */
53
- bodyNoSelect?: boolean
62
+ classes?: {
63
+ activeLine?: string
64
+ inactiveLine?: string
65
+ thumb?: string
66
+ thumbLine?: string
67
+ }
54
68
 
55
- wheel?: InputEventOption
56
- enableDoubleClickDefault?: boolean
57
- style?: CSSObject
58
69
  onChange?: (value: number) => void
59
70
  }
60
71
 
61
- const defaultOptions = {
62
- active: '#7998ec',
63
- inactive: '#eee',
64
- bg: '#ccc',
65
- thumb: '#4e76e6',
66
- lineWeight: 6,
67
- thumbWeight: 4,
68
- } as const
69
-
70
- /**
71
- * simple rotary Knob.
72
- */
73
72
  export function Knob({
74
73
  value,
75
74
  min,
76
75
  max,
77
- defaultValue = min,
78
- startValue = min,
79
76
  step = 1,
80
77
  skew = 1,
81
- size,
82
- width = 50,
83
- height = 50,
84
- options = defaultOptions,
85
- draw,
78
+ defaultValue = min,
79
+ startValue = min,
80
+ size = 50,
86
81
  bodyNoSelect = true,
87
- wheel,
82
+ wheel = ['raw', 1],
83
+ keyboard = ['raw', 1],
88
84
  enableDoubleClickDefault = true,
89
- style,
90
- className,
85
+ disabled = false,
86
+ readonly = false,
87
+ activeLine,
88
+ inactiveLine,
89
+ thumb,
90
+ thumbLine,
91
91
  onChange,
92
- _active,
93
- _focus,
94
- _hover,
92
+ className,
93
+ classes,
95
94
  ...props
96
- }: KnobProps &
97
- UserActionPseudoProps &
98
- Omit<ComponentPropsWithRef<'div'>, keyof KnobProps>) {
95
+ }: KnobProps & Omit<ComponentPropsWithoutRef<'svg'>, keyof KnobProps>) {
99
96
  // -- state and ref ---
100
- // const [privateValue, setPrivateValue] = useState(value);
101
97
  const dragOffsetY = useRef<number | undefined>(undefined)
102
98
 
103
99
  // --- interpret props ---
104
- const opts = { ...defaultOptions, ...options }
105
- // const percent = normalizeValue(value, min, max, skew)
106
-
107
- const isRelativeSize = typeof (size ?? width) == 'string'
108
- const adaptSize = (size: number | `${number}%`) => {
109
- if (typeof size == 'string') {
110
- return Number(size.slice(0, -1))
111
- } else {
112
- return size
113
- }
114
- }
100
+ const padding = 8 // %
101
+ const thumbLineWeight = 6 // %
102
+ const thumbLength = 35 // %
103
+ const lineWeight = 3 // px
104
+ const p = normalizeValue(value, min, max, skew)
105
+ const s = normalizeValue(startValue, min, max, skew)
115
106
 
107
+ // --- internal functions ---
116
108
  const handleEvent = (
117
109
  event:
118
110
  | MouseEvent
119
- | React.MouseEvent<HTMLDivElement, MouseEvent>
111
+ | React.MouseEvent<HTMLOrSVGElement, MouseEvent>
120
112
  | TouchEvent,
121
113
  ) => {
114
+ if (!onChange || readonly) return
122
115
  const isTouch = event instanceof TouchEvent
123
116
  if (isTouch && event.cancelable) event.preventDefault()
124
117
  if (dragOffsetY.current) {
125
118
  if (bodyNoSelect) addNoSelect()
126
119
  const screenY = isTouch ? event.touches[0].screenY : event.screenY
127
120
  const delta = dragOffsetY.current - screenY
121
+ if (Math.abs(delta) < 1) return
128
122
  dragOffsetY.current = screenY
129
123
  const n = normalizeValue(value, min, max, skew)
130
124
  const v = rawValue(n + delta / 100, min, max, skew)
131
125
  const v2 = clamp(stepValue(v, step), min, max)
132
- if (onChange) onChange(v2)
126
+ onChange(v2)
133
127
  }
134
128
  }
135
129
 
130
+ const handleKeyDown = useCallback(
131
+ (event: React.KeyboardEvent<HTMLOrSVGElement>) => {
132
+ if (!keyboard || !onChange || readonly) return
133
+ const key = event.key
134
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
135
+ event.preventDefault()
136
+ const x =
137
+ key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1]
138
+ let v
139
+ if (keyboard[0] == 'normalized') {
140
+ const n = normalizeValue(value, min, max, skew)
141
+ v = rawValue(n + x, min, max, skew)
142
+ } else {
143
+ v = value + x
144
+ }
145
+ onChange(clamp(stepValue(v, step), min, max))
146
+ }
147
+ },
148
+ [value, min, max, step, skew, keyboard, readonly, onChange],
149
+ )
150
+
136
151
  // --- hooks ---
137
152
  const wheelRefCallback = useRefCallbackEvent(
138
153
  'wheel',
@@ -167,34 +182,35 @@ export function Knob({
167
182
  if (bodyNoSelect) removeNoSelect()
168
183
  })
169
184
 
185
+ const center = size / 2
186
+ const r1 = -135
187
+ const r2 = -135 + Math.min(p, s) * 270
188
+ const r3 = -135 + Math.max(p, s) * 270
189
+ const r4 = 135
190
+ const x1 = center + center * Math.cos(radian(r1 - 90))
191
+ const y1 = center + center * Math.sin(radian(r1 - 90))
192
+ const x2 = center + center * Math.cos(radian(r2 - 90))
193
+ const y2 = center + center * Math.sin(radian(r2 - 90))
194
+ const x3 = center + center * Math.cos(radian(r3 - 90))
195
+ const y3 = center + center * Math.sin(radian(r3 - 90))
196
+ const x4 = center + center * Math.cos(radian(r4 - 90))
197
+ const y4 = center + center * Math.sin(radian(r4 - 90))
198
+
170
199
  return (
171
- <div
200
+ <svg
172
201
  className={clsx('tremolo-knob', className)}
173
202
  ref={(div) => {
174
203
  wheelRefCallback(div)
175
204
  touchMoveRefCallback(div)
176
205
  }}
177
- role="slider"
206
+ width={size}
207
+ height={size}
178
208
  tabIndex={0}
179
209
  aria-valuenow={value}
180
- aria-valuemax={max}
181
210
  aria-valuemin={min}
182
- css={css({
183
- display: 'inline-block',
184
- width: size ?? width,
185
- height: size ?? height,
186
- cursor: 'pointer',
187
- ...style,
188
- ':active': {
189
- ..._active,
190
- },
191
- ':focus': {
192
- ..._focus,
193
- },
194
- ':hover': {
195
- ..._hover,
196
- },
197
- })}
211
+ aria-valuemax={max}
212
+ aria-disabled={disabled}
213
+ aria-readonly={readonly}
198
214
  onPointerDown={(event) => {
199
215
  dragOffsetY.current = event.screenY
200
216
  handleEvent(event)
@@ -204,85 +220,56 @@ export function Knob({
204
220
  onChange(defaultValue)
205
221
  }
206
222
  }}
223
+ onKeyDown={handleKeyDown}
224
+ onContextMenu={(e) => e.preventDefault()}
207
225
  {...props}
208
226
  >
209
- <Global
210
- styles={{
211
- '.no-select': {
212
- userSelect: 'none',
213
- },
214
- }}
215
- />
216
- <AnimationCanvas
217
- width={adaptSize(size ?? width)}
218
- height={adaptSize(size ?? height)}
219
- relativeSize={isRelativeSize}
220
- // TODO
221
- // reduceFlickering={false}
222
- draw={draw ? draw : (ctx, width, height) => {
223
- const p = normalizeValue(value, min, max, skew)
224
- const startP = normalizeValue(startValue, min, max, skew)
225
- const w = width.current,
226
- cx = w / 2
227
- const h = height.current,
228
- cy = h / 2
229
- const r = Math.min(cx, cy)
230
- if (r <= 0) return
231
-
232
- // reset
233
- ctx.clearRect(0, 0, w, h)
234
- ctx.lineCap = 'butt'
235
-
236
- // bg
237
- ctx.beginPath()
238
- ctx.fillStyle = opts.bg
239
- ctx.arc(cx, cy, r - 0.5, 0, 2 * Math.PI)
240
- ctx.fill()
241
-
242
- ctx.lineCap = 'round'
243
- ctx.lineWidth = opts.lineWeight
244
-
245
- // inactive rotary
246
- ctx.beginPath()
247
- ctx.strokeStyle = opts.inactive
248
- ctx.arc(
249
- cx,
250
- cy,
251
- r - 0.5 - opts.lineWeight / 2,
252
- radian(135),
253
- radian(45),
254
- )
255
- ctx.stroke()
256
-
257
- // active rotary
258
- ctx.beginPath()
259
- ctx.strokeStyle = opts.active
260
- ctx.arc(
261
- cx,
262
- cy,
263
- r - 0.5 - opts.lineWeight / 2,
264
- radian(135 + 270 * startP),
265
- radian(135 + 270 * p),
266
- p < startP,
267
- )
268
- ctx.stroke()
269
-
270
- // thumb
271
- ctx.beginPath()
272
- ctx.moveTo(cx, cy)
273
- ctx.lineTo(
274
- cx +
275
- Math.cos(radian(135 + 270 * p)) *
276
- (r - 0.5 - opts.thumbWeight / 2),
277
- cy +
278
- Math.sin(radian(135 + 270 * p)) *
279
- (r - 0.5 - opts.thumbWeight / 2),
280
- )
281
- ctx.strokeStyle = opts.thumb
282
- ctx.lineWidth = opts.thumbWeight
283
- ctx.stroke()
284
- }}
227
+ {/* rotary meter */}
228
+ {startValue > min && (
229
+ <path
230
+ className={clsx('tremolo-knob-inactive-line', classes?.inactiveLine)}
231
+ d={`M ${x1} ${y1} A ${center} ${center} -135 ${r2 - r1 > 180 ? 1 : 0} 1 ${x2}, ${y2}`}
232
+ fill="none"
233
+ stroke={inactiveLine || 'currentColor'}
234
+ strokeWidth={lineWeight}
235
+ />
236
+ )}
237
+ <path
238
+ className={clsx('tremolo-knob-active-line', classes?.activeLine)}
239
+ d={`M ${x2} ${y2} A ${center} ${center} -135 ${r3 - r2 > 180 ? 1 : 0} 1 ${x3}, ${y3}`}
240
+ fill="none"
241
+ stroke={activeLine || 'currentColor'}
242
+ strokeWidth={lineWeight}
285
243
  />
286
- </div>
244
+ {startValue < max && (
245
+ <path
246
+ className={clsx('tremolo-knob-inactive-line', classes?.inactiveLine)}
247
+ d={`M ${x3} ${y3} A ${center} ${center} -135 ${r4 - r3 > 180 ? 1 : 0} 1 ${x4}, ${y4}`}
248
+ fill="none"
249
+ stroke={inactiveLine || 'currentColor'}
250
+ strokeWidth={lineWeight}
251
+ />
252
+ )}
253
+ {/* thumb */}
254
+ <svg className={clsx('tremolo-knob-thumb', classes?.thumb)}>
255
+ <circle
256
+ cx="50%"
257
+ cy="50%"
258
+ r={`${50 - padding}%`}
259
+ fill={thumb || 'currentColor'}
260
+ />
261
+ <line
262
+ className={clsx('tremolo-knob-thumb-line', classes?.thumbLine)}
263
+ x1="50%"
264
+ y1={`${padding}%`}
265
+ x2="50%"
266
+ y2={`${thumbLength}%`}
267
+ stroke={thumbLine || 'currentColor'}
268
+ strokeWidth={`${thumbLineWeight}%`}
269
+ transform={`rotate(${-135 + p * 270})`}
270
+ transform-origin="50% 50%"
271
+ />
272
+ </svg>
273
+ </svg>
287
274
  )
288
275
  }
@@ -0,0 +1,25 @@
1
+ .tremolo-number-input {
2
+ display: inline-block;
3
+ font: inherit;
4
+ margin: 0px;
5
+ padding-top: 6px;
6
+ padding-bottom: 6px;
7
+ padding-left: 10px;
8
+ padding-right: 10px;
9
+ border-style: solid;
10
+ border-width: 1px;
11
+ border-color: #bbb;
12
+ border-radius: 4px;
13
+ outline: 0px;
14
+ transition: all 0.1s linear;
15
+ appearance: textfield;
16
+
17
+ &:hover {
18
+ border-color: var(--tremolo-theme-color);
19
+ }
20
+
21
+ &:focus {
22
+ border-color: var(--tremolo-theme-color);
23
+ box-shadow: 0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1);
24
+ }
25
+ }
@@ -1,10 +1,8 @@
1
- import { css, CSSObject } from '@emotion/react'
2
- import { clamp } from '@tremolo-ui/functions'
3
- import { parseValue, Units } from '@tremolo-ui/functions/NumberInput'
4
- import { ChangeEvent, ComponentPropsWithoutRef, useState } from 'react'
5
1
  import clsx from 'clsx'
2
+ import { ChangeEvent, ComponentPropsWithoutRef, useState } from 'react'
6
3
 
7
- import { InputPseudoProps, UserActionPseudoProps } from '../../system/pseudo'
4
+ import { clamp } from '@tremolo-ui/functions'
5
+ import { parseValue, Units } from '@tremolo-ui/functions/NumberInput'
8
6
 
9
7
  export interface NumberInputProps {
10
8
  value: number | string
@@ -31,7 +29,7 @@ export interface NumberInputProps {
31
29
  /**
32
30
  * NOTE: If units is specified, it is forced to `false`
33
31
  */
34
- typeNumber?: boolean // TODO: rename typeNumber
32
+ typeNumber?: boolean
35
33
 
36
34
  /**
37
35
  * Digits for rounding numbers.
@@ -46,7 +44,6 @@ export interface NumberInputProps {
46
44
  selectWithFocus?: 'all' | 'number' | 'none'
47
45
  blurWithEnter?: boolean
48
46
  className?: string
49
- style?: CSSObject
50
47
  onChange?: (value: number, event: ChangeEvent<HTMLInputElement>) => void
51
48
  onFocus?: (
52
49
  value: number,
@@ -77,19 +74,16 @@ export function NumberInput({
77
74
  selectWithFocus = 'none',
78
75
  blurWithEnter = true,
79
76
  className,
80
- style,
81
77
  onChange,
82
78
  onFocus,
83
79
  onBlur,
84
80
  ...props
85
- }: NumberInputProps & UserActionPseudoProps & InputPseudoProps &
86
- Omit<ComponentPropsWithoutRef<'input'>, keyof NumberInputProps>
87
- ) {
81
+ }: NumberInputProps &
82
+ Omit<ComponentPropsWithoutRef<'input'>, keyof NumberInputProps | 'type'>) {
88
83
  const [showValue, setShowValue] = useState(
89
84
  parseValue(String(value), units, digit, defaultValue).formatValue,
90
85
  )
91
86
  const calculatedTypeNumber = units ? false : typeNumber
92
- const { _active, _focus, _hover, ...rest } = props
93
87
 
94
88
  return (
95
89
  <input
@@ -104,40 +98,13 @@ export function NumberInput({
104
98
  placeholder={placeholder}
105
99
  readOnly={readOnly}
106
100
  tabIndex={tabIndex}
107
- css={css({
108
- display: 'inline-block',
109
- font: 'inherit',
110
- margin: 0,
111
- paddingTop: 6,
112
- paddingBottom: 6,
113
- paddingLeft: 10,
114
- paddingRight: 10,
115
- borderStyle: 'solid',
116
- borderWidth: 1,
117
- borderColor: '#bbb',
118
- borderRadius: 4,
119
- outline: 0,
120
- transition: 'all 0.1s linear',
121
- appearance: 'textfield',
122
- '&:hover': {
123
- borderColor: 'var(--tremolo-theme-color)',
124
- ..._hover,
125
- },
126
- '&:focus': {
127
- borderColor: 'var(--tremolo-theme-color)',
128
- boxShadow: '0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1)',
129
- ..._focus,
130
- },
131
- ...(_active && { '&:active': { ..._active } }),
132
- ...style,
133
- })}
134
101
  onChange={(event) => {
135
102
  const v = event.currentTarget.value
136
103
  setShowValue(v)
137
104
  const newValue = clamp(
138
105
  parseValue(v, units, digit, defaultValue).rawValue,
139
106
  min ?? -Infinity,
140
- max ?? Infinity
107
+ max ?? Infinity,
141
108
  )
142
109
  if (onChange) onChange(newValue, event)
143
110
  }}
@@ -166,7 +133,7 @@ export function NumberInput({
166
133
  event.currentTarget.blur()
167
134
  }
168
135
  }}
169
- {...rest}
136
+ {...props}
170
137
  />
171
138
  )
172
139
  }