TelegramPWA/src/components/ui/ProgressSpinner.tsx
2022-05-30 15:40:11 +04:00

85 lines
2.2 KiB
TypeScript

import type { FC } from '../../lib/teact/teact';
import React, { useEffect, useRef, memo } from '../../lib/teact/teact';
import buildClassName from '../../util/buildClassName';
import './ProgressSpinner.scss';
const RADIUSES = {
s: 22, m: 25, l: 28, xl: 20,
};
const STROKE_WIDTH = 2;
const MIN_PROGRESS = 0.05;
const MAX_PROGRESS = 1;
const ProgressSpinner: FC<{
progress?: number;
size?: 's' | 'm' | 'l' | 'xl';
square?: boolean;
transparent?: boolean;
noCross?: boolean;
onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
}> = ({
progress = 0,
size = 'l',
square,
transparent,
noCross,
onClick,
}) => {
const radius = RADIUSES[size];
const circleRadius = radius - STROKE_WIDTH * 2;
const borderRadius = radius - 1;
const circumference = circleRadius * 2 * Math.PI;
// eslint-disable-next-line no-null/no-null
const container = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!container.current) {
return;
}
const svg = container.current.firstElementChild;
const strokeDashOffset = circumference - Math.min(Math.max(MIN_PROGRESS, progress), MAX_PROGRESS) * circumference;
if (!svg) {
container.current.innerHTML = `<svg
viewBox="0 0 ${borderRadius * 2} ${borderRadius * 2}"
height="${borderRadius * 2}"
width="${borderRadius * 2}"
>
<circle
stroke="white"
fill="transparent"
stroke-width=${STROKE_WIDTH}
stroke-dasharray="${circumference} ${circumference}"}
stroke-dashoffset="${strokeDashOffset}"
stroke-linecap="round"
r=${circleRadius}
cx=${borderRadius}
cy=${borderRadius}
/>
</svg>`;
} else {
(svg.firstElementChild as SVGElement).setAttribute('stroke-dashoffset', strokeDashOffset.toString());
}
}, [container, circumference, borderRadius, circleRadius, progress]);
const className = buildClassName(
`ProgressSpinner size-${size}`,
transparent && 'transparent',
square && 'square',
noCross && 'no-cross',
);
return (
<div
ref={container}
className={className}
onClick={onClick}
/>
);
};
export default memo(ProgressSpinner);