'use client'; import * as React from 'react'; import { Icon20CheckBoxIndetermanate, Icon20CheckBoxOff, Icon20CheckBoxOn, Icon24CheckBoxOff, Icon24CheckBoxOn, } from '@vkontakte/icons'; import { classNames } from '@vkontakte/vkjs'; import { useAdaptivityConditionalRender } from '../../../hooks/useAdaptivityConditionalRender'; import { useExternRef } from '../../../hooks/useExternRef'; import { useMergeProps } from '../../../hooks/useMergeProps'; import { usePlatform } from '../../../hooks/usePlatform'; import { warnOnce } from '../../../lib/warnOnce'; import type { HasDataAttribute, HasRootRef } from '../../../types'; import { RootComponent } from '../../RootComponent/RootComponent'; import { VisuallyHidden } from '../../VisuallyHidden/VisuallyHidden'; import styles from './CheckboxInput.module.css'; type VendorIconType = typeof Icon20CheckBoxOn; export type CheckboxInputIconType = | React.ComponentType> | VendorIconType; function setIndeterminate(el: HTMLInputElement, indeterminate: boolean) { el.indeterminate = indeterminate; } export interface CheckboxInputProps extends Pick< React.ComponentProps<'input'>, | 'checked' | 'defaultChecked' | 'disabled' | 'readOnly' | 'required' | 'autoFocus' | 'onChange' | 'name' | 'value' | 'onFocus' | 'onBlur' >, Omit, 'onChange' | 'onFocus' | 'onBlur'>, HasRootRef { /** * @deprecated Since 7.9.0. Вместо этого используйте `slotProps={ input: { getRootRef: ... } }`. */ getRef?: React.Ref | undefined; /** * Свойства, которые можно прокинуть внутрь компонента: * - `root`: свойства для прокидывания в корень компонента; * - `input`: свойства для прокидывания в скрытый `input`. */ slotProps?: | { root?: | (Omit, 'children'> & HasRootRef & HasDataAttribute) | undefined; input?: | (React.ComponentProps<'input'> & HasRootRef & HasDataAttribute) | undefined; } | undefined; /** * Неопределенное состояние чекбокса. */ indeterminate?: boolean | undefined; /** * Неопределенное состояние чекбокса по умолчанию. */ defaultIndeterminate?: boolean | undefined; /** * Иконка для включенного состояния в компактном режиме. */ IconOnCompact?: CheckboxInputIconType | undefined; /** * Иконка для включенного состояния в обычном режиме. */ IconOnRegular?: CheckboxInputIconType | undefined; /** * Иконка для выключенного состояния в компактном режиме. */ IconOffCompact?: CheckboxInputIconType | undefined; /** * Иконка для выключенного состояния в обычном режиме. */ IconOffRegular?: CheckboxInputIconType | undefined; /** * Иконка для неопределенного состояния. */ IconIndeterminate?: CheckboxInputIconType | undefined; } const warn = warnOnce('Checkbox'); export function CheckboxInput({ getRef, // Input props checked, defaultChecked, disabled, readOnly, required, autoFocus, id, name, value, onChange: onChangeProp, onFocus, onBlur, // CheckboxInputProps indeterminate, defaultIndeterminate, IconOnCompact = Icon20CheckBoxOn, IconOnRegular = Icon24CheckBoxOn, IconOffCompact = Icon20CheckBoxOff, IconOffRegular = Icon24CheckBoxOff, IconIndeterminate = Icon20CheckBoxIndetermanate, slotProps, ...restProps }: CheckboxInputProps) { const rootRest = useMergeProps(restProps, slotProps?.root); const { onChange, getRootRef: getInputRef, className: inputClassName, ...inputRest } = useMergeProps( { getRootRef: getRef, checked, defaultChecked, disabled, readOnly, required, autoFocus, id, name, value, onChange: onChangeProp, onFocus, onBlur, }, slotProps?.input, ); const inputRef = useExternRef(getInputRef); const platform = usePlatform(); const { density: adaptiveDensity } = useAdaptivityConditionalRender(); React.useEffect(() => { const indeterminateValue = indeterminate === undefined ? defaultIndeterminate : indeterminate; if (inputRef.current) { setIndeterminate(inputRef.current, Boolean(indeterminateValue)); } }, [defaultIndeterminate, indeterminate, inputRef]); const handleChange = React.useCallback( (event: React.ChangeEvent) => { if ( defaultIndeterminate !== undefined && indeterminate === undefined && inputRest.checked === undefined && inputRef.current ) { setIndeterminate(inputRef.current, false); } if (indeterminate !== undefined && inputRef.current) { setIndeterminate(inputRef.current, Boolean(indeterminate)); } onChange && onChange(event); }, [defaultIndeterminate, indeterminate, inputRest.checked, onChange, inputRef], ); if (process.env.NODE_ENV === 'development') { /* istanbul ignore if: не проверяем в тестах */ if (getRef) { warn('Свойство `getRef` устаревшее, используйте `slotProps={ input: { getRootRef: ... } }`'); } if (defaultIndeterminate && inputRest.defaultChecked) { warn('defaultIndeterminate и defaultChecked не могут быть true одновременно', 'error'); } if (indeterminate && inputRest.checked) { warn('indeterminate и checked не могут быть true одновременно', 'error'); } if (inputRest.defaultChecked && inputRest.checked) { warn('defaultChecked и checked не могут быть true одновременно', 'error'); } } return ( {platform === 'vkcom' ? ( ) : ( {adaptiveDensity.compact && ( )} {adaptiveDensity.regular && ( )} )} {platform === 'vkcom' ? ( ) : ( {adaptiveDensity.compact && ( )} {adaptiveDensity.regular && ( )} )} {platform === 'vkcom' ? ( ) : ( {adaptiveDensity.compact && ( )} {adaptiveDensity.regular && ( )} )} ); }