From 6775f44e632bd99b1d1dd8e44a508c9a2990dc0b Mon Sep 17 00:00:00 2001 From: frozenhelium Date: Fri, 13 Nov 2020 14:41:49 +0545 Subject: [PATCH] Add pending animation component --- src/components/Backdrop/index.tsx | 15 ------ src/components/Loading/index.tsx | 47 +++++++++++++++++++ src/components/Loading/styles.css | 5 ++ src/components/LoadingAnimation/index.tsx | 41 ++++++++++++++++ src/components/LoadingAnimation/styles.css | 54 ++++++++++++++++++++++ src/components/RawButton/index.tsx | 11 +++++ src/components/RawButton/styles.css | 6 +++ src/index.tsx | 2 + src/stories/LoadingAnimation.stories.tsx | 22 +++++++++ src/styles.css | 8 +++- 10 files changed, 194 insertions(+), 17 deletions(-) create mode 100644 src/components/Loading/index.tsx create mode 100644 src/components/Loading/styles.css create mode 100644 src/components/LoadingAnimation/index.tsx create mode 100644 src/components/LoadingAnimation/styles.css create mode 100644 src/stories/LoadingAnimation.stories.tsx diff --git a/src/components/Backdrop/index.tsx b/src/components/Backdrop/index.tsx index 9b6c724..8944213 100644 --- a/src/components/Backdrop/index.tsx +++ b/src/components/Backdrop/index.tsx @@ -8,7 +8,6 @@ import styles from './styles.css'; export interface BackdropProps { className?: string; - parentRef?: React.RefObject; children?: React.ReactNode; uiMode?: UiMode; } @@ -16,7 +15,6 @@ export interface BackdropProps { function Backdrop(props: BackdropProps) { const { className, - parentRef, children, uiMode, } = props; @@ -24,19 +22,6 @@ function Backdrop(props: BackdropProps) { const ref = React.useRef(null); const themeClassName = useThemeClassName(uiMode, styles.light, styles.dark); - React.useLayoutEffect( - () => { - const { - current: el, - } = ref; - if (parentRef && parentRef.current && el) { - const parentBCR = parentRef.current.getBoundingClientRect(); - el.style.width = `${parentBCR.width}px`; - } - }, - [parentRef], - ); - return (
+ + + ); +} + +export default Loading; diff --git a/src/components/Loading/styles.css b/src/components/Loading/styles.css new file mode 100644 index 0000000..fc99f19 --- /dev/null +++ b/src/components/Loading/styles.css @@ -0,0 +1,5 @@ +.loading { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/components/LoadingAnimation/index.tsx b/src/components/LoadingAnimation/index.tsx new file mode 100644 index 0000000..0c512ec --- /dev/null +++ b/src/components/LoadingAnimation/index.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { _cs } from '@togglecorp/fujs'; + +import { UiMode } from '../ThemeContext'; +import { useThemeClassName } from '../../hooks'; + +import styles from './styles.css'; + +export interface LoadingAnimationProps { + className?: string; + uiMode?: UiMode; + compact?: boolean; +} + +function LoadingAnimation(props: LoadingAnimationProps) { + const { + className, + uiMode, + compact, + } = props; + + const themeClassName = useThemeClassName(uiMode, styles.light, styles.dark); + + return ( +
+
+
+
+
+ ); +} + +export default LoadingAnimation; diff --git a/src/components/LoadingAnimation/styles.css b/src/components/LoadingAnimation/styles.css new file mode 100644 index 0000000..da88abb --- /dev/null +++ b/src/components/LoadingAnimation/styles.css @@ -0,0 +1,54 @@ +.loading-animation { + --size: 0.4em; + --half-size: 0.2em; + --gap: 0.1em; + --color: transparent; + --transition-duration: 1s; + + display: flex; + align-items: center; + + &.compact { + --size: 0.24em; + --half-size: 0.12em; + --gap: 0.06em; + } + + &.light { + --color: var(--tui-color-loading-particle-light); + } + + &.dark { + --color: var(--tui-color-loading-particle-dark); + } + + .particle { + flex-shrink: 0; + margin: var(--gap); + border-radius: 50%; + background-color: var(--color); + width: var(--size); + height: var(--size); + animation: wiggle-vertically var(--transition-duration) linear infinite; + + &:nth-child(1) { + animation-delay: 0; + } + + &:nth-child(2) { + animation-delay: calc(var(--transition-duration) / 3); + } + + &:nth-child(3) { + animation-delay: calc(2 * var(--transition-duration) / 3); + } + } +} + +@keyframes wiggle-vertically { + 0% { transform: translateY(0); } + 25% { transform: translateY(calc(-1 * var(--half-size))); } + 75% { transform: translateY(calc(-1 * var(--half-size))); } + 100% { transform: translateY(0); } +} + diff --git a/src/components/RawButton/index.tsx b/src/components/RawButton/index.tsx index 150c4dd..a72efc0 100644 --- a/src/components/RawButton/index.tsx +++ b/src/components/RawButton/index.tsx @@ -4,6 +4,7 @@ import { _cs } from '@togglecorp/fujs'; import { UiMode } from '../ThemeContext'; import { useThemeClassName } from '../../hooks'; import VisualFeedback from '../VisualFeedback'; +import Loading from '../Loading'; import styles from './styles.css'; @@ -23,6 +24,10 @@ export interface RawButtonProps extends O uiMode?: UiMode; name: N; elementRef?: React.Ref; + /** + * Shows the loading animation + */ + pending?: boolean; } /** @@ -37,6 +42,7 @@ function RawButton(props: RawButtonProps< disabled, elementRef, name, + pending, ...otherProps } = props; @@ -61,6 +67,11 @@ function RawButton(props: RawButtonProps< // eslint-disable-next-line react/jsx-props-no-spreading {...otherProps} > + {pending && ( + + )} = (props) => ( + +); + +export const Default = Template.bind({}); +Default.args = { +}; + +export const Compact = Template.bind({}); +Compact.args = { + compact: true, +}; diff --git a/src/styles.css b/src/styles.css index c136693..8b08b12 100644 --- a/src/styles.css +++ b/src/styles.css @@ -107,8 +107,8 @@ --tui-color-shadow: rgba(0, 0, 0, .5); - --tui-color-backdrop-light: rgba(0, 0, 0, .5); - --tui-color-backdrop-dark: rgba(255, 255, 255, .5); + --tui-color-backdrop-light: rgba(0, 0, 0, .6); + --tui-color-backdrop-dark: rgba(255, 255, 255, .7); --tui-color-background-switch-icon-light: rgba(0, 0, 0, .4); --tui-color-background-switch-icon-dark: rgba(255, 255, 255, .4); @@ -129,4 +129,8 @@ --tui-height-max-modal: 96vh; --tui-width-max-modal: 96vw; --tui-width-min-modal: 360px; + + + --tui-color-loading-particle-light: rgba(0, 0, 0, 1); + --tui-color-loading-particle-dark: rgba(255, 255, 255, 1); }