FloatingBubble.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. var __create = Object.create;
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __getProtoOf = Object.getPrototypeOf;
  6. var __hasOwnProp = Object.prototype.hasOwnProperty;
  7. var __export = (target, all) => {
  8. for (var name2 in all)
  9. __defProp(target, name2, { get: all[name2], enumerable: true });
  10. };
  11. var __copyProps = (to, from, except, desc) => {
  12. if (from && typeof from === "object" || typeof from === "function") {
  13. for (let key of __getOwnPropNames(from))
  14. if (!__hasOwnProp.call(to, key) && key !== except)
  15. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  16. }
  17. return to;
  18. };
  19. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  20. // If the importer is in node compatibility mode or this is not an ESM
  21. // file that has been converted to a CommonJS file using a Babel-
  22. // compatible transform (i.e. "__esModule" has not been set), then set
  23. // "default" to the CommonJS "module.exports" for node compatibility.
  24. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  25. mod
  26. ));
  27. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  28. var stdin_exports = {};
  29. __export(stdin_exports, {
  30. default: () => stdin_default,
  31. floatingBubbleProps: () => floatingBubbleProps
  32. });
  33. module.exports = __toCommonJS(stdin_exports);
  34. var import_vue = require("vue");
  35. var import_utils = require("../utils");
  36. var import_use = require("@vant/use");
  37. var import_use_touch = require("../composables/use-touch");
  38. var import_icon = __toESM(require("../icon"));
  39. const floatingBubbleProps = {
  40. gap: (0, import_utils.makeNumberProp)(24),
  41. icon: String,
  42. axis: (0, import_utils.makeStringProp)("y"),
  43. magnetic: String,
  44. offset: {
  45. type: Object,
  46. default: () => ({
  47. x: -1,
  48. y: -1
  49. })
  50. },
  51. teleport: {
  52. type: [String, Object],
  53. default: "body"
  54. }
  55. };
  56. const [name, bem] = (0, import_utils.createNamespace)("floating-bubble");
  57. var stdin_default = (0, import_vue.defineComponent)({
  58. name,
  59. inheritAttrs: false,
  60. props: floatingBubbleProps,
  61. emits: ["click", "update:offset", "offsetChange"],
  62. setup(props, {
  63. slots,
  64. emit,
  65. attrs
  66. }) {
  67. const rootRef = (0, import_vue.ref)();
  68. const state = (0, import_vue.ref)({
  69. x: 0,
  70. y: 0,
  71. width: 0,
  72. height: 0
  73. });
  74. const boundary = (0, import_vue.computed)(() => ({
  75. top: props.gap,
  76. right: import_utils.windowWidth.value - state.value.width - props.gap,
  77. bottom: import_utils.windowHeight.value - state.value.height - props.gap,
  78. left: props.gap
  79. }));
  80. const dragging = (0, import_vue.ref)(false);
  81. let initialized = false;
  82. const rootStyle = (0, import_vue.computed)(() => {
  83. const style = {};
  84. const x = (0, import_utils.addUnit)(state.value.x);
  85. const y = (0, import_utils.addUnit)(state.value.y);
  86. style.transform = `translate3d(${x}, ${y}, 0)`;
  87. if (dragging.value || !initialized) {
  88. style.transition = "none";
  89. }
  90. return style;
  91. });
  92. const updateState = () => {
  93. if (!show.value) return;
  94. const {
  95. width,
  96. height
  97. } = (0, import_use.useRect)(rootRef.value);
  98. const {
  99. offset
  100. } = props;
  101. state.value = {
  102. x: offset.x > -1 ? offset.x : import_utils.windowWidth.value - width - props.gap,
  103. y: offset.y > -1 ? offset.y : import_utils.windowHeight.value - height - props.gap,
  104. width,
  105. height
  106. };
  107. };
  108. const touch = (0, import_use_touch.useTouch)();
  109. let prevX = 0;
  110. let prevY = 0;
  111. const onTouchStart = (e) => {
  112. touch.start(e);
  113. dragging.value = true;
  114. prevX = state.value.x;
  115. prevY = state.value.y;
  116. };
  117. const onTouchMove = (e) => {
  118. e.preventDefault();
  119. touch.move(e);
  120. if (props.axis === "lock") return;
  121. if (!touch.isTap.value) {
  122. if (props.axis === "x" || props.axis === "xy") {
  123. let nextX = prevX + touch.deltaX.value;
  124. if (nextX < boundary.value.left) nextX = boundary.value.left;
  125. if (nextX > boundary.value.right) nextX = boundary.value.right;
  126. state.value.x = nextX;
  127. }
  128. if (props.axis === "y" || props.axis === "xy") {
  129. let nextY = prevY + touch.deltaY.value;
  130. if (nextY < boundary.value.top) nextY = boundary.value.top;
  131. if (nextY > boundary.value.bottom) nextY = boundary.value.bottom;
  132. state.value.y = nextY;
  133. }
  134. const offset = (0, import_utils.pick)(state.value, ["x", "y"]);
  135. emit("update:offset", offset);
  136. }
  137. };
  138. (0, import_use.useEventListener)("touchmove", onTouchMove, {
  139. target: rootRef
  140. });
  141. const onTouchEnd = () => {
  142. dragging.value = false;
  143. (0, import_vue.nextTick)(() => {
  144. if (props.magnetic === "x") {
  145. const nextX = (0, import_utils.closest)([boundary.value.left, boundary.value.right], state.value.x);
  146. state.value.x = nextX;
  147. }
  148. if (props.magnetic === "y") {
  149. const nextY = (0, import_utils.closest)([boundary.value.top, boundary.value.bottom], state.value.y);
  150. state.value.y = nextY;
  151. }
  152. if (!touch.isTap.value) {
  153. const offset = (0, import_utils.pick)(state.value, ["x", "y"]);
  154. emit("update:offset", offset);
  155. if (prevX !== offset.x || prevY !== offset.y) {
  156. emit("offsetChange", offset);
  157. }
  158. }
  159. });
  160. };
  161. const onClick = (e) => {
  162. if (touch.isTap.value) emit("click", e);
  163. else e.stopPropagation();
  164. };
  165. (0, import_vue.onMounted)(() => {
  166. updateState();
  167. (0, import_vue.nextTick)(() => {
  168. initialized = true;
  169. });
  170. });
  171. (0, import_vue.watch)([import_utils.windowWidth, import_utils.windowHeight, () => props.gap, () => props.offset], updateState, {
  172. deep: true
  173. });
  174. const show = (0, import_vue.ref)(true);
  175. (0, import_vue.onActivated)(() => {
  176. show.value = true;
  177. });
  178. (0, import_vue.onDeactivated)(() => {
  179. if (props.teleport) {
  180. show.value = false;
  181. }
  182. });
  183. return () => {
  184. const Content = (0, import_vue.withDirectives)((0, import_vue.createVNode)("div", (0, import_vue.mergeProps)({
  185. "class": bem(),
  186. "ref": rootRef,
  187. "onTouchstartPassive": onTouchStart,
  188. "onTouchend": onTouchEnd,
  189. "onTouchcancel": onTouchEnd,
  190. "onClickCapture": onClick,
  191. "style": rootStyle.value
  192. }, attrs), [slots.default ? slots.default() : (0, import_vue.createVNode)(import_icon.default, {
  193. "name": props.icon,
  194. "class": bem("icon")
  195. }, null)]), [[import_vue.vShow, show.value]]);
  196. return props.teleport ? (0, import_vue.createVNode)(import_vue.Teleport, {
  197. "to": props.teleport
  198. }, {
  199. default: () => [Content]
  200. }) : Content;
  201. };
  202. }
  203. });