@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
169 lines • 6.83 kB
JavaScript
import { AnimatePresence } from 'motion/react';
import React, { useCallback, useContext, useEffect, useMemo, useState, useRef } from 'react';
import { RadioButtonGroupContext } from './radio-button-group/RadioButtonGroup';
import { StyledLabelWrapper, StyledMotionRadioButtonChildren, StyledRadioButton, StyledRadioButtonCheckBox, StyledRadioButtonCheckBoxMark, StyledRadioButtonLabel, StyledRadioButtonPseudoCheckBox, StyledRadioButtonWrapper } from './RadioButton.styles';
import { getHeightOfSingleTextLine } from '../../utils/calculate';
import { useKeyboardFocusHighlighting } from '../../hooks/useKeyboardFocusHighlighting';
const RadioButton = ({
children,
shouldShowRightElementOnlyOnChecked = false,
label,
id,
rightElement,
shouldShowCentered = true,
isDisabled = false,
shouldEnableKeyboardHighlighting
}) => {
const {
selectedRadioButtonId,
updateSelectedRadioButtonId,
radioButtonRightElements,
updateHasRightElement,
radioButtonsCanBeUnchecked,
shouldEnableKeyboardHighlighting: shouldEnableKeyboardHighlightingFromGroup
} = useContext(RadioButtonGroupContext);
const [internalIsChecked, setInternalIsChecked] = useState(false);
const [isHovered, setIsHovered] = useState(false);
const [radioButtonTop, setRadioButtonTop] = useState(undefined);
const radioButtonBoxRef = useRef(null);
const radioButtonRootRef = useRef(null);
const isInGroup = typeof updateSelectedRadioButtonId === 'function';
const isMarked = isInGroup ? selectedRadioButtonId === id : internalIsChecked;
const uncheckable = radioButtonsCanBeUnchecked;
const effectiveShouldEnableKeyboardHighlighting = shouldEnableKeyboardHighlightingFromGroup ?? shouldEnableKeyboardHighlighting;
const shouldShowKeyboardHighlighting = useKeyboardFocusHighlighting(effectiveShouldEnableKeyboardHighlighting && !isDisabled);
useEffect(() => {
if (radioButtonRootRef.current && !shouldShowCentered) {
const singleLineHeight = getHeightOfSingleTextLine({
container: radioButtonRootRef.current
});
const boxHeight = radioButtonBoxRef.current?.getBoundingClientRect().height ?? 0;
setRadioButtonTop((singleLineHeight - boxHeight) / 2);
}
}, [shouldShowCentered]);
const handleClick = useCallback(() => {
if (isDisabled) {
return;
}
if (uncheckable) {
if (updateSelectedRadioButtonId) {
updateSelectedRadioButtonId(id === selectedRadioButtonId ? undefined : id);
}
setInternalIsChecked(prev => !prev);
return;
}
if (typeof updateSelectedRadioButtonId === 'function') {
updateSelectedRadioButtonId(id);
}
setInternalIsChecked(true);
}, [id, isDisabled, uncheckable, selectedRadioButtonId, updateSelectedRadioButtonId]);
const handleMouseEnter = useCallback(() => {
if (!isDisabled) {
setIsHovered(true);
}
}, [isDisabled]);
const handleMouseLeave = () => {
setIsHovered(false);
};
const handleKeyDown = useCallback(event => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
handleClick();
}
}, [handleClick]);
const radioButtonRightElementMargin = useMemo(() => {
if (!radioButtonRightElements) {
return 'NONE';
}
const index = radioButtonRightElements.findIndex(element => element.id === id);
if (index < 0) {
return 'NONE';
}
const prevButton = radioButtonRightElements[index - 1];
const currentButton = radioButtonRightElements[index];
const nextButton = radioButtonRightElements[index + 1];
if (!currentButton?.hasRightElement) {
return 'NONE';
}
switch (true) {
case prevButton?.hasRightElement && !nextButton?.hasRightElement:
return 'TOP';
case !prevButton?.hasRightElement && nextButton?.hasRightElement:
return 'BOTTOM';
case currentButton?.hasRightElement && !nextButton?.hasRightElement && !prevButton?.hasRightElement:
return 'NONE';
default:
return 'BOTH';
}
}, [id, radioButtonRightElements]);
const shouldShowRightElement = useMemo(() => {
if (rightElement) {
if (shouldShowRightElementOnlyOnChecked) {
return isMarked;
}
return true;
}
return false;
}, [isMarked, rightElement, shouldShowRightElementOnlyOnChecked]);
useEffect(() => {
if (typeof updateHasRightElement === 'function') {
window.setTimeout(() => {
updateHasRightElement(id, shouldShowRightElement);
}, 10);
}
}, [id, shouldShowRightElement, updateHasRightElement]);
return useMemo(() => /*#__PURE__*/React.createElement(StyledRadioButton, {
$isDisabled: isDisabled,
$radioButtonRightElementMargin: radioButtonRightElementMargin
}, /*#__PURE__*/React.createElement(StyledRadioButtonWrapper, {
ref: radioButtonRootRef,
$shouldShowKeyboardHighlighting: shouldShowKeyboardHighlighting
}, /*#__PURE__*/React.createElement(StyledRadioButtonCheckBox, {
onClick: handleClick,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
onKeyDown: handleKeyDown,
disabled: isDisabled,
$isDisabled: isDisabled,
$shouldShowKeyboardHighlighting: shouldShowKeyboardHighlighting,
type: "radio",
checked: isMarked,
onChange: () => {}
}), /*#__PURE__*/React.createElement(StyledRadioButtonPseudoCheckBox, {
$isDisabled: isDisabled,
$isChecked: isMarked,
ref: radioButtonBoxRef,
onClick: handleClick,
style: {
top: shouldShowCentered ? '50%' : radioButtonTop,
transform: shouldShowCentered ? 'translateY(-50%)' : undefined
}
}, /*#__PURE__*/React.createElement(StyledRadioButtonCheckBoxMark, {
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
$isHovered: isHovered,
$isSelected: isMarked,
$isDisabled: isDisabled
})), /*#__PURE__*/React.createElement(StyledLabelWrapper, null, label && /*#__PURE__*/React.createElement(StyledRadioButtonLabel, {
$isDisabled: isDisabled,
onClick: handleClick,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave
}, label), shouldShowRightElement && rightElement)), children && /*#__PURE__*/React.createElement(AnimatePresence, {
initial: false
}, /*#__PURE__*/React.createElement(StyledMotionRadioButtonChildren, {
animate: isMarked ? {
opacity: 1,
height: 'auto'
} : {
opacity: 0,
height: 0
},
transition: {
duration: 0.2
}
}, children))), [children, handleClick, handleKeyDown, handleMouseEnter, isDisabled, isHovered, isMarked, label, radioButtonRightElementMargin, radioButtonTop, rightElement, shouldShowCentered, shouldShowKeyboardHighlighting, shouldShowRightElement]);
};
RadioButton.displayName = 'RadioButton';
export default RadioButton;
//# sourceMappingURL=RadioButton.js.map