feat: update vc-menu
parent
93bde3fb67
commit
19e4e27814
|
@ -2,14 +2,15 @@ import raf from 'raf';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import Menu from '../vc-menu';
|
import Menu from '../vc-menu';
|
||||||
import scrollIntoView from 'dom-scroll-into-view';
|
import scrollIntoView from 'dom-scroll-into-view';
|
||||||
import { getSelectKeys, preventDefaultEvent } from './util';
|
import { getSelectKeys, preventDefaultEvent, saveRef } from './util';
|
||||||
import { cloneElement } from '../_util/vnode';
|
import { cloneElement } from '../_util/vnode';
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
import BaseMixin from '../_util/BaseMixin';
|
||||||
import { getSlotOptions, getComponentFromProp, getListeners } from '../_util/props-util';
|
import { getSlotOptions, findDOMNode } from '../_util/props-util';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DropdownMenu',
|
name: 'DropdownMenu',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
ariaId: PropTypes.string,
|
ariaId: PropTypes.string,
|
||||||
defaultActiveFirstOption: PropTypes.bool,
|
defaultActiveFirstOption: PropTypes.bool,
|
||||||
|
@ -42,6 +43,7 @@ export default {
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.rafInstance = null;
|
this.rafInstance = null;
|
||||||
|
this.saveMenuRef = saveRef(this, 'menuRef');
|
||||||
this.lastInputValue = this.$props.inputValue;
|
this.lastInputValue = this.$props.inputValue;
|
||||||
this.lastVisible = false;
|
this.lastVisible = false;
|
||||||
},
|
},
|
||||||
|
@ -86,51 +88,36 @@ export default {
|
||||||
// Delay to scroll since current frame item position is not ready when pre view is by filter
|
// Delay to scroll since current frame item position is not ready when pre view is by filter
|
||||||
// https://github.com/ant-design/ant-design/issues/11268#issuecomment-406634462
|
// https://github.com/ant-design/ant-design/issues/11268#issuecomment-406634462
|
||||||
this.rafInstance = raf(() => {
|
this.rafInstance = raf(() => {
|
||||||
scrollIntoView(itemComponent, this.$refs.menuRef.$el, scrollIntoViewOpts);
|
scrollIntoView(itemComponent, findDOMNode(this.menuRef), scrollIntoViewOpts);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renderMenu() {
|
renderMenu() {
|
||||||
const props = this.$props;
|
const props = { ...this.$props, ...this.$attrs };
|
||||||
const {
|
const {
|
||||||
menuItems,
|
menuItems,
|
||||||
|
menuItemSelectedIcon,
|
||||||
defaultActiveFirstOption,
|
defaultActiveFirstOption,
|
||||||
value,
|
|
||||||
prefixCls,
|
prefixCls,
|
||||||
multiple,
|
multiple,
|
||||||
|
onMenuSelect,
|
||||||
inputValue,
|
inputValue,
|
||||||
firstActiveValue,
|
|
||||||
dropdownMenuStyle,
|
|
||||||
backfillValue,
|
backfillValue,
|
||||||
|
onMenuDeselect,
|
||||||
visible,
|
visible,
|
||||||
} = props;
|
} = props;
|
||||||
const menuItemSelectedIcon = getComponentFromProp(this, 'menuItemSelectedIcon');
|
const firstActiveValue = this.firstActiveValue;
|
||||||
const { menuDeselect, menuSelect, popupScroll } = getListeners(this);
|
|
||||||
if (menuItems && menuItems.length) {
|
if (menuItems && menuItems.length) {
|
||||||
const selectedKeys = getSelectKeys(menuItems, value);
|
const menuProps = {};
|
||||||
const menuProps = {
|
|
||||||
props: {
|
|
||||||
multiple,
|
|
||||||
itemIcon: multiple ? menuItemSelectedIcon : null,
|
|
||||||
selectedKeys,
|
|
||||||
prefixCls: `${prefixCls}-menu`,
|
|
||||||
},
|
|
||||||
on: {},
|
|
||||||
style: dropdownMenuStyle,
|
|
||||||
ref: 'menuRef',
|
|
||||||
attrs: {
|
|
||||||
role: 'listbox',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (popupScroll) {
|
|
||||||
menuProps.on.scroll = popupScroll;
|
|
||||||
}
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
menuProps.on.deselect = menuDeselect;
|
menuProps.onDeselect = onMenuDeselect;
|
||||||
menuProps.on.select = menuSelect;
|
menuProps.onSelect = onMenuSelect;
|
||||||
} else {
|
} else {
|
||||||
menuProps.on.click = menuSelect;
|
menuProps.onClick = onMenuSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const value = this.value;
|
||||||
|
const selectedKeys = getSelectKeys(menuItems, value);
|
||||||
const activeKeyProps = {};
|
const activeKeyProps = {};
|
||||||
|
|
||||||
let defaultActiveFirst = defaultActiveFirstOption;
|
let defaultActiveFirst = defaultActiveFirstOption;
|
||||||
|
@ -155,20 +142,16 @@ export default {
|
||||||
) {
|
) {
|
||||||
foundFirst = true;
|
foundFirst = true;
|
||||||
return cloneElement(item, {
|
return cloneElement(item, {
|
||||||
directives: [
|
ref: ref => {
|
||||||
{
|
this.firstActiveItem = ref;
|
||||||
name: 'ant-ref',
|
},
|
||||||
value: ref => {
|
|
||||||
this.firstActiveItem = ref;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
};
|
};
|
||||||
|
|
||||||
clonedMenuItems = menuItems.map(item => {
|
clonedMenuItems = menuItems.map(item => {
|
||||||
|
debugger;
|
||||||
if (getSlotOptions(item).isMenuItemGroup) {
|
if (getSlotOptions(item).isMenuItemGroup) {
|
||||||
const children = item.componentOptions.children.map(clone);
|
const children = item.componentOptions.children.map(clone);
|
||||||
return cloneElement(item, { children });
|
return cloneElement(item, { children });
|
||||||
|
@ -187,15 +170,29 @@ export default {
|
||||||
if (inputValue !== this.lastInputValue && (!lastValue || lastValue !== backfillValue)) {
|
if (inputValue !== this.lastInputValue && (!lastValue || lastValue !== backfillValue)) {
|
||||||
activeKeyProps.activeKey = '';
|
activeKeyProps.activeKey = '';
|
||||||
}
|
}
|
||||||
menuProps.props = { ...activeKeyProps, ...menuProps.props, defaultActiveFirst };
|
return (
|
||||||
return <Menu {...menuProps}>{clonedMenuItems}</Menu>;
|
<Menu
|
||||||
|
ref={this.saveMenuRef}
|
||||||
|
style={this.dropdownMenuStyle}
|
||||||
|
defaultActiveFirst={defaultActiveFirst}
|
||||||
|
role="listbox"
|
||||||
|
itemIcon={multiple ? menuItemSelectedIcon : null}
|
||||||
|
{...activeKeyProps}
|
||||||
|
multiple={multiple}
|
||||||
|
{...menuProps}
|
||||||
|
selectedKeys={selectedKeys}
|
||||||
|
prefixCls={`${prefixCls}-menu`}
|
||||||
|
>
|
||||||
|
{clonedMenuItems}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const renderMenu = this.renderMenu();
|
const renderMenu = this.renderMenu();
|
||||||
const { popupFocus, popupScroll } = getListeners(this);
|
const { onPopupFocus, onPopupScroll } = this.$attrs;
|
||||||
return renderMenu ? (
|
return renderMenu ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -204,10 +201,9 @@ export default {
|
||||||
}}
|
}}
|
||||||
id={this.$props.ariaId}
|
id={this.$props.ariaId}
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
onFocus={popupFocus}
|
onFocus={onPopupFocus}
|
||||||
onMousedown={preventDefaultEvent}
|
onMousedown={preventDefaultEvent}
|
||||||
onScroll={popupScroll}
|
onScroll={onPopupScroll}
|
||||||
ref="menuContainer"
|
|
||||||
>
|
>
|
||||||
{renderMenu}
|
{renderMenu}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -81,6 +81,7 @@ const Select = {
|
||||||
OptGroup,
|
OptGroup,
|
||||||
name: 'Select',
|
name: 'Select',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
...SelectPropTypes,
|
...SelectPropTypes,
|
||||||
prefixCls: SelectPropTypes.prefixCls.def('rc-select'),
|
prefixCls: SelectPropTypes.prefixCls.def('rc-select'),
|
||||||
|
@ -112,10 +113,10 @@ const Select = {
|
||||||
// onDeselect: noop,
|
// onDeselect: noop,
|
||||||
// onInputKeydown: noop,
|
// onInputKeydown: noop,
|
||||||
},
|
},
|
||||||
model: {
|
// model: {
|
||||||
prop: 'value',
|
// prop: 'value',
|
||||||
event: 'change',
|
// event: 'change',
|
||||||
},
|
// },
|
||||||
created() {
|
created() {
|
||||||
this.saveInputRef = saveRef(this, 'inputRef');
|
this.saveInputRef = saveRef(this, 'inputRef');
|
||||||
this.saveInputMirrorRef = saveRef(this, 'inputMirrorRef');
|
this.saveInputMirrorRef = saveRef(this, 'inputMirrorRef');
|
||||||
|
@ -1667,14 +1668,7 @@ const Select = {
|
||||||
onMouseleave={mouseleave}
|
onMouseleave={mouseleave}
|
||||||
showAction={props.showAction}
|
showAction={props.showAction}
|
||||||
menuItemSelectedIcon={getComponentFromProp(this, 'menuItemSelectedIcon')}
|
menuItemSelectedIcon={getComponentFromProp(this, 'menuItemSelectedIcon')}
|
||||||
{...{
|
ref={this.saveSelectTriggerRef}
|
||||||
directives: [
|
|
||||||
{
|
|
||||||
name: 'ant-ref',
|
|
||||||
value: this.saveSelectTriggerRef,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
dropdownRender={props.dropdownRender}
|
dropdownRender={props.dropdownRender}
|
||||||
ariaId={this.$data._ariaId}
|
ariaId={this.$data._ariaId}
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import PropTypes from '../_util/vue-types';
|
||||||
import DropdownMenu from './DropdownMenu';
|
import DropdownMenu from './DropdownMenu';
|
||||||
import { isSingleMode, saveRef } from './util';
|
import { isSingleMode, saveRef } from './util';
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
import BaseMixin from '../_util/BaseMixin';
|
||||||
import { getListeners } from '../_util/props-util';
|
import { findDOMNode, getSlot } from '../_util/props-util';
|
||||||
|
|
||||||
const BUILT_IN_PLACEMENTS = {
|
const BUILT_IN_PLACEMENTS = {
|
||||||
bottomLeft: {
|
bottomLeft: {
|
||||||
|
@ -29,6 +29,7 @@ const BUILT_IN_PLACEMENTS = {
|
||||||
export default {
|
export default {
|
||||||
name: 'SelectTrigger',
|
name: 'SelectTrigger',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
// onPopupFocus: PropTypes.func,
|
// onPopupFocus: PropTypes.func,
|
||||||
// onPopupScroll: PropTypes.func,
|
// onPopupScroll: PropTypes.func,
|
||||||
|
@ -89,7 +90,7 @@ export default {
|
||||||
setDropdownWidth() {
|
setDropdownWidth() {
|
||||||
this.cancelRafInstance();
|
this.cancelRafInstance();
|
||||||
this.rafInstance = raf(() => {
|
this.rafInstance = raf(() => {
|
||||||
const width = this.$el.offsetWidth;
|
const width = findDOMNode(this).offsetWidth;
|
||||||
if (width !== this.dropdownWidth) {
|
if (width !== this.dropdownWidth) {
|
||||||
this.setState({ dropdownWidth: width });
|
this.setState({ dropdownWidth: width });
|
||||||
}
|
}
|
||||||
|
@ -101,7 +102,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getInnerMenu() {
|
getInnerMenu() {
|
||||||
return this.dropdownMenuRef && this.dropdownMenuRef.$refs.menuRef;
|
return this.dropdownMenuRef && this.dropdownMenuRef.menuRef;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPopupDOMNode() {
|
getPopupDOMNode() {
|
||||||
|
@ -109,45 +110,25 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
getDropdownElement(newProps) {
|
getDropdownElement(newProps) {
|
||||||
const {
|
const props = { ...this.$props, ...this.$attrs };
|
||||||
value,
|
|
||||||
firstActiveValue,
|
|
||||||
defaultActiveFirstOption,
|
|
||||||
dropdownMenuStyle,
|
|
||||||
getDropdownPrefixCls,
|
|
||||||
backfillValue,
|
|
||||||
menuItemSelectedIcon,
|
|
||||||
} = this;
|
|
||||||
const { menuSelect, menuDeselect, popupScroll } = getListeners(this);
|
|
||||||
const props = this.$props;
|
|
||||||
|
|
||||||
const { dropdownRender, ariaId } = props;
|
const { dropdownRender, ariaId } = props;
|
||||||
const dropdownMenuProps = {
|
const menuNode = (
|
||||||
props: {
|
<DropdownMenu
|
||||||
...newProps.props,
|
ref={this.saveDropdownMenuRef}
|
||||||
ariaId,
|
{...newProps}
|
||||||
prefixCls: getDropdownPrefixCls(),
|
ariaId={ariaId}
|
||||||
value,
|
prefixCls={this.getDropdownPrefixCls()}
|
||||||
firstActiveValue,
|
onMenuSelect={props.onMenuSelect}
|
||||||
defaultActiveFirstOption,
|
onMenuDeselect={props.onMenuDeselect}
|
||||||
dropdownMenuStyle,
|
onPopupScroll={props.onPopupScroll}
|
||||||
backfillValue,
|
value={props.value}
|
||||||
menuItemSelectedIcon,
|
backfillValue={props.backfillValue}
|
||||||
},
|
firstActiveValue={props.firstActiveValue}
|
||||||
on: {
|
defaultActiveFirstOption={props.defaultActiveFirstOption}
|
||||||
...newProps.on,
|
dropdownMenuStyle={props.dropdownMenuStyle}
|
||||||
menuSelect,
|
menuItemSelectedIcon={props.menuItemSelectedIcon}
|
||||||
menuDeselect,
|
/>
|
||||||
popupScroll,
|
);
|
||||||
},
|
|
||||||
directives: [
|
|
||||||
{
|
|
||||||
name: 'ant-ref',
|
|
||||||
value: this.saveDropdownMenuRef,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const menuNode = <DropdownMenu {...dropdownMenuProps} />;
|
|
||||||
|
|
||||||
if (dropdownRender) {
|
if (dropdownRender) {
|
||||||
return dropdownRender(menuNode, props);
|
return dropdownRender(menuNode, props);
|
||||||
|
@ -170,7 +151,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { $props, $slots } = this;
|
const { onPopupFocus, empty, ...props } = { ...this.$props, ...this.$attrs };
|
||||||
const {
|
const {
|
||||||
multiple,
|
multiple,
|
||||||
visible,
|
visible,
|
||||||
|
@ -181,12 +162,8 @@ export default {
|
||||||
dropdownClassName,
|
dropdownClassName,
|
||||||
dropdownStyle,
|
dropdownStyle,
|
||||||
dropdownMatchSelectWidth,
|
dropdownMatchSelectWidth,
|
||||||
options,
|
} = props;
|
||||||
getPopupContainer,
|
//const { mouseenter, mouseleave, popupFocus, dropdownVisibleChange } = getListeners(this);
|
||||||
showAction,
|
|
||||||
empty,
|
|
||||||
} = $props;
|
|
||||||
const { mouseenter, mouseleave, popupFocus, dropdownVisibleChange } = getListeners(this);
|
|
||||||
const dropdownPrefixCls = this.getDropdownPrefixCls();
|
const dropdownPrefixCls = this.getDropdownPrefixCls();
|
||||||
const popupClassName = {
|
const popupClassName = {
|
||||||
[dropdownClassName]: !!dropdownClassName,
|
[dropdownClassName]: !!dropdownClassName,
|
||||||
|
@ -194,20 +171,16 @@ export default {
|
||||||
[`${dropdownPrefixCls}--empty`]: empty,
|
[`${dropdownPrefixCls}--empty`]: empty,
|
||||||
};
|
};
|
||||||
const popupElement = this.getDropdownElement({
|
const popupElement = this.getDropdownElement({
|
||||||
props: {
|
menuItems: props.options,
|
||||||
menuItems: options,
|
multiple,
|
||||||
multiple,
|
inputValue,
|
||||||
inputValue,
|
visible,
|
||||||
visible,
|
onPopupFocus,
|
||||||
},
|
|
||||||
on: {
|
|
||||||
popupFocus,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
let hideAction;
|
let hideAction;
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
hideAction = [];
|
hideAction = [];
|
||||||
} else if (isSingleMode($props) && !showSearch) {
|
} else if (isSingleMode(props) && !showSearch) {
|
||||||
hideAction = ['click'];
|
hideAction = ['click'];
|
||||||
} else {
|
} else {
|
||||||
hideAction = ['blur'];
|
hideAction = ['blur'];
|
||||||
|
@ -217,42 +190,25 @@ export default {
|
||||||
if (this.dropdownWidth) {
|
if (this.dropdownWidth) {
|
||||||
popupStyle[widthProp] = `${this.dropdownWidth}px`;
|
popupStyle[widthProp] = `${this.dropdownWidth}px`;
|
||||||
}
|
}
|
||||||
const triggerProps = {
|
|
||||||
props: {
|
|
||||||
...$props,
|
|
||||||
showAction: disabled ? [] : showAction,
|
|
||||||
hideAction,
|
|
||||||
ref: 'triggerRef',
|
|
||||||
popupPlacement: 'bottomLeft',
|
|
||||||
builtinPlacements: BUILT_IN_PLACEMENTS,
|
|
||||||
prefixCls: dropdownPrefixCls,
|
|
||||||
popupTransitionName: this.getDropdownTransitionName(),
|
|
||||||
popupAlign: dropdownAlign,
|
|
||||||
popupVisible: visible,
|
|
||||||
getPopupContainer,
|
|
||||||
popupClassName: classnames(popupClassName),
|
|
||||||
popupStyle,
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
popupVisibleChange: dropdownVisibleChange,
|
|
||||||
},
|
|
||||||
directives: [
|
|
||||||
{
|
|
||||||
name: 'ant-ref',
|
|
||||||
value: this.saveTriggerRef,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
if (mouseenter) {
|
|
||||||
triggerProps.on.mouseenter = mouseenter;
|
|
||||||
}
|
|
||||||
if (mouseleave) {
|
|
||||||
triggerProps.on.mouseleave = mouseleave;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Trigger {...triggerProps}>
|
<Trigger
|
||||||
{$slots.default}
|
{...props}
|
||||||
<template slot="popup">{popupElement}</template>
|
showAction={disabled ? [] : this.$props.showAction}
|
||||||
|
hideAction={hideAction}
|
||||||
|
ref={this.saveTriggerRef}
|
||||||
|
popupPlacement="bottomLeft"
|
||||||
|
builtinPlacements={BUILT_IN_PLACEMENTS}
|
||||||
|
prefixCls={dropdownPrefixCls}
|
||||||
|
popupTransitionName={this.getDropdownTransitionName()}
|
||||||
|
onPopupVisibleChange={props.onDropdownVisibleChange}
|
||||||
|
popup={popupElement}
|
||||||
|
popupAlign={dropdownAlign}
|
||||||
|
popupVisible={visible}
|
||||||
|
getPopupContainer={props.getPopupContainer}
|
||||||
|
popupClassName={classnames(popupClassName)}
|
||||||
|
popupStyle={popupStyle}
|
||||||
|
>
|
||||||
|
{getSlot(this)[0]}
|
||||||
</Trigger>
|
</Trigger>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue