@moises.ai/design-system 3.11.9 → 3.11.10

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.9",
3
+ "version": "3.11.10",
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,71 @@
1
+ import { memo, useRef } from 'react'
2
+ import styles from './PeakLevel.module.css'
3
+
4
+ const PEAK_HOLD_THRESHOLD_HIGH = 0
5
+ const PEAK_HOLD_THRESHOLD_MEDIUM = -1
6
+
7
+ function linearToPeakDb(linear) {
8
+ if (!Array.isArray(linear)) return null
9
+ const peak = Math.max(linear[0] ?? 0, linear[1] ?? 0)
10
+ if (peak <= 0) return null
11
+ const db = 20 * Math.log10(peak)
12
+ if (db <= -96) return null
13
+ return db
14
+ }
15
+
16
+ function getLevel(db) {
17
+ if (db == null) return 'reset'
18
+ if (db >= PEAK_HOLD_THRESHOLD_HIGH) return 'high'
19
+ if (db >= PEAK_HOLD_THRESHOLD_MEDIUM) return 'medium'
20
+ return 'regular'
21
+ }
22
+
23
+ function formatPeakDb(db) {
24
+ if (db == null) return '--'
25
+ return db.toFixed(1)
26
+ }
27
+
28
+ export const PeakLevel = memo(function PeakLevel({
29
+ linear,
30
+ value,
31
+ onClick,
32
+ }) {
33
+ const peakHoldRef = useRef(null)
34
+
35
+ let displayDb = value ?? null
36
+
37
+ if (linear !== undefined) {
38
+ const currentDb = linearToPeakDb(linear)
39
+
40
+ if (currentDb != null) {
41
+ if (peakHoldRef.current == null || currentDb > peakHoldRef.current) {
42
+ peakHoldRef.current = currentDb
43
+ }
44
+ }
45
+
46
+ if (linear[0] <= 0 && linear[1] <= 0) {
47
+ peakHoldRef.current = null
48
+ }
49
+
50
+ displayDb = peakHoldRef.current
51
+ }
52
+
53
+ const level = getLevel(displayDb)
54
+ const text = formatPeakDb(displayDb)
55
+
56
+ return (
57
+ <div
58
+ className={styles.container}
59
+ onClick={onClick}
60
+ role={onClick ? 'button' : undefined}
61
+ tabIndex={onClick ? 0 : undefined}
62
+ style={onClick ? { cursor: 'pointer' } : undefined}
63
+ >
64
+ <span className={`${styles.value} ${styles[level]}`}>
65
+ {text}
66
+ </span>
67
+ </div>
68
+ )
69
+ })
70
+
71
+ PeakLevel.displayName = 'PeakLevel'
@@ -0,0 +1,49 @@
1
+ .container {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ width: 24px;
6
+ padding: 2px 0;
7
+ border-radius: 4px;
8
+ user-select: none;
9
+ }
10
+
11
+ .value {
12
+ font-size: 12px;
13
+ font-weight: 500;
14
+ line-height: 16px;
15
+ letter-spacing: 0.04px;
16
+ white-space: nowrap;
17
+ }
18
+
19
+ .reset {
20
+ color: rgba(214, 235, 253, 0.19);
21
+ }
22
+
23
+ .regular {
24
+ color: #00dae8;
25
+ }
26
+
27
+ .medium {
28
+ color: #ffc53d;
29
+ }
30
+
31
+ .high {
32
+ color: #ec5d5e;
33
+ }
34
+
35
+ .container:hover .reset {
36
+ color: rgba(214, 235, 253, 0.19);
37
+ }
38
+
39
+ .container:hover .regular {
40
+ color: #75ebf5;
41
+ }
42
+
43
+ .container:hover .medium {
44
+ color: #ffe7b3;
45
+ }
46
+
47
+ .container:hover .high {
48
+ color: #ff9592;
49
+ }
@@ -0,0 +1,192 @@
1
+ import { useState, useEffect, useRef } from 'react'
2
+ import { PeakLevel } from './PeakLevel'
3
+ import { InputLevelMeter } from '../InputLevelMeter/InputLevelMeter'
4
+ import { useSimulatedInputLevel } from '../InputLevelMeter/useSimulatedInputLevel'
5
+
6
+ export default {
7
+ title: 'Components/PeakLevel',
8
+ component: PeakLevel,
9
+ tags: ['autodocs'],
10
+ parameters: {
11
+ layout: 'centered',
12
+ },
13
+ decorators: [
14
+ (Story) => (
15
+ <div style={{ padding: '16px', background: '#1d1d1d' }}>
16
+ <Story />
17
+ </div>
18
+ ),
19
+ ],
20
+ }
21
+
22
+ export const Reset = {
23
+ render: () => <PeakLevel value={null} />,
24
+ }
25
+
26
+ export const RegularLevel = {
27
+ render: () => <PeakLevel value={-2} />,
28
+ }
29
+
30
+ export const MediumLevel = {
31
+ render: () => <PeakLevel value={-0.2} />,
32
+ }
33
+
34
+ export const HighLevel = {
35
+ render: () => <PeakLevel value={1.3} />,
36
+ }
37
+
38
+ export const AllLevels = {
39
+ render: () => (
40
+ <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
41
+ <div style={{ textAlign: 'center' }}>
42
+ <PeakLevel value={null} />
43
+ <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: '9px', display: 'block', marginTop: '4px' }}>
44
+ Reset
45
+ </span>
46
+ </div>
47
+ <div style={{ textAlign: 'center' }}>
48
+ <PeakLevel value={-12} />
49
+ <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: '9px', display: 'block', marginTop: '4px' }}>
50
+ Regular
51
+ </span>
52
+ </div>
53
+ <div style={{ textAlign: 'center' }}>
54
+ <PeakLevel value={-0.5} />
55
+ <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: '9px', display: 'block', marginTop: '4px' }}>
56
+ Medium
57
+ </span>
58
+ </div>
59
+ <div style={{ textAlign: 'center' }}>
60
+ <PeakLevel value={1.3} />
61
+ <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: '9px', display: 'block', marginTop: '4px' }}>
62
+ High
63
+ </span>
64
+ </div>
65
+ </div>
66
+ ),
67
+ }
68
+
69
+ export const WithLinearInput = {
70
+ render: () => {
71
+ function LivePeak() {
72
+ const linear = useSimulatedInputLevel()
73
+ return (
74
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
75
+ <div style={{ width: '200px' }}>
76
+ <InputLevelMeter linear={linear} />
77
+ </div>
78
+ <PeakLevel linear={linear} />
79
+ </div>
80
+ )
81
+ }
82
+ return <LivePeak />
83
+ },
84
+ }
85
+
86
+ export const WithClickToReset = {
87
+ render: () => {
88
+ function ResettablePeak() {
89
+ const linear = useSimulatedInputLevel()
90
+ const [peakDb, setPeakDb] = useState(null)
91
+ const peakRef = useRef(null)
92
+
93
+ useEffect(() => {
94
+ const peak = Math.max(linear[0] ?? 0, linear[1] ?? 0)
95
+ if (peak > 0) {
96
+ const db = 20 * Math.log10(peak)
97
+ if (db > -96) {
98
+ if (peakRef.current == null || db > peakRef.current) {
99
+ peakRef.current = db
100
+ setPeakDb(db)
101
+ }
102
+ }
103
+ }
104
+ }, [linear])
105
+
106
+ const handleReset = () => {
107
+ peakRef.current = null
108
+ setPeakDb(null)
109
+ }
110
+
111
+ return (
112
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
113
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
114
+ <div style={{ width: '200px' }}>
115
+ <InputLevelMeter linear={linear} />
116
+ </div>
117
+ <PeakLevel value={peakDb} onClick={handleReset} />
118
+ </div>
119
+ <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: '10px', fontFamily: 'monospace' }}>
120
+ Click the peak value to reset
121
+ </span>
122
+ </div>
123
+ )
124
+ }
125
+ return <ResettablePeak />
126
+ },
127
+ }
128
+
129
+ export const WithVolumeFader = {
130
+ render: () => {
131
+ function FaderWithPeak() {
132
+ const linear = useSimulatedInputLevel()
133
+ const [volume, setVolume] = useState(1)
134
+
135
+ return (
136
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
137
+ <div style={{ width: '200px' }}>
138
+ <InputLevelMeter
139
+ linear={linear}
140
+ volume={volume}
141
+ onVolumeChange={([v]) => setVolume(v)}
142
+ />
143
+ </div>
144
+ <PeakLevel linear={linear} />
145
+ </div>
146
+ )
147
+ }
148
+ return <FaderWithPeak />
149
+ },
150
+ }
151
+
152
+ export const BoundaryValues = {
153
+ render: () => (
154
+ <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
155
+ {[-96, -60, -24, -6, -1, -0.1, 0, 0.1, 1, 3, 6].map((db) => (
156
+ <div key={db} style={{ textAlign: 'center' }}>
157
+ <PeakLevel value={db} />
158
+ <span style={{ color: 'rgba(255,255,255,0.3)', fontSize: '9px', fontFamily: 'monospace', display: 'block', marginTop: '4px' }}>
159
+ {db} dB
160
+ </span>
161
+ </div>
162
+ ))}
163
+ </div>
164
+ ),
165
+ }
166
+
167
+ export const MultipleChannels = {
168
+ render: () => {
169
+ function MultiChannel() {
170
+ const linear = useSimulatedInputLevel()
171
+ const labels = ['Master', 'Vocals', 'Guitar', 'Drums']
172
+ const multipliers = [1, 0.7, 0.4, 0.15]
173
+
174
+ return (
175
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
176
+ {labels.map((label, i) => (
177
+ <div key={label} style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
178
+ <span style={{ color: 'rgba(255,255,255,0.4)', fontSize: '10px', fontFamily: 'monospace', width: '48px' }}>
179
+ {label}
180
+ </span>
181
+ <div style={{ width: '160px' }}>
182
+ <InputLevelMeter linear={linear.map((l) => l * multipliers[i])} />
183
+ </div>
184
+ <PeakLevel linear={linear.map((l) => l * multipliers[i])} />
185
+ </div>
186
+ ))}
187
+ </div>
188
+ )
189
+ }
190
+ return <MultiChannel />
191
+ },
192
+ }
@@ -0,0 +1,18 @@
1
+ export function TrackPreviousIcon({ width = 32, height = 32 }) {
2
+ return (
3
+ <svg
4
+ width={width}
5
+ height={height}
6
+ viewBox="0 0 32 32"
7
+ fill="none"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ >
10
+ <path
11
+ d="M21.1797 9.6884C21.4546 9.86496 21.625 10.1751 21.625 10.5188L21.625 21.4812C21.625 21.8248 21.4546 22.135 21.1797 22.3116C20.9021 22.4898 20.5259 22.5208 20.2018 22.3202L11.8333 17.4237L11.8333 20.7917C11.8333 21.367 11.367 21.8333 10.7917 21.8333C10.2164 21.8333 9.75 21.367 9.75 20.7917V11.2083C9.75 10.633 10.2164 10.1667 10.7917 10.1667C11.367 10.1667 11.8333 10.633 11.8333 11.2083L11.8333 14.5762L20.2018 9.67975C20.5259 9.47916 20.9021 9.51013 21.1797 9.6884Z"
12
+ fill="currentColor"
13
+ />
14
+ </svg>
15
+ )
16
+ }
17
+
18
+ TrackPreviousIcon.displayName = 'TrackPreviousIcon'
package/src/icons.jsx CHANGED
@@ -350,3 +350,4 @@ export { Play1Icon } from './icons/Play1Icon'
350
350
  export { ChevronRightFilledIcon } from './icons/ChevronRightFilledIcon'
351
351
  export { ChevronDownFilledIcon } from './icons/ChevronDownFilledIcon'
352
352
  export { Share2Icon } from './icons/Share2Icon'
353
+ export { TrackPreviousIcon } from './icons/TrackPreviousIcon'
package/src/index.jsx CHANGED
@@ -111,6 +111,7 @@ export { MoreButton } from './components/MoreButton/MoreButton'
111
111
  export { MultiSelect } from './components/MultiSelect/MultiSelect'
112
112
  export { MultiSelectCards } from './components/MultiSelectCards/MultiSelectCards'
113
113
  export { PanControl } from './components/PanControl/PanControl'
114
+ export { PeakLevel } from './components/PeakLevel/PeakLevel'
114
115
  export { ProductsBrandPattern } from './components/ProductsBrandPattern/ProductsBrandPattern'
115
116
  export { ProductsList } from './components/ProductsList/ProductsList'
116
117
  export { ProfileMenu } from './components/ProfileMenu/ProfileMenu'