@lucasols/dnd-kit-sortable 0.1.3 → 0.2.0
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.ts +137 -9
- package/dist/index.js +520 -7
- package/dist/index.js.map +1 -0
- package/package.json +21 -17
- package/dist/components/SortableContext.d.ts +0 -26
- package/dist/components/index.d.ts +0 -2
- package/dist/dnd-kit-sortable.cjs.development.js +0 -801
- package/dist/dnd-kit-sortable.cjs.development.js.map +0 -1
- package/dist/dnd-kit-sortable.cjs.production.min.js +0 -2
- package/dist/dnd-kit-sortable.cjs.production.min.js.map +0 -1
- package/dist/dnd-kit-sortable.esm.js +0 -783
- package/dist/dnd-kit-sortable.esm.js.map +0 -1
- package/dist/hooks/defaults.d.ts +0 -9
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/types.d.ts +0 -24
- package/dist/hooks/useSortable.d.ts +0 -36
- package/dist/hooks/utilities/index.d.ts +0 -1
- package/dist/hooks/utilities/useDerivedTransform.d.ts +0 -11
- package/dist/sensors/index.d.ts +0 -1
- package/dist/sensors/keyboard/index.d.ts +0 -1
- package/dist/sensors/keyboard/sortableKeyboardCoordinates.d.ts +0 -2
- package/dist/strategies/horizontalListSorting.d.ts +0 -2
- package/dist/strategies/index.d.ts +0 -4
- package/dist/strategies/rectSorting.d.ts +0 -2
- package/dist/strategies/rectSwapping.d.ts +0 -2
- package/dist/strategies/verticalListSorting.d.ts +0 -2
- package/dist/types/data.d.ts +0 -8
- package/dist/types/disabled.d.ts +0 -4
- package/dist/types/index.d.ts +0 -4
- package/dist/types/strategies.d.ts +0 -9
- package/dist/types/type-guard.d.ts +0 -7
- package/dist/utilities/arrayMove.d.ts +0 -4
- package/dist/utilities/arraySwap.d.ts +0 -4
- package/dist/utilities/getSortedRects.d.ts +0 -2
- package/dist/utilities/index.d.ts +0 -6
- package/dist/utilities/isValidIndex.d.ts +0 -1
- package/dist/utilities/itemsEqual.d.ts +0 -2
- package/dist/utilities/normalizeDisabled.d.ts +0 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,137 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Active, ClientRect, Data, DraggableNode, DroppableContainer, KeyboardCoordinateGetter, Over, UniqueIdentifier, UseDraggableArguments, UseDroppableArguments } from "@lucasols/dnd-kit-core";
|
|
3
|
+
import { Transform, Transition } from "@lucasols/dnd-kit-utilities";
|
|
4
|
+
//#region src/types/disabled.d.ts
|
|
5
|
+
interface Disabled {
|
|
6
|
+
draggable?: boolean;
|
|
7
|
+
droppable?: boolean;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/types/data.d.ts
|
|
11
|
+
type SortableData = {
|
|
12
|
+
sortable: {
|
|
13
|
+
containerId: UniqueIdentifier;
|
|
14
|
+
items: UniqueIdentifier[];
|
|
15
|
+
index: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/types/strategies.d.ts
|
|
20
|
+
type SortingStrategy = (args: {
|
|
21
|
+
activeNodeRect: ClientRect | null;
|
|
22
|
+
activeIndex: number;
|
|
23
|
+
index: number;
|
|
24
|
+
rects: ClientRect[];
|
|
25
|
+
overIndex: number;
|
|
26
|
+
}) => Transform | null;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/types/type-guard.d.ts
|
|
29
|
+
export declare function hasSortableData<T extends Active | Over | DraggableNode | DroppableContainer>(entry: T | null | undefined): entry is T & {
|
|
30
|
+
data: {
|
|
31
|
+
current: Data<SortableData>;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/components/SortableContext.d.ts
|
|
36
|
+
interface Props {
|
|
37
|
+
children: React.ReactNode;
|
|
38
|
+
items: (UniqueIdentifier | {
|
|
39
|
+
id: UniqueIdentifier;
|
|
40
|
+
})[];
|
|
41
|
+
strategy?: SortingStrategy;
|
|
42
|
+
id?: string;
|
|
43
|
+
disabled?: boolean | Disabled;
|
|
44
|
+
}
|
|
45
|
+
export declare function SortableContext({ children, id, items: userDefinedItems, strategy, disabled: disabledProp }: Props): React.JSX.Element;
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/hooks/types.d.ts
|
|
48
|
+
type SortableTransition = Pick<Transition, 'easing' | 'duration'>;
|
|
49
|
+
type AnimateLayoutChanges = (args: {
|
|
50
|
+
active: Active | null;
|
|
51
|
+
containerId: UniqueIdentifier;
|
|
52
|
+
isDragging: boolean;
|
|
53
|
+
isSorting: boolean;
|
|
54
|
+
id: UniqueIdentifier;
|
|
55
|
+
index: number;
|
|
56
|
+
items: UniqueIdentifier[];
|
|
57
|
+
previousItems: UniqueIdentifier[];
|
|
58
|
+
previousContainerId: UniqueIdentifier;
|
|
59
|
+
newIndex: number;
|
|
60
|
+
transition: SortableTransition | null;
|
|
61
|
+
wasDragging: boolean;
|
|
62
|
+
}) => boolean;
|
|
63
|
+
interface NewIndexGetterArguments {
|
|
64
|
+
id: UniqueIdentifier;
|
|
65
|
+
items: UniqueIdentifier[];
|
|
66
|
+
activeIndex: number;
|
|
67
|
+
overIndex: number;
|
|
68
|
+
}
|
|
69
|
+
type NewIndexGetter = (args: NewIndexGetterArguments) => number;
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/hooks/useSortable.d.ts
|
|
72
|
+
interface Arguments extends Omit<UseDraggableArguments, 'disabled'>, Pick<UseDroppableArguments, 'resizeObserverConfig'> {
|
|
73
|
+
animateLayoutChanges?: AnimateLayoutChanges;
|
|
74
|
+
disabled?: boolean | Disabled;
|
|
75
|
+
getNewIndex?: NewIndexGetter;
|
|
76
|
+
strategy?: SortingStrategy;
|
|
77
|
+
transition?: SortableTransition | null;
|
|
78
|
+
}
|
|
79
|
+
export declare function useSortable({ animateLayoutChanges, attributes: userDefinedAttributes, disabled: localDisabled, data: customData, getNewIndex, id, strategy: localStrategy, resizeObserverConfig, transition }: Arguments): {
|
|
80
|
+
active: import("@lucasols/dnd-kit-core").Active | null;
|
|
81
|
+
activeIndex: number;
|
|
82
|
+
attributes: import("@lucasols/dnd-kit-core").DraggableAttributes;
|
|
83
|
+
data: SortableData & {
|
|
84
|
+
[x: string]: any;
|
|
85
|
+
};
|
|
86
|
+
rect: import("react").RefObject<import("@lucasols/dnd-kit-core").ClientRect | null>;
|
|
87
|
+
index: number;
|
|
88
|
+
newIndex: number;
|
|
89
|
+
items: import("@lucasols/dnd-kit-core").UniqueIdentifier[];
|
|
90
|
+
isOver: boolean;
|
|
91
|
+
isSorting: boolean;
|
|
92
|
+
isDragging: boolean;
|
|
93
|
+
listeners: import("@lucasols/dnd-kit-core").DraggableSyntheticListeners;
|
|
94
|
+
node: import("react").RefObject<HTMLElement | null>;
|
|
95
|
+
overIndex: number;
|
|
96
|
+
over: import("@lucasols/dnd-kit-core").Over | null;
|
|
97
|
+
setNodeRef: (node: HTMLElement | null) => void;
|
|
98
|
+
setActivatorNodeRef: (element: HTMLElement | null) => void;
|
|
99
|
+
setDroppableNodeRef: (element: HTMLElement | null) => void;
|
|
100
|
+
setDraggableNodeRef: (element: HTMLElement | null) => void;
|
|
101
|
+
transform: import("@lucasols/dnd-kit-utilities").Transform | null;
|
|
102
|
+
transition: string | undefined;
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/hooks/defaults.d.ts
|
|
106
|
+
export declare const defaultNewIndexGetter: NewIndexGetter;
|
|
107
|
+
export declare const defaultAnimateLayoutChanges: AnimateLayoutChanges;
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/strategies/horizontalListSorting.d.ts
|
|
110
|
+
export declare const horizontalListSortingStrategy: SortingStrategy;
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/strategies/rectSorting.d.ts
|
|
113
|
+
export declare const rectSortingStrategy: SortingStrategy;
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/strategies/rectSwapping.d.ts
|
|
116
|
+
export declare const rectSwappingStrategy: SortingStrategy;
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/strategies/verticalListSorting.d.ts
|
|
119
|
+
export declare const verticalListSortingStrategy: SortingStrategy;
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/sensors/keyboard/sortableKeyboardCoordinates.d.ts
|
|
122
|
+
export declare const sortableKeyboardCoordinates: KeyboardCoordinateGetter;
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/utilities/arrayMove.d.ts
|
|
125
|
+
/**
|
|
126
|
+
* Move an array item to a different position. Returns a new array with the item moved to the new position.
|
|
127
|
+
*/
|
|
128
|
+
export declare function arrayMove<T>(array: T[], from: number, to: number): T[];
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/utilities/arraySwap.d.ts
|
|
131
|
+
/**
|
|
132
|
+
* Swap an array item to a different position. Returns a new array with the item swapped to the new position.
|
|
133
|
+
*/
|
|
134
|
+
export declare function arraySwap<T>(array: T[], from: number, to: number): T[];
|
|
135
|
+
//#endregion
|
|
136
|
+
export type { AnimateLayoutChanges, NewIndexGetter, Props as SortableContextProps, SortableData, SortingStrategy, Arguments as UseSortableArguments };
|
|
137
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,521 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import React, { useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { KeyboardCode, closestCorners, getClientRect, getFirstCollision, getScrollableAncestors, useDndContext, useDraggable, useDroppable } from "@lucasols/dnd-kit-core";
|
|
3
|
+
import { CSS, isKeyboardEvent, subtract, useCombinedRefs, useIsomorphicLayoutEffect, useUniqueId } from "@lucasols/dnd-kit-utilities";
|
|
4
|
+
//#region src/utilities/arrayMove.ts
|
|
5
|
+
/**
|
|
6
|
+
* Move an array item to a different position. Returns a new array with the item moved to the new position.
|
|
7
|
+
*/
|
|
8
|
+
function arrayMove(array, from, to) {
|
|
9
|
+
const newArray = array.slice();
|
|
10
|
+
newArray.splice(to < 0 ? newArray.length + to : to, 0, newArray.splice(from, 1)[0]);
|
|
11
|
+
return newArray;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/utilities/arraySwap.ts
|
|
15
|
+
/**
|
|
16
|
+
* Swap an array item to a different position. Returns a new array with the item swapped to the new position.
|
|
17
|
+
*/
|
|
18
|
+
function arraySwap(array, from, to) {
|
|
19
|
+
const newArray = array.slice();
|
|
20
|
+
newArray[from] = array[to];
|
|
21
|
+
newArray[to] = array[from];
|
|
22
|
+
return newArray;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/utilities/getSortedRects.ts
|
|
26
|
+
function getSortedRects(items, rects) {
|
|
27
|
+
return items.reduce((accumulator, id, index) => {
|
|
28
|
+
const rect = rects.get(id);
|
|
29
|
+
if (rect) accumulator[index] = rect;
|
|
30
|
+
return accumulator;
|
|
31
|
+
}, Array(items.length));
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/utilities/isValidIndex.ts
|
|
35
|
+
function isValidIndex(index) {
|
|
36
|
+
return index !== null && index >= 0;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/utilities/itemsEqual.ts
|
|
40
|
+
function itemsEqual(a, b) {
|
|
41
|
+
if (a === b) return true;
|
|
42
|
+
if (a.length !== b.length) return false;
|
|
43
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/utilities/normalizeDisabled.ts
|
|
48
|
+
function normalizeDisabled(disabled) {
|
|
49
|
+
if (typeof disabled === "boolean") return {
|
|
50
|
+
draggable: disabled,
|
|
51
|
+
droppable: disabled
|
|
52
|
+
};
|
|
53
|
+
return disabled;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/strategies/horizontalListSorting.ts
|
|
57
|
+
const defaultScale$1 = {
|
|
58
|
+
scaleX: 1,
|
|
59
|
+
scaleY: 1
|
|
60
|
+
};
|
|
61
|
+
const horizontalListSortingStrategy = ({ rects, activeNodeRect: fallbackActiveRect, activeIndex, overIndex, index }) => {
|
|
62
|
+
const activeNodeRect = rects[activeIndex] ?? fallbackActiveRect;
|
|
63
|
+
if (!activeNodeRect) return null;
|
|
64
|
+
const itemGap = getItemGap$1(rects, index, activeIndex);
|
|
65
|
+
if (index === activeIndex) {
|
|
66
|
+
const newIndexRect = rects[overIndex];
|
|
67
|
+
if (!newIndexRect) return null;
|
|
68
|
+
return {
|
|
69
|
+
x: activeIndex < overIndex ? newIndexRect.left + newIndexRect.width - (activeNodeRect.left + activeNodeRect.width) : newIndexRect.left - activeNodeRect.left,
|
|
70
|
+
y: 0,
|
|
71
|
+
...defaultScale$1
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (index > activeIndex && index <= overIndex) return {
|
|
75
|
+
x: -activeNodeRect.width - itemGap,
|
|
76
|
+
y: 0,
|
|
77
|
+
...defaultScale$1
|
|
78
|
+
};
|
|
79
|
+
if (index < activeIndex && index >= overIndex) return {
|
|
80
|
+
x: activeNodeRect.width + itemGap,
|
|
81
|
+
y: 0,
|
|
82
|
+
...defaultScale$1
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
x: 0,
|
|
86
|
+
y: 0,
|
|
87
|
+
...defaultScale$1
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
function getItemGap$1(rects, index, activeIndex) {
|
|
91
|
+
const currentRect = rects[index];
|
|
92
|
+
const previousRect = rects[index - 1];
|
|
93
|
+
const nextRect = rects[index + 1];
|
|
94
|
+
if (!currentRect || !previousRect && !nextRect) return 0;
|
|
95
|
+
if (activeIndex < index) return previousRect ? currentRect.left - (previousRect.left + previousRect.width) : nextRect.left - (currentRect.left + currentRect.width);
|
|
96
|
+
return nextRect ? nextRect.left - (currentRect.left + currentRect.width) : currentRect.left - (previousRect.left + previousRect.width);
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/strategies/rectSorting.ts
|
|
100
|
+
const rectSortingStrategy = ({ rects, activeIndex, overIndex, index }) => {
|
|
101
|
+
const newRects = arrayMove(rects, overIndex, activeIndex);
|
|
102
|
+
const oldRect = rects[index];
|
|
103
|
+
const newRect = newRects[index];
|
|
104
|
+
if (!newRect || !oldRect) return null;
|
|
105
|
+
return {
|
|
106
|
+
x: newRect.left - oldRect.left,
|
|
107
|
+
y: newRect.top - oldRect.top,
|
|
108
|
+
scaleX: newRect.width / oldRect.width,
|
|
109
|
+
scaleY: newRect.height / oldRect.height
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/strategies/rectSwapping.ts
|
|
114
|
+
const rectSwappingStrategy = ({ activeIndex, index, rects, overIndex }) => {
|
|
115
|
+
let oldRect;
|
|
116
|
+
let newRect;
|
|
117
|
+
if (index === activeIndex) {
|
|
118
|
+
oldRect = rects[index];
|
|
119
|
+
newRect = rects[overIndex];
|
|
120
|
+
}
|
|
121
|
+
if (index === overIndex) {
|
|
122
|
+
oldRect = rects[index];
|
|
123
|
+
newRect = rects[activeIndex];
|
|
124
|
+
}
|
|
125
|
+
if (!newRect || !oldRect) return null;
|
|
126
|
+
return {
|
|
127
|
+
x: newRect.left - oldRect.left,
|
|
128
|
+
y: newRect.top - oldRect.top,
|
|
129
|
+
scaleX: newRect.width / oldRect.width,
|
|
130
|
+
scaleY: newRect.height / oldRect.height
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/strategies/verticalListSorting.ts
|
|
135
|
+
const defaultScale = {
|
|
136
|
+
scaleX: 1,
|
|
137
|
+
scaleY: 1
|
|
138
|
+
};
|
|
139
|
+
const verticalListSortingStrategy = ({ activeIndex, activeNodeRect: fallbackActiveRect, index, rects, overIndex }) => {
|
|
140
|
+
const activeNodeRect = rects[activeIndex] ?? fallbackActiveRect;
|
|
141
|
+
if (!activeNodeRect) return null;
|
|
142
|
+
if (index === activeIndex) {
|
|
143
|
+
const overIndexRect = rects[overIndex];
|
|
144
|
+
if (!overIndexRect) return null;
|
|
145
|
+
return {
|
|
146
|
+
x: 0,
|
|
147
|
+
y: activeIndex < overIndex ? overIndexRect.top + overIndexRect.height - (activeNodeRect.top + activeNodeRect.height) : overIndexRect.top - activeNodeRect.top,
|
|
148
|
+
...defaultScale
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const itemGap = getItemGap(rects, index, activeIndex);
|
|
152
|
+
if (index > activeIndex && index <= overIndex) return {
|
|
153
|
+
x: 0,
|
|
154
|
+
y: -activeNodeRect.height - itemGap,
|
|
155
|
+
...defaultScale
|
|
156
|
+
};
|
|
157
|
+
if (index < activeIndex && index >= overIndex) return {
|
|
158
|
+
x: 0,
|
|
159
|
+
y: activeNodeRect.height + itemGap,
|
|
160
|
+
...defaultScale
|
|
161
|
+
};
|
|
162
|
+
return {
|
|
163
|
+
x: 0,
|
|
164
|
+
y: 0,
|
|
165
|
+
...defaultScale
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
function getItemGap(clientRects, index, activeIndex) {
|
|
169
|
+
const currentRect = clientRects[index];
|
|
170
|
+
const previousRect = clientRects[index - 1];
|
|
171
|
+
const nextRect = clientRects[index + 1];
|
|
172
|
+
if (!currentRect) return 0;
|
|
173
|
+
if (activeIndex < index) return previousRect ? currentRect.top - (previousRect.top + previousRect.height) : nextRect ? nextRect.top - (currentRect.top + currentRect.height) : 0;
|
|
174
|
+
return nextRect ? nextRect.top - (currentRect.top + currentRect.height) : previousRect ? currentRect.top - (previousRect.top + previousRect.height) : 0;
|
|
8
175
|
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/components/SortableContext.tsx
|
|
178
|
+
const ID_PREFIX = "Sortable";
|
|
179
|
+
const Context = React.createContext({
|
|
180
|
+
activeIndex: -1,
|
|
181
|
+
containerId: ID_PREFIX,
|
|
182
|
+
disableTransforms: false,
|
|
183
|
+
items: [],
|
|
184
|
+
overIndex: -1,
|
|
185
|
+
useDragOverlay: false,
|
|
186
|
+
sortedRects: [],
|
|
187
|
+
strategy: rectSortingStrategy,
|
|
188
|
+
disabled: {
|
|
189
|
+
draggable: false,
|
|
190
|
+
droppable: false
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
function SortableContext({ children, id, items: userDefinedItems, strategy = rectSortingStrategy, disabled: disabledProp = false }) {
|
|
194
|
+
const { active, dragOverlay, droppableRects, over, measureDroppableContainers } = useDndContext();
|
|
195
|
+
const containerId = useUniqueId(ID_PREFIX, id);
|
|
196
|
+
const useDragOverlay = Boolean(dragOverlay.rect !== null);
|
|
197
|
+
const items = useMemo(() => userDefinedItems.map((item) => typeof item === "object" && "id" in item ? item.id : item), [userDefinedItems]);
|
|
198
|
+
const isDragging = active != null;
|
|
199
|
+
const activeIndex = active ? items.indexOf(active.id) : -1;
|
|
200
|
+
const overIndex = over ? items.indexOf(over.id) : -1;
|
|
201
|
+
const previousItemsRef = useRef(items);
|
|
202
|
+
const itemsHaveChanged = !itemsEqual(items, previousItemsRef.current);
|
|
203
|
+
const disableTransforms = overIndex !== -1 && activeIndex === -1 || itemsHaveChanged;
|
|
204
|
+
const disabled = normalizeDisabled(disabledProp);
|
|
205
|
+
useIsomorphicLayoutEffect(() => {
|
|
206
|
+
if (itemsHaveChanged && isDragging) measureDroppableContainers(items);
|
|
207
|
+
}, [
|
|
208
|
+
itemsHaveChanged,
|
|
209
|
+
items,
|
|
210
|
+
isDragging,
|
|
211
|
+
measureDroppableContainers
|
|
212
|
+
]);
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
previousItemsRef.current = items;
|
|
215
|
+
}, [items]);
|
|
216
|
+
const contextValue = useMemo(() => ({
|
|
217
|
+
activeIndex,
|
|
218
|
+
containerId,
|
|
219
|
+
disabled,
|
|
220
|
+
disableTransforms,
|
|
221
|
+
items,
|
|
222
|
+
overIndex,
|
|
223
|
+
useDragOverlay,
|
|
224
|
+
sortedRects: getSortedRects(items, droppableRects),
|
|
225
|
+
strategy
|
|
226
|
+
}), [
|
|
227
|
+
activeIndex,
|
|
228
|
+
containerId,
|
|
229
|
+
disabled.draggable,
|
|
230
|
+
disabled.droppable,
|
|
231
|
+
disableTransforms,
|
|
232
|
+
items,
|
|
233
|
+
overIndex,
|
|
234
|
+
droppableRects,
|
|
235
|
+
useDragOverlay,
|
|
236
|
+
strategy
|
|
237
|
+
]);
|
|
238
|
+
return /* @__PURE__ */ React.createElement(Context.Provider, { value: contextValue }, children);
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/hooks/defaults.ts
|
|
242
|
+
const defaultNewIndexGetter = ({ id, items, activeIndex, overIndex }) => arrayMove(items, activeIndex, overIndex).indexOf(id);
|
|
243
|
+
const defaultAnimateLayoutChanges = ({ containerId, isSorting, wasDragging, index, items, newIndex, previousItems, previousContainerId, transition }) => {
|
|
244
|
+
if (!transition || !wasDragging) return false;
|
|
245
|
+
if (previousItems !== items && index === newIndex) return false;
|
|
246
|
+
if (isSorting) return true;
|
|
247
|
+
return newIndex !== index && containerId === previousContainerId;
|
|
248
|
+
};
|
|
249
|
+
const defaultTransition = {
|
|
250
|
+
duration: 200,
|
|
251
|
+
easing: "ease"
|
|
252
|
+
};
|
|
253
|
+
const transitionProperty = "transform";
|
|
254
|
+
const disabledTransition = CSS.Transition.toString({
|
|
255
|
+
property: transitionProperty,
|
|
256
|
+
duration: 0,
|
|
257
|
+
easing: "linear"
|
|
258
|
+
});
|
|
259
|
+
const defaultAttributes = { roleDescription: "sortable" };
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/hooks/utilities/useDerivedTransform.ts
|
|
262
|
+
function useDerivedTransform({ disabled, index, node, rect }) {
|
|
263
|
+
const [derivedTransform, setDerivedtransform] = useState(null);
|
|
264
|
+
const previousIndex = useRef(index);
|
|
265
|
+
useIsomorphicLayoutEffect(() => {
|
|
266
|
+
if (!disabled && index !== previousIndex.current && node.current) {
|
|
267
|
+
const initial = rect.current;
|
|
268
|
+
if (initial) {
|
|
269
|
+
const current = getClientRect(node.current, { ignoreTransform: true });
|
|
270
|
+
const delta = {
|
|
271
|
+
x: initial.left - current.left,
|
|
272
|
+
y: initial.top - current.top,
|
|
273
|
+
scaleX: initial.width / current.width,
|
|
274
|
+
scaleY: initial.height / current.height
|
|
275
|
+
};
|
|
276
|
+
if (delta.x || delta.y) setDerivedtransform(delta);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (index !== previousIndex.current) previousIndex.current = index;
|
|
280
|
+
}, [
|
|
281
|
+
disabled,
|
|
282
|
+
index,
|
|
283
|
+
node,
|
|
284
|
+
rect
|
|
285
|
+
]);
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
if (derivedTransform) setDerivedtransform(null);
|
|
288
|
+
}, [derivedTransform]);
|
|
289
|
+
return derivedTransform;
|
|
290
|
+
}
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region src/hooks/useSortable.ts
|
|
293
|
+
function useSortable({ animateLayoutChanges = defaultAnimateLayoutChanges, attributes: userDefinedAttributes, disabled: localDisabled, data: customData, getNewIndex = defaultNewIndexGetter, id, strategy: localStrategy, resizeObserverConfig, transition = defaultTransition }) {
|
|
294
|
+
const { items, containerId, activeIndex, disabled: globalDisabled, disableTransforms, sortedRects, overIndex, useDragOverlay, strategy: globalStrategy } = useContext(Context);
|
|
295
|
+
const disabled = normalizeLocalDisabled(localDisabled, globalDisabled);
|
|
296
|
+
const index = items.indexOf(id);
|
|
297
|
+
const data = useMemo(() => ({
|
|
298
|
+
sortable: {
|
|
299
|
+
containerId,
|
|
300
|
+
index,
|
|
301
|
+
items
|
|
302
|
+
},
|
|
303
|
+
...customData
|
|
304
|
+
}), [
|
|
305
|
+
containerId,
|
|
306
|
+
customData,
|
|
307
|
+
index,
|
|
308
|
+
items
|
|
309
|
+
]);
|
|
310
|
+
const itemsAfterCurrentSortable = useMemo(() => items.slice(items.indexOf(id)), [items, id]);
|
|
311
|
+
const { rect, node, isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
|
312
|
+
id,
|
|
313
|
+
data,
|
|
314
|
+
disabled: disabled.droppable,
|
|
315
|
+
resizeObserverConfig: {
|
|
316
|
+
updateMeasurementsFor: itemsAfterCurrentSortable,
|
|
317
|
+
...resizeObserverConfig
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
const { active, activatorEvent, activeNodeRect, attributes, setNodeRef: setDraggableNodeRef, listeners, isDragging, over, setActivatorNodeRef, transform } = useDraggable({
|
|
321
|
+
id,
|
|
322
|
+
data,
|
|
323
|
+
attributes: {
|
|
324
|
+
...defaultAttributes,
|
|
325
|
+
...userDefinedAttributes
|
|
326
|
+
},
|
|
327
|
+
disabled: disabled.draggable
|
|
328
|
+
});
|
|
329
|
+
const setNodeRef = useCombinedRefs(setDroppableNodeRef, setDraggableNodeRef);
|
|
330
|
+
const isSorting = Boolean(active);
|
|
331
|
+
const displaceItem = isSorting && !disableTransforms && isValidIndex(activeIndex) && isValidIndex(overIndex);
|
|
332
|
+
const shouldDisplaceDragSource = !useDragOverlay && isDragging;
|
|
333
|
+
const finalTransform = displaceItem ? (shouldDisplaceDragSource && displaceItem ? transform : null) ?? (localStrategy ?? globalStrategy)({
|
|
334
|
+
rects: sortedRects,
|
|
335
|
+
activeNodeRect,
|
|
336
|
+
activeIndex,
|
|
337
|
+
overIndex,
|
|
338
|
+
index
|
|
339
|
+
}) : null;
|
|
340
|
+
const newIndex = isValidIndex(activeIndex) && isValidIndex(overIndex) ? getNewIndex({
|
|
341
|
+
id,
|
|
342
|
+
items,
|
|
343
|
+
activeIndex,
|
|
344
|
+
overIndex
|
|
345
|
+
}) : index;
|
|
346
|
+
const activeId = active?.id;
|
|
347
|
+
const previous = useRef({
|
|
348
|
+
activeId,
|
|
349
|
+
items,
|
|
350
|
+
newIndex,
|
|
351
|
+
containerId
|
|
352
|
+
});
|
|
353
|
+
const itemsHaveChanged = items !== previous.current.items;
|
|
354
|
+
const shouldAnimateLayoutChanges = animateLayoutChanges({
|
|
355
|
+
active,
|
|
356
|
+
containerId,
|
|
357
|
+
isDragging,
|
|
358
|
+
isSorting,
|
|
359
|
+
id,
|
|
360
|
+
index,
|
|
361
|
+
items,
|
|
362
|
+
newIndex: previous.current.newIndex,
|
|
363
|
+
previousItems: previous.current.items,
|
|
364
|
+
previousContainerId: previous.current.containerId,
|
|
365
|
+
transition,
|
|
366
|
+
wasDragging: previous.current.activeId != null
|
|
367
|
+
});
|
|
368
|
+
const derivedTransform = useDerivedTransform({
|
|
369
|
+
disabled: !shouldAnimateLayoutChanges,
|
|
370
|
+
index,
|
|
371
|
+
node,
|
|
372
|
+
rect
|
|
373
|
+
});
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
if (isSorting && previous.current.newIndex !== newIndex) previous.current.newIndex = newIndex;
|
|
376
|
+
if (containerId !== previous.current.containerId) previous.current.containerId = containerId;
|
|
377
|
+
if (items !== previous.current.items) previous.current.items = items;
|
|
378
|
+
}, [
|
|
379
|
+
isSorting,
|
|
380
|
+
newIndex,
|
|
381
|
+
containerId,
|
|
382
|
+
items
|
|
383
|
+
]);
|
|
384
|
+
useEffect(() => {
|
|
385
|
+
if (activeId === previous.current.activeId) return;
|
|
386
|
+
if (activeId && !previous.current.activeId) {
|
|
387
|
+
previous.current.activeId = activeId;
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const timeoutId = setTimeout(() => {
|
|
391
|
+
previous.current.activeId = activeId;
|
|
392
|
+
}, 50);
|
|
393
|
+
return () => clearTimeout(timeoutId);
|
|
394
|
+
}, [activeId]);
|
|
395
|
+
return {
|
|
396
|
+
active,
|
|
397
|
+
activeIndex,
|
|
398
|
+
attributes,
|
|
399
|
+
data,
|
|
400
|
+
rect,
|
|
401
|
+
index,
|
|
402
|
+
newIndex,
|
|
403
|
+
items,
|
|
404
|
+
isOver,
|
|
405
|
+
isSorting,
|
|
406
|
+
isDragging,
|
|
407
|
+
listeners,
|
|
408
|
+
node,
|
|
409
|
+
overIndex,
|
|
410
|
+
over,
|
|
411
|
+
setNodeRef,
|
|
412
|
+
setActivatorNodeRef,
|
|
413
|
+
setDroppableNodeRef,
|
|
414
|
+
setDraggableNodeRef,
|
|
415
|
+
transform: derivedTransform ?? finalTransform,
|
|
416
|
+
transition: getTransition()
|
|
417
|
+
};
|
|
418
|
+
function getTransition() {
|
|
419
|
+
if (derivedTransform || itemsHaveChanged && previous.current.newIndex === index) return disabledTransition;
|
|
420
|
+
if (shouldDisplaceDragSource && !isKeyboardEvent(activatorEvent) || !transition) return;
|
|
421
|
+
if (isSorting || shouldAnimateLayoutChanges) return CSS.Transition.toString({
|
|
422
|
+
...transition,
|
|
423
|
+
property: transitionProperty
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function normalizeLocalDisabled(localDisabled, globalDisabled) {
|
|
428
|
+
if (typeof localDisabled === "boolean") return {
|
|
429
|
+
draggable: localDisabled,
|
|
430
|
+
droppable: false
|
|
431
|
+
};
|
|
432
|
+
return {
|
|
433
|
+
draggable: localDisabled?.draggable ?? globalDisabled.draggable,
|
|
434
|
+
droppable: localDisabled?.droppable ?? globalDisabled.droppable
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
//#endregion
|
|
438
|
+
//#region src/types/type-guard.ts
|
|
439
|
+
function hasSortableData(entry) {
|
|
440
|
+
if (!entry) return false;
|
|
441
|
+
const data = entry.data.current;
|
|
442
|
+
if (data && "sortable" in data && typeof data.sortable === "object" && "containerId" in data.sortable && "items" in data.sortable && "index" in data.sortable) return true;
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region src/sensors/keyboard/sortableKeyboardCoordinates.ts
|
|
447
|
+
const directions = [
|
|
448
|
+
KeyboardCode.Down,
|
|
449
|
+
KeyboardCode.Right,
|
|
450
|
+
KeyboardCode.Up,
|
|
451
|
+
KeyboardCode.Left
|
|
452
|
+
];
|
|
453
|
+
const sortableKeyboardCoordinates = (event, { context: { active, collisionRect, droppableRects, droppableContainers, over, scrollableAncestors } }) => {
|
|
454
|
+
if (directions.includes(event.code)) {
|
|
455
|
+
event.preventDefault();
|
|
456
|
+
if (!active || !collisionRect) return;
|
|
457
|
+
const filteredContainers = [];
|
|
458
|
+
droppableContainers.getEnabled().forEach((entry) => {
|
|
459
|
+
if (!entry || entry?.disabled) return;
|
|
460
|
+
const rect = droppableRects.get(entry.id);
|
|
461
|
+
if (!rect) return;
|
|
462
|
+
switch (event.code) {
|
|
463
|
+
case KeyboardCode.Down:
|
|
464
|
+
if (collisionRect.top < rect.top) filteredContainers.push(entry);
|
|
465
|
+
break;
|
|
466
|
+
case KeyboardCode.Up:
|
|
467
|
+
if (collisionRect.top > rect.top) filteredContainers.push(entry);
|
|
468
|
+
break;
|
|
469
|
+
case KeyboardCode.Left:
|
|
470
|
+
if (collisionRect.left > rect.left) filteredContainers.push(entry);
|
|
471
|
+
break;
|
|
472
|
+
case KeyboardCode.Right: if (collisionRect.left < rect.left) filteredContainers.push(entry);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
const collisions = closestCorners({
|
|
476
|
+
active,
|
|
477
|
+
collisionRect,
|
|
478
|
+
droppableRects,
|
|
479
|
+
droppableContainers: filteredContainers,
|
|
480
|
+
pointerCoordinates: null
|
|
481
|
+
});
|
|
482
|
+
let closestId = getFirstCollision(collisions, "id");
|
|
483
|
+
if (closestId === over?.id && collisions.length > 1) closestId = collisions[1].id;
|
|
484
|
+
if (closestId != null) {
|
|
485
|
+
const activeDroppable = droppableContainers.get(active.id);
|
|
486
|
+
const newDroppable = droppableContainers.get(closestId);
|
|
487
|
+
const newRect = newDroppable ? droppableRects.get(newDroppable.id) : null;
|
|
488
|
+
const newNode = newDroppable?.node.current;
|
|
489
|
+
if (newNode && newRect && activeDroppable && newDroppable) {
|
|
490
|
+
const hasDifferentScrollAncestors = getScrollableAncestors(newNode).some((element, index) => scrollableAncestors[index] !== element);
|
|
491
|
+
const hasSameContainer = isSameContainer(activeDroppable, newDroppable);
|
|
492
|
+
const isAfterActive = isAfter(activeDroppable, newDroppable);
|
|
493
|
+
const offset = hasDifferentScrollAncestors || !hasSameContainer ? {
|
|
494
|
+
x: 0,
|
|
495
|
+
y: 0
|
|
496
|
+
} : {
|
|
497
|
+
x: isAfterActive ? collisionRect.width - newRect.width : 0,
|
|
498
|
+
y: isAfterActive ? collisionRect.height - newRect.height : 0
|
|
499
|
+
};
|
|
500
|
+
const rectCoordinates = {
|
|
501
|
+
x: newRect.left,
|
|
502
|
+
y: newRect.top
|
|
503
|
+
};
|
|
504
|
+
return offset.x && offset.y ? rectCoordinates : subtract(rectCoordinates, offset);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
function isSameContainer(a, b) {
|
|
510
|
+
if (!hasSortableData(a) || !hasSortableData(b)) return false;
|
|
511
|
+
return a.data.current.sortable.containerId === b.data.current.sortable.containerId;
|
|
512
|
+
}
|
|
513
|
+
function isAfter(a, b) {
|
|
514
|
+
if (!hasSortableData(a) || !hasSortableData(b)) return false;
|
|
515
|
+
if (!isSameContainer(a, b)) return false;
|
|
516
|
+
return a.data.current.sortable.index < b.data.current.sortable.index;
|
|
517
|
+
}
|
|
518
|
+
//#endregion
|
|
519
|
+
export { SortableContext, arrayMove, arraySwap, defaultAnimateLayoutChanges, defaultNewIndexGetter, hasSortableData, horizontalListSortingStrategy, rectSortingStrategy, rectSwappingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy };
|
|
520
|
+
|
|
521
|
+
//# sourceMappingURL=index.js.map
|