@moises.ai/design-system 4.16.10 → 4.16.11
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/{ChordDiagramGridIcon-CxpGQmg4.js → DynamicMicrophone2Icon-BBVZw0ZO.js} +794 -782
- package/dist/icons.js +484 -483
- package/dist/index.js +5450 -5769
- package/package.json +1 -1
- package/src/components/DropdownButton/DropdownButton.jsx +7 -0
- package/src/components/DropdownButton/DropdownButton.stories.jsx +4 -1
- package/src/components/InstrumentSelector/InstrumentSelector.stories.jsx +9 -1
- package/src/components/MessageWithAction/MessageWithAction.jsx +7 -0
- package/src/components/MessageWithAction/MessageWithAction.stories.jsx +4 -1
- package/src/components/TrackControlsToggle/TrackControlsToggle.stories.jsx +7 -3
- package/src/icons/DynamicMicrophone2Icon.jsx +13 -0
- package/src/icons.jsx +1 -0
- package/src/index.jsx +2 -2
- package/src/components/PlayerBar/PlayerBar.jsx +0 -250
- package/src/components/PlayerBar/PlayerBar.module.css +0 -135
- package/src/components/PlayerBar/PlayerBar.stories.jsx +0 -519
- package/src/components/PlayerMasterVolume/PlayerMasterVolume.jsx +0 -54
- package/src/components/PlayerMasterVolume/PlayerMasterVolume.module.css +0 -31
- package/src/components/PlayerMasterVolume/PlayerMasterVolume.stories.jsx +0 -182
- package/src/components/PlayerSlider/PlayerSlider.jsx +0 -80
- package/src/components/PlayerSlider/PlayerSlider.module.css +0 -180
- package/src/components/PlayerSlider/PlayerSlider.stories.jsx +0 -97
- package/src/components/PlayerSlider/PlayerSliderWaveform.jsx +0 -70
- package/src/components/PlayerSmartMetronome/PlayerSmartMetronome.jsx +0 -79
- package/src/components/PlayerSmartMetronome/PlayerSmartMetronome.module.css +0 -23
- package/src/components/PlayerSmartMetronome/PlayerSmartMetronome.stories.jsx +0 -225
- package/src/components/PlayerSmartMetronome/SegmentedField.jsx +0 -19
- package/src/components/PlayerTempoPitch/PlayerTempoPitch.jsx +0 -123
- package/src/components/PlayerTempoPitch/PlayerTempoPitch.module.css +0 -25
- package/src/components/PlayerTempoPitch/PlayerTempoPitch.stories.jsx +0 -215
- package/src/components/PlayerTempoPitch/StepperField.jsx +0 -57
- package/src/components/PlayerTempoPitch/constants.js +0 -40
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react'
|
|
2
|
-
import { PlayerSmartMetronome } from './PlayerSmartMetronome'
|
|
3
|
-
|
|
4
|
-
const DEFAULTS = {
|
|
5
|
-
subDivision: '1x',
|
|
6
|
-
volume: 50,
|
|
7
|
-
countIn: 'off',
|
|
8
|
-
panValue: 0,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function StatefulPlayerSmartMetronome({
|
|
12
|
-
initialSubDivision = DEFAULTS.subDivision,
|
|
13
|
-
initialVolume = DEFAULTS.volume,
|
|
14
|
-
initialCountIn = DEFAULTS.countIn,
|
|
15
|
-
initialPanValue = DEFAULTS.panValue,
|
|
16
|
-
onSubDivisionChange,
|
|
17
|
-
onVolumeChange,
|
|
18
|
-
onCountInChange,
|
|
19
|
-
onPanChange,
|
|
20
|
-
onRefresh,
|
|
21
|
-
}) {
|
|
22
|
-
const [subDivision, setSubDivision] = useState(initialSubDivision)
|
|
23
|
-
const [volume, setVolume] = useState(initialVolume)
|
|
24
|
-
const [countIn, setCountIn] = useState(initialCountIn)
|
|
25
|
-
const [panValue, setPanValue] = useState(initialPanValue)
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
setSubDivision(initialSubDivision)
|
|
29
|
-
}, [initialSubDivision])
|
|
30
|
-
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
setVolume(initialVolume)
|
|
33
|
-
}, [initialVolume])
|
|
34
|
-
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
setCountIn(initialCountIn)
|
|
37
|
-
}, [initialCountIn])
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
setPanValue(initialPanValue)
|
|
41
|
-
}, [initialPanValue])
|
|
42
|
-
|
|
43
|
-
const handleRefresh = useCallback(() => {
|
|
44
|
-
setSubDivision(DEFAULTS.subDivision)
|
|
45
|
-
setVolume(DEFAULTS.volume)
|
|
46
|
-
setCountIn(DEFAULTS.countIn)
|
|
47
|
-
setPanValue(DEFAULTS.panValue)
|
|
48
|
-
onRefresh?.()
|
|
49
|
-
}, [onRefresh])
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<PlayerSmartMetronome
|
|
53
|
-
subDivision={subDivision}
|
|
54
|
-
volume={volume}
|
|
55
|
-
countIn={countIn}
|
|
56
|
-
panValue={panValue}
|
|
57
|
-
onSubDivisionChange={(value) => {
|
|
58
|
-
setSubDivision(value)
|
|
59
|
-
onSubDivisionChange?.(value)
|
|
60
|
-
}}
|
|
61
|
-
onVolumeChange={(value) => {
|
|
62
|
-
setVolume(value)
|
|
63
|
-
onVolumeChange?.(value)
|
|
64
|
-
}}
|
|
65
|
-
onCountInChange={(value) => {
|
|
66
|
-
setCountIn(value)
|
|
67
|
-
onCountInChange?.(value)
|
|
68
|
-
}}
|
|
69
|
-
onPanChange={(value) => {
|
|
70
|
-
setPanValue(value)
|
|
71
|
-
onPanChange?.(value)
|
|
72
|
-
}}
|
|
73
|
-
onRefresh={handleRefresh}
|
|
74
|
-
/>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export default {
|
|
79
|
-
title: 'New Mixer/PlayerSmartMetronome',
|
|
80
|
-
component: PlayerSmartMetronome,
|
|
81
|
-
parameters: {
|
|
82
|
-
layout: 'centered',
|
|
83
|
-
docs: {
|
|
84
|
-
description: {
|
|
85
|
-
component: `
|
|
86
|
-
Smart metronome panel for New Mixer. Control sub-division, volume, pan and count-in via props and their change handlers.
|
|
87
|
-
`,
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
decorators: [
|
|
92
|
-
(Story) => (
|
|
93
|
-
<div
|
|
94
|
-
style={{
|
|
95
|
-
width: 258,
|
|
96
|
-
padding: 16,
|
|
97
|
-
background: '#1d1d1d',
|
|
98
|
-
borderRadius: 8,
|
|
99
|
-
boxSizing: 'border-box',
|
|
100
|
-
}}
|
|
101
|
-
>
|
|
102
|
-
<Story />
|
|
103
|
-
</div>
|
|
104
|
-
),
|
|
105
|
-
],
|
|
106
|
-
tags: ['autodocs'],
|
|
107
|
-
argTypes: {
|
|
108
|
-
subDivision: {
|
|
109
|
-
description: 'Selected sub-division multiplier.',
|
|
110
|
-
table: { type: { summary: "'0.5x' | '1x' | '2x'" }, defaultValue: { summary: '1x' } },
|
|
111
|
-
control: 'select',
|
|
112
|
-
options: ['0.5x', '1x', '2x'],
|
|
113
|
-
},
|
|
114
|
-
volume: {
|
|
115
|
-
description: 'Metronome volume percentage (0–100).',
|
|
116
|
-
table: { type: { summary: 'number' }, defaultValue: { summary: 50 } },
|
|
117
|
-
control: { type: 'range', min: 0, max: 100, step: 1 },
|
|
118
|
-
},
|
|
119
|
-
countIn: {
|
|
120
|
-
description: 'Count-in bars before playback.',
|
|
121
|
-
table: { type: { summary: "'off' | '1 bar' | '2 bars'" }, defaultValue: { summary: 'off' } },
|
|
122
|
-
control: 'select',
|
|
123
|
-
options: ['off', '1 bar', '2 bars'],
|
|
124
|
-
},
|
|
125
|
-
panValue: {
|
|
126
|
-
description: 'Pan position passed to PanControl.',
|
|
127
|
-
table: { type: { summary: 'number' }, defaultValue: { summary: 0 } },
|
|
128
|
-
control: { type: 'range', min: -1, max: 1, step: 0.01 },
|
|
129
|
-
},
|
|
130
|
-
onSubDivisionChange: {
|
|
131
|
-
table: { type: { summary: '(value: string) => void' } },
|
|
132
|
-
action: 'sub-division changed',
|
|
133
|
-
},
|
|
134
|
-
onVolumeChange: {
|
|
135
|
-
table: { type: { summary: '(value: number) => void' } },
|
|
136
|
-
action: 'volume changed',
|
|
137
|
-
},
|
|
138
|
-
onCountInChange: {
|
|
139
|
-
table: { type: { summary: '(value: string) => void' } },
|
|
140
|
-
action: 'count-in changed',
|
|
141
|
-
},
|
|
142
|
-
onPanChange: {
|
|
143
|
-
table: { type: { summary: '(value: number) => void' } },
|
|
144
|
-
action: 'pan changed',
|
|
145
|
-
},
|
|
146
|
-
onRefresh: {
|
|
147
|
-
table: { type: { summary: '() => void' } },
|
|
148
|
-
action: 'refreshed',
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export const Default = {
|
|
154
|
-
render: (args) => (
|
|
155
|
-
<StatefulPlayerSmartMetronome
|
|
156
|
-
initialSubDivision={args.subDivision}
|
|
157
|
-
initialVolume={args.volume}
|
|
158
|
-
initialCountIn={args.countIn}
|
|
159
|
-
initialPanValue={args.panValue}
|
|
160
|
-
onSubDivisionChange={args.onSubDivisionChange}
|
|
161
|
-
onVolumeChange={args.onVolumeChange}
|
|
162
|
-
onCountInChange={args.onCountInChange}
|
|
163
|
-
onPanChange={args.onPanChange}
|
|
164
|
-
onRefresh={args.onRefresh}
|
|
165
|
-
/>
|
|
166
|
-
),
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export const HalfSubDivision = {
|
|
170
|
-
args: {
|
|
171
|
-
subDivision: '0.5x',
|
|
172
|
-
volume: 75,
|
|
173
|
-
},
|
|
174
|
-
render: (args) => (
|
|
175
|
-
<StatefulPlayerSmartMetronome
|
|
176
|
-
initialSubDivision={args.subDivision}
|
|
177
|
-
initialVolume={args.volume}
|
|
178
|
-
onSubDivisionChange={args.onSubDivisionChange}
|
|
179
|
-
onVolumeChange={args.onVolumeChange}
|
|
180
|
-
onCountInChange={args.onCountInChange}
|
|
181
|
-
onPanChange={args.onPanChange}
|
|
182
|
-
onRefresh={args.onRefresh}
|
|
183
|
-
/>
|
|
184
|
-
),
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export const WithCountIn = {
|
|
188
|
-
args: {
|
|
189
|
-
countIn: '2 bars',
|
|
190
|
-
volume: 80,
|
|
191
|
-
},
|
|
192
|
-
render: (args) => (
|
|
193
|
-
<StatefulPlayerSmartMetronome
|
|
194
|
-
initialCountIn={args.countIn}
|
|
195
|
-
initialVolume={args.volume}
|
|
196
|
-
onSubDivisionChange={args.onSubDivisionChange}
|
|
197
|
-
onVolumeChange={args.onVolumeChange}
|
|
198
|
-
onCountInChange={args.onCountInChange}
|
|
199
|
-
onPanChange={args.onPanChange}
|
|
200
|
-
onRefresh={args.onRefresh}
|
|
201
|
-
/>
|
|
202
|
-
),
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export const Playground = {
|
|
206
|
-
args: {
|
|
207
|
-
subDivision: '1x',
|
|
208
|
-
volume: 50,
|
|
209
|
-
countIn: 'off',
|
|
210
|
-
panValue: 0,
|
|
211
|
-
},
|
|
212
|
-
render: (args) => (
|
|
213
|
-
<StatefulPlayerSmartMetronome
|
|
214
|
-
initialSubDivision={args.subDivision}
|
|
215
|
-
initialVolume={args.volume}
|
|
216
|
-
initialCountIn={args.countIn}
|
|
217
|
-
initialPanValue={args.panValue}
|
|
218
|
-
onSubDivisionChange={args.onSubDivisionChange}
|
|
219
|
-
onVolumeChange={args.onVolumeChange}
|
|
220
|
-
onCountInChange={args.onCountInChange}
|
|
221
|
-
onPanChange={args.onPanChange}
|
|
222
|
-
onRefresh={args.onRefresh}
|
|
223
|
-
/>
|
|
224
|
-
),
|
|
225
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Flex, Text, SegmentedControl } from '../../index'
|
|
2
|
-
import styles from './PlayerSmartMetronome.module.css'
|
|
3
|
-
|
|
4
|
-
export function SegmentedField({ label, items, value, onChange }) {
|
|
5
|
-
return (
|
|
6
|
-
<Flex direction="column" gap="1">
|
|
7
|
-
<Text size="2" className={styles.neutral12}>
|
|
8
|
-
{label}
|
|
9
|
-
</Text>
|
|
10
|
-
|
|
11
|
-
<SegmentedControl
|
|
12
|
-
items={items}
|
|
13
|
-
selectedType={value}
|
|
14
|
-
handleTypeChange={onChange}
|
|
15
|
-
size="2"
|
|
16
|
-
/>
|
|
17
|
-
</Flex>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Flex, Separator, Text, IconButton, Select } from '../../index'
|
|
2
|
-
import styles from './PlayerTempoPitch.module.css'
|
|
3
|
-
import { RefreshBackIcon } from '../../icons'
|
|
4
|
-
import { MIN_VALUE_BPM, MAX_VALUE_BPM, TEMPO_RANGES, PITCH_ITEMS, TUNING_ITEMS } from './constants'
|
|
5
|
-
import { StepperField } from './StepperField'
|
|
6
|
-
|
|
7
|
-
export const PlayerTempoPitch = ({
|
|
8
|
-
tempo = 120,
|
|
9
|
-
pitch = 'C#',
|
|
10
|
-
tuning = 440,
|
|
11
|
-
onTempoChange,
|
|
12
|
-
onPitchChange,
|
|
13
|
-
onTuningChange,
|
|
14
|
-
onRefresh,
|
|
15
|
-
}) => {
|
|
16
|
-
const handleTempoChange = (e) => {
|
|
17
|
-
const raw = e.target.value
|
|
18
|
-
|
|
19
|
-
if (raw === '') {
|
|
20
|
-
onTempoChange?.('')
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const parsed = Number(raw)
|
|
25
|
-
if (Number.isNaN(parsed)) return
|
|
26
|
-
|
|
27
|
-
onTempoChange?.(parsed)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const handleTempoBlur = () => {
|
|
31
|
-
const clamped = Math.min(
|
|
32
|
-
MAX_VALUE_BPM,
|
|
33
|
-
Math.max(MIN_VALUE_BPM, Number(tempo) || MIN_VALUE_BPM),
|
|
34
|
-
)
|
|
35
|
-
onTempoChange?.(clamped)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const handleTempoDecrease = () => {
|
|
39
|
-
onTempoChange?.(Math.max(MIN_VALUE_BPM, tempo - 1))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const handleTempoIncrease = () => {
|
|
43
|
-
onTempoChange?.(Math.min(MAX_VALUE_BPM, tempo + 1))
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handlePitchChange = (e) => {
|
|
47
|
-
onPitchChange?.(e.target.value)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const handlePitchBlur = () => {
|
|
51
|
-
const exists = PITCH_ITEMS.find((item) => item.value === pitch)
|
|
52
|
-
if (!exists) onPitchChange?.(PITCH_ITEMS[0].value)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const handlePitchDecrease = () => {
|
|
56
|
-
const currentIndex = PITCH_ITEMS.findIndex((item) => item.value === pitch)
|
|
57
|
-
if (currentIndex > 0) onPitchChange?.(PITCH_ITEMS[currentIndex - 1].value)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const handlePitchIncrease = () => {
|
|
61
|
-
const currentIndex = PITCH_ITEMS.findIndex((item) => item.value === pitch)
|
|
62
|
-
if (currentIndex < PITCH_ITEMS.length - 1) {
|
|
63
|
-
onPitchChange?.(PITCH_ITEMS[currentIndex + 1].value)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<Flex direction="column" gap="4">
|
|
69
|
-
<Flex align="center" gap="2" justify="between">
|
|
70
|
-
<Text size="3" weight="medium" className={styles.white}>
|
|
71
|
-
Tempo & Pitch
|
|
72
|
-
</Text>
|
|
73
|
-
|
|
74
|
-
<IconButton variant="ghost" size="1" onClick={onRefresh}>
|
|
75
|
-
<RefreshBackIcon width={16} height={16} />
|
|
76
|
-
</IconButton>
|
|
77
|
-
</Flex>
|
|
78
|
-
|
|
79
|
-
<StepperField
|
|
80
|
-
label="Tempo change"
|
|
81
|
-
hint={TEMPO_RANGES.find((item) => item.maxBpm >= tempo)?.marking}
|
|
82
|
-
value={tempo}
|
|
83
|
-
onChange={handleTempoChange}
|
|
84
|
-
onBlur={handleTempoBlur}
|
|
85
|
-
onDecrease={handleTempoDecrease}
|
|
86
|
-
onIncrease={handleTempoIncrease}
|
|
87
|
-
disableDecrease={tempo <= MIN_VALUE_BPM}
|
|
88
|
-
disableIncrease={tempo >= MAX_VALUE_BPM}
|
|
89
|
-
/>
|
|
90
|
-
|
|
91
|
-
<Separator size="4" className={styles.neutralAlpha4} />
|
|
92
|
-
|
|
93
|
-
<StepperField
|
|
94
|
-
label="Pitch change"
|
|
95
|
-
value={pitch}
|
|
96
|
-
onChange={handlePitchChange}
|
|
97
|
-
onBlur={handlePitchBlur}
|
|
98
|
-
onDecrease={handlePitchDecrease}
|
|
99
|
-
onIncrease={handlePitchIncrease}
|
|
100
|
-
disableDecrease={pitch === PITCH_ITEMS[0].value}
|
|
101
|
-
disableIncrease={pitch === PITCH_ITEMS[PITCH_ITEMS.length - 1].value}
|
|
102
|
-
/>
|
|
103
|
-
|
|
104
|
-
<Flex direction="column" gap="1">
|
|
105
|
-
<Text size="2" className={styles.neutral12}>
|
|
106
|
-
Tuning (Hz)
|
|
107
|
-
</Text>
|
|
108
|
-
|
|
109
|
-
<Select
|
|
110
|
-
value={tuning}
|
|
111
|
-
onChange={onTuningChange}
|
|
112
|
-
items={TUNING_ITEMS}
|
|
113
|
-
placeholder="Select tuning"
|
|
114
|
-
size="2"
|
|
115
|
-
variant="soft"
|
|
116
|
-
maxHeight="300px"
|
|
117
|
-
/>
|
|
118
|
-
</Flex>
|
|
119
|
-
</Flex>
|
|
120
|
-
)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
PlayerTempoPitch.displayName = 'PlayerTempoPitch'
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
.PlayerTempoPitch {
|
|
2
|
-
background-color: var(--neutral-alpha-2);
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
.neutral12 {
|
|
6
|
-
color: var(--neutral-12);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.neutralAlpha9 {
|
|
10
|
-
color: var(--neutral-alpha-9);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.neutralAlpha4 {
|
|
14
|
-
color: var(--neutral-alpha-4);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.white {
|
|
18
|
-
color: var(--white);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.customTextField {
|
|
22
|
-
input {
|
|
23
|
-
text-align: center;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react'
|
|
2
|
-
import { PlayerTempoPitch } from './PlayerTempoPitch'
|
|
3
|
-
import { MAX_VALUE_BPM, MIN_VALUE_BPM } from './constants'
|
|
4
|
-
|
|
5
|
-
const DEFAULTS = {
|
|
6
|
-
tempo: 120,
|
|
7
|
-
pitch: 'C#',
|
|
8
|
-
tuning: 440,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function StatefulPlayerTempoPitch({
|
|
12
|
-
initialTempo = DEFAULTS.tempo,
|
|
13
|
-
initialPitch = DEFAULTS.pitch,
|
|
14
|
-
initialTuning = DEFAULTS.tuning,
|
|
15
|
-
onTempoChange,
|
|
16
|
-
onPitchChange,
|
|
17
|
-
onTuningChange,
|
|
18
|
-
onRefresh,
|
|
19
|
-
}) {
|
|
20
|
-
const [tempo, setTempo] = useState(initialTempo)
|
|
21
|
-
const [pitch, setPitch] = useState(initialPitch)
|
|
22
|
-
const [tuning, setTuning] = useState(initialTuning)
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
setTempo(initialTempo)
|
|
26
|
-
}, [initialTempo])
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
setPitch(initialPitch)
|
|
30
|
-
}, [initialPitch])
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
setTuning(initialTuning)
|
|
34
|
-
}, [initialTuning])
|
|
35
|
-
|
|
36
|
-
const handleRefresh = useCallback(() => {
|
|
37
|
-
setTempo(DEFAULTS.tempo)
|
|
38
|
-
setPitch(DEFAULTS.pitch)
|
|
39
|
-
setTuning(DEFAULTS.tuning)
|
|
40
|
-
onRefresh?.()
|
|
41
|
-
}, [onRefresh])
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<PlayerTempoPitch
|
|
45
|
-
tempo={tempo}
|
|
46
|
-
pitch={pitch}
|
|
47
|
-
tuning={tuning}
|
|
48
|
-
onTempoChange={(value) => {
|
|
49
|
-
setTempo(value)
|
|
50
|
-
onTempoChange?.(value)
|
|
51
|
-
}}
|
|
52
|
-
onPitchChange={(value) => {
|
|
53
|
-
setPitch(value)
|
|
54
|
-
onPitchChange?.(value)
|
|
55
|
-
}}
|
|
56
|
-
onTuningChange={(value) => {
|
|
57
|
-
setTuning(value)
|
|
58
|
-
onTuningChange?.(value)
|
|
59
|
-
}}
|
|
60
|
-
onRefresh={handleRefresh}
|
|
61
|
-
/>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export default {
|
|
66
|
-
title: 'New Mixer/PlayerTempoPitch',
|
|
67
|
-
component: PlayerTempoPitch,
|
|
68
|
-
parameters: {
|
|
69
|
-
layout: 'centered',
|
|
70
|
-
docs: {
|
|
71
|
-
description: {
|
|
72
|
-
component: `
|
|
73
|
-
Tempo and pitch panel for New Mixer. Pass \`tempo\`, \`pitch\` and \`tuning\`, then update them from their change handlers. The refresh button resets to defaults.
|
|
74
|
-
`,
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
decorators: [
|
|
79
|
-
(Story) => (
|
|
80
|
-
<div
|
|
81
|
-
style={{
|
|
82
|
-
width: 258,
|
|
83
|
-
padding: 16,
|
|
84
|
-
background: '#1d1d1d',
|
|
85
|
-
borderRadius: 8,
|
|
86
|
-
boxSizing: 'border-box',
|
|
87
|
-
}}
|
|
88
|
-
>
|
|
89
|
-
<Story />
|
|
90
|
-
</div>
|
|
91
|
-
),
|
|
92
|
-
],
|
|
93
|
-
tags: ['autodocs'],
|
|
94
|
-
argTypes: {
|
|
95
|
-
tempo: {
|
|
96
|
-
description: `Tempo in BPM (${MIN_VALUE_BPM}–${MAX_VALUE_BPM}).`,
|
|
97
|
-
table: { type: { summary: 'number' }, defaultValue: { summary: 120 } },
|
|
98
|
-
control: { type: 'range', min: MIN_VALUE_BPM, max: MAX_VALUE_BPM, step: 1 },
|
|
99
|
-
},
|
|
100
|
-
pitch: {
|
|
101
|
-
description: 'Selected pitch note.',
|
|
102
|
-
table: { type: { summary: 'string' }, defaultValue: { summary: 'C#' } },
|
|
103
|
-
control: 'select',
|
|
104
|
-
options: ['C', 'C#', 'D', 'D#', 'E'],
|
|
105
|
-
},
|
|
106
|
-
tuning: {
|
|
107
|
-
description: 'Reference tuning in Hz.',
|
|
108
|
-
table: { type: { summary: 'number' }, defaultValue: { summary: 440 } },
|
|
109
|
-
control: 'select',
|
|
110
|
-
options: [440, 442, 444, 446],
|
|
111
|
-
},
|
|
112
|
-
onTempoChange: {
|
|
113
|
-
table: { type: { summary: '(tempo: number | "") => void' } },
|
|
114
|
-
action: 'tempo changed',
|
|
115
|
-
},
|
|
116
|
-
onPitchChange: {
|
|
117
|
-
table: { type: { summary: '(pitch: string) => void' } },
|
|
118
|
-
action: 'pitch changed',
|
|
119
|
-
},
|
|
120
|
-
onTuningChange: {
|
|
121
|
-
table: { type: { summary: '(tuning: number) => void' } },
|
|
122
|
-
action: 'tuning changed',
|
|
123
|
-
},
|
|
124
|
-
onRefresh: {
|
|
125
|
-
table: { type: { summary: '() => void' } },
|
|
126
|
-
action: 'refreshed',
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export const Default = {
|
|
132
|
-
render: (args) => (
|
|
133
|
-
<StatefulPlayerTempoPitch
|
|
134
|
-
initialTempo={args.tempo}
|
|
135
|
-
initialPitch={args.pitch}
|
|
136
|
-
initialTuning={args.tuning}
|
|
137
|
-
onTempoChange={args.onTempoChange}
|
|
138
|
-
onPitchChange={args.onPitchChange}
|
|
139
|
-
onTuningChange={args.onTuningChange}
|
|
140
|
-
onRefresh={args.onRefresh}
|
|
141
|
-
/>
|
|
142
|
-
),
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export const SlowTempo = {
|
|
146
|
-
args: {
|
|
147
|
-
tempo: 60,
|
|
148
|
-
pitch: 'C',
|
|
149
|
-
},
|
|
150
|
-
render: (args) => (
|
|
151
|
-
<StatefulPlayerTempoPitch
|
|
152
|
-
initialTempo={args.tempo}
|
|
153
|
-
initialPitch={args.pitch}
|
|
154
|
-
initialTuning={args.tuning}
|
|
155
|
-
onTempoChange={args.onTempoChange}
|
|
156
|
-
onPitchChange={args.onPitchChange}
|
|
157
|
-
onTuningChange={args.onTuningChange}
|
|
158
|
-
onRefresh={args.onRefresh}
|
|
159
|
-
/>
|
|
160
|
-
),
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export const FastTempo = {
|
|
164
|
-
args: {
|
|
165
|
-
tempo: 180,
|
|
166
|
-
pitch: 'E',
|
|
167
|
-
},
|
|
168
|
-
render: (args) => (
|
|
169
|
-
<StatefulPlayerTempoPitch
|
|
170
|
-
initialTempo={args.tempo}
|
|
171
|
-
initialPitch={args.pitch}
|
|
172
|
-
initialTuning={args.tuning}
|
|
173
|
-
onTempoChange={args.onTempoChange}
|
|
174
|
-
onPitchChange={args.onPitchChange}
|
|
175
|
-
onTuningChange={args.onTuningChange}
|
|
176
|
-
onRefresh={args.onRefresh}
|
|
177
|
-
/>
|
|
178
|
-
),
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export const AlternateTuning = {
|
|
182
|
-
args: {
|
|
183
|
-
tuning: 442,
|
|
184
|
-
},
|
|
185
|
-
render: (args) => (
|
|
186
|
-
<StatefulPlayerTempoPitch
|
|
187
|
-
initialTempo={args.tempo}
|
|
188
|
-
initialPitch={args.pitch}
|
|
189
|
-
initialTuning={args.tuning}
|
|
190
|
-
onTempoChange={args.onTempoChange}
|
|
191
|
-
onPitchChange={args.onPitchChange}
|
|
192
|
-
onTuningChange={args.onTuningChange}
|
|
193
|
-
onRefresh={args.onRefresh}
|
|
194
|
-
/>
|
|
195
|
-
),
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export const Playground = {
|
|
199
|
-
args: {
|
|
200
|
-
tempo: 120,
|
|
201
|
-
pitch: 'C#',
|
|
202
|
-
tuning: 440,
|
|
203
|
-
},
|
|
204
|
-
render: (args) => (
|
|
205
|
-
<StatefulPlayerTempoPitch
|
|
206
|
-
initialTempo={args.tempo}
|
|
207
|
-
initialPitch={args.pitch}
|
|
208
|
-
initialTuning={args.tuning}
|
|
209
|
-
onTempoChange={args.onTempoChange}
|
|
210
|
-
onPitchChange={args.onPitchChange}
|
|
211
|
-
onTuningChange={args.onTuningChange}
|
|
212
|
-
onRefresh={args.onRefresh}
|
|
213
|
-
/>
|
|
214
|
-
),
|
|
215
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Flex, Text, IconButton, TextField } from '../../index'
|
|
2
|
-
import { MinusIcon, PlusIcon } from '../../icons'
|
|
3
|
-
import styles from './PlayerTempoPitch.module.css'
|
|
4
|
-
|
|
5
|
-
export function StepperField({
|
|
6
|
-
label,
|
|
7
|
-
hint,
|
|
8
|
-
value,
|
|
9
|
-
onChange,
|
|
10
|
-
onBlur,
|
|
11
|
-
onDecrease,
|
|
12
|
-
onIncrease,
|
|
13
|
-
disableDecrease,
|
|
14
|
-
disableIncrease,
|
|
15
|
-
}) {
|
|
16
|
-
return (
|
|
17
|
-
<Flex direction="column" gap="1">
|
|
18
|
-
<Flex width="100%" justify="between" align="center">
|
|
19
|
-
<Text size="2" className={styles.neutral12}>
|
|
20
|
-
{label}
|
|
21
|
-
</Text>
|
|
22
|
-
|
|
23
|
-
{hint && (
|
|
24
|
-
<Text size="2" className={styles.neutralAlpha9}>
|
|
25
|
-
{hint}
|
|
26
|
-
</Text>
|
|
27
|
-
)}
|
|
28
|
-
</Flex>
|
|
29
|
-
|
|
30
|
-
<Flex gap="1" align="center" justify="center">
|
|
31
|
-
<IconButton
|
|
32
|
-
className={styles.button}
|
|
33
|
-
variant="soft"
|
|
34
|
-
size="2"
|
|
35
|
-
onClick={onDecrease}
|
|
36
|
-
disabled={disableDecrease}
|
|
37
|
-
>
|
|
38
|
-
<MinusIcon width={16} height={16} />
|
|
39
|
-
</IconButton>
|
|
40
|
-
|
|
41
|
-
<Flex className={styles.customTextField}>
|
|
42
|
-
<TextField size="2" value={value} onChange={onChange} onBlur={onBlur} />
|
|
43
|
-
</Flex>
|
|
44
|
-
|
|
45
|
-
<IconButton
|
|
46
|
-
className={styles.button}
|
|
47
|
-
variant="soft"
|
|
48
|
-
size="2"
|
|
49
|
-
onClick={onIncrease}
|
|
50
|
-
disabled={disableIncrease}
|
|
51
|
-
>
|
|
52
|
-
<PlusIcon width={16} height={16} />
|
|
53
|
-
</IconButton>
|
|
54
|
-
</Flex>
|
|
55
|
-
</Flex>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// TODO: remove this file when we have the right constants
|
|
2
|
-
export const MIN_VALUE_BPM = 30
|
|
3
|
-
export const MAX_VALUE_BPM = 200
|
|
4
|
-
|
|
5
|
-
export const TEMPO_RANGES = [
|
|
6
|
-
{ maxBpm: 19, marking: 'Larghissimo' },
|
|
7
|
-
{ maxBpm: 40, marking: 'Grave' },
|
|
8
|
-
{ maxBpm: 45, marking: 'Lento' },
|
|
9
|
-
{ maxBpm: 50, marking: 'Largo' },
|
|
10
|
-
{ maxBpm: 55, marking: 'Larghetto' },
|
|
11
|
-
{ maxBpm: 65, marking: 'Adagio' },
|
|
12
|
-
{ maxBpm: 69, marking: 'Adagietto' },
|
|
13
|
-
{ maxBpm: 72, marking: 'Andante Moderato' },
|
|
14
|
-
{ maxBpm: 77, marking: 'Andante' },
|
|
15
|
-
{ maxBpm: 83, marking: 'Andantino' },
|
|
16
|
-
{ maxBpm: 85, marking: 'Marcia Moderato' },
|
|
17
|
-
{ maxBpm: 97, marking: 'Moderato' },
|
|
18
|
-
{ maxBpm: 109, marking: 'Allegretto' },
|
|
19
|
-
{ maxBpm: 132, marking: 'Allegro' },
|
|
20
|
-
{ maxBpm: 140, marking: 'Vivace' },
|
|
21
|
-
{ maxBpm: 150, marking: 'Vivacissimo' },
|
|
22
|
-
{ maxBpm: 167, marking: 'Allegrissimo' },
|
|
23
|
-
{ maxBpm: 177, marking: 'Presto' },
|
|
24
|
-
{ maxBpm: Number.POSITIVE_INFINITY, marking: 'Prestissimo' },
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
export const PITCH_ITEMS = [
|
|
28
|
-
{ value: 'C', label: 'C' },
|
|
29
|
-
{ value: 'C#', label: 'C#' },
|
|
30
|
-
{ value: 'D', label: 'D' },
|
|
31
|
-
{ value: 'D#', label: 'D#' },
|
|
32
|
-
{ value: 'E', label: 'E' },
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
export const TUNING_ITEMS = [
|
|
36
|
-
{ value: 440, label: '440 Hz', aiDetected: true, extra: '(AI detected)' },
|
|
37
|
-
{ value: 442, label: '442 Hz' },
|
|
38
|
-
{ value: 444, label: '444 Hz' },
|
|
39
|
-
{ value: 446, label: '446 Hz' },
|
|
40
|
-
]
|