@moises.ai/design-system 3.10.18 → 3.11.1

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.10.18",
3
+ "version": "3.11.1",
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,55 @@
1
+ import styles from './TrackControlsToggle.module.css'
2
+ import classNames from 'classnames'
3
+ import { Text, Tooltip, Flex } from '../../index'
4
+
5
+ export const TrackControlsToggle = ({ children, className, type, selected, onClick, tooltipContent, ...props }) => {
6
+ const toggleType = {
7
+ record: 'R',
8
+ mute: 'M',
9
+ autoMute: 'M',
10
+ solo: 'S',
11
+ }
12
+
13
+ const content = () => {
14
+ return (
15
+ <Flex className={classNames(styles.TrackControlsToggle, className, {
16
+ [styles.selected]: selected,
17
+ [styles.record]: type === 'record',
18
+ [styles.mute]: type === 'mute',
19
+ [styles.autoMute]: type === 'autoMute',
20
+ [styles.solo]: type === 'solo',
21
+ })}
22
+ onClick={onClick}
23
+ role="button"
24
+ tabIndex={0}
25
+ aria-pressed={selected}
26
+ onKeyDown={(e) => {
27
+ if (e.key === 'Enter') {
28
+ e.preventDefault()
29
+ onClick?.()
30
+ }
31
+ }}
32
+ {...props}>
33
+ <Text size="1" weight="regular">{toggleType[type]}</Text>
34
+ </Flex>
35
+ )
36
+
37
+ }
38
+
39
+ return (
40
+ <>
41
+ {tooltipContent && (
42
+ <Tooltip content={tooltipContent?.text} color='gray' shortcut={tooltipContent?.shortcut}>
43
+ {content()}
44
+ </Tooltip>
45
+ )}
46
+ {!tooltipContent && (
47
+ <>
48
+ {content()}
49
+ </>
50
+ )}
51
+ </>
52
+ )
53
+ }
54
+
55
+ TrackControlsToggle.displayName = 'TrackControlsToggle'
@@ -0,0 +1,44 @@
1
+ .TrackControlsToggle {
2
+ border-radius: 4px;
3
+ background: var(--neutral-alpha-2);
4
+ display: inline-flex;
5
+ padding: 2px;
6
+ justify-content: center;
7
+ align-items: center;
8
+ gap: 4px;
9
+
10
+ color: var(--neutral-alpha-10);
11
+
12
+ width: 20px;
13
+ height: 20px;
14
+
15
+ &:focus-visible:not(.disabled) {
16
+ outline: 2px solid var(--neutral-alpha-8);
17
+ outline-offset: 2px;
18
+ }
19
+ }
20
+
21
+ .TrackControlsToggle:hover {
22
+ background: var(--neutral-alpha-3);
23
+ cursor: pointer;
24
+ }
25
+
26
+ .selected.record {
27
+ background: rgba(255, 100, 101, 0.92);
28
+ color: var(--neutral-1);
29
+ }
30
+
31
+ .selected.mute {
32
+ background: #ffc53d;
33
+ color: var(--neutral-1);
34
+ }
35
+
36
+ .selected.autoMute {
37
+ background: var(--neutral-alpha-2);
38
+ color: #ffc53d;
39
+ }
40
+
41
+ .selected.solo {
42
+ background: var(--aqua-10);
43
+ color: var(--neutral-1);
44
+ }
@@ -0,0 +1,156 @@
1
+ import { useState } from 'react'
2
+ import { TrackControlsToggle } from './TrackControlsToggle'
3
+
4
+ export default {
5
+ title: 'Components/TrackControlsToggle',
6
+ component: TrackControlsToggle,
7
+ parameters: {
8
+ layout: 'centered',
9
+ docs: {
10
+ description: {
11
+ component: 'Toggle button for track controls (Record, Mute, Auto Mute, and Solo). Use `selected` to represent active state and `tooltipContent` to show context and keyboard shortcut.',
12
+ },
13
+ },
14
+ },
15
+ tags: ['autodocs'],
16
+ argTypes: {
17
+ type: {
18
+ control: 'select',
19
+ options: ['record', 'mute', 'autoMute', 'solo'],
20
+ description: 'Defines the control type and the displayed label (R, M, or S).',
21
+ table: {
22
+ type: { summary: "'record' | 'mute' | 'autoMute' | 'solo'" },
23
+ defaultValue: { summary: "'solo'" },
24
+ },
25
+ },
26
+ selected: {
27
+ control: 'boolean',
28
+ description: 'Controls the visual active/inactive state of the toggle.',
29
+ table: {
30
+ type: { summary: 'boolean' },
31
+ defaultValue: { summary: 'false' },
32
+ },
33
+ },
34
+ onClick: {
35
+ action: 'clicked',
36
+ description: 'Triggered when clicking (or pressing Enter/Space) on the toggle.',
37
+ table: {
38
+ type: { summary: '() => void' },
39
+ },
40
+ },
41
+ tooltipContent: {
42
+ control: 'object',
43
+ description: 'Tooltip data in the `{ text, shortcut }` format.',
44
+ table: {
45
+ type: { summary: '{ text?: string; shortcut?: string }' },
46
+ },
47
+ },
48
+ children: {
49
+ control: false,
50
+ table: {
51
+ disable: true,
52
+ },
53
+ },
54
+ },
55
+ }
56
+
57
+ export const Default = {
58
+ args: {
59
+ type: 'solo',
60
+ selected: true,
61
+ tooltipContent: {
62
+ text: 'Tooltip Content',
63
+ shortcut: '⌘ C',
64
+ },
65
+ },
66
+ }
67
+
68
+ export const Inactive = {
69
+ args: {
70
+ type: 'solo',
71
+ selected: false,
72
+ tooltipContent: {
73
+ text: 'Solo',
74
+ shortcut: 'S',
75
+ },
76
+ },
77
+ }
78
+
79
+ export const RecordSelected = {
80
+ args: {
81
+ type: 'record',
82
+ selected: true,
83
+ tooltipContent: {
84
+ text: 'Record',
85
+ shortcut: 'R',
86
+ },
87
+ },
88
+ }
89
+
90
+ export const MuteSelected = {
91
+ args: {
92
+ type: 'mute',
93
+ selected: true,
94
+ tooltipContent: {
95
+ text: 'Mute',
96
+ shortcut: 'M',
97
+ },
98
+ },
99
+ }
100
+
101
+ export const AllStates = {
102
+ parameters: {
103
+ docs: {
104
+ description: {
105
+ story: 'Shows all states with and without tooltip. Click any toggle to switch between inactive and active.',
106
+ },
107
+ },
108
+ },
109
+ render: (args) => {
110
+ const InteractiveGroup = ({ withTooltip }) => {
111
+ const [states, setStates] = useState({
112
+ record: false,
113
+ mute: false,
114
+ autoMute: false,
115
+ solo: false,
116
+ })
117
+
118
+ const types = ['record', 'mute', 'autoMute', 'solo']
119
+
120
+ const toggleState = (type) => {
121
+ setStates((prev) => ({ ...prev, [type]: !prev[type] }))
122
+ }
123
+
124
+ return (
125
+ <div style={{ display: 'flex', gap: 8 }}>
126
+ {types.map((type) => (
127
+ <TrackControlsToggle
128
+ key={`${withTooltip ? 'with' : 'without'}-${type}`}
129
+ {...args}
130
+ type={type}
131
+ selected={states[type]}
132
+ tooltipContent={withTooltip ? { text: `${type}`, shortcut: type.slice(0, 1).toUpperCase() } : undefined}
133
+ onClick={() => {
134
+ args.onClick?.()
135
+ toggleState(type)
136
+ }}
137
+ />
138
+ ))}
139
+ </div>
140
+ )
141
+ }
142
+
143
+ return (
144
+ <div style={{ display: 'grid', gap: 14 }}>
145
+ <div style={{ display: 'grid', gap: 8 }}>
146
+ <span style={{ color: '#9da3b4', fontSize: 12 }}>With tooltip</span>
147
+ <InteractiveGroup withTooltip />
148
+ </div>
149
+ <div style={{ display: 'grid', gap: 8 }}>
150
+ <span style={{ color: '#9da3b4', fontSize: 12 }}>Without tooltip</span>
151
+ <InteractiveGroup withTooltip={false} />
152
+ </div>
153
+ </div>
154
+ )
155
+ },
156
+ }
@@ -1,27 +1,44 @@
1
- import { DotsVerticalIcon } from '@radix-ui/react-icons'
2
- import { IconButton } from '@radix-ui/themes'
3
1
  import classNames from 'classnames'
4
2
  import { memo, useCallback } from 'react'
5
- import { DropdownMenu, HorizontalVolume, PanControl, Text, Tooltip } from '../../index'
6
- import { TrackControlButton } from '../TrackControlButton'
3
+ import {
4
+ ChevronDownFilledIcon,
5
+ ChevronRightFilledIcon,
6
+ More2Icon,
7
+ } from '../../icons'
8
+ import {
9
+ Box,
10
+ DropdownMenu,
11
+ Flex,
12
+ HorizontalVolume,
13
+ IconButton,
14
+ PanControl,
15
+ Text,
16
+ Tooltip,
17
+ TrackControlsToggle,
18
+ } from '../../index'
7
19
  import styles from './TrackHeader.module.css'
8
- import { TrackHeaderOptions } from './TrackHeaderOptions'
9
20
 
10
21
  export const TrackHeader = memo(
11
22
  ({
12
23
  // Config
13
24
  title,
14
25
  menuOptions,
26
+ instrumentOptions,
27
+ onInstrumentChange,
28
+ instrumentSelected,
15
29
  showPan = true,
16
30
  showVolumeControls = true,
17
31
  isGrouped = false,
18
32
  height = 81,
19
33
  compact = false,
34
+ isActive = false,
20
35
 
21
36
  // State
22
37
  volume,
23
38
  pan,
24
39
  isMuted,
40
+ isRecord,
41
+ isAutoMuted,
25
42
  isSolo,
26
43
  isOpen,
27
44
 
@@ -29,6 +46,7 @@ export const TrackHeader = memo(
29
46
  onVolumeChange,
30
47
  onPanChange,
31
48
  onMutedChange,
49
+ onRecordChange,
32
50
  onSoloChange,
33
51
  onOpenChange,
34
52
 
@@ -36,10 +54,15 @@ export const TrackHeader = memo(
36
54
  children,
37
55
  }) => {
38
56
  const hasChildren = Boolean(children)
39
- const handleToggleOpen = useCallback(() => onOpenChange?.(!isOpen), [isOpen, onOpenChange])
57
+ const handleToggleOpen = useCallback(
58
+ () => onOpenChange?.(!isOpen),
59
+ [isOpen, onOpenChange],
60
+ )
40
61
 
41
62
  return (
42
- <div className={classNames(styles.container, { [styles.isOpen]: isOpen })}>
63
+ <div
64
+ className={classNames(styles.container, { [styles.isOpen]: isOpen })}
65
+ >
43
66
  <div
44
67
  className={classNames(styles.track, {
45
68
  [styles.isParentTrack]: hasChildren,
@@ -47,46 +70,131 @@ export const TrackHeader = memo(
47
70
  })}
48
71
  style={{ height: `${height}px` }}
49
72
  >
50
- <div className={styles.trackContent}>
73
+ <Flex
74
+ className={classNames(styles.trackContent, {
75
+ [styles.isActive]: isActive,
76
+ })}
77
+ direction="column"
78
+ gap="2"
79
+ p="12px 12px 12px 4px"
80
+ >
51
81
  <div className={styles.line}>
52
- <div className={styles.left}>
53
- <div
54
- className={styles.leftIcon}
82
+ <Flex
83
+ align="center"
84
+ justify="between"
85
+ direction="row"
86
+ gap="3"
87
+ className={styles.headerActions}
88
+ >
89
+ <Flex
90
+ align="center"
91
+ direction="row"
92
+ gap="1"
93
+ flexGrow="1"
94
+ style={{ minWidth: 0, overflow: 'hidden' }}
95
+ >
96
+ <IconButton
97
+ onPointerDown={(e) => e.stopPropagation()}
98
+ onMouseDown={(e) => e.stopPropagation()}
99
+ onTouchStart={(e) => e.stopPropagation()}
100
+ variant="ghost"
101
+ size="1"
102
+ onClick={handleToggleOpen}
103
+ className={styles.toggleOpenButton}
104
+ >
105
+ {isOpen ? (
106
+ <ChevronDownFilledIcon />
107
+ ) : (
108
+ <ChevronRightFilledIcon />
109
+ )}
110
+ </IconButton>
111
+ {instrumentOptions && (
112
+ <DropdownMenu
113
+ showActiveTrigger={true}
114
+ trigger={
115
+ <IconButton
116
+ variant="ghost"
117
+ size="1"
118
+ className={classNames(
119
+ styles.instrumentIconButton,
120
+ styles.menuOptionsTrigger,
121
+ )}
122
+ >
123
+ {instrumentSelected.icon}
124
+ </IconButton>
125
+ }
126
+ options={instrumentOptions}
127
+ onValueChange={onInstrumentChange}
128
+ side="bottom"
129
+ align="start"
130
+ />
131
+ )}
132
+
133
+ <Tooltip content={title}>
134
+ <Text
135
+ size="2"
136
+ className={styles.name}
137
+ onClick={hasChildren ? handleToggleOpen : undefined}
138
+ >
139
+ {title}
140
+ </Text>
141
+ </Tooltip>
142
+ </Flex>
143
+
144
+ <Flex
145
+ direction="row"
146
+ gap="3"
147
+ align="center"
55
148
  onPointerDown={(e) => e.stopPropagation()}
56
149
  onMouseDown={(e) => e.stopPropagation()}
57
150
  onTouchStart={(e) => e.stopPropagation()}
58
151
  >
59
- <TrackHeaderOptions isOpen={isOpen} onToggleOpen={handleToggleOpen} />
60
- </div>
61
-
62
- <Tooltip content={title}>
63
- <Text
64
- size="2"
65
- className={styles.name}
66
- onClick={hasChildren ? handleToggleOpen : undefined}
67
- >
68
- {title}
69
- </Text>
70
- </Tooltip>
71
- </div>
152
+ <Flex gap="2px">
153
+ <TrackControlsToggle
154
+ type="record"
155
+ selected={isRecord}
156
+ onClick={onRecordChange}
157
+ />
158
+ <TrackControlsToggle
159
+ type={
160
+ isMuted ? 'mute' : isAutoMuted ? 'autoMute' : 'mute'
161
+ }
162
+ selected={isMuted || (!isSolo && isAutoMuted)}
163
+ onClick={onMutedChange}
164
+ />
165
+ <TrackControlsToggle
166
+ type="solo"
167
+ selected={isSolo}
168
+ onClick={onSoloChange}
169
+ />
170
+ </Flex>
171
+ </Flex>
72
172
 
73
- <div
74
- className={styles.menuOptions}
75
- onPointerDown={(e) => e.stopPropagation()}
76
- onMouseDown={(e) => e.stopPropagation()}
77
- onTouchStart={(e) => e.stopPropagation()}
78
- >
79
173
  {menuOptions && (
80
- <DropdownMenu
81
- trigger={
82
- <IconButton className={styles.menuOptionsTrigger} variant="ghost" color="gray" size="1">
83
- <DotsVerticalIcon width={16} height={16} />
84
- </IconButton>
85
- }
86
- options={menuOptions}
87
- />
174
+ <Box
175
+ onPointerDown={(e) => e.stopPropagation()}
176
+ onMouseDown={(e) => e.stopPropagation()}
177
+ onTouchStart={(e) => e.stopPropagation()}>
178
+ <DropdownMenu
179
+ trigger={
180
+ <IconButton
181
+ variant="ghost"
182
+ size="1"
183
+ className={styles.menuOptionsTrigger}
184
+ >
185
+ <More2Icon
186
+ width={16}
187
+ height={16}
188
+ className={styles.menuOptionsIcon}
189
+ />
190
+ </IconButton>
191
+ }
192
+ options={menuOptions}
193
+ />
194
+ </Box>
88
195
  )}
89
- </div>
196
+
197
+ </Flex>
90
198
  </div>
91
199
 
92
200
  <div
@@ -101,39 +209,23 @@ export const TrackHeader = memo(
101
209
  volume={volume}
102
210
  onChangeValue={onVolumeChange}
103
211
  />
104
- {showPan && <PanControl className={styles.pan} value={pan} onChange={onPanChange} minValue={-1} maxValue={1}/>}
212
+ {showPan && (
213
+ <PanControl
214
+ className={styles.pan}
215
+ value={pan}
216
+ onChange={onPanChange}
217
+ minValue={-1}
218
+ maxValue={1}
219
+ />
220
+ )}
105
221
  </>
106
222
  )}
107
223
  </div>
108
- </div>
109
-
110
- {showVolumeControls && (
111
- <div
112
- className={styles.right}
113
- onPointerDown={(e) => e.stopPropagation()}
114
- onMouseDown={(e) => e.stopPropagation()}
115
- onTouchStart={(e) => e.stopPropagation()}
116
- >
117
- <TrackControlButton
118
- className={styles.rightButton}
119
- variant="mute"
120
- isActive={isMuted}
121
- onChange={onMutedChange}
122
- />
123
- <TrackControlButton
124
- className={styles.rightButton}
125
- variant="solo"
126
- isActive={isSolo}
127
- onChange={onSoloChange}
128
- />
129
- </div>
130
- )}
224
+ </Flex>
131
225
  </div>
132
226
 
133
227
  {hasChildren && isOpen && (
134
- <div className={styles.group}>
135
- {children}
136
- </div>
228
+ <div className={styles.group}>{children}</div>
137
229
  )}
138
230
  </div>
139
231
  )