Skip to content

Commit

Permalink
feat(client): add Animated component
Browse files Browse the repository at this point in the history
  • Loading branch information
Jozwiaczek committed Mar 3, 2021
1 parent 0ef3422 commit f1a8b44
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 38 deletions.
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"axios": "^0.21.1",
"i18next": "^19.9.0",
"i18next-browser-languagedetector": "^6.0.1",
"intersection-observer": "^0.12.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-hook-form": "^6.14.1",
Expand Down
79 changes: 41 additions & 38 deletions packages/client/src/containers/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useForm } from 'react-hook-form';
import { useHistory } from 'react-router-dom';

import {
Animated,
AnimatedLogo,
BackgroundSideLogo,
Checkbox,
Expand Down Expand Up @@ -62,44 +63,46 @@ const Login = () => {
return (
<LayoutContainer>
<BackgroundSideLogo />
<StyledCard>
<AnimatedLogo />
<Form
onSubmit={handleSubmit(onSubmit)}
errors={errors}
register={register}
loading={loading}
>
<TextField
autoFocus
required
name="email"
placeholder="Enter your email"
startAdornment={<StyledEmailIcon />}
/>
<TextField
required
name="password"
type="password"
placeholder="Enter your password"
autoComplete="current-password"
/>
<ActionsContainer>
<Checkbox name="keepMeLoggedIn" />
<StyledButton type="submit" fullWidth disabled={loading} withArrow>
Log in
</StyledButton>
</ActionsContainer>
<LinksContainer>
<Link to="/" colorVariant="grey">
Forgot password?
</Link>
<Link to="/registration" colorVariant="colour">
I don’t have an account
</Link>
</LinksContainer>
</Form>
</StyledCard>
<Animated>
<StyledCard>
<AnimatedLogo />
<Form
onSubmit={handleSubmit(onSubmit)}
errors={errors}
register={register}
loading={loading}
>
<TextField
autoFocus
required
name="email"
placeholder="Enter your email"
startAdornment={<StyledEmailIcon />}
/>
<TextField
required
name="password"
type="password"
placeholder="Enter your password"
autoComplete="current-password"
/>
<ActionsContainer>
<Checkbox name="keepMeLoggedIn" />
<StyledButton type="submit" fullWidth disabled={loading} withArrow>
Log in
</StyledButton>
</ActionsContainer>
<LinksContainer>
<Link to="/" colorVariant="grey">
Forgot password?
</Link>
<Link to="/registration" colorVariant="colour">
I don’t have an account
</Link>
</LinksContainer>
</Form>
</StyledCard>
</Animated>
</LayoutContainer>
);
};
Expand Down
17 changes: 17 additions & 0 deletions packages/client/src/elements/Animated/Animated.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Meta, Story } from '@storybook/react/types-6-0';
import React from 'react';

import Animated from '.';
import { AnimatedProps } from './Animated.types';

export default {
title: 'Elements/Animated',
component: Animated,
} as Meta;

const Template: Story<AnimatedProps> = (args) => <Animated {...args} />;

export const Default = Template.bind({});
Default.args = {
children: <>Lorem Ipsum</>,
};
7 changes: 7 additions & 0 deletions packages/client/src/elements/Animated/Animated.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ReactNode } from 'react';

export interface AnimatedProps {
children?: ReactNode;
animateIn?: string;
animateOut?: string;
}
73 changes: 73 additions & 0 deletions packages/client/src/elements/Animated/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import anime, { AnimeInstance } from 'animejs';
import React, { useLayoutEffect, useRef } from 'react';
import styled from 'styled-components';

import { useOnScreen } from '../../hooks';
import { AnimatedProps } from './Animated.types';

const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
`;

const Animated = ({ children, animateIn, animateOut }: AnimatedProps) => {
const animatedContainerRef = useRef<HTMLDivElement>(null);
const isInViewPort = useOnScreen(animatedContainerRef);
const animateInRef = useRef<AnimeInstance>();
const animateOutRef = useRef<AnimeInstance>();

useLayoutEffect(() => {
// const xMax = 16;
// animateInRef.current = anime({
// targets: animatedContainerRef.current,
// easing: 'easeInOutSine',
// duration: 550,
// translateX: [
// {
// value: xMax * -1,
// },
// {
// value: xMax,
// },
// {
// value: xMax / -2,
// },
// {
// value: xMax / 2,
// },
// {
// value: 0,
// },
// ],
// });
if (isInViewPort) {
animateInRef.current = anime({
targets: animatedContainerRef.current,
duration: 750,
opacity: [0, 1],
easing: 'cubicBezier(.5, .05, .1, .3)',
});
}
if (!isInViewPort) {
animateOutRef.current = anime({
targets: animatedContainerRef.current,
duration: 750,
opacity: [1, 0],
easing: 'cubicBezier(.5, .05, .1, .3)',
});
}
}, [isInViewPort]);

return (
<Wrapper ref={animatedContainerRef} data-testid="animated">
{children}
</Wrapper>
);
};

Animated.displayName = 'Animated';

export default Animated;
1 change: 1 addition & 0 deletions packages/client/src/elements/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as Animated } from './Animated';
export { default as AnimatedLogo } from './AnimatedLogo';
export { default as BackgroundSideLogo } from './BackgroundSideLogo';
export { default as Button } from './Button';
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export { default as useHotkeys } from './useHotkeys';
export { default as useMediaDevice } from './useMediaDevice';
export { default as useMediaQuery } from './useMediaQuery';
export { default as useOnClickOutside } from './useOnClickOutside';
export { default as useOnScreen } from './useOnScreen';
export { default as useSnackbar } from './useSnackbar';
export { default as useThemeType } from './useThemeType';
35 changes: 35 additions & 0 deletions packages/client/src/hooks/useOnScreen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { RefObject, useLayoutEffect, useState } from 'react';

const useOnScreen = (ref: RefObject<Element>, rootMargin = '0px') => {
const [isIntersecting, setIntersecting] = useState(true);

useLayoutEffect(() => {
if (!ref && !window && !('IntersectionObserver' in window)) {
return;
}

const observer = new IntersectionObserver(
([entry]) => {
setIntersecting(entry.isIntersecting);
},
{
rootMargin,
},
);

if (ref.current) {
observer.observe(ref.current);
}

return () => {
if (ref.current) {
// eslint-disable-next-line react-hooks/exhaustive-deps
observer.unobserve(ref.current);
}
};
}, [ref, rootMargin]);

return isIntersecting;
};

export default useOnScreen;
7 changes: 7 additions & 0 deletions packages/client/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import Routes from './Routes';
import * as serviceWorkerRegistration from './serviceWorker/serviceWorkerRegistration';
import reportWebVitals from './utils/reportWebVitals';

// Load Polyfills
(async () => {
if (typeof window.IntersectionObserver === 'undefined') {
await import('intersection-observer');
}
})();

ReactDOM.render(
<React.StrictMode>
<Providers>
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/interfaces/intersection-observer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'intersection-observer';
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10758,6 +10758,11 @@ interpret@^2.0.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==

intersection-observer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa"
integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ==

invariant@^2.2.3, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
Expand Down

0 comments on commit f1a8b44

Please sign in to comment.