Skip to content

Commit

Permalink
fix(popover): correct initial animation direction to match fallback p…
Browse files Browse the repository at this point in the history
…lacement (#4460)

* fix(popover): correct initial animation direction to match fallback placement

* fix: type error

* chore: add changeset
  • Loading branch information
ryo-manba authored Dec 30, 2024
1 parent 4f0ef58 commit fb46df2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-goats-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nextui-org/popover": patch
---

Fix initial animation direction to match fallback placement (#4290)
28 changes: 9 additions & 19 deletions packages/components/popover/src/use-popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -81,6 +81,8 @@ export interface Props extends HTMLNextUIProps<"div"> {
onClose?: () => void;
}

const DEFAULT_PLACEMENT = "top";

export type UsePopoverProps = Props &
Omit<ReactAriaPopoverProps, "triggerRef" | "popoverRef"> &
OverlayTriggerProps &
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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: {
Expand All @@ -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(
Expand Down Expand Up @@ -317,7 +307,7 @@ export function usePopover(originalProps: UsePopoverProps) {
classNames,
showArrow,
triggerRef,
placement,
placement: placement || DEFAULT_PLACEMENT,
isNonModal,
popoverRef: domRef,
portalContainer,
Expand Down
30 changes: 28 additions & 2 deletions packages/components/popover/stories/popover.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ const content = (
</PopoverContent>
);

const Template = (args: PopoverProps) => {
const Template = ({label = "Open Popover", ...args}: PopoverProps & {label: string}) => {
return (
<Popover {...args}>
<PopoverTrigger>
<Button>Open Popover</Button>
<Button>{label}</Button>
</PopoverTrigger>
{content}
</Popover>
Expand Down Expand Up @@ -581,6 +581,32 @@ export const CustomMotion = {
},
};

export const WithFallbackPlacements = {
args: {
...defaultProps,
},
render: (args) => (
<div className="relative h-screen w-screen">
<div className="absolute top-0 left-0 p-8 flex gap-4">
<Template {...args} label="placement: top" placement="top" />
<Template {...args} label="placement: bottom" placement="bottom" />
</div>
<div className="absolute bottom-0 left-0 p-8 flex gap-4">
<Template {...args} label="placement: bottom" placement="bottom" />
<Template {...args} label="placement: top" placement="top" />
</div>
<div className="absolute left-0 top-1/2 -translate-y-1/2 p-8 flex flex-col gap-4">
<Template {...args} label="placement: left" placement="left" />
<Template {...args} label="placement: right" placement="right" />
</div>
<div className="absolute right-0 top-1/2 -translate-y-1/2 p-8 flex flex-col gap-4">
<Template {...args} label="placement: right" placement="right" />
<Template {...args} label="placement: left" placement="left" />
</div>
</div>
),
};

export const WithShouldBlockScroll = {
render: (args) => {
return (
Expand Down

0 comments on commit fb46df2

Please sign in to comment.