From aa5ea19a3c990f8f6d47abacf321f0cbce67b927 Mon Sep 17 00:00:00 2001 From: Ryo Matsukawa <76232929+ryo-manba@users.noreply.github.com> Date: Tue, 10 Dec 2024 22:07:50 +0900 Subject: [PATCH] fix(dropdown): correct initial animation direction to match fallback placement (#4288) * fix(dropdown): correct initial animation direction * chore: add changeset * fix: typo --- .changeset/cyan-dodos-glow.md | 5 ++ packages/components/dropdown/package.json | 1 + .../components/dropdown/src/use-dropdown.ts | 24 +++++++-- .../dropdown/stories/dropdown.stories.tsx | 35 +++++++++++- pnpm-lock.yaml | 54 ++++--------------- 5 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 .changeset/cyan-dodos-glow.md diff --git a/.changeset/cyan-dodos-glow.md b/.changeset/cyan-dodos-glow.md new file mode 100644 index 0000000000..c773d28088 --- /dev/null +++ b/.changeset/cyan-dodos-glow.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/dropdown": patch +--- + +Fix initial animation direction to match fallback placement (#4251) diff --git a/packages/components/dropdown/package.json b/packages/components/dropdown/package.json index de9882bb41..3f26c61da3 100644 --- a/packages/components/dropdown/package.json +++ b/packages/components/dropdown/package.json @@ -48,6 +48,7 @@ "@nextui-org/shared-utils": "workspace:*", "@react-aria/focus": "3.19.0", "@react-aria/menu": "3.16.0", + "@react-aria/overlays": "3.24.0", "@react-aria/utils": "3.26.0", "@react-stately/menu": "3.9.0", "@react-types/menu": "3.9.13" diff --git a/packages/components/dropdown/src/use-dropdown.ts b/packages/components/dropdown/src/use-dropdown.ts index 4deb06b42b..df74fed07b 100644 --- a/packages/components/dropdown/src/use-dropdown.ts +++ b/packages/components/dropdown/src/use-dropdown.ts @@ -9,11 +9,12 @@ import {useMenuTrigger} from "@react-aria/menu"; import {dropdown} from "@nextui-org/theme"; import {clsx} from "@nextui-org/shared-utils"; import {ReactRef, mergeRefs} from "@nextui-org/react-utils"; -import {ariaShouldCloseOnInteractOutside} from "@nextui-org/aria-utils"; +import {ariaShouldCloseOnInteractOutside, toReactAriaPlacement} from "@nextui-org/aria-utils"; import {useMemo, useRef} from "react"; import {mergeProps} from "@react-aria/utils"; import {MenuProps} from "@nextui-org/menu"; import {CollectionElement} from "@react-types/shared"; +import {useOverlayPosition} from "@react-aria/overlays"; interface Props extends HTMLNextUIProps<"div"> { /** @@ -77,6 +78,8 @@ const getCloseOnSelect = ( return props?.closeOnSelect; }; +const DEFAULT_PLACEMENT = "bottom"; + export function useDropdown(props: UseDropdownProps): UseDropdownReturn { const globalContext = useProviderContext(); @@ -89,13 +92,17 @@ export function useDropdown(props: UseDropdownProps): UseDropdownReturn { isDisabled, type = "menu", trigger = "press", - placement = "bottom", + placement: placementProp = DEFAULT_PLACEMENT, closeOnSelect = true, shouldBlockScroll = true, classNames: classNamesProp, disableAnimation = globalContext?.disableAnimation ?? false, onClose, className, + containerPadding = 12, + offset = 7, + crossOffset = 0, + shouldFlip = true, ...otherProps } = props; @@ -132,6 +139,17 @@ export function useDropdown(props: UseDropdownProps): UseDropdownReturn { [className], ); + const {placement} = useOverlayPosition({ + isOpen: state.isOpen, + targetRef: triggerRef, + overlayRef: popoverRef, + placement: toReactAriaPlacement(placementProp), + offset, + crossOffset, + shouldFlip, + containerPadding, + }); + const onMenuAction = (menuCloseOnSelect?: boolean) => { if (menuCloseOnSelect !== undefined && !menuCloseOnSelect) { return; @@ -146,7 +164,7 @@ export function useDropdown(props: UseDropdownProps): UseDropdownReturn { return { state, - placement, + placement: placement || DEFAULT_PLACEMENT, ref: popoverRef, disableAnimation, shouldBlockScroll, diff --git a/packages/components/dropdown/stories/dropdown.stories.tsx b/packages/components/dropdown/stories/dropdown.stories.tsx index 0c26be0ad1..6a4f7c6939 100644 --- a/packages/components/dropdown/stories/dropdown.stories.tsx +++ b/packages/components/dropdown/stories/dropdown.stories.tsx @@ -137,10 +137,15 @@ const items = [ }, ]; -const Template = ({color, variant, ...args}: DropdownProps & DropdownMenuProps) => ( +const Template = ({ + color, + variant, + label = "Trigger", + ...args +}: DropdownProps & DropdownMenuProps & {label: string}) => ( - + New file @@ -782,3 +787,29 @@ export const ItemCloseOnSelect = { ...defaultProps, }, }; + +export const WithFallbackPlacements = { + args: { + ...defaultProps, + }, + render: (args) => ( +
+
+