PopupInner.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import { withDirectives as _withDirectives, resolveDirective as _resolveDirective, vShow as _vShow, createVNode as _createVNode } from "vue";
  4. import useVisibleStatus from './useVisibleStatus';
  5. import useStretchStyle from './useStretchStyle';
  6. import { computed, defineComponent, shallowRef, toRef, Transition, watch, withModifiers } from 'vue';
  7. import Align from '../../vc-align/Align';
  8. import { getMotion } from '../utils/motionUtil';
  9. import { flattenChildren } from '../../_util/props-util';
  10. import classNames from '../../_util/classNames';
  11. import { innerProps } from './interface';
  12. import { getTransitionProps } from '../../_util/transition';
  13. import supportsPassive from '../../_util/supportsPassive';
  14. export default defineComponent({
  15. compatConfig: {
  16. MODE: 3
  17. },
  18. name: 'PopupInner',
  19. inheritAttrs: false,
  20. props: innerProps,
  21. emits: ['mouseenter', 'mouseleave', 'mousedown', 'touchstart', 'align'],
  22. setup(props, _ref) {
  23. let {
  24. expose,
  25. attrs,
  26. slots
  27. } = _ref;
  28. const alignRef = shallowRef();
  29. const elementRef = shallowRef();
  30. const alignedClassName = shallowRef();
  31. // ======================= Measure ========================
  32. const [stretchStyle, measureStretchStyle] = useStretchStyle(toRef(props, 'stretch'));
  33. const doMeasure = () => {
  34. if (props.stretch) {
  35. measureStretchStyle(props.getRootDomNode());
  36. }
  37. };
  38. const visible = shallowRef(false);
  39. let timeoutId;
  40. watch(() => props.visible, val => {
  41. clearTimeout(timeoutId);
  42. if (val) {
  43. timeoutId = setTimeout(() => {
  44. visible.value = props.visible;
  45. });
  46. } else {
  47. visible.value = false;
  48. }
  49. }, {
  50. immediate: true
  51. });
  52. // ======================== Status ========================
  53. const [status, goNextStatus] = useVisibleStatus(visible, doMeasure);
  54. // ======================== Aligns ========================
  55. const prepareResolveRef = shallowRef();
  56. // `target` on `rc-align` can accept as a function to get the bind element or a point.
  57. // ref: https://www.npmjs.com/package/rc-align
  58. const getAlignTarget = () => {
  59. if (props.point) {
  60. return props.point;
  61. }
  62. return props.getRootDomNode;
  63. };
  64. const forceAlign = () => {
  65. var _a;
  66. (_a = alignRef.value) === null || _a === void 0 ? void 0 : _a.forceAlign();
  67. };
  68. const onInternalAlign = (popupDomNode, matchAlign) => {
  69. var _a;
  70. const nextAlignedClassName = props.getClassNameFromAlign(matchAlign);
  71. const preAlignedClassName = alignedClassName.value;
  72. if (alignedClassName.value !== nextAlignedClassName) {
  73. alignedClassName.value = nextAlignedClassName;
  74. }
  75. if (status.value === 'align') {
  76. // Repeat until not more align needed
  77. if (preAlignedClassName !== nextAlignedClassName) {
  78. Promise.resolve().then(() => {
  79. forceAlign();
  80. });
  81. } else {
  82. goNextStatus(() => {
  83. var _a;
  84. (_a = prepareResolveRef.value) === null || _a === void 0 ? void 0 : _a.call(prepareResolveRef);
  85. });
  86. }
  87. (_a = props.onAlign) === null || _a === void 0 ? void 0 : _a.call(props, popupDomNode, matchAlign);
  88. }
  89. };
  90. // ======================== Motion ========================
  91. const motion = computed(() => {
  92. const m = typeof props.animation === 'object' ? props.animation : getMotion(props);
  93. ['onAfterEnter', 'onAfterLeave'].forEach(eventName => {
  94. const originFn = m[eventName];
  95. m[eventName] = node => {
  96. goNextStatus();
  97. // 结束后,强制 stable
  98. status.value = 'stable';
  99. originFn === null || originFn === void 0 ? void 0 : originFn(node);
  100. };
  101. });
  102. return m;
  103. });
  104. const onShowPrepare = () => {
  105. return new Promise(resolve => {
  106. prepareResolveRef.value = resolve;
  107. });
  108. };
  109. watch([motion, status], () => {
  110. if (!motion.value && status.value === 'motion') {
  111. goNextStatus();
  112. }
  113. }, {
  114. immediate: true
  115. });
  116. expose({
  117. forceAlign,
  118. getElement: () => {
  119. return elementRef.value.$el || elementRef.value;
  120. }
  121. });
  122. const alignDisabled = computed(() => {
  123. var _a;
  124. if (((_a = props.align) === null || _a === void 0 ? void 0 : _a.points) && (status.value === 'align' || status.value === 'stable')) {
  125. return false;
  126. }
  127. return true;
  128. });
  129. return () => {
  130. var _a;
  131. const {
  132. zIndex,
  133. align,
  134. prefixCls,
  135. destroyPopupOnHide,
  136. onMouseenter,
  137. onMouseleave,
  138. onTouchstart = () => {},
  139. onMousedown
  140. } = props;
  141. const statusValue = status.value;
  142. // ======================== Render ========================
  143. const mergedStyle = [_extends(_extends({}, stretchStyle.value), {
  144. zIndex,
  145. opacity: statusValue === 'motion' || statusValue === 'stable' || !visible.value ? null : 0,
  146. // pointerEvents: statusValue === 'stable' ? null : 'none',
  147. pointerEvents: !visible.value && statusValue !== 'stable' ? 'none' : null
  148. }), attrs.style];
  149. let childNode = flattenChildren((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots, {
  150. visible: props.visible
  151. }));
  152. // Wrapper when multiple children
  153. if (childNode.length > 1) {
  154. const _childNode = function () {
  155. return childNode;
  156. }();
  157. childNode = _createVNode("div", {
  158. "class": `${prefixCls}-content`
  159. }, [childNode]);
  160. }
  161. const mergedClassName = classNames(prefixCls, attrs.class, alignedClassName.value, !props.arrow && `${prefixCls}-arrow-hidden`);
  162. const hasAnimate = visible.value || !props.visible;
  163. const transitionProps = hasAnimate ? getTransitionProps(motion.value.name, motion.value) : {};
  164. return _createVNode(Transition, _objectSpread(_objectSpread({
  165. "ref": elementRef
  166. }, transitionProps), {}, {
  167. "onBeforeEnter": onShowPrepare
  168. }), {
  169. default: () => {
  170. return !destroyPopupOnHide || props.visible ? _withDirectives(_createVNode(Align, {
  171. "target": getAlignTarget(),
  172. "key": "popup",
  173. "ref": alignRef,
  174. "monitorWindowResize": true,
  175. "disabled": alignDisabled.value,
  176. "align": align,
  177. "onAlign": onInternalAlign
  178. }, {
  179. default: () => _createVNode("div", {
  180. "class": mergedClassName,
  181. "onMouseenter": onMouseenter,
  182. "onMouseleave": onMouseleave,
  183. "onMousedown": withModifiers(onMousedown, ['capture']),
  184. [supportsPassive ? 'onTouchstartPassive' : 'onTouchstart']: withModifiers(onTouchstart, ['capture']),
  185. "style": mergedStyle
  186. }, [childNode])
  187. }), [[_vShow, visible.value]]) : null;
  188. }
  189. });
  190. };
  191. }
  192. });