From 637b3a0c34d2d7608c6b8f194e531adac9ebb116 Mon Sep 17 00:00:00 2001 From: Matthew Ellison Date: Tue, 24 Feb 2026 22:16:46 -0500 Subject: [PATCH] Update loading components --- .../loading/bar/CenterGrowingBars.tsx | 82 +++---- lib/component/loading/bar/CircleBars.tsx | 49 +++-- lib/component/loading/bar/FadingBars.tsx | 46 ++-- .../loading/bar/FadingGrowingBars.tsx | 70 +++--- lib/component/loading/bar/GrowingBars.tsx | 82 +++---- lib/component/loading/block/PulsingBlocks.tsx | 102 +++++---- .../loading/block/SlidingBlocks2.tsx | 46 ++-- .../loading/block/SlidingBlocks3.tsx | 58 ++--- lib/component/loading/block/WaveBlocks.tsx | 202 +++++++++--------- lib/component/loading/dot/BouncingDots.tsx | 46 ++-- .../loading/dot/CircleCenterDots.tsx | 116 +++++----- .../loading/dot/CircleFadingDots.tsx | 51 +++-- .../loading/dot/CirclePulsingDots.tsx | 123 ++++++----- .../loading/dot/CircleRotatingDots.tsx | 53 +++-- .../loading/dot/CircleShrinkingDots.tsx | 118 +++++----- .../loading/dot/CircleSpinningDot.tsx | 28 ++- lib/component/loading/dot/CyclingDots.tsx | 71 +++--- lib/component/loading/dot/FadingDots.tsx | 46 ++-- lib/component/loading/dot/PulsingDots.tsx | 39 ++-- lib/component/loading/dot/RotatingDots.tsx | 35 +-- lib/component/loading/dot/SwellingDots.tsx | 46 ++-- lib/component/loading/drop/DoubleDrop.tsx | 46 ++-- lib/component/loading/drop/DoubleWaveDrop.tsx | 54 +++-- lib/component/loading/drop/Drop.tsx | 27 ++- lib/component/loading/drop/QuickDrop.tsx | 54 +++-- lib/component/loading/drop/QuickWaveDrop.tsx | 64 +++--- lib/component/loading/drop/TripleDrop.tsx | 58 ++--- lib/component/loading/drop/TripleWaveDrop.tsx | 70 +++--- lib/component/loading/drop/WaveDrop.tsx | 29 ++- lib/component/loading/spinner/HalfSpinner.tsx | 27 ++- .../loading/spinner/QuarterSpinner.tsx | 27 ++- .../loading/spinner/RubberSpinner.tsx | 34 ++- .../loading/spinner/ThreeQuarterSpinner.tsx | 27 ++- lib/component/loading/various/BouncingDot.tsx | 36 ++-- lib/component/loading/various/PulsingLine.tsx | 35 +-- .../loading/various/SpinningBinary.tsx | 36 ++-- .../loading/various/SpinningClock.tsx | 31 ++- .../loading/various/SpinningEclipse.tsx | 25 ++- .../loading/various/SpinningEclipseHalf.tsx | 25 ++- .../loading/various/SpinningGalaxy.tsx | 25 ++- .../loading/various/SpinningTadpole.tsx | 25 ++- lib/types/LoadingTypes.ts | 15 +- lib/util/AccessibilityUtil.ts | 14 ++ 43 files changed, 1363 insertions(+), 930 deletions(-) create mode 100644 lib/util/AccessibilityUtil.ts diff --git a/lib/component/loading/bar/CenterGrowingBars.tsx b/lib/component/loading/bar/CenterGrowingBars.tsx index 526690e..b871f37 100644 --- a/lib/component/loading/bar/CenterGrowingBars.tsx +++ b/lib/component/loading/bar/CenterGrowingBars.tsx @@ -1,22 +1,32 @@ import type { LoadingBarsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function CenterGrowingBars({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingBarsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/bars-scale-middle.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -26,22 +36,22 @@ export default function CenterGrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -52,22 +62,22 @@ export default function CenterGrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -78,23 +88,23 @@ export default function CenterGrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -105,22 +115,22 @@ export default function CenterGrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -131,23 +141,23 @@ export default function CenterGrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/bar/CircleBars.tsx b/lib/component/loading/bar/CircleBars.tsx index b7ef7de..e03ac72 100644 --- a/lib/component/loading/bar/CircleBars.tsx +++ b/lib/component/loading/bar/CircleBars.tsx @@ -1,21 +1,30 @@ import type { LoadingBarsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function CircleBars({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingBarsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/bars-rotate-fade.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -27,8 +36,8 @@ export default function CircleBars({ height="5" opacity=".14" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} /> diff --git a/lib/component/loading/bar/FadingBars.tsx b/lib/component/loading/bar/FadingBars.tsx index 221bd94..3acddfa 100644 --- a/lib/component/loading/bar/FadingBars.tsx +++ b/lib/component/loading/bar/FadingBars.tsx @@ -1,22 +1,32 @@ import type { LoadingBarsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function FadingBars({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingBarsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/bars-fade.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -27,14 +37,14 @@ export default function FadingBars({ height="14" opacity="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -46,13 +56,13 @@ export default function FadingBars({ height="14" opacity=".4" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -64,14 +74,14 @@ export default function FadingBars({ height="14" opacity=".3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/bar/FadingGrowingBars.tsx b/lib/component/loading/bar/FadingGrowingBars.tsx index 7a04fce..9412cfc 100644 --- a/lib/component/loading/bar/FadingGrowingBars.tsx +++ b/lib/component/loading/bar/FadingGrowingBars.tsx @@ -1,22 +1,32 @@ import type { LoadingBarsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function FadingGrowingBars({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingBarsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/bars-scale-fade.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -27,28 +37,28 @@ export default function FadingGrowingBars({ height="14" opacity="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -60,27 +70,27 @@ export default function FadingGrowingBars({ height="14" opacity=".4" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -92,28 +102,28 @@ export default function FadingGrowingBars({ height="14" opacity=".3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/bar/GrowingBars.tsx b/lib/component/loading/bar/GrowingBars.tsx index 444c453..043db54 100644 --- a/lib/component/loading/bar/GrowingBars.tsx +++ b/lib/component/loading/bar/GrowingBars.tsx @@ -1,22 +1,32 @@ import type { LoadingBarsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function GrowingBars({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingBarsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/bars-scale.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -26,23 +36,23 @@ export default function GrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -53,22 +63,22 @@ export default function GrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -79,22 +89,22 @@ export default function GrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -105,22 +115,22 @@ export default function GrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -131,23 +141,23 @@ export default function GrowingBars({ width="2.8" height="12" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/block/PulsingBlocks.tsx b/lib/component/loading/block/PulsingBlocks.tsx index 0ae96b5..4ac1aca 100644 --- a/lib/component/loading/block/PulsingBlocks.tsx +++ b/lib/component/loading/block/PulsingBlocks.tsx @@ -1,22 +1,32 @@ import type { LoadingBlocksProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function PulsingBlocks({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingBlocksProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/blocks-scale.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -27,35 +37,35 @@ export default function PulsingBlocks({ width="9" height="9" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -67,34 +77,34 @@ export default function PulsingBlocks({ width="9" height="9" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -106,34 +116,34 @@ export default function PulsingBlocks({ width="9" height="9" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -145,35 +155,35 @@ export default function PulsingBlocks({ width="9" height="9" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/block/SlidingBlocks2.tsx b/lib/component/loading/block/SlidingBlocks2.tsx index e145829..f1bc39f 100644 --- a/lib/component/loading/block/SlidingBlocks2.tsx +++ b/lib/component/loading/block/SlidingBlocks2.tsx @@ -1,22 +1,32 @@ import type { LoadingBlocksProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function SlidingBlocks2({ + size, width, height, className, - animationDuration = 0.2, + animationDuration = 200, + color, stroke, - fill -}: LoadingBlocksProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/blocks-shuffle-2.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -27,14 +37,14 @@ export default function SlidingBlocks2({ width="10" height="10" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -42,7 +52,7 @@ export default function SlidingBlocks2({ id={`rectangle1_2_${id}`} begin={`rectangle2_1_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -50,7 +60,7 @@ export default function SlidingBlocks2({ id={`rectangle1_3_${id}`} begin={`rectangle2_2_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> @@ -58,7 +68,7 @@ export default function SlidingBlocks2({ id={`rectangle1_4_${id}`} begin={`rectangle2_3_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> @@ -70,14 +80,14 @@ export default function SlidingBlocks2({ width="10" height="10" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -85,7 +95,7 @@ export default function SlidingBlocks2({ id={`rectangle2_2_${id}`} begin={`rectangle1_2_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -93,7 +103,7 @@ export default function SlidingBlocks2({ id={`rectangle2_3_${id}`} begin={`rectangle1_3_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -101,7 +111,7 @@ export default function SlidingBlocks2({ id={`rectangle2_4_${id}`} begin={`rectangle1_4_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> diff --git a/lib/component/loading/block/SlidingBlocks3.tsx b/lib/component/loading/block/SlidingBlocks3.tsx index 81026df..02218ae 100644 --- a/lib/component/loading/block/SlidingBlocks3.tsx +++ b/lib/component/loading/block/SlidingBlocks3.tsx @@ -1,22 +1,32 @@ import type { LoadingBlocksProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function SlidingBlocks3({ + size, width, height, className, - animationDuration = 0.2, + animationDuration = 200, + color, stroke, - fill -}: LoadingBlocksProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/blocks-shuffle-3.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -27,14 +37,14 @@ export default function SlidingBlocks3({ width="10" height="10" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -42,7 +52,7 @@ export default function SlidingBlocks3({ id={`rectangle1_2_${id}`} begin={`rectangle3_1_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -50,7 +60,7 @@ export default function SlidingBlocks3({ id={`rectangle1_3_${id}`} begin={`rectangle3_2_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> @@ -58,7 +68,7 @@ export default function SlidingBlocks3({ id={`rectangle1_4_${id}`} begin={`rectangle3_3_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> @@ -70,14 +80,14 @@ export default function SlidingBlocks3({ width="10" height="10" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -85,7 +95,7 @@ export default function SlidingBlocks3({ id={`rectangle2_2_${id}`} begin={`rectangle1_2_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -93,7 +103,7 @@ export default function SlidingBlocks3({ id={`rectangle2_3_${id}`} begin={`rectangle1_3_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -101,7 +111,7 @@ export default function SlidingBlocks3({ id={`rectangle2_4_${id}`} begin={`rectangle1_4_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> @@ -113,14 +123,14 @@ export default function SlidingBlocks3({ width="10" height="10" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -128,7 +138,7 @@ export default function SlidingBlocks3({ id={`rectangle3_2_${id}`} begin={`rectangle2_2_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="13;1" fill="freeze" /> @@ -136,7 +146,7 @@ export default function SlidingBlocks3({ id={`rectangle3_3_${id}`} begin={`rectangle2_3_${id}.end`} attributeName="x" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> @@ -144,7 +154,7 @@ export default function SlidingBlocks3({ id={`rectangle3_4_${id}`} begin={`rectangle2_4_${id}.end`} attributeName="y" - dur={animationDuration} + dur={dur} values="1;13" fill="freeze" /> diff --git a/lib/component/loading/block/WaveBlocks.tsx b/lib/component/loading/block/WaveBlocks.tsx index 810e1f3..23b65d1 100644 --- a/lib/component/loading/block/WaveBlocks.tsx +++ b/lib/component/loading/block/WaveBlocks.tsx @@ -1,22 +1,32 @@ import type { LoadingBlocksProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function WaveBlocks({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingBlocksProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/blocks-wave.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -26,32 +36,32 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -61,31 +71,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -95,31 +105,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -129,31 +139,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -163,31 +173,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -197,31 +207,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -231,31 +241,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -265,31 +275,31 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -299,32 +309,32 @@ export default function WaveBlocks({ width="7.33" height="7.33" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/dot/BouncingDots.tsx b/lib/component/loading/dot/BouncingDots.tsx index 2b0dfda..4399cae 100644 --- a/lib/component/loading/dot/BouncingDots.tsx +++ b/lib/component/loading/dot/BouncingDots.tsx @@ -1,22 +1,32 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function BouncingDots({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/3-dots-bounce.svg?short_path=50864c0 - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,15 +35,15 @@ export default function BouncingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -43,15 +53,15 @@ export default function BouncingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -61,15 +71,15 @@ export default function BouncingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/dot/CircleCenterDots.tsx b/lib/component/loading/dot/CircleCenterDots.tsx index 659b691..da54d12 100644 --- a/lib/component/loading/dot/CircleCenterDots.tsx +++ b/lib/component/loading/dot/CircleCenterDots.tsx @@ -1,22 +1,32 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function CircleCenterDots({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/6-dots-scale-middle.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,15 +35,15 @@ export default function CircleCenterDots({ cy="3" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -43,15 +53,15 @@ export default function CircleCenterDots({ cy="4.21" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -61,15 +71,15 @@ export default function CircleCenterDots({ cy="4.21" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -79,15 +89,15 @@ export default function CircleCenterDots({ cy="7.50" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -97,15 +107,15 @@ export default function CircleCenterDots({ cy="7.50" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -115,14 +125,14 @@ export default function CircleCenterDots({ cy="12.00" r="0" className={className} - stroke={stroke} + stroke={color ?? stroke} > @@ -132,15 +142,15 @@ export default function CircleCenterDots({ cy="12.00" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -150,15 +160,15 @@ export default function CircleCenterDots({ cy="16.50" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -168,15 +178,15 @@ export default function CircleCenterDots({ cy="16.50" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -186,15 +196,15 @@ export default function CircleCenterDots({ cy="19.79" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -204,15 +214,15 @@ export default function CircleCenterDots({ cy="19.79" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -221,16 +231,16 @@ export default function CircleCenterDots({ cx="12" cy="21" r="0" - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} className={className} > diff --git a/lib/component/loading/dot/CircleFadingDots.tsx b/lib/component/loading/dot/CircleFadingDots.tsx index 5cea1a2..84aca7d 100644 --- a/lib/component/loading/dot/CircleFadingDots.tsx +++ b/lib/component/loading/dot/CircleFadingDots.tsx @@ -1,19 +1,30 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function CircleFadingDots({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/6-dots-rotate.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -24,8 +35,8 @@ export default function CircleFadingDots({ r="1.5" opacity=".14" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} /> diff --git a/lib/component/loading/dot/CirclePulsingDots.tsx b/lib/component/loading/dot/CirclePulsingDots.tsx index b078646..9791331 100644 --- a/lib/component/loading/dot/CirclePulsingDots.tsx +++ b/lib/component/loading/dot/CirclePulsingDots.tsx @@ -1,23 +1,34 @@ import type { CirclePulsingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function CirclePulsingDots({ + size, width, height, className, - rotationAnimationDuration = 6, - growingAnimationDuration = 0.6, + rotationAnimationDuration = 6000, + growingAnimationDuration = 600, + color, stroke, - fill -}: CirclePulsingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/12-dots-scale-rotate.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const rotationAnimationDur = reducedMotion ? rotationAnimationDuration / 100 : rotationAnimationDuration / 1000; + const growingAnimationDur = reducedMotion ? growingAnimationDuration / 100 : growingAnimationDuration / 1000; return ( @@ -27,15 +38,15 @@ export default function CirclePulsingDots({ cy="3" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -45,15 +56,15 @@ export default function CirclePulsingDots({ cy="4.21" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -63,15 +74,15 @@ export default function CirclePulsingDots({ cy="4.21" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -81,15 +92,15 @@ export default function CirclePulsingDots({ cy="7.50" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -99,15 +110,15 @@ export default function CirclePulsingDots({ cy="7.50" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -117,15 +128,15 @@ export default function CirclePulsingDots({ cy="12.00" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -135,15 +146,15 @@ export default function CirclePulsingDots({ cy="12.00" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -153,15 +164,15 @@ export default function CirclePulsingDots({ cy="16.50" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -171,15 +182,15 @@ export default function CirclePulsingDots({ cy="16.50" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -189,15 +200,15 @@ export default function CirclePulsingDots({ cy="19.79" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -207,15 +218,15 @@ export default function CirclePulsingDots({ cy="19.79" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -225,15 +236,15 @@ export default function CirclePulsingDots({ cy="21" r="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -241,7 +252,7 @@ export default function CirclePulsingDots({ diff --git a/lib/component/loading/dot/CircleRotatingDots.tsx b/lib/component/loading/dot/CircleRotatingDots.tsx index b666666..e473f02 100644 --- a/lib/component/loading/dot/CircleRotatingDots.tsx +++ b/lib/component/loading/dot/CircleRotatingDots.tsx @@ -1,21 +1,30 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function CircleRotatingDots({ + size, width, height, className, - animationDuration = 1.5, + animationDuration = 1500, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/8-dots-rotate.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,69 +34,69 @@ export default function CircleRotatingDots({ cy="12" r="2" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} /> diff --git a/lib/component/loading/dot/CircleShrinkingDots.tsx b/lib/component/loading/dot/CircleShrinkingDots.tsx index 12055f2..17ba6f6 100644 --- a/lib/component/loading/dot/CircleShrinkingDots.tsx +++ b/lib/component/loading/dot/CircleShrinkingDots.tsx @@ -1,22 +1,32 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function CircleShrinkingDots({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/6-dots-scale.svg?short_path=17d1946 - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,15 +35,15 @@ export default function CircleShrinkingDots({ cy="3" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/dot-revolve.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -30,13 +42,13 @@ export default function CircleSpinningDot({ cy="2.5" r="1.5" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/dot/CyclingDots.tsx b/lib/component/loading/dot/CyclingDots.tsx index 56eb659..f82ffe7 100644 --- a/lib/component/loading/dot/CyclingDots.tsx +++ b/lib/component/loading/dot/CyclingDots.tsx @@ -1,21 +1,32 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function CyclingDots({ + size, width, height, className, - animationDuration = 0.5, + animationDuration = 500, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/3-dots-move.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + return ( @@ -24,14 +35,14 @@ export default function CyclingDots({ cy="12" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/3-dots-fade.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -26,14 +36,14 @@ export default function FadingDots({ r="3" opacity="1" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -44,14 +54,14 @@ export default function FadingDots({ r="3" opacity=".4" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -62,14 +72,14 @@ export default function FadingDots({ r="3" opacity=".3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/dot/PulsingDots.tsx b/lib/component/loading/dot/PulsingDots.tsx index 1359c3e..ef46e66 100644 --- a/lib/component/loading/dot/PulsingDots.tsx +++ b/lib/component/loading/dot/PulsingDots.tsx @@ -1,19 +1,30 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function PulsingDots({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/3-dots-scale-middle.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -22,12 +33,12 @@ export default function PulsingDots({ cy="12" r="1.5" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -37,12 +48,12 @@ export default function PulsingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -52,12 +63,12 @@ export default function PulsingDots({ cy="12" r="1.5" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/dot/RotatingDots.tsx b/lib/component/loading/dot/RotatingDots.tsx index ce490e5..55970fd 100644 --- a/lib/component/loading/dot/RotatingDots.tsx +++ b/lib/component/loading/dot/RotatingDots.tsx @@ -1,18 +1,29 @@ import type { LoadingDotsProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function RotatingDots({ + size, width, height, className, - animationDuration = 1, + animationDuration = 1000, + color, stroke, - fill -}: LoadingDotsProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/3-dots-rotate.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -21,8 +32,8 @@ export default function RotatingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} /> ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/3-dots-scale.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,14 +35,14 @@ export default function SwellingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -41,13 +51,13 @@ export default function SwellingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -56,14 +66,14 @@ export default function SwellingDots({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/drop/DoubleDrop.tsx b/lib/component/loading/drop/DoubleDrop.tsx index 4d99c89..2e5b5ba 100644 --- a/lib/component/loading/drop/DoubleDrop.tsx +++ b/lib/component/loading/drop/DoubleDrop.tsx @@ -1,22 +1,32 @@ import type { LoadingPulseProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function DoubleDrop({ + size, width, height, className, - animationDuration = 1.2, + animationDuration = 1200, + color, stroke, - fill -}: LoadingPulseProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-2.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,24 +35,24 @@ export default function DoubleDrop({ cy="12" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-rings-2.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -24,34 +34,34 @@ export default function DoubleWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -60,34 +70,34 @@ export default function DoubleWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/drop/Drop.tsx b/lib/component/loading/drop/Drop.tsx index 88fea9f..a3f791c 100644 --- a/lib/component/loading/drop/Drop.tsx +++ b/lib/component/loading/drop/Drop.tsx @@ -1,21 +1,30 @@ import type { LoadingPulseProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function Drop({ + size, width, height, className, - animationDuration = 1.2, + animationDuration = 1200, + color, stroke, - fill -}: LoadingPulseProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -24,13 +33,13 @@ export default function Drop({ cy="12" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-multiple.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,15 +35,15 @@ export default function QuickDrop({ cy="12" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-rings-multiple.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -24,8 +34,8 @@ export default function QuickWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -43,7 +53,7 @@ export default function QuickWaveDrop({ calcMode="spline" additive="sum" type="scale" - dur={animationDuration} + dur={dur} values="0;1" keySplines=".52,.6,.25,.99" /> @@ -51,7 +61,7 @@ export default function QuickWaveDrop({ begin={`0;drop3_${id}.end`} attributeName="opacity" calcMode="spline" - dur={animationDuration} + dur={dur} values="1;0" keySplines=".52,.6,.25,.99" /> @@ -60,34 +70,34 @@ export default function QuickWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -96,34 +106,34 @@ export default function QuickWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/drop/TripleDrop.tsx b/lib/component/loading/drop/TripleDrop.tsx index 1a52b70..1b7ac14 100644 --- a/lib/component/loading/drop/TripleDrop.tsx +++ b/lib/component/loading/drop/TripleDrop.tsx @@ -1,22 +1,32 @@ import type { LoadingPulseProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function TripleDrop({ + size, width, height, className, - animationDuration = 1.2, + animationDuration = 1200, + color, stroke, - fill -}: LoadingPulseProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-3.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -25,24 +35,24 @@ export default function TripleDrop({ cy="12" r="0" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-rings-3.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -24,34 +34,34 @@ export default function TripleWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -60,34 +70,34 @@ export default function TripleWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -96,34 +106,34 @@ export default function TripleWaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/drop/WaveDrop.tsx b/lib/component/loading/drop/WaveDrop.tsx index bacb664..4065530 100644 --- a/lib/component/loading/drop/WaveDrop.tsx +++ b/lib/component/loading/drop/WaveDrop.tsx @@ -1,21 +1,30 @@ import type { LoadingPulseProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function WaveDrop({ + size, width, height, className, - animationDuration = 1.2, + animationDuration = 1200, + color, stroke, - fill -}: LoadingPulseProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/pulse-ring.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -23,14 +32,14 @@ export default function WaveDrop({ d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,20a9,9,0,1,1,9-9A9,9,0,0,1,12,21Z" transform="translate(12, 12) scale(0)" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/180-ring-with-bg.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -29,13 +40,13 @@ export default function HalfSpinner({ diff --git a/lib/component/loading/spinner/QuarterSpinner.tsx b/lib/component/loading/spinner/QuarterSpinner.tsx index be7ef5c..b2eed0a 100644 --- a/lib/component/loading/spinner/QuarterSpinner.tsx +++ b/lib/component/loading/spinner/QuarterSpinner.tsx @@ -1,22 +1,33 @@ import type { LoadingSpinnerProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function QuarterSpinner({ + size, width, height, - animationDuration = 1, + animationDuration = 1000, + color, className, stroke, fill, trackClassName = "fill-transparent", trackStroke, - trackFill -}: LoadingSpinnerProps){ + trackFill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/90-ring-with-bg.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -29,13 +40,13 @@ export default function QuarterSpinner({ diff --git a/lib/component/loading/spinner/RubberSpinner.tsx b/lib/component/loading/spinner/RubberSpinner.tsx index ea63db4..4ee336d 100644 --- a/lib/component/loading/spinner/RubberSpinner.tsx +++ b/lib/component/loading/spinner/RubberSpinner.tsx @@ -1,23 +1,35 @@ import type { RubberLoadingSpinnerProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function RubberSpinner({ + size, width, height, - animationDuration = 2, - stretchDuration = 1.5, + animationDuration = 2000, + stretchDuration = 1500, + color, className, stroke, fill = "none", trackClassName = "fill-transparent", trackStroke, - trackFill -}: RubberLoadingSpinnerProps){ + trackFill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/ring-resize.svg + const reducedMotion = usePrefersReducedMotion(); + const animationDur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + const stretchDur = reducedMotion ? stretchDuration / 100 : stretchDuration / 1000; + + return ( @@ -33,14 +45,14 @@ export default function RubberSpinner({ cy="12" r="9.5" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} strokeWidth="3" strokeLinecap="round" > diff --git a/lib/component/loading/spinner/ThreeQuarterSpinner.tsx b/lib/component/loading/spinner/ThreeQuarterSpinner.tsx index 0d8ef79..44f99d4 100644 --- a/lib/component/loading/spinner/ThreeQuarterSpinner.tsx +++ b/lib/component/loading/spinner/ThreeQuarterSpinner.tsx @@ -1,22 +1,33 @@ import type { LoadingSpinnerProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function ThreeQuarterSpinner({ + size, width, height, - animationDuration = 1, + animationDuration = 1000, + color, className, stroke, fill, trackClassName = "fill-transparent", trackStroke, - trackFill -}: LoadingSpinnerProps){ + trackFill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/270-ring-with-bg.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; + + return ( @@ -29,13 +40,13 @@ export default function ThreeQuarterSpinner({ diff --git a/lib/component/loading/various/BouncingDot.tsx b/lib/component/loading/various/BouncingDot.tsx index 5498b69..9154da1 100644 --- a/lib/component/loading/various/BouncingDot.tsx +++ b/lib/component/loading/various/BouncingDot.tsx @@ -1,22 +1,32 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; +import { useId } from "react"; export default function BouncingDot({ + size, width, height, className, - animationDuration = 0.9, + animationDuration = 900, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/bouncing-ball.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -26,15 +36,15 @@ export default function BouncingDot({ rx="4" ry="4" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > @@ -51,7 +61,7 @@ export default function BouncingDot({ begin={`dot1_1_${id}.end`} attributeName="ry" calcMode="spline" - dur={animationDuration / 18} + dur={dur / 18} values="4;3;4" keySplines=".33,0,.66,.33;.33,.66,.66,1" /> @@ -60,7 +70,7 @@ export default function BouncingDot({ begin={`dot1_1_${id}.end`} attributeName="cy" calcMode="spline" - dur={animationDuration / 36} + dur={dur / 36} values="20;20.5" keySplines=".33,0,.66,.33" /> @@ -69,7 +79,7 @@ export default function BouncingDot({ begin={`dot1_4_${id}.end`} attributeName="cy" calcMode="spline" - dur={animationDuration * 4 / 9} + dur={dur * 4 / 9} values="20.5;5" keySplines=".33,.66,.66,1" /> diff --git a/lib/component/loading/various/PulsingLine.tsx b/lib/component/loading/various/PulsingLine.tsx index dbe8247..7589e1b 100644 --- a/lib/component/loading/various/PulsingLine.tsx +++ b/lib/component/loading/various/PulsingLine.tsx @@ -1,21 +1,30 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function PulsingLine({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/gooey-balls-1.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -44,13 +53,13 @@ export default function PulsingLine({ cy="12" r="3" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > ){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/gooey-balls-2.svg - const id = crypto.randomUUID().replaceAll("-", ""); + const id = useId(); + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -49,13 +59,13 @@ export default function SpinningBinary({ cy="12" r="4" className={className} - stroke={stroke} - fill={fill} + stroke={color ?? stroke} + fill={color ?? fill} > diff --git a/lib/component/loading/various/SpinningClock.tsx b/lib/component/loading/various/SpinningClock.tsx index 6f4e935..23d18cc 100644 --- a/lib/component/loading/various/SpinningClock.tsx +++ b/lib/component/loading/various/SpinningClock.tsx @@ -1,29 +1,38 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function SpinningClock({ + size, width, height, className, - animationDuration = 9, + animationDuration = 9000, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/clock.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( @@ -54,7 +63,7 @@ export default function SpinningClock({ diff --git a/lib/component/loading/various/SpinningEclipse.tsx b/lib/component/loading/various/SpinningEclipse.tsx index c7991b3..594847c 100644 --- a/lib/component/loading/various/SpinningEclipse.tsx +++ b/lib/component/loading/various/SpinningEclipse.tsx @@ -1,34 +1,43 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function SpinningEclipse({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/eclipse.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( diff --git a/lib/component/loading/various/SpinningEclipseHalf.tsx b/lib/component/loading/various/SpinningEclipseHalf.tsx index b7ea53f..24a7716 100644 --- a/lib/component/loading/various/SpinningEclipseHalf.tsx +++ b/lib/component/loading/various/SpinningEclipseHalf.tsx @@ -1,34 +1,43 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function SpinningEclipseHalf({ + size, width, height, className, - animationDuration = 0.6, + animationDuration = 600, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/eclipse-half.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( diff --git a/lib/component/loading/various/SpinningGalaxy.tsx b/lib/component/loading/various/SpinningGalaxy.tsx index ac6a48c..e41498a 100644 --- a/lib/component/loading/various/SpinningGalaxy.tsx +++ b/lib/component/loading/various/SpinningGalaxy.tsx @@ -1,34 +1,43 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function SpinningGalaxy({ + size, width, height, className, - animationDuration = 1.5, + animationDuration = 1500, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/wind-toy.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( diff --git a/lib/component/loading/various/SpinningTadpole.tsx b/lib/component/loading/various/SpinningTadpole.tsx index 9cdd4e6..04b6dc9 100644 --- a/lib/component/loading/various/SpinningTadpole.tsx +++ b/lib/component/loading/various/SpinningTadpole.tsx @@ -1,34 +1,43 @@ import type { LoadingVariousProps } from "$/types/LoadingTypes"; +import { usePrefersReducedMotion } from "$/util/AccessibilityUtil"; export default function SpinningTadpole({ + size, width, height, className, - animationDuration = 0.75, + animationDuration = 750, + color, stroke, - fill -}: LoadingVariousProps){ + fill, + ariaLabel = "Loading" +}: Readonly){ //https://github.com/n3r4zzurr0/svg-spinners/blob/main/svg-smil/tadpole.svg + const reducedMotion = usePrefersReducedMotion(); + const dur = reducedMotion ? animationDuration / 100 : animationDuration / 1000; return ( diff --git a/lib/types/LoadingTypes.ts b/lib/types/LoadingTypes.ts index cbff29d..4b5eaad 100644 --- a/lib/types/LoadingTypes.ts +++ b/lib/types/LoadingTypes.ts @@ -1,11 +1,15 @@ /* eslint-disable @typescript-eslint/no-empty-object-type */ interface LoadingDefaultProps { - width?: string | number; - height?: string | number; + size?: number; + width?: number; + height?: number; className?: string; animationDuration?: number; + color?: string; stroke?: string; fill?: string; + + ariaLabel?: string; } @@ -26,13 +30,16 @@ export interface LoadingDotsProps extends LoadingDefaultProps { } export interface CirclePulsingDotsProps { - width?: string | number; - height?: string | number; + size?: number; + width?: number; + height?: number; className?: string; rotationAnimationDuration?: number; growingAnimationDuration?: number; + color?: string; stroke?: string; fill?: string; + ariaLabel?: string; } export interface CircleSpinningDotProps extends LoadingDefaultProps { diff --git a/lib/util/AccessibilityUtil.ts b/lib/util/AccessibilityUtil.ts new file mode 100644 index 0000000..758e726 --- /dev/null +++ b/lib/util/AccessibilityUtil.ts @@ -0,0 +1,14 @@ +import { useEffect, useState } from "react"; + + +export function usePrefersReducedMotion(){ + const [ reduced, setReduced ] = useState(false); + + useEffect(() => { + const media = globalThis.matchMedia("(prefers-reduced-motion: reduce)"); + // eslint-disable-next-line react-hooks/set-state-in-effect + setReduced(media.matches); + }, [ ]); + + return reduced; +}