Skip to content

Commit fb46df2

Browse files
authored
fix(popover): correct initial animation direction to match fallback placement (#4460)
* fix(popover): correct initial animation direction to match fallback placement * fix: type error * chore: add changeset
1 parent 4f0ef58 commit fb46df2

File tree

3 files changed

+42
-21
lines changed

3 files changed

+42
-21
lines changed

.changeset/witty-goats-trade.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/popover": patch
3+
---
4+
5+
Fix initial animation direction to match fallback placement (#4290)

packages/components/popover/src/use-popover.ts

+9-19
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
PropGetter,
1515
useProviderContext,
1616
} from "@nextui-org/system";
17-
import {getArrowPlacement, getShouldUseAxisPlacement} from "@nextui-org/aria-utils";
17+
import {getArrowPlacement} from "@nextui-org/aria-utils";
1818
import {popover} from "@nextui-org/theme";
1919
import {mergeProps, mergeRefs} from "@react-aria/utils";
2020
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@@ -81,6 +81,8 @@ export interface Props extends HTMLNextUIProps<"div"> {
8181
onClose?: () => void;
8282
}
8383

84+
const DEFAULT_PLACEMENT = "top";
85+
8486
export type UsePopoverProps = Props &
8587
Omit<ReactAriaPopoverProps, "triggerRef" | "popoverRef"> &
8688
OverlayTriggerProps &
@@ -110,7 +112,7 @@ export function usePopover(originalProps: UsePopoverProps) {
110112
portalContainer,
111113
updatePositionDeps,
112114
dialogProps: dialogPropsProp,
113-
placement: placementProp = "top",
115+
placement: placementProp = DEFAULT_PLACEMENT,
114116
triggerType = "dialog",
115117
showArrow = false,
116118
offset = 7,
@@ -150,11 +152,7 @@ export function usePopover(originalProps: UsePopoverProps) {
150152

151153
const state = stateProp || innerState;
152154

153-
const {
154-
popoverProps,
155-
underlayProps,
156-
placement: ariaPlacement,
157-
} = useReactAriaPopover(
155+
const {popoverProps, underlayProps, placement} = useReactAriaPopover(
158156
{
159157
triggerRef,
160158
isNonModal,
@@ -208,7 +206,7 @@ export function usePopover(originalProps: UsePopoverProps) {
208206
"data-focus": dataAttr(isFocused),
209207
"data-arrow": dataAttr(showArrow),
210208
"data-focus-visible": dataAttr(isFocusVisible),
211-
"data-placement": getArrowPlacement(ariaPlacement || "top", placementProp),
209+
"data-placement": getArrowPlacement(placement || DEFAULT_PLACEMENT, placementProp),
212210
...mergeProps(focusProps, dialogPropsProp, props),
213211
className: slots.base({class: clsx(baseStyles)}),
214212
style: {
@@ -222,18 +220,10 @@ export function usePopover(originalProps: UsePopoverProps) {
222220
"data-slot": "content",
223221
"data-open": dataAttr(state.isOpen),
224222
"data-arrow": dataAttr(showArrow),
225-
"data-placement": getArrowPlacement(ariaPlacement || "top", placementProp),
223+
"data-placement": getArrowPlacement(placement || DEFAULT_PLACEMENT, placementProp),
226224
className: slots.content({class: clsx(classNames?.content, props.className)}),
227225
}),
228-
[slots, state.isOpen, showArrow, ariaPlacement, placementProp, classNames],
229-
);
230-
231-
const placement = useMemo(
232-
() =>
233-
getShouldUseAxisPlacement(ariaPlacement || "top", placementProp)
234-
? ariaPlacement || placementProp
235-
: placementProp,
236-
[ariaPlacement, placementProp],
226+
[slots, state.isOpen, showArrow, placement, placementProp, classNames],
237227
);
238228

239229
const onPress = useCallback(
@@ -317,7 +307,7 @@ export function usePopover(originalProps: UsePopoverProps) {
317307
classNames,
318308
showArrow,
319309
triggerRef,
320-
placement,
310+
placement: placement || DEFAULT_PLACEMENT,
321311
isNonModal,
322312
popoverRef: domRef,
323313
portalContainer,

packages/components/popover/stories/popover.stories.tsx

+28-2
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,11 @@ const content = (
127127
</PopoverContent>
128128
);
129129

130-
const Template = (args: PopoverProps) => {
130+
const Template = ({label = "Open Popover", ...args}: PopoverProps & {label: string}) => {
131131
return (
132132
<Popover {...args}>
133133
<PopoverTrigger>
134-
<Button>Open Popover</Button>
134+
<Button>{label}</Button>
135135
</PopoverTrigger>
136136
{content}
137137
</Popover>
@@ -581,6 +581,32 @@ export const CustomMotion = {
581581
},
582582
};
583583

584+
export const WithFallbackPlacements = {
585+
args: {
586+
...defaultProps,
587+
},
588+
render: (args) => (
589+
<div className="relative h-screen w-screen">
590+
<div className="absolute top-0 left-0 p-8 flex gap-4">
591+
<Template {...args} label="placement: top" placement="top" />
592+
<Template {...args} label="placement: bottom" placement="bottom" />
593+
</div>
594+
<div className="absolute bottom-0 left-0 p-8 flex gap-4">
595+
<Template {...args} label="placement: bottom" placement="bottom" />
596+
<Template {...args} label="placement: top" placement="top" />
597+
</div>
598+
<div className="absolute left-0 top-1/2 -translate-y-1/2 p-8 flex flex-col gap-4">
599+
<Template {...args} label="placement: left" placement="left" />
600+
<Template {...args} label="placement: right" placement="right" />
601+
</div>
602+
<div className="absolute right-0 top-1/2 -translate-y-1/2 p-8 flex flex-col gap-4">
603+
<Template {...args} label="placement: right" placement="right" />
604+
<Template {...args} label="placement: left" placement="left" />
605+
</div>
606+
</div>
607+
),
608+
};
609+
584610
export const WithShouldBlockScroll = {
585611
render: (args) => {
586612
return (

0 commit comments

Comments
 (0)