Skip to content

Commit

Permalink
fix(touch): fixing the selection functionality on touch (#4220)
Browse files Browse the repository at this point in the history
* fix(touch): fixing the selection functionality on touch

* fix: radio, checkbox & switch interactions

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
  • Loading branch information
macci001 and jrgarciadev authored Dec 4, 2024
1 parent d6ae2cb commit 729ede8
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 84 deletions.
7 changes: 7 additions & 0 deletions .changeset/happy-guests-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@nextui-org/checkbox": patch
"@nextui-org/switch": patch
"@nextui-org/radio": patch
---

Fix #4210 radio, checkbox & switch interaction
34 changes: 5 additions & 29 deletions packages/components/checkbox/src/use-checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import type {AriaCheckboxProps} from "@react-types/checkbox";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";

import {useProviderContext} from "@nextui-org/system";
import {ReactNode, Ref, useCallback, useId, useState} from "react";
import {ReactNode, Ref, useCallback, useId} from "react";
import {useMemo, useRef} from "react";
import {useToggleState} from "@react-stately/toggle";
import {checkbox} from "@nextui-org/theme";
import {useCallbackRef} from "@nextui-org/use-callback-ref";
import {useHover, usePress} from "@react-aria/interactions";
import {useHover} from "@react-aria/interactions";
import {useFocusRing} from "@react-aria/focus";
import {mergeProps, chain} from "@react-aria/utils";
import {__DEV__, warn, clsx, dataAttr, safeAriaLabel} from "@nextui-org/shared-utils";
Expand Down Expand Up @@ -182,38 +182,15 @@ export function useCheckbox(props: UseCheckboxProps = {}) {

const toggleState = useToggleState(ariaCheckboxProps);

const {
inputProps,
isSelected,
isDisabled,
isReadOnly,
isPressed: isPressedKeyboard,
} = isInGroup
const {inputProps, isSelected, isDisabled, isReadOnly, isPressed} = isInGroup
? // eslint-disable-next-line
useReactAriaCheckboxGroupItem({...ariaCheckboxProps}, groupContext.groupState, inputRef)
: // eslint-disable-next-line
useReactAriaCheckbox({...ariaCheckboxProps}, toggleState, inputRef);

const isInteractionDisabled = isDisabled || isReadOnly;

// Handle press state for full label. Keyboard press state is returned by useCheckbox
// since it is handled on the <input> element itself.
const [isPressed, setPressed] = useState(false);
const {pressProps} = usePress({
isDisabled: isInteractionDisabled,
onPressStart(e) {
if (e.pointerType !== "keyboard") {
setPressed(true);
}
},
onPressEnd(e) {
if (e.pointerType !== "keyboard") {
setPressed(false);
}
},
});

const pressed = isInteractionDisabled ? false : isPressed || isPressedKeyboard;
const pressed = isInteractionDisabled ? false : isPressed;

const {hoverProps, isHovered} = useHover({
isDisabled: inputProps.disabled,
Expand Down Expand Up @@ -277,7 +254,7 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
"data-readonly": dataAttr(inputProps.readOnly),
"data-focus-visible": dataAttr(isFocusVisible),
"data-indeterminate": dataAttr(isIndeterminate),
...mergeProps(hoverProps, pressProps, otherProps),
...mergeProps(hoverProps, otherProps),
};
}, [
slots,
Expand All @@ -292,7 +269,6 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
inputProps.readOnly,
isFocusVisible,
hoverProps,
pressProps,
otherProps,
]);

Expand Down
33 changes: 5 additions & 28 deletions packages/components/radio/src/use-radio.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type {AriaRadioProps} from "@react-types/radio";
import type {RadioVariantProps, RadioSlots, SlotsToClasses} from "@nextui-org/theme";

import {Ref, ReactNode, useCallback, useId, useState} from "react";
import {Ref, ReactNode, useCallback, useId} from "react";
import {useMemo, useRef} from "react";
import {useFocusRing} from "@react-aria/focus";
import {useHover, usePress} from "@react-aria/interactions";
import {useHover} from "@react-aria/interactions";
import {radio} from "@nextui-org/theme";
import {useRadio as useReactAriaRadio} from "@react-aria/radio";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
Expand Down Expand Up @@ -115,12 +115,7 @@ export function useRadio(props: UseRadioProps) {
descriptionId,
]);

const {
inputProps,
isDisabled,
isSelected,
isPressed: isPressedKeyboard,
} = useReactAriaRadio(
const {inputProps, isDisabled, isSelected, isPressed} = useReactAriaRadio(
{
value,
children: typeof children === "function" ? true : children,
Expand All @@ -135,29 +130,11 @@ export function useRadio(props: UseRadioProps) {
});

const interactionDisabled = isDisabled || inputProps.readOnly;

// Handle press state for full label. Keyboard press state is returned by useCheckbox
// since it is handled on the <input> element itself.
const [isPressed, setPressed] = useState(false);
const {pressProps} = usePress({
isDisabled: interactionDisabled,
onPressStart(e) {
if (e.pointerType !== "keyboard") {
setPressed(true);
}
},
onPressEnd(e) {
if (e.pointerType !== "keyboard") {
setPressed(false);
}
},
});

const {hoverProps, isHovered} = useHover({
isDisabled: interactionDisabled,
});

const pressed = interactionDisabled ? false : isPressed || isPressedKeyboard;
const pressed = interactionDisabled ? false : isPressed;

const slots = useMemo(
() =>
Expand Down Expand Up @@ -189,7 +166,7 @@ export function useRadio(props: UseRadioProps) {
"data-hover-unselected": dataAttr(isHovered && !isSelected),
"data-readonly": dataAttr(inputProps.readOnly),
"aria-required": dataAttr(isRequired),
...mergeProps(hoverProps, pressProps, otherProps),
...mergeProps(hoverProps, otherProps),
};
},
[
Expand Down
32 changes: 5 additions & 27 deletions packages/components/switch/src/use-switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import type {ToggleVariantProps, ToggleSlots, SlotsToClasses} from "@nextui-org/
import type {AriaSwitchProps} from "@react-aria/switch";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";

import {ReactNode, Ref, useCallback, useId, useRef, useState} from "react";
import {ReactNode, Ref, useCallback, useId, useRef} from "react";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {mergeRefs} from "@nextui-org/react-utils";
import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect";
import {useHover, usePress} from "@react-aria/interactions";
import {useHover} from "@react-aria/interactions";
import {toggle} from "@nextui-org/theme";
import {chain, mergeProps} from "@react-aria/utils";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
Expand Down Expand Up @@ -155,36 +155,14 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
state.setSelected(isInputRefChecked);
}, [inputRef.current]);

const {
inputProps,
isPressed: isPressedKeyboard,
isReadOnly,
} = useReactAriaSwitch(ariaSwitchProps, state, inputRef);
const {inputProps, isPressed, isReadOnly} = useReactAriaSwitch(ariaSwitchProps, state, inputRef);
const {focusProps, isFocused, isFocusVisible} = useFocusRing({autoFocus: inputProps.autoFocus});
const {hoverProps, isHovered} = useHover({
isDisabled: inputProps.disabled,
});

const isInteractionDisabled = ariaSwitchProps.isDisabled || isReadOnly;

// Handle press state for full label. Keyboard press state is returned by useSwitch
// since it is handled on the <input> element itself.
const [isPressed, setPressed] = useState(false);
const {pressProps} = usePress({
isDisabled: isInteractionDisabled,
onPressStart(e) {
if (e.pointerType !== "keyboard") {
setPressed(true);
}
},
onPressEnd(e) {
if (e.pointerType !== "keyboard") {
setPressed(false);
}
},
});

const pressed = isInteractionDisabled ? false : isPressed || isPressedKeyboard;
const pressed = isInteractionDisabled ? false : isPressed;

const isSelected = inputProps.checked;
const isDisabled = inputProps.disabled;
Expand All @@ -202,7 +180,7 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {

const getBaseProps: PropGetter = (props) => {
return {
...mergeProps(hoverProps, pressProps, otherProps, props),
...mergeProps(hoverProps, otherProps, props),
ref: domRef,
className: slots.base({class: clsx(baseStyles, props?.className)}),
"data-disabled": dataAttr(isDisabled),
Expand Down

0 comments on commit 729ede8

Please sign in to comment.