Explorar o código

Merge pull request #5218 from weseek/imprv/sidebar-open-delay-for-master

imprv: Sidebar opening delay (merge into master)
Yuki Takei %!s(int64=4) %!d(string=hai) anos
pai
achega
a0d358f192
Modificáronse 1 ficheiros con 65 adicións e 18 borrados
  1. 65 18
      packages/app/src/components/Sidebar.tsx

+ 65 - 18
packages/app/src/components/Sidebar.tsx

@@ -90,8 +90,13 @@ const Sidebar: FC<Props> = (props: Props) => {
   const [isTransitionEnabled, setTransitionEnabled] = useState(false);
 
   const [isHover, setHover] = useState(false);
+  const [isHoverOnResizableContainer, setHoverOnResizableContainer] = useState(false);
   const [isDragging, setDrag] = useState(false);
 
+  const resizableContainer = useRef<HTMLDivElement>(null);
+
+  const timeoutIdRef = useRef<NodeJS.Timeout>();
+
   const isResizableByDrag = !isResizeDisabled && !isDrawerMode && (!isCollapsed || isHover);
 
   const toggleDrawerMode = useCallback((bool) => {
@@ -116,32 +121,21 @@ const Sidebar: FC<Props> = (props: Props) => {
     mutateDrawerOpened(false, false);
   }, [mutateDrawerOpened]);
 
-  useEffect(() => {
-    setTimeout(() => {
-      setTransitionEnabled(true);
-    }, 1000);
-  }, []);
 
-  useEffect(() => {
-    toggleDrawerMode(isDrawerMode);
-  }, [isDrawerMode, toggleDrawerMode]);
-
-  const resizableContainer = useRef<HTMLDivElement>(null);
-  const setContentWidth = useCallback((newWidth) => {
+  const setContentWidth = useCallback((newWidth: number) => {
     if (resizableContainer.current == null) {
       return;
     }
     resizableContainer.current.style.width = `${newWidth}px`;
   }, []);
 
-  const hoverOnResizableContainerHandler = useCallback(() => {
+  const hoverOnHandler = useCallback(() => {
     if (!isCollapsed || isDrawerMode || isDragging) {
       return;
     }
 
     setHover(true);
-    setContentWidth(currentProductNavWidth);
-  }, [isCollapsed, isDrawerMode, isDragging, setContentWidth, currentProductNavWidth]);
+  }, [isCollapsed, isDragging, isDrawerMode]);
 
   const hoverOutHandler = useCallback(() => {
     if (!isCollapsed || isDrawerMode || isDragging) {
@@ -149,8 +143,23 @@ const Sidebar: FC<Props> = (props: Props) => {
     }
 
     setHover(false);
-    setContentWidth(sidebarMinimizeWidth);
-  }, [isCollapsed, isDragging, isDrawerMode, setContentWidth]);
+  }, [isCollapsed, isDragging, isDrawerMode]);
+
+  const hoverOnResizableContainerHandler = useCallback(() => {
+    if (!isCollapsed || isDrawerMode || isDragging) {
+      return;
+    }
+
+    setHoverOnResizableContainer(true);
+  }, [isCollapsed, isDrawerMode, isDragging]);
+
+  const hoverOutResizableContainerHandler = useCallback(() => {
+    if (!isCollapsed || isDrawerMode || isDragging) {
+      return;
+    }
+
+    setHoverOnResizableContainer(false);
+  }, [isCollapsed, isDrawerMode, isDragging]);
 
   const toggleNavigationBtnClickHandler = useCallback(() => {
     const newValue = !isCollapsed;
@@ -163,7 +172,8 @@ const Sidebar: FC<Props> = (props: Props) => {
       setContentWidth(sidebarMinimizeWidth);
     }
     else {
-      setContentWidth(currentProductNavWidth);
+      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+      setContentWidth(currentProductNavWidth!);
     }
   }, [currentProductNavWidth, isCollapsed, setContentWidth]);
 
@@ -222,11 +232,47 @@ const Sidebar: FC<Props> = (props: Props) => {
 
   }, [dragableAreaMouseUpHandler, draggableAreaMoveHandler, isResizableByDrag]);
 
+  useEffect(() => {
+    setTimeout(() => {
+      setTransitionEnabled(true);
+    }, 1000);
+  }, []);
+
+  useEffect(() => {
+    toggleDrawerMode(isDrawerMode);
+  }, [isDrawerMode, toggleDrawerMode]);
+
+  // open/close resizable container
+  useEffect(() => {
+    if (isHoverOnResizableContainer) {
+      // schedule to open
+      timeoutIdRef.current = setTimeout(() => {
+        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        setContentWidth(currentProductNavWidth!);
+      }, 70);
+    }
+    else if (timeoutIdRef.current != null) {
+      // cancel schedule to open
+      clearTimeout(timeoutIdRef.current);
+      timeoutIdRef.current = undefined;
+    }
+
+    // close
+    if (!isHover) {
+      setContentWidth(sidebarMinimizeWidth);
+      timeoutIdRef.current = undefined;
+    }
+  }, [isHover, isHoverOnResizableContainer, currentProductNavWidth, setContentWidth]);
+
   return (
     <>
       <div className={`grw-sidebar d-print-none ${isDrawerMode ? 'grw-sidebar-drawer' : ''} ${isDrawerOpened ? 'open' : ''}`}>
         <div className="data-layout-container">
-          <div className={`navigation ${isTransitionEnabled ? 'transition-enabled' : ''}`} onMouseLeave={hoverOutHandler}>
+          <div
+            className={`navigation ${isTransitionEnabled ? 'transition-enabled' : ''}`}
+            onMouseEnter={hoverOnHandler}
+            onMouseLeave={hoverOutHandler}
+          >
             <div className="grw-navigation-wrap">
               <div className="grw-global-navigation">
                 <GlobalNavigation></GlobalNavigation>
@@ -235,6 +281,7 @@ const Sidebar: FC<Props> = (props: Props) => {
                 ref={resizableContainer}
                 className="grw-contextual-navigation"
                 onMouseEnter={hoverOnResizableContainerHandler}
+                onMouseLeave={hoverOutResizableContainerHandler}
                 style={{ width: isCollapsed ? sidebarMinimizeWidth : currentProductNavWidth }}
               >
                 <div className="grw-contextual-navigation-child">