UNPKG

@gluestack-ui/radio

Version:

A universal headless Radio component for React Native, Next.js & React

80 lines (79 loc) 5.31 kB
import React, { forwardRef, memo } from 'react'; import { useFocusRing, useFocus } from '@react-native-aria/focus'; import { RadioProvider } from './RadioProvider'; import { useRadio } from '@react-native-aria/radio'; import { useRadioGroup } from './RadioGroupContext'; import { usePress, useHover } from '@react-native-aria/interactions'; import { stableHash, composeEventHandlers } from '@gluestack-ui/utils'; import { useFormControlContext } from '@gluestack-ui/form-control'; const RadioComponent = memo(forwardRef(({ StyledRadio, inputProps, combinedProps, isChecked: isCheckedProp, isDisabled: isDisabledProp, isFocusVisible: isFocusVisibleProp, isHovered: isHoveredProp, isInvalid: isInvalidProp, isReadOnly: isReadOnlyProp, isIndeterminate: isIndeterminateProp, isFocused: isFocusedProp, isPressed: isPressedProp, _onPress, onPressIn, onPressOut, onHoverIn, onHoverOut, onFocus, onBlur, children, ...props }, ref) => { const { isInvalid, isReadOnly, isIndeterminate, ...restProps } = combinedProps; const { hoverProps, isHovered } = useHover(); const { focusProps, isFocused } = useFocus(); const { disabled: isDisabled, checked: isChecked } = inputProps; const { focusProps: focusRingProps, isFocusVisible } = useFocusRing(); const { pressProps, isPressed } = usePress({ isDisabled: isDisabled || isDisabledProp, }); return (<StyledRadio disabled={isDisabled || isDisabledProp} {...pressProps} {...restProps} {...inputProps} {...props} ref={ref} role="radio" onPressIn={composeEventHandlers(onPressIn, pressProps.onPressIn)} onPressOut={composeEventHandlers(onPressOut, pressProps.onPressOut)} // @ts-ignore - web only onHoverIn={composeEventHandlers(onHoverIn, hoverProps.onHoverIn)} // @ts-ignore - web only onHoverOut={composeEventHandlers(onHoverOut, hoverProps.onHoverOut)} // @ts-ignore - web only onFocus={composeEventHandlers(composeEventHandlers(onFocus, focusProps.onFocus), focusRingProps.onFocus)} // @ts-ignore - web only onBlur={composeEventHandlers(composeEventHandlers(onBlur, focusProps.onBlur), focusRingProps.onBlur)} states={{ readonly: isReadOnly || isReadOnlyProp, intermediate: isIndeterminate || isIndeterminateProp, checked: isChecked || isCheckedProp, focusVisible: isFocusVisible || isFocusVisibleProp, disabled: isDisabled || isDisabledProp, invalid: isInvalid || isInvalidProp, hover: isHovered || isHoveredProp, focus: isFocused || isFocusedProp, active: isPressed || isPressedProp, }} dataSet={{ readonly: isReadOnly || isReadOnlyProp ? 'true' : 'false', intermediate: isIndeterminate || isIndeterminateProp ? 'true' : 'false', checked: isChecked || isCheckedProp ? 'true' : 'false', focusVisible: isFocusVisible || isFocusVisibleProp ? 'true' : 'false', disabled: isDisabled || isDisabledProp ? 'true' : 'false', invalid: isInvalid || isInvalidProp ? 'true' : 'false', hover: isHovered || isHoveredProp ? 'true' : 'false', focus: isFocused || isFocusedProp ? 'true' : 'false', active: isPressed || isPressedProp ? 'true' : 'false', }}> <RadioProvider isChecked={isChecked || isCheckedProp} isDisabled={isDisabled || isDisabledProp} isFocusVisible={isFocused || isFocusVisibleProp} isHovered={isHovered || isHoveredProp} isInvalid={isInvalid || isInvalidProp} isReadOnly={isReadOnly || isReadOnlyProp} isIndeterminate={isIndeterminate || isIndeterminateProp} isFocused={isFocused || isFocusedProp} isPressed={isPressed || isPressedProp}> {children} </RadioProvider> </StyledRadio>); })); const Radio = (StyledRadio) => forwardRef(({ isFocusVisible: isFocusVisibleProp, isHovered: isHoveredProp, isIndeterminate: isIndeterminateProp, isFocused: isFocusedProp, isPressed: isPressedProp, isInvalid: isInvalidProp, children, ...props }, ref) => { const formControlContext = useFormControlContext(); const contextState = useRadioGroup('RadioGroupContext'); const combinedProps = { ...formControlContext, ...contextState, ...props, }; const inputRef = React.useRef(null); const ariaLabel = props['aria-label'] || props.value || 'Radio'; const { inputProps } = useRadio({ ...combinedProps, 'aria-label': ariaLabel, children, }, contextState.state.state ?? {}, inputRef); const contextCombinedProps = React.useMemo(() => { return { ...combinedProps }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [stableHash(combinedProps)]); if (!contextState) { console.error('Error: Radio must be wrapped inside a Radio.Group'); } const isInvalid = contextCombinedProps?.state?.validationState === 'invalid' ? true : false; return (<RadioComponent StyledRadio={StyledRadio} inputProps={inputProps} combinedProps={contextCombinedProps} children={children} ref={ref} isFocusVisible={isFocusVisibleProp} isHovered={isHoveredProp} isIndeterminate={isIndeterminateProp} isFocused={isFocusedProp} isPressed={isPressedProp} isInvalid={isInvalid || isInvalidProp}/>); }); export { Radio };