Popover.mjs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import { mergeProps as _mergeProps, Fragment as _Fragment, createVNode as _createVNode } from "vue";
  2. import { ref, watch, nextTick, onMounted, watchEffect, onBeforeUnmount, defineComponent } from "vue";
  3. import { createPopper, offsetModifier } from "@vant/popperjs";
  4. import { pick, extend, truthProp, numericProp, unknownProp, BORDER_BOTTOM, makeArrayProp, makeStringProp, createNamespace } from "../utils/index.mjs";
  5. import { useClickAway } from "@vant/use";
  6. import { useSyncPropRef } from "../composables/use-sync-prop-ref.mjs";
  7. import { Icon } from "../icon/index.mjs";
  8. import { Popup } from "../popup/index.mjs";
  9. const [name, bem] = createNamespace("popover");
  10. const popupProps = ["overlay", "duration", "teleport", "overlayStyle", "overlayClass", "closeOnClickOverlay"];
  11. const popoverProps = {
  12. show: Boolean,
  13. theme: makeStringProp("light"),
  14. overlay: Boolean,
  15. actions: makeArrayProp(),
  16. trigger: makeStringProp("click"),
  17. duration: numericProp,
  18. showArrow: truthProp,
  19. placement: makeStringProp("bottom"),
  20. iconPrefix: String,
  21. overlayClass: unknownProp,
  22. overlayStyle: Object,
  23. closeOnClickAction: truthProp,
  24. closeOnClickOverlay: truthProp,
  25. closeOnClickOutside: truthProp,
  26. offset: {
  27. type: Array,
  28. default: () => [0, 8]
  29. },
  30. teleport: {
  31. type: [String, Object],
  32. default: "body"
  33. }
  34. };
  35. var stdin_default = defineComponent({
  36. name,
  37. props: popoverProps,
  38. emits: ["select", "touchstart", "update:show"],
  39. setup(props, {
  40. emit,
  41. slots,
  42. attrs
  43. }) {
  44. let popper;
  45. const popupRef = ref();
  46. const wrapperRef = ref();
  47. const popoverRef = ref();
  48. const show = useSyncPropRef(() => props.show, (value) => emit("update:show", value));
  49. const getPopoverOptions = () => ({
  50. placement: props.placement,
  51. modifiers: [{
  52. name: "computeStyles",
  53. options: {
  54. adaptive: false,
  55. gpuAcceleration: false
  56. }
  57. }, extend({}, offsetModifier, {
  58. options: {
  59. offset: props.offset
  60. }
  61. })]
  62. });
  63. const createPopperInstance = () => {
  64. if (wrapperRef.value && popoverRef.value) {
  65. return createPopper(wrapperRef.value, popoverRef.value.popupRef.value, getPopoverOptions());
  66. }
  67. return null;
  68. };
  69. const updateLocation = () => {
  70. nextTick(() => {
  71. if (!show.value) {
  72. return;
  73. }
  74. if (!popper) {
  75. popper = createPopperInstance();
  76. } else {
  77. popper.setOptions(getPopoverOptions());
  78. }
  79. });
  80. };
  81. const updateShow = (value) => {
  82. show.value = value;
  83. };
  84. const onClickWrapper = () => {
  85. if (props.trigger === "click") {
  86. show.value = !show.value;
  87. }
  88. };
  89. const onClickAction = (action, index) => {
  90. if (action.disabled) {
  91. return;
  92. }
  93. emit("select", action, index);
  94. if (props.closeOnClickAction) {
  95. show.value = false;
  96. }
  97. };
  98. const onClickAway = () => {
  99. if (show.value && props.closeOnClickOutside && (!props.overlay || props.closeOnClickOverlay)) {
  100. show.value = false;
  101. }
  102. };
  103. const renderActionContent = (action, index) => {
  104. if (slots.action) {
  105. return slots.action({
  106. action,
  107. index
  108. });
  109. }
  110. return [action.icon && _createVNode(Icon, {
  111. "name": action.icon,
  112. "classPrefix": props.iconPrefix,
  113. "class": bem("action-icon")
  114. }, null), _createVNode("div", {
  115. "class": [bem("action-text"), BORDER_BOTTOM]
  116. }, [action.text])];
  117. };
  118. const renderAction = (action, index) => {
  119. const {
  120. icon,
  121. color,
  122. disabled,
  123. className
  124. } = action;
  125. return _createVNode("div", {
  126. "role": "menuitem",
  127. "class": [bem("action", {
  128. disabled,
  129. "with-icon": icon
  130. }), className],
  131. "style": {
  132. color
  133. },
  134. "tabindex": disabled ? void 0 : 0,
  135. "aria-disabled": disabled || void 0,
  136. "onClick": () => onClickAction(action, index)
  137. }, [renderActionContent(action, index)]);
  138. };
  139. onMounted(() => {
  140. updateLocation();
  141. watchEffect(() => {
  142. var _a;
  143. popupRef.value = (_a = popoverRef.value) == null ? void 0 : _a.popupRef.value;
  144. });
  145. });
  146. onBeforeUnmount(() => {
  147. if (popper) {
  148. popper.destroy();
  149. popper = null;
  150. }
  151. });
  152. watch(() => [show.value, props.offset, props.placement], updateLocation);
  153. useClickAway([wrapperRef, popupRef], onClickAway, {
  154. eventName: "touchstart"
  155. });
  156. return () => {
  157. var _a;
  158. return _createVNode(_Fragment, null, [_createVNode("span", {
  159. "ref": wrapperRef,
  160. "class": bem("wrapper"),
  161. "onClick": onClickWrapper
  162. }, [(_a = slots.reference) == null ? void 0 : _a.call(slots)]), _createVNode(Popup, _mergeProps({
  163. "ref": popoverRef,
  164. "show": show.value,
  165. "class": bem([props.theme]),
  166. "position": "",
  167. "transition": "van-popover-zoom",
  168. "lockScroll": false,
  169. "onUpdate:show": updateShow
  170. }, attrs, pick(props, popupProps)), {
  171. default: () => [props.showArrow && _createVNode("div", {
  172. "class": bem("arrow")
  173. }, null), _createVNode("div", {
  174. "role": "menu",
  175. "class": bem("content")
  176. }, [slots.default ? slots.default() : props.actions.map(renderAction)])]
  177. })]);
  178. };
  179. }
  180. });
  181. export {
  182. stdin_default as default,
  183. popoverProps
  184. };