diff --git a/.changeset/rude-cobras-grab.md b/.changeset/rude-cobras-grab.md new file mode 100644 index 0000000000..92d853cd85 --- /dev/null +++ b/.changeset/rude-cobras-grab.md @@ -0,0 +1,7 @@ +--- +"@nextui-org/button": patch +"@nextui-org/ripple": patch +"@nextui-org/card": patch +--- + +Refactor Button & Card Ripple diff --git a/packages/components/button/src/use-button.ts b/packages/components/button/src/use-button.ts index 78dd90929f..626a0bf43d 100644 --- a/packages/components/button/src/use-button.ts +++ b/packages/components/button/src/use-button.ts @@ -14,7 +14,7 @@ import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils"; import {button} from "@nextui-org/theme"; import {isValidElement, cloneElement, useMemo} from "react"; import {useAriaButton} from "@nextui-org/use-aria-button"; -import {useHover} from "@react-aria/interactions"; +import {PressEvent, useHover} from "@react-aria/interactions"; import {SpinnerProps} from "@nextui-org/spinner"; import {useRipple} from "@nextui-org/ripple"; @@ -135,22 +135,22 @@ export function useButton(props: UseButtonProps) { ], ); - const {onClick: onRippleClickHandler, onClear: onClearRipple, ripples} = useRipple(); + const {onPress: onRipplePressHandler, onClear: onClearRipple, ripples} = useRipple(); - const handleClick = useCallback( - (e: React.MouseEvent) => { + const handlePress = useCallback( + (e: PressEvent) => { if (disableRipple || isDisabled || disableAnimation) return; - domRef.current && onRippleClickHandler(e); + domRef.current && onRipplePressHandler(e); }, - [disableRipple, isDisabled, disableAnimation, domRef, onRippleClickHandler], + [disableRipple, isDisabled, disableAnimation, domRef, onRipplePressHandler], ); const {buttonProps: ariaButtonProps, isPressed} = useAriaButton( { elementType: as, isDisabled, - onPress, - onClick: chain(onClick, handleClick), + onPress: chain(onPress, handlePress), + onClick: onClick, ...otherProps, } as AriaButtonProps, domRef, diff --git a/packages/components/card/src/use-card.ts b/packages/components/card/src/use-card.ts index 913d3a8f27..ceb0f7f2c8 100644 --- a/packages/components/card/src/use-card.ts +++ b/packages/components/card/src/use-card.ts @@ -4,10 +4,10 @@ import type {AriaButtonProps} from "@nextui-org/use-aria-button"; import type {RippleProps} from "@nextui-org/ripple"; import {card} from "@nextui-org/theme"; -import {MouseEvent, ReactNode, useCallback, useMemo} from "react"; +import {ReactNode, useCallback, useMemo} from "react"; import {chain, mergeProps} from "@react-aria/utils"; import {useFocusRing} from "@react-aria/focus"; -import {useHover} from "@react-aria/interactions"; +import {PressEvent, useHover} from "@react-aria/interactions"; import {useAriaButton} from "@nextui-org/use-aria-button"; import { HTMLNextUIProps, @@ -96,20 +96,22 @@ export function useCard(originalProps: UseCardProps) { const baseStyles = clsx(classNames?.base, className); - const {onClick: onRippleClickHandler, onClear: onClearRipple, ripples} = useRipple(); + const {onClear: onClearRipple, onPress: onRipplePressHandler, ripples} = useRipple(); - const handleClick = (e: MouseEvent) => { - if (!disableAnimation && !disableRipple && domRef.current) { - onRippleClickHandler(e); - } - }; + const handlePress = useCallback( + (e: PressEvent) => { + if (disableRipple || disableAnimation) return; + domRef.current && onRipplePressHandler(e); + }, + [disableRipple, disableAnimation, domRef, onRipplePressHandler], + ); const {buttonProps, isPressed} = useAriaButton( { - onPress, + onPress: chain(onPress, handlePress), elementType: as, isDisabled: !originalProps.isPressable, - onClick: chain(onClick, handleClick), + onClick: onClick, allowTextSelectionOnPress, ...otherProps, } as unknown as AriaButtonProps<"button">, @@ -209,7 +211,7 @@ export function useCard(originalProps: UseCardProps) { isPressable: originalProps.isPressable, isHoverable: originalProps.isHoverable, disableRipple, - handleClick, + handlePress, isFocusVisible, getCardProps, getRippleProps, diff --git a/packages/components/ripple/src/use-ripple.ts b/packages/components/ripple/src/use-ripple.ts index 5c1d24396b..956380858d 100644 --- a/packages/components/ripple/src/use-ripple.ts +++ b/packages/components/ripple/src/use-ripple.ts @@ -1,5 +1,6 @@ import {getUniqueID} from "@nextui-org/shared-utils"; import React, {useCallback, useState} from "react"; +import {PressEvent} from "@react-types/shared"; export type RippleType = { key: React.Key; @@ -13,19 +14,18 @@ export interface UseRippleProps {} export function useRipple(props: UseRippleProps = {}) { const [ripples, setRipples] = useState([]); - const onClick = useCallback((event: React.MouseEvent) => { - const trigger = event.currentTarget; + const onPress = useCallback((event: PressEvent) => { + const trigger = event.target; const size = Math.max(trigger.clientWidth, trigger.clientHeight); - const rect = trigger.getBoundingClientRect(); setRipples((prevRipples) => [ ...prevRipples, { key: getUniqueID(prevRipples.length.toString()), size, - x: event.clientX - rect.left - size / 2, - y: event.clientY - rect.top - size / 2, + x: event.x - size / 2, + y: event.y - size / 2, }, ]); }, []); @@ -34,7 +34,7 @@ export function useRipple(props: UseRippleProps = {}) { setRipples((prevState) => prevState.filter((ripple) => ripple.key !== key)); }, []); - return {ripples, onClick, onClear, ...props}; + return {ripples, onClear, onPress, ...props}; } export type UseRippleReturn = ReturnType;