@nocobase/flow-engine 2.0.0-alpha.2 → 2.0.0-alpha.4
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/lib/components/dnd/findModelUidPosition.d.ts +13 -0
- package/lib/components/dnd/findModelUidPosition.js +50 -0
- package/lib/components/dnd/gridDragPlanner.d.ts +130 -0
- package/lib/components/dnd/gridDragPlanner.js +497 -0
- package/lib/components/dnd/index.d.ts +2 -2
- package/lib/components/dnd/index.js +5 -5
- package/lib/flowContext.js +4 -2
- package/package.json +2 -2
- package/src/components/__tests__/gridDragPlanner.test.ts +494 -0
- package/src/components/dnd/README.md +149 -0
- package/src/components/dnd/findModelUidPosition.ts +26 -0
- package/src/components/dnd/gridDragPlanner.ts +659 -0
- package/src/components/dnd/index.tsx +3 -3
- package/src/flowContext.ts +6 -2
- package/lib/components/dnd/getMousePositionOnElement.d.ts +0 -50
- package/lib/components/dnd/getMousePositionOnElement.js +0 -95
- package/lib/components/dnd/moveBlock.d.ts +0 -33
- package/lib/components/dnd/moveBlock.js +0 -302
- package/src/components/dnd/getMousePositionOnElement.ts +0 -115
- package/src/components/dnd/moveBlock.ts +0 -379
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
export declare const findModelUidPosition: (uid: string, rows: Record<string, string[][]>) => {
|
|
10
|
+
rowId: string;
|
|
11
|
+
columnIndex: number;
|
|
12
|
+
itemIndex: number;
|
|
13
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
19
|
+
var __copyProps = (to, from, except, desc) => {
|
|
20
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
+
for (let key of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
23
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
24
|
+
}
|
|
25
|
+
return to;
|
|
26
|
+
};
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var findModelUidPosition_exports = {};
|
|
29
|
+
__export(findModelUidPosition_exports, {
|
|
30
|
+
findModelUidPosition: () => findModelUidPosition
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(findModelUidPosition_exports);
|
|
33
|
+
const findModelUidPosition = /* @__PURE__ */ __name((uid, rows) => {
|
|
34
|
+
let result = null;
|
|
35
|
+
for (const [rowId, columns] of Object.entries(rows)) {
|
|
36
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
|
|
37
|
+
const column = columns[columnIndex];
|
|
38
|
+
for (let itemIndex = 0; itemIndex < column.length; itemIndex++) {
|
|
39
|
+
if (column[itemIndex] === uid) {
|
|
40
|
+
result = { rowId, columnIndex, itemIndex };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}, "findModelUidPosition");
|
|
47
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
48
|
+
0 && (module.exports = {
|
|
49
|
+
findModelUidPosition
|
|
50
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
/** 栅格系统常量 */
|
|
10
|
+
export declare const DEFAULT_GRID_COLUMNS = 24;
|
|
11
|
+
/** 最小 slot 厚度 */
|
|
12
|
+
export declare const MIN_SLOT_THICKNESS = 16;
|
|
13
|
+
/** 最大 slot 厚度 */
|
|
14
|
+
export declare const MAX_SLOT_THICKNESS = 48;
|
|
15
|
+
/** 列边缘最小宽度 */
|
|
16
|
+
export declare const COLUMN_EDGE_MIN_WIDTH = 12;
|
|
17
|
+
/** 列边缘最大宽度 */
|
|
18
|
+
export declare const COLUMN_EDGE_MAX_WIDTH = 28;
|
|
19
|
+
/** 列边缘宽度占列宽的比例(原来是 1/5) */
|
|
20
|
+
export declare const COLUMN_EDGE_WIDTH_RATIO = 0.2;
|
|
21
|
+
export interface Rect {
|
|
22
|
+
top: number;
|
|
23
|
+
left: number;
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
}
|
|
27
|
+
export interface Point {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
}
|
|
31
|
+
export interface GridLayoutData {
|
|
32
|
+
rows: Record<string, string[][]>;
|
|
33
|
+
sizes: Record<string, number[]>;
|
|
34
|
+
}
|
|
35
|
+
export interface ColumnSlot {
|
|
36
|
+
type: 'column';
|
|
37
|
+
rowId: string;
|
|
38
|
+
columnIndex: number;
|
|
39
|
+
insertIndex: number;
|
|
40
|
+
position: 'before' | 'after';
|
|
41
|
+
rect: Rect;
|
|
42
|
+
}
|
|
43
|
+
export interface ColumnEdgeSlot {
|
|
44
|
+
type: 'column-edge';
|
|
45
|
+
rowId: string;
|
|
46
|
+
columnIndex: number;
|
|
47
|
+
direction: 'left' | 'right';
|
|
48
|
+
rect: Rect;
|
|
49
|
+
}
|
|
50
|
+
export interface RowGapSlot {
|
|
51
|
+
type: 'row-gap';
|
|
52
|
+
targetRowId: string;
|
|
53
|
+
position: 'above' | 'below';
|
|
54
|
+
rect: Rect;
|
|
55
|
+
}
|
|
56
|
+
export interface EmptyRowSlot {
|
|
57
|
+
type: 'empty-row';
|
|
58
|
+
rect: Rect;
|
|
59
|
+
}
|
|
60
|
+
export interface EmptyColumnSlot {
|
|
61
|
+
type: 'empty-column';
|
|
62
|
+
rowId: string;
|
|
63
|
+
columnIndex: number;
|
|
64
|
+
rect: Rect;
|
|
65
|
+
}
|
|
66
|
+
export type LayoutSlot = ColumnSlot | ColumnEdgeSlot | RowGapSlot | EmptyRowSlot | EmptyColumnSlot;
|
|
67
|
+
/**
|
|
68
|
+
* 列内插入的配置
|
|
69
|
+
*/
|
|
70
|
+
export interface ColumnInsertConfig {
|
|
71
|
+
/** 高亮区域的高度(像素) */
|
|
72
|
+
height?: number;
|
|
73
|
+
/** 垂直偏移(像素),正数向下,负数向上 */
|
|
74
|
+
offsetTop?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 列边缘的配置
|
|
78
|
+
*/
|
|
79
|
+
export interface ColumnEdgeConfig {
|
|
80
|
+
/** 高亮区域的宽度(像素) */
|
|
81
|
+
width?: number;
|
|
82
|
+
/** 水平偏移(像素),正数向右,负数向左 */
|
|
83
|
+
offsetLeft?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 行间隙的配置
|
|
87
|
+
*/
|
|
88
|
+
export interface RowGapConfig {
|
|
89
|
+
/** 高亮区域的高度(像素) */
|
|
90
|
+
height?: number;
|
|
91
|
+
/** 垂直偏移(像素),正数向下,负数向上 */
|
|
92
|
+
offsetTop?: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 拖拽高亮区域的全局配置
|
|
96
|
+
*/
|
|
97
|
+
export interface DragOverlayConfig {
|
|
98
|
+
/** 列内插入(before 表示在区块上方插入,after 表示在区块下方插入) */
|
|
99
|
+
columnInsert?: {
|
|
100
|
+
before?: ColumnInsertConfig;
|
|
101
|
+
after?: ColumnInsertConfig;
|
|
102
|
+
};
|
|
103
|
+
/** 列边缘(left 表示在左侧新建列,right 表示在右侧新建列) */
|
|
104
|
+
columnEdge?: {
|
|
105
|
+
left?: ColumnEdgeConfig;
|
|
106
|
+
right?: ColumnEdgeConfig;
|
|
107
|
+
};
|
|
108
|
+
/** 行间隙(above 表示在行上方插入,below 表示在行下方插入) */
|
|
109
|
+
rowGap?: {
|
|
110
|
+
above?: RowGapConfig;
|
|
111
|
+
below?: RowGapConfig;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export interface LayoutSnapshot {
|
|
115
|
+
slots: LayoutSlot[];
|
|
116
|
+
containerRect: Rect;
|
|
117
|
+
}
|
|
118
|
+
export interface BuildLayoutSnapshotOptions {
|
|
119
|
+
container: HTMLElement | null;
|
|
120
|
+
}
|
|
121
|
+
export declare const buildLayoutSnapshot: ({ container }: BuildLayoutSnapshotOptions) => LayoutSnapshot;
|
|
122
|
+
export declare const getSlotKey: (slot: LayoutSlot) => string;
|
|
123
|
+
export declare const resolveDropIntent: (point: Point, slots: LayoutSlot[]) => LayoutSlot | null;
|
|
124
|
+
export interface SimulateLayoutOptions {
|
|
125
|
+
slot: LayoutSlot;
|
|
126
|
+
sourceUid: string;
|
|
127
|
+
layout: GridLayoutData;
|
|
128
|
+
generateRowId?: () => string;
|
|
129
|
+
}
|
|
130
|
+
export declare const simulateLayoutForSlot: ({ slot, sourceUid, layout, generateRowId, }: SimulateLayoutOptions) => GridLayoutData;
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
17
|
+
var __export = (target, all) => {
|
|
18
|
+
for (var name in all)
|
|
19
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(from))
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
25
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
26
|
+
}
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var gridDragPlanner_exports = {};
|
|
39
|
+
__export(gridDragPlanner_exports, {
|
|
40
|
+
COLUMN_EDGE_MAX_WIDTH: () => COLUMN_EDGE_MAX_WIDTH,
|
|
41
|
+
COLUMN_EDGE_MIN_WIDTH: () => COLUMN_EDGE_MIN_WIDTH,
|
|
42
|
+
COLUMN_EDGE_WIDTH_RATIO: () => COLUMN_EDGE_WIDTH_RATIO,
|
|
43
|
+
DEFAULT_GRID_COLUMNS: () => DEFAULT_GRID_COLUMNS,
|
|
44
|
+
MAX_SLOT_THICKNESS: () => MAX_SLOT_THICKNESS,
|
|
45
|
+
MIN_SLOT_THICKNESS: () => MIN_SLOT_THICKNESS,
|
|
46
|
+
buildLayoutSnapshot: () => buildLayoutSnapshot,
|
|
47
|
+
getSlotKey: () => getSlotKey,
|
|
48
|
+
resolveDropIntent: () => resolveDropIntent,
|
|
49
|
+
simulateLayoutForSlot: () => simulateLayoutForSlot
|
|
50
|
+
});
|
|
51
|
+
module.exports = __toCommonJS(gridDragPlanner_exports);
|
|
52
|
+
var import_shared = require("@formily/shared");
|
|
53
|
+
var import_lodash = __toESM(require("lodash"));
|
|
54
|
+
const DEFAULT_GRID_COLUMNS = 24;
|
|
55
|
+
const MIN_SLOT_THICKNESS = 16;
|
|
56
|
+
const MAX_SLOT_THICKNESS = 48;
|
|
57
|
+
const COLUMN_EDGE_MIN_WIDTH = 12;
|
|
58
|
+
const COLUMN_EDGE_MAX_WIDTH = 28;
|
|
59
|
+
const COLUMN_EDGE_WIDTH_RATIO = 0.2;
|
|
60
|
+
const COLUMN_INSERT_THICKNESS_RATIO = 0.5;
|
|
61
|
+
const ROW_GAP_HEIGHT_RATIO = 0.33;
|
|
62
|
+
const toRect = /* @__PURE__ */ __name((domRect) => ({
|
|
63
|
+
top: domRect.top,
|
|
64
|
+
left: domRect.left,
|
|
65
|
+
width: domRect.width,
|
|
66
|
+
height: domRect.height
|
|
67
|
+
}), "toRect");
|
|
68
|
+
const clampSlotHeight = /* @__PURE__ */ __name((value) => Math.max(MIN_SLOT_THICKNESS, Math.min(MAX_SLOT_THICKNESS, value)), "clampSlotHeight");
|
|
69
|
+
const createRect = /* @__PURE__ */ __name(({ top, left, width, height }) => ({
|
|
70
|
+
top,
|
|
71
|
+
left,
|
|
72
|
+
width,
|
|
73
|
+
height
|
|
74
|
+
}), "createRect");
|
|
75
|
+
const offsetRect = /* @__PURE__ */ __name((rect, offsets) => ({
|
|
76
|
+
top: offsets.top ?? rect.top,
|
|
77
|
+
left: offsets.left ?? rect.left,
|
|
78
|
+
width: offsets.width ?? rect.width,
|
|
79
|
+
height: offsets.height ?? rect.height
|
|
80
|
+
}), "offsetRect");
|
|
81
|
+
const createRowGapRect = /* @__PURE__ */ __name((source, position, containerRect) => {
|
|
82
|
+
const baseHeight = clampSlotHeight(source.height * ROW_GAP_HEIGHT_RATIO);
|
|
83
|
+
if (position === "above") {
|
|
84
|
+
const available2 = source.top - containerRect.top;
|
|
85
|
+
const height2 = clampSlotHeight(Math.max(baseHeight, available2));
|
|
86
|
+
return createRect({
|
|
87
|
+
top: source.top - height2,
|
|
88
|
+
left: containerRect.left,
|
|
89
|
+
width: containerRect.width,
|
|
90
|
+
height: height2
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const available = containerRect.top + containerRect.height - (source.top + source.height);
|
|
94
|
+
const height = clampSlotHeight(Math.max(baseHeight, available));
|
|
95
|
+
return createRect({
|
|
96
|
+
top: source.top + source.height,
|
|
97
|
+
left: containerRect.left,
|
|
98
|
+
width: containerRect.width,
|
|
99
|
+
height
|
|
100
|
+
});
|
|
101
|
+
}, "createRowGapRect");
|
|
102
|
+
const createColumnEdgeRect = /* @__PURE__ */ __name((source, side) => {
|
|
103
|
+
const width = Math.min(
|
|
104
|
+
Math.max(COLUMN_EDGE_MIN_WIDTH, source.width * COLUMN_EDGE_WIDTH_RATIO),
|
|
105
|
+
COLUMN_EDGE_MAX_WIDTH
|
|
106
|
+
);
|
|
107
|
+
return createRect({
|
|
108
|
+
top: source.top,
|
|
109
|
+
left: side === "left" ? source.left : source.left + source.width - width,
|
|
110
|
+
width,
|
|
111
|
+
height: source.height
|
|
112
|
+
});
|
|
113
|
+
}, "createColumnEdgeRect");
|
|
114
|
+
const createColumnInsertRect = /* @__PURE__ */ __name((itemRect, position) => {
|
|
115
|
+
const thickness = clampSlotHeight(itemRect.height * COLUMN_INSERT_THICKNESS_RATIO);
|
|
116
|
+
if (position === "before") {
|
|
117
|
+
return createRect({
|
|
118
|
+
top: itemRect.top,
|
|
119
|
+
left: itemRect.left,
|
|
120
|
+
width: itemRect.width,
|
|
121
|
+
height: thickness
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return createRect({
|
|
125
|
+
top: itemRect.top + itemRect.height - thickness,
|
|
126
|
+
left: itemRect.left,
|
|
127
|
+
width: itemRect.width,
|
|
128
|
+
height: thickness
|
|
129
|
+
});
|
|
130
|
+
}, "createColumnInsertRect");
|
|
131
|
+
const expandColumnRect = /* @__PURE__ */ __name((columnRect) => ({
|
|
132
|
+
top: columnRect.top,
|
|
133
|
+
left: columnRect.left,
|
|
134
|
+
width: columnRect.width,
|
|
135
|
+
height: Math.max(columnRect.height, MIN_SLOT_THICKNESS)
|
|
136
|
+
}), "expandColumnRect");
|
|
137
|
+
const buildLayoutSnapshot = /* @__PURE__ */ __name(({ container }) => {
|
|
138
|
+
if (!container) {
|
|
139
|
+
return {
|
|
140
|
+
slots: [],
|
|
141
|
+
containerRect: { top: 0, left: 0, width: 0, height: 0 }
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const containerRect = toRect(container.getBoundingClientRect());
|
|
145
|
+
const slots = [];
|
|
146
|
+
const allRowElements = Array.from(container.querySelectorAll("[data-grid-row-id]"));
|
|
147
|
+
const rowElements = allRowElements.filter((el) => {
|
|
148
|
+
const htmlEl = el;
|
|
149
|
+
let parent = htmlEl.parentElement;
|
|
150
|
+
while (parent && parent !== container) {
|
|
151
|
+
if (parent.hasAttribute("data-grid-row-id")) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
parent = parent.parentElement;
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
});
|
|
158
|
+
if (rowElements.length === 0) {
|
|
159
|
+
slots.push({
|
|
160
|
+
type: "empty-row",
|
|
161
|
+
rect: createRect({
|
|
162
|
+
top: containerRect.top,
|
|
163
|
+
left: containerRect.left,
|
|
164
|
+
width: containerRect.width,
|
|
165
|
+
height: Math.max(containerRect.height, MIN_SLOT_THICKNESS)
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
return { slots, containerRect };
|
|
169
|
+
}
|
|
170
|
+
rowElements.forEach((rowElement, rowIndex) => {
|
|
171
|
+
const rowId = rowElement.dataset.gridRowId;
|
|
172
|
+
if (!rowId) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const rowRect = toRect(rowElement.getBoundingClientRect());
|
|
176
|
+
if (rowIndex === 0) {
|
|
177
|
+
slots.push({
|
|
178
|
+
type: "row-gap",
|
|
179
|
+
targetRowId: rowId,
|
|
180
|
+
position: "above",
|
|
181
|
+
rect: createRowGapRect(rowRect, "above", containerRect)
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const columnElements = Array.from(
|
|
185
|
+
container.querySelectorAll(`[data-grid-column-row-id="${rowId}"][data-grid-column-index]`)
|
|
186
|
+
);
|
|
187
|
+
const sortedColumns = columnElements.sort((a, b) => {
|
|
188
|
+
const indexA = Number(a.dataset.gridColumnIndex || 0);
|
|
189
|
+
const indexB = Number(b.dataset.gridColumnIndex || 0);
|
|
190
|
+
return indexA - indexB;
|
|
191
|
+
});
|
|
192
|
+
sortedColumns.forEach((columnElement) => {
|
|
193
|
+
const columnIndex = Number(columnElement.dataset.gridColumnIndex || 0);
|
|
194
|
+
const columnRect = toRect(columnElement.getBoundingClientRect());
|
|
195
|
+
slots.push({
|
|
196
|
+
type: "column-edge",
|
|
197
|
+
rowId,
|
|
198
|
+
columnIndex,
|
|
199
|
+
direction: "left",
|
|
200
|
+
rect: createColumnEdgeRect(columnRect, "left")
|
|
201
|
+
});
|
|
202
|
+
slots.push({
|
|
203
|
+
type: "column-edge",
|
|
204
|
+
rowId,
|
|
205
|
+
columnIndex,
|
|
206
|
+
direction: "right",
|
|
207
|
+
rect: createColumnEdgeRect(columnRect, "right")
|
|
208
|
+
});
|
|
209
|
+
const itemElements = Array.from(
|
|
210
|
+
columnElement.querySelectorAll(`[data-grid-item-row-id="${rowId}"][data-grid-column-index="${columnIndex}"]`)
|
|
211
|
+
);
|
|
212
|
+
const sortedItems = itemElements.sort((a, b) => {
|
|
213
|
+
const indexA = Number(a.dataset.gridItemIndex || 0);
|
|
214
|
+
const indexB = Number(b.dataset.gridItemIndex || 0);
|
|
215
|
+
return indexA - indexB;
|
|
216
|
+
});
|
|
217
|
+
if (sortedItems.length === 0) {
|
|
218
|
+
slots.push({
|
|
219
|
+
type: "empty-column",
|
|
220
|
+
rowId,
|
|
221
|
+
columnIndex,
|
|
222
|
+
rect: expandColumnRect(columnRect)
|
|
223
|
+
});
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const firstItemRect = toRect(sortedItems[0].getBoundingClientRect());
|
|
227
|
+
slots.push({
|
|
228
|
+
type: "column",
|
|
229
|
+
rowId,
|
|
230
|
+
columnIndex,
|
|
231
|
+
insertIndex: 0,
|
|
232
|
+
position: "before",
|
|
233
|
+
rect: createColumnInsertRect(firstItemRect, "before")
|
|
234
|
+
});
|
|
235
|
+
sortedItems.forEach((itemElement, itemIndex) => {
|
|
236
|
+
const itemRect = toRect(itemElement.getBoundingClientRect());
|
|
237
|
+
slots.push({
|
|
238
|
+
type: "column",
|
|
239
|
+
rowId,
|
|
240
|
+
columnIndex,
|
|
241
|
+
insertIndex: itemIndex + 1,
|
|
242
|
+
position: "after",
|
|
243
|
+
rect: createColumnInsertRect(itemRect, "after")
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
slots.push({
|
|
248
|
+
type: "row-gap",
|
|
249
|
+
targetRowId: rowId,
|
|
250
|
+
position: "below",
|
|
251
|
+
rect: createRowGapRect(rowRect, "below", containerRect)
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
slots,
|
|
256
|
+
containerRect
|
|
257
|
+
};
|
|
258
|
+
}, "buildLayoutSnapshot");
|
|
259
|
+
const getSlotKey = /* @__PURE__ */ __name((slot) => {
|
|
260
|
+
switch (slot.type) {
|
|
261
|
+
case "column":
|
|
262
|
+
return `${slot.type}:${slot.rowId}:${slot.columnIndex}:${slot.insertIndex}:${slot.position}`;
|
|
263
|
+
case "column-edge":
|
|
264
|
+
return `${slot.type}:${slot.rowId}:${slot.columnIndex}:${slot.direction}`;
|
|
265
|
+
case "row-gap":
|
|
266
|
+
return `${slot.type}:${slot.targetRowId}:${slot.position}`;
|
|
267
|
+
case "empty-row":
|
|
268
|
+
return `${slot.type}`;
|
|
269
|
+
case "empty-column":
|
|
270
|
+
return `${slot.type}:${slot.rowId}:${slot.columnIndex}`;
|
|
271
|
+
}
|
|
272
|
+
}, "getSlotKey");
|
|
273
|
+
const isPointInsideRect = /* @__PURE__ */ __name((point, rect) => {
|
|
274
|
+
return point.x >= rect.left && point.x <= rect.left + rect.width && point.y >= rect.top && point.y <= rect.top + rect.height;
|
|
275
|
+
}, "isPointInsideRect");
|
|
276
|
+
const distanceToRect = /* @__PURE__ */ __name((point, rect) => {
|
|
277
|
+
const dx = Math.max(rect.left - point.x, 0, point.x - (rect.left + rect.width));
|
|
278
|
+
const dy = Math.max(rect.top - point.y, 0, point.y - (rect.top + rect.height));
|
|
279
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
280
|
+
}, "distanceToRect");
|
|
281
|
+
const resolveDropIntent = /* @__PURE__ */ __name((point, slots) => {
|
|
282
|
+
if (!slots.length) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
const insideSlot = slots.find((slot) => isPointInsideRect(point, slot.rect));
|
|
286
|
+
if (insideSlot) {
|
|
287
|
+
return insideSlot;
|
|
288
|
+
}
|
|
289
|
+
let closest = null;
|
|
290
|
+
let minDistance = Number.POSITIVE_INFINITY;
|
|
291
|
+
slots.forEach((slot) => {
|
|
292
|
+
const distance = distanceToRect(point, slot.rect);
|
|
293
|
+
if (distance < minDistance) {
|
|
294
|
+
minDistance = distance;
|
|
295
|
+
closest = slot;
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
return closest;
|
|
299
|
+
}, "resolveDropIntent");
|
|
300
|
+
const findUidPosition = /* @__PURE__ */ __name((rows, uidValue) => {
|
|
301
|
+
for (const [rowId, columns] of Object.entries(rows)) {
|
|
302
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
303
|
+
const column = columns[columnIndex];
|
|
304
|
+
const itemIndex = column.indexOf(uidValue);
|
|
305
|
+
if (itemIndex !== -1) {
|
|
306
|
+
return { rowId, columnIndex, itemIndex };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
}, "findUidPosition");
|
|
312
|
+
const removeItemFromLayout = /* @__PURE__ */ __name((layout, uidValue) => {
|
|
313
|
+
const position = findUidPosition(layout.rows, uidValue);
|
|
314
|
+
if (!position) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const { rowId, columnIndex, itemIndex } = position;
|
|
318
|
+
const columns = layout.rows[rowId];
|
|
319
|
+
const column = columns == null ? void 0 : columns[columnIndex];
|
|
320
|
+
if (!column) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
column.splice(itemIndex, 1);
|
|
324
|
+
if (column.length === 0) {
|
|
325
|
+
columns.splice(columnIndex, 1);
|
|
326
|
+
if (layout.sizes[rowId]) {
|
|
327
|
+
layout.sizes[rowId].splice(columnIndex, 1);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (columns.length === 0) {
|
|
331
|
+
delete layout.rows[rowId];
|
|
332
|
+
delete layout.sizes[rowId];
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
normalizeRowSizes(rowId, layout);
|
|
336
|
+
}, "removeItemFromLayout");
|
|
337
|
+
const toIntSizes = /* @__PURE__ */ __name((weights, count) => {
|
|
338
|
+
if (count === 0) {
|
|
339
|
+
return [];
|
|
340
|
+
}
|
|
341
|
+
const normalizedWeights = weights.map((weight) => Number.isFinite(weight) && weight > 0 ? weight : 1);
|
|
342
|
+
const total = normalizedWeights.reduce((sum, weight) => sum + weight, 0) || count;
|
|
343
|
+
const ratios = normalizedWeights.map((weight) => weight / total);
|
|
344
|
+
const raw = ratios.map((ratio) => ratio * DEFAULT_GRID_COLUMNS);
|
|
345
|
+
const floors = raw.map((value) => Math.max(1, Math.floor(value)));
|
|
346
|
+
let remainder = DEFAULT_GRID_COLUMNS - floors.reduce((sum, value) => sum + value, 0);
|
|
347
|
+
if (remainder > 0) {
|
|
348
|
+
const decimals = raw.map((value, index) => ({ index, decimal: value - Math.floor(value) })).sort((a, b) => b.decimal - a.decimal);
|
|
349
|
+
let pointer = 0;
|
|
350
|
+
while (remainder > 0 && decimals.length) {
|
|
351
|
+
const target = decimals[pointer % decimals.length].index;
|
|
352
|
+
floors[target] += 1;
|
|
353
|
+
remainder -= 1;
|
|
354
|
+
pointer += 1;
|
|
355
|
+
}
|
|
356
|
+
} else if (remainder < 0) {
|
|
357
|
+
const decimals = raw.map((value, index) => ({ index, decimal: value - Math.floor(value) })).sort((a, b) => a.decimal - b.decimal);
|
|
358
|
+
let pointer = 0;
|
|
359
|
+
while (remainder < 0 && decimals.length) {
|
|
360
|
+
const target = decimals[pointer % decimals.length].index;
|
|
361
|
+
if (floors[target] > 1) {
|
|
362
|
+
floors[target] -= 1;
|
|
363
|
+
remainder += 1;
|
|
364
|
+
}
|
|
365
|
+
pointer += 1;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const diff = DEFAULT_GRID_COLUMNS - floors.reduce((sum, value) => sum + value, 0);
|
|
369
|
+
if (diff !== 0 && floors.length) {
|
|
370
|
+
floors[floors.length - 1] += diff;
|
|
371
|
+
}
|
|
372
|
+
return floors;
|
|
373
|
+
}, "toIntSizes");
|
|
374
|
+
const normalizeRowSizes = /* @__PURE__ */ __name((rowId, layout) => {
|
|
375
|
+
const columns = layout.rows[rowId];
|
|
376
|
+
if (!columns || columns.length === 0) {
|
|
377
|
+
delete layout.sizes[rowId];
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const current = layout.sizes[rowId] || new Array(columns.length).fill(DEFAULT_GRID_COLUMNS / columns.length);
|
|
381
|
+
const weights = current.length === columns.length ? current : new Array(columns.length).fill(DEFAULT_GRID_COLUMNS / columns.length);
|
|
382
|
+
layout.sizes[rowId] = toIntSizes(weights, columns.length);
|
|
383
|
+
}, "normalizeRowSizes");
|
|
384
|
+
const insertRow = /* @__PURE__ */ __name((rows, referenceRowId, newRowId, position, value) => {
|
|
385
|
+
const entries = Object.entries(rows);
|
|
386
|
+
const result = {};
|
|
387
|
+
let inserted = false;
|
|
388
|
+
entries.forEach(([rowId, rowValue]) => {
|
|
389
|
+
if (!inserted && position === "before" && rowId === referenceRowId) {
|
|
390
|
+
result[newRowId] = value;
|
|
391
|
+
inserted = true;
|
|
392
|
+
}
|
|
393
|
+
result[rowId] = rowValue;
|
|
394
|
+
if (!inserted && position === "after" && rowId === referenceRowId) {
|
|
395
|
+
result[newRowId] = value;
|
|
396
|
+
inserted = true;
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
if (!inserted) {
|
|
400
|
+
result[newRowId] = value;
|
|
401
|
+
}
|
|
402
|
+
return result;
|
|
403
|
+
}, "insertRow");
|
|
404
|
+
const distributeSizesWithNewColumn = /* @__PURE__ */ __name((sizes, insertIndex, columnCount) => {
|
|
405
|
+
if (!sizes || sizes.length === 0) {
|
|
406
|
+
return toIntSizes(new Array(columnCount).fill(1), columnCount);
|
|
407
|
+
}
|
|
408
|
+
const normalized = sizes.map((size) => Number.isFinite(size) && size > 0 ? size : 1);
|
|
409
|
+
const referenceIndex = Math.max(0, Math.min(insertIndex, normalized.length - 1));
|
|
410
|
+
const reference = normalized[referenceIndex] ?? 1;
|
|
411
|
+
const weights = [...normalized];
|
|
412
|
+
weights.splice(insertIndex, 0, reference);
|
|
413
|
+
return toIntSizes(weights, columnCount);
|
|
414
|
+
}, "distributeSizesWithNewColumn");
|
|
415
|
+
const simulateLayoutForSlot = /* @__PURE__ */ __name(({
|
|
416
|
+
slot,
|
|
417
|
+
sourceUid,
|
|
418
|
+
layout,
|
|
419
|
+
generateRowId
|
|
420
|
+
}) => {
|
|
421
|
+
const cloned = {
|
|
422
|
+
rows: import_lodash.default.cloneDeep(layout.rows),
|
|
423
|
+
sizes: import_lodash.default.cloneDeep(layout.sizes)
|
|
424
|
+
};
|
|
425
|
+
removeItemFromLayout(cloned, sourceUid);
|
|
426
|
+
const createRowId = generateRowId ?? import_shared.uid;
|
|
427
|
+
switch (slot.type) {
|
|
428
|
+
case "column": {
|
|
429
|
+
const columns = cloned.rows[slot.rowId] || [];
|
|
430
|
+
if (!cloned.rows[slot.rowId]) {
|
|
431
|
+
cloned.rows[slot.rowId] = columns;
|
|
432
|
+
}
|
|
433
|
+
if (!columns[slot.columnIndex]) {
|
|
434
|
+
columns[slot.columnIndex] = [];
|
|
435
|
+
}
|
|
436
|
+
const targetColumn = columns[slot.columnIndex];
|
|
437
|
+
targetColumn.splice(slot.insertIndex, 0, sourceUid);
|
|
438
|
+
normalizeRowSizes(slot.rowId, cloned);
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
case "empty-column": {
|
|
442
|
+
const columns = cloned.rows[slot.rowId] || [];
|
|
443
|
+
if (!cloned.rows[slot.rowId]) {
|
|
444
|
+
cloned.rows[slot.rowId] = columns;
|
|
445
|
+
}
|
|
446
|
+
if (!columns[slot.columnIndex]) {
|
|
447
|
+
columns[slot.columnIndex] = [];
|
|
448
|
+
}
|
|
449
|
+
columns[slot.columnIndex] = [sourceUid];
|
|
450
|
+
normalizeRowSizes(slot.rowId, cloned);
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case "column-edge": {
|
|
454
|
+
const columns = cloned.rows[slot.rowId] || [];
|
|
455
|
+
if (!cloned.rows[slot.rowId]) {
|
|
456
|
+
cloned.rows[slot.rowId] = columns;
|
|
457
|
+
}
|
|
458
|
+
const insertIndex = slot.direction === "left" ? slot.columnIndex : slot.columnIndex + 1;
|
|
459
|
+
columns.splice(insertIndex, 0, [sourceUid]);
|
|
460
|
+
cloned.sizes[slot.rowId] = distributeSizesWithNewColumn(cloned.sizes[slot.rowId], insertIndex, columns.length);
|
|
461
|
+
normalizeRowSizes(slot.rowId, cloned);
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
case "row-gap": {
|
|
465
|
+
const newRowId = createRowId();
|
|
466
|
+
const rowPosition = slot.position === "above" ? "before" : "after";
|
|
467
|
+
cloned.rows = insertRow(cloned.rows, slot.targetRowId, newRowId, rowPosition, [[sourceUid]]);
|
|
468
|
+
cloned.sizes[newRowId] = [DEFAULT_GRID_COLUMNS];
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
case "empty-row": {
|
|
472
|
+
const newRowId = createRowId();
|
|
473
|
+
cloned.rows = {
|
|
474
|
+
...cloned.rows,
|
|
475
|
+
[newRowId]: [[sourceUid]]
|
|
476
|
+
};
|
|
477
|
+
cloned.sizes[newRowId] = [DEFAULT_GRID_COLUMNS];
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
default:
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
return cloned;
|
|
484
|
+
}, "simulateLayoutForSlot");
|
|
485
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
486
|
+
0 && (module.exports = {
|
|
487
|
+
COLUMN_EDGE_MAX_WIDTH,
|
|
488
|
+
COLUMN_EDGE_MIN_WIDTH,
|
|
489
|
+
COLUMN_EDGE_WIDTH_RATIO,
|
|
490
|
+
DEFAULT_GRID_COLUMNS,
|
|
491
|
+
MAX_SLOT_THICKNESS,
|
|
492
|
+
MIN_SLOT_THICKNESS,
|
|
493
|
+
buildLayoutSnapshot,
|
|
494
|
+
getSlotKey,
|
|
495
|
+
resolveDropIntent,
|
|
496
|
+
simulateLayoutForSlot
|
|
497
|
+
});
|
|
@@ -10,8 +10,8 @@ import { DndContextProps } from '@dnd-kit/core';
|
|
|
10
10
|
import React, { FC } from 'react';
|
|
11
11
|
import { FlowModel } from '../../models';
|
|
12
12
|
import { PersistOptions } from '../../types';
|
|
13
|
-
export * from './
|
|
14
|
-
export * from './
|
|
13
|
+
export * from './findModelUidPosition';
|
|
14
|
+
export * from './gridDragPlanner';
|
|
15
15
|
export declare const EMPTY_COLUMN_UID = "EMPTY_COLUMN";
|
|
16
16
|
export declare const DragHandler: FC<{
|
|
17
17
|
model: FlowModel;
|