Skip to content

Commit

Permalink
Replace loading animation
Browse files Browse the repository at this point in the history
  • Loading branch information
connor-baer committed Nov 30, 2023
1 parent 06308d4 commit 34f0ded
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 40 deletions.
122 changes: 88 additions & 34 deletions packages/circuit-ui/components/Button/Button.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.base {
position: relative;
display: inline-flex;
justify-content: center;
width: auto;
Expand Down Expand Up @@ -30,6 +31,9 @@
/* Sizes */
.s {
--content-gap: var(--cui-spacings-byte);
--loader-diameter: 4px;
--loader-gap: 3px;
--loader-transform: scale(150%);

padding: calc(var(--cui-spacings-bit) - var(--cui-border-width-kilo))
calc(var(--cui-spacings-mega) - var(--cui-border-width-kilo));
Expand All @@ -38,6 +42,9 @@

.m {
--content-gap: var(--cui-spacings-byte);
--loader-diameter: 6px;
--loader-gap: 5px;
--loader-transform: scale(133%);

padding: calc(var(--cui-spacings-kilo) - var(--cui-border-width-kilo))
calc(var(--cui-spacings-giga) - var(--cui-border-width-kilo));
Expand Down Expand Up @@ -193,65 +200,114 @@
border-color: transparent;
}

/* Content */
.leading-icon {
flex-shrink: 0;
margin-right: var(--content-gap);
}

.trailing-icon {
flex-shrink: 0;
margin-left: var(--content-gap);
}

/* Loader */
.loader {
top: calc(50% - 3px);
position: absolute;
top: 0;
left: 0;
display: grid;
grid-auto-flow: column;
gap: var(--loader-gap);
place-content: center;
width: 100%;
height: 100%;
visibility: hidden;
opacity: 0;
transition: opacity var(--cui-transitions-default),
visibility var(--cui-transitions-default);
}

.loader,
.loader::before,
.loader::after {
position: absolute;
/* The animation of the dots consists of five phases: an 80ms pause
and four 160ms transitions between each dot being highlighted */

.dot {
--loader-opacity: 0.25;

display: block;
width: 6px;
height: 6px;
background-color: currentColor;
width: var(--loader-diameter);
height: var(--loader-diameter);
background-color: var(--cui-fg-normal);
border-radius: var(--cui-border-radius-circle);
animation-duration: 720ms; /* 80ms + 4 * 160ms */
animation-play-state: paused;
animation-timing-function: cubic-bezier(0.75, 0, 1, 1);
animation-iteration-count: infinite;
}

.loader::before,
.loader::after {
content: "";
@keyframes pulse1 {
0%,
11%,
55%,
100% {
opacity: var(--loader-opacity);
transform: scale(100%);
}

33% {
opacity: 1;
transform: var(--loader-transform);
}
}

.loader::before {
left: -10px;
.dot:nth-child(1) {
animation-name: pulse1;
}

.loader::after {
right: -10px;
@keyframes pulse2 {
0%,
33%,
77%,
100% {
opacity: var(--loader-opacity);
transform: scale(100%);
}

55% {
opacity: 1;
transform: var(--loader-transform);
}
}

.dot:nth-child(2) {
animation-name: pulse2;
}

@keyframes pulse3 {
0%,
55%,
100% {
opacity: var(--loader-opacity);
transform: scale(100%);
}

77% {
opacity: 1;
transform: var(--loader-transform);
}
}

.dot:nth-child(3) {
animation-name: pulse3;
}

.base[aria-busy="true"] .loader {
visibility: inherit;
opacity: 1;
}

.base[aria-busy="true"] .dot {
animation-play-state: running;
}

/* Content */
.content {
display: inline-flex;
display: grid;
grid-auto-flow: column;
gap: var(--content-gap);
place-content: center;
align-items: center;
visibility: inherit;
opacity: 1;
transition: opacity var(--cui-transitions-default),
transform var(--cui-transitions-default),
visibility var(--cui-transitions-default);
transform: scale3d(1, 1, 1);
transition: opacity var(--cui-transitions-default);
}

.base:active .content,
Expand All @@ -261,7 +317,5 @@
}

.base[aria-busy="true"] .content {
visibility: hidden;
opacity: 0;
transform: scale3d(0, 0, 0);
}
10 changes: 4 additions & 6 deletions packages/circuit-ui/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,20 +220,18 @@ export const Button = forwardRef<any, ButtonProps>(
ref={ref}
>
<span className={classes.loader} aria-hidden={!isLoading}>
<span className={classes.dot} />
<span className={classes.dot} />
<span className={classes.dot} />
<span className={utilityClasses.hideVisually}>{loadingLabel}</span>
</span>
<span className={classes.content}>
{LeadingIcon && (
<LeadingIcon
className={classes['leading-icon']}
size={size === 's' ? '16' : '24'}
aria-hidden="true"
/>
<LeadingIcon size={size === 's' ? '16' : '24'} aria-hidden="true" />
)}
<span className={classes.label}>{label}</span>
{TrailingIcon && (
<TrailingIcon
className={classes['trailing-icon']}
size={size === 's' ? '16' : '24'}
aria-hidden="true"
/>
Expand Down

0 comments on commit 34f0ded

Please sign in to comment.