ant-design-vue/components/vc-trigger/Popup.jsx
tangjinzhou 73bef787cd
Feat 1.5.0 (#1853)
* feat: add Result component

* fix: update md template tag html>tpl
- fix `result` typo
- update jest `result` snapshots

* refactor: svg file to functional component icon
- update jest snapshot

* feat: add result

* Feat descriptions (#1251)

* feat: add descriptions

* fix: add descriptions types and fix docs

* fix: lint change code

* fix: demo warning

* fix: update demo, snapshot and remove classnames

* test: add descriptions test

* fix: descriptions demo (#1498)

* feat: add page header (#1250)

* feat: add page-header component

* update site: page-header

* ts definition update: page-header

* get page-header props with getComponentFromProp func

* optimize page-header

* doc: add page-header actions.md responsive.md

* breadcrumb itemRender add pure function support

* style: format code

* feat: update style to 3.23.6 from 2.13.6

* feat: update style to 3.26.8 from 3.23.6

* chore: update util

* chore: update util

* feat: update affix

* feat: update alert

* feat: update anchor

* feat: update auto-complete

* feat: update avatar

* feat: update back-top

* feat: update badge

* feat: update button

* feat: update breadcrumb

* feat: update ts

* docs: update doc

* feat: update calendat

* feat: update card

* feat: update carousel

* feat: update carousel

* feat: update checkbox

* feat: update comment

* feat: update config-provider

* docs: update doc

* feat: update collapse

* feat: update locale

* feat: update date-picker

* feat: update divider

* feat: update drawer

* feat: update dropdown

* feat: update rc-trigger

* feat: update dropdown

* feat: update empty

* test: add empty test

* feat: update form

* feat: update form

* feat: update spin

* feat: update grid

* docs: update grid doc

* feat: update icon

* feat: update slider

* feat: update textarea

* feat: update input-number

* feat: update layout

* feat: update list

* feat: update menu

* feat: meaage add key for update content

* feat: modal add closeIcon support

* feat: update notification

* feat: add pagination disabled support

* feat: popconfirm add disabled support

* test: update popover

* feat: progress support custom line-gradiend

* feat: update radio

* test: update radio test

* docs: update rate demo

* feat: skeleton add avatar support number type

* test: add switch test

* test: update statistic test

* fix: input clear icon event

* feat: steps add type、 v-model、subTitle

* feat: delete typography component

* feat: delete Typography style

* perf: update select

* feat: add download transformFile previewFile actio

* docs: update upload

* feat: update  tree-select

* docs: update tree-select

* feat: tree add blockNode selectable

* docs: add tree demo

* test: update snap

* docs: updatedoc

* feat: update tag

* docs: update ad doc

* feat: update tooltip

* feat: update timeline

* feat: time-picker add clearIcon

* docs: update tabs

* feat: transfer support custom children

* test: update transfer test

* feat: update table

* test: update table test

* test: update test

* feat: calendar update locale

* test: update test snap

* feat: add mentions (#1790)

* feat: mentions style

* feat: theme default

* feat: add mentions component

* feat: mentions API

* feat: add unit test for mentions

* feat: update mentions demo

* perf: model and inheritAttrs for mentions

* perf: use getComponentFromProp instead of this.$props

* perf: mentions rm defaultProps

* feat: rm rows in mentionsProps

* fix: mentions keyDown didn't work

* docs: update mentions api

* perf: mentions code

* feat: update mentions

* bump 1.5.0-alpha.1

* feat: pageheader add ghost prop

* docs: update descriptions demo

* chore: page-header add ghost type

* fix: color error

* feat: update to 3.26.12

* fix: some prop default value

* fix(typo): form, carousel, upload. duplicate identifier (#1848)

* Add Mentions Type (#1845)

* feat: add mentions type

* feat: add mentions in ant-design-vue.d.ts

* docs: update doc

* docs: add changelog

* fix: mentions getPopupCotainer value (#1850)

* docs: update doc

* docs: uptate demo

* docs: update demo

* docs: delete demo

* docs: delete doc

* test: update snapshots

* style: format code

* chore: update travis

* docs: update demo

Co-authored-by: Sendya <18x@loacg.com>
Co-authored-by: zkwolf <chenhao5866@gmail.com>
Co-authored-by: drafish <xwlyy1991@163.com>
Co-authored-by: Amour1688 <31695475+Amour1688@users.noreply.github.com>
2020-03-07 19:45:13 +08:00

333 lines
9.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import PropTypes from '../_util/vue-types';
import Align from '../vc-align';
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';
export default {
name: 'VCTriggerPopup',
mixins: [BaseMixin],
props: {
visible: PropTypes.bool,
getClassNameFromAlign: PropTypes.func,
getRootDomNode: PropTypes.func,
align: PropTypes.any,
destroyPopupOnHide: PropTypes.bool,
prefixCls: PropTypes.string,
getContainer: PropTypes.func,
transitionName: PropTypes.string,
animation: PropTypes.any,
maskAnimation: PropTypes.string,
maskTransitionName: PropTypes.string,
mask: PropTypes.bool,
zIndex: PropTypes.number,
popupClassName: PropTypes.any,
popupStyle: PropTypes.object.def(() => ({})),
stretch: PropTypes.string,
point: PropTypes.shape({
pageX: PropTypes.number,
pageY: PropTypes.number,
}),
},
data() {
this.domEl = null;
return {
// Used for stretch
stretchChecked: false,
targetWidth: undefined,
targetHeight: undefined,
};
},
mounted() {
this.$nextTick(() => {
this.rootNode = this.getPopupDomNode();
this.setStretchSize();
});
},
beforeUpdate() {
if (this.domEl && this.domEl.rcEndListener) {
this.domEl.rcEndListener();
this.domEl = null;
}
},
updated() {
this.$nextTick(() => {
this.setStretchSize();
});
},
beforeDestroy() {
if (this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
} else if (this.$el.remove) {
this.$el.remove();
}
},
methods: {
onAlign(popupDomNode, align) {
const props = this.$props;
const currentAlignClassName = props.getClassNameFromAlign(align);
// FIX: https://github.com/react-component/trigger/issues/56
// FIX: https://github.com/react-component/tooltip/issues/79
if (this.currentAlignClassName !== currentAlignClassName) {
this.currentAlignClassName = currentAlignClassName;
popupDomNode.className = this.getClassName(currentAlignClassName);
}
const listeners = getListeners(this);
listeners.align && listeners.align(popupDomNode, align);
},
// Record size if stretch needed
setStretchSize() {
const { stretch, getRootDomNode, visible } = this.$props;
const { stretchChecked, targetHeight, targetWidth } = this.$data;
if (!stretch || !visible) {
if (stretchChecked) {
this.setState({ stretchChecked: false });
}
return;
}
const $ele = getRootDomNode();
if (!$ele) return;
const height = $ele.offsetHeight;
const width = $ele.offsetWidth;
if (targetHeight !== height || targetWidth !== width || !stretchChecked) {
this.setState({
stretchChecked: true,
targetHeight: height,
targetWidth: width,
});
}
},
getPopupDomNode() {
return this.$refs.popupInstance ? this.$refs.popupInstance.$el : null;
},
getTargetElement() {
return this.$props.getRootDomNode();
},
// `target` on `rc-align` can accept as a function to get the bind element or a point.
// ref: https://www.npmjs.com/package/rc-align
getAlignTarget() {
const { point } = this.$props;
if (point) {
return point;
}
return this.getTargetElement;
},
getMaskTransitionName() {
const props = this.$props;
let transitionName = props.maskTransitionName;
const animation = props.maskAnimation;
if (!transitionName && animation) {
transitionName = `${props.prefixCls}-${animation}`;
}
return transitionName;
},
getTransitionName() {
const props = this.$props;
let transitionName = props.transitionName;
const animation = props.animation;
if (!transitionName) {
if (typeof animation === 'string') {
transitionName = `${animation}`;
} else if (animation && animation.props && animation.props.name) {
transitionName = animation.props.name;
}
}
return transitionName;
},
getClassName(currentAlignClassName) {
return `${this.$props.prefixCls} ${this.$props.popupClassName} ${currentAlignClassName}`;
},
getPopupElement() {
const { $props: props, $slots, getTransitionName } = this;
const { stretchChecked, targetHeight, targetWidth } = this.$data;
const {
align,
visible,
prefixCls,
animation,
popupStyle,
getClassNameFromAlign,
destroyPopupOnHide,
stretch,
} = props;
const className = this.getClassName(
this.currentAlignClassName || getClassNameFromAlign(align),
);
// const hiddenClassName = `${prefixCls}-hidden`
if (!visible) {
this.currentAlignClassName = null;
}
const sizeStyle = {};
if (stretch) {
// Stretch with target
if (stretch.indexOf('height') !== -1) {
sizeStyle.height = typeof targetHeight === 'number' ? `${targetHeight}px` : targetHeight;
} else if (stretch.indexOf('minHeight') !== -1) {
sizeStyle.minHeight =
typeof targetHeight === 'number' ? `${targetHeight}px` : targetHeight;
}
if (stretch.indexOf('width') !== -1) {
sizeStyle.width = typeof targetWidth === 'number' ? `${targetWidth}px` : targetWidth;
} else if (stretch.indexOf('minWidth') !== -1) {
sizeStyle.minWidth = typeof targetWidth === 'number' ? `${targetWidth}px` : targetWidth;
}
// Delay force align to makes ui smooth
if (!stretchChecked) {
// sizeStyle.visibility = 'hidden'
setTimeout(() => {
if (this.$refs.alignInstance) {
this.$refs.alignInstance.forceAlign();
}
}, 0);
}
}
const popupInnerProps = {
props: {
prefixCls,
visible,
// hiddenClassName,
},
class: className,
on: getListeners(this),
ref: 'popupInstance',
style: { ...sizeStyle, ...popupStyle, ...this.getZIndexStyle() },
};
let transitionProps = {
props: Object.assign({
appear: true,
css: false,
}),
};
const transitionName = getTransitionName();
let useTransition = !!transitionName;
const transitionEvent = {
beforeEnter: () => {
// el.style.display = el.__vOriginalDisplay
// this.$refs.alignInstance.forceAlign();
},
enter: (el, done) => {
// render 后 vue 会移除通过animate动态添加的 class导致动画闪动延迟两帧添加动画class可以进一步定位或者重写 transition 组件
this.$nextTick(() => {
if (this.$refs.alignInstance) {
this.$refs.alignInstance.$nextTick(() => {
this.domEl = el;
animate(el, `${transitionName}-enter`, done);
});
}
});
},
beforeLeave: () => {
this.domEl = null;
},
leave: (el, done) => {
animate(el, `${transitionName}-leave`, done);
},
};
if (typeof animation === 'object') {
useTransition = true;
const { on = {}, props = {} } = animation;
transitionProps.props = { ...transitionProps.props, ...props };
transitionProps.on = { ...transitionEvent, ...on };
} else {
transitionProps.on = transitionEvent;
}
if (!useTransition) {
transitionProps = {};
}
if (destroyPopupOnHide) {
return (
<transition {...transitionProps}>
{visible ? (
<Align
target={this.getAlignTarget()}
key="popup"
ref="alignInstance"
monitorWindowResize
align={align}
onAlign={this.onAlign}
>
<PopupInner {...popupInnerProps}>{$slots.default}</PopupInner>
</Align>
) : null}
</transition>
);
}
return (
<transition {...transitionProps}>
<Align
v-show={visible}
target={this.getAlignTarget()}
key="popup"
ref="alignInstance"
monitorWindowResize
disabled={!visible}
align={align}
onAlign={this.onAlign}
>
<PopupInner {...popupInnerProps}>{$slots.default}</PopupInner>
</Align>
</transition>
);
},
getZIndexStyle() {
const style = {};
const props = this.$props;
if (props.zIndex !== undefined) {
style.zIndex = props.zIndex;
}
return style;
},
getMaskElement() {
const props = this.$props;
let maskElement = null;
if (props.mask) {
const maskTransition = this.getMaskTransitionName();
maskElement = (
<LazyRenderBox
v-show={props.visible}
style={this.getZIndexStyle()}
key="mask"
class={`${props.prefixCls}-mask`}
visible={props.visible}
/>
);
if (maskTransition) {
maskElement = (
<transition appear name={maskTransition}>
{maskElement}
</transition>
);
}
}
return maskElement;
},
},
render() {
const { getMaskElement, getPopupElement } = this;
return (
<div>
{getMaskElement()}
{getPopupElement()}
</div>
);
},
};