react-reorder-list 0.10.1 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +21 -0
- package/dist/index.mjs +279 -0
- package/dist/types-CRxTdmXH.d.mts +50 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +1 -0
- package/package.json +7 -8
- package/dist/chunks/chunk-RWSH3ATP.js +0 -248
- package/dist/components.d.ts +0 -7
- package/dist/components.js +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -1
- package/dist/types.d.ts +0 -49
- package/dist/types.js +0 -1
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { o as DivProps, p as ReorderListProps } from "./types-CRxTdmXH.mjs";
|
|
2
|
+
import { JSX } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components.d.ts
|
|
5
|
+
declare function ReorderIcon({
|
|
6
|
+
children,
|
|
7
|
+
style,
|
|
8
|
+
...props
|
|
9
|
+
}: DivProps): JSX.Element;
|
|
10
|
+
declare function ReorderList({
|
|
11
|
+
useOnlyIconToDrag,
|
|
12
|
+
selectedItemOpacity,
|
|
13
|
+
animationDuration,
|
|
14
|
+
preserveOrder,
|
|
15
|
+
onPositionChange,
|
|
16
|
+
disabled,
|
|
17
|
+
props,
|
|
18
|
+
children
|
|
19
|
+
}: ReorderListProps): JSX.Element;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { ReorderIcon, ReorderList as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import React, { Children, cloneElement, createRef, isValidElement, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
//#region src/constants.ts
|
|
3
|
+
const scrollThreshold = {
|
|
4
|
+
x: 10,
|
|
5
|
+
y: 100
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/hooks.ts
|
|
9
|
+
function useDraggable(initValue = false) {
|
|
10
|
+
const [draggable, setDraggable] = useState(initValue);
|
|
11
|
+
const enableDragging = useCallback(() => setDraggable(true), []);
|
|
12
|
+
const disableDragging = useCallback(() => setDraggable(false), []);
|
|
13
|
+
return {
|
|
14
|
+
draggable,
|
|
15
|
+
onMouseEnter: enableDragging,
|
|
16
|
+
onMouseLeave: disableDragging,
|
|
17
|
+
onTouchStart: enableDragging,
|
|
18
|
+
onTouchEnd: disableDragging
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function useStateWithHistory(initValue) {
|
|
22
|
+
const [state, setState] = useState(initValue);
|
|
23
|
+
const [prevState, setPrevState] = useState();
|
|
24
|
+
function setStateWithHistory(value) {
|
|
25
|
+
setPrevState(state);
|
|
26
|
+
setState(value);
|
|
27
|
+
}
|
|
28
|
+
return [
|
|
29
|
+
state,
|
|
30
|
+
prevState,
|
|
31
|
+
setStateWithHistory
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/icons.tsx
|
|
36
|
+
function PiDotsSixVerticalBold(props) {
|
|
37
|
+
return /* @__PURE__ */ React.createElement("span", props, /* @__PURE__ */ React.createElement("svg", {
|
|
38
|
+
viewBox: "0 0 256 256",
|
|
39
|
+
fill: "currentColor",
|
|
40
|
+
width: "1.25rem",
|
|
41
|
+
height: "1.25rem"
|
|
42
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "M108,60A16,16,0,1,1,92,44,16,16,0,0,1,108,60Zm56,16a16,16,0,1,0-16-16A16,16,0,0,0,164,76ZM92,112a16,16,0,1,0,16,16A16,16,0,0,0,92,112Zm72,0a16,16,0,1,0,16,16A16,16,0,0,0,164,112ZM92,180a16,16,0,1,0,16,16A16,16,0,0,0,92,180Zm72,0a16,16,0,1,0,16,16A16,16,0,0,0,164,180Z" })));
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/lib/react.ts
|
|
46
|
+
function calculateBoundingBoxes(children) {
|
|
47
|
+
const boundingBoxes = {};
|
|
48
|
+
Children.forEach(children, (child) => {
|
|
49
|
+
const { key } = child;
|
|
50
|
+
if (key) boundingBoxes[key] = child.props.ref.current.getBoundingClientRect();
|
|
51
|
+
});
|
|
52
|
+
return boundingBoxes;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/lib/utils.ts
|
|
56
|
+
const areOrdersEqual = (a, b) => a.length === b.length && a.every((key, index) => key === b[index]);
|
|
57
|
+
function swap(array, i, j) {
|
|
58
|
+
const temp = array[i];
|
|
59
|
+
array[i] = array[j];
|
|
60
|
+
array[j] = temp;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/components.tsx
|
|
64
|
+
if (typeof window !== "undefined") import("drag-drop-touch");
|
|
65
|
+
function Animation({ duration, children }) {
|
|
66
|
+
const [boundingBox, prevBoundingBox, setBoundingBox] = useStateWithHistory({});
|
|
67
|
+
useLayoutEffect(() => {
|
|
68
|
+
if (duration > 0) setBoundingBox(calculateBoundingBoxes(children));
|
|
69
|
+
else setBoundingBox({});
|
|
70
|
+
}, [children]);
|
|
71
|
+
useLayoutEffect(() => {
|
|
72
|
+
if (duration <= 0 || !prevBoundingBox || !Object.keys(prevBoundingBox).length) return;
|
|
73
|
+
children.forEach((child) => {
|
|
74
|
+
const { key } = child;
|
|
75
|
+
if (key == null) return;
|
|
76
|
+
const domNode = child.props.ref.current;
|
|
77
|
+
if (!domNode) return;
|
|
78
|
+
const { left: prevLeft, top: prevTop } = prevBoundingBox[key] || {};
|
|
79
|
+
const { left, top } = boundingBox[key] || {};
|
|
80
|
+
const changeInX = prevLeft - left;
|
|
81
|
+
const changeInY = prevTop - top;
|
|
82
|
+
if (!changeInX && !changeInY) return;
|
|
83
|
+
requestAnimationFrame(() => {
|
|
84
|
+
domNode.style.transform = `translate(${changeInX}px, ${changeInY}px)`;
|
|
85
|
+
domNode.style.transition = "none";
|
|
86
|
+
requestAnimationFrame(() => {
|
|
87
|
+
domNode.style.transform = "";
|
|
88
|
+
domNode.style.transition = `transform ${duration}ms`;
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}, [boundingBox]);
|
|
93
|
+
return children;
|
|
94
|
+
}
|
|
95
|
+
function ReorderIcon({ children = /* @__PURE__ */ React.createElement(PiDotsSixVerticalBold, null), style, ...props }) {
|
|
96
|
+
return /* @__PURE__ */ React.createElement("span", {
|
|
97
|
+
style: {
|
|
98
|
+
cursor: "grab",
|
|
99
|
+
...style
|
|
100
|
+
},
|
|
101
|
+
...props
|
|
102
|
+
}, children);
|
|
103
|
+
}
|
|
104
|
+
function ReorderItem({ useOnlyIconToDrag, disable, ref, style, children, onTouchEnd: propOnTouchEnd, ...events }) {
|
|
105
|
+
const { draggable, onTouchEnd: draggableOnTouchEnd, ...draggableProps } = useDraggable();
|
|
106
|
+
const recursiveClone = (children) => Children.map(children, (child) => {
|
|
107
|
+
if (!isValidElement(child)) return child;
|
|
108
|
+
return cloneElement(child, child.type === ReorderIcon ? draggableProps : {}, recursiveClone(child.props.children));
|
|
109
|
+
});
|
|
110
|
+
const recursiveChildren = useMemo(() => useOnlyIconToDrag ? recursiveClone(children) : children, [useOnlyIconToDrag, children]);
|
|
111
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
112
|
+
ref,
|
|
113
|
+
draggable: !disable && draggable,
|
|
114
|
+
style: {
|
|
115
|
+
...style,
|
|
116
|
+
touchAction: "pan-y",
|
|
117
|
+
cursor: useOnlyIconToDrag ? "default" : "grab"
|
|
118
|
+
},
|
|
119
|
+
...!disable && {
|
|
120
|
+
...events,
|
|
121
|
+
...!useOnlyIconToDrag && draggableProps,
|
|
122
|
+
onTouchEnd: (event) => {
|
|
123
|
+
draggableOnTouchEnd(event);
|
|
124
|
+
propOnTouchEnd(event);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}, recursiveChildren);
|
|
128
|
+
}
|
|
129
|
+
function ReorderList({ useOnlyIconToDrag = false, selectedItemOpacity = .5, animationDuration = 300, preserveOrder = true, onPositionChange, disabled = false, props, children }) {
|
|
130
|
+
const containerRef = useRef(null);
|
|
131
|
+
const itemRefs = useRef(/* @__PURE__ */ new Map());
|
|
132
|
+
const [order, setOrder] = useState([]);
|
|
133
|
+
const [dragState, setDragState] = useState();
|
|
134
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
135
|
+
const [scroll, setScroll] = useState();
|
|
136
|
+
const childMap = useMemo(() => {
|
|
137
|
+
const map = /* @__PURE__ */ new Map();
|
|
138
|
+
Children.forEach(children, (child) => {
|
|
139
|
+
if (!isValidElement(child)) return;
|
|
140
|
+
const { key, props } = child;
|
|
141
|
+
if (key != null) map.set(key, {
|
|
142
|
+
child,
|
|
143
|
+
disabled: props["data-disable-reorder"]
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
return map;
|
|
147
|
+
}, [children]);
|
|
148
|
+
const orderedChildren = useMemo(() => {
|
|
149
|
+
if (!order.length) return [];
|
|
150
|
+
return order.flatMap((key, orderIndex) => {
|
|
151
|
+
const entry = childMap.get(key);
|
|
152
|
+
if (!entry) return [];
|
|
153
|
+
const { child, disabled } = entry;
|
|
154
|
+
const ref = getRef(key);
|
|
155
|
+
const isSelected = dragState?.currentIndex === orderIndex;
|
|
156
|
+
return /* @__PURE__ */ React.createElement(ReorderItem, {
|
|
157
|
+
key,
|
|
158
|
+
ref,
|
|
159
|
+
useOnlyIconToDrag,
|
|
160
|
+
disable: disabled,
|
|
161
|
+
style: { opacity: isSelected ? selectedItemOpacity : 1 },
|
|
162
|
+
onDragStart: (event) => {
|
|
163
|
+
event.stopPropagation();
|
|
164
|
+
setDragState({
|
|
165
|
+
startIndex: orderIndex,
|
|
166
|
+
currentIndex: orderIndex,
|
|
167
|
+
startOrder: [...order],
|
|
168
|
+
startRect: ref.current?.getBoundingClientRect?.() || void 0
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
onDragEnter: (event) => {
|
|
172
|
+
event.stopPropagation();
|
|
173
|
+
if (!dragState || dragState.currentIndex === orderIndex || isAnimating) return;
|
|
174
|
+
const { width: startWidth, height: startHeight } = dragState.startRect || {
|
|
175
|
+
width: 0,
|
|
176
|
+
height: 0
|
|
177
|
+
};
|
|
178
|
+
const { left, top, width, height } = event.currentTarget.getBoundingClientRect();
|
|
179
|
+
if (event.clientX - left > Math.min(startWidth, width) || event.clientY - top > Math.min(startHeight, height)) return;
|
|
180
|
+
setDragState((prev) => prev ? {
|
|
181
|
+
...prev,
|
|
182
|
+
currentIndex: orderIndex
|
|
183
|
+
} : void 0);
|
|
184
|
+
setOrder(() => {
|
|
185
|
+
const newOrder = [...dragState.startOrder];
|
|
186
|
+
const shiftForward = dragState.startIndex < orderIndex;
|
|
187
|
+
const increment = shiftForward ? 1 : -1;
|
|
188
|
+
let currentPos = dragState.startIndex;
|
|
189
|
+
for (let index = dragState.startIndex + increment; shiftForward ? index <= orderIndex : index >= orderIndex; index += increment) {
|
|
190
|
+
const key = dragState.startOrder[index];
|
|
191
|
+
if (childMap.get(key)?.disabled) continue;
|
|
192
|
+
swap(newOrder, currentPos, index);
|
|
193
|
+
currentPos = index;
|
|
194
|
+
}
|
|
195
|
+
return newOrder;
|
|
196
|
+
});
|
|
197
|
+
setIsAnimating(true);
|
|
198
|
+
setTimeout(() => setIsAnimating(false), animationDuration);
|
|
199
|
+
},
|
|
200
|
+
onDragEnd: handleDragEnd,
|
|
201
|
+
onTouchMove: (event) => {
|
|
202
|
+
if (!dragState) return;
|
|
203
|
+
const { clientX, screenX, clientY, screenY } = event.touches[0];
|
|
204
|
+
const left = clientX < scrollThreshold.x ? -5 : innerWidth - screenX < scrollThreshold.x ? 5 : 0;
|
|
205
|
+
const top = clientY < scrollThreshold.y ? -10 : innerHeight - screenY < scrollThreshold.y ? 10 : 0;
|
|
206
|
+
setScroll(left || top ? {
|
|
207
|
+
left,
|
|
208
|
+
top
|
|
209
|
+
} : void 0);
|
|
210
|
+
},
|
|
211
|
+
onTouchEnd: () => setScroll(void 0)
|
|
212
|
+
}, child);
|
|
213
|
+
});
|
|
214
|
+
}, [
|
|
215
|
+
childMap,
|
|
216
|
+
order,
|
|
217
|
+
dragState,
|
|
218
|
+
isAnimating,
|
|
219
|
+
useOnlyIconToDrag,
|
|
220
|
+
selectedItemOpacity,
|
|
221
|
+
animationDuration
|
|
222
|
+
]);
|
|
223
|
+
function getRef(key) {
|
|
224
|
+
if (!itemRefs.current.has(key)) itemRefs.current.set(key, createRef());
|
|
225
|
+
return itemRefs.current.get(key);
|
|
226
|
+
}
|
|
227
|
+
function handleDragEnd(event) {
|
|
228
|
+
if (event) {
|
|
229
|
+
event.stopPropagation();
|
|
230
|
+
if (dragState && dragState.currentIndex !== dragState.startIndex) onPositionChange?.({
|
|
231
|
+
start: dragState.startIndex,
|
|
232
|
+
end: dragState.currentIndex,
|
|
233
|
+
oldOrder: dragState.startOrder,
|
|
234
|
+
newOrder: order,
|
|
235
|
+
revert: () => setOrder(dragState.startOrder)
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
setDragState(void 0);
|
|
239
|
+
setScroll(void 0);
|
|
240
|
+
}
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
const currentKeys = [];
|
|
243
|
+
Children.forEach(children, (child) => {
|
|
244
|
+
if (!isValidElement(child)) return;
|
|
245
|
+
const { key } = child;
|
|
246
|
+
if (key != null) currentKeys.push(key);
|
|
247
|
+
});
|
|
248
|
+
let newOrder;
|
|
249
|
+
if (preserveOrder) {
|
|
250
|
+
const currentKeySet = new Set(currentKeys);
|
|
251
|
+
const orderSet = new Set(order);
|
|
252
|
+
const newKeys = currentKeys.filter((key) => !orderSet.has(key));
|
|
253
|
+
newOrder = [...order.filter((key) => currentKeySet.has(key)), ...newKeys];
|
|
254
|
+
} else newOrder = currentKeys;
|
|
255
|
+
if (!areOrdersEqual(order, newOrder)) {
|
|
256
|
+
if (dragState) setDragState(void 0);
|
|
257
|
+
setOrder(newOrder);
|
|
258
|
+
}
|
|
259
|
+
}, [children]);
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
if (!scroll) return;
|
|
262
|
+
const { left, top } = scroll;
|
|
263
|
+
const { scrollWidth, scrollHeight } = document.body;
|
|
264
|
+
const interval = setInterval(() => {
|
|
265
|
+
if (left < 0 || top < 0 || scrollWidth - scrollX > innerWidth - left || scrollHeight - scrollY > innerHeight - top) scrollBy({
|
|
266
|
+
left,
|
|
267
|
+
top,
|
|
268
|
+
behavior: "instant"
|
|
269
|
+
});
|
|
270
|
+
}, 20);
|
|
271
|
+
return () => clearInterval(interval);
|
|
272
|
+
}, [scroll]);
|
|
273
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
274
|
+
ref: containerRef,
|
|
275
|
+
...props
|
|
276
|
+
}, disabled ? children : /* @__PURE__ */ React.createElement(Animation, { duration: dragState && !scroll ? animationDuration : 0 }, orderedChildren));
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
export { ReorderIcon, ReorderList as default };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CSSProperties, DetailedHTMLProps, DragEventHandler, HTMLAttributes, Key, MouseEventHandler, ReactElement, ReactNode, RefObject, TouchEventHandler } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type AnimationProps = {
|
|
5
|
+
duration: number;
|
|
6
|
+
children: Child[];
|
|
7
|
+
};
|
|
8
|
+
type BoundingBox = Record<string, DOMRect>;
|
|
9
|
+
type Child = ReactElement<{
|
|
10
|
+
ref: RefObject<HTMLElement>;
|
|
11
|
+
}>;
|
|
12
|
+
type Order = Key[];
|
|
13
|
+
type DivDragEventHandler = DragEventHandler<HTMLDivElement>;
|
|
14
|
+
type DivMouseEventHandler = MouseEventHandler<HTMLDivElement>;
|
|
15
|
+
type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
|
16
|
+
type DivRef = RefObject<HTMLDivElement | null>;
|
|
17
|
+
type DivTouchEventHandler = TouchEventHandler<HTMLDivElement>;
|
|
18
|
+
type PositionChangeHandler = (event: {
|
|
19
|
+
start: number;
|
|
20
|
+
end: number;
|
|
21
|
+
oldOrder: Order;
|
|
22
|
+
newOrder: Order;
|
|
23
|
+
revert: RevertHandler;
|
|
24
|
+
}) => void;
|
|
25
|
+
type ReorderItemProps = {
|
|
26
|
+
useOnlyIconToDrag: boolean;
|
|
27
|
+
disable?: boolean;
|
|
28
|
+
ref: DivRef;
|
|
29
|
+
style: CSSProperties;
|
|
30
|
+
onDragStart?: DivDragEventHandler;
|
|
31
|
+
onDragEnter: DivDragEventHandler;
|
|
32
|
+
onDragEnd: DivDragEventHandler;
|
|
33
|
+
onTouchMove: DivTouchEventHandler;
|
|
34
|
+
onTouchEnd: DivTouchEventHandler;
|
|
35
|
+
children: ReactNode;
|
|
36
|
+
};
|
|
37
|
+
type ReorderListProps = {
|
|
38
|
+
useOnlyIconToDrag?: boolean;
|
|
39
|
+
selectedItemOpacity?: number;
|
|
40
|
+
animationDuration?: number;
|
|
41
|
+
preserveOrder?: boolean;
|
|
42
|
+
onPositionChange?: PositionChangeHandler;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
props?: DivProps;
|
|
45
|
+
children?: ReactNode;
|
|
46
|
+
};
|
|
47
|
+
type RevertHandler = () => void;
|
|
48
|
+
type IconProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { DivMouseEventHandler as a, DivTouchEventHandler as c, PositionChangeHandler as d, ReorderItemProps as f, DivDragEventHandler as i, IconProps as l, RevertHandler as m, BoundingBox as n, DivProps as o, ReorderListProps as p, Child as r, DivRef as s, AnimationProps as t, Order as u };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as DivMouseEventHandler, c as DivTouchEventHandler, d as PositionChangeHandler, f as ReorderItemProps, i as DivDragEventHandler, l as IconProps, m as RevertHandler, n as BoundingBox, o as DivProps, p as ReorderListProps, r as Child, s as DivRef, t as AnimationProps, u as Order } from "./types-CRxTdmXH.mjs";
|
|
2
|
+
export { AnimationProps, BoundingBox, Child, DivDragEventHandler, DivMouseEventHandler, DivProps, DivRef, DivTouchEventHandler, IconProps, Order, PositionChangeHandler, ReorderItemProps, ReorderListProps, RevertHandler };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-reorder-list",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "A simple react component that facilitates the reordering of JSX/HTML elements through drag-and-drop functionality, allowing for easy position changes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sahil Aggarwal <aggarwalsahil2004@gmail.com>",
|
|
@@ -15,15 +15,14 @@
|
|
|
15
15
|
},
|
|
16
16
|
"type": "module",
|
|
17
17
|
"exports": {
|
|
18
|
-
".": "./dist/index.
|
|
19
|
-
"./types": "./dist/types.
|
|
18
|
+
".": "./dist/index.mjs",
|
|
19
|
+
"./types": "./dist/types.mjs"
|
|
20
20
|
},
|
|
21
|
-
"main": "dist/index.js",
|
|
22
21
|
"files": [
|
|
23
22
|
"dist"
|
|
24
23
|
],
|
|
25
24
|
"sideEffects": true,
|
|
26
|
-
"types": "dist/index.d.ts",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
27
26
|
"dependencies": {
|
|
28
27
|
"drag-drop-touch": "^1.3.1"
|
|
29
28
|
},
|
|
@@ -35,7 +34,7 @@
|
|
|
35
34
|
"@types/react": "^19.2.14",
|
|
36
35
|
"prettier-package-json": "^2.8.0",
|
|
37
36
|
"release-it": "^19.2.4",
|
|
38
|
-
"
|
|
37
|
+
"tsdown": "^0.21.0",
|
|
39
38
|
"typescript": "^5.9.3"
|
|
40
39
|
},
|
|
41
40
|
"keywords": [
|
|
@@ -50,8 +49,8 @@
|
|
|
50
49
|
],
|
|
51
50
|
"scripts": {
|
|
52
51
|
"build": "pnpm i && pnpm run compile",
|
|
53
|
-
"compile": "
|
|
54
|
-
"dev": "
|
|
52
|
+
"compile": "tsdown",
|
|
53
|
+
"dev": "tsdown --watch",
|
|
55
54
|
"dry-release": "release-it --ci --dry-run",
|
|
56
55
|
"prettier": "prettier-package-json --write package.json",
|
|
57
56
|
"pub": "pnpm login && pnpm publish",
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import React2, { useRef, useState, useMemo, Children, isValidElement, createRef, useEffect, useLayoutEffect, useCallback, cloneElement } from 'react';
|
|
2
|
-
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defProps = Object.defineProperties;
|
|
5
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
9
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
|
-
var __spreadValues = (a, b) => {
|
|
11
|
-
for (var prop in b || (b = {}))
|
|
12
|
-
if (__hasOwnProp.call(b, prop))
|
|
13
|
-
__defNormalProp(a, prop, b[prop]);
|
|
14
|
-
if (__getOwnPropSymbols)
|
|
15
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
16
|
-
if (__propIsEnum.call(b, prop))
|
|
17
|
-
__defNormalProp(a, prop, b[prop]);
|
|
18
|
-
}
|
|
19
|
-
return a;
|
|
20
|
-
};
|
|
21
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
22
|
-
var __objRest = (source, exclude) => {
|
|
23
|
-
var target = {};
|
|
24
|
-
for (var prop in source)
|
|
25
|
-
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
26
|
-
target[prop] = source[prop];
|
|
27
|
-
if (source != null && __getOwnPropSymbols)
|
|
28
|
-
for (var prop of __getOwnPropSymbols(source)) {
|
|
29
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
30
|
-
target[prop] = source[prop];
|
|
31
|
-
}
|
|
32
|
-
return target;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// src/constants.ts
|
|
36
|
-
var scrollThreshold = { x: 10, y: 100 };
|
|
37
|
-
function useDraggable(initValue = false) {
|
|
38
|
-
const [draggable, setDraggable] = useState(initValue);
|
|
39
|
-
const enableDragging = useCallback(() => setDraggable(true), []);
|
|
40
|
-
const disableDragging = useCallback(() => setDraggable(false), []);
|
|
41
|
-
return { draggable, onMouseEnter: enableDragging, onMouseLeave: disableDragging, onTouchStart: enableDragging, onTouchEnd: disableDragging };
|
|
42
|
-
}
|
|
43
|
-
function useStateWithHistory(initValue) {
|
|
44
|
-
const [state, setState] = useState(initValue);
|
|
45
|
-
const [prevState, setPrevState] = useState();
|
|
46
|
-
function setStateWithHistory(value) {
|
|
47
|
-
setPrevState(state);
|
|
48
|
-
setState(value);
|
|
49
|
-
}
|
|
50
|
-
return [state, prevState, setStateWithHistory];
|
|
51
|
-
}
|
|
52
|
-
function PiDotsSixVerticalBold(props) {
|
|
53
|
-
return /* @__PURE__ */ React2.createElement("span", __spreadValues({}, props), /* @__PURE__ */ React2.createElement("svg", { viewBox: "0 0 256 256", fill: "currentColor", width: "1.25rem", height: "1.25rem" }, /* @__PURE__ */ React2.createElement("path", { d: "M108,60A16,16,0,1,1,92,44,16,16,0,0,1,108,60Zm56,16a16,16,0,1,0-16-16A16,16,0,0,0,164,76ZM92,112a16,16,0,1,0,16,16A16,16,0,0,0,92,112Zm72,0a16,16,0,1,0,16,16A16,16,0,0,0,164,112ZM92,180a16,16,0,1,0,16,16A16,16,0,0,0,92,180Zm72,0a16,16,0,1,0,16,16A16,16,0,0,0,164,180Z" })));
|
|
54
|
-
}
|
|
55
|
-
function calculateBoundingBoxes(children) {
|
|
56
|
-
const boundingBoxes = {};
|
|
57
|
-
Children.forEach(children, (child) => {
|
|
58
|
-
const { key } = child;
|
|
59
|
-
if (key) boundingBoxes[key] = child.props.ref.current.getBoundingClientRect();
|
|
60
|
-
});
|
|
61
|
-
return boundingBoxes;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// src/lib/utils.ts
|
|
65
|
-
var areOrdersEqual = (a, b) => a.length === b.length && a.every((key, index) => key === b[index]);
|
|
66
|
-
function swap(array, i, j) {
|
|
67
|
-
const temp = array[i];
|
|
68
|
-
array[i] = array[j];
|
|
69
|
-
array[j] = temp;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// src/components.tsx
|
|
73
|
-
if (typeof window !== "undefined") import('drag-drop-touch');
|
|
74
|
-
function Animation({ duration, children }) {
|
|
75
|
-
const [boundingBox, prevBoundingBox, setBoundingBox] = useStateWithHistory({});
|
|
76
|
-
useLayoutEffect(() => {
|
|
77
|
-
if (duration > 0) setBoundingBox(calculateBoundingBoxes(children));
|
|
78
|
-
else setBoundingBox({});
|
|
79
|
-
}, [children]);
|
|
80
|
-
useLayoutEffect(() => {
|
|
81
|
-
if (duration <= 0 || !prevBoundingBox || !Object.keys(prevBoundingBox).length) return;
|
|
82
|
-
children.forEach((child) => {
|
|
83
|
-
const { key } = child;
|
|
84
|
-
if (!key) return;
|
|
85
|
-
const domNode = child.props.ref.current;
|
|
86
|
-
if (!domNode) return;
|
|
87
|
-
const { left: prevLeft, top: prevTop } = prevBoundingBox[key] || {};
|
|
88
|
-
const { left, top } = boundingBox[key] || {};
|
|
89
|
-
const changeInX = prevLeft - left;
|
|
90
|
-
const changeInY = prevTop - top;
|
|
91
|
-
if (!changeInX && !changeInY) return;
|
|
92
|
-
requestAnimationFrame(() => {
|
|
93
|
-
domNode.style.transform = `translate(${changeInX}px, ${changeInY}px)`;
|
|
94
|
-
domNode.style.transition = "none";
|
|
95
|
-
requestAnimationFrame(() => {
|
|
96
|
-
domNode.style.transform = "";
|
|
97
|
-
domNode.style.transition = `transform ${duration}ms`;
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
}, [boundingBox]);
|
|
102
|
-
return children;
|
|
103
|
-
}
|
|
104
|
-
function ReorderIcon(_a) {
|
|
105
|
-
var _b = _a, { children = /* @__PURE__ */ React2.createElement(PiDotsSixVerticalBold, null), style } = _b, props = __objRest(_b, ["children", "style"]);
|
|
106
|
-
return /* @__PURE__ */ React2.createElement("span", __spreadValues({ style: __spreadValues({ cursor: "grab" }, style) }, props), children);
|
|
107
|
-
}
|
|
108
|
-
function ReorderItem(_a) {
|
|
109
|
-
var _b = _a, { useOnlyIconToDrag, disable, ref, style, children, onTouchEnd: propOnTouchEnd } = _b, events = __objRest(_b, ["useOnlyIconToDrag", "disable", "ref", "style", "children", "onTouchEnd"]);
|
|
110
|
-
const _a2 = useDraggable(), { draggable, onTouchEnd: draggableOnTouchEnd } = _a2, draggableProps = __objRest(_a2, ["draggable", "onTouchEnd"]);
|
|
111
|
-
const recursiveClone = (children2) => Children.map(children2, (child) => {
|
|
112
|
-
if (!isValidElement(child)) return child;
|
|
113
|
-
return cloneElement(child, child.type === ReorderIcon ? draggableProps : {}, recursiveClone(child.props.children));
|
|
114
|
-
});
|
|
115
|
-
const recursiveChildren = useMemo(() => useOnlyIconToDrag ? recursiveClone(children) : children, [useOnlyIconToDrag, children]);
|
|
116
|
-
return /* @__PURE__ */ React2.createElement(
|
|
117
|
-
"div",
|
|
118
|
-
__spreadValues({
|
|
119
|
-
ref,
|
|
120
|
-
draggable: !disable && draggable,
|
|
121
|
-
style: __spreadProps(__spreadValues({}, style), { touchAction: "pan-y", cursor: useOnlyIconToDrag ? "default" : "grab" })
|
|
122
|
-
}, !disable && __spreadProps(__spreadValues(__spreadValues({}, events), !useOnlyIconToDrag && draggableProps), {
|
|
123
|
-
onTouchEnd: (event) => {
|
|
124
|
-
draggableOnTouchEnd(event);
|
|
125
|
-
propOnTouchEnd(event);
|
|
126
|
-
}
|
|
127
|
-
})),
|
|
128
|
-
recursiveChildren
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
function ReorderList({ useOnlyIconToDrag = false, selectedItemOpacity = 0.5, animationDuration = 300, preserveOrder = true, onPositionChange, disabled = false, props, children }) {
|
|
132
|
-
const containerRef = useRef(null);
|
|
133
|
-
const itemRefs = useRef(/* @__PURE__ */ new Map());
|
|
134
|
-
const [order, setOrder] = useState([]);
|
|
135
|
-
const [dragState, setDragState] = useState();
|
|
136
|
-
const [isAnimating, setIsAnimating] = useState(false);
|
|
137
|
-
const [scroll, setScroll] = useState();
|
|
138
|
-
const childMap = useMemo(() => {
|
|
139
|
-
const map = /* @__PURE__ */ new Map();
|
|
140
|
-
Children.forEach(children, (child) => {
|
|
141
|
-
if (!isValidElement(child)) return;
|
|
142
|
-
const { key, props: props2 } = child;
|
|
143
|
-
if (!key) return;
|
|
144
|
-
map.set(key, { child, disabled: props2["data-disable-reorder"] });
|
|
145
|
-
});
|
|
146
|
-
return map;
|
|
147
|
-
}, [children]);
|
|
148
|
-
const orderedChildren = useMemo(() => {
|
|
149
|
-
if (!order.length) return [];
|
|
150
|
-
return order.flatMap((key, orderIndex) => {
|
|
151
|
-
const { child, disabled: disabled2 } = childMap.get(key) || {};
|
|
152
|
-
if (!isValidElement(child)) return [];
|
|
153
|
-
const ref = getRef(key);
|
|
154
|
-
const isSelected = (dragState == null ? void 0 : dragState.currentIndex) === orderIndex;
|
|
155
|
-
return /* @__PURE__ */ React2.createElement(
|
|
156
|
-
ReorderItem,
|
|
157
|
-
{
|
|
158
|
-
key,
|
|
159
|
-
ref,
|
|
160
|
-
useOnlyIconToDrag,
|
|
161
|
-
disable: disabled2,
|
|
162
|
-
style: { opacity: isSelected ? selectedItemOpacity : 1 },
|
|
163
|
-
onDragStart: (event) => {
|
|
164
|
-
var _a, _b;
|
|
165
|
-
event.stopPropagation();
|
|
166
|
-
setDragState({ startIndex: orderIndex, currentIndex: orderIndex, startOrder: [...order], startRect: ((_b = (_a = ref.current) == null ? void 0 : _a.getBoundingClientRect) == null ? void 0 : _b.call(_a)) || void 0 });
|
|
167
|
-
},
|
|
168
|
-
onDragEnter: (event) => {
|
|
169
|
-
event.stopPropagation();
|
|
170
|
-
if (!dragState || dragState.currentIndex === orderIndex || isAnimating) return;
|
|
171
|
-
const { width: startWidth, height: startHeight } = dragState.startRect || { width: 0, height: 0 };
|
|
172
|
-
const { left, top, width, height } = event.currentTarget.getBoundingClientRect();
|
|
173
|
-
if (event.clientX - left > Math.min(startWidth, width) || event.clientY - top > Math.min(startHeight, height)) return;
|
|
174
|
-
setDragState((prev) => prev ? __spreadProps(__spreadValues({}, prev), { currentIndex: orderIndex }) : void 0);
|
|
175
|
-
setOrder(() => {
|
|
176
|
-
var _a;
|
|
177
|
-
const newOrder = [...dragState.startOrder];
|
|
178
|
-
const shiftForward = dragState.startIndex < orderIndex;
|
|
179
|
-
const increment = shiftForward ? 1 : -1;
|
|
180
|
-
let currentPos = dragState.startIndex;
|
|
181
|
-
for (let index = dragState.startIndex + increment; shiftForward ? index <= orderIndex : index >= orderIndex; index += increment) {
|
|
182
|
-
const key2 = dragState.startOrder[index];
|
|
183
|
-
if ((_a = childMap.get(key2)) == null ? void 0 : _a.disabled) continue;
|
|
184
|
-
swap(newOrder, currentPos, index);
|
|
185
|
-
currentPos = index;
|
|
186
|
-
}
|
|
187
|
-
return newOrder;
|
|
188
|
-
});
|
|
189
|
-
setIsAnimating(true);
|
|
190
|
-
setTimeout(() => setIsAnimating(false), animationDuration);
|
|
191
|
-
},
|
|
192
|
-
onDragEnd: handleDragEnd,
|
|
193
|
-
onTouchMove: (event) => {
|
|
194
|
-
if (!dragState) return;
|
|
195
|
-
const { clientX, screenX, clientY, screenY } = event.touches[0];
|
|
196
|
-
const left = clientX < scrollThreshold.x ? -5 : innerWidth - screenX < scrollThreshold.x ? 5 : 0;
|
|
197
|
-
const top = clientY < scrollThreshold.y ? -10 : innerHeight - screenY < scrollThreshold.y ? 10 : 0;
|
|
198
|
-
setScroll(left || top ? { left, top } : void 0);
|
|
199
|
-
},
|
|
200
|
-
onTouchEnd: () => setScroll(void 0)
|
|
201
|
-
},
|
|
202
|
-
child
|
|
203
|
-
);
|
|
204
|
-
});
|
|
205
|
-
}, [childMap, order, dragState, isAnimating, useOnlyIconToDrag, selectedItemOpacity, animationDuration]);
|
|
206
|
-
function getRef(key) {
|
|
207
|
-
if (!itemRefs.current.has(key)) itemRefs.current.set(key, createRef());
|
|
208
|
-
return itemRefs.current.get(key);
|
|
209
|
-
}
|
|
210
|
-
function handleDragEnd(event) {
|
|
211
|
-
if (event) {
|
|
212
|
-
event.stopPropagation();
|
|
213
|
-
if (dragState && dragState.currentIndex !== dragState.startIndex) onPositionChange == null ? void 0 : onPositionChange({ start: dragState.startIndex, end: dragState.currentIndex, oldOrder: dragState.startOrder, newOrder: order, revert: () => setOrder(dragState.startOrder) });
|
|
214
|
-
}
|
|
215
|
-
setDragState(void 0);
|
|
216
|
-
setScroll(void 0);
|
|
217
|
-
}
|
|
218
|
-
useEffect(() => {
|
|
219
|
-
const currentKeys = [];
|
|
220
|
-
Children.forEach(children, (child) => {
|
|
221
|
-
const { key } = child;
|
|
222
|
-
if (key) currentKeys.push(key);
|
|
223
|
-
});
|
|
224
|
-
let newOrder;
|
|
225
|
-
if (preserveOrder) {
|
|
226
|
-
const currentKeySet = new Set(currentKeys);
|
|
227
|
-
const newKeys = currentKeys.filter((key) => !order.includes(key));
|
|
228
|
-
const filteredOrder = order.filter((key) => currentKeySet.has(key));
|
|
229
|
-
newOrder = [...filteredOrder, ...newKeys];
|
|
230
|
-
} else newOrder = currentKeys;
|
|
231
|
-
if (!areOrdersEqual(order, newOrder)) {
|
|
232
|
-
if (dragState) setDragState(void 0);
|
|
233
|
-
setOrder(newOrder);
|
|
234
|
-
}
|
|
235
|
-
}, [children]);
|
|
236
|
-
useEffect(() => {
|
|
237
|
-
if (!scroll) return;
|
|
238
|
-
const { left, top } = scroll;
|
|
239
|
-
const { scrollWidth, scrollHeight } = document.body;
|
|
240
|
-
const interval = setInterval(() => {
|
|
241
|
-
if (left < 0 || top < 0 || scrollWidth - scrollX > innerWidth - left || scrollHeight - scrollY > innerHeight - top) scrollBy({ left, top, behavior: "instant" });
|
|
242
|
-
}, 20);
|
|
243
|
-
return () => clearInterval(interval);
|
|
244
|
-
}, [scroll]);
|
|
245
|
-
return /* @__PURE__ */ React2.createElement("div", __spreadValues({ ref: containerRef }, props), disabled ? children : /* @__PURE__ */ React2.createElement(Animation, { duration: dragState && !scroll ? animationDuration : 0 }, orderedChildren));
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export { ReorderIcon, ReorderList };
|
package/dist/components.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { JSX } from 'react';
|
|
2
|
-
import { ReorderListProps, DivProps } from './types.js';
|
|
3
|
-
|
|
4
|
-
declare function ReorderIcon({ children, style, ...props }: DivProps): JSX.Element;
|
|
5
|
-
declare function ReorderList({ useOnlyIconToDrag, selectedItemOpacity, animationDuration, preserveOrder, onPositionChange, disabled, props, children }: ReorderListProps): JSX.Element;
|
|
6
|
-
|
|
7
|
-
export { ReorderIcon, ReorderList as default };
|
package/dist/components.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ReorderIcon, ReorderList as default } from './chunks/chunk-RWSH3ATP.js';
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ReorderIcon, ReorderList as default } from './chunks/chunk-RWSH3ATP.js';
|
package/dist/types.d.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { Key, DetailedHTMLProps, HTMLAttributes, ReactNode, ReactElement, RefObject, DragEventHandler, MouseEventHandler, TouchEventHandler, CSSProperties } from 'react';
|
|
2
|
-
|
|
3
|
-
type AnimationProps = {
|
|
4
|
-
duration: number;
|
|
5
|
-
children: Child[];
|
|
6
|
-
};
|
|
7
|
-
type BoundingBox = Record<string, DOMRect>;
|
|
8
|
-
type Child = ReactElement<{
|
|
9
|
-
ref: RefObject<HTMLElement>;
|
|
10
|
-
}>;
|
|
11
|
-
type Order = Key[];
|
|
12
|
-
type DivDragEventHandler = DragEventHandler<HTMLDivElement>;
|
|
13
|
-
type DivMouseEventHandler = MouseEventHandler<HTMLDivElement>;
|
|
14
|
-
type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
|
15
|
-
type DivRef = RefObject<HTMLDivElement | null>;
|
|
16
|
-
type DivTouchEventHandler = TouchEventHandler<HTMLDivElement>;
|
|
17
|
-
type PositionChangeHandler = (event: {
|
|
18
|
-
start: number;
|
|
19
|
-
end: number;
|
|
20
|
-
oldOrder: Order;
|
|
21
|
-
newOrder: Order;
|
|
22
|
-
revert: RevertHandler;
|
|
23
|
-
}) => void;
|
|
24
|
-
type ReorderItemProps = {
|
|
25
|
-
useOnlyIconToDrag: boolean;
|
|
26
|
-
disable?: boolean;
|
|
27
|
-
ref: DivRef;
|
|
28
|
-
style: CSSProperties;
|
|
29
|
-
onDragStart?: DivDragEventHandler;
|
|
30
|
-
onDragEnter: DivDragEventHandler;
|
|
31
|
-
onDragEnd: DivDragEventHandler;
|
|
32
|
-
onTouchMove: DivTouchEventHandler;
|
|
33
|
-
onTouchEnd: DivTouchEventHandler;
|
|
34
|
-
children: ReactNode;
|
|
35
|
-
};
|
|
36
|
-
type ReorderListProps = {
|
|
37
|
-
useOnlyIconToDrag?: boolean;
|
|
38
|
-
selectedItemOpacity?: number;
|
|
39
|
-
animationDuration?: number;
|
|
40
|
-
preserveOrder?: boolean;
|
|
41
|
-
onPositionChange?: PositionChangeHandler;
|
|
42
|
-
disabled?: boolean;
|
|
43
|
-
props?: DivProps;
|
|
44
|
-
children?: ReactNode;
|
|
45
|
-
};
|
|
46
|
-
type RevertHandler = () => void;
|
|
47
|
-
type IconProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
|
|
48
|
-
|
|
49
|
-
export type { AnimationProps, BoundingBox, Child, DivDragEventHandler, DivMouseEventHandler, DivProps, DivRef, DivTouchEventHandler, IconProps, Order, PositionChangeHandler, ReorderItemProps, ReorderListProps, RevertHandler };
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|