Skip to content

Commit

Permalink
feat: checkbox performance improved and added to
Browse files Browse the repository at this point in the history
  • Loading branch information
Ajamuar committed Dec 16, 2021
1 parent 8e6310f commit 82286d9
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 174 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ android/keystores/debug.keystore
lib/
src/jest/mock.ts
node_modules

# personal
.env
225 changes: 132 additions & 93 deletions src/components/primitives/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,33 @@ import {
import SizedIcon from './SizedIcon';

const Checkbox = ({ wrapperRef, ...props }: ICheckboxProps, ref: any) => {
const { hoverProps, isHovered } = useHover();
const { pressableProps, isPressed } = useIsPressed();
const { focusProps, isFocused } = useFocus();
const formControlContext = useFormControlContext();

const combinedProps = combineContextAndProps(formControlContext, props);

const _ref = React.useRef();
const mergedRef = mergeRefs([ref, _ref]);
const {
isInvalid,
isReadOnly,
isIndeterminate,
...combinedProps
} = combineContextAndProps(formControlContext, props);

const checkboxGroupContext = useContext(CheckboxGroupContext);
const state = useToggleState({
...combinedProps,
defaultSelected: combinedProps.defaultIsChecked,
isSelected: combinedProps.isChecked,
});
const groupState = useContext(CheckboxGroupContext);

const _ref = React.useRef();
const mergedRef = mergeRefs([ref, _ref]);

// Swap hooks depending on whether this checkbox is inside a CheckboxGroup.
// This is a bit unorthodox. Typically, hooks cannot be called in a conditional,
// but since the checkbox won't move in and out of a group, it should be safe.
const { inputProps } = groupState
const { inputProps: groupItemInputProps } = checkboxGroupContext
? // eslint-disable-next-line react-hooks/rules-of-hooks
useCheckboxGroupItem(
combinedProps,
groupState.state,
checkboxGroupContext.state,
//@ts-ignore
mergedRef
)
Expand All @@ -56,97 +58,134 @@ const Checkbox = ({ wrapperRef, ...props }: ICheckboxProps, ref: any) => {
mergedRef
);

const {
checked: isChecked,
disabled: isDisabled,
isInvalid,
isReadOnly,
isIndeterminate,
} = inputProps;
// eslint-disable-next-line react-hooks/exhaustive-deps
const inputProps = React.useMemo(() => groupItemInputProps, [
groupItemInputProps.checked,
groupItemInputProps.disabled,
]);

const {
icon,
_interactionBox,
_icon,
// destructuring pressable props and passing it manually
onPress,
onPressIn,
onPressOut,
onHoverIn,
onHoverOut,
onFocus,
onBlur,
...resolvedProps
} = usePropsResolution('Checkbox', inputProps, {
const [contextCombinedProps] = React.useState({
...checkboxGroupContext,
...combinedProps,
});

return (
<CheckboxComponent
inputProps={inputProps}
combinedProps={contextCombinedProps}
isInvalid={isInvalid}
isReadOnly={isReadOnly}
isIndeterminate={isIndeterminate}
wrapperRef={wrapperRef}
/>
);
};
const CheckboxComponent = React.memo(
({
wrapperRef,
inputProps,
combinedProps,
isInvalid,
isReadOnly,
isIndeterminate,
isDisabled,
isChecked,
isHovered,
isPressed,
isFocused,
});
}: any) => {
const _ref = React.useRef();
const { hoverProps, isHovered } = useHover();
const { pressableProps, isPressed } = useIsPressed();
const { focusProps, isFocused } = useFocus();

const [layoutProps, nonLayoutProps] = extractInObject(resolvedProps, [
...stylingProps.margin,
...stylingProps.layout,
...stylingProps.flexbox,
...stylingProps.position,
'_text',
]);
const { checked: isChecked, disabled: isDisabled } = inputProps;

const [
accessibilityProps,
nonAccessibilityProps,
] = extractInObject(nonLayoutProps, [
'accessibilityRole',
'accessibilityState',
]);
const {
icon,
_interactionBox,
_icon,
// destructuring pressable props and passing it manually
onPress,
onPressIn,
onPressOut,
onHoverIn,
onHoverOut,
onFocus,
onBlur,
...resolvedProps
} = usePropsResolution('Checkbox', inputProps, {
isInvalid,
isReadOnly,
isIndeterminate,
isDisabled,
isChecked,
isHovered,
isPressed,
isFocused,
});

//TODO: refactor for responsive prop
if (useHasResponsiveProps(resolvedProps)) {
return null;
}
const [layoutProps, nonLayoutProps] = extractInObject(resolvedProps, [
...stylingProps.margin,
...stylingProps.layout,
...stylingProps.flexbox,
...stylingProps.position,
'_text',
]);

return (
<Pressable
{...(pressableProps as IPressableProps)}
{...accessibilityProps}
onPress={onPress}
ref={mergeRefs([ref, wrapperRef])}
accessibilityRole="checkbox"
onPressIn={composeEventHandlers(onPressIn, pressableProps.onPressIn)}
onPressOut={composeEventHandlers(onPressOut, pressableProps.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.onFocu
)}
// @ts-ignore - web only
onBlur={composeEventHandlers(
composeEventHandlers(onBlur, focusProps.onBlur)
// focusRingProps.onBlur
)}
>
<Box {...layoutProps}>
<Center>
{/* Interaction Wrapper */}
<Box {..._interactionBox} p={5} w="100%" height="100%" zIndex={-1} />
{/* Checkbox */}
<Center {...nonAccessibilityProps}>
<SizedIcon icon={icon} _icon={_icon} isChecked={isChecked} />
const [
accessibilityProps,
nonAccessibilityProps,
] = extractInObject(nonLayoutProps, [
'accessibilityRole',
'accessibilityState',
]);

//TODO: refactor for responsive prop
if (useHasResponsiveProps(resolvedProps)) {
return null;
}

return (
<Pressable
{...(pressableProps as IPressableProps)}
{...accessibilityProps}
onPress={onPress}
ref={mergeRefs([_ref, wrapperRef])}
accessibilityRole="checkbox"
onPressIn={composeEventHandlers(onPressIn, pressableProps.onPressIn)}
onPressOut={composeEventHandlers(onPressOut, pressableProps.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.onFocu
)}
// @ts-ignore - web only
onBlur={composeEventHandlers(
composeEventHandlers(onBlur, focusProps.onBlur)
// focusRingProps.onBlur
)}
>
<Box {...layoutProps}>
<Center>
{/* Interaction Wrapper */}
<Box
{..._interactionBox}
p={5}
w="100%"
height="100%"
zIndex={-1}
/>
{/* Checkbox */}
<Center {...nonAccessibilityProps}>
<SizedIcon icon={icon} _icon={_icon} isChecked={isChecked} />
</Center>
</Center>
</Center>
{/* Label */}
{combinedProps.children}
</Box>
</Pressable>
);
};
{/* Label */}
{combinedProps.children}
</Box>
</Pressable>
);
}
);

export default memo(forwardRef(Checkbox));
Loading

0 comments on commit 82286d9

Please sign in to comment.