@kietpt2003/react-native-core-ui
Version:
React Native Core UI components by KietPT
249 lines (248 loc) • 12.5 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/// <reference lib="dom" /> TODO: DO NOT REMOVE THIS LINE
import React from "react";
import { DEFAULT_PROPS } from "../constants/DraggableFlatList/constants";
import { CellProvider } from "../context/DraggableFlatList/cellContext";
import DraggableFlatListProvider from "../context/DraggableFlatList/draggableFlatListContext";
function DraggableFlatListWeb(_a) {
var { data, renderItem, keyExtractor, onDragEnd, onDragBegin, onRelease, onPlaceholderIndexChange, activationDistance = DEFAULT_PROPS.activationDistance, containerStyle, horizontal = false } = _a, props = __rest(_a, ["data", "renderItem", "keyExtractor", "onDragEnd", "onDragBegin", "onRelease", "onPlaceholderIndexChange", "activationDistance", "containerStyle", "horizontal"]);
const [draggedIndex, setDraggedIndex] = React.useState(null);
const [tempData, setTempData] = React.useState(null);
const placeholderIndexRef = React.useRef(null);
const containerRef = React.useRef(null);
const itemRefs = React.useRef(new Map());
const currentIndexRef = React.useRef(null);
const draggedKeyRef = React.useRef(null);
const positionsRef = React.useRef(new Map());
const lastReorderIndexRef = React.useRef(null);
const lastPointerRef = React.useRef(null);
const dragAnchorRef = React.useRef(null);
const containerRectRef = React.useRef(null);
const [dragGhost, setDragGhost] = React.useState(null);
const activeKey = draggedKeyRef.current;
const getKey = React.useCallback((item, index) => {
return keyExtractor(item, index);
}, [keyExtractor]);
const handleDragStart = React.useCallback((e, index) => {
var _a, _b;
setDraggedIndex(index);
const key = keyExtractor(data[index], index);
draggedKeyRef.current = key;
currentIndexRef.current = index;
setTempData([...data]);
placeholderIndexRef.current = index;
onDragBegin === null || onDragBegin === void 0 ? void 0 : onDragBegin(index);
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/plain", index.toString());
const el = itemRefs.current.get(key);
if (el) {
const rect = el.getBoundingClientRect();
const container = containerRef.current;
if (container) {
containerRectRef.current = container.getBoundingClientRect();
}
const img = new Image();
img.src =
"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>";
e.dataTransfer.setDragImage(img, 0, 0);
const mouseY = e.clientY;
const mouseX = e.clientX;
const anchor = dragAnchorRef.current;
setDragGhost({
x: e.clientX,
y: e.clientY,
offsetX: (_a = anchor === null || anchor === void 0 ? void 0 : anchor.offsetX) !== null && _a !== void 0 ? _a : rect.width / 2,
offsetY: (_b = anchor === null || anchor === void 0 ? void 0 : anchor.offsetY) !== null && _b !== void 0 ? _b : rect.height / 2,
width: rect.width,
height: rect.height,
item: data[index],
index,
key,
});
}
}, [onDragBegin, data, keyExtractor]);
const handleDragEnd = React.useCallback(() => {
if (draggedIndex !== null) {
onRelease === null || onRelease === void 0 ? void 0 : onRelease(draggedIndex);
}
placeholderIndexRef.current = null;
lastPointerRef.current = null;
setDraggedIndex(null);
setDragGhost(null);
lastReorderIndexRef.current = null;
}, [draggedIndex, onRelease]);
const handleContainerDragOver = React.useCallback((e) => {
e.preventDefault();
setDragGhost((prev) => {
const rect = containerRectRef.current;
if (!prev || !rect)
return prev;
return Object.assign(Object.assign({}, prev), { x: e.clientX - rect.left, y: e.clientY - rect.top });
});
if (!tempData || !draggedKeyRef.current)
return;
const mouseY = e.clientY;
const mouseX = e.clientX;
let nextIndex = null;
if (lastPointerRef.current) {
const dx = Math.abs(mouseX - lastPointerRef.current.x);
const dy = Math.abs(mouseY - lastPointerRef.current.y);
if (dx < 2 && dy < 2) {
return;
}
}
lastPointerRef.current = { x: mouseX, y: mouseY };
for (let i = 0; i < tempData.length; i++) {
const key = keyExtractor(tempData[i], i);
const el = itemRefs.current.get(key);
if (!el)
continue;
const rect = el.getBoundingClientRect();
const isInside = horizontal
? mouseX >= rect.left && mouseX <= rect.right
: mouseY >= rect.top && mouseY <= rect.bottom;
if (!isInside)
continue;
const isAfter = horizontal
? mouseX > rect.left + rect.width / 1.5
: mouseY > rect.top + rect.height / 1.5;
nextIndex = isAfter ? i + 1 : i;
break;
}
if (nextIndex === null ||
placeholderIndexRef.current === nextIndex ||
lastReorderIndexRef.current === nextIndex) {
return;
}
positionsRef.current.clear();
tempData.forEach((item, index) => {
const key = keyExtractor(item, index);
const el = itemRefs.current.get(key);
if (el)
positionsRef.current.set(key, el.getBoundingClientRect());
});
placeholderIndexRef.current = nextIndex;
onPlaceholderIndexChange === null || onPlaceholderIndexChange === void 0 ? void 0 : onPlaceholderIndexChange(nextIndex);
setTempData((prev) => {
if (!prev || !draggedKeyRef.current)
return prev;
const from = prev.findIndex((item, index) => keyExtractor(item, index) === draggedKeyRef.current);
if (from === -1 || from === nextIndex)
return prev;
const arr = [...prev];
const [item] = arr.splice(from, 1);
arr.splice(nextIndex, 0, item);
return arr;
});
lastReorderIndexRef.current = nextIndex;
requestAnimationFrame(() => {
positionsRef.current.forEach((prevRect, key) => {
if (key === draggedKeyRef.current)
return;
const el = itemRefs.current.get(key);
if (!el)
return;
const nextRect = el.getBoundingClientRect();
const dx = prevRect.left - nextRect.left;
const dy = prevRect.top - nextRect.top;
if (!dx && !dy)
return;
el.style.transform = `translate(${dx}px, ${dy}px)`;
el.style.transition = "none";
requestAnimationFrame(() => {
el.style.transform = "";
el.style.transition =
"transform 220ms cubic-bezier(0.22, 1, 0.36, 1)";
});
});
});
}, [tempData, horizontal, keyExtractor, onPlaceholderIndexChange]);
const workingData = tempData !== null && tempData !== void 0 ? tempData : data;
const getItemStyle = (key) => key === draggedKeyRef.current ? { opacity: 0 } : {};
React.useLayoutEffect(() => {
if (draggedKeyRef.current !== null)
return;
itemRefs.current.forEach((el) => {
el.style.transform = "";
el.style.transition = "";
});
}, [workingData]);
return (_jsx(DraggableFlatListProvider, { activeKey: activeKey, keyExtractor: keyExtractor, horizontal: !!horizontal, layoutAnimationDisabled: false, children: _jsxs("div", Object.assign({ ref: containerRef, style: Object.assign({ display: horizontal ? "flex" : "block", overflow: horizontal ? "auto" : "visible", minHeight: horizontal ? "auto" : "100%" }, containerStyle), onDragOver: handleContainerDragOver, onDrop: (e) => {
e.preventDefault();
if (!tempData || !draggedKeyRef.current)
return;
const from = data.findIndex((item) => keyExtractor(item, 0) === draggedKeyRef.current);
const to = placeholderIndexRef.current;
if (from === -1 || to == null)
return;
const newData = [...data];
const [item] = newData.splice(from, 1);
newData.splice(to, 0, item);
onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd({ from, to, data: newData });
draggedKeyRef.current = null;
currentIndexRef.current = null;
placeholderIndexRef.current = null;
setDragGhost(null);
setDraggedIndex(null);
setTempData(null);
lastReorderIndexRef.current = null;
itemRefs.current.forEach((el) => {
el.style.transform = "";
el.style.transition = "";
});
lastPointerRef.current = null;
onRelease === null || onRelease === void 0 ? void 0 : onRelease(from);
} }, props, { children: [workingData.map((item, index) => {
const key = getKey(item, index);
const isActive = key === draggedKeyRef.current;
return (_jsx(CellProvider, { isActive: isActive, children: _jsx("div", { ref: (el) => {
if (el) {
itemRefs.current.set(key, el);
}
else {
itemRefs.current.delete(key);
}
}, draggable: draggedIndex === null, onMouseDown: (e) => {
const el = itemRefs.current.get(key);
if (!el)
return;
const rect = el.getBoundingClientRect();
dragAnchorRef.current = {
offsetX: e.clientX - rect.left,
offsetY: e.clientY - rect.top,
};
}, onDragStart: (e) => {
handleDragStart(e, index);
}, onDragEnd: handleDragEnd, style: Object.assign({ cursor: draggedIndex === null ? "grab" : "grabbing", userSelect: "none", position: "relative" }, getItemStyle(key)), children: renderItem({
item,
getIndex: () => index,
drag: () => { },
isActive,
}) }) }, key));
}), dragGhost && (_jsx(CellProvider, { isActive: true, children: _jsx("div", { style: {
position: "absolute",
left: dragGhost.x - dragGhost.offsetX,
top: dragGhost.y - dragGhost.offsetY,
width: dragGhost.width,
height: dragGhost.height,
pointerEvents: "none",
zIndex: 9999,
}, children: renderItem({
item: dragGhost.item,
getIndex: () => dragGhost.index,
drag: () => { },
isActive: true,
}) }) }))] })) }));
}
export default DraggableFlatListWeb;