diff --git a/.changeset/witty-goats-trade.md b/.changeset/witty-goats-trade.md new file mode 100644 index 0000000000..1a52e0c75b --- /dev/null +++ b/.changeset/witty-goats-trade.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/popover": patch +--- + +Fix initial animation direction to match fallback placement (#4290) diff --git a/packages/components/popover/src/use-popover.ts b/packages/components/popover/src/use-popover.ts index bc12cb14f4..074081000b 100644 --- a/packages/components/popover/src/use-popover.ts +++ b/packages/components/popover/src/use-popover.ts @@ -14,7 +14,7 @@ import { PropGetter, useProviderContext, } from "@nextui-org/system"; -import {getArrowPlacement, getShouldUseAxisPlacement} from "@nextui-org/aria-utils"; +import {getArrowPlacement} from "@nextui-org/aria-utils"; import {popover} from "@nextui-org/theme"; import {mergeProps, mergeRefs} from "@react-aria/utils"; import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils"; @@ -81,6 +81,8 @@ export interface Props extends HTMLNextUIProps<"div"> { onClose?: () => void; } +const DEFAULT_PLACEMENT = "top"; + export type UsePopoverProps = Props & Omit & OverlayTriggerProps & @@ -110,7 +112,7 @@ export function usePopover(originalProps: UsePopoverProps) { portalContainer, updatePositionDeps, dialogProps: dialogPropsProp, - placement: placementProp = "top", + placement: placementProp = DEFAULT_PLACEMENT, triggerType = "dialog", showArrow = false, offset = 7, @@ -150,11 +152,7 @@ export function usePopover(originalProps: UsePopoverProps) { const state = stateProp || innerState; - const { - popoverProps, - underlayProps, - placement: ariaPlacement, - } = useReactAriaPopover( + const {popoverProps, underlayProps, placement} = useReactAriaPopover( { triggerRef, isNonModal, @@ -208,7 +206,7 @@ export function usePopover(originalProps: UsePopoverProps) { "data-focus": dataAttr(isFocused), "data-arrow": dataAttr(showArrow), "data-focus-visible": dataAttr(isFocusVisible), - "data-placement": getArrowPlacement(ariaPlacement || "top", placementProp), + "data-placement": getArrowPlacement(placement || DEFAULT_PLACEMENT, placementProp), ...mergeProps(focusProps, dialogPropsProp, props), className: slots.base({class: clsx(baseStyles)}), style: { @@ -222,18 +220,10 @@ export function usePopover(originalProps: UsePopoverProps) { "data-slot": "content", "data-open": dataAttr(state.isOpen), "data-arrow": dataAttr(showArrow), - "data-placement": getArrowPlacement(ariaPlacement || "top", placementProp), + "data-placement": getArrowPlacement(placement || DEFAULT_PLACEMENT, placementProp), className: slots.content({class: clsx(classNames?.content, props.className)}), }), - [slots, state.isOpen, showArrow, ariaPlacement, placementProp, classNames], - ); - - const placement = useMemo( - () => - getShouldUseAxisPlacement(ariaPlacement || "top", placementProp) - ? ariaPlacement || placementProp - : placementProp, - [ariaPlacement, placementProp], + [slots, state.isOpen, showArrow, placement, placementProp, classNames], ); const onPress = useCallback( @@ -317,7 +307,7 @@ export function usePopover(originalProps: UsePopoverProps) { classNames, showArrow, triggerRef, - placement, + placement: placement || DEFAULT_PLACEMENT, isNonModal, popoverRef: domRef, portalContainer, diff --git a/packages/components/popover/stories/popover.stories.tsx b/packages/components/popover/stories/popover.stories.tsx index 3df9aae279..1edfb00a5c 100644 --- a/packages/components/popover/stories/popover.stories.tsx +++ b/packages/components/popover/stories/popover.stories.tsx @@ -127,11 +127,11 @@ const content = ( ); -const Template = (args: PopoverProps) => { +const Template = ({label = "Open Popover", ...args}: PopoverProps & {label: string}) => { return ( - + {content} @@ -581,6 +581,32 @@ export const CustomMotion = { }, }; +export const WithFallbackPlacements = { + args: { + ...defaultProps, + }, + render: (args) => ( +
+
+