respinner
Version:
React SVG spinner components
313 lines (302 loc) • 11.4 kB
JavaScript
import React, { useId } from 'react';
const BeatLoading = ({ duration = 0.8, count = 6, size = 8, gap = 6, color, fill, ...rest })=>{
const viewWidth = (size + gap) * count - gap;
const fillColor = color || fill;
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: viewWidth,
height: size
}, Array.from({
length: count
}).map((_, i)=>{
const cx = size * (i + 1) + gap * i - size / 2;
const cy = size / 2;
return(// @ts-expect-error transformOrigin is not a valid prop for svg <circle>
/*#__PURE__*/ React.createElement("circle", {
transformOrigin: `${cx}px ${cy}px`,
key: `c-${i}`,
fill: fillColor,
r: size / 2,
cx: cx,
cy: cy
}, /*#__PURE__*/ React.createElement("animateTransform", {
attributeName: "transform",
attributeType: "XML",
type: "scale",
values: "0; 0; 1; 0; 0",
begin: `${-duration / (count + 1) * (count - i)}s`,
dur: `${duration}s`,
repeatCount: "indefinite"
})));
}));
};
const BounceLoading = ({ gap = 6, count = 4, barWidth = 4, barHeight = 16, duration = 0.8, color, fill, ...rest })=>{
const viewWidth = (barWidth + gap) * count - gap;
const fillColor = color || fill;
return /*#__PURE__*/ React.createElement("svg", {
width: viewWidth,
height: barHeight * 3,
...rest
}, Array.from({
length: count
}).map((_, i)=>{
return /*#__PURE__*/ React.createElement("rect", {
key: `rect-${i}`,
fill: fillColor,
height: barHeight,
width: barWidth,
x: (barWidth + gap) * i,
y: barHeight
}, /*#__PURE__*/ React.createElement("animateTransform", {
attributeName: "transform",
type: "translate",
values: "0 0; 0 8; 0 -8; 0 0",
keyTimes: "0; 0.25; 0.75; 1",
dur: `${duration}s`,
begin: `${-duration / (count + 1) * (count - i)}s`,
repeatCount: "indefinite"
}));
}));
};
// View box is based on 50x50 size
// from: https://codepen.io/jczimm/pen/vEBpoL
const CIRCLE_RADIUS = 50 / 2;
const CircularLoading = ({ size = 40, strokeWidth = 5, linecap = 'round', duration = 1, color, stroke, ...rest })=>{
const center = CIRCLE_RADIUS;
const strokeColor = color || stroke;
return /*#__PURE__*/ React.createElement("svg", {
...rest,
viewBox: `0 0 ${CIRCLE_RADIUS * 2} ${CIRCLE_RADIUS * 2}`,
width: size,
height: size
}, /*#__PURE__*/ React.createElement("circle", {
fill: "none",
stroke: strokeColor,
strokeWidth: strokeWidth,
strokeLinecap: linecap,
cx: CIRCLE_RADIUS,
cy: CIRCLE_RADIUS,
r: CIRCLE_RADIUS - strokeWidth
}, /*#__PURE__*/ React.createElement("animateTransform", {
attributeName: "transform",
attributeType: "XML",
type: "rotate",
from: `0 ${center} ${center}`,
to: `360 ${center} ${center}`,
dur: `${duration * 4 / 3}s`,
repeatCount: "indefinite"
}), /*#__PURE__*/ React.createElement("animate", {
attributeName: "stroke-dasharray",
values: "1,200; 89,200; 89 200;",
dur: `${duration}s`,
repeatCount: "indefinite"
}), /*#__PURE__*/ React.createElement("animate", {
attributeName: "stroke-dashoffset",
values: "0;-35;-124;",
dur: `${duration}s`,
repeatCount: "indefinite"
})));
};
const ClockLoading = ({ size = 40, duration = 2, strokeWidth = 2, color, stroke, ...rest })=>{
const center = size / 2;
const strokeColor = color || stroke;
const needleProps = {
strokeWidth: strokeWidth,
stroke: strokeColor,
strokeLinecap: 'round',
x1: center,
y1: strokeWidth * 2,
x2: center,
y2: size - strokeWidth * 2
};
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: size,
height: size,
viewBox: `0 0 ${size} ${size}`
}, /*#__PURE__*/ React.createElement("circle", {
fill: "none",
stroke: strokeColor,
strokeWidth: strokeWidth,
cx: center,
cy: center,
r: size / 2 - strokeWidth
}), /*#__PURE__*/ React.createElement("line", {
...needleProps,
strokeDasharray: `${size / 3} ${size / 2}`,
strokeDashoffset: size / 3 + strokeWidth * 2
}, /*#__PURE__*/ React.createElement("animateTransform", {
attributeName: "transform",
attributeType: "XML",
type: "rotate",
from: `0 ${center} ${center}`,
to: `360 ${center} ${center}`,
dur: `${duration}s`,
repeatCount: "indefinite"
})));
};
const RotateLoading = ({ size = 40, opacity = 0.2, strokeWidth = 4, duration = 1.6, color, stroke, ...rest })=>{
const radius = size / 2 - strokeWidth;
const center = radius + strokeWidth;
const strokeColor = color || stroke;
const circleProps = {
strokeWidth,
stroke: strokeColor,
r: radius,
cx: radius + strokeWidth,
cy: radius + strokeWidth,
fill: 'none'
};
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: size,
height: size
}, /*#__PURE__*/ React.createElement("circle", {
...circleProps,
style: {
opacity
}
}), /*#__PURE__*/ React.createElement("circle", {
...circleProps,
strokeDasharray: "20 180"
}, /*#__PURE__*/ React.createElement("animateTransform", {
attributeName: "transform",
attributeType: "XML",
type: "rotate",
from: `0 ${center} ${center}`,
to: `360 ${center} ${center}`,
dur: `${duration}s`,
repeatCount: "indefinite"
})));
};
const SpinLoading = ({ size = 40, count = 8, barWidth = 4, barHeight = 10, duration = 1, borderRadius = 1, color, fill, ...rest })=>{
const radius = size / 2 - barHeight / 2;
const fillColor = color || fill;
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: size,
height: size
}, Array.from({
length: count
}).map((_, i)=>{
const angle = 360 / count * i;
/* (barWidth + borderRadius) / 2 is used to fix the excursion caused by thickness */ const x = Math.cos(Math.PI * angle / 180) * radius + radius + (barWidth + borderRadius) / 2;
const y = Math.sin(Math.PI * angle / 180) * radius + radius;
return /*#__PURE__*/ React.createElement("rect", {
x: x,
y: y,
fill: fillColor,
key: `r-${i}`,
width: barWidth,
height: barHeight,
rx: borderRadius,
ry: borderRadius,
transform: `rotate(${90 + angle} ${x + barWidth / 2} ${y + barHeight / 2})`
}, /*#__PURE__*/ React.createElement("animate", {
attributeName: "opacity",
values: "0; 0.3; 1",
begin: `${duration * 0.8 / count * i}s`,
dur: `${duration}s`,
repeatCount: "indefinite"
}));
}));
};
const WaveLoading = ({ size = 40, count = 3, duration = 1.5, strokeWidth = 2, color, stroke, ...rest })=>{
const radius = size / 2 - strokeWidth;
const strokeColor = color || stroke;
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: size,
height: size
}, Array.from({
length: count
}).map((_, i)=>{
const pos = size / 2;
return /*#__PURE__*/ React.createElement("circle", {
key: `c-${i}`,
stroke: strokeColor,
strokeWidth: strokeWidth,
// @ts-expect-error transformOrigin is not a valid prop for svg <circle>
transformOrigin: `${pos}px ${pos}px`,
fill: "none",
r: radius,
cx: pos,
cy: pos
}, /*#__PURE__*/ React.createElement("animate", {
attributeName: "opacity",
values: "1; 0.7; 0",
keyTimes: "0; 0.7; 1",
dur: `${duration}s`,
begin: `${duration / count * i}s`
}), /*#__PURE__*/ React.createElement("animateTransform", {
attributeName: "transform",
attributeType: "XML",
type: "scale",
values: ".1; 1; 1",
keyTimes: "0; 0.7; 1",
dur: `${duration}s`,
begin: `${duration / count * i}s`,
repeatCount: "indefinite"
}));
}));
};
const DashedRotateAnimation = (uniqId, dash)=>`@keyframes DashedRotate${uniqId}` + '{' + `0% {stroke-dasharray:${dash} ${dash} 1 ${dash};transform:rotate(0deg);}` + `50% {stroke-dasharray:${dash};transform:rotate(360deg);}` + `100% {stroke-dasharray:${dash} ${dash} 1 ${dash};transform:rotate(720deg);}` + '}';
const DashLoading = ({ size = 40, strokeWidth = 4, duration = 1.8, color, stroke, ...rest })=>{
const radius = size / 2 - strokeWidth;
const dash = Math.PI * radius / 5;
const uniqId = useId();
const strokeColor = color || stroke;
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: size,
height: size
}, /*#__PURE__*/ React.createElement("style", null, DashedRotateAnimation(uniqId, dash)), /*#__PURE__*/ React.createElement("circle", {
fill: "none",
stroke: strokeColor,
strokeLinecap: "round",
strokeWidth: strokeWidth,
cx: size / 2,
cy: size / 2,
r: radius,
style: {
transformOrigin: 'center',
animationName: `DashedRotate${uniqId}`,
animationDuration: `${duration}s`,
animationIterationCount: 'infinite'
}
}));
};
const createTransRotate = (uniqId)=>`@keyframes TransRotate${uniqId}` + '{' + '0% {transform:rotate(45deg) scale(1);}' + '50% {transform:rotate(405deg) scale(.2);}' + '100% {transform:rotate(765deg) scale(1);}';
const CopperLoading = ({ size = 40, strokeWidth = 4, duration = 2, color, stroke, fill, ...rest })=>{
const uniqId = useId();
const fillColor = color || fill;
const strokeColor = color || stroke || fill;
const commonStyle = {
transformOrigin: 'center',
animation: `TransRotate${uniqId} ${duration}s infinite`
};
return /*#__PURE__*/ React.createElement("svg", {
...rest,
width: size,
height: size
}, /*#__PURE__*/ React.createElement("style", null, createTransRotate(uniqId)), /*#__PURE__*/ React.createElement("rect", {
width: size / 3,
height: size / 3,
x: size / 3,
y: size / 3,
fill: fillColor,
style: commonStyle
}), /*#__PURE__*/ React.createElement("circle", {
cx: size / 2,
cy: size / 2,
r: size / 2 - strokeWidth,
fill: "transparent",
stroke: strokeColor,
strokeWidth: strokeWidth,
style: {
...commonStyle,
animationDelay: `${duration / 2}s`
}
}));
};
export { BeatLoading, BounceLoading, CircularLoading, ClockLoading, CopperLoading, DashLoading, RotateLoading, SpinLoading, WaveLoading };