UNPKG

@syncfusion/react-buttons

Version:

Syncfusion React Buttons package is a feature-rich collection of UI components including Button, CheckBox, RadioButton, Switch, Chip, and more for building modern, interactive React applications.

146 lines (145 loc) 8.12 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect, useCallback, useImperativeHandle, useRef, forwardRef } from 'react'; import { preRender, useProviderContext, SvgIcon, useRippleEffect, getUniqueID, Size, Position } from '@syncfusion/react-base'; const CHECK = 'sf-checkbox-checked'; const DISABLED = 'sf-disabled sf-no-pointer'; const FRAME = 'sf-checkbox-frame'; const INDETERMINATE = 'sf-checkbox-indeterminate'; const LABEL = 'sf-label'; const WRAPPER = 'sf-control sf-checkbox-wrapper'; const CHECKBOX_CLASS = 'sf-checkbox'; /** * The Checkbox component allows users to select one or multiple options from a list, providing a visual representation of a binary choice with states like checked, unchecked, or indeterminate. * * ```typescript * import { Checkbox } from "@syncfusion/react-buttons"; * * <Checkbox checked={true} label="Accept Terms and Conditions" /> * ``` */ export const Checkbox = forwardRef((props, ref) => { const { onChange, checked, defaultChecked = false, color, icon, checkedIcon, className = '', disabled = false, indeterminate = false, labelPlacement = Position.Right, name = '', value = '', size = Size.Medium, id = getUniqueID('checkbox'), ...domProps } = props; const isControlled = checked !== undefined; const [checkedState, setCheckedState] = useState(() => { if (isControlled) { return checked; } return defaultChecked; }); const [isIndeterminate, setIsIndeterminate] = useState(indeterminate); const [isFocused, setIsFocused] = useState(false); const [storedLabel, setStoredLabel] = useState(props.label ?? ''); const [storedLabelPosition, setStoredLabelPosition] = useState(labelPlacement ?? Position.Right); const inputRef = useRef(null); const wrapperRef = useRef(null); const rippleContainerRef = useRef(null); const { dir, ripple } = useProviderContext(); const { rippleMouseDown, Ripple } = useRippleEffect(ripple, { isCenterRipple: true }); const checkIcon = 'M23.8284 3.75L8.5 19.0784L0.17157 10.75L3 7.92157L8.5 13.4216L21 0.92157L23.8284 3.75Z'; const indeterminateIcon = 'M0.5 0.5H17.5V3.5H0.5V0.5Z'; const publicAPI = { checked, indeterminate, value, color, size, icon, checkedIcon }; useImperativeHandle(ref, () => ({ ...publicAPI, element: inputRef.current }), [publicAPI]); useEffect(() => { if (isControlled) { setCheckedState(!!checked); } }, [checked, isControlled]); useEffect(() => { setStoredLabel(props.label ?? ''); setStoredLabelPosition(labelPlacement ?? 'After'); }, [props.label, labelPlacement]); useEffect(() => { preRender('checkbox'); }, []); useEffect(() => { setIsIndeterminate(indeterminate); }, [indeterminate]); const handleStateChange = useCallback((event) => { const newChecked = event.target.checked; setIsIndeterminate(false); setIsFocused(false); if (!isControlled) { setCheckedState(newChecked); } if (onChange) { onChange({ event, value: newChecked }); } }, [onChange, isControlled]); const handleFocus = () => { setIsFocused(true); }; const handleBlur = () => { setIsFocused(false); }; const handleMouseDown = useCallback((e) => { if (ripple && rippleContainerRef.current && rippleMouseDown) { const syntheticEvent = { ...e, currentTarget: rippleContainerRef.current, target: rippleContainerRef.current, preventDefault: e.preventDefault, stopPropagation: e.stopPropagation }; rippleMouseDown(syntheticEvent); } }, [ripple, rippleMouseDown]); const wrapperClass = [ WRAPPER, className, color && color.toLowerCase() !== 'secondary' ? `sf-${color.toLowerCase()}` : '', disabled ? DISABLED : '', isFocused ? 'sf-focus' : '', dir === 'rtl' ? 'sf-rtl' : '', size && size.toLowerCase() !== 'medium' ? `sf-${size.toLowerCase()}` : '' ].filter(Boolean).join(' '); const renderRipple = () => (_jsx("span", { ref: rippleContainerRef, className: `sf-checkbox-ripple sf-checkbox-ripple-${size.toLowerCase().substring(0, 2)} ${(storedLabelPosition === 'Top' || storedLabelPosition === 'Bottom') ? 'sf-checkbox-vertical' : 'sf-checkbox-horizontal'}`, children: ripple && _jsx(Ripple, {}) })); const labelFontSizeClass = size && size.toLowerCase() === 'small' ? 'sf-font-size-12' : size && size.toLowerCase() === 'large' ? 'sf-font-size-16' : 'sf-font-size-14'; const renderIcons = () => { const sizeDimensions = { Small: { width: '12', height: '12', viewBox: '0 0 26 20' }, Medium: { width: '12', height: '12', viewBox: '0 0 25 20' }, Large: { width: '16', height: '16', viewBox: '0 0 26 20' } }; const dimensions = sizeDimensions[size] || sizeDimensions.Medium; return (_jsxs("span", { className: `sf-checkbox-icons ${FRAME}-${size.toLowerCase().substring(0, 2)} ${isIndeterminate ? INDETERMINATE : checkedState ? CHECK : ''}`, children: [isIndeterminate && (_jsx(SvgIcon, { width: dimensions.width, height: dimensions.height, viewBox: "0 0 20 2", d: indeterminateIcon, fill: "currentColor" })), checkedState && !isIndeterminate && (_jsx(SvgIcon, { width: dimensions.width, height: dimensions.height, viewBox: dimensions.viewBox, d: checkIcon, fill: "currentColor" }))] })); }; return (_jsx("div", { ref: wrapperRef, className: wrapperClass, "aria-disabled": disabled ? 'true' : 'false', onMouseDown: handleMouseDown, children: _jsxs("label", { className: `sf-checkbox-label sf-${storedLabelPosition.toLowerCase()}`, children: [_jsx("input", { ref: inputRef, id: id, className: `${CHECKBOX_CLASS} ${className}`, type: "checkbox", name: name, value: value, checked: isControlled ? checked : checkedState, disabled: disabled, onFocus: handleFocus, onBlur: handleBlur, onChange: handleStateChange, ...domProps }), _jsx("span", { className: `${LABEL} ${labelFontSizeClass}`, children: storedLabel }), renderRipple(), checkedState ? checkedIcon : icon, !checkedIcon && !icon && renderIcons()] }) })); }); Checkbox.displayName = 'Checkbox'; export default Checkbox; const createCSSCheckbox = (props) => { const { className = '', checked = false, label = '', ...domProps } = props; const { dir, ripple } = useProviderContext(); const checkIcon = 'M23.8284 3.75L8.5 19.0784L0.17157 10.75L3 7.92157L8.5 13.4216L21 0.92157L23.8284 3.75Z'; const rippleContainerRef = useRef(null); const { rippleMouseDown, Ripple } = useRippleEffect(ripple, { isCenterRipple: true }); const handleMouseDown = useCallback((e) => { if (ripple && rippleContainerRef.current && rippleMouseDown) { const syntheticEvent = { ...e, currentTarget: rippleContainerRef.current, target: rippleContainerRef.current, preventDefault: e.preventDefault, stopPropagation: e.stopPropagation }; rippleMouseDown(syntheticEvent); } }, [ripple, rippleMouseDown]); return (_jsxs("div", { className: `sf-checkbox-wrapper ${className} ${(dir === 'rtl') ? 'sf-rtl' : ''}`, onMouseDown: handleMouseDown, ...domProps, children: [_jsx("span", { ref: rippleContainerRef, className: `sf-ripple-container ${checked ? 'sf-ripple-check' : ''}`, children: ripple && _jsx(Ripple, {}) }), _jsx("span", { className: `sf-frame e-icons ${checked ? 'sf-check' : ''}`, children: checked && (_jsx(SvgIcon, { width: '12', height: '12', viewBox: '0 0 25 20', d: checkIcon, fill: "currentColor" })) }), label && (_jsx("span", { className: LABEL, children: label }))] })); }; // Component definition for Checkbox using create function export const CSSCheckbox = (props) => { return createCSSCheckbox(props); };