2021-05-16 19:35:49 +00:00
|
|
|
import React, { Suspense } from 'react';
|
2020-07-04 19:39:55 +00:00
|
|
|
import styled, { css, keyframes } from 'styled-components/macro';
|
|
|
|
import tw from 'twin.macro';
|
2022-06-21 22:43:59 +00:00
|
|
|
import ErrorBoundary from '@/components/elements/ErrorBoundary';
|
2019-06-29 23:14:32 +00:00
|
|
|
|
2020-07-04 19:39:55 +00:00
|
|
|
export type SpinnerSize = 'small' | 'base' | 'large';
|
2019-08-17 23:03:10 +00:00
|
|
|
|
2019-12-22 22:53:27 +00:00
|
|
|
interface Props {
|
|
|
|
size?: SpinnerSize;
|
|
|
|
centered?: boolean;
|
2020-07-04 19:39:55 +00:00
|
|
|
isBlue?: boolean;
|
2019-12-22 22:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-05-16 19:35:49 +00:00
|
|
|
interface Spinner extends React.FC<Props> {
|
|
|
|
Size: Record<'SMALL' | 'BASE' | 'LARGE', SpinnerSize>;
|
|
|
|
Suspense: React.FC<Props>;
|
|
|
|
}
|
|
|
|
|
2020-07-04 19:39:55 +00:00
|
|
|
const spin = keyframes`
|
|
|
|
to { transform: rotate(360deg); }
|
|
|
|
`;
|
|
|
|
|
|
|
|
// noinspection CssOverwrittenProperties
|
|
|
|
const SpinnerComponent = styled.div<Props>`
|
|
|
|
${tw`w-8 h-8`};
|
|
|
|
border-width: 3px;
|
|
|
|
border-radius: 50%;
|
2022-06-26 19:13:52 +00:00
|
|
|
animation: ${spin} 1s cubic-bezier(0.55, 0.25, 0.25, 0.7) infinite;
|
2022-06-21 22:43:59 +00:00
|
|
|
|
2022-06-26 19:13:52 +00:00
|
|
|
${(props) =>
|
|
|
|
props.size === 'small'
|
|
|
|
? tw`w-4 h-4 border-2`
|
|
|
|
: props.size === 'large'
|
|
|
|
? css`
|
|
|
|
${tw`w-16 h-16`};
|
|
|
|
border-width: 6px;
|
|
|
|
`
|
|
|
|
: null};
|
2022-06-21 22:43:59 +00:00
|
|
|
|
2022-06-26 19:13:52 +00:00
|
|
|
border-color: ${(props) => (!props.isBlue ? 'rgba(255, 255, 255, 0.2)' : 'hsla(212, 92%, 43%, 0.2)')};
|
|
|
|
border-top-color: ${(props) => (!props.isBlue ? 'rgb(255, 255, 255)' : 'hsl(212, 92%, 43%)')};
|
2020-07-04 19:39:55 +00:00
|
|
|
`;
|
|
|
|
|
2022-06-26 19:13:52 +00:00
|
|
|
const Spinner: Spinner = ({ centered, ...props }) =>
|
|
|
|
centered ? (
|
|
|
|
<div css={[tw`flex justify-center items-center`, props.size === 'large' ? tw`m-20` : tw`m-6`]}>
|
|
|
|
<SpinnerComponent {...props} />
|
2019-07-10 05:00:29 +00:00
|
|
|
</div>
|
2022-06-26 19:13:52 +00:00
|
|
|
) : (
|
|
|
|
<SpinnerComponent {...props} />
|
|
|
|
);
|
2021-05-16 19:35:49 +00:00
|
|
|
Spinner.displayName = 'Spinner';
|
2020-02-08 23:23:08 +00:00
|
|
|
|
2020-08-26 04:25:31 +00:00
|
|
|
Spinner.Size = {
|
2021-05-16 19:35:49 +00:00
|
|
|
SMALL: 'small',
|
|
|
|
BASE: 'base',
|
|
|
|
LARGE: 'large',
|
2020-08-26 04:25:31 +00:00
|
|
|
};
|
|
|
|
|
2021-05-16 19:35:49 +00:00
|
|
|
Spinner.Suspense = ({ children, centered = true, size = Spinner.Size.LARGE, ...props }) => (
|
2022-06-26 19:13:52 +00:00
|
|
|
<Suspense fallback={<Spinner centered={centered} size={size} {...props} />}>
|
|
|
|
<ErrorBoundary>{children}</ErrorBoundary>
|
2021-05-16 19:35:49 +00:00
|
|
|
</Suspense>
|
|
|
|
);
|
|
|
|
Spinner.Suspense.displayName = 'Spinner.Suspense';
|
|
|
|
|
2020-02-08 23:23:08 +00:00
|
|
|
export default Spinner;
|