diff --git a/README.md b/README.md
index d265ba0..ff0e824 100644
--- a/README.md
+++ b/README.md
@@ -73,9 +73,13 @@ Additional props are passed to the underlying [`@rc-component/trigger`](https://
| prefixCls | Component class name prefix | string | `rc-dropdown` |
| transitionName | Popup transition class name | string | - |
| trigger | Trigger action | `ActionType \| ActionType[]` | `['hover']` |
-| visible | Controlled visible state | boolean | - |
+| open | Controlled open state | boolean | - |
| onOverlayClick | Callback when overlay is clicked | `(event: Event) => void` | - |
-| onVisibleChange | Callback when visibility changes | `(visible: boolean) => void` | - |
+| onOpenChange | Callback when the open state changes | `(open: boolean) => void` | - |
+
+`visible` and `onVisibleChange` have been removed. Use `open` and `onOpenChange` instead. This is a breaking API change; callers must migrate when upgrading.
+
+Clicking the overlay closes an uncontrolled dropdown and calls `onOverlayClick`, without calling `onOpenChange`.
## Development
diff --git a/README.zh-CN.md b/README.zh-CN.md
index ed96f31..f0a7efc 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -73,9 +73,13 @@ npm start
| prefixCls | 组件类名前缀 | string | `rc-dropdown` |
| transitionName | 弹层过渡类名 | string | - |
| trigger | 触发动作 | `ActionType \| ActionType[]` | `['hover']` |
-| visible | 受控可见状态 | boolean | - |
+| open | 受控可见状态 | boolean | - |
| onOverlayClick | 点击下拉菜单内容时的回调 | `(event: Event) => void` | - |
-| onVisibleChange | 可见性变化时的回调 | `(visible: boolean) => void` | - |
+| onOpenChange | 可见性变化时的回调 | `(open: boolean) => void` | - |
+
+`visible` 和 `onVisibleChange` 已移除,请改用 `open` 和 `onOpenChange`。这是不兼容的 API 变更,调用方升级时需同步迁移。
+
+点击浮层会关闭非受控下拉菜单并调用 `onOverlayClick`,不会调用 `onOpenChange`。
## 本地开发
diff --git a/docs/examples/arrow.jsx b/docs/examples/arrow.jsx
index 224fc06..e291a92 100644
--- a/docs/examples/arrow.jsx
+++ b/docs/examples/arrow.jsx
@@ -7,8 +7,8 @@ function onSelect({ key }) {
console.log(`${key} selected`);
}
-function onVisibleChange(visible) {
- console.log(visible);
+function onOpenChange(open) {
+ console.log(open);
}
const menu = (
@@ -30,7 +30,7 @@ export default function Arrow() {
trigger={['click']}
overlay={menu}
animation="slide-up"
- onVisibleChange={onVisibleChange}
+ onOpenChange={onOpenChange}
>
@@ -42,7 +42,7 @@ export default function Arrow() {
trigger={['click']}
overlay={menu}
animation="slide-up"
- onVisibleChange={onVisibleChange}
+ onOpenChange={onOpenChange}
>
diff --git a/docs/examples/multiple.jsx b/docs/examples/multiple.jsx
index 34f33df..b117ddf 100644
--- a/docs/examples/multiple.jsx
+++ b/docs/examples/multiple.jsx
@@ -5,13 +5,13 @@ import '../../assets/index.less';
class Test extends Component {
state = {
- visible: false,
+ open: false,
};
- onVisibleChange = (visible) => {
- console.log('visible', visible);
+ onOpenChange = (open) => {
+ console.log('open', open);
this.setState({
- visible,
+ open,
});
};
@@ -24,7 +24,7 @@ class Test extends Component {
confirm = () => {
console.log(this.selected);
this.setState({
- visible: false,
+ open: false,
});
};
@@ -57,8 +57,8 @@ class Test extends Component {
return (
(
@@ -29,7 +29,7 @@ export default function OverlayCallback() {
trigger={['click']}
overlay={menuCallback}
animation="slide-up"
- onVisibleChange={onVisibleChange}
+ onOpenChange={onOpenChange}
>
diff --git a/docs/examples/simple.jsx b/docs/examples/simple.jsx
index f2f0fec..a672dbb 100644
--- a/docs/examples/simple.jsx
+++ b/docs/examples/simple.jsx
@@ -8,8 +8,8 @@ function onSelect({ key }) {
console.log(`${key} selected`);
}
-function onVisibleChange(visible) {
- console.log(visible);
+function onOpenChange(open) {
+ console.log(open);
}
const menu = (
@@ -31,7 +31,7 @@ export default function Simple() {
trigger={['click']}
overlay={menu}
animation="slide-up"
- onVisibleChange={onVisibleChange}
+ onOpenChange={onOpenChange}
>
diff --git a/src/Dropdown.tsx b/src/Dropdown.tsx
index f2deba4..6854bae 100644
--- a/src/Dropdown.tsx
+++ b/src/Dropdown.tsx
@@ -25,7 +25,7 @@ export interface DropdownProps
> {
minOverlayWidthMatchTrigger?: boolean;
arrow?: boolean;
- onVisibleChange?: (visible: boolean) => void;
+ onOpenChange?: (open: boolean) => void;
onOverlayClick?: (e: Event) => void;
prefixCls?: string;
transitionName?: string;
@@ -41,7 +41,7 @@ export interface DropdownProps
alignPoint?: boolean;
showAction?: ActionType[];
hideAction?: ActionType[];
- visible?: boolean;
+ open?: boolean;
autoFocus?: boolean;
}
@@ -59,18 +59,18 @@ const Dropdown = React.forwardRef((props, ref) => {
hideAction,
overlayClassName,
overlayStyle,
- visible,
+ open,
trigger = ['hover'],
autoFocus,
overlay,
children,
- onVisibleChange,
+ onOpenChange,
disabled,
...otherProps
} = props as DropdownProps & { disabled?: boolean };
- const [triggerVisible, setTriggerVisible] = React.useState();
- const mergedVisible = 'visible' in props ? visible : triggerVisible;
+ const [triggerOpen, setTriggerOpen] = React.useState();
+ const mergedOpen = 'open' in props ? open : triggerOpen;
const mergedMotionName = animation
? `${prefixCls}-${animation}`
: transitionName;
@@ -80,22 +80,22 @@ const Dropdown = React.forwardRef((props, ref) => {
const childRef = React.useRef(null);
React.useImperativeHandle(ref, () => triggerRef.current);
- const handleVisibleChange = (newVisible: boolean) => {
- setTriggerVisible(newVisible);
- onVisibleChange?.(newVisible);
+ const handleOpenChange = (newOpen: boolean) => {
+ setTriggerOpen(newOpen);
+ onOpenChange?.(newOpen);
};
useAccessibility({
- visible: mergedVisible,
+ open: mergedOpen,
triggerRef: childRef,
- onVisibleChange: handleVisibleChange,
+ onOpenChange: handleOpenChange,
autoFocus,
overlayRef,
});
const onClick = (e) => {
const { onOverlayClick } = props;
- setTriggerVisible(false);
+ setTriggerOpen(false);
if (onOverlayClick) {
onOverlayClick(e);
@@ -140,7 +140,7 @@ const Dropdown = React.forwardRef((props, ref) => {
>;
const childClassName = clsx(
elementChild.props?.className,
- mergedVisible && getOpenClassName(),
+ mergedOpen && getOpenClassName(),
);
const triggerChildProps: React.HTMLAttributes &
React.RefAttributes = {
@@ -148,21 +148,20 @@ const Dropdown = React.forwardRef((props, ref) => {
ref: composeRef(childRef, getNodeRef(elementChild)),
};
- const childrenNode =
- supportRef(elementChild) ? (
- React.cloneElement(
- elementChild as React.ReactElement<
- React.HTMLAttributes & React.RefAttributes
- >,
- triggerChildProps,
- )
- ) : (
-
- {React.cloneElement(elementChild, {
- className: childClassName,
- })}
-
- );
+ const childrenNode = supportRef(elementChild) ? (
+ React.cloneElement(
+ elementChild as React.ReactElement<
+ React.HTMLAttributes & React.RefAttributes
+ >,
+ triggerChildProps,
+ )
+ ) : (
+
+ {React.cloneElement(elementChild, {
+ className: childClassName,
+ })}
+
+ );
let triggerHideAction = hideAction;
if (!triggerHideAction && trigger.indexOf('contextMenu') !== -1) {
@@ -185,10 +184,10 @@ const Dropdown = React.forwardRef((props, ref) => {
popupPlacement={placement}
popupAlign={align}
popupMotion={{ motionName: mergedMotionName }}
- popupVisible={mergedVisible}
+ popupVisible={mergedOpen}
stretch={getMinOverlayWidthMatchTrigger() ? 'minWidth' : ''}
popup={getMenuElementOrLambda()}
- onOpenChange={handleVisibleChange}
+ onOpenChange={handleOpenChange}
onPopupClick={onClick}
getPopupContainer={getPopupContainer}
>
diff --git a/src/hooks/useAccessibility.ts b/src/hooks/useAccessibility.ts
index 2fdc744..7f31291 100644
--- a/src/hooks/useAccessibility.ts
+++ b/src/hooks/useAccessibility.ts
@@ -4,26 +4,26 @@ import * as React from 'react';
const { ESC, TAB } = KeyCode;
interface UseAccessibilityProps {
- visible: boolean;
+ open: boolean;
triggerRef: React.RefObject;
- onVisibleChange?: (visible: boolean) => void;
+ onOpenChange?: (open: boolean) => void;
autoFocus?: boolean;
overlayRef?: React.RefObject;
}
export default function useAccessibility({
- visible,
+ open,
triggerRef,
- onVisibleChange,
+ onOpenChange,
autoFocus,
overlayRef,
}: UseAccessibilityProps) {
const focusMenuRef = React.useRef(false);
const handleCloseMenuAndReturnFocus = () => {
- if (visible) {
+ if (open) {
triggerRef.current?.focus?.();
- onVisibleChange?.(false);
+ onOpenChange?.(false);
}
};
@@ -58,7 +58,7 @@ export default function useAccessibility({
};
React.useEffect(() => {
- if (visible) {
+ if (open) {
window.addEventListener('keydown', handleKeyDown);
if (autoFocus) {
// FIXME: hack with raf
@@ -72,5 +72,5 @@ export default function useAccessibility({
return () => {
focusMenuRef.current = false;
};
- }, [visible]); // eslint-disable-line react-hooks/exhaustive-deps
+ }, [open]); // eslint-disable-line react-hooks/exhaustive-deps
}
diff --git a/tests/__snapshots__/basic.test.tsx.snap b/tests/__snapshots__/basic.test.tsx.snap
index ad46ebc..c771852 100644
--- a/tests/__snapshots__/basic.test.tsx.snap
+++ b/tests/__snapshots__/basic.test.tsx.snap
@@ -20,7 +20,7 @@ exports[`dropdown simply works 1`] = `
>