35 lines
1.2 KiB
TypeScript
35 lines
1.2 KiB
TypeScript
import styles from './Spinner.module.css'
|
||
|
||
type SpinnerSize = 'sm' | 'md' | 'lg'
|
||
|
||
interface Props {
|
||
/** Размер спиннера. По умолчанию `md`. */
|
||
size?: SpinnerSize
|
||
/** Подпись под спиннером. */
|
||
label?: string
|
||
/** Растянуть на всю высоту контейнера и отцентрировать содержимое. */
|
||
fullscreen?: boolean
|
||
/** Зафиксировать поверх всего экрана с подложкой (для загрузки на весь вьюпорт). */
|
||
overlay?: boolean
|
||
className?: string
|
||
}
|
||
|
||
export function Spinner({ size = 'md', label, fullscreen, overlay, className }: Props) {
|
||
const wrapClass = [
|
||
styles.wrap,
|
||
fullscreen ? styles.fullscreen : '',
|
||
overlay ? styles.overlay : '',
|
||
className ?? '',
|
||
]
|
||
.filter(Boolean)
|
||
.join(' ')
|
||
|
||
return (
|
||
<div className={wrapClass} role="status" aria-live="polite" aria-busy="true">
|
||
<span className={`${styles.spinner} ${styles[size]}`} aria-hidden="true" />
|
||
{label ? <span className={styles.label}>{label}</span> : null}
|
||
<span className={styles.srOnly}>{label ?? 'Загрузка'}</span>
|
||
</div>
|
||
)
|
||
}
|