Skip to content

Commit

Permalink
Add: xs size to LoadingSpinner (#5148)
Browse files Browse the repository at this point in the history
* add xs to LoadingSpinner, update render method to switch and migrate to css vars

* add changeset

* update docs

* move spinner icons into a subcomponent

* update css specificity

* update to px values

* remove redundant stickersheet col

* update docs and outline current colors used in Figma for spinner

* Update packages/components/src/Loading/LoadingSpinner/_docs/LoadingSpinner.stories.tsx

Co-authored-by: Cassandra <[email protected]>

* Update stickersheet story for icon xs for Button examples and clean up LoadingSpinenr stories

---------

Co-authored-by: Cassandra <[email protected]>
  • Loading branch information
mcwinter07 and HeartSquared authored Oct 14, 2024
1 parent 4048050 commit 3e2d4e6
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 75 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-boats-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kaizen/components": minor
---

Add `xs` size to LoadingSpinner
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.loadingSpinner {
--loading-spinner-size: 48px;

display: flex;
width: var(--loading-spinner-size);
height: var(--loading-spinner-size);
}

.xs {
--loading-spinner-size: 16px;
}

.sm {
--loading-spinner-size: 24px;
}

.md {
--loading-spinner-size: 48px;
}

.spinner {
animation: spinner var(--animation-duration-deliberate)
var(--animation-easing-function-ease-in-out) infinite;
width: 100%;
height: 100%;
}

@keyframes spinner {
100% {
transform: rotate(360deg);
}
}

This file was deleted.

64 changes: 10 additions & 54 deletions packages/components/src/Loading/LoadingSpinner/LoadingSpinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import React, { HTMLAttributes } from "react"
import classnames from "classnames"
import { VisuallyHidden } from "~components/VisuallyHidden"
import { OverrideClassName } from "~components/types/OverrideClassName"
import styles from "./LoadingSpinner.module.scss"
import { SpinnerIcon } from "./subcomponents"
import styles from "./LoadingSpinner.module.css"

export type LoadingSpinnerProps = {
accessibilityLabel: string
/**
* Generally use "md" unless spinner is inside a form field
* Generally use "md" unless spinner is inside a form field. @default "md"
*/
size?: "sm" | "md"
size?: "xs" | "sm" | "md"
} & OverrideClassName<Omit<HTMLAttributes<HTMLDivElement>, "children">>

/**
Expand All @@ -23,61 +24,16 @@ export const LoadingSpinner = ({
...props
}: LoadingSpinnerProps): JSX.Element => (
<div
data-automation-id="loading-spinner"
className={classnames(styles.loadingSpinner, classNameOverride)}
className={classnames(
styles.loadingSpinner,
styles[size],
classNameOverride
)}
role="status"
{...props}
>
<VisuallyHidden>{accessibilityLabel}</VisuallyHidden>
{size === "md" ? (
<svg
className={styles.spinner}
aria-hidden="true"
viewBox="0 0 48 48"
width={48} // Ideally we'd use spacing tokens converted to unitless values
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="24"
cy="24"
r="22.5"
stroke="currentColor"
strokeWidth="3"
strokeOpacity="0.3"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
fill="currentColor"
d="M46.5 24c.8284 0 1.5049-.6734 1.4539-1.5002C47.21 10.44 37.5601.789989 25.5003.0461639 24.6734-.004835 24 .671607 24 1.50003c0 .82843.6738 1.49444 1.5002 1.55277 10.4023.73424 18.7128 9.0447 19.447 19.447C45.0056 23.3262 45.6716 24 46.5 24z"
/>
</svg>
) : (
<svg
className={styles.spinner}
aria-hidden="true"
viewBox="0 0 24 24"
width={24} // Ideally we'd use spacing tokens converted to unitless values
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="9"
stroke="currentColor"
strokeWidth="2"
strokeOpacity="0.3"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
fill="currentColor"
d="M21.0564 13c.5076 0 .9377-.3851.9431-.8926.0004-.0358.0005-.0716.0005-.1074 0-5.52285-4.4771-10-10-10-.0359 0-.0718.00019-.1076.00057-.5076.00535-.8926.43552-.8926.94308v.11543C10.9998 3.59163 11.4675 4 12 4c4.4183 0 8 3.58172 8 8 0 .5324.4083 1 .9407 1h.1157z"
/>
</svg>
)}
<SpinnerIcon size={size} />
</div>
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,17 @@ When inside a button, it is intended to have the same color as the label text.

### ClassNameOverride

Override styles such as the colour of the spinner using `classNameOverride`.
Override styles, such as the colour of the spinner using `classNameOverride`.

<Canvas of={LoadingSpinnerStories.ClassNameOverride} />

Below is an example of how to apply the current color tokens used in designs.

<Canvas of={LoadingSpinnerStories.Colors} />

### Size

Generally use `"md"` (default value) unless spinner is inside a form field.
Generally use `"md"` (default value) unless spinner is inside a form field, in which case use `sm`. The `xs` size is for buttons or content dense layouts.

<Canvas of={LoadingSpinnerStories.Size} />

Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ const StickerSheetTemplate: StickerSheetStory = {
render: ({ isReversed }) => (
<StickerSheet isReversed={isReversed}>
<StickerSheet.Header
headings={['Size "sm"', 'Size "md"', "Custom colour"]}
headings={['Size "xs"', 'Size "sm"', 'Size "md"', "Custom color"]}
/>
<StickerSheet.Body>
<StickerSheet.Row>
<LoadingSpinner accessibilityLabel="Loading" size="xs" />
<LoadingSpinner accessibilityLabel="Loading" size="sm" />
<LoadingSpinner accessibilityLabel="Loading" size="md" />
<LoadingSpinner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,28 @@ export const ClassNameOverride: Story = {
args: { classNameOverride: "text-green-400" },
}

export const Colors: Story = {
render: args => (
<>
<LoadingSpinner {...args} classNameOverride="text-green-400" />
<LoadingSpinner {...args} classNameOverride="text-purple-800" />
<LoadingSpinner {...args} classNameOverride="text-blue-500" />
<LoadingSpinner {...args} classNameOverride="text-red-500" />
</>
),
decorators: [
Story => (
<div className="flex gap-24">
<Story />
</div>
),
],
}

export const Size: Story = {
render: args => (
<>
<LoadingSpinner {...args} size="xs" />
<LoadingSpinner {...args} size="sm" />
<LoadingSpinner {...args} size="md" />
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from "react"
import styles from "../LoadingSpinner.module.css"

const SmallSpinnerIcon = (): JSX.Element => (
<svg
className={styles.spinner}
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="9"
stroke="currentColor"
strokeWidth="2"
strokeOpacity="0.3"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
fill="currentColor"
d="M21.0564 13c.5076 0 .9377-.3851.9431-.8926.0004-.0358.0005-.0716.0005-.1074 0-5.52285-4.4771-10-10-10-.0359 0-.0718.00019-.1076.00057-.5076.00535-.8926.43552-.8926.94308v.11543C10.9998 3.59163 11.4675 4 12 4c4.4183 0 8 3.58172 8 8 0 .5324.4083 1 .9407 1h.1157z"
/>
</svg>
)

const MediumSpinnerIcon = (): JSX.Element => (
<svg
className={styles.spinner}
aria-hidden="true"
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="24"
cy="24"
r="22.5"
stroke="currentColor"
strokeWidth="3"
strokeOpacity="0.3"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
fill="currentColor"
d="M46.5 24c.8284 0 1.5049-.6734 1.4539-1.5002C47.21 10.44 37.5601.789989 25.5003.0461639 24.6734-.004835 24 .671607 24 1.50003c0 .82843.6738 1.49444 1.5002 1.55277 10.4023.73424 18.7128 9.0447 19.447 19.447C45.0056 23.3262 45.6716 24 46.5 24z"
/>
</svg>
)

const ExtraSmallSpinnerIcon = (): JSX.Element => (
<svg
className={styles.spinner}
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
opacity="0.3"
cx="8"
cy="8"
r="6"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M14 8C14 4.68629 11.3137 2 8 2"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)

type SpinnerIconProps = {
size: "xs" | "sm" | "md"
}

export const SpinnerIcon = ({ size }: SpinnerIconProps): JSX.Element => {
if (size === "xs") return <ExtraSmallSpinnerIcon />
if (size === "sm") return <SmallSpinnerIcon />
return <MediumSpinnerIcon />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./SpinnerIcon"
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const StickerSheetTemplate: StickerSheetStory = {
<ArrowForwardIcon role="presentation" />
</Button>
<Button size="small" isDisabled>
<LoadingSpinner size="sm" accessibilityLabel="submitting label" />
<LoadingSpinner size="xs" accessibilityLabel="submitting label" />
</Button>
</StickerSheet.Row>
<StickerSheet.Row rowTitle="Icon only small">
Expand All @@ -93,7 +93,7 @@ const StickerSheetTemplate: StickerSheetStory = {
<TrashIcon role="img" aria-label="Remove label" />
</Button>
<Button size="small" isDisabled>
<LoadingSpinner size="sm" accessibilityLabel="Removing label" />
<LoadingSpinner size="xs" accessibilityLabel="Removing label" />
</Button>
</StickerSheet.Row>
</StickerSheet.Body>
Expand Down

0 comments on commit 3e2d4e6

Please sign in to comment.