Explorar o código

use SimpleBar

Yuki Takei %!s(int64=4) %!d(string=hai) anos
pai
achega
8591d363f7

+ 11 - 22
packages/app/src/components/Sidebar.tsx

@@ -2,8 +2,6 @@ import React, {
   FC, useCallback, useEffect, useRef, useState,
 } from 'react';
 
-import SimpleBar from 'simplebar-react';
-
 import { scheduleToPutUserUISettings } from '~/client/services/user-ui-settings';
 import {
   useDrawerMode, useDrawerOpened,
@@ -18,7 +16,7 @@ import DrawerToggler from './Navbar/DrawerToggler';
 import SidebarNav from './Sidebar/SidebarNav';
 import SidebarContents from './Sidebar/SidebarContents';
 import { NavigationResizeHexagon } from './Sidebar/NavigationResizeHexagon';
-import StickyStretchableScroller from './StickyStretchableScroller';
+import { StickyStretchableScroller } from './StickyStretchableScroller';
 
 const sidebarMinWidth = 240;
 const sidebarMinimizeWidth = 20;
@@ -52,33 +50,24 @@ const GlobalNavigation = () => {
 };
 
 const SidebarContentsWrapper = () => {
-  const [resetKey, setResetKey] = useState(0);
-
-  const scrollTargetSelector = '#grw-sidebar-contents-scroll-target';
-
   const calcViewHeight = useCallback(() => {
-    const scrollTargetElem = document.querySelector('#grw-sidebar-contents-scroll-target');
-    return scrollTargetElem != null
-      ? window.innerHeight - scrollTargetElem?.getBoundingClientRect().top
+    const elem = document.querySelector('#grw-sidebar-contents-wrapper');
+    return elem != null
+      ? window.innerHeight - elem?.getBoundingClientRect().top
       : window.innerHeight;
   }, []);
 
   return (
     <>
-      <StickyStretchableScroller
-        scrollTargetSelector={scrollTargetSelector}
-        contentsElemSelector="#grw-sidebar-content-container"
-        stickyElemSelector=".grw-sidebar"
-        calcViewHeightFunc={calcViewHeight}
-        resetKey={resetKey}
-      />
-
-      <div id="grw-sidebar-contents-scroll-target" style={{ minHeight: '100%' }}>
-        <SimpleBar style={{ minHeight: `${calcViewHeight()}px` }}>
-          <div id="grw-sidebar-content-container" className="grw-sidebar-content-container" onLoad={() => setResetKey(Math.random())}>
+      <div id="grw-sidebar-contents-wrapper" style={{ minHeight: '100%' }}>
+        <StickyStretchableScroller
+          stickyElemSelector=".grw-sidebar"
+          calcViewHeight={calcViewHeight}
+        >
+          <div id="grw-sidebar-content-container" className="grw-sidebar-content-container">
             <SidebarContents />
           </div>
-        </SimpleBar>
+        </StickyStretchableScroller>
       </div>
 
       <DrawerToggler iconClass="icon-arrow-left" />

+ 36 - 93
packages/app/src/components/StickyStretchableScroller.tsx

@@ -1,14 +1,22 @@
-import React, { useEffect, useCallback } from 'react';
-import PropTypes from 'prop-types';
+import React, {
+  useEffect, useCallback, ReactNode, useRef, useState, useMemo,
+} from 'react';
 
 import { debounce } from 'throttle-debounce';
 import StickyEvents from 'sticky-events';
+import SimpleBar from 'simplebar-react';
+
 import loggerFactory from '~/utils/logger';
-import { SidebarScrollerEvent } from '~/interfaces/ui';
 
 const logger = loggerFactory('growi:cli:StickyStretchableScroller');
 
 
+export type StickyStretchableScrollerProps = {
+  stickyElemSelector: string,
+  calcViewHeight?: (scrollElement: HTMLElement) => number,
+  children?: ReactNode,
+}
+
 /**
  * USAGE:
  *
@@ -22,89 +30,44 @@ const logger = loggerFactory('growi:cli:StickyStretchableScroller');
 
   return (
     <StickyStretchableScroller
-      contentsElemSelector="#long-contents-elem"
       stickyElemSelector="#sticky-elem"
-      calcViewHeightFunc={calcViewHeight}
+      calcViewHeight={calcViewHeight}
     >
-      <div id="scroll-elem">
+      <div>
         ...
       </div>
     </StickyStretchableScroller>
   );
-
-  or
-
-  return (
-    <StickyStretchableScroller
-      scrollTargetId="scroll-elem"
-      contentsElemSelector="#long-contents-elem"
-      stickyElemSelector="#sticky-elem"
-      calcViewHeightFunc={calcViewHeight}
-    />
-  );
  */
-const StickyStretchableScroller = (props) => {
+export const StickyStretchableScroller = (props: StickyStretchableScrollerProps): JSX.Element => {
 
-  let { scrollTargetSelector } = props;
   const {
-    children, contentsElemSelector, stickyElemSelector,
-    calcViewHeightFunc, calcContentsHeightFunc,
-    resetKey,
+    children, stickyElemSelector, calcViewHeight,
   } = props;
 
-  if (scrollTargetSelector == null && children == null) {
-    throw new Error('Either of scrollTargetSelector or children is required');
-  }
-
-  if (scrollTargetSelector == null) {
-    scrollTargetSelector = `#${children.props.id}`;
-  }
+  const simplebarRef = useRef<SimpleBar>(null);
+  const [simplebarMaxHeight, setSimplebarMaxHeight] = useState<number|undefined>();
 
   /**
    * Reset scrollbar
    */
   const resetScrollbar = useCallback(() => {
-    const contentsElem = document.querySelector(contentsElemSelector);
-    if (contentsElem == null) {
+    if (simplebarRef.current == null || calcViewHeight == null) {
       return;
     }
-    const viewHeight = calcViewHeightFunc != null
-      ? calcViewHeightFunc()
-      : 'auto';
-    const contentsHeight = calcContentsHeightFunc != null
-      ? calcContentsHeightFunc(contentsElem)
-      : contentsElem.getBoundingClientRect().height;
-
-    logger.debug(`[${scrollTargetSelector}] viewHeight`, viewHeight);
-    logger.debug(`[${scrollTargetSelector}] contentsHeight`, contentsHeight);
 
-    // const isScrollEnabled = viewHeight === 'auto' || (viewHeight < contentsHeight);
+    const scrollElement = simplebarRef.current.getScrollElement();
+    const newHeight = calcViewHeight(scrollElement);
 
-    // $(scrollTargetSelector).slimScroll({
-    //   color: '#666',
-    //   railColor: '#999',
-    //   railVisible: true,
-    //   position: 'right',
-    //   height: isScrollEnabled ? viewHeight : contentsHeight,
-    //   wheelStep: 10,
-    //   allowPageScroll: true,
-    // });
+    logger.debug('Set new height to simplebar', newHeight);
 
-    /**
-     * The below code is a workaround for the following effect
-     * The scrollbar doesn't move without mouseover event after applying slimscroll
-     * https://github.com/rochal/jQuery-slimScroll/issues/287#issuecomment-797090432
-     */
-    // $(scrollTargetSelector).trigger('mouseover');
+    // set new height
+    setSimplebarMaxHeight(newHeight);
+    // reculculate
+    simplebarRef.current.recalculate();
+  }, [calcViewHeight]);
 
-    // destroy
-    // if (!isScrollEnabled) {
-    //   $(scrollTargetSelector).slimScroll({ destroy: true });
-    // }
-
-  }, [contentsElemSelector, calcViewHeightFunc, calcContentsHeightFunc, scrollTargetSelector]);
-
-  const resetScrollbarDebounced = debounce(100, resetScrollbar);
+  const resetScrollbarDebounced = useMemo(() => debounce(100, resetScrollbar), [resetScrollbar]);
 
 
   // useEffect(() => {
@@ -114,20 +77,17 @@ const StickyStretchableScroller = (props) => {
   //   };
   // }, []);
 
-  const stickyChangeHandler = useCallback((event) => {
+  const stickyChangeHandler = useCallback(() => {
     logger.debug('StickyEvents.CHANGE detected');
-    setTimeout(resetScrollbar, 100);
-  }, [resetScrollbar]);
+    resetScrollbarDebounced();
+  }, [resetScrollbarDebounced]);
 
   // setup effect by sticky event
   useEffect(() => {
-    if (stickyElemSelector == null) {
-      return;
-    }
-
     // sticky
     // See: https://github.com/ryanwalters/sticky-events
     const stickyEvents = new StickyEvents({ stickySelector: stickyElemSelector });
+    stickyEvents.enableEvents();
     const { stickySelector } = stickyEvents;
     const elem = document.querySelector(stickySelector);
     elem.addEventListener(StickyEvents.CHANGE, stickyChangeHandler);
@@ -140,7 +100,7 @@ const StickyStretchableScroller = (props) => {
 
   // setup effect by resizing event
   useEffect(() => {
-    const resizeHandler = (event) => {
+    const resizeHandler = () => {
       resetScrollbarDebounced();
     };
 
@@ -154,29 +114,12 @@ const StickyStretchableScroller = (props) => {
 
   // setup effect on init
   useEffect(() => {
-    if (resetKey != null) {
-      resetScrollbarDebounced();
-    }
-  }, [resetKey, resetScrollbarDebounced]);
+    resetScrollbarDebounced();
+  }, [resetScrollbarDebounced]);
 
   return (
-    <>
+    <SimpleBar style={{ maxHeight: simplebarMaxHeight }} ref={simplebarRef}>
       { children }
-    </>
+    </SimpleBar>
   );
 };
-
-StickyStretchableScroller.propTypes = {
-  contentsElemSelector: PropTypes.string.isRequired,
-
-  children: PropTypes.node,
-  scrollTargetSelector: PropTypes.string,
-  stickyElemSelector: PropTypes.string,
-
-  resetKey: PropTypes.any,
-
-  calcViewHeightFunc: PropTypes.func,
-  calcContentsHeightFunc: PropTypes.func,
-};
-
-export default StickyStretchableScroller;

+ 2 - 3
packages/app/src/components/TableOfContents.jsx

@@ -10,7 +10,7 @@ import { blinkElem } from '~/client/util/blink-section-header';
 
 import { withUnstatedContainers } from './UnstatedUtils';
 
-import StickyStretchableScroller from './StickyStretchableScroller';
+import { StickyStretchableScroller } from './StickyStretchableScroller';
 
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:TableOfContents');
@@ -56,9 +56,8 @@ const TableOfContents = (props) => {
 
   return (
     <StickyStretchableScroller
-      contentsElemSelector=".revision-toc .markdownIt-TOC"
       stickyElemSelector=".grw-side-contents-sticky-container"
-      calcViewHeightFunc={calcViewHeight}
+      calcViewHeight={calcViewHeight}
     >
       { tocHtml !== ''
         ? (

+ 2 - 2
packages/app/src/styles/_sidebar.scss

@@ -74,7 +74,7 @@
             flex-direction: column;
             width: 100%;
             height: 100%;
-            overflow: hidden auto;
+            overflow: hidden;
           }
         }
       }
@@ -89,7 +89,7 @@
       top: 0px;
       bottom: 0px;
       left: 100%;
-      z-index: 100; // greater than the value of slimScrollBar
+      z-index: 10; // greater than the value of SimpleBar
       width: 0;
       .grw-navigation-draggable-hitarea {
         position: relative;