UNPKG

@fecp/mobile

Version:

208 lines (207 loc) 6.73 kB
import { defineComponent, ref, computed, onMounted, nextTick, watch, onActivated, onDeactivated, withDirectives, createVNode, mergeProps, vShow, Teleport } from "vue"; import { useEventListener, useRect } from "../../../../../../node_modules/.pnpm/@vant_use@1.6.0_vue@3.5.13_typescript@5.7.3_/node_modules/@vant/use/dist/index.esm.mjs"; import { useTouch } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/composables/use-touch.mjs"; import stdin_default$1 from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/icon/index.mjs"; import { createNamespace } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/utils/create.mjs"; import { makeStringProp, makeNumberProp } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/utils/props.mjs"; import { windowHeight, windowWidth } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/utils/dom.mjs"; import { addUnit } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/utils/format.mjs"; import { pick } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/utils/basic.mjs"; import { closest } from "../../../../../../node_modules/.pnpm/vant@4.9.17_vue@3.5.13_typescript@5.7.3_/node_modules/vant/es/utils/closest.mjs"; const floatingBubbleProps = { gapX: makeNumberProp(24), gapY: makeNumberProp(24), icon: String, axis: makeStringProp("y"), magnetic: String, offset: { type: Object, default: () => ({ x: -1, y: -1 }) }, teleport: { type: [String, Object], default: "body" } }; const [name, bem] = createNamespace("floating-bubble"); var stdin_default = defineComponent({ name, inheritAttrs: false, props: floatingBubbleProps, emits: ["click", "update:offset", "offsetChange"], setup(props, { slots, emit, attrs }) { const rootRef = ref(); const state = ref({ x: 0, y: 0, width: 0, height: 0 }); const boundary = computed(() => ({ top: props.gapY, right: windowWidth.value - state.value.width - props.gapX, bottom: windowHeight.value - state.value.height - props.gapY, left: props.gapX })); const dragging = ref(false); let initialized = false; const rootStyle = computed(() => { const style = {}; const x = addUnit(state.value.x); const y = addUnit(state.value.y); style.transform = `translate3d(${x}, ${y}, 0)`; if (dragging.value || !initialized) { style.transition = "none"; } return style; }); const updateState = () => { if (!show.value) return; const { width, height } = useRect(rootRef.value); const { offset } = props; state.value = { x: offset.x > -1 ? offset.x : windowWidth.value - width - props.gapX, y: offset.y > -1 ? offset.y : windowHeight.value - height - props.gapY, width, height }; }; const touch = useTouch(); let prevX = 0; let prevY = 0; const onTouchStart = (e) => { touch.start(e); dragging.value = true; prevX = state.value.x; prevY = state.value.y; }; const onTouchMove = (e) => { e.preventDefault(); touch.move(e); if (props.axis === "lock") return; if (!touch.isTap.value) { if (props.axis === "x" || props.axis === "xy") { let nextX = prevX + touch.deltaX.value; if (nextX < boundary.value.left) nextX = boundary.value.left; if (nextX > boundary.value.right) nextX = boundary.value.right; state.value.x = nextX; } if (props.axis === "y" || props.axis === "xy") { let nextY = prevY + touch.deltaY.value; if (nextY < boundary.value.top) nextY = boundary.value.top; if (nextY > boundary.value.bottom) nextY = boundary.value.bottom; state.value.y = nextY; } const offset = pick(state.value, ["x", "y"]); emit("update:offset", offset); } }; useEventListener("touchmove", onTouchMove, { target: rootRef }); const onTouchEnd = () => { dragging.value = false; nextTick(() => { if (props.magnetic === "x") { const nextX = closest( [boundary.value.left, boundary.value.right], state.value.x ); state.value.x = nextX; } if (props.magnetic === "y") { const nextY = closest( [boundary.value.top, boundary.value.bottom], state.value.y ); state.value.y = nextY; } if (!touch.isTap.value) { const offset = pick(state.value, ["x", "y"]); emit("update:offset", offset); if (prevX !== offset.x || prevY !== offset.y) { emit("offsetChange", offset); } } }); }; const onClick = (e) => { if (touch.isTap.value) emit("click", e); else e.stopPropagation(); }; onMounted(() => { updateState(); nextTick(() => { initialized = true; }); }); watch( [ windowWidth, windowHeight, () => props.gapX, () => props.gapY, () => props.offset ], updateState, { deep: true } ); const show = ref(true); onActivated(() => { show.value = true; }); onDeactivated(() => { if (props.teleport) { show.value = false; } }); return () => { const Content = withDirectives( createVNode( "div", mergeProps( { class: bem(), ref: rootRef, onTouchstartPassive: onTouchStart, onTouchend: onTouchEnd, onTouchcancel: onTouchEnd, onClickCapture: onClick, style: rootStyle.value }, attrs ), [ slots.default ? slots.default() : createVNode( stdin_default$1, { name: props.icon, class: bem("icon") }, null ) ] ), [[vShow, show.value]] ); return props.teleport ? createVNode( Teleport, { to: props.teleport }, { default: () => [Content] } ) : Content; }; } }); export { stdin_default as default, floatingBubbleProps };