ant-design-vue/components/vc-dropdown/src/Dropdown.jsx

209 lines
5.8 KiB
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 BaseMixin from '../../_util/BaseMixin';
import { cloneElement } from '../../_util/vnode';
export default {
mixins: [BaseMixin],
props: {
minOverlayWidthMatchTrigger: PropTypes.bool,
prefixCls: PropTypes.string.def('rc-dropdown'),
transitionName: PropTypes.string,
overlayClassName: PropTypes.string.def(''),
openClassName: PropTypes.string,
animation: PropTypes.any,
align: PropTypes.object,
overlayStyle: PropTypes.object.def(() => ({})),
placement: PropTypes.string.def('bottomLeft'),
overlay: PropTypes.any,
trigger: PropTypes.array.def(['hover']),
alignPoint: PropTypes.bool,
showAction: PropTypes.array.def([]),
hideAction: PropTypes.array.def([]),
getPopupContainer: PropTypes.func,
visible: PropTypes.bool,
defaultVisible: PropTypes.bool.def(false),
mouseEnterDelay: PropTypes.number.def(0.15),
mouseLeaveDelay: PropTypes.number.def(0.1),
},
data() {
let sVisible = this.defaultVisible;
if (hasProp(this, 'visible')) {
sVisible = this.visible;
}
return {
sVisible,
};
},
watch: {
visible(val) {
if (val !== undefined) {
this.setState({
sVisible: val,
});
}
},
},
methods: {
onClick(e) {
// do no call onVisibleChange, if you need click to hide, use onClick and control visible
if (!hasProp(this, 'visible')) {
this.setState({
sVisible: false,
});
}
this.$emit('overlayClick', e);
if (this.childOriginEvents.click) {
this.childOriginEvents.click(e);
}
},
onVisibleChange(visible) {
if (!hasProp(this, 'visible')) {
this.setState({
sVisible: visible,
});
}
this.__emit('visibleChange', visible);
},
getMinOverlayWidthMatchTrigger() {
const props = getOptionProps(this);
const { minOverlayWidthMatchTrigger, alignPoint } = props;
if ('minOverlayWidthMatchTrigger' in props) {
return minOverlayWidthMatchTrigger;
}
return !alignPoint;
},
getOverlayElement() {
const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
let overlayElement;
if (typeof overlay === 'function') {
overlayElement = overlay();
} else {
overlayElement = overlay;
}
return overlayElement;
},
getMenuElement() {
const { onClick, prefixCls, $slots } = this;
this.childOriginEvents = getEvents($slots.overlay[0]);
const overlayElement = this.getOverlayElement();
const extraOverlayProps = {
props: {
prefixCls: `${prefixCls}-menu`,
getPopupContainer: () => this.getPopupDomNode(),
},
on: {
click: onClick,
},
};
if (typeof overlayElement.type === 'string') {
delete extraOverlayProps.props.prefixCls;
}
return cloneElement($slots.overlay[0], extraOverlayProps);
},
getMenuElementOrLambda() {
const overlay = this.overlay || this.$slots.overlay || this.$scopedSlots.overlay;
if (typeof overlay === 'function') {
return this.getMenuElement;
}
return this.getMenuElement();
},
getPopupDomNode() {
return this.$refs.trigger.getPopupDomNode();
},
getOpenClassName() {
const { openClassName, prefixCls } = this.$props;
if (openClassName !== undefined) {
return openClassName;
}
return `${prefixCls}-open`;
},
afterVisibleChange(visible) {
if (visible && this.getMinOverlayWidthMatchTrigger()) {
const overlayNode = this.getPopupDomNode();
const rootNode = this.$el;
if (rootNode && overlayNode && rootNode.offsetWidth > overlayNode.offsetWidth) {
overlayNode.style.minWidth = `${rootNode.offsetWidth}px`;
if (
this.$refs.trigger &&
this.$refs.trigger._component &&
this.$refs.trigger._component.alignInstance
) {
this.$refs.trigger._component.alignInstance.forceAlign();
}
}
}
},
renderChildren() {
const children = this.$slots.default && this.$slots.default[0];
const { sVisible } = this;
return sVisible && children
? cloneElement(children, { class: this.getOpenClassName() })
: children;
},
},
render() {
const {
prefixCls,
transitionName,
animation,
align,
placement,
getPopupContainer,
showAction,
hideAction,
overlayClassName,
overlayStyle,
trigger,
...otherProps
} = this.$props;
let triggerHideAction = hideAction;
if (!triggerHideAction && trigger.indexOf('contextmenu') !== -1) {
triggerHideAction = ['click'];
}
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,
},
ref: 'trigger',
};
return (
<Trigger {...triggerProps}>
{this.renderChildren()}
<template slot="popup">{this.$slots.overlay && this.getMenuElement()}</template>
</Trigger>
);
},
};