react-transition-group#CSSTransition TypeScript Examples

The following examples show how to use react-transition-group#CSSTransition. 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: NoConnectionIndicator.tsx    From atlas with GNU General Public License v3.0 6 votes vote down vote up
NoConnectionIndicator: React.FC<NoConnectionIndicatorProps> = ({
  nodeConnectionStatus,
  isConnectedToInternet,
  hasSidebar,
}) => {
  return (
    <CSSTransition
      in={nodeConnectionStatus === 'disconnected' || !isConnectedToInternet}
      timeout={{
        enter: parseInt(cVar('animationTimingMedium', true)) + ENTER_TRANSITION_DELAY,
        exit: parseInt(cVar('animationTimingMedium', true)),
      }}
      classNames={CONNECTION_INDICATOR_CLASSNAME}
      mountOnEnter
      unmountOnExit
    >
      <IndicatorWrapper hasSidebar={hasSidebar}>
        <IconWrapper>
          <SvgAlertsWarning24 />
        </IconWrapper>
        <TextWrapper>
          {!isConnectedToInternet ? (
            <Text variant="h400">No network connection</Text>
          ) : (
            nodeConnectionStatus === 'disconnected' && <Text variant="t200">No node connection</Text>
          )}
          <Text variant="t200" secondary>
            Wait for connection to restore
          </Text>
        </TextWrapper>
      </IndicatorWrapper>
    </CSSTransition>
  )
}
Example #2
Source File: index.tsx    From hive with MIT License 6 votes vote down vote up
render() {
        const { location } = this.props;
        const currentKey = location.pathname || '/';
        const timeout = { enter: 300, exit: 200 };

        return (
            <Fragment>
                <WidthCalculator />
                <Tabs location={location} />
                <TransitionGroup component="div" className={styles.mainTransition}>
                    <CSSTransition
                        key={currentKey}
                        timeout={timeout}
                        classNames="animated-fade"
                        appear
                    >
                        <div className={styles.transition}>
                            <Switch location={location}>
                                <AuthorizedRoute path={constants.paths.admin} component={Admin} />
                                <AuthorizedRoute
                                    path={constants.paths.dashboard}
                                    component={Dashboard}
                                />
                            </Switch>
                        </div>
                    </CSSTransition>
                </TransitionGroup>
            </Fragment>
        );
    }
Example #3
Source File: App.tsx    From RPG-Inventory-UI with GNU General Public License v3.0 6 votes vote down vote up
render() {
        return (
            <CSSTransition
                in={inventoryStore.inventoryVisible}
                classNames='transitionOpacity'
                timeout={500}
                unmountOnExit
            >
                <div className="viewport">
                    <div className="blurBackground"></div>
                    <React.Suspense fallback="loading">
                        <Inventory />
                    </React.Suspense>
                </div>
            </CSSTransition>
        )
    }
Example #4
Source File: Logo.tsx    From apps with GNU Affero General Public License v3.0 6 votes vote down vote up
export default function Logo({
  showGreeting,
  onLogoClick,
}: LogoProps): ReactElement {
  return (
    <LinkWithTooltip
      href={process.env.NEXT_PUBLIC_WEBAPP_URL}
      passHref
      prefetch={false}
      tooltip={{ placement: 'right', content: 'Home' }}
    >
      {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
      <a className="flex items-center" onClick={onLogoClick}>
        <LogoIcon className="h-logo" />
        <CSSTransition
          in={!showGreeting}
          timeout={500}
          classNames="fade"
          unmountOnExit
        >
          <LogoText className="hidden laptop:block ml-1 h-logo" />
        </CSSTransition>
      </a>
    </LinkWithTooltip>
  );
}
Example #5
Source File: LaunchpadWrapper.spec.tsx    From next-basics with GNU General Public License v3.0 6 votes vote down vote up
describe("LaunchpadWrapper", () => {
  it("should fade out when launchpad will close", async () => {
    const handleWillClose = jest.fn();
    const handleClose = jest.fn();
    const wrapper = mount(
      <LaunchpadWrapper onWillClose={handleWillClose} onClose={handleClose} />
    );
    act(() => {
      wrapper.find(Launchpad).invoke("onWillClose")();
    });
    wrapper.update();
    expect(wrapper.find(CSSTransition).prop("in")).toBe(false);
    expect(handleWillClose).toBeCalled();

    expect(handleClose).not.toBeCalled();
    await jest.advanceTimersByTime(wrapper
      .find(CSSTransition)
      .prop("timeout") as number);
    expect(handleClose).toBeCalled();
  });
});
Example #6
Source File: index.tsx    From vagasExplorer with MIT License 6 votes vote down vote up
Routes: React.FC<ToggleTheme> = ({ toggleTheme }) => (
  <Route
    render={({ location }) => (
      <TransitionGroup>
        <CSSTransition key={location.key} timeout={300} classNames="fade">
          <Switch location={location}>
            <Route
              exact
              path="/"
              component={() => <Home toggleTheme={toggleTheme} />}
            />
            <Route
              exact
              path="/dashboard"
              component={() => <Dashboard toggleTheme={toggleTheme} />}
            />
            <Route
              path="/repository/:repository+"
              component={() => <Repository toggleTheme={toggleTheme} />}
            />
          </Switch>
        </CSSTransition>
      </TransitionGroup>
    )}
  />
)
Example #7
Source File: index.tsx    From polkabtc-ui with Apache License 2.0 6 votes vote down vote up
TransitionWrapper = ({
  location,
  children
}: Props): JSX.Element => (
  <TransitionGroup>
    <CSSTransition
      key={location.key}
      classNames='fade'
      timeout={300}>
      {children}
    </CSSTransition>
  </TransitionGroup>
)
Example #8
Source File: Alerts.tsx    From flood with GNU General Public License v3.0 6 votes vote down vote up
Alerts: FC = observer(() => {
  const {sortedAlerts} = AlertStore;

  return (
    <TransitionGroup>
      {sortedAlerts != null && sortedAlerts.length > 0 ? (
        <CSSTransition classNames="alerts__list" timeout={{enter: 250, exit: 250}}>
          <ul className="alerts__list" key="alerts-list">
            {sortedAlerts.map((alert) => (
              <Alert key={alert.id} id={alert.id} />
            ))}
          </ul>
        </CSSTransition>
      ) : null}
    </TransitionGroup>
  );
})
Example #9
Source File: MinimizedChats.tsx    From foodie with MIT License 6 votes vote down vote up
MinimizedChats: React.FC<IProps> = ({ users }) => {
    const dispatch = useDispatch();

    return (
        <div className="p-4 absolute bottom-0 right-0">
            <TransitionGroup component={null}>
                {users.map(chat => chat.minimized && (
                    <CSSTransition
                        timeout={500}
                        classNames="fade"
                        key={chat.username}
                    >
                        <div
                            key={chat.username}
                            onClick={() => dispatch(initiateChat(chat))}
                            title={chat.username}
                        >
                            <Avatar
                                url={chat.profilePicture?.url}
                                size="lg"
                                className="cursor-pointer shadow-md hover:border-2 hover:border-indigo-500 hover:opacity-90  mr-2 my-4 border border-indigo-700"
                            />
                        </div>
                    </CSSTransition>
                ))}
            </TransitionGroup>
        </div>
    );
}
Example #10
Source File: Modal.tsx    From mStable-apps with GNU Lesser General Public License v3.0 6 votes vote down vote up
Animation = styled(CSSTransition)<{ classNames: string }>`
  transform-origin: 50% 50%;
  &.item-enter-active {
    animation: ${css`
        ${scale}`} 0.25s cubic-bezier(0.19, 1, 0.22, 1);
  }

  &.item-exit-active {
    animation: ${css`
        ${scale}`} 0.2s cubic-bezier(0.19, 1, 0.22, 1) reverse;
  }
`
Example #11
Source File: app.tsx    From Aragorn with MIT License 6 votes vote down vote up
App = () => {
  useAppStateHandle();
  useAppUpdateHandle();
  useFileDownloadHandle();
  const platform = usePlatform();

  return (
    <HashRouter>
      {platform === 'win32' && <WindowButton />}
      <SideBar className={platform === 'win32' ? 'app-win32-wrapper' : ''} routes={routes} />
      <div className="page-container">
        {routes.map(
          route =>
            route.path && (
              <Route key={route.path} path={route.path} exact>
                {({ match }) => (
                  <CSSTransition in={match !== null} exit={false} timeout={300} classNames="page" unmountOnExit>
                    <div className="page">
                      <div
                        className={
                          platform === 'win32'
                            ? 'app-main-content-wrapper app-win32-wrapper'
                            : 'app-main-content-wrapper'
                        }
                      >
                        {route.component && <route.component />}
                      </div>
                    </div>
                  </CSSTransition>
                )}
              </Route>
            )
        )}
      </div>
    </HashRouter>
  );
}
Example #12
Source File: index.tsx    From oasis-wallet-web with Apache License 2.0 6 votes vote down vote up
export function TransitionRoute(props: Props) {
  const fullPath = props.path
  const Component = props.component as any
  const nodeRef = useRef(null)
  let match = useRouteMatch(fullPath)

  return (
    <Route exact={props.exact} path={fullPath} key={props.path}>
      <CSSTransition
        in={match != null}
        timeout={300}
        classNames="fade"
        key={props.path}
        nodeRef={nodeRef}
        unmountOnExit
      >
        <Transition ref={nodeRef}>
          <Component />
        </Transition>
      </CSSTransition>
    </Route>
  )
}
Example #13
Source File: App.transitions.tsx    From tezos-academy with MIT License 6 votes vote down vote up
AppTransitions = ({ pageKey, children, reverse }: { pageKey: any; children: any; reverse: boolean }) => {
  const { pathname } = useLocation()

  useEffect(() => {
    window.scrollTo(0, 0)
  }, [pathname])

  const animation = reverse ? 'slide-right' : 'slide-left'

  return (
    <TransitionGroup
      childFactory={childFactoryCreator({
        classNames: animation,
        timeout: 300,
      })}
    >
      <CSSTransition timeout={0} key={pageKey}>
        <AppWrapper>{children}</AppWrapper>
      </CSSTransition>
    </TransitionGroup>
  )
}
Example #14
Source File: index.tsx    From interactsh-web with MIT License 6 votes vote down vote up
AnimatedSwitch = withRouter(({ location }) => {
  window.scrollTo(0, 0);
  document.getElementsByTagName("html")[0].style.overflow = "visible";
  return (
    <TransitionGroup>
      <CSSTransition key={location.pathname} classNames="slide slide" timeout={10}>
        <Switch>
          <Route exact path="/" component={HomePage} />
          <Route exact path="/terms" component={TermsPage} />
        </Switch>
      </CSSTransition>
    </TransitionGroup>
  );
})
Example #15
Source File: FadeTransition.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
export function FadeTransition(props: Props) {
  const { visible, children, duration = 250 } = props;
  const styles = getStyles(duration);
  return (
    <CSSTransition in={visible} mountOnEnter={true} unmountOnExit={true} timeout={duration} classNames={styles}>
      {children}
    </CSSTransition>
  );
}
Example #16
Source File: Avatar.tsx    From atlas with GNU General Public License v3.0 5 votes vote down vote up
Avatar: React.FC<AvatarProps> = ({
  assetUrl,
  hasAvatarUploadFailed,
  withoutOutline,
  loading = false,
  size = 'default',
  children,
  onClick,
  className,
  editable,
  newChannel,
  clickable,
  onError,
}) => {
  const isEditable = !loading && editable && size !== 'default' && size !== 'bid'

  return (
    <Container
      as={onClick ? 'button' : 'div'}
      type={onClick ? 'button' : undefined}
      onClick={onClick}
      size={size}
      className={className}
      isLoading={loading}
      withoutOutline={withoutOutline}
      isClickable={clickable || !!onClick}
    >
      {isEditable && (
        <EditOverlay size={size}>
          <SvgActionImage />
          <span>{assetUrl ? 'Edit avatar' : 'Add avatar'}</span>
        </EditOverlay>
      )}
      {!children &&
        (newChannel && !isEditable ? (
          <NewChannelAvatar>
            <SvgActionNewChannel />
          </NewChannelAvatar>
        ) : (
          <SwitchTransition>
            <CSSTransition
              key={loading ? 'placeholder' : 'content'}
              timeout={parseInt(transitions.timings.loading)}
              classNames={transitions.names.fade}
            >
              {loading ? (
                <StyledSkeletonLoader rounded />
              ) : assetUrl ? (
                <StyledImage src={assetUrl} onError={onError} />
              ) : hasAvatarUploadFailed ? (
                <NewChannelAvatar>
                  <StyledSvgIllustrativeFileFailed />
                </NewChannelAvatar>
              ) : (
                <SilhouetteAvatar />
              )}
            </CSSTransition>
          </SwitchTransition>
        ))}
      {children && (loading ? <StyledSkeletonLoader rounded /> : <ChildrenWrapper>{children}</ChildrenWrapper>)}
    </Container>
  )
}
Example #17
Source File: Greeting.tsx    From apps with GNU Affero General Public License v3.0 5 votes vote down vote up
export default function Greeting({
  onEnter,
  onExit,
  user,
}: {
  user?: LoggedUser;
  onEnter: () => unknown;
  onExit: () => unknown;
}): ReactElement {
  const [show, setShow] = useState(false);

  const greetingElement = useMemo(() => {
    const firstName = user?.name?.split?.(' ')?.[0];
    const greeting = getGreetingData();
    return (
      <div className="ml-2 font-bold typo-callout">
        {greeting.text}
        {firstName && (
          <span className="hidden laptop:inline">, {firstName}</span>
        )}{' '}
        {greeting.emoji}
      </div>
    );
  }, []);

  useEffect(() => {
    (async () => {
      const media = window.matchMedia(tablet.replace('@media ', ''));
      if (!media.matches) {
        return;
      }

      const now = new Date();
      const lastGreeting = await getCache<Date>('greeting');
      const showGreeting =
        !lastGreeting ||
        !isSameDay(now, lastGreeting) ||
        getGreetingSlot(lastGreeting.getHours()) !==
          getGreetingSlot(now.getHours());
      if (showGreeting) {
        await setCache('greeting', now);
        setTimeout(() => {
          onEnter();
          setTimeout(() => {
            setShow(true);
            setTimeout(() => setShow(false), 7000);
          }, 500);
        }, 1500);
      }
    })();
  }, []);

  return (
    <CSSTransition
      in={show}
      timeout={500}
      classNames="fade"
      unmountOnExit
      onExited={onExit}
    >
      {greetingElement}
    </CSSTransition>
  );
}
Example #18
Source File: FilterCard.tsx    From crypto-fees with MIT License 5 votes vote down vote up
FilterCard: React.FC<FilterCardProps> = ({ open, /*onClose,*/ filters, onFilterChange }) => {
  return (
    <Fragment>
      <CSSTransition in={open} transitionName="example" timeout={500} unmountOnExit>
        <div className="filers-card">
          <div className="column">
            <div className="title">Categories</div>
            <ToggleList
              items={allCategories}
              selected={filters.categories}
              onSelectedChanged={(categories: string[]) =>
                onFilterChange({ ...filters, categories })
              }
            />
          </div>

          <div className="column">
            <div className="title">Blockchain</div>
            <ToggleList
              items={allChains}
              selected={filters.chains}
              onSelectedChanged={(chains: string[]) => onFilterChange({ ...filters, chains })}
            />
          </div>
        </div>
      </CSSTransition>

      <style jsx>{`
        @keyframes filter-slidein {
          from {
            height: 0px;
          }

          to {
            height: ${height}px;
          }
        }

        @keyframes filter-slideout {
          from {
            height: ${height}px;
          }

          to {
            height: 0px;
          }
        }

        .title {
          font-size: 12px;
          font-weight: 700;
          padding: 4px;
        }

        .column {
          flex: 1;
          padding: 8px;
        }

        .filers-card {
          height: ${height}px;
          animation: 0.5s 1 filter-slidein;
          overflow: hidden;
          display: flex;
          width: 100%;
        }

        .filers-card.exit {
          height: 0;
          animation: 0.5s 1 filter-slideout;
        }
      `}</style>
    </Fragment>
  );
}
Example #19
Source File: CollectWinningsPopup.tsx    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
CollectWinningsPopup = () => {
  const [isOpen, setIsOpen] = useState(false)
  const { t } = useTranslation()
  const ref = useRef(null)
  const timer = useRef(null)
  const { account } = useWeb3React()
  const predictionStatus = useGetPredictionsStatus()
  const isHistoryPaneOpen = useIsHistoryPaneOpen()
  const dispatch = useAppDispatch()

  const handleOpenHistory = () => {
    dispatch(setHistoryPaneState(true))
  }

  const handleClick = () => {
    setIsOpen(false)
    clearInterval(timer.current)
  }

  // Check user's history for unclaimed winners
  useEffect(() => {
    let isCancelled = false
    if (account) {
      timer.current = setInterval(async () => {
        const bets = await getBetHistory({ user: account.toLowerCase(), claimed: false })

        if (!isCancelled) {
          // Filter out bets that were not winners
          const winnerBets = bets.filter((bet) => {
            return bet.position === bet.round.position
          })

          if (!isHistoryPaneOpen) {
            setIsOpen(winnerBets.length > 0)
          }
        }
      }, 30000)
    }

    return () => {
      clearInterval(timer.current)
      isCancelled = true
    }
  }, [account, timer, predictionStatus, setIsOpen, isHistoryPaneOpen])

  // Any time the history pane is open make sure the popup closes
  useEffect(() => {
    if (isHistoryPaneOpen) {
      setIsOpen(false)
    }
  }, [isHistoryPaneOpen, setIsOpen])

  return (
    <CSSTransition in={isOpen} unmountOnExit nodeRef={ref} timeout={1000} classNames="popup">
      <Wrapper ref={ref}>
        <Popup>
          <TrophyGoldIcon width="64px" style={{ flex: 'none' }} mr="8px" />
          <Button style={{ flex: 1 }} onClick={handleOpenHistory}>
            {t('Collect Winnings')}
          </Button>
          <IconButton variant="text" onClick={handleClick}>
            <CloseIcon color="primary" width="24px" />
          </IconButton>
        </Popup>
      </Wrapper>
    </CSSTransition>
  )
}
Example #20
Source File: AppWrapper.tsx    From flood with GNU General Public License v3.0 5 votes vote down vote up
AppWrapper: FC<AppWrapperProps> = observer(({children, className}: AppWrapperProps) => {
  const navigate = useNavigate();

  const [searchParams] = useSearchParams();

  useEffectOnce(() => {
    AuthActions.verify().then(
      ({initialUser}: {initialUser?: boolean}): void => {
        if (initialUser) {
          navigate('/register', {replace: true});
        } else {
          navigate('/overview', {replace: true});
        }
      },
      (): void => {
        navigate('/login', {replace: true});
      },
    );
  });

  if (searchParams.has('action')) {
    if (searchParams.get('action') === 'add-urls') {
      if (searchParams.has('url')) {
        UIStore.setActiveModal({
          id: 'add-torrents',
          tab: 'by-url',
          urls: [{id: 0, value: searchParams.get('url') as string}],
        });
      }
    }
  }

  let overlay: ReactNode = null;
  if (!AuthStore.isAuthenticating || (AuthStore.isAuthenticated && !UIStore.haveUIDependenciesResolved)) {
    overlay = <LoadingOverlay dependencies={UIStore.dependencies} />;
  }

  if (AuthStore.isAuthenticated && !ClientStatusStore.isConnected && ConfigStore.authMethod !== 'none') {
    overlay = (
      <div className="application__loading-overlay">
        <div className="application__entry-barrier">
          <LogoutButton className={css({position: 'absolute', left: '5px', top: '5px'})} />
          <ClientConnectionInterruption />
        </div>
      </div>
    );
  }

  return (
    <div className={classnames('application', className)}>
      <WindowTitle />
      <TransitionGroup>
        {overlay != null ? (
          <CSSTransition timeout={{enter: 1000, exit: 1000}} classNames="application__loading-overlay">
            {overlay}
          </CSSTransition>
        ) : null}
      </TransitionGroup>
      {children}
    </div>
  );
})
Example #21
Source File: CommentList.tsx    From foodie with MIT License 5 votes vote down vote up
CommentList: React.FC<IProps> = ({ comments, updateCommentCallback }) => {
    const didMount = useDidMount();
    const dispatch = useDispatch();
    const [replies, setReplies] = useState<IComment[]>(comments);
    const { isOpen, closeModal, openModal } = useModal();

    useEffect(() => {
        didMount && setReplies(comments);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [comments]);

    const deleteSuccessCallback = (comment: IComment) => {
        if (didMount) {
            (updateCommentCallback) && updateCommentCallback(comment); // For updating the base/parent comment
            dispatch(setTargetComment(null));
            setReplies(oldComments => oldComments.filter((cmt) => cmt.id !== comment.id));
        }
    }

    return (
        <TransitionGroup component={null}>
            {replies.map(comment => (
                <CSSTransition
                    timeout={500}
                    classNames="fade"
                    key={comment.id}
                >
                    <CommentItem openDeleteModal={openModal} comment={comment} />
                </CSSTransition>
            ))}
            {/* ---- DELETE MODAL ---- */}
            <Suspense fallback={<LoadingOutlined className="text-gray-800 dark:text-white" />}>
                {isOpen && (
                    <DeleteCommentModal
                        isOpen={isOpen}
                        closeModal={closeModal}
                        deleteSuccessCallback={deleteSuccessCallback}
                    />
                )}
            </Suspense>
        </TransitionGroup>
    );
}
Example #22
Source File: ResultBox.tsx    From art with MIT License 5 votes vote down vote up
render() {
    let museumName = this.props.data.Museum === "met" ? "The Met" : "The Rijks";

    return (

      <Card className="grid-card" onMouseEnter={() => this.setState({ hover: true })} onMouseLeave={() => this.setState({ hover: false })}>
        <Card.Item className="grid-card__link">
          <div onClick={() => {
            if (isBeta) {
              window.location.href = urlEncodeArt(this.props.data.id);
            } else {
              this.openModal()
            };
          }}> 
            <LazyLoad
              throttle={250}
              height={200}
              offset={1000}
              placeholder={<CircularProgress style={{ color: '#6A6A6A' }} />}
            >
              <Image className="grid-card__img" alt="thumbnail" src={this.props.data.Thumbnail_Url} imageFit={ImageFit.contain} />
            </LazyLoad>
          </div>
          <Popup
            open={this.state.open}
            closeOnDocumentClick
            onClose={this.closeModal}
          >
            <div className="modal">
              <button className="close" onClick={this.closeModal}>
                &times;
              </button>
              {betaMessageDiv}
            </div>
          </Popup>

        </Card.Item>
        <Card.Item>
          <div className="grid-card__title" style={{ marginTop: -10, textAlign: "center" }}>{!this.props.data.Title ?
            "Untitled Piece" :
            this.props.data.Title.length < 55 ? this.props.data.Title : this.props.data.Title.substring(0, 55) + "..."}</div>
        </Card.Item>
        <Card.Item >
          <div className="grid-card__text" style={{ marginTop: -10, textAlign: "center" }}>{!this.props.data.Artist ? "No known artist" : this.props.data.Artist}</div>
        </Card.Item>
        <Card.Item>
          <CSSTransition in={this.state.hover} timeout={0} classNames="grid-card__slide">
            <Stack horizontal className="grid-card__buttons">
              <a
                href={this.props.data.Museum_Page}
                onClick={() => this.props.handleTrackEvent("Source", { "Location": "SearchPage", "ArtLink": this.props.data.Link_Resource })}
                className="grid-card__button_link"
                target="_blank"
                rel="noopener noreferrer">View Source at {museumName}</a>
              <div className="grid-card__button_sep"></div>
            </Stack>
          </CSSTransition>
        </Card.Item>
      </Card>
    );
  }
Example #23
Source File: Modal.tsx    From tailchat with GNU General Public License v3.0 5 votes vote down vote up
Modal: React.FC<ModalProps> = React.memo((props) => {
  const {
    visible,
    onChangeVisible,
    closable = false,
    maskClosable = true,
  } = props;
  const [showing, setShowing] = useState(true);

  const closeModal = useCallback(() => {
    setShowing(false);
  }, []);

  const handleClose = useCallback(() => {
    if (maskClosable === false) {
      return;
    }

    closeModal();
  }, [maskClosable, closeModal]);

  if (visible === false) {
    return null;
  }

  return (
    <CSSTransition
      in={showing}
      classNames="modal-anim"
      timeout={200}
      addEndListener={transitionEndListener}
      onExited={() => {
        if (showing === false && _isFunction(onChangeVisible)) {
          onChangeVisible(false);
        }
      }}
      appear={true}
    >
      <div
        className="absolute left-0 right-0 top-0 bottom-0 bg-black bg-opacity-60 flex justify-center items-center z-10"
        onClick={handleClose}
        data-tc-role="modal-mask"
      >
        <ModalContext.Provider value={{ closeModal }}>
          {/* Inner */}
          <div
            className="modal-inner bg-content-light dark:bg-content-dark rounded overflow-auto relative z-10"
            style={{ maxHeight: '80vh', maxWidth: '80vw' }}
            onClick={stopPropagation}
            data-tc-role="modal"
          >
            {closable === true && (
              <Icon
                className="absolute right-2.5 top-3.5 text-xl z-10 cursor-pointer"
                icon="mdi:close"
                onClick={closeModal}
              />
            )}

            <ErrorBoundary>{props.children}</ErrorBoundary>
          </div>
        </ModalContext.Provider>
      </div>
    </CSSTransition>
  );
})
Example #24
Source File: index.tsx    From questdb.io with Apache License 2.0 5 votes vote down vote up
Subscribe: React.FunctionComponent<Props> = ({
  placeholder = "Email address",
  provider = "enterprise",
  submitButtonText = "SUBMIT",
  submitButtonVariant,
  className,
}) => {
  const [loading, setLoading] = useState(false)
  const [sent, setSent] = useState(false)

  const onSubmit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault()

    setLoading(true)

    const target = event.target as HTMLFormElement
    const email = new FormData(target).get("email") as string

    try {
      if (provider === "newsletter") {
        await fetch(
          `${providers.newsletter}&EMAIL=${encodeURIComponent(email)}`,
          { method: "GET" },
        )
      } else {
        await fetch(providers[provider], {
          body: JSON.stringify({ email }),
          headers: { "Content-Type": "application/json" },
          method: "POST",
        })
      }
    } catch (e) {}

    setSent(true)
  }

  return (
    <form className={clsx(style.root, className)} onSubmit={onSubmit}>
      <TransitionGroup>
        <CSSTransition key={sent.toString()} timeout={200} classNames="item">
          {sent ? (
            <p className={style.success}>
              Thank you, we will be in touch soon!
            </p>
          ) : (
            <div className={style.inputs}>
              <Input
                className={style.input}
                name="email"
                type="email"
                title="Email address should be valid"
                placeholder={placeholder}
                required
                pattern={emailPattern}
              />

              <Button
                className={style.submit}
                variant={submitButtonVariant}
                type="submit"
              >
                {loading ? <span className={style.loader} /> : submitButtonText}
              </Button>
            </div>
          )}
        </CSSTransition>
      </TransitionGroup>
    </form>
  )
}
Example #25
Source File: LoginPage.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
LoginPage: FC = () => {
  return (
    <Branding.LoginBackground className="login container">
      <div className="login-content">
        <div className="login-branding">
          <Branding.LoginLogo className="login-logo" />
        </div>
        <LoginCtrl>
          {({
            loginHint,
            passwordHint,
            isOauthEnabled,
            ldapEnabled,
            authProxyEnabled,
            disableLoginForm,
            disableUserSignUp,
            login,
            isLoggingIn,
            changePassword,
            skipPasswordChange,
            isChangingPassword,
          }) => (
            <div className="login-outer-box">
              <div className={`login-inner-box ${isChangingPassword ? 'hidden' : ''}`} id="login-view">
                {!disableLoginForm ? (
                  <LoginForm
                    displayForgotPassword={!(ldapEnabled || authProxyEnabled)}
                    onSubmit={login}
                    loginHint={loginHint}
                    passwordHint={passwordHint}
                    isLoggingIn={isLoggingIn}
                  />
                ) : null}

                <LoginServiceButtons />
                {!disableUserSignUp ? <UserSignup /> : null}
              </div>
              <CSSTransition
                appear={true}
                mountOnEnter={true}
                in={isChangingPassword}
                timeout={250}
                classNames="login-inner-box"
              >
                <ChangePassword onSubmit={changePassword} onSkip={skipPasswordChange} focus={isChangingPassword} />
              </CSSTransition>
            </div>
          )}
        </LoginCtrl>

        <div className="clearfix" />
      </div>
      <Footer />
    </Branding.LoginBackground>
  );
}
Example #26
Source File: Toast.tsx    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
Toast: React.FC<ToastProps> = ({ toast, onRemove, style, ttl, ...props }) => {
  const timer = useRef<number>()
  const ref = useRef(null)
  const removeHandler = useRef(onRemove)
  const { id, title, description, type } = toast

  const handleRemove = useCallback(() => removeHandler.current(id), [id, removeHandler])

  const handleMouseEnter = () => {
    clearTimeout(timer.current)
  }

  const handleMouseLeave = () => {
    if (timer.current) {
      clearTimeout(timer.current)
    }

    timer.current = window.setTimeout(() => {
      handleRemove()
    }, ttl)
  }

  useEffect(() => {
    if (timer.current) {
      clearTimeout(timer.current)
    }

    timer.current = window.setTimeout(() => {
      handleRemove()
    }, ttl)

    return () => {
      clearTimeout(timer.current)
    }
  }, [timer, ttl, handleRemove])

  return (
    <CSSTransition nodeRef={ref} timeout={250} style={style} {...props}>
      <StyledToast ref={ref} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
        <Alert title={title} variant={alertTypeMap[type]} onClick={handleRemove}>
          {description}
        </Alert>
      </StyledToast>
    </CSSTransition>
  )
}
Example #27
Source File: Products.tsx    From next-shopping-cart with MIT License 5 votes vote down vote up
Products = ({ searchTerm, productsList, openModal }: Props) => {
  const { addProduct } = useContext<Init>(CartContext);

  const term = searchTerm;

  const searchingFor = (searchText: string) => {
    return (x) => {
      return (
        x.name.toLowerCase().includes(searchText.toLowerCase()) || !searchText
      );
    };
  };

  const productsData = productsList
    .filter(searchingFor(term))
    .map((product) => {
      return (
        <CSSTransition
          key={product.id}
          classNames="fadeIn"
          timeout={{
            enter: 300,
            exit: 500,
          }}
        >
          <ProductItem
            // key={product.id}
            price={product.price}
            name={product.name}
            image={product.image}
            id={parseInt(product.id, 10)}
            unit={product.unit}
            addToCart={addProduct}
            // productQuantity={props.productQuantity}
            openModal={openModal}
          />
        </CSSTransition>
      );
    });

  // Empty and Loading States
  let view;
  // if (productsData.length <= 0 && !term) {
  //   view = <LoadingProducts />;
  // } else
  if (productsData.length <= 0 && term) {
    view = <NoResults />;
  } else {
    view = (
      <TransitionGroup component="div" className={styles.products}>
        {productsData}
      </TransitionGroup>
    );
  }
  return <div className={styles.productsWrapper}>{view}</div>;
}
Example #28
Source File: APICUDPage.tsx    From one-platform with MIT License 4 votes vote down vote up
APICUDPage = () => {
  const [wizardStep, setWizardStep] = useState(1);
  const { handleDynamicCrumbs } = useBreadcrumb();
  const userInfo = opcBase.auth?.getUserInfo();
  const navigate = useNavigate();
  const { slug } = useParams();
  const gqlClient = useURQL();
  const isUpdate = Boolean(slug);

  const [isDeleteConfirmationOpen, setIsDeleteConfirmationOpen] = useToggle();

  // gql queries
  const [createNsState, createNamespace] = useCreateNamespace();
  const [, updateANamespace] = useUpdateNamespace();
  const [deleteNamespaceState, deleteANamespace] = useDeleteANamespace();
  const { isLoading: isNamespaceLoading, data: nsData } = useGetANamespaceBySlug({ slug });

  const namespace = nsData?.getNamespaceBySlug;
  const id = namespace?.id;

  const formMethod = useForm<FormData>({
    defaultValues: FORM_DEFAULT_VALUE,
    mode: 'onBlur',
    reValidateMode: 'onBlur',
    resolver: yupResolver(
      wizardValidationSchemas[wizardStep as keyof typeof wizardValidationSchemas]
    ),
  });

  const { handleSubmit, reset } = formMethod;

  // effect for breadcrumb data
  useEffect(() => {
    if (!isNamespaceLoading && isUpdate && namespace?.name && namespace?.slug) {
      handleDynamicCrumbs({
        'api-name': { label: namespace.name, url: `/apis/${namespace.slug}` },
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isNamespaceLoading, namespace?.name, namespace?.slug, isUpdate]);

  /**
   * This effect validated whether user has edit access if not move them to explore
   * Checks user is in owner list or in createdBy
   */
  useEffect(() => {
    if (!isNamespaceLoading && isUpdate && namespace) {
      const userUuid = userInfo?.rhatUUID;
      const isApiCreatedUser = userUuid === (namespace?.createdBy as UserRoverDetails)?.rhatUUID;
      const isOwner =
        namespace?.owners.findIndex(
          (owner) => owner.group === ApiEmailGroup.USER && owner.user.rhatUUID === userUuid
        ) !== -1;
      const hasEditAccess = isApiCreatedUser || isOwner;
      if (!hasEditAccess) navigate('/apis');
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isNamespaceLoading, namespace, isUpdate, userInfo?.rhatUUID]);

  /**
   * In update mode the form is prefilled with API config data
   */
  useEffect(() => {
    if (!isNamespaceLoading && isUpdate && namespace) {
      const owners = namespace.owners.map((owner) => ({
        group: owner.group,
        mid: owner.group === ApiEmailGroup.USER ? owner?.user?.rhatUUID : owner?.email,
        email: owner.group === ApiEmailGroup.USER ? owner?.user?.mail : owner?.email,
      }));
      reset({
        ...namespace,
        owners,
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isNamespaceLoading, namespace, isUpdate]);

  const isLastStep = wizardStep === MAX_WIZARD_STEPS;

  const formatFormData = ({ id: nsId, slug: nSlug, ...data }: FormData) => {
    return {
      ...data,
      owners: data.owners.map(({ group, mid }) => ({ group, mid })),
      schemas: data.schemas.map((schema) => ({
        ...schema,
        environments: schema.environments.map(({ slug: eSlug, ...env }) => ({
          ...env,
          headers: (env?.headers || [])
            .filter(({ id: hId, key, value }) => (hId && key) || (key && value))
            .map(({ id: hID, key, value }) => (hID ? { id: hID, key } : { key, value })),
        })),
      })),
    };
  };

  const handleCreateNamespace = async (data: FormData) => {
    const payload = formatFormData(data) as CreateNamespaceType;
    try {
      const res = await createNamespace({ payload });
      if (res.error) {
        window.OpNotification.danger({
          subject: 'Failed to create API',
          body: res.error?.message,
        });
        return;
      }
      navigate(`/apis/${res.data?.createNamespace.slug}`);
    } catch (error) {
      window.OpNotification.danger({
        subject: 'Failed to create API',
      });
    }
  };

  const handleUpdateNamespace = async (data: FormData) => {
    const payload = formatFormData(data) as CreateNamespaceType;
    delete (payload as any).createdBy;
    try {
      const res = await updateANamespace({ payload, id: id as string });
      if (res.error) {
        window.OpNotification.danger({
          subject: 'Failed to update API',
          body: res.error?.message,
        });
        return;
      }
      navigate(`/apis/${res.data?.updateNamespace.slug}`);
    } catch (error) {
      window.OpNotification.danger({
        subject: 'Failed to update API',
      });
    }
  };

  const handleSchemaValidation = async ({ envSlug, ...config }: HandleSchemaValidationArg) => {
    try {
      const res = await gqlClient
        .query<UseGetAPISchemaFileQuery, UseGetAPISchemaFileVariable>(GET_API_SCHEMA_FILE, {
          config,
          envSlug,
        })
        .toPromise();

      return res.data?.fetchAPISchema;
    } catch (error) {
      window.OpNotification.danger({
        subject: 'Failed to fetch schema',
      });
    }
    return undefined;
  };

  const handleApiDelete = async (): Promise<void> => {
    if (deleteNamespaceState.fetching) return;
    const res = await deleteANamespace({ id: id as string });
    if (res.error) {
      window.OpNotification.danger({
        subject: `Failed to delete API`,
        body: res.error?.message,
      });
    } else {
      navigate('/apis');
    }
  };

  const onFormSubmit = (data: FormData) => {
    if (wizardStep < MAX_WIZARD_STEPS) {
      setWizardStep((state) => state + 1);
      return;
    }
    if (isUpdate) {
      handleUpdateNamespace(data);
    } else {
      handleCreateNamespace(data);
    }
  };

  const onPrev = () => {
    if (wizardStep > 1) {
      setWizardStep((state) => state - 1);
    }
  };

  const onSearchOwners = async (search: string): Promise<JSX.Element[]> => {
    if (!search || search.length < 3) {
      return [
        <SelectOption key="no-result" value="Please type atleast 3 characters" isPlaceholder />,
      ];
    }

    try {
      const res = await gqlClient.query<UserSearchQuery>(GET_USERS_QUERY, { search }).toPromise();
      const options = (res.data?.searchRoverUsers || []).map((owner) => (
        <SelectOption
          key={`user:${owner.mail}-owner-${owner.rhatUUID}`}
          value={{
            ...owner,
            toString: () => owner.cn,
          }}
          description={owner.mail}
        />
      ));
      return options;
    } catch (error) {
      window.OpNotification.danger({
        subject: 'Failed to search for users',
      });
    }
    return [];
  };

  if (isUpdate && isNamespaceLoading) {
    return (
      <Bullseye>
        <Spinner size="xl" />
      </Bullseye>
    );
  }

  return (
    <PageSection
      isCenterAligned
      isWidthLimited
      style={{ backgroundColor: 'var(--pf-global--BackgroundColor--light-300)' }}
      className="pf-u-h-100 pf-u-pb-4xl"
    >
      <Form
        onSubmit={handleSubmit(onFormSubmit)}
        style={{ maxWidth: '1080px', margin: 'auto' }}
        autoComplete="off"
      >
        <FormProvider {...formMethod}>
          <Stack hasGutter>
            {/* Top Stepper */}
            <StackItem>
              <Card>
                <CardBody>
                  <ProgressStepper isCenterAligned>
                    {wizardStepDetails.map(({ title }, index) => (
                      <ProgressStep
                        variant={wizardStep <= index ? 'pending' : 'success'}
                        id={`wizard-step-icon-${index}`}
                        key={`wizard-step-icon-${index + 1}`}
                        titleId={`wizard-step-icon-${index}`}
                        aria-label={title}
                        isCurrent={wizardStep === index + 1}
                      >
                        {title}
                      </ProgressStep>
                    ))}
                  </ProgressStepper>
                </CardBody>
              </Card>
            </StackItem>
            {/* Form Steps */}
            <StackItem>
              <CSSTransition in={wizardStep === 1} timeout={200} classNames="fade-in" unmountOnExit>
                <APIBasicDetailsForm onSearchOwners={onSearchOwners} />
              </CSSTransition>
            </StackItem>
            <StackItem>
              <CSSTransition in={wizardStep === 2} timeout={200} classNames="fade-in" unmountOnExit>
                <APISchemaForm
                  handleSchemaValidation={handleSchemaValidation}
                  isUpdate={isUpdate}
                />
              </CSSTransition>
            </StackItem>
            <StackItem>
              <CSSTransition in={wizardStep === 3} timeout={200} classNames="fade-in" unmountOnExit>
                <APIReview />
              </CSSTransition>
            </StackItem>
            {/* Form Action Buttons */}
            <StackItem>
              <Card>
                <CardBody>
                  <Split hasGutter>
                    <SplitItem>
                      <Button type="submit" isLoading={createNsState.fetching}>
                        {isLastStep ? (isUpdate ? 'Update' : 'Create') : 'Next'}
                      </Button>
                    </SplitItem>
                    <SplitItem>
                      <Button variant="secondary" onClick={onPrev} isDisabled={wizardStep === 1}>
                        Back
                      </Button>
                    </SplitItem>
                    <SplitItem isFilled>
                      <Link to={isUpdate ? `/apis/${namespace?.slug}` : '/apis'}>
                        <Button variant="link">Cancel</Button>
                      </Link>
                    </SplitItem>
                    {isUpdate && (
                      <SplitItem>
                        <Button variant="link" isDanger onClick={setIsDeleteConfirmationOpen.on}>
                          Delete
                        </Button>
                      </SplitItem>
                    )}
                  </Split>
                </CardBody>
              </Card>
            </StackItem>
          </Stack>
        </FormProvider>
      </Form>
      <Modal
        variant={ModalVariant.medium}
        title={`Delete ${namespace?.name} API`}
        titleIconVariant="danger"
        isOpen={isDeleteConfirmationOpen}
        onClose={setIsDeleteConfirmationOpen.off}
        actions={[
          <Button
            key="confirm"
            variant="primary"
            onClick={handleApiDelete}
            isLoading={deleteNamespaceState.fetching}
          >
            Confirm
          </Button>,
          <Button key="cancel" variant="link" onClick={setIsDeleteConfirmationOpen.off}>
            Cancel
          </Button>,
        ]}
      >
        This action is irreversible. Are you sure you want to delete this API?
      </Modal>
    </PageSection>
  );
}
Example #29
Source File: ActionBar.tsx    From atlas with GNU General Public License v3.0 4 votes vote down vote up
ActionBar = React.forwardRef<HTMLDivElement, ActionBarProps>(
  ({ primaryText, secondaryText, className, primaryButton, secondaryButton, draftBadge, variant = 'new' }, ref) => {
    const smMatch = useMediaMatch('sm')

    const textNode = (
      <>
        <StyledPrimaryText variant={!smMatch ? 'h300' : 'h400'}>{primaryText}</StyledPrimaryText>
        <StyledSecondaryText variant="t200" secondary>
          {secondaryText}
        </StyledSecondaryText>
      </>
    )

    const primaryButtonNode = (
      <ActionButtonPrimaryTooltip arrowDisabled placement="top-end" {...primaryButton?.tooltip}>
        <ActionButtonPrimary {...primaryButton} size="large" type="submit">
          {primaryButton.text}
        </ActionButtonPrimary>
      </ActionButtonPrimaryTooltip>
    )

    const secondaryButtonNode = (
      <CSSTransition
        in={secondaryButton?.visible}
        timeout={parseInt(transitions.timings.sharp)}
        classNames={transitions.names.fade}
        mountOnEnter
        unmountOnExit
      >
        <SecondaryButton {...secondaryButton} variant="secondary" size="large">
          {secondaryButton?.text}
        </SecondaryButton>
      </CSSTransition>
    )

    const draftNode = draftBadge ? (
      <Tooltip arrowDisabled placement="top-end" {...draftBadge?.tooltip}>
        <DraftsBadgeContainer>
          <Text variant="t200" secondary>
            {draftBadge?.text}
          </Text>
          <DetailsIconWrapper>
            <SvgActionInformative />
          </DetailsIconWrapper>
        </DraftsBadgeContainer>
      </Tooltip>
    ) : null

    const getActionBarVariant = (variant: ActionBarVariant) => {
      switch (variant) {
        case 'new':
          return (
            <>
              {textNode}
              {draftNode}
              {primaryButtonNode}
            </>
          )
        case 'edit':
          return (
            <>
              {textNode}
              <EditSecondaryButton
                {...secondaryButton}
                icon={!smMatch ? <SvgControlsCancel width={16} height={16} /> : undefined}
                variant={!smMatch ? 'tertiary' : 'secondary'}
                size={!smMatch ? 'small' : 'large'}
                iconPlacement="right"
              >
                {secondaryButton?.text}
              </EditSecondaryButton>
              {primaryButtonNode}
            </>
          )
        case 'nft':
          return smMatch ? (
            <>
              {textNode}
              {draftNode}
              {secondaryButtonNode}
              {primaryButtonNode}
            </>
          ) : (
            <>
              <NFTTopWrapper>
                {textNode}
                {draftNode}
              </NFTTopWrapper>
              <NFTBottomWrapper>
                {secondaryButtonNode}
                {primaryButtonNode}
              </NFTBottomWrapper>
            </>
          )
      }
    }

    return (
      <ActionBarContainer
        variant={variant}
        ref={ref}
        className={className}
        isActive={variant === 'edit' ? !primaryButton?.disabled : true}
      >
        {getActionBarVariant(variant)}
      </ActionBarContainer>
    )
  }
)