import React, { forwardRef, InputHTMLAttributes, ReactNode, useRef, useImperativeHandle, useMemo } from 'react'; import { useMergedState } from 'rc-util'; import { type TStyle, useClassnames } from '../../../hooks/use-classnames'; import { IconArrowsRefreshCcw } from '../../icons/arrows/refresh-ccw'; import style from './index.module.pcss'; type TNative = InputHTMLAttributes; export interface IProps { /** * Название поля ввода, которое будет отправлено на сервер вместе со значением. **/ readonly name: string, /** * Позволяет добавить пользовательские CSS-классы **/ readonly className?: string | TStyle, /** * Текст метки, связанной с переключателем. **/ readonly label?: ReactNode, /** * Значение, которое будет отправлено на сервер при отправке формы. **/ readonly value?: boolean, /** * Значение переключателя по умолчанию. **/ readonly defaultValue?: boolean, /** * Устанавливает или определяет, должен ли компонент быть отмечен. **/ readonly checked?: TNative['checked'], /** * Определяет, должен ли флажок быть установлен при первоначальной загрузке компонента. **/ readonly defaultChecked?: TNative['defaultChecked'], /** * Функция обратного вызова, которая будет вызываться при изменении значения переключателя. **/ readonly onChange?: (newChecked: boolean, event: React.MouseEvent | React.KeyboardEvent) => void, /** * Функция обратного вызова, которая будет вызываться при клике на переключатель. **/ readonly onClick?: (newChecked: boolean, event: React.MouseEvent | React.KeyboardEvent) => void, /** * Функция обратного вызова, которая будет вызываться при потере фокуса на переключателе. **/ readonly onKeyDown?: ( event: React.KeyboardEvent) => void, /** * Функция обратного вызова, которая будет вызываться при нажатии на клавиши клавиатуры. **/ readonly onBlur?: TNative['onBlur'], /** * Функция обратного вызова, которая будет вызываться при получении фокуса на переключателе. **/ readonly onFocus?: TNative['onFocus'], /** * Указывает, должен ли компонент получать фокус при монтировании (отрисовке) на странице. **/ readonly autoFocus?: TNative['autoFocus'], /** * Уникальный идентификатор переключателя. **/ readonly id?: TNative['id'], /** * Порядковый номер элемента при переключении по `Tab`. **/ readonly tabIndex?: TNative['tabIndex'], /** * Определяет, будет ли компонент отключен. **/ readonly disabled?: TNative['disabled'], /** * Размер элемента. **/ readonly size?: 'sm' | 'md' | 'lg', /** * Дизейблит компонент и отображает анимацию загрузки. **/ readonly loading?: boolean } /** * Компонент `Switch` представляет собой переключатель, который позволяет пользователю выбирать один или несколько вариантов из группы. **/ export const Switch = forwardRef(({ tabIndex = 0, size = 'md', ...props }, ref) => { const cn = useClassnames(style, props.className); const [innerChecked, setInnerChecked] = useMergedState(false, { value : props.checked, defaultValue: props.defaultChecked }); const switchRef = useRef(null); useImperativeHandle(ref, () => switchRef.current); const isDisabled = props.disabled ?? props.loading; const triggerChange = ( newChecked: boolean, event: React.MouseEvent | React.KeyboardEvent ) => { let mergedChecked = innerChecked; if(!props.disabled) { mergedChecked = newChecked; setInnerChecked(mergedChecked); props.onChange?.(mergedChecked, event); } return mergedChecked; }; const onInternalKeyDown = (event: React.KeyboardEvent) => { if(event.key === 'ArrowRight') { triggerChange(true, event); } else if(event.key === 'ArrowLeft') { triggerChange(false, event); } props.onKeyDown?.(event); }; const onInternalClick = (event: React.MouseEvent) => { const checkedValue = triggerChange(!innerChecked, event); props.onClick?.(checkedValue, event); }; const onMouseLeaveCallback = () => { switchRef.current?.blur(); }; const elLoading = useMemo(() => { if(props.loading) { return ( ); } }, [props.loading]); return ( ); });