fix(dropdown): correct initial animation direction to match fallback placement (#4288)

* fix(dropdown): correct initial animation direction

* chore: add changeset

* fix: typo
This commit is contained in:
Ryo Matsukawa 2024-12-10 22:07:50 +09:00 committed by GitHub
parent 1485eca48f
commit aa5ea19a3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 71 additions and 48 deletions

View File

@ -0,0 +1,5 @@
---
"@nextui-org/dropdown": patch
---
Fix initial animation direction to match fallback placement (#4251)

View File

@ -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"

View File

@ -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 = <T extends object>(
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,

View File

@ -137,10 +137,15 @@ const items = [
},
];
const Template = ({color, variant, ...args}: DropdownProps & DropdownMenuProps) => (
const Template = ({
color,
variant,
label = "Trigger",
...args
}: DropdownProps & DropdownMenuProps & {label: string}) => (
<Dropdown {...args}>
<DropdownTrigger>
<Button>Trigger</Button>
<Button>{label}</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Actions" color={color} variant={variant}>
<DropdownItem key="new">New file</DropdownItem>
@ -782,3 +787,29 @@ export const ItemCloseOnSelect = {
...defaultProps,
},
};
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>
),
};

54
pnpm-lock.yaml generated
View File

@ -1581,6 +1581,9 @@ importers:
'@react-aria/menu':
specifier: 3.16.0
version: 3.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@react-aria/overlays':
specifier: 3.24.0
version: 3.24.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@react-aria/utils':
specifier: 3.26.0
version: 3.26.0(react@18.2.0)
@ -3318,7 +3321,7 @@ importers:
version: 18.2.0
tailwind-variants:
specifier: ^0.1.20
version: 0.1.20(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5)))
version: 0.1.20(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.6.3)))
packages/core/theme:
dependencies:
@ -3345,7 +3348,7 @@ importers:
version: 2.5.4
tailwind-variants:
specifier: ^0.1.20
version: 0.1.20(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5)))
version: 0.1.20(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.6.3)))
devDependencies:
'@types/color':
specifier: ^3.0.3
@ -3358,7 +3361,7 @@ importers:
version: 2.2.0
tailwindcss:
specifier: ^3.4.0
version: 3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5))
version: 3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.6.3))
packages/hooks/use-aria-accordion:
dependencies:
@ -26223,14 +26226,6 @@ snapshots:
postcss: 8.4.49
ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5)
postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5)):
dependencies:
lilconfig: 3.1.2
yaml: 2.6.1
optionalDependencies:
postcss: 8.4.49
ts-node: 10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5)
postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.2.5)(typescript@5.6.3)):
dependencies:
lilconfig: 3.1.2
@ -27782,10 +27777,10 @@ snapshots:
tailwind-merge: 1.14.0
tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.2.5)(typescript@5.6.3))
tailwind-variants@0.1.20(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5))):
tailwind-variants@0.1.20(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.6.3))):
dependencies:
tailwind-merge: 1.14.0
tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5))
tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.6.3))
tailwindcss@3.4.14(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.2.5)(typescript@5.6.3)):
dependencies:
@ -27814,33 +27809,6 @@ snapshots:
transitivePeerDependencies:
- ts-node
tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5)):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
chokidar: 3.6.0
didyoumean: 1.2.2
dlv: 1.1.3
fast-glob: 3.3.2
glob-parent: 6.0.2
is-glob: 4.0.3
jiti: 1.21.6
lilconfig: 2.1.0
micromatch: 4.0.8
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.1.1
postcss: 8.4.49
postcss-import: 15.1.0(postcss@8.4.49)
postcss-js: 4.0.1(postcss@8.4.49)
postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@15.14.9)(typescript@4.9.5))
postcss-nested: 6.2.0(postcss@8.4.49)
postcss-selector-parser: 6.1.2
resolve: 1.22.8
sucrase: 3.35.0
transitivePeerDependencies:
- ts-node
tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.2(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.6.3)):
dependencies:
'@alloc/quick-lru': 5.2.0
@ -27928,14 +27896,14 @@ snapshots:
'@swc/core': 1.9.2(@swc/helpers@0.5.15)
esbuild: 0.15.18
terser-webpack-plugin@5.3.10(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack@5.96.1(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack-cli@3.3.12(webpack@5.96.1))):
terser-webpack-plugin@5.3.10(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack@5.96.1(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.15.18)(webpack-cli@3.3.12)):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 3.3.0
serialize-javascript: 6.0.2
terser: 5.36.0
webpack: 5.96.1(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack-cli@3.3.12(webpack@5.96.1))
webpack: 5.96.1(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.15.18)(webpack-cli@3.3.12)
optionalDependencies:
'@swc/core': 1.9.2(@swc/helpers@0.5.15)
esbuild: 0.21.5
@ -28742,7 +28710,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
terser-webpack-plugin: 5.3.10(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack@5.96.1(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack-cli@3.3.12(webpack@5.96.1)))
terser-webpack-plugin: 5.3.10(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.21.5)(webpack@5.96.1(@swc/core@1.9.2(@swc/helpers@0.5.15))(esbuild@0.15.18)(webpack-cli@3.3.12))
watchpack: 2.4.2
webpack-sources: 3.2.3
optionalDependencies: