diff --git a/example/src/pages/Loaders.tsx b/example/src/pages/Loaders.tsx new file mode 100644 index 00000000..2b53d12b --- /dev/null +++ b/example/src/pages/Loaders.tsx @@ -0,0 +1,17 @@ +import { IOColors, LoadingSpinner } from "@pagopa/io-app-design-system"; +import React from "react"; +import { View } from "react-native"; +import { Screen } from "../components/Screen"; + +export const Loaders = () => ( + + + + + + + + + + +); diff --git a/src/components/index.tsx b/src/components/index.tsx index 7862aa35..267c2c81 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -10,6 +10,7 @@ export * from "./featureInfo"; export * from "./icons"; export * from "./listitems"; export * from "./logos"; +export * from "./loadingSpinner"; export * from "./modules"; export * from "./banner"; export * from "./pictograms"; diff --git a/src/components/loadingSpinner/LoadingSpinner.tsx b/src/components/loadingSpinner/LoadingSpinner.tsx new file mode 100644 index 00000000..21b2a19a --- /dev/null +++ b/src/components/loadingSpinner/LoadingSpinner.tsx @@ -0,0 +1,121 @@ +import React, { useEffect, useRef } from "react"; +import { View, Animated, Easing } from "react-native"; +import Svg, { Defs, G, LinearGradient, Path, Stop } from "react-native-svg"; +import { WithTestID } from "../../utils/types"; +import { IOColors } from "../../core"; + +type Props = WithTestID<{ + color?: IOColors; + stroke?: number; + size?: IOLoadingSpinnerSizeScale; + durationMs?: number; +}>; + +/** + * Size scale, 76 is kept for backward compatibility with the old design system but 48 is enough for the new one. + * It will be removed in the future. + */ +export type IOLoadingSpinnerSizeScale = 24 | 48 | 76; + +const startRotationAnimation = ( + durationMs: number, + rotationDegree: Animated.Value +): void => { + Animated.loop( + Animated.timing(rotationDegree, { + toValue: 360, + duration: durationMs, + easing: Easing.linear, + useNativeDriver: true + }) + ).start(); +}; + +export const LoadingSpinner = ({ + color = "blueIO-500", + stroke = 3, + size = 24, + durationMs = 750 +}: Props): React.ReactElement => { + const rotationDegree = useRef(new Animated.Value(0)).current; + + useEffect(() => { + startRotationAnimation(durationMs, rotationDegree); + }, [durationMs, rotationDegree]); + + return ( + <> + + + {/* Thanks to Ben Ilegbodu for the article on how to + create a a SVG gradient loading spinner. Below is + a parameterized version of his version of his code. + Source: https://www.benmvp.com/blog/how-to-create-circle-svg-gradient-loading-spinner/ */} + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/src/components/loadingSpinner/index.tsx b/src/components/loadingSpinner/index.tsx new file mode 100644 index 00000000..ba09efca --- /dev/null +++ b/src/components/loadingSpinner/index.tsx @@ -0,0 +1 @@ +export * from "./LoadingSpinner";