feat: update dropdown
parent
96ba93cf9b
commit
a0e637da9c
|
@ -1 +1 @@
|
|||
Subproject commit 78341d7cd7c34015b7369982cfa7914fbc558232
|
||||
Subproject commit bf1777054fbe55a0d3bbdd037573e3a235137fbb
|
|
@ -43,3 +43,7 @@ v-model -> v-model:value
|
|||
## menu
|
||||
|
||||
v-model -> v-model:selectedKeys :openKeys.sync -> v-mdoel:openKeys
|
||||
|
||||
## dropdown
|
||||
|
||||
v-model -> v-model:visible
|
||||
|
|
|
@ -200,7 +200,6 @@ const getAllProps = ele => {
|
|||
return props;
|
||||
};
|
||||
|
||||
// 使用 getOptionProps 替换 ,待测试
|
||||
const getPropsData = vnode => {
|
||||
const res = {};
|
||||
const originProps = vnode.props || {};
|
||||
|
@ -208,7 +207,7 @@ const getPropsData = vnode => {
|
|||
Object.keys(originProps).forEach(key => {
|
||||
props[camelize(key)] = originProps[key];
|
||||
});
|
||||
const options = vnode.type.props;
|
||||
const options = isPlainObject(vnode.type) ? vnode.type.props : {};
|
||||
Object.keys(options).forEach(k => {
|
||||
const v = resolvePropValue(options, props, k, props[k]);
|
||||
if (k in props) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { provide, inject } from 'vue';
|
||||
import Button from '../button';
|
||||
import buttonTypes from '../button/buttonTypes';
|
||||
import { ButtonGroupProps } from '../button/button-group';
|
||||
import Dropdown from './dropdown';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { hasProp, getComponentFromProp } from '../_util/props-util';
|
||||
import { hasProp, getComponent, getSlot } from '../_util/props-util';
|
||||
import getDropdownProps from './getDropdownProps';
|
||||
import { ConfigConsumerProps } from '../config-provider';
|
||||
import EllipsisOutlined from '@ant-design/icons-vue/EllipsisOutlined';
|
||||
|
@ -27,18 +28,14 @@ const DropdownButtonProps = {
|
|||
export { DropdownButtonProps };
|
||||
export default {
|
||||
name: 'ADropdownButton',
|
||||
model: {
|
||||
prop: 'visible',
|
||||
event: 'visibleChange',
|
||||
},
|
||||
props: DropdownButtonProps,
|
||||
provide() {
|
||||
setup() {
|
||||
return {
|
||||
savePopupRef: this.savePopupRef,
|
||||
configProvider: inject('configProvider', ConfigConsumerProps),
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
configProvider: { default: () => ConfigConsumerProps },
|
||||
created() {
|
||||
provide('savePopupRef', this.savePopupRef);
|
||||
},
|
||||
methods: {
|
||||
savePopupRef(ref) {
|
||||
|
@ -48,6 +45,7 @@ export default {
|
|||
this.$emit('click', e);
|
||||
},
|
||||
onVisibleChange(val) {
|
||||
this.$emit('update:visible', val);
|
||||
this.$emit('visibleChange', val);
|
||||
},
|
||||
},
|
||||
|
@ -66,30 +64,24 @@ export default {
|
|||
title,
|
||||
...restProps
|
||||
} = this.$props;
|
||||
const icon = getComponentFromProp(this, 'icon') || <EllipsisOutlined />;
|
||||
const icon = getComponent(this, 'icon') || <EllipsisOutlined />;
|
||||
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('dropdown-button', customizePrefixCls);
|
||||
const dropdownProps = {
|
||||
props: {
|
||||
align,
|
||||
disabled,
|
||||
trigger: disabled ? [] : trigger,
|
||||
placement,
|
||||
getPopupContainer: getPopupContainer || getContextPopupContainer,
|
||||
},
|
||||
on: {
|
||||
visibleChange: this.onVisibleChange,
|
||||
},
|
||||
align,
|
||||
disabled,
|
||||
trigger: disabled ? [] : trigger,
|
||||
placement,
|
||||
getPopupContainer: getPopupContainer || getContextPopupContainer,
|
||||
onVisibleChange: this.onVisibleChange,
|
||||
};
|
||||
if (hasProp(this, 'visible')) {
|
||||
dropdownProps.props.visible = visible;
|
||||
dropdownProps.visible = visible;
|
||||
}
|
||||
|
||||
const buttonGroupProps = {
|
||||
props: {
|
||||
...restProps,
|
||||
},
|
||||
...restProps,
|
||||
class: prefixCls,
|
||||
};
|
||||
|
||||
|
@ -103,10 +95,9 @@ export default {
|
|||
href={href}
|
||||
title={title}
|
||||
>
|
||||
{this.$slots.default}
|
||||
{getSlot(this)}
|
||||
</Button>
|
||||
<Dropdown {...dropdownProps}>
|
||||
<template slot="overlay">{getComponentFromProp(this, 'overlay')}</template>
|
||||
<Dropdown {...dropdownProps} overlay={getComponent(this, 'overlay')}>
|
||||
<Button type={type}>{icon}</Button>
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { provide, inject, cloneVNode } from 'vue';
|
||||
import RcDropdown from '../vc-dropdown/src/index';
|
||||
import DropdownButton from './dropdown-button';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
|
@ -5,8 +6,9 @@ import { cloneElement } from '../_util/vnode';
|
|||
import {
|
||||
getOptionProps,
|
||||
getPropsData,
|
||||
getComponentFromProp,
|
||||
getListeners,
|
||||
getComponent,
|
||||
isValidElement,
|
||||
getSlot,
|
||||
} from '../_util/props-util';
|
||||
import getDropdownProps from './getDropdownProps';
|
||||
import { ConfigConsumerProps } from '../config-provider';
|
||||
|
@ -22,17 +24,13 @@ const Dropdown = {
|
|||
mouseLeaveDelay: PropTypes.number.def(0.1),
|
||||
placement: DropdownProps.placement.def('bottomLeft'),
|
||||
},
|
||||
model: {
|
||||
prop: 'visible',
|
||||
event: 'visibleChange',
|
||||
},
|
||||
provide() {
|
||||
setup() {
|
||||
return {
|
||||
savePopupRef: this.savePopupRef,
|
||||
configProvider: inject('configProvider', ConfigConsumerProps),
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
configProvider: { default: () => ConfigConsumerProps },
|
||||
created() {
|
||||
provide('savePopupRef', this.savePopupRef);
|
||||
},
|
||||
methods: {
|
||||
savePopupRef(ref) {
|
||||
|
@ -49,7 +47,7 @@ const Dropdown = {
|
|||
return 'slide-up';
|
||||
},
|
||||
renderOverlay(prefixCls) {
|
||||
const overlay = getComponentFromProp(this, 'overlay');
|
||||
const overlay = getComponent(this, 'overlay');
|
||||
const overlayNode = Array.isArray(overlay) ? overlay[0] : overlay;
|
||||
// menu cannot be selectable in dropdown defaultly
|
||||
// menu should be focusable in dropdown defaultly
|
||||
|
@ -61,57 +59,48 @@ const Dropdown = {
|
|||
</span>
|
||||
);
|
||||
|
||||
const fixedModeOverlay =
|
||||
overlayNode && overlayNode.componentOptions
|
||||
? cloneElement(overlayNode, {
|
||||
props: {
|
||||
mode: 'vertical',
|
||||
selectable,
|
||||
focusable,
|
||||
expandIcon,
|
||||
},
|
||||
})
|
||||
: overlay;
|
||||
const fixedModeOverlay = isValidElement(overlayNode)
|
||||
? cloneVNode(overlayNode, {
|
||||
mode: 'vertical',
|
||||
selectable,
|
||||
focusable,
|
||||
expandIcon,
|
||||
})
|
||||
: overlay;
|
||||
return fixedModeOverlay;
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const { $slots } = this;
|
||||
const props = getOptionProps(this);
|
||||
const { prefixCls: customizePrefixCls, trigger, disabled, getPopupContainer } = props;
|
||||
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
|
||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
||||
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
|
||||
|
||||
const dropdownTrigger = cloneElement($slots.default, {
|
||||
class: `${prefixCls}-trigger`,
|
||||
props: {
|
||||
const dropdownTrigger = cloneElement(
|
||||
getSlot(this),
|
||||
{
|
||||
class: `${prefixCls}-trigger`,
|
||||
disabled,
|
||||
},
|
||||
});
|
||||
false,
|
||||
);
|
||||
const triggerActions = disabled ? [] : trigger;
|
||||
let alignPoint;
|
||||
if (triggerActions && triggerActions.indexOf('contextmenu') !== -1) {
|
||||
alignPoint = true;
|
||||
}
|
||||
const dropdownProps = {
|
||||
props: {
|
||||
alignPoint,
|
||||
...props,
|
||||
prefixCls,
|
||||
getPopupContainer: getPopupContainer || getContextPopupContainer,
|
||||
transitionName: this.getTransitionName(),
|
||||
trigger: triggerActions,
|
||||
},
|
||||
on: getListeners(this),
|
||||
alignPoint,
|
||||
...props,
|
||||
prefixCls,
|
||||
getPopupContainer: getPopupContainer || getContextPopupContainer,
|
||||
transitionName: this.getTransitionName(),
|
||||
trigger: triggerActions,
|
||||
overlay: this.renderOverlay(prefixCls),
|
||||
};
|
||||
return (
|
||||
<RcDropdown {...dropdownProps}>
|
||||
{dropdownTrigger}
|
||||
<template slot="overlay">{this.renderOverlay(prefixCls)}</template>
|
||||
</RcDropdown>
|
||||
);
|
||||
return <RcDropdown {...dropdownProps}>{dropdownTrigger}</RcDropdown>;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import addEventListener from '../vc-util/Dom/addEventListener';
|
|||
import { isWindow, buffer, isSamePoint, isSimilarValue, restoreFocus } from './util';
|
||||
import { cloneElement } from '../_util/vnode.js';
|
||||
import clonedeep from 'lodash/cloneDeep';
|
||||
import { getSlot, getListeners } from '../_util/props-util';
|
||||
import { getSlot, findDOMNode } from '../_util/props-util';
|
||||
|
||||
function getElement(func) {
|
||||
if (typeof func !== 'function' || !func) return null;
|
||||
|
@ -117,8 +117,7 @@ export default {
|
|||
forceAlign() {
|
||||
const { disabled, target, align } = this.$props;
|
||||
if (!disabled && target) {
|
||||
const source = this.$el;
|
||||
const listeners = getListeners(this);
|
||||
const source = findDOMNode(this);
|
||||
let result;
|
||||
const element = getElement(target);
|
||||
const point = getPoint(target);
|
||||
|
@ -134,7 +133,7 @@ export default {
|
|||
}
|
||||
restoreFocus(activeElement, source);
|
||||
this.aligned = true;
|
||||
listeners.align && listeners.align(source, result);
|
||||
this.$attrs.onAlign && this.$attrs.onAlign(source, result);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -143,7 +142,7 @@ export default {
|
|||
const { childrenProps } = this.$props;
|
||||
const child = getSlot(this);
|
||||
if (child && childrenProps) {
|
||||
return cloneElement(child[0], { props: childrenProps });
|
||||
return cloneElement(child[0], childrenProps);
|
||||
}
|
||||
return child && child[0];
|
||||
},
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
import { Text } from 'vue';
|
||||
import PropTypes from '../../_util/vue-types';
|
||||
import Trigger from '../../vc-trigger';
|
||||
import placements from './placements';
|
||||
import { hasProp, getEvents, getOptionProps } from '../../_util/props-util';
|
||||
import {
|
||||
hasProp,
|
||||
getComponent,
|
||||
getOptionProps,
|
||||
getSlot,
|
||||
findDOMNode,
|
||||
} from '../../_util/props-util';
|
||||
import BaseMixin from '../../_util/BaseMixin';
|
||||
import { cloneElement } from '../../_util/vnode';
|
||||
|
||||
|
@ -48,6 +55,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
onClick(e) {
|
||||
const overlayProps = this.getOverlayElement().props;
|
||||
// do no call onVisibleChange, if you need click to hide, use onClick and control visible
|
||||
if (!hasProp(this, 'visible')) {
|
||||
this.setState({
|
||||
|
@ -55,8 +63,8 @@ export default {
|
|||
});
|
||||
}
|
||||
this.$emit('overlayClick', e);
|
||||
if (this.childOriginEvents.click) {
|
||||
this.childOriginEvents.click(e);
|
||||
if (overlayProps.onClick) {
|
||||
overlayProps.onClick(e);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -66,6 +74,7 @@ export default {
|
|||
sVisible: visible,
|
||||
});
|
||||
}
|
||||
this.$emit('update:visible', visible);
|
||||
this.__emit('visibleChange', visible);
|
||||
},
|
||||
|
||||
|
@ -80,37 +89,26 @@ export default {
|
|||
},
|
||||
|
||||
getOverlayElement() {
|
||||
const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
|
||||
let overlayElement;
|
||||
if (typeof overlay === 'function') {
|
||||
overlayElement = overlay();
|
||||
} else {
|
||||
overlayElement = overlay;
|
||||
}
|
||||
return overlayElement;
|
||||
const overlay = getComponent(this, 'overlay');
|
||||
return Array.isArray(overlay) ? overlay[0] : overlay;
|
||||
},
|
||||
|
||||
getMenuElement() {
|
||||
const { onClick, prefixCls, $slots } = this;
|
||||
this.childOriginEvents = getEvents($slots.overlay[0]);
|
||||
const { onClick, prefixCls } = this;
|
||||
const overlayElement = this.getOverlayElement();
|
||||
const extraOverlayProps = {
|
||||
props: {
|
||||
prefixCls: `${prefixCls}-menu`,
|
||||
getPopupContainer: () => this.getPopupDomNode(),
|
||||
},
|
||||
on: {
|
||||
click: onClick,
|
||||
},
|
||||
prefixCls: `${prefixCls}-menu`,
|
||||
getPopupContainer: () => this.getPopupDomNode(),
|
||||
onClick,
|
||||
};
|
||||
if (typeof overlayElement.type === 'string') {
|
||||
delete extraOverlayProps.props.prefixCls;
|
||||
if (overlayElement && overlayElement.type === Text) {
|
||||
delete extraOverlayProps.prefixCls;
|
||||
}
|
||||
return cloneElement($slots.overlay[0], extraOverlayProps);
|
||||
return cloneElement(overlayElement, extraOverlayProps);
|
||||
},
|
||||
|
||||
getMenuElementOrLambda() {
|
||||
const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
|
||||
const overlay = this.overlay || this.$slots.overlay;
|
||||
if (typeof overlay === 'function') {
|
||||
return this.getMenuElement;
|
||||
}
|
||||
|
@ -132,7 +130,7 @@ export default {
|
|||
afterVisibleChange(visible) {
|
||||
if (visible && this.getMinOverlayWidthMatchTrigger()) {
|
||||
const overlayNode = this.getPopupDomNode();
|
||||
const rootNode = this.$el;
|
||||
const rootNode = findDOMNode(this);
|
||||
if (rootNode && overlayNode && rootNode.offsetWidth > overlayNode.offsetWidth) {
|
||||
overlayNode.style.minWidth = `${rootNode.offsetWidth}px`;
|
||||
if (
|
||||
|
@ -147,10 +145,10 @@ export default {
|
|||
},
|
||||
|
||||
renderChildren() {
|
||||
const children = this.$slots.default && this.$slots.default[0];
|
||||
const children = getSlot(this);
|
||||
const { sVisible } = this;
|
||||
return sVisible && children
|
||||
? cloneElement(children, { class: this.getOpenClassName() })
|
||||
? cloneElement(children[0], { class: this.getOpenClassName() }, false)
|
||||
: children;
|
||||
},
|
||||
},
|
||||
|
@ -176,33 +174,25 @@ export default {
|
|||
}
|
||||
|
||||
const triggerProps = {
|
||||
props: {
|
||||
...otherProps,
|
||||
prefixCls,
|
||||
popupClassName: overlayClassName,
|
||||
popupStyle: overlayStyle,
|
||||
builtinPlacements: placements,
|
||||
action: trigger,
|
||||
showAction,
|
||||
hideAction: triggerHideAction || [],
|
||||
popupPlacement: placement,
|
||||
popupAlign: align,
|
||||
popupTransitionName: transitionName,
|
||||
popupAnimation: animation,
|
||||
popupVisible: this.sVisible,
|
||||
afterPopupVisibleChange: this.afterVisibleChange,
|
||||
getPopupContainer,
|
||||
},
|
||||
on: {
|
||||
popupVisibleChange: this.onVisibleChange,
|
||||
},
|
||||
...otherProps,
|
||||
prefixCls,
|
||||
popupClassName: overlayClassName,
|
||||
popupStyle: overlayStyle,
|
||||
builtinPlacements: placements,
|
||||
action: trigger,
|
||||
showAction,
|
||||
hideAction: triggerHideAction || [],
|
||||
popupPlacement: placement,
|
||||
popupAlign: align,
|
||||
popupTransitionName: transitionName,
|
||||
popupAnimation: animation,
|
||||
popupVisible: this.sVisible,
|
||||
afterPopupVisibleChange: this.afterVisibleChange,
|
||||
getPopupContainer,
|
||||
onPopupVisibleChange: this.onVisibleChange,
|
||||
popup: this.getMenuElementOrLambda(),
|
||||
ref: 'trigger',
|
||||
};
|
||||
return (
|
||||
<Trigger {...triggerProps}>
|
||||
{this.renderChildren()}
|
||||
<template slot="popup">{this.$slots.overlay && this.getMenuElement()}</template>
|
||||
</Trigger>
|
||||
);
|
||||
return <Trigger {...triggerProps}>{this.renderChildren()}</Trigger>;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Text } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { getSlot } from '../_util/props-util';
|
||||
|
||||
|
@ -10,7 +11,11 @@ export default {
|
|||
render() {
|
||||
const { hiddenClassName } = this.$props;
|
||||
const child = getSlot(this);
|
||||
if (hiddenClassName || (child && child.length > 1)) {
|
||||
if (
|
||||
hiddenClassName ||
|
||||
(child && child.length > 1) ||
|
||||
(child && child[0] && child[0].type === Text)
|
||||
) {
|
||||
// const cls = '';
|
||||
// if (!visible && hiddenClassName) {
|
||||
// // cls += ` ${hiddenClassName}`
|
||||
|
|
|
@ -32,6 +32,7 @@ import message from 'ant-design-vue/message';
|
|||
import Modal from 'ant-design-vue/modal';
|
||||
import Menu from 'ant-design-vue/menu';
|
||||
import Mentions from 'ant-design-vue/mentions';
|
||||
import Dropdown from 'ant-design-vue/dropdown';
|
||||
import 'ant-design-vue/style.js';
|
||||
|
||||
const basic = {
|
||||
|
@ -77,4 +78,5 @@ app
|
|||
.use(Modal)
|
||||
.use(Menu)
|
||||
.use(Mentions)
|
||||
.use(Dropdown)
|
||||
.mount('#app');
|
||||
|
|
Loading…
Reference in New Issue