Popup.mjs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import { Fragment as _Fragment, withDirectives as _withDirectives, mergeProps as _mergeProps, vShow as _vShow, createVNode as _createVNode } from "vue";
  2. import { ref, watch, provide, Teleport, nextTick, computed, onMounted, Transition, onActivated, onDeactivated, defineComponent } from "vue";
  3. import { popupSharedProps } from "./shared.mjs";
  4. import { isDef, extend, makeStringProp, callInterceptor, createNamespace, HAPTICS_FEEDBACK } from "../utils/index.mjs";
  5. import { useEventListener } from "@vant/use";
  6. import { useExpose } from "../composables/use-expose.mjs";
  7. import { useLockScroll } from "../composables/use-lock-scroll.mjs";
  8. import { useLazyRender } from "../composables/use-lazy-render.mjs";
  9. import { POPUP_TOGGLE_KEY } from "../composables/on-popup-reopen.mjs";
  10. import { useGlobalZIndex } from "../composables/use-global-z-index.mjs";
  11. import { Icon } from "../icon/index.mjs";
  12. import { Overlay } from "../overlay/index.mjs";
  13. const popupProps = extend({}, popupSharedProps, {
  14. round: Boolean,
  15. position: makeStringProp("center"),
  16. closeIcon: makeStringProp("cross"),
  17. closeable: Boolean,
  18. transition: String,
  19. iconPrefix: String,
  20. closeOnPopstate: Boolean,
  21. closeIconPosition: makeStringProp("top-right"),
  22. safeAreaInsetTop: Boolean,
  23. safeAreaInsetBottom: Boolean
  24. });
  25. const [name, bem] = createNamespace("popup");
  26. var stdin_default = defineComponent({
  27. name,
  28. inheritAttrs: false,
  29. props: popupProps,
  30. emits: ["open", "close", "opened", "closed", "keydown", "update:show", "click-overlay", "click-close-icon"],
  31. setup(props, {
  32. emit,
  33. attrs,
  34. slots
  35. }) {
  36. let opened;
  37. let shouldReopen;
  38. const zIndex = ref();
  39. const popupRef = ref();
  40. const lazyRender = useLazyRender(() => props.show || !props.lazyRender);
  41. const style = computed(() => {
  42. const style2 = {
  43. zIndex: zIndex.value
  44. };
  45. if (isDef(props.duration)) {
  46. const key = props.position === "center" ? "animationDuration" : "transitionDuration";
  47. style2[key] = `${props.duration}s`;
  48. }
  49. return style2;
  50. });
  51. const open = () => {
  52. if (!opened) {
  53. opened = true;
  54. zIndex.value = props.zIndex !== void 0 ? +props.zIndex : useGlobalZIndex();
  55. emit("open");
  56. }
  57. };
  58. const close = () => {
  59. if (opened) {
  60. callInterceptor(props.beforeClose, {
  61. done() {
  62. opened = false;
  63. emit("close");
  64. emit("update:show", false);
  65. }
  66. });
  67. }
  68. };
  69. const onClickOverlay = (event) => {
  70. emit("click-overlay", event);
  71. if (props.closeOnClickOverlay) {
  72. close();
  73. }
  74. };
  75. const renderOverlay = () => {
  76. if (props.overlay) {
  77. return _createVNode(Overlay, {
  78. "show": props.show,
  79. "class": props.overlayClass,
  80. "zIndex": zIndex.value,
  81. "duration": props.duration,
  82. "customStyle": props.overlayStyle,
  83. "role": props.closeOnClickOverlay ? "button" : void 0,
  84. "tabindex": props.closeOnClickOverlay ? 0 : void 0,
  85. "onClick": onClickOverlay
  86. }, {
  87. default: slots["overlay-content"]
  88. });
  89. }
  90. };
  91. const onClickCloseIcon = (event) => {
  92. emit("click-close-icon", event);
  93. close();
  94. };
  95. const renderCloseIcon = () => {
  96. if (props.closeable) {
  97. return _createVNode(Icon, {
  98. "role": "button",
  99. "tabindex": 0,
  100. "name": props.closeIcon,
  101. "class": [bem("close-icon", props.closeIconPosition), HAPTICS_FEEDBACK],
  102. "classPrefix": props.iconPrefix,
  103. "onClick": onClickCloseIcon
  104. }, null);
  105. }
  106. };
  107. const onOpened = () => emit("opened");
  108. const onClosed = () => emit("closed");
  109. const onKeydown = (event) => emit("keydown", event);
  110. const renderPopup = lazyRender(() => {
  111. var _a;
  112. const {
  113. round,
  114. position,
  115. safeAreaInsetTop,
  116. safeAreaInsetBottom
  117. } = props;
  118. return _withDirectives(_createVNode("div", _mergeProps({
  119. "ref": popupRef,
  120. "style": style.value,
  121. "role": "dialog",
  122. "tabindex": 0,
  123. "class": [bem({
  124. round,
  125. [position]: position
  126. }), {
  127. "van-safe-area-top": safeAreaInsetTop,
  128. "van-safe-area-bottom": safeAreaInsetBottom
  129. }],
  130. "onKeydown": onKeydown
  131. }, attrs), [(_a = slots.default) == null ? void 0 : _a.call(slots), renderCloseIcon()]), [[_vShow, props.show]]);
  132. });
  133. const renderTransition = () => {
  134. const {
  135. position,
  136. transition,
  137. transitionAppear
  138. } = props;
  139. const name2 = position === "center" ? "van-fade" : `van-popup-slide-${position}`;
  140. return _createVNode(Transition, {
  141. "name": transition || name2,
  142. "appear": transitionAppear,
  143. "onAfterEnter": onOpened,
  144. "onAfterLeave": onClosed
  145. }, {
  146. default: renderPopup
  147. });
  148. };
  149. watch(() => props.show, (show) => {
  150. if (show && !opened) {
  151. open();
  152. if (attrs.tabindex === 0) {
  153. nextTick(() => {
  154. var _a;
  155. (_a = popupRef.value) == null ? void 0 : _a.focus();
  156. });
  157. }
  158. }
  159. if (!show && opened) {
  160. opened = false;
  161. emit("close");
  162. }
  163. });
  164. useExpose({
  165. popupRef
  166. });
  167. useLockScroll(popupRef, () => props.show && props.lockScroll);
  168. useEventListener("popstate", () => {
  169. if (props.closeOnPopstate) {
  170. close();
  171. shouldReopen = false;
  172. }
  173. });
  174. onMounted(() => {
  175. if (props.show) {
  176. open();
  177. }
  178. });
  179. onActivated(() => {
  180. if (shouldReopen) {
  181. emit("update:show", true);
  182. shouldReopen = false;
  183. }
  184. });
  185. onDeactivated(() => {
  186. if (props.show && props.teleport) {
  187. close();
  188. shouldReopen = true;
  189. }
  190. });
  191. provide(POPUP_TOGGLE_KEY, () => props.show);
  192. return () => {
  193. if (props.teleport) {
  194. return _createVNode(Teleport, {
  195. "to": props.teleport
  196. }, {
  197. default: () => [renderOverlay(), renderTransition()]
  198. });
  199. }
  200. return _createVNode(_Fragment, null, [renderOverlay(), renderTransition()]);
  201. };
  202. }
  203. });
  204. export {
  205. stdin_default as default
  206. };