175 lines
5.0 KiB
JavaScript
175 lines
5.0 KiB
JavaScript
import { ref, reactive, computed, defineComponent, createVNode as _createVNode } from "vue";
|
|
import { clamp, isDef, numericProp, preventDefault, callInterceptor, createNamespace, makeNumericProp } from "../utils/index.mjs";
|
|
import { useRect, useClickAway, useEventListener } from "@vant/use";
|
|
import { useTouch } from "../composables/use-touch.mjs";
|
|
import { useExpose } from "../composables/use-expose.mjs";
|
|
const [name, bem] = createNamespace("swipe-cell");
|
|
const swipeCellProps = {
|
|
name: makeNumericProp(""),
|
|
disabled: Boolean,
|
|
leftWidth: numericProp,
|
|
rightWidth: numericProp,
|
|
beforeClose: Function,
|
|
stopPropagation: Boolean
|
|
};
|
|
var stdin_default = defineComponent({
|
|
name,
|
|
props: swipeCellProps,
|
|
emits: ["open", "close", "click"],
|
|
setup(props, {
|
|
emit,
|
|
slots
|
|
}) {
|
|
let opened;
|
|
let lockClick;
|
|
let startOffset;
|
|
let isInBeforeClosing;
|
|
const root = ref();
|
|
const leftRef = ref();
|
|
const rightRef = ref();
|
|
const state = reactive({
|
|
offset: 0,
|
|
dragging: false
|
|
});
|
|
const touch = useTouch();
|
|
const getWidthByRef = (ref2) => ref2.value ? useRect(ref2).width : 0;
|
|
const leftWidth = computed(() => isDef(props.leftWidth) ? +props.leftWidth : getWidthByRef(leftRef));
|
|
const rightWidth = computed(() => isDef(props.rightWidth) ? +props.rightWidth : getWidthByRef(rightRef));
|
|
const open = (side) => {
|
|
state.offset = side === "left" ? leftWidth.value : -rightWidth.value;
|
|
if (!opened) {
|
|
opened = true;
|
|
emit("open", {
|
|
name: props.name,
|
|
position: side
|
|
});
|
|
}
|
|
};
|
|
const close = (position) => {
|
|
state.offset = 0;
|
|
if (opened) {
|
|
opened = false;
|
|
emit("close", {
|
|
name: props.name,
|
|
position
|
|
});
|
|
}
|
|
};
|
|
const toggle = (side) => {
|
|
const offset = Math.abs(state.offset);
|
|
const THRESHOLD = 0.15;
|
|
const threshold = opened ? 1 - THRESHOLD : THRESHOLD;
|
|
const width = side === "left" ? leftWidth.value : rightWidth.value;
|
|
if (width && offset > width * threshold) {
|
|
open(side);
|
|
} else {
|
|
close(side);
|
|
}
|
|
};
|
|
const onTouchStart = (event) => {
|
|
if (!props.disabled) {
|
|
startOffset = state.offset;
|
|
touch.start(event);
|
|
}
|
|
};
|
|
const onTouchMove = (event) => {
|
|
if (props.disabled) {
|
|
return;
|
|
}
|
|
const {
|
|
deltaX
|
|
} = touch;
|
|
touch.move(event);
|
|
if (touch.isHorizontal()) {
|
|
lockClick = true;
|
|
state.dragging = true;
|
|
const isEdge = !opened || deltaX.value * startOffset < 0;
|
|
if (isEdge) {
|
|
preventDefault(event, props.stopPropagation);
|
|
}
|
|
state.offset = clamp(deltaX.value + startOffset, -rightWidth.value, leftWidth.value);
|
|
}
|
|
};
|
|
const onTouchEnd = () => {
|
|
if (state.dragging) {
|
|
state.dragging = false;
|
|
toggle(state.offset > 0 ? "left" : "right");
|
|
setTimeout(() => {
|
|
lockClick = false;
|
|
}, 0);
|
|
}
|
|
};
|
|
const onClick = (position = "outside", event) => {
|
|
if (isInBeforeClosing) return;
|
|
emit("click", position);
|
|
if (opened && !lockClick) {
|
|
isInBeforeClosing = true;
|
|
callInterceptor(props.beforeClose, {
|
|
args: [{
|
|
event,
|
|
name: props.name,
|
|
position
|
|
}],
|
|
done: () => {
|
|
isInBeforeClosing = false;
|
|
close(position);
|
|
},
|
|
canceled: () => isInBeforeClosing = false,
|
|
error: () => isInBeforeClosing = false
|
|
});
|
|
}
|
|
};
|
|
const getClickHandler = (position, stop) => (event) => {
|
|
if (stop) {
|
|
event.stopPropagation();
|
|
}
|
|
if (lockClick) {
|
|
return;
|
|
}
|
|
onClick(position, event);
|
|
};
|
|
const renderSideContent = (side, ref2) => {
|
|
const contentSlot = slots[side];
|
|
if (contentSlot) {
|
|
return _createVNode("div", {
|
|
"ref": ref2,
|
|
"class": bem(side),
|
|
"onClick": getClickHandler(side, true)
|
|
}, [contentSlot()]);
|
|
}
|
|
};
|
|
useExpose({
|
|
open,
|
|
close
|
|
});
|
|
useClickAway(root, (event) => onClick("outside", event), {
|
|
eventName: "touchstart"
|
|
});
|
|
useEventListener("touchmove", onTouchMove, {
|
|
target: root
|
|
});
|
|
return () => {
|
|
var _a;
|
|
const wrapperStyle = {
|
|
transform: `translate3d(${state.offset}px, 0, 0)`,
|
|
transitionDuration: state.dragging ? "0s" : ".6s"
|
|
};
|
|
return _createVNode("div", {
|
|
"ref": root,
|
|
"class": bem(),
|
|
"onClick": getClickHandler("cell", lockClick),
|
|
"onTouchstartPassive": onTouchStart,
|
|
"onTouchend": onTouchEnd,
|
|
"onTouchcancel": onTouchEnd
|
|
}, [_createVNode("div", {
|
|
"class": bem("wrapper"),
|
|
"style": wrapperStyle
|
|
}, [renderSideContent("left", leftRef), (_a = slots.default) == null ? void 0 : _a.call(slots), renderSideContent("right", rightRef)])]);
|
|
};
|
|
}
|
|
});
|
|
export {
|
|
stdin_default as default,
|
|
swipeCellProps
|
|
};
|