form-driver 0.4.20 → 0.4.22
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 +1487 -1263
- package/lib/m3.css +116 -8
- package/lib/m3.js +1486 -1262
- package/package.json +4 -1
- package/src/framework/MUtil.tsx +145 -0
- package/src/types/MDateRangeType.ts +7 -7
- package/src/types/MDateTimeType.ts +6 -6
- package/src/ui/editor/basic/ARangePicker.tsx +56 -24
- 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/framework/MUtil.d.ts +14 -0
- package/types/types/MDateRangeType.d.ts +2 -0
- package/types/ui/widget/EnhancedSortDrag.d.ts +3 -1
|
@@ -1,32 +1,97 @@
|
|
|
1
1
|
.sortDrag {
|
|
2
2
|
.dragItem {
|
|
3
3
|
display: flex;
|
|
4
|
+
align-items: center;
|
|
4
5
|
justify-content: space-between;
|
|
5
|
-
padding: 4px
|
|
6
|
+
padding: 0 4px;
|
|
6
7
|
background: #fff;
|
|
7
|
-
// border: 1px solid #d9d9d9;
|
|
8
|
-
// border-radius: 4px;
|
|
9
|
-
// box-shadow: 0 1px 2px #00000008;
|
|
10
8
|
font-size: 14px;
|
|
11
|
-
transition: background 0.
|
|
9
|
+
transition: background 0.15s ease, box-shadow 0.15s ease;
|
|
10
|
+
cursor: default;
|
|
11
|
+
user-select: none;
|
|
12
|
+
-webkit-user-select: none;
|
|
13
|
+
// 拖拽中占位符状态
|
|
14
|
+
&.dragging {
|
|
15
|
+
background: #fafafa;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.dragHandleWrapper {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
min-width: 36px;
|
|
24
|
+
min-height: 36px;
|
|
12
25
|
cursor: grab;
|
|
26
|
+
margin-left: 2px;
|
|
27
|
+
border-radius: 4px;
|
|
28
|
+
touch-action: none;
|
|
29
|
+
-webkit-touch-callout: none;
|
|
30
|
+
transition: background 0.15s ease;
|
|
13
31
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
background: #bae7ff;
|
|
17
|
-
box-shadow: 0 2px 8px #1890ff33;
|
|
32
|
+
&:hover {
|
|
33
|
+
background: #f5f5f5;
|
|
18
34
|
}
|
|
19
35
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
background: #
|
|
36
|
+
&:active {
|
|
37
|
+
cursor: grabbing;
|
|
38
|
+
background: #e8e8e8;
|
|
39
|
+
|
|
40
|
+
.dragHandleIcon {
|
|
41
|
+
color: #1890ff;
|
|
42
|
+
}
|
|
23
43
|
}
|
|
24
44
|
}
|
|
25
45
|
|
|
46
|
+
.dragHandleIcon {
|
|
47
|
+
font-size: 16px;
|
|
48
|
+
color: #bfbfbf;
|
|
49
|
+
transition: color 0.15s ease;
|
|
50
|
+
}
|
|
51
|
+
|
|
26
52
|
.dragBody {
|
|
27
53
|
flex: 1;
|
|
54
|
+
min-height: 0;
|
|
28
55
|
}
|
|
56
|
+
|
|
29
57
|
.dragHandle {
|
|
30
|
-
width:
|
|
58
|
+
width: 36px;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ========== 拖拽预览 — 简洁浮动卡片 ==========
|
|
63
|
+
.sortDrag-overlay {
|
|
64
|
+
.sortDrag-overlay-inner {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: space-between;
|
|
68
|
+
padding: 4px 8px;
|
|
69
|
+
background: #ffffff;
|
|
70
|
+
border-radius: 8px;
|
|
71
|
+
box-shadow:
|
|
72
|
+
0 1px 3px rgba(0, 0, 0, 0.08),
|
|
73
|
+
0 8px 24px rgba(0, 0, 0, 0.12);
|
|
74
|
+
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
75
|
+
|
|
76
|
+
.dragBody {
|
|
77
|
+
flex: 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.sortDrag-overlay-handle {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
width: 28px;
|
|
86
|
+
height: 28px;
|
|
87
|
+
border-radius: 4px;
|
|
88
|
+
background: #f0f0f0;
|
|
89
|
+
margin-left: 6px;
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.sortDrag-overlay-handleIcon {
|
|
94
|
+
font-size: 14px;
|
|
95
|
+
color: #8c8c8c;
|
|
31
96
|
}
|
|
32
97
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import React, { memo,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { Button } from "antd";
|
|
1
|
+
import React, { memo, useState, useEffect, ReactNode } from "react";
|
|
2
|
+
import { DndContext, closestCenter, DragOverlay, DragStartEvent, DragEndEvent, PointerSensor, TouchSensor, KeyboardSensor, useSensor, useSensors } from "@dnd-kit/core";
|
|
3
|
+
import { SortableContext, useSortable, arrayMove, verticalListSortingStrategy, sortableKeyboardCoordinates } from "@dnd-kit/sortable";
|
|
4
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
6
5
|
import { HolderOutlined } from "@ant-design/icons";
|
|
7
6
|
import clsx from "clsx";
|
|
8
7
|
|
|
@@ -19,113 +18,130 @@ type SortDragProps = {
|
|
|
19
18
|
}>;
|
|
20
19
|
};
|
|
21
20
|
|
|
21
|
+
const SortableItem: React.FC<{
|
|
22
|
+
item: SortDragProps["sortList"][0];
|
|
23
|
+
}> = memo(({ item }) => {
|
|
24
|
+
const {
|
|
25
|
+
attributes,
|
|
26
|
+
listeners,
|
|
27
|
+
setNodeRef,
|
|
28
|
+
transform,
|
|
29
|
+
transition,
|
|
30
|
+
isDragging,
|
|
31
|
+
} = useSortable({
|
|
32
|
+
id: item.id,
|
|
33
|
+
disabled: !item.isChecked,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const style: React.CSSProperties = {
|
|
37
|
+
transform: CSS.Transform.toString(transform),
|
|
38
|
+
transition,
|
|
39
|
+
opacity: isDragging ? 0 : 1,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const itemClass = clsx("dragItem", {
|
|
43
|
+
dragging: isDragging,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
className={itemClass}
|
|
49
|
+
ref={setNodeRef}
|
|
50
|
+
style={style}
|
|
51
|
+
>
|
|
52
|
+
<div className="dragBody">{item.cpn}</div>
|
|
53
|
+
<div>
|
|
54
|
+
{item.isChecked ? (
|
|
55
|
+
<div
|
|
56
|
+
className="dragHandleWrapper"
|
|
57
|
+
{...attributes}
|
|
58
|
+
{...listeners}
|
|
59
|
+
>
|
|
60
|
+
<HolderOutlined className="dragHandleIcon" />
|
|
61
|
+
</div>
|
|
62
|
+
) : null}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
SortableItem.displayName = "SortableItem";
|
|
69
|
+
|
|
22
70
|
const SortDrag: React.FC<SortDragProps> = memo((props) => {
|
|
23
71
|
const { sortList, changeOriginDataSource } = props;
|
|
24
72
|
const [items, setItems] = useState<SortDragProps["sortList"]>(sortList);
|
|
73
|
+
const [activeId, setActiveId] = useState<string | null>(null);
|
|
25
74
|
|
|
26
|
-
//
|
|
27
|
-
const [draggingId, setDraggingId] = useState<string | null>(null);
|
|
28
|
-
// 记录当前 hover 的 Id
|
|
29
|
-
const [droppingId, setDroppingId] = useState<string | null>(null);
|
|
30
|
-
// refs 用于绑定每个 item 的 DOM
|
|
31
|
-
const itemRefs = useRef<Record<string, HTMLDivElement | null>>({});
|
|
32
|
-
// 修改:为每个 item 单独管理 dragHandle ref
|
|
33
|
-
const dragHandleRefs = useRef<Record<string, HTMLSpanElement | null>>({});
|
|
34
|
-
|
|
35
|
-
// 注册拖拽和 drop target
|
|
75
|
+
// 同步外部 sortList 变化到内部状态
|
|
36
76
|
useEffect(() => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const fromIdx = items.findIndex((i) => i.id === source.data.id);
|
|
78
|
-
const toIdx = idx;
|
|
79
|
-
if (fromIdx === -1 || fromIdx === toIdx) return;
|
|
80
|
-
const newItems = [...items];
|
|
81
|
-
const [moved] = newItems.splice(fromIdx, 1);
|
|
82
|
-
newItems.splice(toIdx, 0, moved);
|
|
83
|
-
console.log("排序之后的数据", newItems);
|
|
84
|
-
setItems(newItems);
|
|
85
|
-
|
|
86
|
-
changeOriginDataSource(newItems);
|
|
87
|
-
setDroppingId(null);
|
|
88
|
-
},
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
});
|
|
92
|
-
// 监听全局拖拽,拖拽结束时清理 draggingId
|
|
93
|
-
const monitorCleanup = monitorForElements({
|
|
94
|
-
onDrop: () => setDraggingId(null),
|
|
95
|
-
});
|
|
96
|
-
cleanups.push(monitorCleanup);
|
|
97
|
-
return () => {
|
|
98
|
-
cleanups.forEach((fn) => fn());
|
|
99
|
-
};
|
|
100
|
-
}, [items]);
|
|
77
|
+
setItems(sortList);
|
|
78
|
+
}, [sortList]);
|
|
79
|
+
|
|
80
|
+
const sensors = useSensors(
|
|
81
|
+
useSensor(TouchSensor, {
|
|
82
|
+
activationConstraint: {
|
|
83
|
+
delay: 200,
|
|
84
|
+
tolerance: 5,
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
useSensor(PointerSensor, {
|
|
88
|
+
activationConstraint: {
|
|
89
|
+
distance: 10,
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
useSensor(KeyboardSensor, {
|
|
93
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const handleDragStart = (event: DragStartEvent) => {
|
|
98
|
+
setActiveId(event.active.id as string);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const handleDragEnd = (event: DragEndEvent) => {
|
|
102
|
+
const { active, over } = event;
|
|
103
|
+
setActiveId(null);
|
|
104
|
+
|
|
105
|
+
if (!over || active.id === over.id) return;
|
|
106
|
+
|
|
107
|
+
const oldIndex = items.findIndex((item) => item.id === active.id);
|
|
108
|
+
const newIndex = items.findIndex((item) => item.id === over.id);
|
|
109
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
110
|
+
|
|
111
|
+
const newItems = arrayMove(items, oldIndex, newIndex);
|
|
112
|
+
setItems(newItems);
|
|
113
|
+
changeOriginDataSource(newItems);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const activeItem = items.find((item) => item.id === activeId);
|
|
101
117
|
|
|
102
118
|
return (
|
|
103
|
-
<
|
|
104
|
-
{
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
/>
|
|
123
|
-
|
|
119
|
+
<DndContext
|
|
120
|
+
sensors={sensors}
|
|
121
|
+
collisionDetection={closestCenter}
|
|
122
|
+
onDragStart={handleDragStart}
|
|
123
|
+
onDragEnd={handleDragEnd}
|
|
124
|
+
>
|
|
125
|
+
<SortableContext items={items} strategy={verticalListSortingStrategy}>
|
|
126
|
+
<div className="sortDrag">
|
|
127
|
+
{items.map((item) => (
|
|
128
|
+
<SortableItem key={item.id} item={item} />
|
|
129
|
+
))}
|
|
130
|
+
</div>
|
|
131
|
+
</SortableContext>
|
|
132
|
+
<DragOverlay dropAnimation={null}>
|
|
133
|
+
{activeItem ? (
|
|
134
|
+
<div className="sortDrag-overlay">
|
|
135
|
+
<div className="sortDrag-overlay-inner">
|
|
136
|
+
<div className="dragBody">{activeItem.cpn}</div>
|
|
137
|
+
<div className="sortDrag-overlay-handle">
|
|
138
|
+
<HolderOutlined className="sortDrag-overlay-handleIcon" />
|
|
139
|
+
</div>
|
|
124
140
|
</div>
|
|
125
141
|
</div>
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
</
|
|
142
|
+
) : null}
|
|
143
|
+
</DragOverlay>
|
|
144
|
+
</DndContext>
|
|
129
145
|
);
|
|
130
146
|
});
|
|
131
147
|
|
|
@@ -115,6 +115,20 @@ export declare let MUtil: {
|
|
|
115
115
|
renameKey: (object: any, renameTo: {
|
|
116
116
|
[oldKey: string]: string;
|
|
117
117
|
}, removeNotExistKey?: boolean) => any;
|
|
118
|
+
/**
|
|
119
|
+
* 提交时将时间字段转换为可读格式
|
|
120
|
+
* @param schema 表单 schema(type 为 object 的根 schema)
|
|
121
|
+
* @param database 表单数据
|
|
122
|
+
* @returns 深拷贝后转换过的数据
|
|
123
|
+
*/
|
|
124
|
+
formatForExport: (schema: MFieldSchemaAnonymity, database: any) => any;
|
|
125
|
+
/**
|
|
126
|
+
* 回填时将可读格式的时间字段反解析为内部格式
|
|
127
|
+
* @param schema 表单 schema(type 为 object 的根 schema)
|
|
128
|
+
* @param database 可读格式的数据
|
|
129
|
+
* @returns 深拷贝后反解析过的数据
|
|
130
|
+
*/
|
|
131
|
+
parseFromExport: (schema: MFieldSchemaAnonymity, database: any) => any;
|
|
118
132
|
/** 啥也不干的空回调 */
|
|
119
133
|
doNothing: () => void;
|
|
120
134
|
/**
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { MFieldSchemaAnonymity } from "../framework/Schema";
|
|
2
2
|
import { MType } from "./MType";
|
|
3
3
|
import { Assembly } from "../framework/Assembly";
|
|
4
|
+
/** 根据 precision 获取可读格式 */
|
|
5
|
+
export declare function getReadableFormat(precision?: string, showTime?: boolean): string;
|
|
4
6
|
export declare function timeRangeExpr(assembly: Assembly, from: number | string, to: number | string, tillNow: boolean, readableFormat?: string): string;
|
|
5
7
|
export declare const MDateRangeType: MType & {
|
|
6
8
|
toReadableN: (assembly: Assembly, s: MFieldSchemaAnonymity, vs: any) => string | undefined;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React, { ReactNode } from "react";
|
|
2
|
+
import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities";
|
|
2
3
|
import "./EnhancedSortDrag.less";
|
|
4
|
+
type DndListeners = SyntheticListenerMap | undefined;
|
|
3
5
|
/**
|
|
4
6
|
* 拖拽项数据类型定义
|
|
5
7
|
*/
|
|
@@ -27,7 +29,7 @@ export interface EnhancedSortDragProps {
|
|
|
27
29
|
/** 拖拽失败回调 */
|
|
28
30
|
onDragFail?: (error: DragError) => void;
|
|
29
31
|
/** 自定义拖拽句柄渲染 */
|
|
30
|
-
renderDragHandle?: (item: DragItem, isDragging: boolean) => ReactNode;
|
|
32
|
+
renderDragHandle?: (item: DragItem, isDragging: boolean, listeners?: DndListeners) => ReactNode;
|
|
31
33
|
/** 拖拽预览内容 */
|
|
32
34
|
renderDragPreview?: (item: DragItem) => ReactNode;
|
|
33
35
|
/** 是否为表格行模式 */
|