@i-novus/ui-core
Version:
Базовые UI компоненты
65 lines (64 loc) • 4.23 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useCallback, useMemo, useState } from 'react';
import classNames from 'classnames';
import { useConfigProvider } from '../../core';
import { useCheckboxGroupContext } from './CheckboxGroup';
// eslint-disable-next-line sonarjs/cognitive-complexity
export const CheckboxBody = forwardRef((props, ref) => {
const { className, prefix, indeterminate = false, title, visible = true, children, id: optionId, style, ...restProps } = props;
const { getPrefix } = useConfigProvider();
const prefixCls = getPrefix(prefix);
const checkboxPrefix = `${prefixCls}-checkbox`;
const groupContext = useCheckboxGroupContext();
const [inputId] = useState(`checkbox-${Math.round(Math.random() * 10e6)}`);
const checkboxProps = useMemo(() => ({ ...restProps }), [restProps]);
if (groupContext) {
checkboxProps.checked = groupContext.value.includes(optionId) || null;
checkboxProps.disabled = groupContext.disabled || checkboxProps.disabled;
checkboxProps.readOnly = groupContext.readOnly || checkboxProps.readOnly;
checkboxProps.onBlur = groupContext.onBlur || checkboxProps.onBlur;
}
/**
* тут имеем значение checkboxProps.checked с учетом возможного наличия контекста группы
*/
const [internalChecked, setInternalChecked] = useState(!!checkboxProps.checked || !!checkboxProps.defaultChecked);
const hasExternalControl = useMemo(() => Boolean(checkboxProps.onChange || groupContext?.onChange), [groupContext?.onChange, checkboxProps.onChange]);
const hasCheckedProp = useMemo(() => (Object.hasOwn(props, 'checked')), [props]);
const checkedResultValue = useMemo(() => {
if (!hasExternalControl && !hasCheckedProp) {
return internalChecked;
}
return !!checkboxProps.checked;
}, [hasCheckedProp, hasExternalControl, internalChecked, checkboxProps.checked]);
const labelClassName = useMemo(() => {
return classNames(checkboxPrefix, `${checkboxPrefix}-label`, {
[`${checkboxPrefix}_readonly`]: checkboxProps.readOnly,
[`${checkboxPrefix}_checked`]: checkedResultValue,
[`${checkboxPrefix}_unchecked`]: !checkedResultValue,
[`${checkboxPrefix}_disabled`]: checkboxProps.disabled,
[`${checkboxPrefix}_indeterminate`]: indeterminate,
}, className);
}, [checkboxPrefix, checkboxProps.readOnly, checkboxProps.disabled,
checkedResultValue, indeterminate, className]);
const ariaChecked = useMemo(() => {
return indeterminate ? 'mixed' : !!checkboxProps.checked;
}, [checkboxProps.checked, indeterminate]);
const onCheckboxChange = useCallback((event) => {
checkboxProps.onChange?.(event.target.checked, event);
groupContext?.onChange?.(optionId, event);
// @ts-ignore
checkboxProps.onBlur?.(event);
/**
* изменяем внутренний стейт если чекбокс не управляется извне и не имеет пропа checked
* (может иметь checked для принудительной блокировки включенного состояния)
*/
if (!hasExternalControl && !hasCheckedProp) {
setInternalChecked(prevState => !prevState);
}
}, [groupContext, hasCheckedProp, hasExternalControl, optionId, checkboxProps]);
if (!visible) {
return null;
}
return (_jsxs("label", { htmlFor: inputId, className: labelClassName, title: title, style: style, children: [_jsxs("div", { className: `${checkboxPrefix}__input-wrapper`, children: [_jsx("input", { ...checkboxProps, id: inputId, ref: ref, "aria-checked": ariaChecked, onChange: onCheckboxChange, disabled: checkboxProps.disabled || checkboxProps.readOnly, checked: checkedResultValue, type: "checkbox", className: `${checkboxPrefix}__input` }), _jsx("span", { className: `${checkboxPrefix}__pseudo-input` })] }), !!children && _jsx("span", { className: `${checkboxPrefix}-label__text`, children: children })] }));
});
CheckboxBody.displayName = 'Checkbox';