From ee0fdfac5bfcdba3d95ce100ee5e448494fea56e Mon Sep 17 00:00:00 2001 From: Lachlan Campbell Date: Sun, 15 Jan 2023 23:10:03 -0800 Subject: [PATCH 1/2] components: Rewrite Spinner for better performance --- packages/components/src/Spinner.tsx | 71 +++++++++++------------------ 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/packages/components/src/Spinner.tsx b/packages/components/src/Spinner.tsx index f3a030312..19b9bffda 100644 --- a/packages/components/src/Spinner.tsx +++ b/packages/components/src/Spinner.tsx @@ -1,28 +1,17 @@ -import React, { SVGAttributes } from 'react' -import { keyframes } from '@emotion/react' - +import React from 'react' import type { ThemeUICSSObject } from '@theme-ui/css' import { Box, BoxOwnProps, BoxProps } from './Box' import type { ForwardRef } from './types' import { __internalProps } from './util' -const spin = keyframes({ - from: { - transform: 'rotate(0deg)', - }, - to: { - transform: 'rotate(360deg)', - }, -}) - export interface SpinnerProps extends Omit< React.ComponentPropsWithRef<'svg'>, 'opacity' | 'color' | 'css' | 'sx' | 'strokeWidth' >, BoxOwnProps { - size?: number | string + size?: number strokeWidth?: number title?: string duration?: number @@ -34,41 +23,21 @@ export const Spinner: ForwardRef = size = 48, strokeWidth = 4, max = 1, - title = 'Loading...', - duration = 500, + title = 'Loading…', + duration = 750, ...props }, ref ) { - const r = 16 - strokeWidth - const C = 2 * r * Math.PI - const offset = C - (1 / 4) * C - const __css: ThemeUICSSObject = { color: 'primary', overflow: 'visible', } - const circleProps: SVGAttributes = { - cx: 16, - cy: 16, - r, - strokeDasharray: C, - strokeDashoffset: offset, - } - - const __circleCss: ThemeUICSSObject = { - transformOrigin: '50% 50%', - animationName: spin.toString(), - animationTimingFunction: 'linear', - animationDuration: duration + 'ms', - animationIterationCount: 'infinite', - } - const svgProps = { strokeWidth, - viewBox: '0 0 32 32', + viewBox: `0 0 ${size} ${size}`, width: size, height: size, @@ -77,6 +46,16 @@ export const Spinner: ForwardRef = role: 'img', } + const radius = size / 2 - strokeWidth + const center = radius + strokeWidth + const circleProps = { + strokeWidth, + r: radius, + cx: radius + strokeWidth, + cy: radius + strokeWidth, + fill: 'none', + } + return ( = {...__internalProps({ __css })} > {title} - - + + + + ) }) From 716501e7c107bcf2edd5e0203ddf5c3f3639f397 Mon Sep 17 00:00:00 2001 From: Lachlan Campbell Date: Sun, 15 Jan 2023 23:23:46 -0800 Subject: [PATCH 2/2] Fix scaling --- packages/components/src/Spinner.tsx | 18 +++---- .../test/__snapshots__/index.tsx.snap | 53 ++++++------------- .../docs/src/pages/components/spinner.mdx | 9 ++-- 3 files changed, 30 insertions(+), 50 deletions(-) diff --git a/packages/components/src/Spinner.tsx b/packages/components/src/Spinner.tsx index 19b9bffda..c78572b95 100644 --- a/packages/components/src/Spinner.tsx +++ b/packages/components/src/Spinner.tsx @@ -23,7 +23,7 @@ export const Spinner: ForwardRef = size = 48, strokeWidth = 4, max = 1, - title = 'Loading…', + title = 'Loading', duration = 750, ...props }, @@ -37,7 +37,7 @@ export const Spinner: ForwardRef = const svgProps = { strokeWidth, - viewBox: `0 0 ${size} ${size}`, + viewBox: '0 0 32 32', width: size, height: size, @@ -46,13 +46,11 @@ export const Spinner: ForwardRef = role: 'img', } - const radius = size / 2 - strokeWidth - const center = radius + strokeWidth const circleProps = { strokeWidth, - r: radius, - cx: radius + strokeWidth, - cy: radius + strokeWidth, + r: 16 - strokeWidth, + cx: 16, + cy: 16, fill: 'none', } @@ -66,13 +64,13 @@ export const Spinner: ForwardRef = > {title} - + diff --git a/packages/components/test/__snapshots__/index.tsx.snap b/packages/components/test/__snapshots__/index.tsx.snap index 28cee6254..d066a34c2 100644 --- a/packages/components/test/__snapshots__/index.tsx.snap +++ b/packages/components/test/__snapshots__/index.tsx.snap @@ -1329,22 +1329,6 @@ exports[`Slider renders 1`] = ` `; exports[`Spinner renders 1`] = ` -@keyframes animation-0 { - from { - -webkit-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -ms-transform: rotate(0deg); - transform: rotate(0deg); - } - - to { - -webkit-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -ms-transform: rotate(360deg); - transform: rotate(360deg); - } -} - .emotion-0 { box-sizing: border-box; margin: 0; @@ -1353,21 +1337,6 @@ exports[`Spinner renders 1`] = ` overflow: visible; } -.emotion-1 { - box-sizing: border-box; - margin: 0; - min-width: 0; - transform-origin: 50% 50%; - -webkit-animation-name: animation-0; - animation-name: animation-0; - -webkit-animation-timing-function: linear; - animation-timing-function: linear; - -webkit-animation-duration: 500ms; - animation-duration: 500ms; - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; -} - - Loading... + Loading + strokeDasharray="20 110" + strokeWidth={4} + > + + `; diff --git a/packages/docs/src/pages/components/spinner.mdx b/packages/docs/src/pages/components/spinner.mdx index 01ab9fd8e..7abfacebc 100644 --- a/packages/docs/src/pages/components/spinner.mdx +++ b/packages/docs/src/pages/components/spinner.mdx @@ -19,12 +19,13 @@ import { Spinner } from 'theme-ui' | Name | Type | Description | | ------------- | ------ | ------------------------------------------------ | | `title` | String | (default `'loading'`) Text for SVG `` tag | -| `size` | Number | (default `48`) chart diameter | +| `size` | Number | (default `48`) indicator diameter | | `strokeWidth` | Number | (default `4`) stroke width | +| `duration` | Number | (default `750`) duration of animation in ms | -A `title` attribute should be provided to the component for accessibility purposes. -The element uses `role='img'` by default. -Pass any overrides or additional attributes for the SVG element as props. +A `title` attribute should be provided to the component for accessibility +purposes. The element uses `role='img'` by default. Pass any overrides or +additional attributes for the SVG element as props. ## Variants