Popup.mjs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { ref, watch, provide, Teleport, nextTick, computed, onMounted, Transition, onActivated, onDeactivated, defineComponent, mergeProps as _mergeProps, createVNode as _createVNode, vShow as _vShow, withDirectives as _withDirectives, Fragment as _Fragment } from "vue";
  2. import { popupSharedProps } from "./shared.mjs";
  3. import { isDef, extend, makeStringProp, callInterceptor, createNamespace, HAPTICS_FEEDBACK } from "../utils/index.mjs";
  4. import { useEventListener } from "@vant/use";
  5. import { useExpose } from "../composables/use-expose.mjs";
  6. import { useLockScroll } from "../composables/use-lock-scroll.mjs";
  7. import { useLazyRender } from "../composables/use-lazy-render.mjs";
  8. import { POPUP_TOGGLE_KEY } from "../composables/on-popup-reopen.mjs";
  9. import { useGlobalZIndex } from "../composables/use-global-z-index.mjs";
  10. import { useScopeId } from "../composables/use-scope-id.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", "clickOverlay", "clickCloseIcon"],
  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("clickOverlay", event);
  71. if (props.closeOnClickOverlay) {
  72. close();
  73. }
  74. };
  75. const renderOverlay = () => {
  76. if (props.overlay) {
  77. return _createVNode(Overlay, _mergeProps({
  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. }, useScopeId(), {
  86. "onClick": onClickOverlay
  87. }), {
  88. default: slots["overlay-content"]
  89. });
  90. }
  91. };
  92. const onClickCloseIcon = (event) => {
  93. emit("clickCloseIcon", event);
  94. close();
  95. };
  96. const renderCloseIcon = () => {
  97. if (props.closeable) {
  98. return _createVNode(Icon, {
  99. "role": "button",
  100. "tabindex": 0,
  101. "name": props.closeIcon,
  102. "class": [bem("close-icon", props.closeIconPosition), HAPTICS_FEEDBACK],
  103. "classPrefix": props.iconPrefix,
  104. "onClick": onClickCloseIcon
  105. }, null);
  106. }
  107. };
  108. let timer;
  109. const onOpened = () => {
  110. if (timer) clearTimeout(timer);
  111. timer = setTimeout(() => {
  112. emit("opened");
  113. });
  114. };
  115. const onClosed = () => emit("closed");
  116. const onKeydown = (event) => emit("keydown", event);
  117. const renderPopup = lazyRender(() => {
  118. var _a;
  119. const {
  120. round,
  121. position,
  122. safeAreaInsetTop,
  123. safeAreaInsetBottom
  124. } = props;
  125. return _withDirectives(_createVNode("div", _mergeProps({
  126. "ref": popupRef,
  127. "style": style.value,
  128. "role": "dialog",
  129. "tabindex": 0,
  130. "class": [bem({
  131. round,
  132. [position]: position
  133. }), {
  134. "van-safe-area-top": safeAreaInsetTop,
  135. "van-safe-area-bottom": safeAreaInsetBottom
  136. }],
  137. "onKeydown": onKeydown
  138. }, attrs, useScopeId()), [(_a = slots.default) == null ? void 0 : _a.call(slots), renderCloseIcon()]), [[_vShow, props.show]]);
  139. });
  140. const renderTransition = () => {
  141. const {
  142. position,
  143. transition,
  144. transitionAppear
  145. } = props;
  146. const name2 = position === "center" ? "van-fade" : `van-popup-slide-${position}`;
  147. return _createVNode(Transition, {
  148. "name": transition || name2,
  149. "appear": transitionAppear,
  150. "onAfterEnter": onOpened,
  151. "onAfterLeave": onClosed
  152. }, {
  153. default: renderPopup
  154. });
  155. };
  156. watch(() => props.show, (show) => {
  157. if (show && !opened) {
  158. open();
  159. if (attrs.tabindex === 0) {
  160. nextTick(() => {
  161. var _a;
  162. (_a = popupRef.value) == null ? void 0 : _a.focus();
  163. });
  164. }
  165. }
  166. if (!show && opened) {
  167. opened = false;
  168. emit("close");
  169. }
  170. });
  171. useExpose({
  172. popupRef
  173. });
  174. useLockScroll(popupRef, () => props.show && props.lockScroll);
  175. useEventListener("popstate", () => {
  176. if (props.closeOnPopstate) {
  177. close();
  178. shouldReopen = false;
  179. }
  180. });
  181. onMounted(() => {
  182. if (props.show) {
  183. open();
  184. }
  185. });
  186. onActivated(() => {
  187. if (shouldReopen) {
  188. emit("update:show", true);
  189. shouldReopen = false;
  190. }
  191. });
  192. onDeactivated(() => {
  193. if (props.show && props.teleport) {
  194. close();
  195. shouldReopen = true;
  196. }
  197. });
  198. provide(POPUP_TOGGLE_KEY, () => props.show);
  199. return () => {
  200. if (props.teleport) {
  201. return _createVNode(Teleport, {
  202. "to": props.teleport
  203. }, {
  204. default: () => [renderOverlay(), renderTransition()]
  205. });
  206. }
  207. return _createVNode(_Fragment, null, [renderOverlay(), renderTransition()]);
  208. };
  209. }
  210. });
  211. export {
  212. stdin_default as default,
  213. popupProps
  214. };