modules_Loaders_RingLoader_index.js

import { classnames, PropTypes, React } from '@gravityforms/libraries';
import Loader from '../Loader';
import { spacerClasses } from '@gravityforms/utils';

const { forwardRef } = React;

/**
 * @module RingLoader
 * @description A svg based ring spinner loader component.
 *
 * @since 1.1.15
 *
 * @param {object}                     props                        Component props.
 * @param {object}                     props.customAttributes       Custom attributes for the component.
 * @param {string|Array|object}        props.customClasses          Custom classes for the component.
 * @param {string}                     props.foreground             Color for the loader foreground element.
 * @param {number}                     props.lineWeight             Line weight for the svg stroke of this loader.
 * @param {object}                     props.loaderCustomAttributes Custom attributes for the base loader component.
 * @param {number}                     props.size                   Size in pixels for the loader.
 * @param {string|number|Array|object} props.spacing                The spacing for the component, as a string, number, array, or object.
 * @param {number}                     props.speed                  Speed in seconds for the animation of this component.
 * @param {object|null}                ref                          Ref to the component.
 *
 * @return {JSX.Element} A ring spinner loader component with elastic animation.
 *
 * @example
 * import RingLoader from '@gravityforms/components/react/admin/modules/Loaders/RingLoader';
 *
 * return <RingLoader foreground="#242748" lineWeight={ 4 } size={ 40 } />;
 *
 */
const RingLoader = forwardRef( ( {
	customAttributes = {},
	customClasses = [],
	foreground = '',
	lineWeight = 2,
	loaderCustomAttributes = {},
	size = 40,
	spacing = '',
	speed = 2,
}, ref ) => {
	const componentProps = {
		className: classnames( {
			'gform-loader': true,
			'gform-loader--ring': true,
			...spacerClasses( spacing ),
		}, customClasses ),
		height: size,
		width: size,
		viewBox: '25 25 50 50',
		style: {
			animation: `gformLoaderRotate ${ speed }s linear infinite`,
			height: `${ size }px`,
			width: `${ size }px`,
		},
		...customAttributes,
	};
	const strokeWidth = lineWeight * 50 / size;
	const circleStyle = {
		animation: `animation: gformLoaderStretch calc(${ speed }s * 0.75) ease-in-out infinite`,
	};
	if ( foreground ) {
		circleStyle.stroke = foreground;
	}

	const loaderProps = {
		...loaderCustomAttributes,
		loader: (
			<svg
				{ ...componentProps }
				ref={ ref }
			>
				<circle
					cx="50"
					cy="50"
					r="20"
					strokeWidth={ strokeWidth }
					style={ circleStyle }
				/>
			</svg>
		),
	};

	return <Loader { ...loaderProps } />;
} );

RingLoader.propTypes = {
	customAttributes: PropTypes.object,
	customClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	foreground: PropTypes.string,
	lineWeight: PropTypes.number,
	loaderCustomAttributes: PropTypes.object,
	size: PropTypes.number,
	spacing: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.number,
		PropTypes.array,
		PropTypes.object,
	] ),
	speed: PropTypes.number,
};

RingLoader.displayName = 'Loaders/RingLoader';

export default RingLoader;