fix: update spinner to use svg instead

This commit is contained in:
Tobias Johansson
2025-04-24 11:32:54 +02:00
committed by Simon Emanuelsson
parent f56a1ece0f
commit d0c6d1d875
5 changed files with 69 additions and 155 deletions

View File

@@ -5,6 +5,7 @@ import { variants } from './variants'
import type { ButtonProps } from './types' import type { ButtonProps } from './types'
import { Spinner } from '../Spinner' import { Spinner } from '../Spinner'
import styles from './button.module.css' import styles from './button.module.css'
import { SpinnerProps } from '../Spinner/Spinner'
export function Button({ export function Button({
variant, variant,
@@ -15,7 +16,6 @@ export function Button({
typography, typography,
className, className,
children, children,
isPending,
...props ...props
}: ButtonProps) { }: ButtonProps) {
const classNames = variants({ const classNames = variants({
@@ -27,15 +27,28 @@ export function Button({
className, className,
}) })
let spinnerType: SpinnerProps['type'] = 'Dark'
switch (color) {
case 'Primary':
spinnerType = 'Dark'
break
case 'Inverted':
spinnerType = 'White'
break
default:
spinnerType = 'Dark'
}
return ( return (
<ButtonRAC {...props} className={classNames} isPending={isPending}> <ButtonRAC {...props} className={classNames}>
{({ isPending }) => { {({ isPending }) => {
return ( return (
<> <>
{children} {children}
{isPending && ( {isPending && (
<div className={styles.spinnerWrapper}> <div className={styles.spinnerWrapper}>
<Spinner size="Small" color="CurrentColor" /> <Spinner size={20} type={spinnerType} />
</div> </div>
)} )}
</> </>

View File

@@ -7,98 +7,35 @@ import { Spinner } from './Spinner'
const meta: Meta<typeof Spinner> = { const meta: Meta<typeof Spinner> = {
title: 'Components/Spinner', title: 'Components/Spinner',
component: Spinner, component: Spinner,
argTypes: {}, argTypes: {
type: {
control: 'text',
},
size: {
control: 'number',
},
},
} }
export default meta export default meta
type Story = StoryObj<typeof Spinner> type Story = StoryObj<typeof Spinner>
function Wrapper({ export const Dark: Story = {
children, args: {
backgroundColor, type: 'Dark',
}: { size: 40,
children: React.ReactNode },
backgroundColor?: string
}) {
return (
<div
style={{
height: '200px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor,
}}
>
{children}
</div>
)
} }
export const Default: Story = { export const White: Story = {
args: { args: {
color: 'Accent', type: 'White',
size: 'Medium', size: 40,
}, },
decorators: [ parameters: {
(Story) => ( backgrounds: {
<Wrapper> default: 'Scandic Primary Dark',
<Story /> },
</Wrapper>
),
],
}
export const Inverted: Story = {
args: {
color: 'Inverted',
size: 'Medium',
}, },
decorators: [
(Story) => (
<Wrapper backgroundColor="var(--Icon-Interactive-Default)">
<Story />
</Wrapper>
),
],
}
export const Small: Story = {
args: {
size: 'Small',
},
decorators: [
(Story) => (
<Wrapper>
<Story />
</Wrapper>
),
],
}
export const Medium: Story = {
args: {
size: 'Medium',
},
decorators: [
(Story) => (
<Wrapper>
<Story />
</Wrapper>
),
],
}
export const Large: Story = {
args: {
size: 'Large',
},
decorators: [
(Story) => (
<Wrapper>
<Story />
</Wrapper>
),
],
} }

View File

@@ -1,21 +1,34 @@
import { VariantProps } from 'class-variance-authority'
import styles from './spinner.module.css' import styles from './spinner.module.css'
import { VariantProps } from 'class-variance-authority'
import { variants } from './variants' import { variants } from './variants'
type SpinnerProps = VariantProps<typeof variants> export interface SpinnerProps extends VariantProps<typeof variants> {
size?: number
}
export function Spinner({ color, size }: SpinnerProps) { export function Spinner({ type, size = 20 }: SpinnerProps) {
const classNames = variants({ const classNames = variants({
color, type,
size,
}) })
return ( return (
<div className={classNames}> <svg
{[...Array(8)].map((_, i) => ( xmlns="http://www.w3.org/2000/svg"
<div key={i} className={styles.dot} /> width={size}
))} height={size}
</div> viewBox="0 0 20 21"
fill="none"
className={classNames}
>
<circle className={styles.dot} cx="10" cy="2.64147" r="1.73913" />
<circle className={styles.dot} cx="16.087" cy="5.25018" r="1.73913" />
<circle className={styles.dot} cx="18.2609" cy="10.9023" r="1.73913" />
<circle className={styles.dot} cx="16.087" cy="16.5545" r="1.73913" />
<circle className={styles.dot} cx="10" cy="19.1632" r="1.73913" />
<circle className={styles.dot} cx="3.91304" cy="16.5545" r="1.73913" />
<circle className={styles.dot} cx="1.73913" cy="10.9023" r="1.73913" />
<circle className={styles.dot} cx="3.91304" cy="5.25018" r="1.73913" />
</svg>
) )
} }

View File

@@ -1,84 +1,42 @@
.spinner { .spinner {
display: inline-block; display: inline-block;
position: relative;
--size: 20px;
--dot-size: 3px;
width: var(--size);
height: var(--size);
} }
.size-small { .dot {
--size: 20px;
}
.size-medium {
--size: 30px;
--dot-size: 5px;
}
.size-large {
--size: 40px;
--dot-size: 6px;
}
.spinner .dot {
transform-origin: calc(var(--size) / 2) calc(var(--size) / 2);
animation: spinnerAnimation 0.8s linear infinite; animation: spinnerAnimation 0.8s linear infinite;
transform-origin: center;
} }
.spinner .dot::after { .dark .dot {
content: ' '; fill: var(--Icon-Interactive-Default);
display: block;
position: absolute;
top: calc(var(--dot-size) / 2);
left: var(--dot-size);
width: var(--dot-size);
height: var(--dot-size);
border-radius: 50%;
background-color: currentColor;
} }
.accent .dot::after { .white .dot {
background-color: var(--Icon-Interactive-Default); fill: var(--Icon-Inverted);
}
.inverted .dot::after {
background-color: var(--Icon-Inverted);
} }
.dot:nth-child(1) { .dot:nth-child(1) {
transform: rotate(0deg);
animation-delay: -0.7s; animation-delay: -0.7s;
} }
.dot:nth-child(2) { .dot:nth-child(2) {
transform: rotate(45deg);
animation-delay: -0.6s; animation-delay: -0.6s;
} }
.dot:nth-child(3) { .dot:nth-child(3) {
transform: rotate(90deg);
animation-delay: -0.5s; animation-delay: -0.5s;
} }
.dot:nth-child(4) { .dot:nth-child(4) {
transform: rotate(135deg);
animation-delay: -0.4s; animation-delay: -0.4s;
} }
.dot:nth-child(5) { .dot:nth-child(5) {
transform: rotate(180deg);
animation-delay: -0.3s; animation-delay: -0.3s;
} }
.dot:nth-child(6) { .dot:nth-child(6) {
transform: rotate(225deg);
animation-delay: -0.2s; animation-delay: -0.2s;
} }
.dot:nth-child(7) { .dot:nth-child(7) {
transform: rotate(270deg);
animation-delay: -0.1s; animation-delay: -0.1s;
} }
.dot:nth-child(8) { .dot:nth-child(8) {
transform: rotate(315deg);
animation-delay: 0s; animation-delay: 0s;
} }

View File

@@ -4,20 +4,13 @@ import styles from './spinner.module.css'
export const config = { export const config = {
variants: { variants: {
color: { type: {
Accent: styles.accent, Dark: styles.dark,
Inverted: styles.inverted, White: styles.white,
CurrentColor: 'currentColor',
},
size: {
Small: styles['size-small'],
Medium: styles['size-medium'],
Large: styles['size-large'],
}, },
}, },
defaultVariants: { defaultVariants: {
color: 'Accent', type: 'Dark',
size: 'Medium',
}, },
} as const } as const