diff --git a/.changeset/violet-tools-refuse.md b/.changeset/violet-tools-refuse.md new file mode 100644 index 0000000000..b6c6ccf257 --- /dev/null +++ b/.changeset/violet-tools-refuse.md @@ -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 diff --git a/packages/components/checkbox/src/checkbox.tsx b/packages/components/checkbox/src/checkbox.tsx index 9ca4ee6e2a..2fc2a18c2d 100644 --- a/packages/components/checkbox/src/checkbox.tsx +++ b/packages/components/checkbox/src/checkbox.tsx @@ -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 ( - - - + {clonedIcon} {children && {children}} diff --git a/packages/components/checkbox/src/use-checkbox.ts b/packages/components/checkbox/src/use-checkbox.ts index 376541cb1d..bba104f6d6 100644 --- a/packages/components/checkbox/src/use-checkbox.ts +++ b/packages/components/checkbox/src/use-checkbox.ts @@ -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( () => ({ diff --git a/packages/components/radio/src/radio.tsx b/packages/components/radio/src/radio.tsx index 85535004f0..df80b892a1 100644 --- a/packages/components/radio/src/radio.tsx +++ b/packages/components/radio/src/radio.tsx @@ -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 ( - - - + diff --git a/packages/components/radio/src/use-radio.ts b/packages/components/radio/src/use-radio.ts index b171b1e006..78b452827e 100644 --- a/packages/components/radio/src/use-radio.ts +++ b/packages/components/radio/src/use-radio.ts @@ -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), }; }, diff --git a/packages/components/switch/src/switch.tsx b/packages/components/switch/src/switch.tsx index d60428bfcd..bc64125194 100644 --- a/packages/components/switch/src/switch.tsx +++ b/packages/components/switch/src/switch.tsx @@ -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 ( - - - + {startContent && clonedStartContent} {thumbIcon && clonedThumbIcon} diff --git a/packages/components/switch/src/use-switch.ts b/packages/components/switch/src/use-switch.ts index 34adb52e54..faee7334ed 100644 --- a/packages/components/switch/src/use-switch.ts +++ b/packages/components/switch/src/use-switch.ts @@ -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), }; }; diff --git a/packages/core/theme/src/components/checkbox.ts b/packages/core/theme/src/components/checkbox.ts index 3a9de2c9a0..847f640662 100644 --- a/packages/core/theme/src/components/checkbox.ts +++ b/packages/core/theme/src/components/checkbox.ts @@ -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: { diff --git a/packages/core/theme/src/components/radio.ts b/packages/core/theme/src/components/radio.ts index a5161981fd..40a826e1e2 100644 --- a/packages/core/theme/src/components/radio.ts +++ b/packages/core/theme/src/components/radio.ts @@ -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", diff --git a/packages/core/theme/src/components/toggle.ts b/packages/core/theme/src/components/toggle.ts index a06217e8ae..2787728200 100644 --- a/packages/core/theme/src/components/toggle.ts +++ b/packages/core/theme/src/components/toggle.ts @@ -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", diff --git a/packages/core/theme/src/utils/classes.ts b/packages/core/theme/src/utils/classes.ts index 7ed19d23a1..2711a48a3b 100644 --- a/packages/core/theme/src/utils/classes.ts +++ b/packages/core/theme/src/utils/classes.ts @@ -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", +]; diff --git a/packages/core/theme/src/utils/index.ts b/packages/core/theme/src/utils/index.ts index 2a096ff86a..f80e69ec6b 100644 --- a/packages/core/theme/src/utils/index.ts +++ b/packages/core/theme/src/utils/index.ts @@ -7,6 +7,7 @@ export { translateCenterClasses, absoluteFullClasses, collapseAdjacentVariantBorders, + hiddenInputClasses, } from "./classes"; export type {SlotsToClasses} from "./types"; export {colorVariants} from "./variants";