mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
fix(dropdown): popover and dropdown fixes (#1458)
This commit is contained in:
parent
a17b6c7502
commit
4e94c11528
40
.changeset/violet-zoos-promise.md
Normal file
40
.changeset/violet-zoos-promise.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
"@nextui-org/scroll-shadow": patch
|
||||
"@nextui-org/pagination": patch
|
||||
"@nextui-org/accordion": patch
|
||||
"@nextui-org/checkbox": patch
|
||||
"@nextui-org/dropdown": patch
|
||||
"@nextui-org/progress": patch
|
||||
"@nextui-org/skeleton": patch
|
||||
"@nextui-org/divider": patch
|
||||
"@nextui-org/listbox": patch
|
||||
"@nextui-org/popover": patch
|
||||
"@nextui-org/snippet": patch
|
||||
"@nextui-org/spinner": patch
|
||||
"@nextui-org/tooltip": patch
|
||||
"@nextui-org/avatar": patch
|
||||
"@nextui-org/button": patch
|
||||
"@nextui-org/navbar": patch
|
||||
"@nextui-org/ripple": patch
|
||||
"@nextui-org/select": patch
|
||||
"@nextui-org/spacer": patch
|
||||
"@nextui-org/switch": patch
|
||||
"@nextui-org/badge": patch
|
||||
"@nextui-org/image": patch
|
||||
"@nextui-org/input": patch
|
||||
"@nextui-org/modal": patch
|
||||
"@nextui-org/radio": patch
|
||||
"@nextui-org/table": patch
|
||||
"@nextui-org/card": patch
|
||||
"@nextui-org/chip": patch
|
||||
"@nextui-org/code": patch
|
||||
"@nextui-org/link": patch
|
||||
"@nextui-org/menu": patch
|
||||
"@nextui-org/tabs": patch
|
||||
"@nextui-org/user": patch
|
||||
"@nextui-org/kbd": patch
|
||||
"@nextui-org/react": patch
|
||||
"@nextui-org/theme": patch
|
||||
---
|
||||
|
||||
Fix dropdown trigger events and popover arrow styles
|
||||
@ -2,19 +2,18 @@ import {PopoverContent} from "@nextui-org/popover";
|
||||
import {FocusScope} from "@react-aria/focus";
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {Menu, MenuProps} from "@nextui-org/menu";
|
||||
import {mergeRefs} from "@nextui-org/react-utils";
|
||||
|
||||
import {useDropdownContext} from "./dropdown-context";
|
||||
|
||||
export interface DropdownMenuProps extends Omit<MenuProps, "menuProps"> {}
|
||||
|
||||
const DropdownMenu = forwardRef<"ul", DropdownMenuProps>((props, ref) => {
|
||||
const {menuRef, menuProps} = useDropdownContext();
|
||||
const {getMenuProps} = useDropdownContext();
|
||||
|
||||
return (
|
||||
<PopoverContent>
|
||||
<FocusScope contain restoreFocus>
|
||||
<Menu ref={mergeRefs(ref, menuRef)} menuProps={menuProps} {...props} />
|
||||
<Menu {...getMenuProps(props, ref)} />
|
||||
</FocusScope>
|
||||
</PopoverContent>
|
||||
);
|
||||
|
||||
@ -10,6 +10,7 @@ import {clsx} from "@nextui-org/shared-utils";
|
||||
import {ReactRef, mergeRefs} from "@nextui-org/react-utils";
|
||||
import {useMemo, useRef} from "react";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {MenuProps} from "@nextui-org/menu";
|
||||
|
||||
interface Props extends HTMLNextUIProps<"div"> {
|
||||
/**
|
||||
@ -92,6 +93,15 @@ export function useDropdown(props: UseDropdownProps) {
|
||||
[className],
|
||||
);
|
||||
|
||||
const onMenuAction = (menuCloseOnSelect?: boolean) => {
|
||||
if (menuCloseOnSelect !== undefined && !menuCloseOnSelect) {
|
||||
return;
|
||||
}
|
||||
if (closeOnSelect) {
|
||||
state.close();
|
||||
}
|
||||
};
|
||||
|
||||
const getPopoverProps: PropGetter = (props = {}) => ({
|
||||
state,
|
||||
placement,
|
||||
@ -113,12 +123,24 @@ export function useDropdown(props: UseDropdownProps) {
|
||||
props = {},
|
||||
_ref: Ref<any> | null | undefined = null,
|
||||
) => {
|
||||
// These props are not needed for the menu trigger since it is handled by the popover trigger.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const {onKeyDown, onPress, onPressStart, ...otherMenuTriggerProps} = menuTriggerProps;
|
||||
|
||||
return {
|
||||
...mergeProps(menuTriggerProps, props),
|
||||
...mergeProps(otherMenuTriggerProps, props),
|
||||
ref: mergeRefs(_ref, triggerRef),
|
||||
};
|
||||
};
|
||||
|
||||
const getMenuProps = (props?: Partial<MenuProps>, _ref: Ref<any> | null | undefined = null) => {
|
||||
return {
|
||||
ref: mergeRefs(_ref, menuRef),
|
||||
menuProps,
|
||||
...mergeProps(props, {onAction: () => onMenuAction(props?.closeOnSelect)}),
|
||||
} as MenuProps;
|
||||
};
|
||||
|
||||
return {
|
||||
Component,
|
||||
menuRef,
|
||||
@ -129,6 +151,7 @@ export function useDropdown(props: UseDropdownProps) {
|
||||
autoFocus: state.focusStrategy || true,
|
||||
disableAnimation,
|
||||
getPopoverProps,
|
||||
getMenuProps,
|
||||
getMenuTriggerProps,
|
||||
};
|
||||
}
|
||||
|
||||
@ -73,6 +73,8 @@ const FreeSoloPopover = forwardRef<"div", FreeSoloPopoverProps>((props, ref) =>
|
||||
getArrowProps,
|
||||
} = usePopover({
|
||||
...props,
|
||||
// avoid closing the popover when navigating with the keyboard
|
||||
shouldCloseOnInteractOutside: undefined,
|
||||
ref,
|
||||
});
|
||||
|
||||
|
||||
@ -59,8 +59,8 @@ const PopoverContent = forwardRef<"div", PopoverContentProps>((props, _) => {
|
||||
{!isNonModal && <DismissButton onDismiss={onClose} />}
|
||||
<Component {...getDialogProps(mergeProps(dialogProps, otherProps))} ref={dialogRef}>
|
||||
{typeof children === "function" ? children(titleProps) : children}
|
||||
{arrowContent}
|
||||
</Component>
|
||||
{arrowContent}
|
||||
<DismissButton onDismiss={onClose} />
|
||||
</>
|
||||
);
|
||||
|
||||
@ -50,6 +50,7 @@ export function useReactAriaPopover(
|
||||
shouldCloseOnBlur = true,
|
||||
placement: placementProp = "top",
|
||||
containerPadding,
|
||||
shouldCloseOnInteractOutside,
|
||||
isNonModal: isNonModalProp,
|
||||
isKeyboardDismissDisabled,
|
||||
...otherProps
|
||||
@ -64,6 +65,14 @@ export function useReactAriaPopover(
|
||||
shouldCloseOnBlur,
|
||||
isDismissable: !isNonModal,
|
||||
isKeyboardDismissDisabled,
|
||||
shouldCloseOnInteractOutside: shouldCloseOnInteractOutside
|
||||
? shouldCloseOnInteractOutside
|
||||
: (element) => {
|
||||
// Don't close if the click is within the trigger or the popover itself
|
||||
let trigger = triggerRef?.current;
|
||||
|
||||
return !trigger || !trigger.contains(element);
|
||||
},
|
||||
},
|
||||
popoverRef,
|
||||
);
|
||||
|
||||
@ -99,6 +99,7 @@ export function usePopover(originalProps: UsePopoverProps) {
|
||||
crossOffset = 0,
|
||||
boundaryElement,
|
||||
isKeyboardDismissDisabled,
|
||||
shouldCloseOnInteractOutside,
|
||||
motionProps,
|
||||
className,
|
||||
classNames,
|
||||
@ -148,6 +149,7 @@ export function usePopover(originalProps: UsePopoverProps) {
|
||||
shouldFlip,
|
||||
containerPadding,
|
||||
isKeyboardDismissDisabled,
|
||||
shouldCloseOnInteractOutside,
|
||||
},
|
||||
state,
|
||||
);
|
||||
@ -194,7 +196,7 @@ export function usePopover(originalProps: UsePopoverProps) {
|
||||
(props = {}, _ref: Ref<any> | null | undefined = null) => {
|
||||
return {
|
||||
"aria-haspopup": "dialog",
|
||||
...mergeProps(!triggerRefProp ? triggerProps : {}, props),
|
||||
...mergeProps(triggerProps, props),
|
||||
className: slots.trigger({class: clsx(classNames?.trigger, props.className)}),
|
||||
ref: mergeRefs(_ref, triggerRef),
|
||||
};
|
||||
|
||||
@ -22,7 +22,6 @@ const popover = tv({
|
||||
base: [
|
||||
"z-10",
|
||||
"relative",
|
||||
"overflow-hidden",
|
||||
"inline-flex",
|
||||
"flex-col",
|
||||
"items-center",
|
||||
@ -39,7 +38,7 @@ const popover = tv({
|
||||
trigger: ["z-10"],
|
||||
backdrop: ["hidden"],
|
||||
arrow: [
|
||||
"-z-10",
|
||||
"z-[-1]",
|
||||
"absolute",
|
||||
"rotate-45",
|
||||
"bg-inherit",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user