Path: blob/1.0-develop/resources/scripts/components/elements/Spinner.tsx
7461 views
import React, { Suspense } from 'react';1import styled, { css, keyframes } from 'styled-components/macro';2import tw from 'twin.macro';3import ErrorBoundary from '@/components/elements/ErrorBoundary';45export type SpinnerSize = 'small' | 'base' | 'large';67interface Props {8size?: SpinnerSize;9centered?: boolean;10isBlue?: boolean;11}1213interface Spinner extends React.FC<Props> {14Size: Record<'SMALL' | 'BASE' | 'LARGE', SpinnerSize>;15Suspense: React.FC<Props>;16}1718const spin = keyframes`19to { transform: rotate(360deg); }20`;2122// noinspection CssOverwrittenProperties23const SpinnerComponent = styled.div<Props>`24${tw`w-8 h-8`};25border-width: 3px;26border-radius: 50%;27animation: ${spin} 1s cubic-bezier(0.55, 0.25, 0.25, 0.7) infinite;2829${(props) =>30props.size === 'small'31? tw`w-4 h-4 border-2`32: props.size === 'large'33? css`34${tw`w-16 h-16`};35border-width: 6px;36`37: null};3839border-color: ${(props) => (!props.isBlue ? 'rgba(255, 255, 255, 0.2)' : 'hsla(212, 92%, 43%, 0.2)')};40border-top-color: ${(props) => (!props.isBlue ? 'rgb(255, 255, 255)' : 'hsl(212, 92%, 43%)')};41`;4243const Spinner: Spinner = ({ centered, ...props }) =>44centered ? (45<div css={[tw`flex justify-center items-center`, props.size === 'large' ? tw`m-20` : tw`m-6`]}>46<SpinnerComponent {...props} />47</div>48) : (49<SpinnerComponent {...props} />50);51Spinner.displayName = 'Spinner';5253Spinner.Size = {54SMALL: 'small',55BASE: 'base',56LARGE: 'large',57};5859Spinner.Suspense = ({ children, centered = true, size = Spinner.Size.LARGE, ...props }) => (60<Suspense fallback={<Spinner centered={centered} size={size} {...props} />}>61<ErrorBoundary>{children}</ErrorBoundary>62</Suspense>63);64Spinner.Suspense.displayName = 'Spinner.Suspense';6566export default Spinner;676869