feat: update tooltip
parent
69a53b303d
commit
905bfd586f
|
@ -1,15 +1,16 @@
|
|||
import { inject, cloneVNode, isVNode } from 'vue';
|
||||
import { inject } from 'vue';
|
||||
import VcTooltip from '../vc-tooltip';
|
||||
import getPlacements from './placements';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import {
|
||||
hasProp,
|
||||
getComponent,
|
||||
getClass,
|
||||
getStyle,
|
||||
filterEmpty,
|
||||
getSlot,
|
||||
isValidElement,
|
||||
} from '../_util/props-util';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { ConfigConsumerProps } from '../config-provider';
|
||||
import abstractTooltipProps from './abstractTooltipProps';
|
||||
|
||||
|
@ -27,6 +28,7 @@ const splitObject = (obj, keys) => {
|
|||
const props = abstractTooltipProps();
|
||||
export default {
|
||||
name: 'ATooltip',
|
||||
inheritAttrs: false,
|
||||
model: {
|
||||
prop: 'visible',
|
||||
event: 'visibleChange',
|
||||
|
@ -80,18 +82,14 @@ export default {
|
|||
// mouse events don't trigger at disabled button in Chrome
|
||||
// https://github.com/react-component/tooltip/issues/18
|
||||
getDisabledCompatibleChildren(ele) {
|
||||
const options = (ele.componentOptions && ele.componentOptions.Ctor.options) || {};
|
||||
|
||||
if (
|
||||
((options.__ANT_BUTTON === true ||
|
||||
options.__ANT_SWITCH === true ||
|
||||
options.__ANT_CHECKBOX === true) &&
|
||||
(ele.componentOptions.propsData.disabled ||
|
||||
ele.componentOptions.propsData.disabled === '')) ||
|
||||
(ele.tag === 'button' &&
|
||||
ele.data &&
|
||||
ele.data.attrs &&
|
||||
ele.data.attrs.disabled !== undefined)
|
||||
((typeof ele.type === 'object' &&
|
||||
(ele.type.__ANT_BUTTON === true ||
|
||||
ele.type.__ANT_SWITCH === true ||
|
||||
ele.type.__ANT_CHECKBOX === true)) ||
|
||||
ele.type === 'button') &&
|
||||
ele.props &&
|
||||
(ele.props.disabled || ele.props.disabled === '')
|
||||
) {
|
||||
// Pick some layout related style properties up to span
|
||||
// Prevent layout bugs like https://github.com/ant-design/ant-design/issues/5254
|
||||
|
@ -115,16 +113,14 @@ export default {
|
|||
...omitted,
|
||||
pointerEvents: 'none',
|
||||
};
|
||||
const spanCls = getClass(ele);
|
||||
const child = cloneVNode(ele, {
|
||||
style: buttonStyle,
|
||||
class: null,
|
||||
});
|
||||
return (
|
||||
<span style={spanStyle} class={spanCls}>
|
||||
{child}
|
||||
</span>
|
||||
const child = cloneElement(
|
||||
ele,
|
||||
{
|
||||
style: buttonStyle,
|
||||
},
|
||||
true,
|
||||
);
|
||||
return <span style={spanStyle}>{child}</span>;
|
||||
}
|
||||
return ele;
|
||||
},
|
||||
|
@ -191,10 +187,11 @@ export default {
|
|||
return null;
|
||||
}
|
||||
const child = this.getDisabledCompatibleChildren(
|
||||
isVNode(children) ? children : <span>{children}</span>,
|
||||
isValidElement(children) ? children : <span>{children}</span>,
|
||||
);
|
||||
const childCls = {
|
||||
[openClassName || `${prefixCls}-open`]: true,
|
||||
[child.props && child.props.class]: child.props && child.props.class,
|
||||
};
|
||||
const tooltipProps = {
|
||||
...$attrs,
|
||||
|
@ -210,7 +207,7 @@ export default {
|
|||
};
|
||||
return (
|
||||
<VcTooltip {...tooltipProps}>
|
||||
{sVisible ? cloneVNode(child, { class: childCls }) : child}
|
||||
{sVisible ? cloneElement(child, { class: childCls }) : child}
|
||||
</VcTooltip>
|
||||
);
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import PropTypes from '../_util/vue-types';
|
||||
|
||||
export default {
|
||||
name: 'Content',
|
||||
props: {
|
||||
prefixCls: PropTypes.string,
|
||||
overlay: PropTypes.any,
|
||||
|
|
|
@ -5,6 +5,8 @@ import Content from './Content';
|
|||
import { hasProp, getComponent, getOptionProps } from '../_util/props-util';
|
||||
function noop() {}
|
||||
export default {
|
||||
name: 'Tooltip',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
trigger: PropTypes.any.def(['hover']),
|
||||
defaultVisible: PropTypes.bool,
|
||||
|
@ -91,12 +93,8 @@ export default {
|
|||
onPopupVisibleChange: $attrs.onVisibleChange || noop,
|
||||
onPopupAlign: $attrs.onPopupAlign || noop,
|
||||
ref: 'trigger',
|
||||
popup: this.getPopupElement(),
|
||||
};
|
||||
return (
|
||||
<Trigger {...triggerProps}>
|
||||
<template slot="popup">{this.getPopupElement()}</template>
|
||||
{this.$slots.default && this.$slots.default()}
|
||||
</Trigger>
|
||||
);
|
||||
return <Trigger {...triggerProps}>{this.$slots.default && this.$slots.default()[0]}</Trigger>;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
import PropTypes from '../_util/vue-types';
|
||||
|
||||
export default {
|
||||
name: 'LazyRenderBox',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
visible: PropTypes.bool,
|
||||
hiddenClassName: PropTypes.string,
|
||||
},
|
||||
render() {
|
||||
const { hiddenClassName, visible } = this.$props;
|
||||
const { hiddenClassName } = this.$props;
|
||||
const child = this.$slots.default && this.$slots.default();
|
||||
if (hiddenClassName || (child && child.length > 1)) {
|
||||
const cls = '';
|
||||
if (!visible && hiddenClassName) {
|
||||
// cls += ` ${hiddenClassName}`
|
||||
}
|
||||
return <div class={cls}>{child}</div>;
|
||||
// const cls = '';
|
||||
// if (!visible && hiddenClassName) {
|
||||
// // cls += ` ${hiddenClassName}`
|
||||
// }
|
||||
return <div {...this.$attrs}>{child}</div>;
|
||||
}
|
||||
return child;
|
||||
return child && child[0];
|
||||
},
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ import PopupInner from './PopupInner';
|
|||
import LazyRenderBox from './LazyRenderBox';
|
||||
import animate from '../_util/css-animation';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import { getListeners } from '../_util/props-util';
|
||||
import { getListeners, splitAttrs } from '../_util/props-util';
|
||||
|
||||
export default {
|
||||
name: 'VCTriggerPopup',
|
||||
|
@ -35,6 +35,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
this.domEl = null;
|
||||
this.currentAlignClassName = undefined;
|
||||
return {
|
||||
// Used for stretch
|
||||
stretchChecked: false,
|
||||
|
@ -152,12 +153,15 @@ export default {
|
|||
},
|
||||
|
||||
getClassName(currentAlignClassName) {
|
||||
return `${this.$props.prefixCls} ${this.$props.popupClassName} ${currentAlignClassName}`;
|
||||
return `${this.$props.prefixCls} ${this.$attrs.class || ''} ${
|
||||
this.$props.popupClassName
|
||||
} ${currentAlignClassName}`;
|
||||
},
|
||||
getPopupElement() {
|
||||
const { $props: props, $slots, getTransitionName } = this;
|
||||
const { $props: props, $attrs, $slots, getTransitionName } = this;
|
||||
const { stretchChecked, targetHeight, targetWidth } = this.$data;
|
||||
|
||||
const { style = {} } = $attrs;
|
||||
const onEvents = splitAttrs($attrs).onEvents;
|
||||
const {
|
||||
align,
|
||||
visible,
|
||||
|
@ -200,30 +204,26 @@ export default {
|
|||
}
|
||||
}
|
||||
const popupInnerProps = {
|
||||
props: {
|
||||
prefixCls,
|
||||
visible,
|
||||
// hiddenClassName,
|
||||
},
|
||||
prefixCls,
|
||||
visible,
|
||||
// hiddenClassName,
|
||||
class: className,
|
||||
on: getListeners(this),
|
||||
...onEvents,
|
||||
ref: 'popupInstance',
|
||||
style: { ...sizeStyle, ...popupStyle, ...this.getZIndexStyle() },
|
||||
style: { ...sizeStyle, ...popupStyle, ...style, ...this.getZIndexStyle() },
|
||||
};
|
||||
let transitionProps = {
|
||||
props: {
|
||||
appear: true,
|
||||
css: false,
|
||||
},
|
||||
appear: true,
|
||||
css: false,
|
||||
};
|
||||
const transitionName = getTransitionName();
|
||||
let useTransition = !!transitionName;
|
||||
const transitionEvent = {
|
||||
beforeEnter: () => {
|
||||
onBeforeEnter: () => {
|
||||
// el.style.display = el.__vOriginalDisplay
|
||||
// this.$refs.alignInstance.forceAlign();
|
||||
},
|
||||
enter: (el, done) => {
|
||||
onEnter: (el, done) => {
|
||||
// render 后 vue 会移除通过animate动态添加的 class导致动画闪动,延迟两帧添加动画class,可以进一步定位或者重写 transition 组件
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.alignInstance) {
|
||||
|
@ -236,21 +236,17 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
beforeLeave: () => {
|
||||
onBeforeLeave: () => {
|
||||
this.domEl = null;
|
||||
},
|
||||
leave: (el, done) => {
|
||||
onLeave: (el, done) => {
|
||||
animate(el, `${transitionName}-leave`, done);
|
||||
},
|
||||
};
|
||||
|
||||
transitionProps = { ...transitionProps, ...transitionEvent };
|
||||
if (typeof animation === 'object') {
|
||||
useTransition = true;
|
||||
const { on = {}, props = {} } = animation;
|
||||
transitionProps.props = { ...transitionProps.props, ...props };
|
||||
transitionProps.on = { ...transitionEvent, ...on };
|
||||
} else {
|
||||
transitionProps.on = transitionEvent;
|
||||
transitionProps = { ...transitionProps, ...animation };
|
||||
}
|
||||
if (!useTransition) {
|
||||
transitionProps = {};
|
||||
|
@ -267,7 +263,7 @@ export default {
|
|||
align={align}
|
||||
onAlign={this.onAlign}
|
||||
>
|
||||
<PopupInner {...popupInnerProps}>{$slots.default}</PopupInner>
|
||||
<PopupInner {...popupInnerProps}>{$slots.default && $slots.default()}</PopupInner>
|
||||
</Align>
|
||||
) : null}
|
||||
</Transition>
|
||||
|
@ -285,7 +281,7 @@ export default {
|
|||
align={align}
|
||||
onAlign={this.onAlign}
|
||||
>
|
||||
<PopupInner {...popupInnerProps}>{$slots.default}</PopupInner>
|
||||
<PopupInner {...popupInnerProps}>{$slots.default && $slots.default()}</PopupInner>
|
||||
</Align>
|
||||
</Transition>
|
||||
);
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
import { cloneVNode, inject, provide } from 'vue';
|
||||
import ref from 'vue-ref';
|
||||
import { inject, provide } from 'vue';
|
||||
import antRef from '../_util/ant-ref';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import contains from '../vc-util/Dom/contains';
|
||||
import {
|
||||
hasProp,
|
||||
getComponentFromProp,
|
||||
getEvents,
|
||||
filterEmpty,
|
||||
getSlot,
|
||||
getListeners,
|
||||
} from '../_util/props-util';
|
||||
import { hasProp, getComponent, getEvents, filterEmpty, getSlot } from '../_util/props-util';
|
||||
import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout';
|
||||
import addEventListener from '../vc-util/Dom/addEventListener';
|
||||
import warning from '../_util/warning';
|
||||
|
@ -17,6 +10,9 @@ import Popup from './Popup';
|
|||
import { getAlignFromPlacement, getAlignPopupClassName, noop } from './utils';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import Portal from '../_util/Portal';
|
||||
import classNames from 'classnames';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import createRefHooks from '../_util/createRefHooks';
|
||||
|
||||
function returnEmptyString() {
|
||||
return '';
|
||||
|
@ -38,7 +34,7 @@ const ALL_HANDLERS = [
|
|||
|
||||
export default {
|
||||
name: 'Trigger',
|
||||
directives: { 'ant-ref': ref },
|
||||
directives: { 'ant-ref': antRef },
|
||||
mixins: [BaseMixin],
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
|
@ -89,6 +85,7 @@ export default {
|
|||
this.fireEvents(h, e);
|
||||
};
|
||||
});
|
||||
this._component = null;
|
||||
return {
|
||||
prevPopupVisible: popupVisible,
|
||||
sPopupVisible: popupVisible,
|
||||
|
@ -328,8 +325,7 @@ export default {
|
|||
},
|
||||
|
||||
getRootDomNode() {
|
||||
return this.$el;
|
||||
// return this.$el.children[0] || this.$el
|
||||
return this.$refs.trigger.$el || this.$refs.trigger;
|
||||
},
|
||||
|
||||
handleGetPopupClassFromAlign(align) {
|
||||
|
@ -367,14 +363,14 @@ export default {
|
|||
const self = this;
|
||||
const mouseProps = {};
|
||||
if (this.isMouseEnterToShow()) {
|
||||
mouseProps.mouseenter = self.onPopupMouseenter;
|
||||
mouseProps.onMouseenter = self.onPopupMouseenter;
|
||||
}
|
||||
if (this.isMouseLeaveToHide()) {
|
||||
mouseProps.mouseleave = self.onPopupMouseleave;
|
||||
mouseProps.onMouseleave = self.onPopupMouseleave;
|
||||
}
|
||||
mouseProps.mousedown = this.onPopupMouseDown;
|
||||
mouseProps.touchstart = this.onPopupMouseDown;
|
||||
const { handleGetPopupClassFromAlign, getRootDomNode, getContainer } = self;
|
||||
mouseProps.onMousedown = this.onPopupMouseDown;
|
||||
mouseProps.onTouchstart = this.onPopupMouseDown;
|
||||
const { handleGetPopupClassFromAlign, getRootDomNode, getContainer, $attrs } = self;
|
||||
const {
|
||||
prefixCls,
|
||||
destroyPopupOnHide,
|
||||
|
@ -393,34 +389,31 @@ export default {
|
|||
const { sPopupVisible, point } = this.$data;
|
||||
const align = this.getPopupAlign();
|
||||
const popupProps = {
|
||||
props: {
|
||||
prefixCls,
|
||||
destroyPopupOnHide,
|
||||
visible: sPopupVisible,
|
||||
point: alignPoint && point,
|
||||
action,
|
||||
align,
|
||||
animation: popupAnimation,
|
||||
getClassNameFromAlign: handleGetPopupClassFromAlign,
|
||||
stretch,
|
||||
getRootDomNode,
|
||||
mask,
|
||||
zIndex,
|
||||
transitionName: popupTransitionName,
|
||||
maskAnimation,
|
||||
maskTransitionName,
|
||||
getContainer,
|
||||
popupClassName,
|
||||
popupStyle,
|
||||
},
|
||||
on: {
|
||||
align: getListeners(this).popupAlign || noop,
|
||||
...mouseProps,
|
||||
},
|
||||
prefixCls,
|
||||
destroyPopupOnHide,
|
||||
visible: sPopupVisible,
|
||||
point: alignPoint && point,
|
||||
action,
|
||||
align,
|
||||
animation: popupAnimation,
|
||||
getClassNameFromAlign: handleGetPopupClassFromAlign,
|
||||
stretch,
|
||||
getRootDomNode,
|
||||
mask,
|
||||
zIndex,
|
||||
transitionName: popupTransitionName,
|
||||
maskAnimation,
|
||||
maskTransitionName,
|
||||
getContainer,
|
||||
popupClassName,
|
||||
popupStyle,
|
||||
onAlign: $attrs.onPopupAlign || noop,
|
||||
...mouseProps,
|
||||
...createRefHooks(this.savePopup),
|
||||
};
|
||||
return (
|
||||
<Popup v-ant-ref={this.savePopup} {...popupProps}>
|
||||
{getComponentFromProp(self, 'popup')}
|
||||
<Popup ref="popup" key="ddd" {...popupProps}>
|
||||
{getComponent(self, 'popup')}
|
||||
</Popup>
|
||||
);
|
||||
},
|
||||
|
@ -521,7 +514,7 @@ export default {
|
|||
|
||||
createTwoChains(event) {
|
||||
let fn = () => {};
|
||||
const events = getListeners(this);
|
||||
const events = getEvents(this);
|
||||
if (this.childOriginEvents[event] && events[event]) {
|
||||
return this[`fire${event}`];
|
||||
}
|
||||
|
@ -564,8 +557,8 @@ export default {
|
|||
return action.indexOf('focus') !== -1 || hideAction.indexOf('blur') !== -1;
|
||||
},
|
||||
forcePopupAlign() {
|
||||
if (this.$data.sPopupVisible && this._component && this._component.$refs.alignInstance) {
|
||||
this._component.$refs.alignInstance.forceAlign();
|
||||
if (this.$data.sPopupVisible && this._component && this._component.refs.alignInstance) {
|
||||
this._component.refs.alignInstance.forceAlign();
|
||||
}
|
||||
},
|
||||
fireEvents(type, e) {
|
||||
|
@ -591,7 +584,7 @@ export default {
|
|||
this.childOriginEvents = getEvents(this);
|
||||
const newChildProps = {
|
||||
key: 'trigger',
|
||||
class: $attrs.class,
|
||||
ref: 'trigger',
|
||||
};
|
||||
|
||||
if (this.isContextmenuToShow()) {
|
||||
|
@ -634,8 +627,11 @@ export default {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
const trigger = cloneVNode(child, newChildProps);
|
||||
const childrenClassName = classNames(child && child.props && child.props.class, $attrs.class);
|
||||
if (childrenClassName) {
|
||||
newChildProps.class = childrenClassName;
|
||||
}
|
||||
const trigger = cloneElement(child, newChildProps);
|
||||
let portal;
|
||||
// prevent unmounting after it's rendered
|
||||
if (sPopupVisible || this._component || forceRender) {
|
||||
|
|
|
@ -1,654 +0,0 @@
|
|||
import { cloneVNode, inject, provide } from 'vue';
|
||||
import ref from 'vue-ref';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import contains from '../vc-util/Dom/contains';
|
||||
import {
|
||||
hasProp,
|
||||
getComponentFromProp,
|
||||
getEvents,
|
||||
filterEmpty,
|
||||
getSlot,
|
||||
getListeners,
|
||||
} from '../_util/props-util';
|
||||
import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout';
|
||||
import addEventListener from '../vc-util/Dom/addEventListener';
|
||||
import warning from '../_util/warning';
|
||||
import Popup from './Popup';
|
||||
import { getAlignFromPlacement, getAlignPopupClassName, noop } from './utils';
|
||||
import BaseMixin from '../_util/BaseMixin';
|
||||
import Portal from '../_util/Portal';
|
||||
|
||||
function returnEmptyString() {
|
||||
return '';
|
||||
}
|
||||
|
||||
function returnDocument() {
|
||||
return window.document;
|
||||
}
|
||||
const ALL_HANDLERS = [
|
||||
'click',
|
||||
'mousedown',
|
||||
'touchstart',
|
||||
'mouseenter',
|
||||
'mouseleave',
|
||||
'focus',
|
||||
'blur',
|
||||
'contextmenu',
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'Trigger',
|
||||
directives: { 'ant-ref': ref },
|
||||
mixins: [BaseMixin],
|
||||
props: {
|
||||
action: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).def([]),
|
||||
showAction: PropTypes.any.def([]),
|
||||
hideAction: PropTypes.any.def([]),
|
||||
getPopupClassNameFromAlign: PropTypes.any.def(returnEmptyString),
|
||||
// onPopupVisibleChange: PropTypes.func.def(noop),
|
||||
afterPopupVisibleChange: PropTypes.func.def(noop),
|
||||
popup: PropTypes.any,
|
||||
popupStyle: PropTypes.object.def(() => ({})),
|
||||
prefixCls: PropTypes.string.def('rc-trigger-popup'),
|
||||
popupClassName: PropTypes.string.def(''),
|
||||
popupPlacement: PropTypes.string,
|
||||
builtinPlacements: PropTypes.object,
|
||||
popupTransitionName: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
popupAnimation: PropTypes.any,
|
||||
mouseEnterDelay: PropTypes.number.def(0),
|
||||
mouseLeaveDelay: PropTypes.number.def(0.1),
|
||||
zIndex: PropTypes.number,
|
||||
focusDelay: PropTypes.number.def(0),
|
||||
blurDelay: PropTypes.number.def(0.15),
|
||||
getPopupContainer: PropTypes.func,
|
||||
getDocument: PropTypes.func.def(returnDocument),
|
||||
forceRender: PropTypes.bool,
|
||||
destroyPopupOnHide: PropTypes.bool.def(false),
|
||||
mask: PropTypes.bool.def(false),
|
||||
maskClosable: PropTypes.bool.def(true),
|
||||
// onPopupAlign: PropTypes.func.def(noop),
|
||||
popupAlign: PropTypes.object.def(() => ({})),
|
||||
popupVisible: PropTypes.bool,
|
||||
defaultPopupVisible: PropTypes.bool.def(false),
|
||||
maskTransitionName: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
maskAnimation: PropTypes.string,
|
||||
stretch: PropTypes.string,
|
||||
alignPoint: PropTypes.bool, // Maybe we can support user pass position in the future
|
||||
},
|
||||
data() {
|
||||
const props = this.$props;
|
||||
let popupVisible;
|
||||
if (hasProp(this, 'popupVisible')) {
|
||||
popupVisible = !!props.popupVisible;
|
||||
} else {
|
||||
popupVisible = !!props.defaultPopupVisible;
|
||||
}
|
||||
ALL_HANDLERS.forEach(h => {
|
||||
this[`fire${h}`] = e => {
|
||||
this.fireEvents(h, e);
|
||||
};
|
||||
});
|
||||
return {
|
||||
prevPopupVisible: popupVisible,
|
||||
sPopupVisible: popupVisible,
|
||||
point: null,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
popupVisible(val) {
|
||||
if (val !== undefined) {
|
||||
this.prevPopupVisible = this.sPopupVisible;
|
||||
this.sPopupVisible = val;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
provide('vcTriggerContext', this);
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
vcTriggerContext: inject('configProvider', {}),
|
||||
savePopupRef: inject('vcTriggerContext', noop),
|
||||
dialogContext: inject('dialogContext', null),
|
||||
};
|
||||
},
|
||||
deactivated() {
|
||||
this.setPopupVisible(false);
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.updatedCal();
|
||||
});
|
||||
},
|
||||
|
||||
updated() {
|
||||
this.$nextTick(() => {
|
||||
this.updatedCal();
|
||||
});
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.clearDelayTimer();
|
||||
this.clearOutsideHandler();
|
||||
clearTimeout(this.mouseDownTimeout);
|
||||
},
|
||||
methods: {
|
||||
updatedCal() {
|
||||
const props = this.$props;
|
||||
const state = this.$data;
|
||||
|
||||
// We must listen to `mousedown` or `touchstart`, edge case:
|
||||
// https://github.com/ant-design/ant-design/issues/5804
|
||||
// https://github.com/react-component/calendar/issues/250
|
||||
// https://github.com/react-component/trigger/issues/50
|
||||
if (state.sPopupVisible) {
|
||||
let currentDocument;
|
||||
if (!this.clickOutsideHandler && (this.isClickToHide() || this.isContextmenuToShow())) {
|
||||
currentDocument = props.getDocument();
|
||||
this.clickOutsideHandler = addEventListener(
|
||||
currentDocument,
|
||||
'mousedown',
|
||||
this.onDocumentClick,
|
||||
);
|
||||
}
|
||||
// always hide on mobile
|
||||
if (!this.touchOutsideHandler) {
|
||||
currentDocument = currentDocument || props.getDocument();
|
||||
this.touchOutsideHandler = addEventListener(
|
||||
currentDocument,
|
||||
'touchstart',
|
||||
this.onDocumentClick,
|
||||
);
|
||||
}
|
||||
// close popup when trigger type contains 'onContextmenu' and document is scrolling.
|
||||
if (!this.contextmenuOutsideHandler1 && this.isContextmenuToShow()) {
|
||||
currentDocument = currentDocument || props.getDocument();
|
||||
this.contextmenuOutsideHandler1 = addEventListener(
|
||||
currentDocument,
|
||||
'scroll',
|
||||
this.onContextmenuClose,
|
||||
);
|
||||
}
|
||||
// close popup when trigger type contains 'onContextmenu' and window is blur.
|
||||
if (!this.contextmenuOutsideHandler2 && this.isContextmenuToShow()) {
|
||||
this.contextmenuOutsideHandler2 = addEventListener(
|
||||
window,
|
||||
'blur',
|
||||
this.onContextmenuClose,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.clearOutsideHandler();
|
||||
}
|
||||
},
|
||||
onMouseenter(e) {
|
||||
const { mouseEnterDelay } = this.$props;
|
||||
this.fireEvents('mouseenter', e);
|
||||
this.delaySetPopupVisible(true, mouseEnterDelay, mouseEnterDelay ? null : e);
|
||||
},
|
||||
|
||||
onMouseMove(e) {
|
||||
this.fireEvents('mousemove', e);
|
||||
this.setPoint(e);
|
||||
},
|
||||
|
||||
onMouseleave(e) {
|
||||
this.fireEvents('mouseleave', e);
|
||||
this.delaySetPopupVisible(false, this.$props.mouseLeaveDelay);
|
||||
},
|
||||
|
||||
onPopupMouseenter() {
|
||||
this.clearDelayTimer();
|
||||
},
|
||||
|
||||
onPopupMouseleave(e) {
|
||||
if (
|
||||
e &&
|
||||
e.relatedTarget &&
|
||||
!e.relatedTarget.setTimeout &&
|
||||
this._component &&
|
||||
this._component.getPopupDomNode &&
|
||||
contains(this._component.getPopupDomNode(), e.relatedTarget)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.delaySetPopupVisible(false, this.$props.mouseLeaveDelay);
|
||||
},
|
||||
|
||||
onFocus(e) {
|
||||
this.fireEvents('focus', e);
|
||||
// incase focusin and focusout
|
||||
this.clearDelayTimer();
|
||||
if (this.isFocusToShow()) {
|
||||
this.focusTime = Date.now();
|
||||
this.delaySetPopupVisible(true, this.$props.focusDelay);
|
||||
}
|
||||
},
|
||||
|
||||
onMousedown(e) {
|
||||
this.fireEvents('mousedown', e);
|
||||
this.preClickTime = Date.now();
|
||||
},
|
||||
|
||||
onTouchstart(e) {
|
||||
this.fireEvents('touchstart', e);
|
||||
this.preTouchTime = Date.now();
|
||||
},
|
||||
|
||||
onBlur(e) {
|
||||
if (!contains(e.target, e.relatedTarget || document.activeElement)) {
|
||||
this.fireEvents('blur', e);
|
||||
this.clearDelayTimer();
|
||||
if (this.isBlurToHide()) {
|
||||
this.delaySetPopupVisible(false, this.$props.blurDelay);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onContextmenu(e) {
|
||||
e.preventDefault();
|
||||
this.fireEvents('contextmenu', e);
|
||||
this.setPopupVisible(true, e);
|
||||
},
|
||||
|
||||
onContextmenuClose() {
|
||||
if (this.isContextmenuToShow()) {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
|
||||
onClick(event) {
|
||||
this.fireEvents('click', event);
|
||||
// focus will trigger click
|
||||
if (this.focusTime) {
|
||||
let preTime;
|
||||
if (this.preClickTime && this.preTouchTime) {
|
||||
preTime = Math.min(this.preClickTime, this.preTouchTime);
|
||||
} else if (this.preClickTime) {
|
||||
preTime = this.preClickTime;
|
||||
} else if (this.preTouchTime) {
|
||||
preTime = this.preTouchTime;
|
||||
}
|
||||
if (Math.abs(preTime - this.focusTime) < 20) {
|
||||
return;
|
||||
}
|
||||
this.focusTime = 0;
|
||||
}
|
||||
this.preClickTime = 0;
|
||||
this.preTouchTime = 0;
|
||||
// Only prevent default when all the action is click.
|
||||
// https://github.com/ant-design/ant-design/issues/17043
|
||||
// https://github.com/ant-design/ant-design/issues/17291
|
||||
if (
|
||||
this.isClickToShow() &&
|
||||
(this.isClickToHide() || this.isBlurToHide()) &&
|
||||
event &&
|
||||
event.preventDefault
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (event && event.domEvent) {
|
||||
event.domEvent.preventDefault();
|
||||
}
|
||||
const nextVisible = !this.$data.sPopupVisible;
|
||||
if ((this.isClickToHide() && !nextVisible) || (nextVisible && this.isClickToShow())) {
|
||||
this.setPopupVisible(!this.$data.sPopupVisible, event);
|
||||
}
|
||||
},
|
||||
onPopupMouseDown(...args) {
|
||||
const { vcTriggerContext = {} } = this;
|
||||
this.hasPopupMouseDown = true;
|
||||
|
||||
clearTimeout(this.mouseDownTimeout);
|
||||
this.mouseDownTimeout = setTimeout(() => {
|
||||
this.hasPopupMouseDown = false;
|
||||
}, 0);
|
||||
|
||||
if (vcTriggerContext.onPopupMouseDown) {
|
||||
vcTriggerContext.onPopupMouseDown(...args);
|
||||
}
|
||||
},
|
||||
|
||||
onDocumentClick(event) {
|
||||
if (this.$props.mask && !this.$props.maskClosable) {
|
||||
return;
|
||||
}
|
||||
const target = event.target;
|
||||
const root = this.$el;
|
||||
if (!contains(root, target) && !this.hasPopupMouseDown) {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
getPopupDomNode() {
|
||||
if (this._component && this._component.getPopupDomNode) {
|
||||
return this._component.getPopupDomNode();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
getRootDomNode() {
|
||||
return this.$el;
|
||||
// return this.$el.children[0] || this.$el
|
||||
},
|
||||
|
||||
handleGetPopupClassFromAlign(align) {
|
||||
const className = [];
|
||||
const props = this.$props;
|
||||
const {
|
||||
popupPlacement,
|
||||
builtinPlacements,
|
||||
prefixCls,
|
||||
alignPoint,
|
||||
getPopupClassNameFromAlign,
|
||||
} = props;
|
||||
if (popupPlacement && builtinPlacements) {
|
||||
className.push(getAlignPopupClassName(builtinPlacements, prefixCls, align, alignPoint));
|
||||
}
|
||||
if (getPopupClassNameFromAlign) {
|
||||
className.push(getPopupClassNameFromAlign(align));
|
||||
}
|
||||
return className.join(' ');
|
||||
},
|
||||
|
||||
getPopupAlign() {
|
||||
const props = this.$props;
|
||||
const { popupPlacement, popupAlign, builtinPlacements } = props;
|
||||
if (popupPlacement && builtinPlacements) {
|
||||
return getAlignFromPlacement(builtinPlacements, popupPlacement, popupAlign);
|
||||
}
|
||||
return popupAlign;
|
||||
},
|
||||
savePopup(node) {
|
||||
this._component = node;
|
||||
this.savePopupRef(node);
|
||||
},
|
||||
getComponent() {
|
||||
const self = this;
|
||||
const mouseProps = {};
|
||||
if (this.isMouseEnterToShow()) {
|
||||
mouseProps.mouseenter = self.onPopupMouseenter;
|
||||
}
|
||||
if (this.isMouseLeaveToHide()) {
|
||||
mouseProps.mouseleave = self.onPopupMouseleave;
|
||||
}
|
||||
mouseProps.mousedown = this.onPopupMouseDown;
|
||||
mouseProps.touchstart = this.onPopupMouseDown;
|
||||
const { handleGetPopupClassFromAlign, getRootDomNode, getContainer } = self;
|
||||
const {
|
||||
prefixCls,
|
||||
destroyPopupOnHide,
|
||||
popupClassName,
|
||||
action,
|
||||
popupAnimation,
|
||||
popupTransitionName,
|
||||
popupStyle,
|
||||
mask,
|
||||
maskAnimation,
|
||||
maskTransitionName,
|
||||
zIndex,
|
||||
stretch,
|
||||
alignPoint,
|
||||
} = self.$props;
|
||||
const { sPopupVisible, point } = this.$data;
|
||||
const align = this.getPopupAlign();
|
||||
const popupProps = {
|
||||
props: {
|
||||
prefixCls,
|
||||
destroyPopupOnHide,
|
||||
visible: sPopupVisible,
|
||||
point: alignPoint && point,
|
||||
action,
|
||||
align,
|
||||
animation: popupAnimation,
|
||||
getClassNameFromAlign: handleGetPopupClassFromAlign,
|
||||
stretch,
|
||||
getRootDomNode,
|
||||
mask,
|
||||
zIndex,
|
||||
transitionName: popupTransitionName,
|
||||
maskAnimation,
|
||||
maskTransitionName,
|
||||
getContainer,
|
||||
popupClassName,
|
||||
popupStyle,
|
||||
},
|
||||
on: {
|
||||
align: getListeners(this).popupAlign || noop,
|
||||
...mouseProps,
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Popup v-ant-ref={this.savePopup} {...popupProps}>
|
||||
{getComponentFromProp(self, 'popup')}
|
||||
</Popup>
|
||||
);
|
||||
},
|
||||
|
||||
getContainer() {
|
||||
const { $props: props, dialogContext } = this;
|
||||
const popupContainer = document.createElement('div');
|
||||
// Make sure default popup container will never cause scrollbar appearing
|
||||
// https://github.com/react-component/trigger/issues/41
|
||||
popupContainer.style.position = 'absolute';
|
||||
popupContainer.style.top = '0';
|
||||
popupContainer.style.left = '0';
|
||||
popupContainer.style.width = '100%';
|
||||
const mountNode = props.getPopupContainer
|
||||
? props.getPopupContainer(this.$el, dialogContext)
|
||||
: props.getDocument().body;
|
||||
mountNode.appendChild(popupContainer);
|
||||
this.popupContainer = popupContainer;
|
||||
return popupContainer;
|
||||
},
|
||||
|
||||
setPopupVisible(sPopupVisible, event) {
|
||||
const { alignPoint, sPopupVisible: prevPopupVisible } = this;
|
||||
this.clearDelayTimer();
|
||||
if (prevPopupVisible !== sPopupVisible) {
|
||||
if (!hasProp(this, 'popupVisible')) {
|
||||
this.setState({
|
||||
sPopupVisible,
|
||||
prevPopupVisible,
|
||||
});
|
||||
}
|
||||
const listeners = getListeners(this);
|
||||
listeners.popupVisibleChange && listeners.popupVisibleChange(sPopupVisible);
|
||||
}
|
||||
// Always record the point position since mouseEnterDelay will delay the show
|
||||
if (alignPoint && event) {
|
||||
this.setPoint(event);
|
||||
}
|
||||
},
|
||||
|
||||
setPoint(point) {
|
||||
const { alignPoint } = this.$props;
|
||||
if (!alignPoint || !point) return;
|
||||
|
||||
this.setState({
|
||||
point: {
|
||||
pageX: point.pageX,
|
||||
pageY: point.pageY,
|
||||
},
|
||||
});
|
||||
},
|
||||
handlePortalUpdate() {
|
||||
if (this.prevPopupVisible !== this.sPopupVisible) {
|
||||
this.afterPopupVisibleChange(this.sPopupVisible);
|
||||
}
|
||||
},
|
||||
delaySetPopupVisible(visible, delayS, event) {
|
||||
const delay = delayS * 1000;
|
||||
this.clearDelayTimer();
|
||||
if (delay) {
|
||||
const point = event ? { pageX: event.pageX, pageY: event.pageY } : null;
|
||||
this.delayTimer = requestAnimationTimeout(() => {
|
||||
this.setPopupVisible(visible, point);
|
||||
this.clearDelayTimer();
|
||||
}, delay);
|
||||
} else {
|
||||
this.setPopupVisible(visible, event);
|
||||
}
|
||||
},
|
||||
|
||||
clearDelayTimer() {
|
||||
if (this.delayTimer) {
|
||||
cancelAnimationTimeout(this.delayTimer);
|
||||
this.delayTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
clearOutsideHandler() {
|
||||
if (this.clickOutsideHandler) {
|
||||
this.clickOutsideHandler.remove();
|
||||
this.clickOutsideHandler = null;
|
||||
}
|
||||
|
||||
if (this.contextmenuOutsideHandler1) {
|
||||
this.contextmenuOutsideHandler1.remove();
|
||||
this.contextmenuOutsideHandler1 = null;
|
||||
}
|
||||
|
||||
if (this.contextmenuOutsideHandler2) {
|
||||
this.contextmenuOutsideHandler2.remove();
|
||||
this.contextmenuOutsideHandler2 = null;
|
||||
}
|
||||
|
||||
if (this.touchOutsideHandler) {
|
||||
this.touchOutsideHandler.remove();
|
||||
this.touchOutsideHandler = null;
|
||||
}
|
||||
},
|
||||
|
||||
createTwoChains(event) {
|
||||
let fn = () => {};
|
||||
const events = getListeners(this);
|
||||
if (this.childOriginEvents[event] && events[event]) {
|
||||
return this[`fire${event}`];
|
||||
}
|
||||
fn = this.childOriginEvents[event] || events[event] || fn;
|
||||
return fn;
|
||||
},
|
||||
|
||||
isClickToShow() {
|
||||
const { action, showAction } = this.$props;
|
||||
return action.indexOf('click') !== -1 || showAction.indexOf('click') !== -1;
|
||||
},
|
||||
|
||||
isContextmenuToShow() {
|
||||
const { action, showAction } = this.$props;
|
||||
return action.indexOf('contextmenu') !== -1 || showAction.indexOf('contextmenu') !== -1;
|
||||
},
|
||||
|
||||
isClickToHide() {
|
||||
const { action, hideAction } = this.$props;
|
||||
return action.indexOf('click') !== -1 || hideAction.indexOf('click') !== -1;
|
||||
},
|
||||
|
||||
isMouseEnterToShow() {
|
||||
const { action, showAction } = this.$props;
|
||||
return action.indexOf('hover') !== -1 || showAction.indexOf('mouseenter') !== -1;
|
||||
},
|
||||
|
||||
isMouseLeaveToHide() {
|
||||
const { action, hideAction } = this.$props;
|
||||
return action.indexOf('hover') !== -1 || hideAction.indexOf('mouseleave') !== -1;
|
||||
},
|
||||
|
||||
isFocusToShow() {
|
||||
const { action, showAction } = this.$props;
|
||||
return action.indexOf('focus') !== -1 || showAction.indexOf('focus') !== -1;
|
||||
},
|
||||
|
||||
isBlurToHide() {
|
||||
const { action, hideAction } = this.$props;
|
||||
return action.indexOf('focus') !== -1 || hideAction.indexOf('blur') !== -1;
|
||||
},
|
||||
forcePopupAlign() {
|
||||
if (this.$data.sPopupVisible && this._component && this._component.$refs.alignInstance) {
|
||||
this._component.$refs.alignInstance.forceAlign();
|
||||
}
|
||||
},
|
||||
fireEvents(type, e) {
|
||||
if (this.childOriginEvents[type]) {
|
||||
this.childOriginEvents[type](e);
|
||||
}
|
||||
this.__emit(type, e);
|
||||
},
|
||||
|
||||
close() {
|
||||
this.setPopupVisible(false);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const { sPopupVisible } = this;
|
||||
const children = filterEmpty(getSlot(this));
|
||||
const { forceRender, alignPoint } = this.$props;
|
||||
|
||||
if (children.length > 1) {
|
||||
warning(false, 'Trigger $slots.default.length > 1, just support only one default', true);
|
||||
}
|
||||
const child = children[0];
|
||||
this.childOriginEvents = getEvents(child);
|
||||
const newChildProps = {
|
||||
props: {},
|
||||
on: {},
|
||||
key: 'trigger',
|
||||
};
|
||||
|
||||
if (this.isContextmenuToShow()) {
|
||||
newChildProps.on.contextmenu = this.onContextmenu;
|
||||
} else {
|
||||
newChildProps.on.contextmenu = this.createTwoChains('contextmenu');
|
||||
}
|
||||
|
||||
if (this.isClickToHide() || this.isClickToShow()) {
|
||||
newChildProps.on.click = this.onClick;
|
||||
newChildProps.on.mousedown = this.onMousedown;
|
||||
newChildProps.on.touchstart = this.onTouchstart;
|
||||
} else {
|
||||
newChildProps.on.click = this.createTwoChains('click');
|
||||
newChildProps.on.mousedown = this.createTwoChains('mousedown');
|
||||
newChildProps.on.touchstart = this.createTwoChains('onTouchstart');
|
||||
}
|
||||
if (this.isMouseEnterToShow()) {
|
||||
newChildProps.on.mouseenter = this.onMouseenter;
|
||||
if (alignPoint) {
|
||||
newChildProps.on.mousemove = this.onMouseMove;
|
||||
}
|
||||
} else {
|
||||
newChildProps.on.mouseenter = this.createTwoChains('mouseenter');
|
||||
}
|
||||
if (this.isMouseLeaveToHide()) {
|
||||
newChildProps.on.mouseleave = this.onMouseleave;
|
||||
} else {
|
||||
newChildProps.on.mouseleave = this.createTwoChains('mouseleave');
|
||||
}
|
||||
|
||||
if (this.isFocusToShow() || this.isBlurToHide()) {
|
||||
newChildProps.on.focus = this.onFocus;
|
||||
newChildProps.on.blur = this.onBlur;
|
||||
} else {
|
||||
newChildProps.on.focus = this.createTwoChains('focus');
|
||||
newChildProps.on.blur = e => {
|
||||
if (e && (!e.relatedTarget || !contains(e.target, e.relatedTarget))) {
|
||||
this.createTwoChains('blur')(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const trigger = cloneVNode(child, newChildProps);
|
||||
let portal;
|
||||
// prevent unmounting after it's rendered
|
||||
if (sPopupVisible || this._component || forceRender) {
|
||||
portal = (
|
||||
<Portal
|
||||
key="portal"
|
||||
children={this.getComponent()}
|
||||
getContainer={this.getContainer}
|
||||
didUpdate={this.handlePortalUpdate}
|
||||
></Portal>
|
||||
);
|
||||
}
|
||||
return [portal, trigger];
|
||||
},
|
||||
};
|
|
@ -17,6 +17,7 @@ import PageHeader from 'ant-design-vue/page-header';
|
|||
import Skeleton from 'ant-design-vue/skeleton';
|
||||
import Empty from 'ant-design-vue/empty';
|
||||
import Timeline from 'ant-design-vue/timeline';
|
||||
import Tooltip from 'ant-design-vue/tooltip';
|
||||
import 'ant-design-vue/style.js';
|
||||
|
||||
createApp(App)
|
||||
|
@ -36,4 +37,5 @@ createApp(App)
|
|||
.use(Spin)
|
||||
.use(Empty)
|
||||
.use(Timeline)
|
||||
.use(Tooltip)
|
||||
.mount('#app');
|
||||
|
|
Loading…
Reference in New Issue