This repository has been archived by the owner on Jan 20, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add loading spinner * Make demo groups shared * Loader story * Add key and remove unused declaration * Switch DOM prperties to camelCase * Change to theme * Color and type comments * Change sizes * README/storybook changes * Prettier
- Loading branch information
Showing
7 changed files
with
344 additions
and
107 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/** @jsx jsx */ | ||
import { jsx } from "@emotion/core"; | ||
import { storiesOf } from "@storybook/react"; | ||
import { LoadingSpinner, Size } from "./index"; | ||
import { Button } from "../Button"; | ||
import { colors } from "../colors"; | ||
import * as typography from "../typography"; | ||
import { DemoSection, DemoGroup } from "../shared/DemoSection"; | ||
|
||
const SPINNER_SIZES: Size[] = ["large", "medium", "small", "xsmall", "2xsmall"]; | ||
|
||
storiesOf("Loaders", module) | ||
.addParameters({ | ||
options: { | ||
showPanel: false, | ||
}, | ||
}) | ||
.add("Catalog", () => ( | ||
<div css={{ color: colors.black.base }}> | ||
<DemoSection | ||
title="Spinners" | ||
description="Spinners are used when we are unable to determine loading time. Ideally, they should appear as briefly and infrequently as possible." | ||
> | ||
<DemoGroup | ||
title="On Pages & Cards" | ||
description="Spinners will most often appear on full pages and cards. Whenever possible, they should be paired with descriptive text that helps the user understand exactly what the system is working toward. Spinners should be center-aligned to the page with any text spaced 20 px below." | ||
> | ||
<div | ||
css={{ | ||
flex: "1 1 0%", | ||
border: `1px solid ${colors.silver.dark}`, | ||
borderRadius: 8, | ||
margin: 6, | ||
}} | ||
> | ||
{SPINNER_SIZES.map(size => ( | ||
<div key={size} css={{ margin: 20 }}> | ||
<span | ||
css={{ | ||
...typography.base.small, | ||
fontWeight: 600, | ||
display: "block", | ||
textTransform: "uppercase", | ||
}} | ||
> | ||
{size} | ||
</span> | ||
<LoadingSpinner css={{ display: "block" }} size={size} /> | ||
</div> | ||
))} | ||
</div> | ||
<div | ||
css={{ | ||
backgroundColor: colors.black.base, | ||
flex: "1 1 0%", | ||
border: `1px solid ${colors.silver.dark}`, | ||
borderRadius: 8, | ||
margin: 6, | ||
}} | ||
> | ||
{SPINNER_SIZES.map(size => ( | ||
<div key={size} css={{ margin: 20 }}> | ||
<span | ||
css={{ | ||
...typography.base.small, | ||
fontWeight: 600, | ||
color: colors.grey.lighter, | ||
display: "block", | ||
textTransform: "uppercase", | ||
}} | ||
> | ||
{size} | ||
</span> | ||
<LoadingSpinner | ||
theme="dark" | ||
css={{ display: "block" }} | ||
size={size} | ||
/> | ||
</div> | ||
))} | ||
</div> | ||
</DemoGroup> | ||
<DemoGroup | ||
title="In Buttons" | ||
description="Spinners may also exist inside buttons. If a user clicks on a button and the system needs time to process the request, the button should expand horizontally to the right, the color should change to the next lightest shade, and the spinner should appear to the left of the text." | ||
> | ||
<Button | ||
color={colors.blue.base} | ||
icon={<LoadingSpinner theme="dark" size="2xsmall" />} | ||
css={{ width: "100%", marginTop: 6, marginBottom: 20 }} | ||
> | ||
Submit | ||
</Button> | ||
<Button | ||
color={colors.blue.base} | ||
disabled | ||
icon={<LoadingSpinner size="2xsmall" />} | ||
css={{ width: "100%", marginBottom: 20 }} | ||
> | ||
Submit | ||
</Button> | ||
<Button | ||
feel="flat" | ||
icon={<LoadingSpinner size="2xsmall" />} | ||
css={{ width: "100%" }} | ||
> | ||
Submit | ||
</Button> | ||
</DemoGroup> | ||
</DemoSection> | ||
</div> | ||
)); |
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,112 @@ | ||
/** @jsx jsx */ | ||
import React from "react"; | ||
import * as CSS from "csstype"; | ||
import { jsx, keyframes } from "@emotion/core"; | ||
import { colors } from "../colors"; | ||
|
||
export type Size = "large" | "medium" | "small" | "xsmall" | "2xsmall"; | ||
export type Theme = "light" | "dark"; | ||
interface Props { | ||
/** | ||
* Class name that will be applied to the svg | ||
*/ | ||
className?: string; | ||
|
||
/** | ||
* Theme for the spinner | ||
* @default "light" | ||
*/ | ||
theme?: Theme; | ||
|
||
/** | ||
* Size of the spinner | ||
* @default "medium" | ||
*/ | ||
size?: Size; | ||
} | ||
|
||
// The whole animation is exactly 5 seconds long. | ||
// Each rotation is 450 degrees, with a deceleration at | ||
// 420 degrees, and a reduced speed between 420-450. | ||
// 1st rotation: 60 deg and 90 deg | ||
// 2nd rotation: 150 deg and 180 deg | ||
// 3rd rotation: 240 deg and 270 deg | ||
// 4th rotation: 330 deg and 360 deg (restart loop) | ||
const SPIN = keyframes` | ||
25% { transform: rotate(450deg) } | ||
50% { transform: rotate(900deg) } | ||
75% { transform: rotate(1350deg) } | ||
100% { transform: rotate(1800deg) } | ||
`; | ||
|
||
const SIZE_MAP: Record<Size, number> = { | ||
large: 90, | ||
medium: 64, | ||
small: 48, | ||
xsmall: 32, | ||
"2xsmall": 16, | ||
}; | ||
|
||
const THEME_MAP: Record< | ||
Theme, | ||
{ | ||
orbitColor: CSS.ColorProperty; | ||
orbitOpacity: CSS.GlobalsNumber; | ||
asteroidColor: CSS.ColorProperty; | ||
} | ||
> = { | ||
light: { | ||
orbitColor: colors.silver.light, | ||
orbitOpacity: 1, | ||
asteroidColor: colors.blue.base, | ||
}, | ||
dark: { | ||
orbitColor: colors.white, | ||
orbitOpacity: 0.5, | ||
asteroidColor: colors.white, | ||
}, | ||
}; | ||
|
||
export const LoadingSpinner: React.FC<Props> = ({ | ||
theme = "light", | ||
size = "medium", | ||
className, | ||
...props | ||
}) => { | ||
const { orbitColor, orbitOpacity, asteroidColor } = THEME_MAP[theme]; | ||
|
||
const pixelSize = SIZE_MAP[size]; | ||
|
||
return ( | ||
<svg | ||
className={className} | ||
viewBox="0 0 100 100" | ||
css={{ | ||
width: pixelSize, | ||
height: pixelSize, | ||
}} | ||
{...props} | ||
> | ||
<circle | ||
strokeWidth="8" | ||
stroke={orbitColor} | ||
strokeOpacity={orbitOpacity} | ||
fill="transparent" | ||
r="41" | ||
cx="50" | ||
cy="50" | ||
/> | ||
<g transform="translate(50 50)"> | ||
<circle | ||
css={{ | ||
animation: `${SPIN} 5s cubic-bezier(0.6, 0.22, 0.44, 0.8) infinite`, | ||
}} | ||
fill={asteroidColor} | ||
r="10" | ||
cx="40" | ||
cy="0" | ||
/> | ||
</g> | ||
</svg> | ||
); | ||
}; |
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 @@ | ||
export * from "./LoadingSpinner"; |
Oops, something went wrong.