UNPKG

@nex-ui/react

Version:

🎉 A beautiful, modern, and reliable React component library.

194 lines (191 loc) • 6.61 kB
"use client"; import { jsxs, jsx } from 'react/jsx-runtime'; import { useId, useMemo, isValidElement, cloneElement } from 'react'; import { __DEV__, isString, isFunction } from '@nex-ui/utils'; import { useControlledState, useEvent } from '@nex-ui/hooks'; import { useCheckboxGroup } from './CheckboxGroupContext.mjs'; import { CheckedIcon } from './CheckedIcon.mjs'; import { IndeterminateIcon } from './IndeterminateIcon.mjs'; import { useNexUI } from '../provider/Context.mjs'; import { useDefaultProps } from '../utils/useDefaultProps.mjs'; import { useSlotClasses } from '../utils/useSlotClasses.mjs'; import { useStyles } from '../utils/useStyles.mjs'; import { useSlot } from '../utils/useSlot.mjs'; import { InputBase } from '../inputBase/InputBase.mjs'; import { checkboxRecipe } from '../../theme/recipes/checkbox.mjs'; const slots = [ 'root', 'input', 'label', 'icon' ]; const useSlotAriaProps = (ownerState)=>{ const { children, slotProps, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy } = ownerState; const id = useId(); return useMemo(()=>{ const labelProps = slotProps?.label; const stringChildren = isString(children); const hasLabel = !!children; const labelId = labelProps?.id ?? (hasLabel ? id : undefined); return { input: { 'aria-labelledby': ariaLabelledBy ?? labelId, 'aria-label': ariaLabel ?? (stringChildren ? children : undefined) }, label: { id: labelId } }; }, [ ariaLabel, ariaLabelledBy, children, id, slotProps?.label ]); }; const Checkbox = (inProps)=>{ const { primaryThemeColor, css } = useNexUI(); const props = useDefaultProps({ name: 'Checkbox', props: inProps }); const groupCtx = useCheckboxGroup(); const inGroup = !!groupCtx; if (__DEV__ && inGroup) { if ('checked' in props) { console.warn('[Nex UI] Checkbox: The CheckboxGroup is being used, `checked` will be ignored. Use the `value` of the CheckboxGroup instead.'); } if ('defaultChecked' in props) { console.warn('[Nex UI] Checkbox: The CheckboxGroup is being used, `defaultChecked` will be ignored. Use the `defaultValue` of the CheckboxGroup instead.'); } if (!('value' in props)) { console.error('[Nex UI] Checkbox: The `value` prop is required when using Checkbox inside a CheckboxGroup.'); } } const { sx, icon, value, className, classNames, children, slotProps, onCheckedChange, indeterminate = false, as = 'input', checked: checkedProp, type = 'checkbox', defaultChecked = false, name = groupCtx?.name, color = groupCtx?.color ?? primaryThemeColor, disabled = groupCtx?.disabled ?? false, size = groupCtx?.size ?? 'md', radius = groupCtx?.radius ?? groupCtx?.size ?? size, ...remainingProps } = props; const [rawChecked, setRawChecked] = useControlledState(checkedProp, defaultChecked, onCheckedChange); const checked = inGroup ? groupCtx.isChecked(value) : rawChecked; const ownerState = { ...props, as, defaultChecked, type, name, disabled, color, checked, size, radius, inGroup, indeterminate }; const handleChange = useEvent((newChecked)=>{ if (inGroup && value !== undefined) { groupCtx.toggleValue(value); } if (!inGroup) { setRawChecked(newChecked); } }); const slotClasses = useSlotClasses({ name: 'Checkbox', slots, classNames }); const styles = useStyles({ ownerState, name: 'Checkbox', recipe: checkboxRecipe }); const slotAriaProps = useSlotAriaProps(ownerState); const [CheckboxRoot, getCheckboxRootProps] = useSlot({ elementType: 'label', externalSlotProps: slotProps?.root, style: styles.root, classNames: slotClasses.root, additionalProps: { sx, className }, dataAttrs: { radius, size, color, disabled, checked, indeterminate, inGroup } }); const [CheckboxInput, getCheckboxInputProps] = useSlot({ elementType: InputBase, externalForwardedProps: remainingProps, classNames: slotClasses.input, style: styles.input, a11y: slotAriaProps.input, shouldForwardComponent: false, additionalProps: { as, type, name, disabled, checked, value, onCheckedChange: handleChange } }); const [CheckboxIcon, getCheckboxIconProps] = useSlot({ elementType: 'span', externalSlotProps: slotProps?.icon, style: styles.icon, classNames: slotClasses.icon }); const [CheckboxLabel, getCheckboxLabelProps] = useSlot({ elementType: 'span', externalSlotProps: slotProps?.label, style: styles.label, classNames: slotClasses.label, a11y: slotAriaProps.label }); const renderCheckedIcon = ()=>{ if (indeterminate) { return /*#__PURE__*/ jsx(IndeterminateIcon, {}); } const customIcon = icon ? isFunction(icon) ? icon(ownerState) : icon : null; if (!customIcon) { return /*#__PURE__*/ jsx(CheckedIcon, { checked: checked }); } if (/*#__PURE__*/ isValidElement(customIcon)) { const element = customIcon; return /*#__PURE__*/ cloneElement(element, { ...element.props, style: { ...element.props.style, ...css(styles.checkedIcon) } }); } return customIcon; }; return /*#__PURE__*/ jsxs(CheckboxRoot, { ...getCheckboxRootProps(), children: [ /*#__PURE__*/ jsx(CheckboxInput, { ...getCheckboxInputProps() }), /*#__PURE__*/ jsx(CheckboxIcon, { ...getCheckboxIconProps(), children: renderCheckedIcon() }), children && /*#__PURE__*/ jsx(CheckboxLabel, { ...getCheckboxLabelProps(), children: children }) ] }); }; Checkbox.displayName = 'Checkbox'; export { Checkbox };