@@ -6,6 +6,7 @@ import { Button } from '../Button';
66import  {  DropdownTriggerRenderFunction  }  from  './DropdownTrigger' ; 
77import  {  shortcuts  }  from  '../HotKeyWrapper' ; 
88import  {  Shortcut  }  from  '../Shortcut' ; 
9+ import  {  transition  }  from  '../../helpers/transition' ; 
910
1011export  const  DIVIDER  =  'divider'  as  const ; 
1112
@@ -96,13 +97,17 @@ export function DropdownMenu({
9697  const  dropdownRef  =  useRef < HTMLDivElement > ( null ) ; 
9798  const  triggerRef  =  useRef < HTMLButtonElement > ( null ) ; 
9899  const  [ isActive ,  setIsActive ]  =  useState ( false ) ; 
100+   const  [ visible ,  setVisible ]  =  useState ( false ) ; 
99101
100102  const  handleClose  =  useCallback ( ( )  =>  { 
101-     setIsActive ( false ) ; 
103+     setVisible ( false ) ; 
102104    // Whenever the menu closes, assume that the next one will be opened with mouse 
103105    setUseKeys ( false ) ; 
104106    // Always reset to the top item on close 
105-     setSelectedIndex ( 0 ) ; 
107+     setTimeout ( ( )  =>  { 
108+       setIsActive ( false ) ; 
109+       setSelectedIndex ( 0 ) ; 
110+     } ,  100 ) ; 
106111  } ,  [ ] ) ; 
107112
108113  useClickAwayListener ( [ triggerRef ,  dropdownRef ] ,  handleClose ,  isActive ,  [ 
@@ -126,27 +131,31 @@ export function DropdownMenu({
126131      return ; 
127132    } 
128133
129-     const  triggerRect  =  triggerRef . current ! . getBoundingClientRect ( ) ; 
130-     const  menuRect  =  dropdownRef . current ! . getBoundingClientRect ( ) ; 
131-     const  topPos  =  triggerRect . y  -  menuRect . height ; 
134+     setIsActive ( true ) ; 
132135
133-     // If the top is outside of the screen, render it below 
134-     if  ( topPos  <  0 )  { 
135-       setY ( triggerRect . y  +  triggerRect . height  /  2 ) ; 
136-     }  else  { 
137-       setY ( topPos  +  triggerRect . height  /  2 ) ; 
138-     } 
136+     requestAnimationFrame ( ( )  =>  { 
137+       const  triggerRect  =  triggerRef . current ! . getBoundingClientRect ( ) ; 
138+       const  menuRect  =  dropdownRef . current ! . getBoundingClientRect ( ) ; 
139+       const  topPos  =  triggerRect . y  -  menuRect . height ; 
139140
140-     const  leftPos  =  triggerRect . x  -  menuRect . width ; 
141+       // If the top is outside of the screen, render it below 
142+       if  ( topPos  <  0 )  { 
143+         setY ( triggerRect . y  +  triggerRect . height  /  2 ) ; 
144+       }  else  { 
145+         setY ( topPos  +  triggerRect . height  /  2 ) ; 
146+       } 
141147
142-     // If the left is outside of the screen, render it to the right 
143-     if  ( leftPos  <  0 )  { 
144-       setX ( triggerRect . x ) ; 
145-     }  else  { 
146-       setX ( triggerRect . x  -  menuRect . width  +  triggerRect . width ) ; 
147-     } 
148+       const  leftPos  =  triggerRect . x  -  menuRect . width ; 
148149
149-     setIsActive ( true ) ; 
150+       // If the left is outside of the screen, render it to the right 
151+       if  ( leftPos  <  0 )  { 
152+         setX ( triggerRect . x ) ; 
153+       }  else  { 
154+         setX ( triggerRect . x  -  menuRect . width  +  triggerRect . width ) ; 
155+       } 
156+ 
157+       setVisible ( true ) ; 
158+     } ) ; 
150159  } ,  [ isActive ] ) ; 
151160
152161  const  handleTriggerClick  =  useCallback ( ( )  =>  { 
@@ -219,7 +228,7 @@ export function DropdownMenu({
219228        isActive = { isActive } 
220229        menuId = { menuId } 
221230      /> 
222-       < Menu  ref = { dropdownRef }  isActive = { isActive }  x = { x }  y = { y }  id = { menuId } > 
231+       < Menu  ref = { dropdownRef }  visible = { visible }  x = { x }  y = { y }  id = { menuId } > 
223232        { isActive  && 
224233          normalizedItems . map ( ( props ,  i )  =>  { 
225234            if  ( ! isItem ( props ) )  { 
@@ -252,12 +261,6 @@ export function DropdownMenu({
252261  ) ; 
253262} 
254263
255- interface  MenuProps  { 
256-   isActive : boolean ; 
257-   x : number ; 
258-   y : number ; 
259- } 
260- 
261264export  interface  MenuItemSidebarProps  extends  MenuItemMinimial  { 
262265  handleClickItem ?: ( )  =>  unknown ; 
263266} 
@@ -343,6 +346,12 @@ const ItemDivider = styled.div`
343346  border-bottom: 1px solid ${ p  =>  p . theme . colors . bg2 }  ; 
344347` ; 
345348
349+ interface  MenuProps  { 
350+   visible : boolean ; 
351+   x : number ; 
352+   y : number ; 
353+ } 
354+ 
346355const  Menu  =  styled . div < MenuProps > ` 
347356  font-size: ${ p  =>  p . theme . fontSizeBody }  rem; 
348357  overflow: hidden; 
@@ -358,6 +367,7 @@ const Menu = styled.div<MenuProps>`
358367  left: ${ p  =>  p . x }  px; 
359368  width: auto; 
360369  box-shadow: ${ p  =>  p . theme . boxShadowSoft }  ; 
361-   opacity: ${ p  =>  ( p . isActive  ? 1  : 0 ) }  ; 
362-   visibility: ${ p  =>  ( p . isActive  ? 'visible'  : 'hidden' ) }  ; 
370+   opacity: ${ p  =>  ( p . visible  ? 1  : 0 ) }  ; 
371+ 
372+   transition: ${ ( )  =>  transition ( 'opacity' ) }  ; 
363373` ; 
0 commit comments