@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
82 lines • 3.92 kB
JavaScript
import { Shade, createComponent } from '@furystack/shades';
import { cssVariableTheme } from '../services/css-variable-theme.js';
import { ThemeProviderService } from '../services/theme-provider-service.js';
const SVG_SIZE = 44;
const DEFAULT_SIZE = 40;
const DEFAULT_THICKNESS = 3.6;
const clampValue = (v) => Math.max(0, Math.min(100, v));
export const CircularProgress = Shade({
customElementName: 'shade-circular-progress',
css: {
display: 'inline-flex',
fontFamily: cssVariableTheme.typography.fontFamily,
alignItems: 'center',
justifyContent: 'center',
lineHeight: '1',
'& svg': {
display: 'block',
},
'& .progress-track': {
stroke: 'color-mix(in srgb, var(--circular-progress-color) 20%, transparent)',
fill: 'none',
},
'& .progress-circle': {
stroke: 'var(--circular-progress-color)',
fill: 'none',
strokeLinecap: 'round',
transition: `stroke-dashoffset ${cssVariableTheme.transitions.duration.normal} ${cssVariableTheme.transitions.easing.easeInOut}`,
},
},
render: ({ props, injector, useHostProps }) => {
const themeProvider = injector.get(ThemeProviderService);
const variant = props.variant || 'indeterminate';
const value = clampValue(props.value ?? 0);
const size = props.size ?? DEFAULT_SIZE;
const thickness = props.thickness ?? DEFAULT_THICKNESS;
const indeterminate = variant === 'indeterminate';
const radius = (SVG_SIZE - thickness) / 2;
const circumference = 2 * Math.PI * radius;
const color = themeProvider.theme.palette[props.color || 'primary'].main;
useHostProps({
role: 'progressbar',
...(variant === 'determinate'
? {
'aria-valuenow': String(value),
'aria-valuemin': '0',
'aria-valuemax': '100',
}
: {
'aria-valuenow': undefined,
}),
style: { '--circular-progress-color': color },
});
const dashOffset = variant === 'determinate' ? circumference - (value / 100) * circumference : 0;
const center = SVG_SIZE / 2;
return (createComponent("svg", { width: size, height: size, viewBox: `0 0 ${SVG_SIZE} ${SVG_SIZE}`, style: indeterminate ? { animation: 'circular-rotate 1.4s linear infinite' } : undefined },
indeterminate && (createComponent("style", null, `
@keyframes circular-rotate {
100% { transform: rotate(360deg); }
}
@keyframes circular-dash {
0% {
stroke-dasharray: ${circumference * 0.05} ${circumference};
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: ${circumference * 0.7} ${circumference};
stroke-dashoffset: ${-circumference * 0.12};
}
100% {
stroke-dasharray: ${circumference * 0.7} ${circumference};
stroke-dashoffset: ${-circumference * 0.88};
}
}
`)),
createComponent("circle", { className: "progress-track", cx: center, cy: center, r: radius, "stroke-width": thickness }),
createComponent("circle", { className: "progress-circle", cx: center, cy: center, r: radius, "stroke-width": thickness, "stroke-dasharray": indeterminate ? `${circumference * 0.05} ${circumference}` : `${circumference}`, style: {
strokeDashoffset: `${dashOffset}`,
...(indeterminate ? { animation: 'circular-dash 1.4s ease-in-out infinite' } : {}),
}, transform: `rotate(-90 ${SVG_SIZE / 2} ${SVG_SIZE / 2})` })));
},
});
//# sourceMappingURL=circular-progress.js.map