@kiwicom/orbit-components
Version:
<div align="center"> <a href="https://orbit.kiwi" target="_blank"> <img alt="orbit-components" src="https://orbit.kiwi/wp-content/uploads/2018/08/orbit-components.png" srcset="https://orbit.kiwi/wp-content/uploads/2018/08/orbit-components@2x.png 2x"
142 lines (125 loc) • 4.27 kB
JavaScript
// @flow
import * as React from "react";
import styled, { keyframes } from "styled-components";
import defaultTokens from "../defaultTokens";
import TYPE_OPTIONS from "./consts";
import type { Props } from "../Loading/index";
// Animations
const SpinnerAnimation = keyframes`
100% { transform: rotate(360deg); }
`;
const LoaderAnimation = keyframes`
0% {opacity: .3; transform:translateY(0px);}
20% {opacity: 1; transform: translateY(-3px);}
40% {opacity: .3; transform:translateY(0px);}
100% {opacity: .3; transform:translateY(0px);}
`;
const StyledLoading = styled(({ children, className, dataTest }) => (
<div className={className} data-test={dataTest}>
{children}
</div>
))`
position: ${({ type }) => type === TYPE_OPTIONS.BUTTON_LOADER && "absolute"};
left: ${({ type }) => type === TYPE_OPTIONS.BUTTON_LOADER && "0"};
width: ${({ type }) => type === TYPE_OPTIONS.BUTTON_LOADER && "100%"};
height: ${({ tokens, type }) => tokens.heightLoadingContainer[type]};
padding: 0 ${({ theme }) => theme.orbit.spaceSmall}; // TODO: create token paddingLoading
display: flex;
flex-direction: ${({ type }) => (type === TYPE_OPTIONS.PAGE_LOADER ? "column" : "row")};
justify-content: ${({ tokens, type }) => tokens.alignLoadingContainer[type]};
align-items: center;
overflow: hidden;
box-sizing: border-box;
`;
StyledLoading.defaultProps = {
theme: defaultTokens,
};
const StyledLoadingText = styled.div`
font-family: ${({ theme }) => theme.orbit.fontFamily};
font-size: ${({ theme }) => theme.orbit.fontSizeTextNormal};
color: ${({ theme }) => theme.orbit.paletteInkLighter}; // TODO: create token colorTextLoading
line-height: ${({ theme }) => theme.orbit.lineHeightText};
margin-top: ${({ theme, type }) => type === TYPE_OPTIONS.PAGE_LOADER && theme.orbit.spaceMedium};
margin-left: ${({ theme, type }) => type !== TYPE_OPTIONS.PAGE_LOADER && theme.orbit.spaceSmall};
`;
StyledLoadingText.defaultProps = {
theme: defaultTokens,
};
export const StyledSpinner = styled.svg`
width: 40px;
height: 40px;
animation: ${SpinnerAnimation} 0.75s linear infinite;
`;
const StyledSpinnerCircle = styled.circle`
fill: transparent;
stroke: ${({ theme, type }) =>
type === TYPE_OPTIONS.BUTTON_LOADER ? "currentColor" : theme.orbit.paletteInkLighter};
stroke-width: 3px;
stroke-linecap: round;
stroke-dasharray: 128px;
stroke-dashoffset: 64px;
`;
StyledSpinnerCircle.defaultProps = {
theme: defaultTokens,
};
const StyledLoader = styled.div`
display: flex;
justify-content: center;
align-items: center;
`;
const StyledLoaderCircle = styled.div`
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
background: ${({ theme }) => theme.orbit.paletteInkLighter};
animation: ${LoaderAnimation} 1.25s infinite ease-in-out;
&:nth-child(2) {
animation-delay: 0.1s;
}
&:nth-child(3) {
animation-delay: 0.2s;
margin: 0;
}
`;
StyledLoaderCircle.defaultProps = {
theme: defaultTokens,
};
const Loading = (props: Props) => {
const { loading = false, type = TYPE_OPTIONS.PAGE_LOADER, text, children, dataTest } = props;
const tokens = {
alignLoadingContainer: {
[TYPE_OPTIONS.BUTTON_LOADER]: "center",
[TYPE_OPTIONS.SEARCH_LOADER]: "start",
[TYPE_OPTIONS.BOX_LOADER]: "center",
[TYPE_OPTIONS.PAGE_LOADER]: "center",
},
heightLoadingContainer: {
[TYPE_OPTIONS.BUTTON_LOADER]: "100%",
[TYPE_OPTIONS.SEARCH_LOADER]: "40px",
[TYPE_OPTIONS.BOX_LOADER]: "80px",
[TYPE_OPTIONS.PAGE_LOADER]: "120px",
},
};
return children && !loading ? (
children
) : (
<StyledLoading tokens={tokens} type={type} dataTest={dataTest}>
{type === TYPE_OPTIONS.BOX_LOADER || type === TYPE_OPTIONS.SEARCH_LOADER ? (
<StyledLoader>
<StyledLoaderCircle />
<StyledLoaderCircle />
<StyledLoaderCircle />
</StyledLoader>
) : (
<StyledSpinner viewBox="0 0 40 40">
<StyledSpinnerCircle cx="50%" cy="50%" r="18" type={type} />
</StyledSpinner>
)}
{type !== TYPE_OPTIONS.BUTTON_LOADER && (
<StyledLoadingText type={type}>{text}</StyledLoadingText>
)}
</StyledLoading>
);
};
export default Loading;