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`] = ` >