-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: added basic loader * refactor styles * removed types * feat: add tests * fix tsconfig * fix: review changes * fix: fix tsconfig * fix: fix hardcoded width * fix tsconfig * fix: refactor test * fix: fix exports
- Loading branch information
1 parent
91cf31f
commit 261715b
Showing
21 changed files
with
479 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import styled, { keyframes } from '@xstyled/styled-components'; | ||
|
||
import { tet } from '@/tetrisly'; | ||
|
||
const animationCircle = keyframes` | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
`; | ||
|
||
const animationBar = keyframes` | ||
0% { | ||
transform: translate(-50%, 0px); | ||
} | ||
100% { | ||
transform: translate(150%, 0px); | ||
} | ||
`; | ||
|
||
export const AnimatedPath = styled(tet.path)<{ | ||
shape: string; | ||
}>` | ||
aspect-ratio: 1; | ||
transform-origin: center center; | ||
animation: ${({ shape }) => | ||
shape === 'circle' ? animationCircle : animationBar} | ||
1.4s infinite linear; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { SystemProps } from '@xstyled/styled-components'; | ||
|
||
import { config } from './Loader.styles'; | ||
import type { LoaderAppearance, LoaderShape, LoaderSize } from './types'; | ||
|
||
import { Theme } from '@/theme'; | ||
import { DeepPartial } from '@/utility-types/DeepPartial'; | ||
|
||
export type LoaderProps = { | ||
appearance?: LoaderAppearance; | ||
size?: LoaderSize; | ||
progress?: number; | ||
shape: LoaderShape; | ||
custom?: DeepPartial<SystemProps<Theme> & typeof config>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
import { Loader } from './Loader'; | ||
|
||
const meta = { | ||
title: 'Components/Loader', | ||
component: Loader, | ||
tags: ['autodocs'], | ||
} satisfies Meta<typeof Loader>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const DefaultCircle: Story = { | ||
args: { | ||
shape: 'circle', | ||
}, | ||
}; | ||
|
||
export const DefaultBar: Story = { | ||
args: { | ||
shape: 'bar', | ||
}, | ||
}; | ||
|
||
export const ProgressCircle = () => { | ||
const [progress, setProgress] = useState(0); | ||
useEffect(() => { | ||
const interval = setInterval(() => setProgress((p) => (p + 0.01) % 1), 50); | ||
return () => clearInterval(interval); | ||
}, []); | ||
return <Loader shape="circle" progress={progress} />; | ||
}; | ||
|
||
export const ProgressBar = () => { | ||
const [progress, setProgress] = useState(0); | ||
useEffect(() => { | ||
const interval = setInterval(() => setProgress((p) => (p + 0.01) % 1), 50); | ||
return () => clearInterval(interval); | ||
}, []); | ||
return <Loader shape="bar" progress={progress} />; | ||
}; | ||
|
||
export const White: Story = { | ||
args: { | ||
shape: 'circle', | ||
appearance: 'white', | ||
}, | ||
parameters: { | ||
backgrounds: { | ||
default: 'dark', | ||
}, | ||
}, | ||
}; | ||
|
||
export const Inverted: Story = { | ||
args: { | ||
shape: 'bar', | ||
appearance: 'inverted', | ||
}, | ||
parameters: { | ||
backgrounds: { | ||
default: 'dark', | ||
}, | ||
}, | ||
}; | ||
|
||
export const Greyscale: Story = { | ||
args: { | ||
shape: 'circle', | ||
appearance: 'greyscale', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { SystemProps } from '@xstyled/styled-components'; | ||
import { SvgProperties } from 'csstype'; | ||
|
||
import type { LoaderAppearance, LoaderShape, LoaderSize } from './types'; | ||
|
||
import { BaseConfigProps } from '@/utility-types/BaseConfigProps'; | ||
|
||
type Config = { | ||
size: Record< | ||
LoaderShape, | ||
Record<LoaderSize, SystemProps & Pick<SvgProperties, 'strokeWidth'>> | ||
>; | ||
appearance: Record< | ||
LoaderAppearance, | ||
Record<'base' | 'progress', SystemProps> | ||
>; | ||
svg: SystemProps; | ||
progress: SystemProps & Pick<SvgProperties, 'strokeLinecap'>; | ||
}; | ||
|
||
export const config = { | ||
size: { | ||
circle: { | ||
large: { | ||
w: 48, | ||
h: 48, | ||
strokeWidth: '2', | ||
}, | ||
medium: { | ||
w: 32, | ||
h: 32, | ||
strokeWidth: '2', | ||
}, | ||
small: { | ||
w: 20, | ||
h: 20, | ||
strokeWidth: '2', | ||
}, | ||
}, | ||
bar: { | ||
large: { | ||
w: 128, | ||
h: 8, | ||
strokeWidth: '8', | ||
}, | ||
medium: { | ||
w: 128, | ||
h: 6, | ||
strokeWidth: '6', | ||
}, | ||
small: { | ||
w: 128, | ||
h: 4, | ||
strokeWidth: '4', | ||
}, | ||
}, | ||
}, | ||
appearance: { | ||
primary: { | ||
base: { | ||
stroke: 'interaction-neutral-subtle-normal', | ||
}, | ||
progress: { | ||
stroke: 'interaction-default-normal', | ||
}, | ||
}, | ||
inverted: { | ||
base: { | ||
stroke: 'interaction-inverted-normal', | ||
}, | ||
progress: { | ||
stroke: 'interaction-default-normal', | ||
}, | ||
}, | ||
white: { | ||
base: { | ||
stroke: 'interaction-inverted-normal', | ||
opacity: 0.4, | ||
}, | ||
progress: { | ||
stroke: 'interaction-inverted-normal', | ||
}, | ||
}, | ||
greyscale: { | ||
base: { | ||
stroke: 'interaction-neutral-subtle-normal', | ||
}, | ||
progress: { | ||
stroke: 'interaction-neutral-normal', | ||
}, | ||
}, | ||
}, | ||
svg: { | ||
fill: 'none', | ||
borderRadius: 'large', | ||
}, | ||
progress: { | ||
strokeLinecap: 'round', | ||
}, | ||
} as const satisfies BaseConfigProps & Config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { Loader } from './Loader'; | ||
import { render } from '../../tests/render'; | ||
|
||
const getLoader = (jsx: JSX.Element) => { | ||
const { queryByTestId } = render(jsx); | ||
|
||
return { | ||
loader: queryByTestId('loader'), | ||
base: queryByTestId('loader-base'), | ||
progress: queryByTestId('loader-progress'), | ||
}; | ||
}; | ||
|
||
describe('Loader', () => { | ||
it('should render the loader', () => { | ||
const { loader } = getLoader(<Loader shape="circle" />); | ||
expect(loader).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render correct size (circle small)', () => { | ||
const { loader } = getLoader(<Loader shape="circle" size="small" />); | ||
expect(loader).toHaveStyle('width: 20px'); | ||
expect(loader).toHaveStyle('height: 20px'); | ||
}); | ||
|
||
it('should render correct size (circle medium)', () => { | ||
const { loader } = getLoader(<Loader shape="circle" size="medium" />); | ||
expect(loader).toHaveStyle('width: 32px'); | ||
expect(loader).toHaveStyle('height: 32px'); | ||
}); | ||
|
||
it('should render correct size (circle large)', () => { | ||
const { loader } = getLoader(<Loader shape="circle" size="large" />); | ||
expect(loader).toHaveStyle('width: 48px'); | ||
expect(loader).toHaveStyle('height: 48px'); | ||
}); | ||
|
||
it('should render correct size (bar small)', () => { | ||
const { loader } = getLoader(<Loader shape="bar" size="small" />); | ||
expect(loader).toHaveStyle('width: 128px'); | ||
expect(loader).toHaveStyle('height: 4px'); | ||
}); | ||
|
||
it('should render correct size (bar medium)', () => { | ||
const { loader } = getLoader(<Loader shape="bar" size="medium" />); | ||
expect(loader).toHaveStyle('width: 128px'); | ||
expect(loader).toHaveStyle('height: 6px'); | ||
}); | ||
|
||
it('should render correct size (bar large)', () => { | ||
const { loader } = getLoader(<Loader shape="bar" size="large" />); | ||
expect(loader).toHaveStyle('width: 128px'); | ||
expect(loader).toHaveStyle('height: 8px'); | ||
}); | ||
|
||
it('should animate when progress is undefined', () => { | ||
const { progress } = getLoader(<Loader shape="bar" size="medium" />); | ||
expect(progress).toHaveStyle('animation: fBJDHo 1.4s infinite linear'); | ||
}); | ||
|
||
it('should render correct appearance', () => { | ||
const { base, progress } = getLoader(<Loader shape="circle" />); | ||
expect(base).toHaveStyle('stroke: hsla(204,20%,95%,1);'); | ||
expect(progress).toHaveStyle('stroke: hsla(222,66%,51%,1);'); | ||
}); | ||
|
||
it('should render correct appearance (greyscale)', () => { | ||
const { base, progress } = getLoader( | ||
<Loader shape="circle" appearance="greyscale" /> | ||
); | ||
expect(base).toHaveStyle('stroke: hsla(204,20%,95%,1); '); | ||
expect(progress).toHaveStyle('stroke: hsla(210,12%,33%,1);'); | ||
}); | ||
|
||
it('should render correct appearance (inverted)', () => { | ||
const { base, progress } = getLoader( | ||
<Loader shape="circle" appearance="inverted" /> | ||
); | ||
expect(base).toHaveStyle('stroke: hsla(0,0%,100%,1);'); | ||
expect(progress).toHaveStyle('stroke: hsla(222,66%,51%,1);'); | ||
}); | ||
|
||
it('should render correct appearance (white)', () => { | ||
const { base, progress } = getLoader( | ||
<Loader shape="circle" appearance="white" /> | ||
); | ||
expect(base).toHaveStyle('stroke: hsla(0,0%,100%,1);'); | ||
expect(progress).toHaveStyle('stroke: hsla(0,0%,100%,1);'); | ||
}); | ||
}); |
Oops, something went wrong.