fix: radio, checkbox, switch touch and selection behavior (#4311)

* fix: radio, checkbox, switch touch and selection behavior

* Update .changeset/violet-tools-refuse.md

* fix: switch toggle on tables
This commit is contained in:
Junior Garcia 2024-12-10 10:26:09 -03:00 committed by GitHub
parent dfefdd6250
commit 03abf1daf4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 60 additions and 17 deletions

View File

@ -0,0 +1,8 @@
---
"@nextui-org/checkbox": patch
"@nextui-org/switch": patch
"@nextui-org/radio": patch
"@nextui-org/theme": patch
---
Fix #4252 #4260 interactive elements were not working properly

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {cloneElement, ReactElement} from "react";
import {UseCheckboxProps, useCheckbox} from "./use-checkbox";
@ -26,9 +25,7 @@ const Checkbox = forwardRef<"input", CheckboxProps>((props, ref) => {
return (
<Component {...getBaseProps()}>
<VisuallyHidden elementType="span">
<input {...getInputProps()} />
</VisuallyHidden>
<input {...getInputProps()} />
<span {...getWrapperProps()}>{clonedIcon}</span>
{children && <span {...getLabelProps()}>{children}</span>}
</Component>

View File

@ -310,9 +310,10 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
return {
ref: mergeRefs(inputRef, ref),
...mergeProps(inputProps, focusProps),
className: slots.hiddenInput({class: classNames?.hiddenInput}),
onChange: chain(inputProps.onChange, handleCheckboxChange),
};
}, [inputProps, focusProps, handleCheckboxChange]);
}, [inputProps, focusProps, handleCheckboxChange, classNames?.hiddenInput]);
const getLabelProps: PropGetter = useCallback(
() => ({

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {UseRadioProps, useRadio} from "./use-radio";
@ -21,9 +20,7 @@ const Radio = forwardRef<"input", RadioProps>((props, ref) => {
return (
<Component {...getBaseProps()}>
<VisuallyHidden elementType="span">
<input {...getInputProps()} />
</VisuallyHidden>
<input {...getInputProps()} />
<span {...getWrapperProps()}>
<span {...getControlProps()} />
</span>

View File

@ -202,6 +202,7 @@ export function useRadio(props: UseRadioProps) {
return {
ref: inputRef,
...mergeProps(props, inputProps, focusProps),
className: slots.hiddenInput({class: classNames?.hiddenInput}),
onChange: chain(inputProps.onChange, onChange),
};
},

View File

@ -1,4 +1,3 @@
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {cloneElement, ReactElement} from "react";
import {forwardRef} from "@nextui-org/system";
@ -35,9 +34,7 @@ const Switch = forwardRef<"input", SwitchProps>((props, ref) => {
return (
<Component {...getBaseProps()}>
<VisuallyHidden elementType="span">
<input {...getInputProps()} />
</VisuallyHidden>
<input {...getInputProps()} />
<span {...getWrapperProps()}>
{startContent && clonedStartContent}
<span {...getThumbProps()}>{thumbIcon && clonedThumbIcon}</span>

View File

@ -162,6 +162,7 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
});
const isInteractionDisabled = ariaSwitchProps.isDisabled || isReadOnly;
const pressed = isInteractionDisabled ? false : isPressed;
const isSelected = inputProps.checked;
@ -209,6 +210,7 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
...mergeProps(inputProps, focusProps, props),
ref: mergeRefs(inputRef, ref),
id: inputProps.id,
className: slots.hiddenInput({class: classNames?.hiddenInput}),
onChange: chain(onChange, inputProps.onChange),
};
};

View File

@ -1,7 +1,7 @@
import type {VariantProps} from "tailwind-variants";
import {tv} from "../utils/tv";
import {groupDataFocusVisibleClasses} from "../utils";
import {groupDataFocusVisibleClasses, hiddenInputClasses} from "../utils";
/**
* Checkbox wrapper **Tailwind Variants** component
@ -51,7 +51,8 @@ const checkbox = tv({
// focus ring
...groupDataFocusVisibleClasses,
],
icon: "z-10 w-4 h-3 opacity-0 group-data-[selected=true]:opacity-100",
hiddenInput: hiddenInputClasses,
icon: "z-10 w-4 h-3 opacity-0 group-data-[selected=true]:opacity-100 pointer-events-none",
label: "relative text-foreground select-none",
},
variants: {

View File

@ -1,7 +1,7 @@
import type {VariantProps} from "tailwind-variants";
import {tv} from "../utils/tv";
import {groupDataFocusVisibleClasses} from "../utils";
import {groupDataFocusVisibleClasses, hiddenInputClasses} from "../utils";
/**
* Radio wrapper **Tailwind Variants** component
@ -44,6 +44,7 @@ const radio = tv({
// focus ring
...groupDataFocusVisibleClasses,
],
hiddenInput: hiddenInputClasses,
labelWrapper: "flex flex-col ml-1",
control: [
"z-10",

View File

@ -1,7 +1,7 @@
import type {VariantProps} from "tailwind-variants";
import {tv} from "../utils/tv";
import {groupDataFocusVisibleClasses} from "../utils";
import {groupDataFocusVisibleClasses, hiddenInputClasses} from "../utils";
/**
* Toggle (Switch) wrapper **Tailwind Variants** component
@ -53,7 +53,9 @@ const toggle = tv({
"shadow-small",
"rounded-full",
"origin-right",
"pointer-events-none",
],
hiddenInput: hiddenInputClasses,
startContent: "z-0 absolute start-1.5 text-current",
endContent: "z-0 absolute end-1.5 text-default-600",
thumbIcon: "text-black",

View File

@ -67,3 +67,38 @@ export const collapseAdjacentVariantBorders = {
warning: ["[&+.border-medium.border-warning]:ms-[calc(theme(borderWidth.medium)*-1)]"],
danger: ["[&+.border-medium.border-danger]:ms-[calc(theme(borderWidth.medium)*-1)]"],
};
export const hiddenInputClasses = [
// Variables
"[--cursor-hit-x:8px]",
// Font styles
"font-inherit",
"text-[100%]",
"leading-[1.15]",
// Reset margins and padding
"m-0",
"p-0",
// Overflow and box-sizing
"overflow-visible",
"box-border",
// Positioning & Hit area
"absolute",
"top-0",
"start-[calc(var(--cursor-hit-x)*-1)]",
"w-[calc(100%+var(--cursor-hit-x)*2)]",
"h-full",
// Opacity and z-index
"opacity-[0.0001]",
"z-[1]",
// Cursor
"cursor-pointer",
// Disabled state
"disabled:cursor-default",
];

View File

@ -7,6 +7,7 @@ export {
translateCenterClasses,
absoluteFullClasses,
collapseAdjacentVariantBorders,
hiddenInputClasses,
} from "./classes";
export type {SlotsToClasses} from "./types";
export {colorVariants} from "./variants";