Popover.mjs 5.2 KB

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