form-driver 0.4.21 → 0.4.23
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/m3.css +116 -8
- package/dist/m3.js +1 -1
- package/es/m3.css +116 -8
- package/es/m3.js +486 -474
- package/lib/m3.css +116 -8
- package/lib/m3.js +485 -473
- package/package.json +4 -1
- package/src/ui/editor/basic/ARangePicker.tsx +15 -3
- package/src/ui/widget/EnhancedSortDrag.less +61 -0
- package/src/ui/widget/EnhancedSortDrag.tsx +294 -284
- package/src/ui/widget/SortDrag.less +78 -13
- package/src/ui/widget/SortDrag.tsx +119 -103
- package/types/ui/widget/EnhancedSortDrag.d.ts +3 -1
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
import { HolderOutlined } from "@ant-design/icons";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
DndContext,
|
|
4
|
+
closestCenter,
|
|
5
|
+
DragOverlay,
|
|
6
|
+
TouchSensor,
|
|
7
|
+
PointerSensor,
|
|
8
|
+
KeyboardSensor,
|
|
9
|
+
useSensor,
|
|
10
|
+
useSensors,
|
|
11
|
+
DragStartEvent,
|
|
12
|
+
DragEndEvent,
|
|
13
|
+
} from "@dnd-kit/core";
|
|
14
|
+
import {
|
|
15
|
+
SortableContext,
|
|
16
|
+
useSortable,
|
|
17
|
+
arrayMove,
|
|
18
|
+
verticalListSortingStrategy,
|
|
19
|
+
horizontalListSortingStrategy,
|
|
20
|
+
sortableKeyboardCoordinates,
|
|
21
|
+
} from "@dnd-kit/sortable";
|
|
22
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
7
23
|
import clsx from "clsx";
|
|
8
24
|
import React, {
|
|
9
25
|
memo,
|
|
10
26
|
ReactNode,
|
|
11
27
|
useCallback,
|
|
12
|
-
useEffect,
|
|
13
|
-
useRef,
|
|
14
28
|
useState,
|
|
29
|
+
useMemo,
|
|
15
30
|
} from "react";
|
|
16
31
|
|
|
32
|
+
import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities";
|
|
33
|
+
|
|
17
34
|
import "./EnhancedSortDrag.less";
|
|
18
35
|
|
|
36
|
+
// 使用 @dnd-kit 原生的 listeners 类型
|
|
37
|
+
type DndListeners = SyntheticListenerMap | undefined;
|
|
38
|
+
|
|
19
39
|
/**
|
|
20
40
|
* 拖拽项数据类型定义
|
|
21
41
|
*/
|
|
@@ -44,7 +64,7 @@ export interface EnhancedSortDragProps {
|
|
|
44
64
|
/** 拖拽失败回调 */
|
|
45
65
|
onDragFail?: (error: DragError) => void;
|
|
46
66
|
/** 自定义拖拽句柄渲染 */
|
|
47
|
-
renderDragHandle?: (item: DragItem, isDragging: boolean) => ReactNode;
|
|
67
|
+
renderDragHandle?: (item: DragItem, isDragging: boolean, listeners?: DndListeners) => ReactNode;
|
|
48
68
|
/** 拖拽预览内容 */
|
|
49
69
|
renderDragPreview?: (item: DragItem) => ReactNode;
|
|
50
70
|
/** 是否为表格行模式 */
|
|
@@ -79,6 +99,119 @@ interface ValidationResult {
|
|
|
79
99
|
error?: DragError;
|
|
80
100
|
}
|
|
81
101
|
|
|
102
|
+
/**
|
|
103
|
+
* 可排序的拖拽项子组件
|
|
104
|
+
*/
|
|
105
|
+
const SortableEnhancedItem: React.FC<{
|
|
106
|
+
item: DragItem;
|
|
107
|
+
index: number;
|
|
108
|
+
enableAnimation: boolean;
|
|
109
|
+
direction: "vertical" | "horizontal";
|
|
110
|
+
renderDragHandle?: (item: DragItem, isDragging: boolean, listeners?: DndListeners) => ReactNode;
|
|
111
|
+
isTableRow: boolean;
|
|
112
|
+
}> = memo(({ item, index, enableAnimation, direction, renderDragHandle, isTableRow }) => {
|
|
113
|
+
const {
|
|
114
|
+
attributes,
|
|
115
|
+
listeners,
|
|
116
|
+
setNodeRef,
|
|
117
|
+
transform,
|
|
118
|
+
transition,
|
|
119
|
+
isDragging,
|
|
120
|
+
} = useSortable({
|
|
121
|
+
id: item.id,
|
|
122
|
+
disabled: !item.isChecked,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const style = {
|
|
126
|
+
transform: CSS.Transform.toString(transform),
|
|
127
|
+
transition: enableAnimation ? transition : undefined,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const renderDefaultDragHandle = () => (
|
|
131
|
+
<div className="enhanced-dragHandleWrapper">
|
|
132
|
+
<HolderOutlined
|
|
133
|
+
className="enhanced-dragHandleIcon"
|
|
134
|
+
style={{
|
|
135
|
+
opacity: isDragging ? 0.5 : 1,
|
|
136
|
+
transition: enableAnimation ? "opacity 0.2s" : "none",
|
|
137
|
+
}}
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// 表格行模式
|
|
143
|
+
if (isTableRow) {
|
|
144
|
+
return (
|
|
145
|
+
<tr
|
|
146
|
+
ref={setNodeRef}
|
|
147
|
+
key={item.id}
|
|
148
|
+
data-drag-id={item.id}
|
|
149
|
+
data-drag-index={index}
|
|
150
|
+
style={{
|
|
151
|
+
opacity: isDragging ? 0.5 : 1,
|
|
152
|
+
...style,
|
|
153
|
+
}}
|
|
154
|
+
{...attributes}
|
|
155
|
+
>
|
|
156
|
+
{renderDragHandle ? (
|
|
157
|
+
renderDragHandle(item, isDragging, listeners)
|
|
158
|
+
) : (
|
|
159
|
+
<td
|
|
160
|
+
{...listeners}
|
|
161
|
+
style={{
|
|
162
|
+
cursor: isDragging ? "grabbing" : "grab",
|
|
163
|
+
textAlign: "center",
|
|
164
|
+
width: "40px",
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
<HolderOutlined
|
|
168
|
+
style={{
|
|
169
|
+
opacity: isDragging ? 0.5 : 1,
|
|
170
|
+
transition: enableAnimation ? "opacity 0.2s" : "none",
|
|
171
|
+
}}
|
|
172
|
+
/>
|
|
173
|
+
</td>
|
|
174
|
+
)}
|
|
175
|
+
{item.cpn}
|
|
176
|
+
</tr>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 普通模式
|
|
181
|
+
const itemClass = clsx("enhanced-dragItem", {
|
|
182
|
+
dragging: isDragging,
|
|
183
|
+
disabled: !item.isChecked,
|
|
184
|
+
[`direction-${direction}`]: true,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<div
|
|
189
|
+
className={itemClass}
|
|
190
|
+
ref={setNodeRef}
|
|
191
|
+
key={item.id}
|
|
192
|
+
data-drag-id={item.id}
|
|
193
|
+
data-drag-index={index}
|
|
194
|
+
style={style}
|
|
195
|
+
{...attributes}
|
|
196
|
+
>
|
|
197
|
+
<div className="enhanced-dragBody">{item.cpn}</div>
|
|
198
|
+
<div className="enhanced-dragHandle">
|
|
199
|
+
{item.isChecked && (
|
|
200
|
+
renderDragHandle
|
|
201
|
+
? renderDragHandle(item, isDragging, listeners)
|
|
202
|
+
: (
|
|
203
|
+
<div {...listeners}>
|
|
204
|
+
{renderDefaultDragHandle()}
|
|
205
|
+
</div>
|
|
206
|
+
)
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
SortableEnhancedItem.displayName = "SortableEnhancedItem";
|
|
214
|
+
|
|
82
215
|
/**
|
|
83
216
|
* 增强版通用拖拽排序组件
|
|
84
217
|
* 解决原组件的性能问题和功能局限性
|
|
@@ -96,23 +229,33 @@ const EnhancedSortDrag: React.FC<EnhancedSortDragProps> = memo((props) => {
|
|
|
96
229
|
isTableRow = false,
|
|
97
230
|
} = props;
|
|
98
231
|
|
|
99
|
-
// 使用 useRef 缓存 items 避免不必要的重渲染
|
|
100
|
-
const itemsRef = useRef<DragItem[]>(items);
|
|
101
|
-
itemsRef.current = items;
|
|
102
|
-
|
|
103
232
|
// 拖拽状态管理
|
|
233
|
+
const [activeId, setActiveId] = useState<string | null>(null);
|
|
104
234
|
const [dragState, setDragState] = useState<DragState>({
|
|
105
235
|
draggingId: null,
|
|
106
236
|
droppingId: null,
|
|
107
237
|
isAnimating: false,
|
|
108
238
|
});
|
|
109
239
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
240
|
+
/**
|
|
241
|
+
* 配置传感器
|
|
242
|
+
*/
|
|
243
|
+
const sensors = useSensors(
|
|
244
|
+
useSensor(TouchSensor, {
|
|
245
|
+
activationConstraint: {
|
|
246
|
+
delay: 200,
|
|
247
|
+
tolerance: 5,
|
|
248
|
+
},
|
|
249
|
+
}),
|
|
250
|
+
useSensor(PointerSensor, {
|
|
251
|
+
activationConstraint: {
|
|
252
|
+
distance: 10,
|
|
253
|
+
},
|
|
254
|
+
}),
|
|
255
|
+
useSensor(KeyboardSensor, {
|
|
256
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
257
|
+
})
|
|
258
|
+
);
|
|
116
259
|
|
|
117
260
|
/**
|
|
118
261
|
* 验证拖拽操作是否有效
|
|
@@ -194,304 +337,171 @@ const EnhancedSortDrag: React.FC<EnhancedSortDragProps> = memo((props) => {
|
|
|
194
337
|
);
|
|
195
338
|
|
|
196
339
|
/**
|
|
197
|
-
*
|
|
340
|
+
* 拖拽开始事件处理
|
|
198
341
|
*/
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
342
|
+
const handleDragStart = useCallback((event: DragStartEvent) => {
|
|
343
|
+
const { active } = event;
|
|
344
|
+
setActiveId(active.id as string);
|
|
345
|
+
setDragState((prev) => ({
|
|
346
|
+
...prev,
|
|
347
|
+
draggingId: active.id as string,
|
|
348
|
+
isAnimating: !!enableAnimation,
|
|
349
|
+
}));
|
|
350
|
+
}, [enableAnimation]);
|
|
203
351
|
|
|
204
|
-
|
|
205
|
-
|
|
352
|
+
/**
|
|
353
|
+
* 拖拽结束事件处理
|
|
354
|
+
*/
|
|
355
|
+
const handleDragEnd = useCallback((event: DragEndEvent) => {
|
|
356
|
+
const { active, over } = event;
|
|
357
|
+
setActiveId(null);
|
|
358
|
+
setDragState((prev) => ({
|
|
359
|
+
...prev,
|
|
360
|
+
draggingId: null,
|
|
361
|
+
droppingId: null,
|
|
362
|
+
isAnimating: false,
|
|
363
|
+
}));
|
|
364
|
+
|
|
365
|
+
if (over && active.id !== over.id) {
|
|
366
|
+
const oldIndex = items.findIndex((item) => item.id === active.id);
|
|
367
|
+
const newIndex = items.findIndex((item) => item.id === over.id);
|
|
368
|
+
|
|
369
|
+
if (oldIndex === -1 || newIndex === -1) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
const validation = validateDragOperation(
|
|
375
|
+
active.id as string,
|
|
376
|
+
over.id as string,
|
|
377
|
+
items
|
|
378
|
+
);
|
|
206
379
|
if (!validation.isValid) {
|
|
207
380
|
throw new Error(validation.error?.message || "拖拽验证失败");
|
|
208
381
|
}
|
|
209
382
|
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// 边界条件检查
|
|
214
|
-
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const [moved] = currentItems.splice(fromIndex, 1);
|
|
219
|
-
currentItems.splice(toIndex, 0, moved);
|
|
220
|
-
|
|
221
|
-
// 更新引用
|
|
222
|
-
itemsRef.current = currentItems;
|
|
223
|
-
|
|
224
|
-
// 触发回调
|
|
225
|
-
onChange(currentItems);
|
|
383
|
+
const newItems = arrayMove(items, oldIndex, newIndex);
|
|
384
|
+
onChange(newItems);
|
|
226
385
|
} catch (error) {
|
|
227
386
|
console.error("拖拽交换数据失败:", error);
|
|
228
|
-
|
|
229
|
-
// 触发错误回调
|
|
230
387
|
const dragError: DragError = {
|
|
231
388
|
type: "DATA_ERROR",
|
|
232
389
|
message: error instanceof Error ? error.message : "未知错误",
|
|
233
|
-
sourceId:
|
|
234
|
-
targetId:
|
|
390
|
+
sourceId: active.id as string,
|
|
391
|
+
targetId: over.id as string,
|
|
235
392
|
};
|
|
236
|
-
|
|
237
393
|
onDragFail?.(dragError);
|
|
238
394
|
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
);
|
|
395
|
+
}
|
|
396
|
+
}, [items, onChange, onDragFail, validateDragOperation]);
|
|
242
397
|
|
|
243
398
|
/**
|
|
244
|
-
*
|
|
399
|
+
* 获取当前拖拽项
|
|
245
400
|
*/
|
|
246
|
-
const
|
|
247
|
-
(
|
|
248
|
-
|
|
249
|
-
const dragHandle = dragHandleRefs.current.get(item.id);
|
|
250
|
-
|
|
251
|
-
if (!el) return;
|
|
252
|
-
|
|
253
|
-
// 清理之前的监听器
|
|
254
|
-
const existingCleanup = cleanupRefs.current.get(item.id);
|
|
255
|
-
if (existingCleanup) {
|
|
256
|
-
existingCleanup();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const cleanups: (() => void)[] = [];
|
|
260
|
-
|
|
261
|
-
// 注册为可拖拽元素
|
|
262
|
-
cleanups.push(
|
|
263
|
-
draggable({
|
|
264
|
-
element: el,
|
|
265
|
-
dragHandle: dragHandle,
|
|
266
|
-
canDrag: () => item.isChecked,
|
|
267
|
-
getInitialData: () => ({
|
|
268
|
-
id: item.id,
|
|
269
|
-
index,
|
|
270
|
-
label: item.label,
|
|
271
|
-
}),
|
|
272
|
-
onDragStart: () => {
|
|
273
|
-
setDragState((prev) => ({
|
|
274
|
-
...prev,
|
|
275
|
-
draggingId: item.id,
|
|
276
|
-
isAnimating: !!enableAnimation,
|
|
277
|
-
}));
|
|
278
|
-
console.log("开始拖拽:", item.label);
|
|
279
|
-
},
|
|
280
|
-
onDrop: () => {
|
|
281
|
-
setDragState((prev) => ({
|
|
282
|
-
...prev,
|
|
283
|
-
draggingId: null,
|
|
284
|
-
droppingId: null,
|
|
285
|
-
isAnimating: false,
|
|
286
|
-
}));
|
|
287
|
-
},
|
|
288
|
-
})
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
// 注册为拖拽目标
|
|
292
|
-
cleanups.push(
|
|
293
|
-
dropTargetForElements({
|
|
294
|
-
element: el,
|
|
295
|
-
canDrop: () => item.isChecked,
|
|
296
|
-
onDragEnter: (args) => {
|
|
297
|
-
const sourceId = args.source.data.id as string;
|
|
298
|
-
if (sourceId === item.id) return;
|
|
299
|
-
|
|
300
|
-
console.log("拖拽进入:", item.id);
|
|
301
|
-
setDragState((prev) => ({
|
|
302
|
-
...prev,
|
|
303
|
-
droppingId: item.id,
|
|
304
|
-
}));
|
|
305
|
-
},
|
|
306
|
-
onDragLeave: () => {
|
|
307
|
-
setDragState((prev) => ({
|
|
308
|
-
...prev,
|
|
309
|
-
droppingId: null,
|
|
310
|
-
}));
|
|
311
|
-
},
|
|
312
|
-
onDrop: ({ source }) => {
|
|
313
|
-
if (!source) return;
|
|
314
|
-
const sourceId = source.data.id as string;
|
|
315
|
-
if (sourceId === item.id) return;
|
|
316
|
-
|
|
317
|
-
// 执行数据交换
|
|
318
|
-
swapItems(sourceId, item.id);
|
|
319
|
-
},
|
|
320
|
-
})
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
// 存储清理函数
|
|
324
|
-
const combinedCleanup = () => {
|
|
325
|
-
cleanups.forEach((fn) => fn());
|
|
326
|
-
};
|
|
327
|
-
cleanupRefs.current.set(item.id, combinedCleanup);
|
|
328
|
-
},
|
|
329
|
-
[swapItems, enableAnimation]
|
|
401
|
+
const activeItem = useMemo(
|
|
402
|
+
() => items.find((item) => item.id === activeId),
|
|
403
|
+
[items, activeId]
|
|
330
404
|
);
|
|
331
405
|
|
|
332
406
|
/**
|
|
333
|
-
*
|
|
407
|
+
* 选择排序策略
|
|
334
408
|
*/
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
items.forEach((item, index) => {
|
|
342
|
-
registerDragListeners(item, index);
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
// 监听全局拖拽结束
|
|
346
|
-
const monitorCleanup = monitorForElements({
|
|
347
|
-
onDrop: () => {
|
|
348
|
-
setDragState((prev) => ({
|
|
349
|
-
...prev,
|
|
350
|
-
draggingId: null,
|
|
351
|
-
droppingId: null,
|
|
352
|
-
isAnimating: false,
|
|
353
|
-
}));
|
|
354
|
-
},
|
|
355
|
-
});
|
|
356
|
-
cleanupRefs.current.set("monitor", monitorCleanup);
|
|
357
|
-
|
|
358
|
-
return () => {
|
|
359
|
-
cleanupRefs.current.forEach((cleanup) => cleanup());
|
|
360
|
-
cleanupRefs.current.clear();
|
|
361
|
-
};
|
|
362
|
-
}, [items.length, registerDragListeners]); // 只在列表长度变化时重新注册
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* 渲染默认拖拽句柄
|
|
366
|
-
*/
|
|
367
|
-
const renderDefaultDragHandle = useCallback(
|
|
368
|
-
(item: DragItem, isDragging: boolean) => (
|
|
369
|
-
<HolderOutlined
|
|
370
|
-
ref={(el) => {
|
|
371
|
-
if (el) {
|
|
372
|
-
dragHandleRefs.current.set(item.id, el);
|
|
373
|
-
}
|
|
374
|
-
}}
|
|
375
|
-
style={{
|
|
376
|
-
cursor: isDragging ? "grabbing" : "grab",
|
|
377
|
-
marginLeft: "8px",
|
|
378
|
-
opacity: isDragging ? 0.5 : 1,
|
|
379
|
-
transition: enableAnimation ? "opacity 0.2s" : "none",
|
|
380
|
-
}}
|
|
381
|
-
/>
|
|
382
|
-
),
|
|
383
|
-
[enableAnimation]
|
|
409
|
+
const sortingStrategy = useMemo(
|
|
410
|
+
() =>
|
|
411
|
+
direction === "vertical"
|
|
412
|
+
? verticalListSortingStrategy
|
|
413
|
+
: horizontalListSortingStrategy,
|
|
414
|
+
[direction]
|
|
384
415
|
);
|
|
385
416
|
|
|
386
417
|
/**
|
|
387
|
-
*
|
|
418
|
+
* 缓存 item id 列表,避免每次渲染创建新数组引用
|
|
388
419
|
*/
|
|
389
|
-
const
|
|
390
|
-
(item: DragItem, index: number) => {
|
|
391
|
-
const isDragging = dragState.draggingId === item.id;
|
|
392
|
-
const isDropping = dragState.droppingId === item.id;
|
|
393
|
-
|
|
394
|
-
// 如果是表格行模式,直接返回组件内容
|
|
395
|
-
if (isTableRow) {
|
|
396
|
-
// console.log("表格行数据", item);
|
|
397
|
-
return (
|
|
398
|
-
<tr
|
|
399
|
-
ref={(el) => {
|
|
400
|
-
if (el) {
|
|
401
|
-
itemRefs.current.set(item.id, el as unknown as HTMLDivElement);
|
|
402
|
-
}
|
|
403
|
-
}}
|
|
404
|
-
key={item.id}
|
|
405
|
-
data-drag-id={item.id}
|
|
406
|
-
data-drag-index={index}
|
|
407
|
-
style={{
|
|
408
|
-
transition: enableAnimation ? "all 0.3s ease" : "none",
|
|
409
|
-
opacity: isDragging ? 0.5 : 1,
|
|
410
|
-
backgroundColor: isDropping ? "#e6f7ff" : "transparent",
|
|
411
|
-
}}
|
|
412
|
-
>
|
|
413
|
-
{/* 如果提供了自定义拖拽句柄,则将其作为第一列 */}
|
|
414
|
-
{renderDragHandle && renderDragHandle(item, isDragging)}
|
|
415
|
-
{!renderDragHandle && (
|
|
416
|
-
<td
|
|
417
|
-
ref={(el) => {
|
|
418
|
-
if (el) {
|
|
419
|
-
dragHandleRefs.current.set(
|
|
420
|
-
item.id,
|
|
421
|
-
el as unknown as HTMLSpanElement
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
}}
|
|
425
|
-
style={{
|
|
426
|
-
cursor: isDragging ? "grabbing" : "grab",
|
|
427
|
-
textAlign: "center",
|
|
428
|
-
width: "40px",
|
|
429
|
-
}}
|
|
430
|
-
>
|
|
431
|
-
<HolderOutlined
|
|
432
|
-
style={{
|
|
433
|
-
opacity: isDragging ? 0.5 : 1,
|
|
434
|
-
transition: enableAnimation ? "opacity 0.2s" : "none",
|
|
435
|
-
}}
|
|
436
|
-
/>
|
|
437
|
-
</td>
|
|
438
|
-
)}
|
|
439
|
-
{item.cpn}
|
|
440
|
-
</tr>
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
const itemClass = clsx("enhanced-dragItem", {
|
|
445
|
-
dragging: isDragging,
|
|
446
|
-
dropping: isDropping,
|
|
447
|
-
disabled: !item.isChecked,
|
|
448
|
-
[`direction-${direction}`]: true,
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
return (
|
|
452
|
-
<div
|
|
453
|
-
className={itemClass}
|
|
454
|
-
ref={(el) => {
|
|
455
|
-
if (el) {
|
|
456
|
-
itemRefs.current.set(item.id, el);
|
|
457
|
-
}
|
|
458
|
-
}}
|
|
459
|
-
key={item.id}
|
|
460
|
-
data-drag-id={item.id}
|
|
461
|
-
data-drag-index={index}
|
|
462
|
-
style={{
|
|
463
|
-
transition: enableAnimation ? "all 0.3s ease" : "none",
|
|
464
|
-
}}
|
|
465
|
-
>
|
|
466
|
-
<div className="enhanced-dragBody">{item.cpn}</div>
|
|
467
|
-
<div className="enhanced-dragHandle">
|
|
468
|
-
{item.isChecked &&
|
|
469
|
-
(renderDragHandle
|
|
470
|
-
? renderDragHandle(item, isDragging)
|
|
471
|
-
: renderDefaultDragHandle(item, isDragging))}
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
);
|
|
475
|
-
},
|
|
476
|
-
[
|
|
477
|
-
dragState,
|
|
478
|
-
direction,
|
|
479
|
-
enableAnimation,
|
|
480
|
-
renderDragHandle,
|
|
481
|
-
renderDefaultDragHandle,
|
|
482
|
-
isTableRow,
|
|
483
|
-
]
|
|
484
|
-
);
|
|
420
|
+
const itemIds = useMemo(() => items.map((item) => item.id), [items]);
|
|
485
421
|
|
|
486
422
|
// 如果是表格行模式,直接渲染子元素而不是包装div
|
|
487
423
|
if (isTableRow) {
|
|
488
|
-
return
|
|
424
|
+
return (
|
|
425
|
+
<DndContext
|
|
426
|
+
sensors={sensors}
|
|
427
|
+
collisionDetection={closestCenter}
|
|
428
|
+
onDragStart={handleDragStart}
|
|
429
|
+
onDragEnd={handleDragEnd}
|
|
430
|
+
>
|
|
431
|
+
<SortableContext
|
|
432
|
+
items={itemIds}
|
|
433
|
+
strategy={sortingStrategy}
|
|
434
|
+
>
|
|
435
|
+
{items.map((item, index) => (
|
|
436
|
+
<SortableEnhancedItem
|
|
437
|
+
key={item.id}
|
|
438
|
+
item={item}
|
|
439
|
+
index={index}
|
|
440
|
+
enableAnimation={enableAnimation}
|
|
441
|
+
direction={direction}
|
|
442
|
+
renderDragHandle={renderDragHandle}
|
|
443
|
+
isTableRow={isTableRow}
|
|
444
|
+
/>
|
|
445
|
+
))}
|
|
446
|
+
</SortableContext>
|
|
447
|
+
<DragOverlay dropAnimation={null}>
|
|
448
|
+
{activeItem ? (
|
|
449
|
+
<div className="enhanced-sortDrag-overlay">
|
|
450
|
+
{renderDragPreview
|
|
451
|
+
? renderDragPreview(activeItem)
|
|
452
|
+
: (
|
|
453
|
+
<div className="enhanced-sortDrag-overlay-row">
|
|
454
|
+
<span className="enhanced-sortDrag-overlay-label">
|
|
455
|
+
{activeItem.label || activeItem.id || '拖拽中...'}
|
|
456
|
+
</span>
|
|
457
|
+
</div>
|
|
458
|
+
)}
|
|
459
|
+
</div>
|
|
460
|
+
) : null}
|
|
461
|
+
</DragOverlay>
|
|
462
|
+
</DndContext>
|
|
463
|
+
);
|
|
489
464
|
}
|
|
490
465
|
|
|
491
466
|
return (
|
|
492
|
-
<
|
|
493
|
-
{
|
|
494
|
-
|
|
467
|
+
<DndContext
|
|
468
|
+
sensors={sensors}
|
|
469
|
+
collisionDetection={closestCenter}
|
|
470
|
+
onDragStart={handleDragStart}
|
|
471
|
+
onDragEnd={handleDragEnd}
|
|
472
|
+
>
|
|
473
|
+
<div className={`enhanced-sortDrag direction-${direction}`}>
|
|
474
|
+
<SortableContext
|
|
475
|
+
items={itemIds}
|
|
476
|
+
strategy={sortingStrategy}
|
|
477
|
+
>
|
|
478
|
+
{items.map((item, index) => (
|
|
479
|
+
<SortableEnhancedItem
|
|
480
|
+
key={item.id}
|
|
481
|
+
item={item}
|
|
482
|
+
index={index}
|
|
483
|
+
enableAnimation={enableAnimation}
|
|
484
|
+
direction={direction}
|
|
485
|
+
renderDragHandle={renderDragHandle}
|
|
486
|
+
isTableRow={isTableRow}
|
|
487
|
+
/>
|
|
488
|
+
))}
|
|
489
|
+
</SortableContext>
|
|
490
|
+
</div>
|
|
491
|
+
<DragOverlay dropAnimation={null}>
|
|
492
|
+
{activeItem ? (
|
|
493
|
+
<div className="enhanced-sortDrag-overlay">
|
|
494
|
+
{renderDragPreview
|
|
495
|
+
? renderDragPreview(activeItem)
|
|
496
|
+
: (
|
|
497
|
+
<div className="enhanced-sortDrag-overlay-content">
|
|
498
|
+
<div className="enhanced-sortDrag-overlay-body">{activeItem.cpn}</div>
|
|
499
|
+
</div>
|
|
500
|
+
)}
|
|
501
|
+
</div>
|
|
502
|
+
) : null}
|
|
503
|
+
</DragOverlay>
|
|
504
|
+
</DndContext>
|
|
495
505
|
);
|
|
496
506
|
});
|
|
497
507
|
|