Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 6 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`。

## 本地开发

Expand Down
8 changes: 4 additions & 4 deletions docs/examples/arrow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand All @@ -30,7 +30,7 @@ export default function Arrow() {
trigger={['click']}
overlay={menu}
animation="slide-up"
onVisibleChange={onVisibleChange}
onOpenChange={onOpenChange}
>
<button style={{ width: 100 }}>open</button>
</Dropdown>
Expand All @@ -42,7 +42,7 @@ export default function Arrow() {
trigger={['click']}
overlay={menu}
animation="slide-up"
onVisibleChange={onVisibleChange}
onOpenChange={onOpenChange}
>
<button style={{ width: 100 }}>open</button>
</Dropdown>
Expand Down
14 changes: 7 additions & 7 deletions docs/examples/multiple.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
};

Expand All @@ -24,7 +24,7 @@ class Test extends Component {
confirm = () => {
console.log(this.selected);
this.setState({
visible: false,
open: false,
});
};

Expand Down Expand Up @@ -57,8 +57,8 @@ class Test extends Component {
return (
<Dropdown
trigger={['click']}
onVisibleChange={this.onVisibleChange}
visible={this.state.visible}
onOpenChange={this.onOpenChange}
open={this.state.open}
closeOnSelect={false}
overlay={menu}
animation="slide-up"
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/overlay-callback.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ function onSelect({ key }) {
console.log(`${key} selected`);
}

function onVisibleChange(visible) {
console.log(visible);
function onOpenChange(open) {
console.log(open);
}

const menuCallback = () => (
Expand All @@ -29,7 +29,7 @@ export default function OverlayCallback() {
trigger={['click']}
overlay={menuCallback}
animation="slide-up"
onVisibleChange={onVisibleChange}
onOpenChange={onOpenChange}
>
<button style={{ width: 100 }}>open</button>
</Dropdown>
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/simple.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand All @@ -31,7 +31,7 @@ export default function Simple() {
trigger={['click']}
overlay={menu}
animation="slide-up"
onVisibleChange={onVisibleChange}
onOpenChange={onOpenChange}
>
<button style={{ width: 100 }}>open</button>
</Dropdown>
Expand Down
59 changes: 29 additions & 30 deletions src/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -41,7 +41,7 @@ export interface DropdownProps
alignPoint?: boolean;
showAction?: ActionType[];
hideAction?: ActionType[];
visible?: boolean;
open?: boolean;
autoFocus?: boolean;
}

Expand All @@ -59,18 +59,18 @@ const Dropdown = React.forwardRef<TriggerRef, DropdownProps>((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<boolean>();
const mergedVisible = 'visible' in props ? visible : triggerVisible;
const [triggerOpen, setTriggerOpen] = React.useState<boolean>();
const mergedOpen = 'open' in props ? open : triggerOpen;
const mergedMotionName = animation
? `${prefixCls}-${animation}`
: transitionName;
Expand All @@ -80,22 +80,22 @@ const Dropdown = React.forwardRef<TriggerRef, DropdownProps>((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);
Expand Down Expand Up @@ -140,29 +140,28 @@ const Dropdown = React.forwardRef<TriggerRef, DropdownProps>((props, ref) => {
>;
const childClassName = clsx(
elementChild.props?.className,
mergedVisible && getOpenClassName(),
mergedOpen && getOpenClassName(),
);
const triggerChildProps: React.HTMLAttributes<HTMLElement> &
React.RefAttributes<HTMLElement> = {
className: childClassName,
ref: composeRef(childRef, getNodeRef(elementChild)),
};

const childrenNode =
supportRef(elementChild) ? (
React.cloneElement(
elementChild as React.ReactElement<
React.HTMLAttributes<HTMLElement> & React.RefAttributes<HTMLElement>
>,
triggerChildProps,
)
) : (
<span className={childClassName} ref={childRef}>
{React.cloneElement(elementChild, {
className: childClassName,
})}
</span>
);
const childrenNode = supportRef(elementChild) ? (
React.cloneElement(
elementChild as React.ReactElement<
React.HTMLAttributes<HTMLElement> & React.RefAttributes<HTMLElement>
>,
triggerChildProps,
)
) : (
<span className={childClassName} ref={childRef}>
{React.cloneElement(elementChild, {
className: childClassName,
})}
</span>
);

let triggerHideAction = hideAction;
if (!triggerHideAction && trigger.indexOf('contextMenu') !== -1) {
Expand All @@ -185,10 +184,10 @@ const Dropdown = React.forwardRef<TriggerRef, DropdownProps>((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}
>
Expand Down
16 changes: 8 additions & 8 deletions src/hooks/useAccessibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import * as React from 'react';
const { ESC, TAB } = KeyCode;

interface UseAccessibilityProps {
visible: boolean;
open: boolean;
triggerRef: React.RefObject<any>;
onVisibleChange?: (visible: boolean) => void;
onOpenChange?: (open: boolean) => void;
autoFocus?: boolean;
overlayRef?: React.RefObject<any>;
}

export default function useAccessibility({
visible,
open,
triggerRef,
onVisibleChange,
onOpenChange,
autoFocus,
overlayRef,
}: UseAccessibilityProps) {
const focusMenuRef = React.useRef<boolean>(false);

const handleCloseMenuAndReturnFocus = () => {
if (visible) {
if (open) {
triggerRef.current?.focus?.();
onVisibleChange?.(false);
onOpenChange?.(false);
}
};

Expand Down Expand Up @@ -58,7 +58,7 @@ export default function useAccessibility({
};

React.useEffect(() => {
if (visible) {
if (open) {
window.addEventListener('keydown', handleKeyDown);
if (autoFocus) {
// FIXME: hack with raf
Expand All @@ -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
}
4 changes: 2 additions & 2 deletions tests/__snapshots__/basic.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ exports[`dropdown simply works 1`] = `
>
<li
class="rc-menu-item"
data-menu-id="rc-menu-uuid-1"
data-menu-id="rc-menu-uuid-test-id-1"
role="menuitem"
tabindex="-1"
>
Expand All @@ -36,7 +36,7 @@ exports[`dropdown simply works 1`] = `
/>
<li
class="rc-menu-item"
data-menu-id="rc-menu-uuid-2"
data-menu-id="rc-menu-uuid-test-id-2"
role="menuitem"
tabindex="-1"
>
Expand Down
Loading
Loading