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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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}>
×
</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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
)
}
)