react-use#useScroll TypeScript Examples

The following examples show how to use react-use#useScroll. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: page-container.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
PageContainer = ({ route }: IProps) => {
  const [noAuth, notFound] = userStore.useStore((s: any) => [s.noAuth, s.notFound]);
  const currentOrg = orgStore.useStore((s) => s.currentOrg);
  const [showMessage, customMain] = layoutStore.useStore((s) => [s.showMessage, s.customMain]);
  const [currentRoute, prevRouteInfo] = routeInfoStore.useStore((s) => [s.currentRoute, s.prevRouteInfo]);
  const [state, updater] = useUpdate({
    startInit: false,
  });

  const mainEle = React.useRef<HTMLDivElement>(null);
  const { y } = useScroll(mainEle);

  useEffectOnce(() => {
    const skeleton = document.querySelector('#erda-skeleton');
    const content = document.querySelector('#erda-content');
    if (skeleton && content) {
      skeleton.className += ' fade';
      content.classList.remove('hidden');
      setTimeout(() => {
        skeleton.remove();
      }, 500);
    }
    emit('layout/mount');

    if (process.env.NODE_ENV === 'production') {
      checkVersion();
    }
    const checkLoginStatus = () => {
      agent.get('/api/users/me').catch((error: any) => {
        const { statusCode } = error.response;
        if ([401].includes(statusCode)) {
          userStore.effects.login();
        }
      });
    };

    // 注册并监听登录状态的变化
    LSObserver.watch('diceLoginState', (val: any) => {
      if (val.toString() === 'false' && currentOrg.id) {
        setTimeout(() => {
          checkLoginStatus();
        }, 0);
      }
    });

    // wait for layout complete
    setTimeout(() => {
      updater.startInit(true);
    }, 0);
  });

  React.useEffect(() => {
    if (prevRouteInfo?.currentRoute.path !== currentRoute.path) {
      if (mainEle && mainEle.current) {
        mainEle.current.scrollTop = 0;
      }
    }
  }, [currentRoute, prevRouteInfo, mainEle]);

  const { layout } = currentRoute;
  const hideHeader = showMessage || layout?.hideHeader;
  const layoutCls = [];
  let showSidebar = !noAuth && !notFound;
  let CustomLayout;
  let noWrapper = false;
  if (typeof layout === 'object') {
    const { className, use, hideSidebar } = layout;
    if (hideSidebar) showSidebar = false;
    className && layoutCls.push(className);
    layoutMap[use] && (CustomLayout = layoutMap[use]);
    noWrapper = layout.noWrapper;
  }
  const layoutClass = classnames(layoutCls);
  if (CustomLayout) {
    return <CustomLayout layoutClass={layoutClass}>{renderRoutes(route.routes)}</CustomLayout>;
  }
  let MainContent = null;
  if (noAuth) {
    MainContent = <NoAuth />;
  } else if (notFound) {
    MainContent = <NotFound />;
  } else if (state.startInit) {
    MainContent = <RenderMainContent noWrapper={noWrapper} customMain={customMain} route={route} layout={layout} />;
  }
  return (
    <Shell
      className={layoutClass}
      navigation={<Navigation />}
      sidebar={showSidebar ? <SideBar /> : undefined}
      breadcrumb={!hideHeader ? <Breadcrumb /> : undefined}
      announcement={!hideHeader ? <Announcement /> : undefined}
      mainClassName={classnames({ 'mt-0': hideHeader })}
    >
      {!hideHeader && (
        <>
          <Header layout={layout} />
          <div className={`main-scroll-tip ${y > 2 ? 'show' : ''}`} aria-hidden="true" />
        </>
      )}
      <div id="main" ref={mainEle} style={{ opacity: showMessage ? 0 : undefined }} className={hideHeader ? 'p-0' : ''}>
        {MainContent}
      </div>
      <MessageCenter show={showMessage} />
    </Shell>
  );
}
Example #2
Source File: issue-drawer.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
IssueDrawer = (props: IProps) => {
  const {
    className = '',
    canCreate = false,
    canDelete = false,
    children,
    editMode,
    shareLink,
    loading = false,
    visible,
    onClose,
    onDelete,
    confirmCloseTip,
    handleCopy,
    maskClosable,
    data,
    issueType,
    projectId,
    setData,
    header = IssueDrawer.Empty,
    footer = IssueDrawer.Empty,
    extraHeaderOp = null,
    detailTitle,
    ...rest
  } = props;
  const [
    formField = IssueDrawer.Empty,
    descField = IssueDrawer.Empty,
    workflowField = IssueDrawer.Empty,
    inclusionField = IssueDrawer.Empty,
    relationField = IssueDrawer.Empty,
    logField = IssueDrawer.Empty,
  ] = React.Children.toArray(children);

  const customFieldDetail = issueStore.useStore((s) => s.customFieldDetail);
  const escStack = layoutStore.useStore((s) => s.escStack);
  const [copyTitle, setCopyTitle] = React.useState('');
  const [isChanged, setIsChanged] = React.useState(false);
  const [showCopy, setShowCopy] = React.useState(false);
  const [showAnchor, setShowAnchor] = React.useState(false);
  const preDataRef = React.useRef(data);
  const preData = preDataRef.current;

  const escClose = React.useCallback(
    (e) => {
      if (e.key === 'Escape') {
        if (escStack.length) {
          return;
        }
        if (isChanged && confirmCloseTip) {
          Modal.confirm({
            title: confirmCloseTip,
            onOk() {
              onClose(e);
            },
          });
        } else {
          onClose(e);
        }
      }
    },
    [confirmCloseTip, escStack, isChanged, onClose],
  );

  useEvent('keydown', escClose);

  React.useEffect(() => {
    const isIssueDrawerChanged = (initData: CreateDrawerData, currentData: CreateDrawerData) => {
      setIsChanged(false);

      Object.keys(currentData).forEach((key) => {
        if (key in initData) {
          if (!isEqual(initData[key], currentData[key])) {
            setIsChanged(true);
          }
        } else {
          const defaultValue = find(customFieldDetail?.property, { propertyName: key })?.values;

          // Determine whether the field has changed. When the value is the following conditions, the field has not changed
          const notChange =
            isEqual(defaultValue, currentData[key]) ||
            currentData[key] === undefined ||
            currentData[key] === '' ||
            isEqual(currentData[key], []) ||
            isEqual(currentData[key], { estimateTime: 0, remainingTime: 0 });

          if (!notChange) {
            setIsChanged(true);
          }
        }
      });
    };
    isIssueDrawerChanged(preData, data);
  }, [customFieldDetail?.property, data, preData]);

  const mainEle = React.useRef<HTMLDivElement>(null);
  const { y } = useScroll(mainEle);

  React.useLayoutEffect(() => {
    let timer: NodeJS.Timeout;
    if (mainEle.current) {
      // wait for layout stable
      timer = setTimeout(() => {
        setShowAnchor(true);
      }, 1000);
    }
    return () => timer && clearTimeout(timer);
  }, []);

  return (
    <Modal
      wrapClassName="issue-drawer-modal"
      className={`task-drawer ${className}`}
      width="calc(100% - 80px)"
      closable={false}
      visible={visible}
      onCancel={onClose}
      footer={null}
      maskClosable={maskClosable || !isChanged}
      keyboard={false}
      forceRender // useScroll will not take effect if mainRel is lazy mounted
      {...rest}
    >
      <Spin spinning={loading}>
        <div className="relative flex flex-col" style={{ height: 'calc(100vh - 80px)' }}>
          <If condition={header !== IssueDrawer.Empty}>
            <div className={`task-drawer-header ${y > 2 ? 'shadow-card' : ''}`}>
              <div className="flex justify-between items-center">
                <div className="flex-1 nowrap">{typeof header === 'function' ? header(y) : header}</div>
                <div className="task-drawer-op flex items-center">
                  {extraHeaderOp}
                  <SubscribersSelector
                    subscribers={data.subscribers}
                    issueID={customFieldDetail?.issueID}
                    issueType={issueType}
                    projectId={projectId}
                    setData={setData}
                    data={data}
                  />
                  <If condition={editMode && shareLink}>
                    <Copy selector=".copy-share-link" tipName={i18n.t('dop:link-share')} />
                    <ErdaIcon
                      type="lianjie"
                      className="cursor-copy hover-active copy-share-link ml-4 text-default-6"
                      size="20"
                      data-clipboard-text={shareLink}
                    />
                  </If>
                  <If condition={editMode}>
                    <WithAuth pass={canCreate}>
                      <Popover
                        title={i18n.t('dop:Copy issue')}
                        visible={showCopy}
                        onVisibleChange={(v) => setShowCopy(v)}
                        content={
                          <>
                            <Input
                              placeholder={i18n.t('dop:Please enter the issue title')}
                              style={{ width: 400 }}
                              value={copyTitle}
                              onChange={(e) => setCopyTitle(e.target.value)}
                            />
                            <div className="flex items-center flex-wrap justify-end mt-2">
                              <Button
                                className="mr-2"
                                onClick={() => {
                                  setCopyTitle('');
                                  setShowCopy(false);
                                }}
                              >
                                {i18n.t('Cancel')}
                              </Button>
                              <Button
                                onClick={() => {
                                  if (copyTitle === '') {
                                    message.error(i18n.t('dop:The title can not be empty'));
                                    return;
                                  }
                                  handleCopy && handleCopy(true, copyTitle);
                                  setCopyTitle('');
                                  setShowCopy(false);
                                }}
                                type="primary"
                              >
                                {i18n.t('Copy')}
                              </Button>
                            </div>
                          </>
                        }
                        placement="leftTop"
                        trigger="click"
                      >
                        <ErdaIcon type="fuzhi" className="hover-active ml-4 text-default-6" size="20" />
                      </Popover>
                    </WithAuth>
                  </If>
                  {onDelete ? (
                    <WithAuth pass={canDelete}>
                      <Popconfirm
                        title={`${i18n.t('common:confirm to delete')}?`}
                        placement="bottomRight"
                        onConfirm={onDelete}
                      >
                        <ErdaIcon type="shanchu-4d7l02mb" className="hover-active ml-4 text-default-6" size="20" />
                      </Popconfirm>
                    </WithAuth>
                  ) : null}
                  {isChanged && confirmCloseTip ? (
                    <Popconfirm title={confirmCloseTip} placement="bottomRight" onConfirm={onClose}>
                      <ErdaIcon type="guanbi" className="ml-4 hover-active text-default-6" size="20" />
                    </Popconfirm>
                  ) : (
                    <ErdaIcon type="guanbi" className="ml-4 hover-active text-default-6" size="20" onClick={onClose} />
                  )}
                </div>
              </div>
            </div>
          </If>
          <div
            ref={mainEle}
            className="relative flex-1 overflow-x-hidden overflow-y-auto"
            style={footer !== IssueDrawer.Empty ? { padding: '0 12% 60px' } : { padding: '0 12%' }}
          >
            <If condition={editMode && showAnchor}>
              <div className="absolute">
                <Anchor offsetTop={16} getContainer={() => mainEle.current || document.body}>
                  {formField !== IssueDrawer.Empty && <Anchor.Link href="#field" title={i18n.t('dop:Basic')} />}
                  {descField !== IssueDrawer.Empty && <Anchor.Link href="#desc" title={i18n.t('dop:Content')} />}
                  {workflowField !== IssueDrawer.Empty && (
                    <Anchor.Link href="#workflow" title={i18n.t('dop:workflow')} />
                  )}
                  {inclusionField !== IssueDrawer.Empty && (
                    <Anchor.Link href="#inclusion" title={i18n.t('dop:Contain')} />
                  )}
                  {relationField !== IssueDrawer.Empty && (
                    <Anchor.Link href="#relation" title={i18n.t('dop:Reference')} />
                  )}
                  {logField !== IssueDrawer.Empty && <Anchor.Link href="#log" title={i18n.t('dop:Log')} />}
                </Anchor>
              </div>
            </If>
            <If condition={formField !== IssueDrawer.Empty}>
              <div id="field">{formField}</div>
            </If>
            <If condition={descField !== IssueDrawer.Empty}>
              <div id="desc" className="h-px bg-default-08 my-4" />
              {descField}
            </If>
            <If condition={workflowField !== IssueDrawer.Empty}>
              <div id="workflow" className="mt-6">
                {workflowField}
              </div>
            </If>
            <If condition={inclusionField !== IssueDrawer.Empty}>
              <div id="inclusion" className="mt-6">
                {inclusionField}
              </div>
            </If>
            <If condition={relationField !== IssueDrawer.Empty}>
              <div id="relation" className="mt-6">
                {relationField}
              </div>
            </If>
            <If condition={logField !== IssueDrawer.Empty}>
              <div id="log" className="mt-6">
                {logField}
              </div>
            </If>
          </div>
          <If condition={footer !== IssueDrawer.Empty}>
            <div className="task-drawer-footer">
              {typeof footer === 'function' ? footer(isChanged, confirmCloseTip) : footer}
            </div>
          </If>
        </div>
      </Spin>
    </Modal>
  );
}
Example #3
Source File: HorizontalScrollable.tsx    From oxen-website with GNU General Public License v3.0 4 votes vote down vote up
function HorizontalScrollableInner(props: Props) {
  const { onItemClick, children } = props;

  const scrollRef = useRef(null);
  const innerContentRef = useRef(null);

  const { x } = useScroll(scrollRef);
  const pageWidth = useWindowSize().width;
  const scrollDistance = pageWidth > 1400 ? 450 : pageWidth / 3;

  const [rightScrollHidden, setRightScrollHidden] = useState(false);

  const { isDesktop } = useContext(ScreenContext);

  const handleLeftScroll = () => {
    scrollRef.current.scrollBy({
      left: -scrollDistance,
      behavior: 'smooth',
    });
  };

  const handleRightScroll = () => {
    scrollRef.current.scrollBy({
      left: scrollDistance,
      behavior: 'smooth',
    });
  };

  function handleItemClick() {
    if (onItemClick) {
      onItemClick();
    }
  }

  useEffect(() => {
    const isFullRight =
      scrollRef.current.scrollWidth - scrollRef.current.clientWidth ===
      scrollRef.current.scrollLeft;

    const tooSmallToScroll =
      innerContentRef.current.clientWidth < scrollRef.current.clientWidth;

    setRightScrollHidden(tooSmallToScroll || isFullRight);
  }, [x, children]);

  return (
    <div className="relative flex w-full">
      <div
        className={classNames(
          'absolute left-0 flex items-center justify-between h-full w-full',
          !isDesktop && 'hidden',
        )}
      >
        <div
          className={classNames(
            'flex flex-col justify-center h-full z-50 duration-300 -ml-8',
            x <= 1 && 'opacity-0',
          )}
        >
          <LeftOutlined
            onClick={handleLeftScroll}
            className={classNames('h-20 mt-1 cursor-pointer')}
          />
        </div>

        <div
          className={classNames(
            'flex flex-col justify-center h-full z-50 duration-300 -mr-8',
            rightScrollHidden && 'opacity-0',
          )}
        >
          <RightOutlined
            onClick={handleRightScroll}
            className="h-20 mt-1 cursor-pointer"
          />
        </div>
      </div>
      <div
        ref={scrollRef}
        className={classNames(
          'relative',
          'w-full',
          'hide_scroll',
          'scrolling-touch hide-scroll',
          isDesktop ? 'overflow-x-scroll' : 'overflow-x-scroll',
        )}
      >
        <div
          ref={innerContentRef}
          className={classNames('flex space-x-8 overflow-y-visible')}
          style={{
            width: 'min-content',
            marginLeft: `${!isDesktop ? UI.PAGE_CONTAINED_PADDING_VW : 0}vw`,
            paddingRight: `${!isDesktop ? UI.PAGE_CONTAINED_PADDING_VW : 0}vw`,
          }}
        >
          {children}
        </div>
      </div>
    </div>
  );
}