初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
export const DRAG_START_GUARD_PX = 8;
|
||||
|
||||
const INTERACTIVE_SELECTOR = "button, input, select, textarea, a[href], [contenteditable]:not([contenteditable='false'])";
|
||||
|
||||
export function pointInsideExpandedRect(x, y, rect, padding = DRAG_START_GUARD_PX) {
|
||||
return x >= rect.left - padding
|
||||
&& x <= rect.right + padding
|
||||
&& y >= rect.top - padding
|
||||
&& y <= rect.bottom + padding;
|
||||
}
|
||||
|
||||
export function isProtectedDragStart(card, event, padding = DRAG_START_GUARD_PX) {
|
||||
const target = typeof Element !== "undefined" && event.target instanceof Element ? event.target : null;
|
||||
if (target?.closest(INTERACTIVE_SELECTOR)) return true;
|
||||
if (!Number.isFinite(event.clientX) || !Number.isFinite(event.clientY)) return false;
|
||||
return [...card.querySelectorAll(INTERACTIVE_SELECTOR)].some((control) => (
|
||||
pointInsideExpandedRect(event.clientX, event.clientY, control.getBoundingClientRect(), padding)
|
||||
));
|
||||
}
|
||||
|
||||
export function protectCardDragStart(card, { locked = false } = {}) {
|
||||
let dragging = false;
|
||||
let restoreListeners = null;
|
||||
|
||||
const restore = () => {
|
||||
restoreListeners?.();
|
||||
restoreListeners = null;
|
||||
if (!locked && !dragging) card.draggable = true;
|
||||
};
|
||||
|
||||
card.draggable = !locked;
|
||||
card.addEventListener("pointerdown", (event) => {
|
||||
if (locked || dragging) return;
|
||||
restore();
|
||||
if (!isProtectedDragStart(card, event)) {
|
||||
card.draggable = true;
|
||||
return;
|
||||
}
|
||||
card.draggable = false;
|
||||
const pointerId = event.pointerId;
|
||||
const finish = (finishEvent) => {
|
||||
if (finishEvent.pointerId !== pointerId) return;
|
||||
queueMicrotask(restore);
|
||||
};
|
||||
window.addEventListener("pointerup", finish, true);
|
||||
window.addEventListener("pointercancel", finish, true);
|
||||
restoreListeners = () => {
|
||||
window.removeEventListener("pointerup", finish, true);
|
||||
window.removeEventListener("pointercancel", finish, true);
|
||||
};
|
||||
}, true);
|
||||
card.addEventListener("dragstart", (event) => {
|
||||
if (locked || !card.draggable || isProtectedDragStart(card, event)) {
|
||||
event.preventDefault();
|
||||
restore();
|
||||
return;
|
||||
}
|
||||
dragging = true;
|
||||
restoreListeners?.();
|
||||
restoreListeners = null;
|
||||
card.classList.add("is-dragging");
|
||||
});
|
||||
card.addEventListener("dragend", () => {
|
||||
dragging = false;
|
||||
card.classList.remove("is-dragging");
|
||||
restore();
|
||||
});
|
||||
|
||||
return { restore };
|
||||
}
|
||||
|
||||
export function reorderByKey(items, sourceKey, targetKey) {
|
||||
const order = [...items];
|
||||
const from = order.indexOf(sourceKey);
|
||||
const target = order.indexOf(targetKey);
|
||||
if (from < 0 || target < 0 || from === target) return null;
|
||||
order.splice(target, 0, order.splice(from, 1)[0]);
|
||||
return order;
|
||||
}
|
||||
Reference in New Issue
Block a user