@moises.ai/design-system 3.11.2 → 3.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moises.ai/design-system",
3
- "version": "3.11.2",
3
+ "version": "3.11.4",
4
4
  "description": "Design System package based on @radix-ui/themes with custom defaults",
5
5
  "private": false,
6
6
  "type": "module",
@@ -0,0 +1,205 @@
1
+ import { memo, useCallback, useRef, useState } from 'react'
2
+ import styles from './InputLevelMeter.module.css'
3
+
4
+ const SEGMENT_MIN = 5
5
+ const SEGMENT_RANGE = 25
6
+ const UNITY_GAIN_POS = 0.667
7
+ const MAX_BOOST_DB = 6
8
+
9
+ function linearToMeterLevel(linear) {
10
+ const peakDb = 20 * Math.log10(Math.max(linear, 1e-6))
11
+ return Math.max(0, Math.min(30, (peakDb + 60) / 2))
12
+ }
13
+
14
+ function clampLevel(level) {
15
+ if (!Number.isFinite(level)) return 0
16
+ return Math.max(0, Math.min(30, level))
17
+ }
18
+
19
+ function clampPeakDb(peakDb) {
20
+ if (!Number.isFinite(peakDb)) return Number.NEGATIVE_INFINITY
21
+ return Math.max(-96, peakDb)
22
+ }
23
+
24
+ function getNormalizedLevel(level) {
25
+ return Math.max(
26
+ 0,
27
+ Math.min(100, ((clampLevel(level) - SEGMENT_MIN) / SEGMENT_RANGE) * 100),
28
+ )
29
+ }
30
+
31
+ function getPeakHoldColor(peakPct) {
32
+ if (peakPct >= 88) return 'rgba(254, 78, 84, 0.89)'
33
+ if (peakPct >= 69) return 'rgb(255, 197, 61)'
34
+ return '#00dae8'
35
+ }
36
+
37
+ function gainToFaderPosition(gain) {
38
+ if (gain <= 0) return 0
39
+ const db = 20 * Math.log10(gain)
40
+ if (db <= -96) return 0
41
+ if (db <= 0) return ((db + 96) / 96) * UNITY_GAIN_POS
42
+ return (
43
+ UNITY_GAIN_POS +
44
+ (Math.min(db, MAX_BOOST_DB) / MAX_BOOST_DB) * (1 - UNITY_GAIN_POS)
45
+ )
46
+ }
47
+
48
+ function faderPositionToGain(pos) {
49
+ if (pos <= 0) return 0
50
+ let db
51
+ if (pos <= UNITY_GAIN_POS) {
52
+ db = (pos / UNITY_GAIN_POS) * 96 - 96
53
+ } else {
54
+ db = ((pos - UNITY_GAIN_POS) / (1 - UNITY_GAIN_POS)) * MAX_BOOST_DB
55
+ }
56
+ return 10 ** (db / 20)
57
+ }
58
+
59
+ function MeterRow({ level }) {
60
+ const pct = getNormalizedLevel(level)
61
+ return (
62
+ <div className={styles.barRow}>
63
+ <div className={styles.barTrack} />
64
+ <div
65
+ className={styles.barFill}
66
+ style={{
67
+ width: `${pct}%`,
68
+ backgroundSize: pct > 0 ? `${10000 / pct}% 100%` : '100% 100%',
69
+ }}
70
+ />
71
+ </div>
72
+ )
73
+ }
74
+
75
+ export const InputLevelMeter = memo(function InputLevelMeter({
76
+ linear = [0, 0],
77
+ volume = 1,
78
+ onVolumeChange,
79
+ showHandler = true,
80
+ showMeter = true,
81
+ }) {
82
+ const [linearL, linearR] = linear
83
+ const leftLevel = clampLevel(linearToMeterLevel(linearL ?? 0))
84
+ const rightLevel = clampLevel(linearToMeterLevel(linearR ?? 0))
85
+
86
+ const [isPressed, setIsPressed] = useState(false)
87
+ const isPressedRef = useRef(false)
88
+ const meterRef = useRef(null)
89
+ const peakHoldRef = useRef(0)
90
+
91
+ const faderPercent = Math.max(
92
+ 0,
93
+ Math.min(100, gainToFaderPosition(volume) * 100),
94
+ )
95
+
96
+ const leftNormalized = getNormalizedLevel(leftLevel)
97
+ const rightNormalized = getNormalizedLevel(rightLevel)
98
+ const currentPeakPct = Math.max(leftNormalized, rightNormalized)
99
+
100
+ if (currentPeakPct > peakHoldRef.current) {
101
+ peakHoldRef.current = currentPeakPct
102
+ }
103
+ if (currentPeakPct <= 0) {
104
+ peakHoldRef.current = 0
105
+ }
106
+
107
+ const peakHoldPct = peakHoldRef.current
108
+ const peakHoldColor = getPeakHoldColor(peakHoldPct)
109
+ const showPeakHold = peakHoldPct > 0
110
+
111
+ const handlePointerDown = useCallback(
112
+ (e) => {
113
+ if (!onVolumeChange) return
114
+ e.currentTarget.setPointerCapture(e.pointerId)
115
+ isPressedRef.current = true
116
+ setIsPressed(true)
117
+ const rect = meterRef.current?.getBoundingClientRect()
118
+ if (rect) {
119
+ const pos = Math.max(
120
+ 0,
121
+ Math.min(1, (e.clientX - rect.left) / rect.width),
122
+ )
123
+ onVolumeChange([faderPositionToGain(pos)])
124
+ }
125
+ },
126
+ [onVolumeChange],
127
+ )
128
+
129
+ const handlePointerMove = useCallback(
130
+ (e) => {
131
+ if (!isPressedRef.current || !onVolumeChange) return
132
+ const rect = meterRef.current?.getBoundingClientRect()
133
+ if (rect) {
134
+ const pos = Math.max(
135
+ 0,
136
+ Math.min(1, (e.clientX - rect.left) / rect.width),
137
+ )
138
+ onVolumeChange([faderPositionToGain(pos)])
139
+ }
140
+ },
141
+ [onVolumeChange],
142
+ )
143
+
144
+ const handlePointerUp = useCallback(() => {
145
+ isPressedRef.current = false
146
+ setIsPressed(false)
147
+ }, [])
148
+
149
+ const meterClassName = [styles.bars, isPressed ? styles.pressed : '']
150
+ .filter(Boolean)
151
+ .join(' ')
152
+
153
+ const hasHandler = onVolumeChange && showHandler
154
+
155
+ return (
156
+ <div
157
+ className={styles.container}
158
+ onMouseLeave={() => {
159
+ if (!isPressed) setIsPressed(false)
160
+ }}
161
+ onPointerDown={handlePointerDown}
162
+ onPointerMove={handlePointerMove}
163
+ onPointerUp={handlePointerUp}
164
+ >
165
+ <div ref={meterRef} className={meterClassName}>
166
+ <MeterRow level={leftLevel} />
167
+ <MeterRow level={rightLevel} />
168
+
169
+ {hasHandler && (
170
+ <div
171
+ className={`${styles.thumb} ${isPressed ? styles.pressed : ''}`}
172
+ style={{ left: `${faderPercent}%` }}
173
+ />
174
+ )}
175
+
176
+ {showPeakHold && (
177
+ <>
178
+ <div
179
+ className={styles.peakDotTop}
180
+ style={{
181
+ left: `min(calc(${peakHoldPct}% + 3px), calc(100% - 3px))`,
182
+ background: peakHoldColor,
183
+ }}
184
+ />
185
+ <div
186
+ className={styles.peakDotBottom}
187
+ style={{
188
+ left: `min(calc(${peakHoldPct}% + 3px), calc(100% - 3px))`,
189
+ background: peakHoldColor,
190
+ }}
191
+ />
192
+ </>
193
+ )}
194
+ </div>
195
+
196
+ {showMeter && (
197
+ <div
198
+ className={`${styles.zeroDbDot} ${isPressed ? styles.pressed : ''}`}
199
+ />
200
+ )}
201
+ </div>
202
+ )
203
+ })
204
+
205
+ InputLevelMeter.displayName = 'InputLevelMeter'
@@ -0,0 +1,111 @@
1
+ .container {
2
+ position: relative;
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 4px;
6
+ align-items: flex-start;
7
+ width: 100%;
8
+ }
9
+
10
+ .bars {
11
+ position: relative;
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: 1px;
15
+ padding: 2px;
16
+ border-radius: 3px;
17
+ width: 100%;
18
+ background: rgba(216, 244, 246, 0.04);
19
+ transition: background-color 0.1s ease;
20
+ }
21
+
22
+ .bars.pressed {
23
+ background: rgba(221, 234, 248, 0.08);
24
+ }
25
+
26
+ .barRow {
27
+ display: inline-grid;
28
+ grid-template-rows: max-content;
29
+ place-items: start;
30
+ width: 100%;
31
+ position: relative;
32
+ line-height: 0;
33
+ }
34
+
35
+ .barTrack {
36
+ grid-column: 1;
37
+ grid-row: 1;
38
+ height: 3px;
39
+ width: 100%;
40
+ border-radius: 9999px;
41
+ }
42
+
43
+ .barFill {
44
+ grid-column: 1;
45
+ grid-row: 1;
46
+ height: 3px;
47
+ border-radius: 9999px;
48
+ background: linear-gradient(
49
+ 270deg,
50
+ rgba(254, 78, 84, 0.894) 12%,
51
+ rgb(255, 197, 61) 12%,
52
+ rgb(255, 197, 61) 31%,
53
+ rgb(0, 218, 232) 31%
54
+ );
55
+ will-change: width;
56
+ }
57
+
58
+ .thumb {
59
+ position: absolute;
60
+ top: 50%;
61
+ transform: translate(-50%, -50%);
62
+ width: 8px;
63
+ height: 19px;
64
+ border-radius: 9999px;
65
+ background: #edeef0;
66
+ cursor: ew-resize;
67
+ z-index: 2;
68
+ touch-action: none;
69
+ }
70
+
71
+ .thumb.pressed {
72
+ background: white;
73
+ }
74
+
75
+ .peakDot {
76
+ position: absolute;
77
+ width: 1px;
78
+ height: 3px;
79
+ border-radius: 9999px;
80
+ z-index: 1;
81
+ pointer-events: none;
82
+ }
83
+
84
+ .peakDotTop {
85
+ composes: peakDot;
86
+ top: calc(50% - 2px);
87
+ transform: translate(-50%, -50%);
88
+ }
89
+
90
+ .peakDotBottom {
91
+ composes: peakDot;
92
+ top: calc(50% + 2px);
93
+ transform: translate(-50%, -50%);
94
+ }
95
+
96
+ .zeroDbDot {
97
+ position: absolute;
98
+ left: 66.7%;
99
+ top: 12px;
100
+ width: 2px;
101
+ height: 2px;
102
+ border-radius: 50%;
103
+ background: rgba(255, 255, 255, 0.12);
104
+ pointer-events: none;
105
+ transform: translateX(-50%);
106
+ }
107
+
108
+ .zeroDbDot.pressed {
109
+ width: 3px;
110
+ height: 3px;
111
+ }
@@ -0,0 +1,27 @@
1
+ import { InputLevelMeter } from './InputLevelMeter'
2
+ import { useSimulatedInputLevel } from './useSimulatedInputLevel'
3
+
4
+ export default {
5
+ title: 'Components/InputLevelMeter',
6
+ component: InputLevelMeter,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ decorators: [
12
+ (Story) => (
13
+ <div style={{ padding: '16px', background: '#1d1d1d', width: '200px' }}>
14
+ <Story />
15
+ </div>
16
+ ),
17
+ ],
18
+ }
19
+
20
+ function AnimatedMeter() {
21
+ const linear = useSimulatedInputLevel()
22
+ return <InputLevelMeter linear={linear} />
23
+ }
24
+
25
+ export const Default = {
26
+ render: () => <AnimatedMeter />,
27
+ }
@@ -0,0 +1,33 @@
1
+ import { useEffect, useRef, useState } from 'react'
2
+
3
+ export function useSimulatedInputLevel() {
4
+ const [linear, setLinear] = useState([0.5, 0.5])
5
+ const targetRef = useRef([0.5, 0.5])
6
+ const currentRef = useRef([0.5, 0.5])
7
+ const frameRef = useRef(null)
8
+ const tickRef = useRef(0)
9
+
10
+ useEffect(() => {
11
+ function animate() {
12
+ tickRef.current++
13
+
14
+ if (tickRef.current % 20 === 0) {
15
+ targetRef.current = [Math.random(), Math.random()]
16
+ }
17
+
18
+ currentRef.current = currentRef.current.map((cur, i) => {
19
+ const target = targetRef.current[i]
20
+ const speed = cur > target ? 0.15 : 0.08
21
+ return cur + (target - cur) * speed
22
+ })
23
+
24
+ setLinear([...currentRef.current])
25
+ frameRef.current = requestAnimationFrame(animate)
26
+ }
27
+
28
+ frameRef.current = requestAnimationFrame(animate)
29
+ return () => cancelAnimationFrame(frameRef.current)
30
+ }, [])
31
+
32
+ return linear
33
+ }
@@ -1,8 +1,8 @@
1
1
  import { Flex, Text } from '@radix-ui/themes'
2
2
  import { Popover } from 'radix-ui'
3
3
  import { useCallback, useState } from 'react'
4
+ import { InputLevelMeter } from '../InputLevelMeter/InputLevelMeter'
4
5
  import { Select } from '../Select/Select'
5
- import { Slider } from '../Slider/Slider'
6
6
  import styles from './RecordSettingsPopover.module.css'
7
7
 
8
8
  export function RecordSettingsPopover({
@@ -18,11 +18,14 @@ export function RecordSettingsPopover({
18
18
  }) {
19
19
  const [opened, setOpened] = useState(false)
20
20
 
21
- const handleOpenChange = useCallback((open) => {
22
- if (!open || !isRecord) {
23
- setOpened(open)
24
- }
25
- }, [])
21
+ const handleOpenChange = useCallback(
22
+ (open) => {
23
+ if (!open || !isRecord) {
24
+ setOpened(open)
25
+ }
26
+ },
27
+ [open, isRecord],
28
+ )
26
29
 
27
30
  const handleContextMenu = useCallback(() => {
28
31
  e.preventDefault()
@@ -69,11 +72,7 @@ export function RecordSettingsPopover({
69
72
  </Text>
70
73
 
71
74
  {opened && (
72
- <Slider
73
- value={inputLevel}
74
- max={30}
75
- style={{ paddingTop: '8px', paddingBottom: '8px' }}
76
- />
75
+ <InputLevelMeter linear={inputLevel} showHandler={false} />
77
76
  )}
78
77
  </Flex>
79
78
  </Flex>
@@ -9,8 +9,8 @@ import {
9
9
  Box,
10
10
  DropdownMenu,
11
11
  Flex,
12
- HorizontalVolume,
13
12
  IconButton,
13
+ InputLevelMeter,
14
14
  PanControl,
15
15
  Text,
16
16
  Tooltip,
@@ -32,14 +32,13 @@ export const TrackHeader = memo(
32
32
  menuOptions,
33
33
  showPan = true,
34
34
  showVolumeControls = true,
35
- isGrouped = false,
36
35
  height = 81,
37
36
  compact = false,
38
37
  isActive = false,
39
38
  instrumentOptions,
40
39
  deviceOptions,
41
40
  channelOptions,
42
- inputLevel,
41
+ inputLevel: inputLevel,
43
42
 
44
43
  // State
45
44
  volume,
@@ -213,9 +212,10 @@ export const TrackHeader = memo(
213
212
  <div {...DND_PROTECTION} className={styles.trackControls}>
214
213
  {!compact && showVolumeControls && (
215
214
  <>
216
- <HorizontalVolume
215
+ <InputLevelMeter
216
+ linear={inputLevel}
217
217
  volume={volume}
218
- onChangeValue={onVolumeChange}
218
+ onVolumeChange={onVolumeChange}
219
219
  />
220
220
  {showPan && (
221
221
  <PanControl
@@ -1,5 +1,6 @@
1
1
  import { useState } from 'react'
2
2
  import { BassIcon, DrumsIcon, ElectricGuitarIcon, KeysIcon } from '../../icons'
3
+ import { useSimulatedInputLevel } from '../InputLevelMeter/useSimulatedInputLevel'
3
4
  import { TrackHeader } from './TrackHeader'
4
5
  export default {
5
6
  title: 'Components/TrackHeader',
@@ -130,7 +131,33 @@ export const Default = {
130
131
  instrumentOptions,
131
132
  instrumentSelected: instrumentOptions[0],
132
133
  },
133
- render: (args) => <TrackHeader {...args} />,
134
+ render: (args) => {
135
+ const inputLevel = useSimulatedInputLevel()
136
+ const [isRecord, setIsRecord] = useState(false)
137
+ const [isMuted, setIsMuted] = useState(args.isMuted)
138
+ const [isSolo, setIsSolo] = useState(args.isSolo)
139
+
140
+ return (
141
+ <TrackHeader
142
+ {...args}
143
+ deviceOptions={[
144
+ { value: 'mic', label: 'Built-in Microphone' },
145
+ { value: 'interface', label: 'Audio Interface' },
146
+ ]}
147
+ channelOptions={[
148
+ { value: '1', label: 'Channel 1' },
149
+ { value: '2', label: 'Channel 2' },
150
+ ]}
151
+ isRecord={isRecord}
152
+ onRecordChange={() => setIsRecord((v) => !v)}
153
+ isMuted={isMuted}
154
+ onMutedChange={() => setIsMuted((v) => !v)}
155
+ isSolo={isSolo}
156
+ onSoloChange={() => setIsSolo((v) => !v)}
157
+ inputLevel={inputLevel}
158
+ />
159
+ )
160
+ },
134
161
  }
135
162
 
136
163
  export const Group = {
@@ -8,7 +8,7 @@ export const MusicIcon = ({ width = 16, height = 16, className, ...props }) => (
8
8
  className={className}
9
9
  {...props}
10
10
  >
11
- <g clipPath="url(#clip0_23974_2573)">
11
+ <g>
12
12
  <path
13
13
  d="M5.56027 10.1048V12.6086C5.56027 13.2138 5.15269 13.743 4.5676 13.8977L3.13494 14.2763C2.28917 14.4998 1.46094 13.862 1.46094 12.9872V12.2149C1.46094 11.6097 1.86851 11.0804 2.45361 10.9258L5.56027 10.1048ZM5.56027 10.1048V3.48019C5.56027 3.17846 5.76292 2.91435 6.05437 2.83624L13.3084 0.892231C13.7318 0.778757 14.1476 1.09781 14.1476 1.53617V7.79232M14.1476 7.79232V10.3072C14.1476 10.9124 13.74 11.4417 13.1549 11.5963L11.7216 11.975C10.8758 12.1985 10.0476 11.5607 10.0476 10.6859V9.91825C10.0476 9.3154 10.4521 8.78755 11.0342 8.63079L14.1476 7.79232Z"
14
14
  stroke="currentColor"
@@ -8,7 +8,7 @@ export const PianoIcon = ({ width = 16, height = 16, className, ...props }) => (
8
8
  className={className}
9
9
  {...props}
10
10
  >
11
- <g clipPath="url(#clip0_2034_833)">
11
+ <g>
12
12
  <path
13
13
  d="M3.6875 15.8182C3.6875 15.4385 3.3797 15.1307 3 15.1307C2.6203 15.1307 2.3125 15.4385 2.3125 15.8182H3.6875ZM6.8125 19.5C6.8125 19.8797 7.1203 20.1875 7.5 20.1875C7.8797 20.1875 8.1875 19.8797 8.1875 19.5H6.8125ZM11.3125 19.6364C11.3125 20.0161 11.6203 20.3239 12 20.3239C12.3797 20.3239 12.6875 20.0161 12.6875 19.6364H11.3125ZM15.8125 19.6364C15.8125 20.0161 16.1203 20.3239 16.5 20.3239C16.8797 20.3239 17.1875 20.0161 17.1875 19.6364H15.8125ZM23 15.8182V16.5057C23.3797 16.5057 23.6875 16.1979 23.6875 15.8182H23ZM1 15.8182H0.312501C0.312501 16.1979 0.620305 16.5057 1 16.5057L1 15.8182ZM14.2535 4.84091L14.8918 4.58551L14.2535 4.84091ZM2.3125 15.8182V21.5455H3.6875V15.8182H2.3125ZM4 23.1875H20.25V21.8125H4V23.1875ZM21.6875 21.5455V15.8182H20.3125V21.5455H21.6875ZM20.25 23.1875C20.7252 23.1875 21.1201 22.9735 21.373 22.6218C21.6066 22.297 21.6875 21.9028 21.6875 21.5455H20.3125C20.3125 21.7153 20.2715 21.7984 20.2567 21.819C20.2522 21.8253 20.2552 21.8193 20.2667 21.8134C20.2784 21.8074 20.2774 21.8125 20.25 21.8125V23.1875ZM2.3125 21.5455C2.3125 22.5017 3.1654 23.1875 4 23.1875V21.8125C3.93616 21.8125 3.8491 21.7824 3.77703 21.7158C3.70741 21.6514 3.6875 21.5875 3.6875 21.5455H2.3125ZM6.8125 15.8182V19.5H8.1875V15.8182H6.8125ZM11.3125 15.8182V19.6364H12.6875V15.8182H11.3125ZM15.8125 15.8182V19.6364H17.1875V15.8182H15.8125ZM22.3125 11.0455V15.8182H23.6875V11.0455H22.3125ZM1.6875 15.8182V6.27273H0.312501V15.8182H1.6875ZM5.58333 2.1875H9.44097V0.812501H5.58333V2.1875ZM17.691 7.91477H19.3333V6.53977H17.691V7.91477ZM9.44097 2.1875C11.2517 2.1875 12.9052 3.32202 13.6152 5.09631L14.8918 4.58551C13.9827 2.31361 11.8397 0.812501 9.44097 0.812501V2.1875ZM23.6875 11.0455C23.6875 8.58354 21.764 6.53977 19.3333 6.53977V7.91477C20.9527 7.91477 22.3125 9.28992 22.3125 11.0455H23.6875ZM13.6152 5.09631C14.2929 6.79018 15.8936 7.91477 17.691 7.91477V6.53977C16.4816 6.53977 15.3704 5.78177 14.8918 4.58551L13.6152 5.09631ZM1.6875 6.27273C1.6875 3.99002 3.4577 2.1875 5.58333 2.1875V0.812501C2.64636 0.812501 0.312501 3.28363 0.312501 6.27273H1.6875ZM23 15.1307H12V16.5057H23V15.1307ZM12 15.1307H1V16.5057H12V15.1307Z"
14
14
  fill="currentColor"
@@ -13,7 +13,7 @@ export const StringsIcon = ({
13
13
  className={className}
14
14
  {...props}
15
15
  >
16
- <g clipPath="url(#clip0_23974_1518)">
16
+ <g>
17
17
  <path
18
18
  d="M7.39153 4.17461C7.56357 5.40362 9.99918 5.73374 10.732 4.00041C11.3987 2.48864 10.132 0.33374 7.73596 0.709194C5.54171 1.02654 4.54794 3.50424 5.33203 5.33377C5.83203 6.50042 6.55153 7.386 7.36952 9.01859C8.02847 10.3338 8.02847 12.367 8.02847 12.367L8.50909 12.4824C9.81528 12.7962 10.8055 13.8634 11.0207 15.1894L11.0442 15.3337H14.9987C14.6654 11.6671 13.6654 9.66707 9.33203 6.50042C8.4067 5.82422 7.62246 5.00666 7.44544 4.41706C7.41961 4.33103 7.40196 4.25018 7.39153 4.17461ZM7.39153 4.17461C7.24806 3.13477 8.46886 3.06401 8.46886 3.3682M2.33203 6.50044C2.33203 6.77658 2.55589 7.00044 2.83203 7.00044C3.10817 7.00044 3.33203 6.77658 3.33203 6.50044C3.33203 6.22429 3.10817 6.00044 2.83203 6.00044C2.55589 6.00044 2.33203 6.22429 2.33203 6.50044ZM4.33203 10.5004C4.33203 10.7766 4.55589 11.0004 4.83203 11.0004C5.10817 11.0004 5.33203 10.7766 5.33203 10.5004C5.33203 10.2243 5.10817 10.0004 4.83203 10.0004C4.55589 10.0004 4.33203 10.2243 4.33203 10.5004Z"
19
19
  stroke="currentColor"
package/src/index.jsx CHANGED
@@ -87,6 +87,7 @@ export { Countdown } from './components/Countdown/Countdown'
87
87
  export { DataTable } from './components/DataTable/DataTable'
88
88
  export { DropdownButton } from './components/DropdownButton/DropdownButton'
89
89
  export { DropdownMenu } from './components/DropdownMenu/DropdownMenu'
90
+ export { EmptyState } from './components/EmptyState/EmptyState'
90
91
  export {
91
92
  Extension,
92
93
  useExtension,
@@ -100,6 +101,7 @@ export { GroupButtons } from './components/GroupButtons/GroupButtons'
100
101
  export { HeaderPanel } from './components/HeaderPanel/HeaderPanel'
101
102
  export { HorizontalVolume } from './components/HorizontalVolume/HorizontalVolume'
102
103
  export { IconButton } from './components/IconButton/IconButton'
104
+ export { InputLevelMeter } from './components/InputLevelMeter/InputLevelMeter'
103
105
  export { InstrumentSelector } from './components/InstrumentSelector/InstrumentSelector'
104
106
  export { Knob } from './components/Knob/Knob'
105
107
  export { ListCards } from './components/ListCards/ListCards'
@@ -132,15 +134,16 @@ export { Text } from './components/Text/Text'
132
134
  export { TextArea } from './components/TextArea/TextArea'
133
135
  export { TextField } from './components/TextField/TextField'
134
136
  export { Theme } from './components/theme/Theme'
135
- export { ToastProvider, useToast } from './components/ToastProvider/ToastProvider'
136
137
  export { ThumbnailPicker } from './components/ThumbnailPicker/ThumbnailPicker'
138
+ export {
139
+ ToastProvider,
140
+ useToast,
141
+ } from './components/ToastProvider/ToastProvider'
137
142
  export { Tooltip } from './components/Tooltip/Tooltip'
138
143
  export { TooltipWithInfoIcon } from './components/TooltipWithInfoIcon/TooltipWithInfoIcon'
139
144
  export { TrackControlButton } from './components/TrackControlButton'
145
+ export { TrackControlsToggle } from './components/TrackControlsToggle/TrackControlsToggle'
140
146
  export { TrackHeader } from './components/TrackHeader/TrackHeader'
141
147
  export { useForm } from './components/useForm/useForm'
142
148
  export { VoiceConversionForm } from './components/VoiceConversionForm/VoiceConversionForm'
143
149
  export { Waveform } from './components/VoiceConversionForm/Waveform/Waveform'
144
-
145
- export { EmptyState } from './components/EmptyState/EmptyState'
146
- export { TrackControlsToggle } from './components/TrackControlsToggle/TrackControlsToggle'
@@ -72,6 +72,7 @@ export const createRenderItem = (MenuPrimitives) => {
72
72
  },
73
73
  )}
74
74
  >
75
+ {opt.icon && <span className={styles.leftIcon}>{opt.icon}</span>}
75
76
  {opt.label}
76
77
  <div className={styles.rightSlot}>
77
78
  <ChevronRightIcon />