@moises.ai/design-system 3.6.1 → 3.6.3

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.6.1",
3
+ "version": "3.6.3",
4
4
  "description": "Design System package based on @radix-ui/themes with custom defaults",
5
5
  "private": false,
6
6
  "type": "module",
@@ -22,7 +22,7 @@ export function MenuTrigger({ className, user, collapsed, ...props }) {
22
22
  onMouseLeave={handleMouseLeave}
23
23
  className={classNames(styles.userProfile, { [styles.collapsed]: collapsed }, className)}
24
24
  align="center"
25
- justify="between"
25
+ justify={collapsed ? 'center' : 'between'}
26
26
  {...props}
27
27
  >
28
28
  <div className={styles.userProfileInner}>
@@ -1,34 +1,11 @@
1
1
  import classNames from 'classnames'
2
- import React, { useMemo } from 'react'
2
+ import React from 'react'
3
3
  import { Button } from '../Button/Button'
4
4
  import { useIsMobileViewport } from '../../utils/useIsMobileViewport'
5
5
  import { DropdownMenu } from '../DropdownMenu/DropdownMenu'
6
6
  import { MenuTrigger } from './MenuTrigger'
7
7
  import styles from './ProfileMenu.module.css'
8
8
 
9
- const renderUserMenuOption = (opt) => (
10
- <div key={opt.key} className={styles.creditsHeader}>
11
- <div className={styles.creditsInfo}>
12
- <span className={styles.creditsLabel}>Credits: </span>
13
- <span className={styles.creditsValue}>{opt.current}</span>/{opt.total}
14
- </div>
15
- {opt.onUpgrade && (
16
- <Button
17
- variant="solid"
18
- color="cyan"
19
- size="2"
20
- onClick={(e) => {
21
- e.stopPropagation()
22
- opt.onUpgrade()
23
- }}
24
- className={styles.upgradeButton}
25
- >
26
- Upgrade
27
- </Button>
28
- )}
29
- </div>
30
- )
31
-
32
9
  export const ProfileMenu = ({
33
10
  className,
34
11
  user,
@@ -38,27 +15,12 @@ export const ProfileMenu = ({
38
15
  }) => {
39
16
  const isMobile = useIsMobileViewport()
40
17
 
41
- const processedItems = useMemo(() => {
42
- const creditsItem = menuOptions.find((item) => item.type === 'credits')
43
- const otherItems = menuOptions.filter((item) => item.type !== 'credits')
44
-
45
- return creditsItem
46
- ? [
47
- {
48
- type: 'custom',
49
- key: 'credits-header',
50
- customRender: () => renderUserMenuOption(creditsItem),
51
- },
52
- ...otherItems,
53
- ]
54
- : otherItems
55
- }, [menuOptions])
56
18
 
57
19
  return (
58
20
  <DropdownMenu
59
21
  className={classNames(styles.profileMenu, className)}
60
22
  trigger={<MenuTrigger user={user} collapsed={collapsed} />}
61
- options={processedItems}
23
+ options={menuOptions}
62
24
  side={isMobile ? 'left' : 'right'}
63
25
  {...props}
64
26
  />
@@ -1,6 +1,14 @@
1
1
  .userProfile {
2
2
  cursor: pointer;
3
3
  width: 100%;
4
+ min-width: 0;
5
+ transition: width 280ms cubic-bezier(0.4, 0, 0.2, 1);
6
+ }
7
+
8
+ .collapsed .userProfile {
9
+ width: auto;
10
+ min-width: 0;
11
+ flex-shrink: 0;
4
12
  }
5
13
 
6
14
  .userProfile:focus-visible {
@@ -13,11 +21,13 @@
13
21
  align-items: center;
14
22
  flex: 1;
15
23
  gap: 13px;
24
+ min-width: 0;
16
25
  transition: gap 280ms cubic-bezier(0.4, 0, 0.2, 1);
17
26
  }
18
27
 
19
28
  .collapsed .userProfileInner {
20
29
  gap: 0;
30
+ flex: 0;
21
31
  }
22
32
 
23
33
  .userAvatar {
@@ -42,6 +52,9 @@
42
52
  opacity: 0;
43
53
  transform: translateX(-8px);
44
54
  flex: 0;
55
+ width: 0;
56
+ min-width: 0;
57
+ overflow: hidden;
45
58
  transition-delay: 50ms;
46
59
  }
47
60
 
@@ -78,6 +91,10 @@
78
91
  opacity: 0;
79
92
  transform: translateX(-8px);
80
93
  pointer-events: none;
94
+ width: 0;
95
+ min-width: 0;
96
+ flex: 0;
97
+ overflow: hidden;
81
98
  transition-delay: 50ms;
82
99
  }
83
100
 
@@ -86,6 +103,34 @@
86
103
  width: 100%;
87
104
  }
88
105
 
106
+ .creditsHeader {
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: space-between;
110
+ gap: 12px;
111
+ padding: 8px 12px;
112
+ }
113
+
114
+ .creditsInfo {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 4px;
118
+ }
119
+
120
+ .creditsLabel {
121
+ color: var(--neutral-alpha-11);
122
+ font-size: 14px;
123
+ }
124
+
125
+ .creditsValue {
126
+ color: var(--neutral-alpha-12);
127
+ font-size: 14px;
128
+ font-weight: 500;
129
+ }
130
+
131
+ .upgradeButton {
132
+ flex-shrink: 0;
133
+ }
89
134
 
90
135
  .dropdownTriggerWrapper {
91
136
  display: flex;
@@ -9,7 +9,8 @@ import {
9
9
  PlusIcon,
10
10
  } from '../../icons'
11
11
  import { DropdownMenu } from '../DropdownMenu/DropdownMenu'
12
- import { useState, useEffect, useRef, useMemo } from 'react'
12
+ import { Tooltip } from '../Tooltip/Tooltip'
13
+ import { useState, useEffect, useRef, useMemo, Fragment } from 'react'
13
14
  import { MoreButton } from '../MoreButton/MoreButton'
14
15
 
15
16
  export const SetlistItem = ({
@@ -154,6 +155,7 @@ export const SetlistList = ({
154
155
  const [isFullyCollapsed, setIsFullyCollapsed] = useState(false)
155
156
  const hoverTimeoutRef = useRef(null)
156
157
  const collapseCenterTimeoutRef = useRef(null)
158
+ const hoverRegionRef = useRef(null)
157
159
  const collapsedItemHeight = 44
158
160
  const collapsedVisibleOffset = 8
159
161
  const maxCollapsedItems = 4
@@ -182,12 +184,29 @@ export const SetlistList = ({
182
184
  }, 180)
183
185
  }
184
186
 
187
+ const handleFocus = () => {
188
+ if (collapsed) setIsHoveredWhenCollapsed(true)
189
+ }
190
+
191
+ const handleBlur = () => {
192
+ if (!collapsed) return
193
+ const el = hoverRegionRef.current
194
+ if (!el) return
195
+ setTimeout(() => {
196
+ if (!el.contains(document.activeElement)) {
197
+ setIsHoveredWhenCollapsed(false)
198
+ }
199
+ }, 0)
200
+ }
201
+
202
+ // Só centraliza os avatares depois que a sidebar terminou de colapsar (width 280ms + delay 100ms)
203
+ const collapseAnimationDuration = 400
185
204
  useEffect(() => {
186
205
  if (showCollapsedStack) {
187
206
  collapseCenterTimeoutRef.current = setTimeout(() => {
188
207
  setIsFullyCollapsed(true)
189
208
  collapseCenterTimeoutRef.current = null
190
- }, 200)
209
+ }, collapseAnimationDuration)
191
210
  } else {
192
211
  setIsFullyCollapsed(false)
193
212
  if (collapseCenterTimeoutRef.current) {
@@ -274,9 +293,12 @@ export const SetlistList = ({
274
293
  })}
275
294
  >
276
295
  <div
296
+ ref={hoverRegionRef}
277
297
  className={styles.hoverRegion}
278
298
  onMouseEnter={handleMouseEnter}
279
299
  onMouseLeave={handleMouseLeave}
300
+ onFocusCapture={handleFocus}
301
+ onBlurCapture={handleBlur}
280
302
  >
281
303
  <Flex
282
304
  direction="column"
@@ -317,9 +339,8 @@ export const SetlistList = ({
317
339
  ))}
318
340
  {visibleSetlists.map((setlist, index) => {
319
341
  const isSelected = selectedSetlistId === setlist.id
320
- return (
342
+ const setlistItem = (
321
343
  <SetlistItem
322
- key={setlist.id}
323
344
  isSelected={isSelected}
324
345
  onClick={() => onSetlistClick?.(setlist.id)}
325
346
  dropdownMenuOpen={openSetlistMenuId === setlist.id}
@@ -349,6 +370,15 @@ export const SetlistList = ({
349
370
  style={getCollapsedStackStyle(index, setlist)}
350
371
  />
351
372
  )
373
+ return collapsed && !showCollapsedStack ? (
374
+ <Tooltip key={setlist.id} content={setlist.label} side="right">
375
+ <div className={styles.tooltipTriggerWrapper}>
376
+ {setlistItem}
377
+ </div>
378
+ </Tooltip>
379
+ ) : (
380
+ <Fragment key={setlist.id}>{setlistItem}</Fragment>
381
+ )
352
382
  })}
353
383
  </Flex>
354
384
  </div>
@@ -1,3 +1,8 @@
1
+ .tooltipTriggerWrapper {
2
+ display: block;
3
+ width: 100%;
4
+ }
5
+
1
6
  .newSetlistItem {
2
7
  cursor: pointer;
3
8
  margin: 0 12px;
@@ -64,7 +64,8 @@ export const Shell = ({
64
64
  selectedAdditionalItemId={selectedAdditionalItemId}
65
65
  />
66
66
  <ProfileMenu
67
- userProfileItems={userProfileItems}
67
+ user={userProfileItems}
68
+ menuOptions={userProfileItems?.menuOptions}
68
69
  collapsed={effectiveCollapsed}
69
70
  />
70
71
  </Flex>
@@ -0,0 +1,67 @@
1
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip'
2
+ import styles from './Tooltip.module.css'
3
+ import classNames from 'classnames'
4
+
5
+ export const Tooltip = ({
6
+ children,
7
+ content,
8
+ shortcut,
9
+ color = 'gray',
10
+ delayDuration = 200,
11
+ skipDelayDuration,
12
+ disableHoverableContent,
13
+ ...props
14
+ }) => {
15
+
16
+ const {
17
+ defaultOpen,
18
+ open,
19
+ onOpenChange,
20
+ ...restContentProps
21
+ } = props
22
+
23
+ const providerProps = {
24
+ delayDuration,
25
+ skipDelayDuration,
26
+ disableHoverableContent,
27
+ }
28
+
29
+ const rootProps = {
30
+ defaultOpen,
31
+ open,
32
+ onOpenChange,
33
+ }
34
+
35
+ return (
36
+ <TooltipPrimitive.Provider {...providerProps}>
37
+ <TooltipPrimitive.Root {...rootProps}>
38
+ <TooltipPrimitive.Trigger asChild>
39
+ {children}
40
+ </TooltipPrimitive.Trigger>
41
+ <TooltipPrimitive.Portal>
42
+ <TooltipPrimitive.Content
43
+ className={classNames(
44
+ styles.TooltipContent,
45
+ styles[`TooltipContent--${color}`]
46
+ )}
47
+ sideOffset={5}
48
+ {...restContentProps}
49
+ >
50
+ <span className={styles.TooltipText}>{content}</span>
51
+ {shortcut && (
52
+ <span className={classNames(
53
+ styles.TooltipShortcut,
54
+ styles[`TooltipShortcut--${color}`]
55
+ )}>
56
+ {shortcut}
57
+ </span>
58
+ )}
59
+ <TooltipPrimitive.Arrow className={styles.TooltipArrow} />
60
+ </TooltipPrimitive.Content>
61
+ </TooltipPrimitive.Portal>
62
+ </TooltipPrimitive.Root>
63
+ </TooltipPrimitive.Provider>
64
+ )
65
+ }
66
+
67
+ Tooltip.displayName = 'Tooltip'
@@ -0,0 +1,129 @@
1
+ .TooltipContent {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 8px;
5
+ padding: 6px 12px;
6
+ text-align: center;
7
+ font-family: var(--Typography-Font-family-text, "Articulat CF");
8
+ font-size: var(--Typography-Font-size-1, 12px);
9
+ font-style: normal;
10
+ font-weight: 400;
11
+ line-height: var(--Typography-Line-height-1, 16px);
12
+ letter-spacing: var(--Typography-Letter-spacing-1, 0.04px);
13
+ z-index: 9999;
14
+ animation-duration: 0.15s;
15
+ animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
16
+ will-change: transform, opacity;
17
+ }
18
+
19
+ .TooltipContent[data-state='delayed-open'][data-side='top'] {
20
+ animation-name: slideDownAndFade;
21
+ }
22
+
23
+ .TooltipContent[data-state='delayed-open'][data-side='right'] {
24
+ animation-name: slideLeftAndFade;
25
+ }
26
+
27
+ .TooltipContent[data-state='delayed-open'][data-side='bottom'] {
28
+ animation-name: slideUpAndFade;
29
+ }
30
+
31
+ .TooltipContent[data-state='delayed-open'][data-side='left'] {
32
+ animation-name: slideRightAndFade;
33
+ }
34
+
35
+ @keyframes slideUpAndFade {
36
+ from {
37
+ opacity: 0;
38
+ transform: translateY(2px);
39
+ }
40
+ to {
41
+ opacity: 1;
42
+ transform: translateY(0);
43
+ }
44
+ }
45
+
46
+ @keyframes slideRightAndFade {
47
+ from {
48
+ opacity: 0;
49
+ transform: translateX(-2px);
50
+ }
51
+ to {
52
+ opacity: 1;
53
+ transform: translateX(0);
54
+ }
55
+ }
56
+
57
+ @keyframes slideDownAndFade {
58
+ from {
59
+ opacity: 0;
60
+ transform: translateY(-2px);
61
+ }
62
+ to {
63
+ opacity: 1;
64
+ transform: translateY(0);
65
+ }
66
+ }
67
+
68
+ @keyframes slideLeftAndFade {
69
+ from {
70
+ opacity: 0;
71
+ transform: translateX(2px);
72
+ }
73
+ to {
74
+ opacity: 1;
75
+ transform: translateX(0);
76
+ }
77
+ }
78
+
79
+ /* White variant */
80
+ .TooltipContent--white {
81
+ border-radius: var(--Radius-1, 3px);
82
+ background: var(--Colors-Neutral-Neutral-12, #EDEEF0);
83
+ color: var(--Colors-Neutral-Neutral-1, #111113);
84
+ }
85
+
86
+ /* Gray variant */
87
+ .TooltipContent--gray {
88
+ border-radius: var(--Radius-1, 3px);
89
+ background: var(--Colors-Neutral-Neutral-4, #272A2D);
90
+ color: var(--Colors-Neutral-Neutral-Alpha-12, rgba(252, 253, 255, 0.94));
91
+ }
92
+
93
+ .TooltipText {
94
+ white-space: nowrap;
95
+ }
96
+
97
+ .TooltipShortcut {
98
+ font-family: var(--Typography-Font-family-text, "Articulat CF");
99
+ font-size: var(--Typography-Font-size-0, 11px);
100
+ font-style: normal;
101
+ font-weight: 400;
102
+ line-height: var(--Typography-Line-height-0, 11px);
103
+ letter-spacing: var(--Typography-Letter-spacing-0, 0);
104
+ white-space: nowrap;
105
+ }
106
+
107
+ /* White shortcut */
108
+ .TooltipShortcut--white {
109
+ color: var(--Colors-Neutral-Neutral-8, #5A6169);
110
+ }
111
+
112
+ /* Gray shortcut */
113
+ .TooltipShortcut--gray {
114
+ color: var(--Colors-Neutral-Neutral-Alpha-10, rgba(229, 237, 253, 0.48));
115
+ }
116
+
117
+ .TooltipArrow {
118
+ fill: var(--Colors-Neutral-Neutral-4, #272A2D);
119
+ }
120
+
121
+ .TooltipContent--white .TooltipArrow {
122
+ fill: var(--Colors-Neutral-Neutral-12, #EDEEF0);
123
+ }
124
+
125
+ .TooltipContent {
126
+ display: flex;
127
+ flex-direction: column;
128
+ gap: 0px;
129
+ }
@@ -0,0 +1,59 @@
1
+ import { Tooltip } from './Tooltip'
2
+ import { Button } from '../Button/Button'
3
+
4
+ export default {
5
+ title: 'Components/Tooltip',
6
+ component: Tooltip,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ color: {
13
+ control: 'select',
14
+ options: ['white', 'gray'],
15
+ },
16
+ },
17
+ }
18
+
19
+ export const Default = {
20
+ args: {
21
+ content: 'Tooltip',
22
+ color: 'gray',
23
+ children: <Button>Hover me</Button>,
24
+ },
25
+ }
26
+
27
+ export const GrayVariant = {
28
+ args: {
29
+ content: 'Tooltip',
30
+ color: 'gray',
31
+ children: <Button>Hover me</Button>,
32
+ },
33
+ }
34
+
35
+ export const WhiteVariant = {
36
+ args: {
37
+ content: 'Tooltip',
38
+ color: 'white',
39
+ children: <Button>Hover me</Button>,
40
+ },
41
+ }
42
+
43
+ export const WithShortcutGray = {
44
+ args: {
45
+ content: 'Tooltip',
46
+ shortcut: '⌘ C',
47
+ color: 'gray',
48
+ children: <Button>Hover me</Button>,
49
+ },
50
+ }
51
+
52
+ export const WithShortcutWhite = {
53
+ args: {
54
+ content: 'Tooltip',
55
+ shortcut: '⌘ C',
56
+ color: 'white',
57
+ children: <Button>Hover me</Button>,
58
+ },
59
+ }
package/src/index.jsx CHANGED
@@ -32,7 +32,6 @@ import {
32
32
  Switch,
33
33
  Table,
34
34
  Tabs,
35
- Tooltip,
36
35
  VisuallyHidden,
37
36
  DataList,
38
37
  } from '@radix-ui/themes'
@@ -70,7 +69,6 @@ export {
70
69
  Switch,
71
70
  Table,
72
71
  Tabs,
73
- Tooltip,
74
72
  VisuallyHidden,
75
73
  DataList,
76
74
  }
@@ -154,4 +152,5 @@ export { InstrumentSelector } from './components/InstrumentSelector/InstrumentSe
154
152
  export { Card as CardWidget } from './components/Card/Card'
155
153
  export { ProjectsList } from './components/ProjectsList/ProjectsList'
156
154
 
157
- export { MoreButton } from './components/MoreButton/MoreButton'
155
+ export { MoreButton } from './components/MoreButton/MoreButton'
156
+ export { Tooltip } from './components/Tooltip/Tooltip'