@moises.ai/design-system 4.14.3 → 4.14.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.
package/package.json
CHANGED
|
@@ -37,21 +37,20 @@ export const Callout = ({
|
|
|
37
37
|
|
|
38
38
|
const contentRef = useRef(null)
|
|
39
39
|
const actionsRef = useRef(null)
|
|
40
|
-
const [
|
|
40
|
+
const [outerAlign, setOuterAlign] = useState('start')
|
|
41
41
|
|
|
42
42
|
useLayoutEffect(() => {
|
|
43
|
-
|
|
44
43
|
if (!hasActions) {
|
|
45
|
-
|
|
44
|
+
setOuterAlign('start')
|
|
46
45
|
return
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
if (!contentRef.current || !actionsRef.current) return
|
|
50
49
|
|
|
51
50
|
const updateAlign = () => {
|
|
52
|
-
const contentHeight = contentRef.current.
|
|
53
|
-
const actionsHeight = actionsRef.current.
|
|
54
|
-
|
|
51
|
+
const contentHeight = contentRef.current.scrollHeight
|
|
52
|
+
const actionsHeight = actionsRef.current.scrollHeight
|
|
53
|
+
setOuterAlign(contentHeight <= actionsHeight ? 'center' : 'start')
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
updateAlign()
|
|
@@ -90,11 +89,10 @@ export const Callout = ({
|
|
|
90
89
|
)}
|
|
91
90
|
{...props}
|
|
92
91
|
>
|
|
93
|
-
<Flex justify="between" gap="3" width="100%">
|
|
92
|
+
<Flex justify="between" gap="3" width="100%" align={outerAlign}>
|
|
94
93
|
<Flex
|
|
95
94
|
direction="row"
|
|
96
95
|
gap="2"
|
|
97
|
-
align={contentAlign}
|
|
98
96
|
width="100%"
|
|
99
97
|
>
|
|
100
98
|
{renderIcon()}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
memo,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react'
|
|
2
9
|
import { Tooltip } from '../Tooltip/Tooltip'
|
|
3
10
|
import styles from './InputLevelMeter.module.css'
|
|
4
11
|
|
|
@@ -7,6 +14,8 @@ const SEGMENT_RANGE = 25
|
|
|
7
14
|
const UNITY_GAIN_POS = 0.667
|
|
8
15
|
const MAX_BOOST_DB = 6
|
|
9
16
|
const FADER_KEYBOARD_STEP = 0.02
|
|
17
|
+
const THUMB_DOUBLE_TAP_MS = 400
|
|
18
|
+
const THUMB_DOUBLE_TAP_MAX_PX = 12
|
|
10
19
|
|
|
11
20
|
function linearToMeterLevel(linear) {
|
|
12
21
|
const peakDb = 20 * Math.log10(Math.max(linear, 1e-6))
|
|
@@ -81,10 +90,134 @@ function MeterRow({ level }) {
|
|
|
81
90
|
)
|
|
82
91
|
}
|
|
83
92
|
|
|
93
|
+
const MeterThumb = memo(
|
|
94
|
+
forwardRef(function MeterThumb(
|
|
95
|
+
{
|
|
96
|
+
faderPercent,
|
|
97
|
+
isPressed,
|
|
98
|
+
hover,
|
|
99
|
+
volume,
|
|
100
|
+
doubleTapStateRef,
|
|
101
|
+
onVolumeChange,
|
|
102
|
+
onVolumeReset,
|
|
103
|
+
},
|
|
104
|
+
ref,
|
|
105
|
+
) {
|
|
106
|
+
const [thumbFocused, setThumbFocused] = useState(false)
|
|
107
|
+
const [hoverOpen, setHoverOpen] = useState(false)
|
|
108
|
+
|
|
109
|
+
const tooltipOpen = isPressed || thumbFocused || hoverOpen
|
|
110
|
+
|
|
111
|
+
const handlePointerDownCapture = useCallback(
|
|
112
|
+
(e) => {
|
|
113
|
+
if (!onVolumeReset || e.button !== 0) return
|
|
114
|
+
const now = performance.now()
|
|
115
|
+
const prev = doubleTapStateRef.current
|
|
116
|
+
if (
|
|
117
|
+
prev &&
|
|
118
|
+
now - prev.t < THUMB_DOUBLE_TAP_MS &&
|
|
119
|
+
Math.hypot(e.clientX - prev.x, e.clientY - prev.y) <
|
|
120
|
+
THUMB_DOUBLE_TAP_MAX_PX
|
|
121
|
+
) {
|
|
122
|
+
e.preventDefault()
|
|
123
|
+
e.stopPropagation()
|
|
124
|
+
doubleTapStateRef.current = null
|
|
125
|
+
onVolumeReset()
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
doubleTapStateRef.current = {
|
|
129
|
+
t: now,
|
|
130
|
+
x: e.clientX,
|
|
131
|
+
y: e.clientY,
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
[doubleTapStateRef, onVolumeReset],
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
const handleKeyDown = useCallback(
|
|
138
|
+
(e) => {
|
|
139
|
+
if (!onVolumeChange) return
|
|
140
|
+
const pos = gainToFaderPosition(volume)
|
|
141
|
+
let nextPos = pos
|
|
142
|
+
switch (e.key) {
|
|
143
|
+
case 'ArrowRight':
|
|
144
|
+
case 'ArrowUp':
|
|
145
|
+
e.preventDefault()
|
|
146
|
+
nextPos = Math.min(1, pos + FADER_KEYBOARD_STEP)
|
|
147
|
+
onVolumeChange([faderPositionToGain(nextPos)])
|
|
148
|
+
break
|
|
149
|
+
case 'ArrowLeft':
|
|
150
|
+
case 'ArrowDown':
|
|
151
|
+
e.preventDefault()
|
|
152
|
+
nextPos = Math.max(0, pos - FADER_KEYBOARD_STEP)
|
|
153
|
+
onVolumeChange([faderPositionToGain(nextPos)])
|
|
154
|
+
break
|
|
155
|
+
case 'Home':
|
|
156
|
+
e.preventDefault()
|
|
157
|
+
onVolumeChange([faderPositionToGain(0)])
|
|
158
|
+
break
|
|
159
|
+
case 'End':
|
|
160
|
+
e.preventDefault()
|
|
161
|
+
onVolumeChange([faderPositionToGain(1)])
|
|
162
|
+
break
|
|
163
|
+
case 'PageUp':
|
|
164
|
+
e.preventDefault()
|
|
165
|
+
nextPos = Math.min(1, pos + FADER_KEYBOARD_STEP * 4)
|
|
166
|
+
onVolumeChange([faderPositionToGain(nextPos)])
|
|
167
|
+
break
|
|
168
|
+
case 'PageDown':
|
|
169
|
+
e.preventDefault()
|
|
170
|
+
nextPos = Math.max(0, pos - FADER_KEYBOARD_STEP * 4)
|
|
171
|
+
onVolumeChange([faderPositionToGain(nextPos)])
|
|
172
|
+
break
|
|
173
|
+
default:
|
|
174
|
+
break
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
[onVolumeChange, volume],
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
const gainDbForAria =
|
|
181
|
+
volume <= 0 ? -96 : 20 * Math.log10(Math.max(volume, 1e-6))
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<Tooltip
|
|
185
|
+
content={formatGainDb(volume)}
|
|
186
|
+
open={tooltipOpen}
|
|
187
|
+
onOpenChange={setHoverOpen}
|
|
188
|
+
side="bottom"
|
|
189
|
+
align="center"
|
|
190
|
+
sideOffset={3}
|
|
191
|
+
delayDuration={0}
|
|
192
|
+
>
|
|
193
|
+
<div
|
|
194
|
+
ref={ref}
|
|
195
|
+
role="slider"
|
|
196
|
+
tabIndex={0}
|
|
197
|
+
aria-label="Input gain"
|
|
198
|
+
aria-valuemin={-96}
|
|
199
|
+
aria-valuemax={MAX_BOOST_DB}
|
|
200
|
+
aria-valuenow={Math.round(gainDbForAria * 10) / 10}
|
|
201
|
+
aria-valuetext={formatGainDb(volume)}
|
|
202
|
+
className={`${styles.thumb} ${isPressed ? styles.pressed : hover ? styles.hovered : ''}`}
|
|
203
|
+
style={{ left: `${faderPercent}%` }}
|
|
204
|
+
onPointerDownCapture={handlePointerDownCapture}
|
|
205
|
+
onFocus={() => setThumbFocused(true)}
|
|
206
|
+
onBlur={() => setThumbFocused(false)}
|
|
207
|
+
onKeyDown={handleKeyDown}
|
|
208
|
+
/>
|
|
209
|
+
</Tooltip>
|
|
210
|
+
)
|
|
211
|
+
}),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
MeterThumb.displayName = 'MeterThumb'
|
|
215
|
+
|
|
84
216
|
export const InputLevelMeter = memo(function InputLevelMeter({
|
|
85
217
|
linear = [0, 0],
|
|
86
218
|
volume = 1,
|
|
87
219
|
onVolumeChange,
|
|
220
|
+
onVolumeReset,
|
|
88
221
|
showHandler = true,
|
|
89
222
|
showMeter = true,
|
|
90
223
|
hover = false,
|
|
@@ -97,14 +230,13 @@ export const InputLevelMeter = memo(function InputLevelMeter({
|
|
|
97
230
|
const [isPressed, setIsPressed] = useState(false)
|
|
98
231
|
const isPressedRef = useRef(false)
|
|
99
232
|
const meterRef = useRef(null)
|
|
233
|
+
const thumbRef = useRef(null)
|
|
234
|
+
const thumbDoubleTapStateRef = useRef(null)
|
|
100
235
|
const peakHoldRef = useRef(0)
|
|
101
236
|
const peakTimerRef = useRef(null)
|
|
102
237
|
const [peakHoldPct, setPeakHoldPct] = useState(0)
|
|
103
238
|
const [peakRising, setPeakRising] = useState(false)
|
|
104
239
|
|
|
105
|
-
const [thumbFocused, setThumbFocused] = useState(false)
|
|
106
|
-
const [hoverOpen, setHoverOpen] = useState(false)
|
|
107
|
-
|
|
108
240
|
useEffect(() => {
|
|
109
241
|
peakHoldRef.current = 0
|
|
110
242
|
setPeakHoldPct(0)
|
|
@@ -151,6 +283,13 @@ export const InputLevelMeter = memo(function InputLevelMeter({
|
|
|
151
283
|
const handlePointerDown = useCallback(
|
|
152
284
|
(e) => {
|
|
153
285
|
if (!onVolumeChange) return
|
|
286
|
+
if (
|
|
287
|
+
thumbRef.current &&
|
|
288
|
+
e.target instanceof Element &&
|
|
289
|
+
!thumbRef.current.contains(e.target)
|
|
290
|
+
) {
|
|
291
|
+
thumbDoubleTapStateRef.current = null
|
|
292
|
+
}
|
|
154
293
|
e.currentTarget.setPointerCapture(e.pointerId)
|
|
155
294
|
isPressedRef.current = true
|
|
156
295
|
setIsPressed(true)
|
|
@@ -188,49 +327,6 @@ export const InputLevelMeter = memo(function InputLevelMeter({
|
|
|
188
327
|
document.body.style.cursor = ''
|
|
189
328
|
}, [])
|
|
190
329
|
|
|
191
|
-
const handleThumbKeyDown = useCallback(
|
|
192
|
-
(e) => {
|
|
193
|
-
if (!onVolumeChange) return
|
|
194
|
-
const pos = gainToFaderPosition(volume)
|
|
195
|
-
let nextPos = pos
|
|
196
|
-
switch (e.key) {
|
|
197
|
-
case 'ArrowRight':
|
|
198
|
-
case 'ArrowUp':
|
|
199
|
-
e.preventDefault()
|
|
200
|
-
nextPos = Math.min(1, pos + FADER_KEYBOARD_STEP)
|
|
201
|
-
onVolumeChange([faderPositionToGain(nextPos)])
|
|
202
|
-
break
|
|
203
|
-
case 'ArrowLeft':
|
|
204
|
-
case 'ArrowDown':
|
|
205
|
-
e.preventDefault()
|
|
206
|
-
nextPos = Math.max(0, pos - FADER_KEYBOARD_STEP)
|
|
207
|
-
onVolumeChange([faderPositionToGain(nextPos)])
|
|
208
|
-
break
|
|
209
|
-
case 'Home':
|
|
210
|
-
e.preventDefault()
|
|
211
|
-
onVolumeChange([faderPositionToGain(0)])
|
|
212
|
-
break
|
|
213
|
-
case 'End':
|
|
214
|
-
e.preventDefault()
|
|
215
|
-
onVolumeChange([faderPositionToGain(1)])
|
|
216
|
-
break
|
|
217
|
-
case 'PageUp':
|
|
218
|
-
e.preventDefault()
|
|
219
|
-
nextPos = Math.min(1, pos + FADER_KEYBOARD_STEP * 4)
|
|
220
|
-
onVolumeChange([faderPositionToGain(nextPos)])
|
|
221
|
-
break
|
|
222
|
-
case 'PageDown':
|
|
223
|
-
e.preventDefault()
|
|
224
|
-
nextPos = Math.max(0, pos - FADER_KEYBOARD_STEP * 4)
|
|
225
|
-
onVolumeChange([faderPositionToGain(nextPos)])
|
|
226
|
-
break
|
|
227
|
-
default:
|
|
228
|
-
break
|
|
229
|
-
}
|
|
230
|
-
},
|
|
231
|
-
[onVolumeChange, volume],
|
|
232
|
-
)
|
|
233
|
-
|
|
234
330
|
const hasHandler = onVolumeChange && showHandler
|
|
235
331
|
|
|
236
332
|
const meterClassName = [
|
|
@@ -241,11 +337,6 @@ export const InputLevelMeter = memo(function InputLevelMeter({
|
|
|
241
337
|
.filter(Boolean)
|
|
242
338
|
.join(' ')
|
|
243
339
|
|
|
244
|
-
const tooltipOpen = isPressed || thumbFocused || hoverOpen
|
|
245
|
-
|
|
246
|
-
const gainDbForAria =
|
|
247
|
-
volume <= 0 ? -96 : 20 * Math.log10(Math.max(volume, 1e-6))
|
|
248
|
-
|
|
249
340
|
return (
|
|
250
341
|
<div
|
|
251
342
|
className={styles.container}
|
|
@@ -261,30 +352,16 @@ export const InputLevelMeter = memo(function InputLevelMeter({
|
|
|
261
352
|
<MeterRow level={rightLevel} />
|
|
262
353
|
|
|
263
354
|
{hasHandler && (
|
|
264
|
-
<
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
role="slider"
|
|
275
|
-
tabIndex={0}
|
|
276
|
-
aria-label="Input gain"
|
|
277
|
-
aria-valuemin={-96}
|
|
278
|
-
aria-valuemax={MAX_BOOST_DB}
|
|
279
|
-
aria-valuenow={Math.round(gainDbForAria * 10) / 10}
|
|
280
|
-
aria-valuetext={formatGainDb(volume)}
|
|
281
|
-
className={`${styles.thumb} ${isPressed ? styles.pressed : hover ? styles.hovered : ''}`}
|
|
282
|
-
style={{ left: `${faderPercent}%` }}
|
|
283
|
-
onFocus={() => setThumbFocused(true)}
|
|
284
|
-
onBlur={() => setThumbFocused(false)}
|
|
285
|
-
onKeyDown={handleThumbKeyDown}
|
|
286
|
-
/>
|
|
287
|
-
</Tooltip>
|
|
355
|
+
<MeterThumb
|
|
356
|
+
ref={thumbRef}
|
|
357
|
+
faderPercent={faderPercent}
|
|
358
|
+
isPressed={isPressed}
|
|
359
|
+
hover={hover}
|
|
360
|
+
volume={volume}
|
|
361
|
+
doubleTapStateRef={thumbDoubleTapStateRef}
|
|
362
|
+
onVolumeChange={onVolumeChange}
|
|
363
|
+
onVolumeReset={onVolumeReset}
|
|
364
|
+
/>
|
|
288
365
|
)}
|
|
289
366
|
|
|
290
367
|
<div
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
2
|
import { InputLevelMeter } from './InputLevelMeter'
|
|
3
3
|
import { useSimulatedInputLevel } from './useSimulatedInputLevel'
|
|
4
4
|
|
|
@@ -47,12 +47,18 @@ function InteractiveMeter({ initialVolume = 1, ...props }) {
|
|
|
47
47
|
linear={linear}
|
|
48
48
|
volume={volume}
|
|
49
49
|
onVolumeChange={handleVolumeChange}
|
|
50
|
+
onVolumeReset={() => setVolume(1)}
|
|
50
51
|
{...props}
|
|
51
52
|
/>
|
|
52
53
|
<span
|
|
53
|
-
style={{
|
|
54
|
+
style={{
|
|
55
|
+
color: 'rgba(255,255,255,0.5)',
|
|
56
|
+
fontSize: '11px',
|
|
57
|
+
fontFamily: 'monospace',
|
|
58
|
+
}}
|
|
54
59
|
>
|
|
55
|
-
gain: {volume.toFixed(3)} | dB:
|
|
60
|
+
gain: {volume.toFixed(3)} | dB:{' '}
|
|
61
|
+
{volume > 0 ? (20 * Math.log10(volume)).toFixed(1) : '-∞'}
|
|
56
62
|
</span>
|
|
57
63
|
</div>
|
|
58
64
|
)
|
|
@@ -152,13 +158,29 @@ export const HoverState = {
|
|
|
152
158
|
render: () => (
|
|
153
159
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
154
160
|
<div>
|
|
155
|
-
<span
|
|
161
|
+
<span
|
|
162
|
+
style={{
|
|
163
|
+
color: 'rgba(255,255,255,0.4)',
|
|
164
|
+
fontSize: '10px',
|
|
165
|
+
fontFamily: 'monospace',
|
|
166
|
+
display: 'block',
|
|
167
|
+
marginBottom: '4px',
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
156
170
|
Default
|
|
157
171
|
</span>
|
|
158
172
|
<AnimatedMeter />
|
|
159
173
|
</div>
|
|
160
174
|
<div>
|
|
161
|
-
<span
|
|
175
|
+
<span
|
|
176
|
+
style={{
|
|
177
|
+
color: 'rgba(255,255,255,0.4)',
|
|
178
|
+
fontSize: '10px',
|
|
179
|
+
fontFamily: 'monospace',
|
|
180
|
+
display: 'block',
|
|
181
|
+
marginBottom: '4px',
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
162
184
|
hover=true (parent hovered)
|
|
163
185
|
</span>
|
|
164
186
|
<AnimatedMeter hover />
|
|
@@ -258,13 +280,15 @@ export const MultipleMeters = {
|
|
|
258
280
|
const linear = useSimulatedInputLevel()
|
|
259
281
|
const [volumes, setVolumes] = useState([1, 0.7, 0.4, 0.1])
|
|
260
282
|
|
|
261
|
-
const makeHandler =
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
283
|
+
const makeHandler =
|
|
284
|
+
(idx) =>
|
|
285
|
+
([v]) => {
|
|
286
|
+
setVolumes((prev) => {
|
|
287
|
+
const next = [...prev]
|
|
288
|
+
next[idx] = v
|
|
289
|
+
return next
|
|
290
|
+
})
|
|
291
|
+
}
|
|
268
292
|
|
|
269
293
|
const labels = ['Master', 'Vocals', 'Guitar', 'Drums']
|
|
270
294
|
|