Skip to content

Commit

Permalink
fix(web-components): move spinner animation off of mainthread (#32056)
Browse files Browse the repository at this point in the history
  • Loading branch information
davatron5000 authored Jul 22, 2024
1 parent 0c3c4ac commit 1bfb9c9
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "fix: move spinner animation off of main thread",
"packageName": "@fluentui/web-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
169 changes: 127 additions & 42 deletions packages/web-components/src/spinner/spinner.styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { css } from '@microsoft/fast-element';
import { display } from '../utils/index.js';
import { colorBrandStroke1, colorBrandStroke2, colorNeutralStrokeOnBrand2 } from '../theme/design-tokens.js';
import { display, forcedColorsStylesheetBehavior } from '../utils/index.js';
import {
colorBrandStroke1,
colorBrandStroke2,
colorNeutralStrokeOnBrand2,
curveEasyEase,
strokeWidthThick,
strokeWidthThicker,
strokeWidthThickest,
} from '../theme/design-tokens.js';
import {
extraLargeState,
extraSmallState,
Expand All @@ -12,81 +20,158 @@ import {
} from '../styles/states/index.js';

export const styles = css`
${display('flex')}
${display('inline-flex')}
:host {
display: flex;
align-items: center;
height: 32px;
width: 32px;
contain: content;
--duration: 1.5s;
--indicatorSize: ${strokeWidthThicker};
--size: 32px;
height: var(--size);
width: var(--size);
contain: strict;
content-visibility: auto;
}
:host(${tinyState}) {
height: 20px;
width: 20px;
--indicatorSize: ${strokeWidthThick};
--size: 20px;
}
:host(${extraSmallState}) {
height: 24px;
width: 24px;
--indicatorSize: ${strokeWidthThick};
--size: 24px;
}
:host(${smallState}) {
height: 28px;
width: 28px;
--indicatorSize: ${strokeWidthThick};
--size: 28px;
}
:host(${largeState}) {
height: 36px;
width: 36px;
--indicatorSize: ${strokeWidthThicker};
--size: 36px;
}
:host(${extraLargeState}) {
height: 40px;
width: 40px;
--indicatorSize: ${strokeWidthThicker};
--size: 40px;
}
:host(${hugeState}) {
height: 44px;
width: 44px;
--indicatorSize: ${strokeWidthThickest};
--size: 44px;
}
.progress,
.background,
.spinner,
.start,
.end,
.indicator {
position: absolute;
inset: 0;
}
.progress,
.spinner,
.indicator {
animation: none var(--duration) infinite ${curveEasyEase};
}
.progress {
height: 100%;
width: 100%;
animation-timing-function: linear;
animation-name: spin-linear;
}
.background {
fill: none;
stroke: ${colorBrandStroke2};
stroke-width: 1.5px;
border: var(--indicatorSize) solid ${colorBrandStroke2};
border-radius: 50%;
}
:host(${invertedState}) .background {
stroke: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.2);
}
.spinner {
animation-name: spin-swing;
}
.start {
overflow: hidden;
inset-inline-end: 50%;
}
.end {
overflow: hidden;
inset-inline-start: 50%;
}
.indicator {
stroke: ${colorBrandStroke1};
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
transform-origin: 50% 50%;
transform: rotate(-90deg);
transition: all 0.2s ease-in-out;
animation: spin-infinite 3s cubic-bezier(0.53, 0.21, 0.29, 0.67) infinite;
color: ${colorBrandStroke1};
box-sizing: border-box;
border-radius: 50%;
border: var(--indicatorSize) solid transparent;
border-block-start-color: currentcolor;
border-inline-end-color: currentcolor;
}
:host(${invertedState}) .indicator {
stroke: ${colorNeutralStrokeOnBrand2};
color: ${colorNeutralStrokeOnBrand2};
}
@keyframes spin-infinite {
.start .indicator {
rotate: 135deg; /* Starts 9 o'clock */
inset: 0 -100% 0 0;
animation-name: spin-start;
}
.end .indicator {
rotate: 135deg; /* Ends at 3 o'clock */
inset: 0 0 0 -100%;
animation-name: spin-end;
}
@keyframes spin-linear {
100% {
transform: rotate(360deg);
}
}
@keyframes spin-swing {
0% {
stroke-dasharray: 0.01px 43.97px;
transform: rotate(-135deg);
}
50% {
transform: rotate(0deg);
}
100% {
transform: rotate(225deg);
}
}
@keyframes spin-start {
0%,
100% {
transform: rotate(0deg);
}
50% {
stroke-dasharray: 21.99px 21.99px;
transform: rotate(450deg);
transform: rotate(-80deg);
}
}
@keyframes spin-end {
0%,
100% {
stroke-dasharray: 0.01px 43.97px;
transform: rotate(1080deg);
transform: rotate(0deg);
}
50% {
transform: rotate(70deg);
}
}
`;
`.withBehaviors(
forcedColorsStylesheetBehavior(css`
.background {
display: none;
}
.indicator {
border-color: Canvas;
border-block-start-color: Highlight;
border-inline-end-color: Highlight;
}
`),
);
18 changes: 13 additions & 5 deletions packages/web-components/src/spinner/spinner.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@ import { html } from '@microsoft/fast-element';
import { Spinner } from './spinner.js';

export const template = html<Spinner>`
<slot name="indicator"
><svg class="progress" part="progress" viewBox="0 0 16 16">
<circle class="background" cx="8px" cy="8px" r="7px"></circle>
<circle class="indicator" cx="8px" cy="8px" r="7px"></circle></svg
></slot>
<slot name="indicator">
<div class="background"></div>
<div class="progress">
<div class="spinner">
<div class="start">
<div class="indicator"></div>
</div>
<div class="end">
<div class="indicator"></div>
</div>
</div>
</div>
</slot>
`;

0 comments on commit 1bfb9c9

Please sign in to comment.