Dropdown overlay support function callback (#14003)

* Dropdown's overlay prop support function callback.
* Dropdown 的 overlay 属性支持函数调用。
pull/13779/head^2
zombieJ 6 years ago committed by GitHub
parent 192e188fe8
commit 144b0f4c60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,9 +16,12 @@ const Placements = tuple(
'bottomRight',
);
type Placement = (typeof Placements)[number];
type OverlayFunc = () => React.ReactNode;
export interface DropDownProps {
trigger?: ('click' | 'hover' | 'contextMenu')[];
overlay: React.ReactNode;
overlay: React.ReactNode | OverlayFunc;
onVisibleChange?: (visible?: boolean) => void;
visible?: boolean;
disabled?: boolean;
@ -55,16 +58,49 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
return 'slide-up';
}
componentDidMount() {
renderOverlay = (prefixCls: string) => {
// rc-dropdown already can process the function of overlay, but we have check logic here.
// So we need render the element to check and pass back to rc-dropdown.
const { overlay } = this.props;
if (overlay) {
const overlayProps = (overlay as React.ReactElement<any>).props;
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
let overlayNode;
if (typeof overlay === 'function') {
overlayNode = (overlay as OverlayFunc)();
} else {
overlayNode = overlay;
}
}
overlayNode = React.Children.only(overlayNode);
const overlayProps = overlayNode.props;
// Warning if use other mode
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
// menu cannot be selectable in dropdown defaultly
// menu should be focusable in dropdown defaultly
const { selectable = false, focusable = true } = overlayProps;
const expandIcon = (
<span className={`${prefixCls}-menu-submenu-arrow`}>
<Icon type="right" className={`${prefixCls}-menu-submenu-arrow-icon`} />
</span>
);
const fixedModeOverlay =
typeof overlayNode.type === 'string'
? overlay
: React.cloneElement(overlayNode, {
mode: 'vertical',
selectable,
focusable,
expandIcon,
});
return fixedModeOverlay;
};
renderDropDown = ({
getPopupContainer: getContextPopupContainer,
@ -73,7 +109,6 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
const {
prefixCls: customizePrefixCls,
children,
overlay: overlayElements,
trigger,
disabled,
getPopupContainer,
@ -81,31 +116,11 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
const child = React.Children.only(children);
const overlay = React.Children.only(overlayElements);
const dropdownTrigger = React.cloneElement(child, {
className: classNames(child.props.className, `${prefixCls}-trigger`),
disabled,
});
// menu cannot be selectable in dropdown defaultly
// menu should be focusable in dropdown defaultly
const { selectable = false, focusable = true } = overlay.props;
const expandIcon = (
<span className={`${prefixCls}-menu-submenu-arrow`}>
<Icon type="right" className={`${prefixCls}-menu-submenu-arrow-icon`} />
</span>
);
const fixedModeOverlay =
typeof overlay.type === 'string'
? overlay
: React.cloneElement(overlay, {
mode: 'vertical',
selectable,
focusable,
expandIcon,
});
const triggerActions = disabled ? [] : trigger;
let alignPoint;
@ -121,7 +136,7 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
getPopupContainer={getPopupContainer || getContextPopupContainer}
transitionName={this.getTransitionName()}
trigger={triggerActions}
overlay={fixedModeOverlay}
overlay={() => this.renderOverlay(prefixCls)}
>
{dropdownTrigger}
</RcDropdown>

@ -18,7 +18,7 @@ If there are too many operations to display, you can wrap them in a `Dropdown`.
| -------- | ----------- | ---- | ------- |
| disabled | whether the dropdown menu is disabled | boolean | - |
| getPopupContainer | to set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` |
| overlay | the dropdown menu | [Menu](/components/menu) | - |
| overlay | the dropdown menu | [Menu](/components/menu) \| () => Menu | - |
| overlayClassName | Class name of the dropdown root element | string | - |
| overlayStyle | Style of the dropdown root element | object | - |
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |

@ -19,7 +19,7 @@ title: Dropdown
| --- | --- | --- | --- |
| disabled | 菜单是否禁用 | boolean | - |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` |
| overlay | 菜单 | [Menu](/components/menu) | - |
| overlay | 菜单 | [Menu](/components/menu) \| () => Menu | - |
| overlayClassName | 下拉根元素的类名称 | string | - |
| overlayStyle | 下拉根元素的样式 | object | - |
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |

@ -61,7 +61,7 @@
"rc-collapse": "~1.10.0",
"rc-dialog": "~7.3.0",
"rc-drawer": "~1.7.6",
"rc-dropdown": "~2.3.0",
"rc-dropdown": "~2.4.1",
"rc-editor-mention": "^1.1.7",
"rc-form": "^2.4.0",
"rc-input-number": "~4.3.7",

Loading…
Cancel
Save