@bemedev/mind-flow 0.3.2 → 1.0.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/README.md +55 -12
- package/lib/helpers/clamp.d.ts +2 -0
- package/lib/helpers/clamp.d.ts.map +1 -0
- package/lib/helpers/createContext.d.ts +1 -1
- package/lib/helpers/createContext.d.ts.map +1 -1
- package/lib/helpers/index.d.ts +3 -0
- package/lib/helpers/index.d.ts.map +1 -0
- package/lib/index.cjs.js +1 -1
- package/lib/index.d.ts +9 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +2473 -373
- package/lib/output.css +1 -1
- package/lib/server.cjs.js +1011 -262
- package/lib/server.es.js +977 -272
- package/lib/services/main.machine.d.ts +1564 -667
- package/lib/services/main.machine.d.ts.map +1 -1
- package/lib/services/main.machine.data.d.ts +14 -1
- package/lib/services/main.machine.data.d.ts.map +1 -1
- package/lib/services/main.machine.helpers.d.ts +1 -1
- package/lib/services/main.machine.helpers.d.ts.map +1 -1
- package/lib/services/main.machine.test.d.ts +2 -0
- package/lib/services/main.machine.test.d.ts.map +1 -0
- package/lib/services/main.machine.typings.d.ts +26 -8
- package/lib/services/main.machine.typings.d.ts.map +1 -1
- package/lib/ui/Flow.d.ts +8 -4
- package/lib/ui/Flow.d.ts.map +1 -1
- package/lib/ui/components/Bounds.d.ts.map +1 -1
- package/lib/ui/components/EdgeComponent.d.ts.map +1 -1
- package/lib/ui/components/EdgesBoard.d.ts.map +1 -1
- package/lib/ui/components/EditPanel.d.ts +19 -0
- package/lib/ui/components/EditPanel.d.ts.map +1 -0
- package/lib/ui/components/EditPanel.hooks.d.ts +29 -0
- package/lib/ui/components/EditPanel.hooks.d.ts.map +1 -0
- package/lib/ui/components/EditPanel.types.d.ts +47 -0
- package/lib/ui/components/EditPanel.types.d.ts.map +1 -0
- package/lib/ui/components/FlowChart.context.d.ts +1563 -666
- package/lib/ui/components/FlowChart.context.d.ts.map +1 -1
- package/lib/ui/components/FlowChart.d.ts +8 -47
- package/lib/ui/components/FlowChart.d.ts.map +1 -1
- package/lib/ui/components/FlowChart.types.d.ts +87 -0
- package/lib/ui/components/FlowChart.types.d.ts.map +1 -0
- package/lib/ui/components/NodeComponent.d.ts +10 -12
- package/lib/ui/components/NodeComponent.d.ts.map +1 -1
- package/lib/ui/components/NodesBoard.d.ts +17 -2
- package/lib/ui/components/NodesBoard.d.ts.map +1 -1
- package/lib/ui/components/Panels.d.ts +12 -0
- package/lib/ui/components/Panels.d.ts.map +1 -0
- package/lib/ui/globals/components/atoms/TypingText.d.ts +29 -0
- package/lib/ui/globals/components/atoms/TypingText.d.ts.map +1 -0
- package/lib/ui/globals/components/molecules/FadingDots.d.ts +21 -0
- package/lib/ui/globals/components/molecules/FadingDots.d.ts.map +1 -0
- package/lib/ui/globals/components/organisms/LoadingFallback.d.ts +46 -0
- package/lib/ui/globals/components/organisms/LoadingFallback.d.ts.map +1 -0
- package/lib/ui/globals/constants/index.d.ts +3 -0
- package/lib/ui/globals/constants/index.d.ts.map +1 -0
- package/lib/ui/globals/constants/links.d.ts +4 -0
- package/lib/ui/globals/constants/links.d.ts.map +1 -0
- package/lib/ui/globals/constants/strings.d.ts +5 -0
- package/lib/ui/globals/constants/strings.d.ts.map +1 -0
- package/lib/ui/globals/directives/clickOutside.d.ts +9 -0
- package/lib/ui/globals/directives/clickOutside.d.ts.map +1 -0
- package/lib/ui/globals/directives/index.d.ts +16 -0
- package/lib/ui/globals/directives/index.d.ts.map +1 -0
- package/lib/ui/globals/directives/mouseOut.d.ts +33 -0
- package/lib/ui/globals/directives/mouseOut.d.ts.map +1 -0
- package/lib/ui/globals/directives/mouseOut.test.d.ts +2 -0
- package/lib/ui/globals/directives/mouseOut.test.d.ts.map +1 -0
- package/lib/ui/globals/directives/resize.d.ts +11 -0
- package/lib/ui/globals/directives/resize.d.ts.map +1 -0
- package/lib/ui/globals/helpers/espace.d.ts +17 -0
- package/lib/ui/globals/helpers/espace.d.ts.map +1 -0
- package/lib/ui/globals/signals/createTyping.d.ts +27 -0
- package/lib/ui/globals/signals/createTyping.d.ts.map +1 -0
- package/lib/ui/globals/types.d.ts +54 -0
- package/lib/ui/globals/types.d.ts.map +1 -0
- package/lib/ui/utils.d.ts +11 -0
- package/lib/ui/utils.d.ts.map +1 -0
- package/package.json +2 -3
- package/src/helpers/clamp.ts +3 -0
- package/src/helpers/createContext.ts +20 -4
- package/src/helpers/index.ts +2 -0
- package/src/index.ts +9 -1
- package/src/services/main.machine.data.ts +13 -2
- package/src/services/main.machine.helpers.ts +12 -4
- package/src/services/main.machine.test.ts +205 -0
- package/src/services/main.machine.ts +136 -65
- package/src/services/main.machine.typings.ts +31 -6
- package/src/ui/Flow.tsx +47 -8
- package/src/ui/components/Bounds.tsx +0 -2
- package/src/ui/components/EdgeComponent.tsx +60 -46
- package/src/ui/components/EdgesBoard.tsx +1 -2
- package/src/ui/components/EditPanel.hooks.ts +69 -0
- package/src/ui/components/EditPanel.tsx +89 -0
- package/src/ui/components/EditPanel.types.ts +49 -0
- package/src/ui/components/FlowChart.context.ts +21 -11
- package/src/ui/components/FlowChart.tsx +20 -57
- package/src/ui/components/FlowChart.types.ts +92 -0
- package/src/ui/components/NodeComponent.tsx +81 -58
- package/src/ui/components/NodesBoard.tsx +29 -7
- package/src/ui/components/Panels.tsx +40 -0
- package/src/ui/globals/components/atoms/TypingText.tsx +63 -0
- package/src/ui/globals/components/molecules/FadingDots.tsx +45 -0
- package/src/ui/globals/components/organisms/LoadingFallback.tsx +116 -0
- package/src/ui/globals/constants/index.ts +2 -0
- package/src/ui/globals/constants/links.ts +15 -0
- package/src/ui/globals/constants/strings.ts +5 -0
- package/src/ui/globals/directives/clickOutside.ts +18 -0
- package/src/ui/globals/directives/index.ts +16 -0
- package/src/ui/globals/directives/mouseOut.test.ts +115 -0
- package/src/ui/globals/directives/mouseOut.ts +98 -0
- package/src/ui/globals/directives/resize.ts +33 -0
- package/src/ui/globals/helpers/espace.ts +26 -0
- package/src/ui/globals/signals/createTyping.ts +82 -0
- package/src/ui/globals/types.ts +83 -0
- package/src/ui/utils.ts +14 -0
package/lib/server.es.js
CHANGED
|
@@ -1,11 +1,189 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isDefined, toArray, type } from "@bemedev/app/bemedev";
|
|
2
|
+
import { Dynamic, createComponent, escape, memo, mergeProps, ssr, ssrAttribute, ssrClassList, ssrElement, ssrHydrationKey, ssrStyle, ssrStyleProperty } from "solid-js/web";
|
|
2
3
|
import { createState } from "@bemedev/app-solidjs";
|
|
3
|
-
import { For, Show, createContext, createEffect, createSignal, on, onCleanup, onMount, useContext } from "solid-js";
|
|
4
|
-
import { createMachine, interpret, toArray } from "@bemedev/app";
|
|
5
|
-
import { toArray as toArray$1, type } from "@bemedev/app/bemedev";
|
|
4
|
+
import { For, Show, createComponent as createComponent$1, createContext as createContext$1, createEffect, createMemo, createSignal, on, onCleanup, onMount, splitProps, useContext } from "solid-js";
|
|
5
|
+
import { createMachine, deepEqual, interpret, toArray as toArray$1 } from "@bemedev/app";
|
|
6
6
|
import { nanoid } from "nanoid";
|
|
7
7
|
import { DragDropProvider, DragDropSensors, DragOverlay, createDraggable, useDragDropContext } from "@thisbeyond/solid-dnd";
|
|
8
8
|
import { dequal } from "dequal";
|
|
9
|
+
import { clsx } from "clsx";
|
|
10
|
+
import { twMerge } from "tailwind-merge";
|
|
11
|
+
//#region src/services/main.machine.data.ts
|
|
12
|
+
/** Horizontal gap in pixels between a parent node and newly created child node. */
|
|
13
|
+
var PARENT_CHILD_GAP_WIDTH = 100;
|
|
14
|
+
/** Default width and height dimensions for newly created flowchart nodes. */
|
|
15
|
+
var DEFAULT_SIZE = {
|
|
16
|
+
width: 192,
|
|
17
|
+
height: 50
|
|
18
|
+
};
|
|
19
|
+
/** Default node width in pixels. */
|
|
20
|
+
var DEFAULT_NODE_WIDTH = DEFAULT_SIZE.width;
|
|
21
|
+
/** Default node height in pixels. */
|
|
22
|
+
var DEFAULT_NODE_HEIGHT = DEFAULT_SIZE.height;
|
|
23
|
+
/** Default node data payload applied when creating new nodes. */
|
|
24
|
+
var DEFAULT_DATA = { content: "<Nouveau nœud>" };
|
|
25
|
+
/** Border width in pixels for a node container. */
|
|
26
|
+
var NODE_BORDER_WIDTH = 1.5;
|
|
27
|
+
/** Diameter in pixels of a node connection handle. */
|
|
28
|
+
var HANDLE_SIZE = 12;
|
|
29
|
+
/** Radius in pixels of a node connection handle. */
|
|
30
|
+
var HANDLE_RADIUS = 6;
|
|
31
|
+
/** Top margin in pixels for positioning connection handles. */
|
|
32
|
+
var HANDLE_MARGIN_TOP = 12;
|
|
33
|
+
/** Horizontal container offset in pixels for handle placement. */
|
|
34
|
+
var HANDLE_CONTAINER_OFFSET_X = 18;
|
|
35
|
+
/** Y-axis center coordinate in pixels of a handle. */
|
|
36
|
+
var HANDLE_CENTER_Y = 18;
|
|
37
|
+
/** X-axis center offset in pixels from the node container edge. */
|
|
38
|
+
var HANDLE_CENTER_X_OFFSET = 10.5;
|
|
39
|
+
/** Default X offset in pixels for input connection handles. */
|
|
40
|
+
var DEFAULT_INPUT_OFFSET_X = -10.5;
|
|
41
|
+
/** Default Y offset in pixels for input connection handles. */
|
|
42
|
+
var DEFAULT_INPUT_OFFSET_Y = 18;
|
|
43
|
+
/** Default 2D offset coordinates for input connection handles. */
|
|
44
|
+
var DEFAULT_INPUT_OFFSET = {
|
|
45
|
+
x: DEFAULT_INPUT_OFFSET_X,
|
|
46
|
+
y: 18
|
|
47
|
+
};
|
|
48
|
+
/** Dimensions representing width and height of the flow chart container canvas. */
|
|
49
|
+
var CONTAINER_DIMENSIONS = {
|
|
50
|
+
WIDTH: 5e3,
|
|
51
|
+
HEIGHT: 3500
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Computes default output handle offset coordinates given a node width.
|
|
55
|
+
*
|
|
56
|
+
* @param width - Node width in pixels, defaults to `0`.
|
|
57
|
+
*
|
|
58
|
+
* @returns 2D offset coordinates for the output handle.
|
|
59
|
+
*
|
|
60
|
+
* @see {@linkcode HANDLE_CENTER_X_OFFSET}, {@linkcode HANDLE_CENTER_Y}
|
|
61
|
+
*/
|
|
62
|
+
var getDefaultOutputOffset = (width = 0) => ({
|
|
63
|
+
x: width + HANDLE_CENTER_X_OFFSET,
|
|
64
|
+
y: 18
|
|
65
|
+
});
|
|
66
|
+
/** Top offset in pixels for node action toolbars. */
|
|
67
|
+
var TOOLBAR_TOP_OFFSET = 30;
|
|
68
|
+
/** Safety buffer in pixels applied above the toolbar. */
|
|
69
|
+
var TOOLBAR_BUFFER = 5;
|
|
70
|
+
/**
|
|
71
|
+
* Boundary padding constraints for node dragging and positioning within the
|
|
72
|
+
* viewport.
|
|
73
|
+
*/
|
|
74
|
+
var BOUNDS_CONSTRAINTS = {
|
|
75
|
+
horizontal: 55,
|
|
76
|
+
vertical: 40
|
|
77
|
+
};
|
|
78
|
+
/** Multiplier factor used to compute canvas virtual scroll dimensions. */
|
|
79
|
+
var CANVAS_FACTOR = 5;
|
|
80
|
+
/** Multiplier factor used to compute canvas scroll dimensions. */
|
|
81
|
+
var SCROLL_MULTIPLIER = 3;
|
|
82
|
+
/**
|
|
83
|
+
* Default node items of type {@linkcode NodeProps} provided when no initial
|
|
84
|
+
* configuration is given.
|
|
85
|
+
*/
|
|
86
|
+
var DEFAULT_NODES = [{
|
|
87
|
+
id: "node-0",
|
|
88
|
+
data: {
|
|
89
|
+
content: "Some text",
|
|
90
|
+
label: "Root node"
|
|
91
|
+
},
|
|
92
|
+
position: {
|
|
93
|
+
x: 350,
|
|
94
|
+
y: 100
|
|
95
|
+
}
|
|
96
|
+
}];
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/services/main.machine.typings.ts
|
|
99
|
+
/** Schema definition for 2D coordinates `(x, y)`. */
|
|
100
|
+
var point = type({
|
|
101
|
+
x: "number",
|
|
102
|
+
y: "number"
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* Schema definition for node handle offsets (input and output).
|
|
106
|
+
*
|
|
107
|
+
* @see {@linkcode point}
|
|
108
|
+
*/
|
|
109
|
+
var nodeOffset = type(({ use }) => ({
|
|
110
|
+
input: use(point),
|
|
111
|
+
output: use(point)
|
|
112
|
+
}));
|
|
113
|
+
/** Schema definition for edge extremities. */
|
|
114
|
+
var extremities = type({
|
|
115
|
+
from: "string",
|
|
116
|
+
to: "string"
|
|
117
|
+
});
|
|
118
|
+
/** Schema definition for primitive values allowed in node data. */
|
|
119
|
+
var nodeDataValue = type(({ union }) => union("string", "boolean", "number"));
|
|
120
|
+
/**
|
|
121
|
+
* Schema definition for serialized node data dictionary.
|
|
122
|
+
*
|
|
123
|
+
* @see {@linkcode nodeDataValue}
|
|
124
|
+
*/
|
|
125
|
+
var data = type(({ record, use }) => record(use(nodeDataValue)));
|
|
126
|
+
/**
|
|
127
|
+
* Schema definition for a serialized flowchart node entity.
|
|
128
|
+
*
|
|
129
|
+
* @see {@linkcode point}, {@linkcode data}
|
|
130
|
+
*/
|
|
131
|
+
var nodeJSON = type(({ use }) => ({
|
|
132
|
+
position: use(point),
|
|
133
|
+
data: use(data)
|
|
134
|
+
}));
|
|
135
|
+
/**
|
|
136
|
+
* Schema definition for a serialized flowchart edge entity.
|
|
137
|
+
*
|
|
138
|
+
* @see {@linkcode extremities}
|
|
139
|
+
*/
|
|
140
|
+
var edgeJSON = extremities;
|
|
141
|
+
/**
|
|
142
|
+
* Schema definition for layout dimensions and connection points of a node.
|
|
143
|
+
*
|
|
144
|
+
* @see {@linkcode point}
|
|
145
|
+
*/
|
|
146
|
+
var dimension = type(({ optional, use }) => ({
|
|
147
|
+
width: "number",
|
|
148
|
+
height: "number",
|
|
149
|
+
output: use(point),
|
|
150
|
+
input: optional(use(point)),
|
|
151
|
+
inputOffset: optional(use(point)),
|
|
152
|
+
outputOffset: optional(use(point))
|
|
153
|
+
}));
|
|
154
|
+
/**
|
|
155
|
+
* Schema definition for a 2D line vector representing edge coordinates `(x0, y0)` to
|
|
156
|
+
* `(x1, y1)`.
|
|
157
|
+
*/
|
|
158
|
+
var vector = type({
|
|
159
|
+
x0: "number",
|
|
160
|
+
y0: "number",
|
|
161
|
+
x1: "number",
|
|
162
|
+
y1: "number"
|
|
163
|
+
});
|
|
164
|
+
/**
|
|
165
|
+
* Schema definition for an ongoing new connection edge creation preview between
|
|
166
|
+
* source node and cursor position.
|
|
167
|
+
*
|
|
168
|
+
* @see {@linkcode vector}
|
|
169
|
+
*/
|
|
170
|
+
var newEdge = type(({ intersection, use }) => intersection({ from: "string" }, use(vector)));
|
|
171
|
+
/** Schema definition for flowchart board geometry and container scroll dimensions. */
|
|
172
|
+
var board = type(({ optional }) => ({
|
|
173
|
+
self: {
|
|
174
|
+
left: "number",
|
|
175
|
+
top: "number",
|
|
176
|
+
width: "number",
|
|
177
|
+
height: "number"
|
|
178
|
+
},
|
|
179
|
+
parent: optional({
|
|
180
|
+
scrollLeft: "number",
|
|
181
|
+
scrollTop: "number",
|
|
182
|
+
height: "number",
|
|
183
|
+
width: "number"
|
|
184
|
+
})
|
|
185
|
+
}));
|
|
186
|
+
//#endregion
|
|
9
187
|
//#region src/ui/components/classes.ts
|
|
10
188
|
/**
|
|
11
189
|
* List of Tailwind CSS class names used across flowchart UI components to ensure
|
|
@@ -92,50 +270,11 @@ var CLASSES = [
|
|
|
92
270
|
"cursor-crosshair",
|
|
93
271
|
"mt-3"
|
|
94
272
|
];
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
x: -10.5,
|
|
100
|
-
y: 18
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
* Computes default output handle offset coordinates given a node width.
|
|
104
|
-
*
|
|
105
|
-
* @param width - Node width in pixels, defaults to `0`.
|
|
106
|
-
*
|
|
107
|
-
* @returns 2D offset coordinates for the output handle.
|
|
108
|
-
*
|
|
109
|
-
* @see {@linkcode HANDLE_CENTER_X_OFFSET}, {@linkcode HANDLE_CENTER_Y}
|
|
110
|
-
*/
|
|
111
|
-
var getDefaultOutputOffset = (width = 0) => ({
|
|
112
|
-
x: width + HANDLE_CENTER_X_OFFSET,
|
|
113
|
-
y: 18
|
|
114
|
-
});
|
|
115
|
-
/**
|
|
116
|
-
* Boundary padding constraints for node dragging and positioning within the
|
|
117
|
-
* viewport.
|
|
118
|
-
*/
|
|
119
|
-
var BOUNDS_CONSTRAINTS = {
|
|
120
|
-
horizontal: 55,
|
|
121
|
-
vertical: 40
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/helpers/clamp.ts
|
|
275
|
+
var clamp = (value, min, max) => {
|
|
276
|
+
return Math.min(Math.max(value, min), max);
|
|
122
277
|
};
|
|
123
|
-
/**
|
|
124
|
-
* Default node items of type {@linkcode NodeProps} provided when no initial
|
|
125
|
-
* configuration is given.
|
|
126
|
-
*/
|
|
127
|
-
var DEFAULT_NODES = [{
|
|
128
|
-
id: "node-0",
|
|
129
|
-
data: {
|
|
130
|
-
content: "Some text",
|
|
131
|
-
label: "Root node"
|
|
132
|
-
},
|
|
133
|
-
input: false,
|
|
134
|
-
position: {
|
|
135
|
-
x: 350,
|
|
136
|
-
y: 100
|
|
137
|
-
}
|
|
138
|
-
}];
|
|
139
278
|
//#endregion
|
|
140
279
|
//#region src/helpers/createContext.ts
|
|
141
280
|
/**
|
|
@@ -152,13 +291,21 @@ var DEFAULT_NODES = [{
|
|
|
152
291
|
*
|
|
153
292
|
* @see {@linkcode createSolidContext}, {@linkcode useContext}
|
|
154
293
|
*/
|
|
155
|
-
var createContext
|
|
156
|
-
const _context = createContext(
|
|
157
|
-
const Provider = (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
294
|
+
var createContext = (context, options) => {
|
|
295
|
+
const _context = createContext$1(void 0, options);
|
|
296
|
+
const Provider = (props) => {
|
|
297
|
+
return createComponent$1(_context.Provider, {
|
|
298
|
+
value: context(),
|
|
299
|
+
get children() {
|
|
300
|
+
return props.children;
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
};
|
|
304
|
+
const _useContext = () => {
|
|
305
|
+
const __context = useContext(_context);
|
|
306
|
+
if (!__context) throw new Error("useContext must be used within a Provider");
|
|
307
|
+
return __context;
|
|
308
|
+
};
|
|
162
309
|
return [
|
|
163
310
|
Provider,
|
|
164
311
|
_useContext,
|
|
@@ -198,17 +345,17 @@ var buildNodeID = (generated) => {
|
|
|
198
345
|
*
|
|
199
346
|
* @returns Node layout dimension object of type {@linkcode Dimension}.
|
|
200
347
|
*
|
|
201
|
-
* @see {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}
|
|
348
|
+
* @see {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode DEFAULT_SIZE}
|
|
202
349
|
*/
|
|
203
350
|
var calculateDimensions = (position, parentDimension = {
|
|
204
|
-
width:
|
|
205
|
-
height:
|
|
351
|
+
width: DEFAULT_SIZE.width,
|
|
352
|
+
height: DEFAULT_SIZE.height,
|
|
206
353
|
inputOffset: DEFAULT_INPUT_OFFSET
|
|
207
354
|
}) => {
|
|
208
355
|
const width = parentDimension.width;
|
|
209
356
|
const height = parentDimension.height;
|
|
210
357
|
const outputOffset = parentDimension.outputOffset ?? getDefaultOutputOffset(width);
|
|
211
|
-
const inputOffset = parentDimension.inputOffset;
|
|
358
|
+
const inputOffset = parentDimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
212
359
|
return {
|
|
213
360
|
width,
|
|
214
361
|
height,
|
|
@@ -225,92 +372,12 @@ var calculateDimensions = (position, parentDimension = {
|
|
|
225
372
|
};
|
|
226
373
|
};
|
|
227
374
|
//#endregion
|
|
228
|
-
//#region src/services/main.machine.typings.ts
|
|
229
|
-
/** Schema definition for 2D coordinates `(x, y)`. */
|
|
230
|
-
var point = type({
|
|
231
|
-
x: "number",
|
|
232
|
-
y: "number"
|
|
233
|
-
});
|
|
234
|
-
type(({ optional, use }) => ({
|
|
235
|
-
input: optional(use(point)),
|
|
236
|
-
output: use(point)
|
|
237
|
-
}));
|
|
238
|
-
/** Schema definition for edge extremities. */
|
|
239
|
-
var extremities = type({
|
|
240
|
-
from: "string",
|
|
241
|
-
to: "string"
|
|
242
|
-
});
|
|
243
|
-
/**
|
|
244
|
-
* Schema definition for a serialized flowchart node entity.
|
|
245
|
-
*
|
|
246
|
-
* @see {@linkcode point}
|
|
247
|
-
*/
|
|
248
|
-
var nodeJSON = type(({ optional, use }) => ({
|
|
249
|
-
position: use(point),
|
|
250
|
-
data: {
|
|
251
|
-
label: optional("string"),
|
|
252
|
-
content: "string"
|
|
253
|
-
},
|
|
254
|
-
input: "boolean"
|
|
255
|
-
}));
|
|
256
|
-
/**
|
|
257
|
-
* Schema definition for a serialized flowchart edge entity.
|
|
258
|
-
*
|
|
259
|
-
* @see {@linkcode extremities}
|
|
260
|
-
*/
|
|
261
|
-
var edgeJSON = extremities;
|
|
262
|
-
/**
|
|
263
|
-
* Schema definition for layout dimensions and connection points of a node.
|
|
264
|
-
*
|
|
265
|
-
* @see {@linkcode point}
|
|
266
|
-
*/
|
|
267
|
-
var dimension = type(({ optional, use }) => ({
|
|
268
|
-
width: "number",
|
|
269
|
-
height: "number",
|
|
270
|
-
output: use(point),
|
|
271
|
-
input: optional(use(point)),
|
|
272
|
-
inputOffset: optional(use(point)),
|
|
273
|
-
outputOffset: optional(use(point))
|
|
274
|
-
}));
|
|
275
|
-
/**
|
|
276
|
-
* Schema definition for a 2D line vector representing edge coordinates `(x0, y0)` to
|
|
277
|
-
* `(x1, y1)`.
|
|
278
|
-
*/
|
|
279
|
-
var vector = type({
|
|
280
|
-
x0: "number",
|
|
281
|
-
y0: "number",
|
|
282
|
-
x1: "number",
|
|
283
|
-
y1: "number"
|
|
284
|
-
});
|
|
285
|
-
/**
|
|
286
|
-
* Schema definition for an ongoing new connection edge creation preview between
|
|
287
|
-
* source node and cursor position.
|
|
288
|
-
*
|
|
289
|
-
* @see {@linkcode vector}
|
|
290
|
-
*/
|
|
291
|
-
var newEdge = type(({ intersection, use }) => intersection({ from: "string" }, use(vector)));
|
|
292
|
-
/** Schema definition for flowchart board geometry and container scroll dimensions. */
|
|
293
|
-
var board = type(({ optional }) => ({
|
|
294
|
-
self: {
|
|
295
|
-
left: "number",
|
|
296
|
-
top: "number",
|
|
297
|
-
width: "number",
|
|
298
|
-
height: "number"
|
|
299
|
-
},
|
|
300
|
-
parent: optional({
|
|
301
|
-
scrollLeft: "number",
|
|
302
|
-
scrollTop: "number",
|
|
303
|
-
height: "number",
|
|
304
|
-
width: "number"
|
|
305
|
-
})
|
|
306
|
-
}));
|
|
307
|
-
//#endregion
|
|
308
375
|
//#region src/services/main.machine.ts
|
|
309
376
|
/**
|
|
310
377
|
* State machine managing flowchart state transitions, nodes, edges, selection, and
|
|
311
378
|
* layout actions.
|
|
312
379
|
*
|
|
313
|
-
* @see {@linkcode calculateDimensions}, {@linkcode buildEdgeId}, {@linkcode buildNodeID}, {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}
|
|
380
|
+
* @see {@linkcode calculateDimensions}, {@linkcode buildEdgeId}, {@linkcode buildNodeID}, {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode DEFAULT_SIZE}, {@linkcode DEFAULT_DATA}
|
|
314
381
|
*/
|
|
315
382
|
var machine = createMachine({
|
|
316
383
|
initial: "idle",
|
|
@@ -319,7 +386,7 @@ var machine = createMachine({
|
|
|
319
386
|
idle: { on: {
|
|
320
387
|
CONFIGURE: {
|
|
321
388
|
actions: ["configure"],
|
|
322
|
-
target: "/
|
|
389
|
+
target: "/construction"
|
|
323
390
|
},
|
|
324
391
|
CONFIGURE_EMPTY: "/working"
|
|
325
392
|
} },
|
|
@@ -328,6 +395,10 @@ var machine = createMachine({
|
|
|
328
395
|
target: "/working"
|
|
329
396
|
} },
|
|
330
397
|
working: { on: {
|
|
398
|
+
CONFIGURE: {
|
|
399
|
+
actions: ["configure"],
|
|
400
|
+
target: "/construction"
|
|
401
|
+
},
|
|
331
402
|
MOVE_IMMEDIATE: { actions: [{
|
|
332
403
|
name: "buildUI",
|
|
333
404
|
description: "Must be in the ui"
|
|
@@ -354,7 +425,6 @@ var machine = createMachine({
|
|
|
354
425
|
],
|
|
355
426
|
target: "/construction"
|
|
356
427
|
},
|
|
357
|
-
ADD_DIMENSION: { actions: ["addDimension"] },
|
|
358
428
|
ADD_SIBLING: {
|
|
359
429
|
actions: [
|
|
360
430
|
"generateID",
|
|
@@ -366,6 +436,7 @@ var machine = createMachine({
|
|
|
366
436
|
],
|
|
367
437
|
target: "/construction"
|
|
368
438
|
},
|
|
439
|
+
RESIZE: { actions: ["resize", "buildUI"] },
|
|
369
440
|
MOVE: {
|
|
370
441
|
actions: ["moveNode", "buildUI"],
|
|
371
442
|
target: "/construction"
|
|
@@ -385,14 +456,18 @@ var machine = createMachine({
|
|
|
385
456
|
DESELECT: { actions: ["deselect"] },
|
|
386
457
|
ZOOM: { actions: ["zoom"] },
|
|
387
458
|
TOGGLE_ZOOM: { actions: ["toggleZoom"] },
|
|
388
|
-
SET_BOARD: { actions: ["setBoard"] }
|
|
459
|
+
SET_BOARD: { actions: ["setBoard"] },
|
|
460
|
+
SET_NODE_DATA: { actions: ["setNodeData"] },
|
|
461
|
+
EDIT: { actions: ["edit"] },
|
|
462
|
+
STOP_EDIT: { actions: ["stopEdit"] }
|
|
389
463
|
} }
|
|
390
464
|
}
|
|
391
465
|
}, {
|
|
392
|
-
eventsMap: type(({ intersection, use, array }) => ({
|
|
466
|
+
eventsMap: type(({ intersection, use, array, optional }) => ({
|
|
393
467
|
CONFIGURE: {
|
|
394
468
|
nodes: array(intersection(use(nodeJSON), { id: "string" })),
|
|
395
|
-
edges: array(intersection(use(edgeJSON), { id: "string" }))
|
|
469
|
+
edges: array(intersection(use(edgeJSON), { id: "string" })),
|
|
470
|
+
defaultData: optional(use(data))
|
|
396
471
|
},
|
|
397
472
|
SET_BOARD: use(board),
|
|
398
473
|
CONFIGURE_EMPTY: "never",
|
|
@@ -412,15 +487,24 @@ var machine = createMachine({
|
|
|
412
487
|
DELETE: "string",
|
|
413
488
|
SELECT: "string",
|
|
414
489
|
DESELECT: "never",
|
|
490
|
+
EDIT: "string",
|
|
491
|
+
STOP_EDIT: "never",
|
|
415
492
|
ADD_EDGE: use(extremities),
|
|
416
493
|
START_NEW_EDGE: "string",
|
|
417
494
|
MOVE_NEW_EDGE: use(point),
|
|
418
495
|
CLEAR_NEW_EDGE: "never",
|
|
419
496
|
ZOOM: "number",
|
|
420
497
|
TOGGLE_ZOOM: "never",
|
|
421
|
-
|
|
498
|
+
RESIZE: {
|
|
499
|
+
id: "string",
|
|
500
|
+
size: {
|
|
501
|
+
width: "number",
|
|
502
|
+
height: "number"
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
SET_NODE_DATA: {
|
|
422
506
|
id: "string",
|
|
423
|
-
|
|
507
|
+
data: use(data)
|
|
424
508
|
}
|
|
425
509
|
})),
|
|
426
510
|
sync: true,
|
|
@@ -428,6 +512,7 @@ var machine = createMachine({
|
|
|
428
512
|
generatedId: union("string", "null"),
|
|
429
513
|
previousZoom: optional("number"),
|
|
430
514
|
dimensions: record(use(dimension)),
|
|
515
|
+
defaultData: optional(use(data)),
|
|
431
516
|
getBoardPosition: custom(),
|
|
432
517
|
clampPosition: custom(),
|
|
433
518
|
calculateDimensions: custom()
|
|
@@ -447,23 +532,42 @@ var machine = createMachine({
|
|
|
447
532
|
edgesPositions: record(use(vector)),
|
|
448
533
|
newEdge: optional(use(newEdge)),
|
|
449
534
|
selected: optional("string"),
|
|
535
|
+
editing: optional("string"),
|
|
450
536
|
updatingUI: optional("boolean"),
|
|
451
537
|
zoom: "number",
|
|
452
538
|
bounds: use(point)
|
|
453
539
|
}))
|
|
454
540
|
}).provideOptions(({ assign, batch, erase, filter, action }) => ({ actions: {
|
|
455
|
-
configure: batch(assign("data", { CONFIGURE: ({ payload
|
|
541
|
+
configure: batch(assign("data", { CONFIGURE: ({ payload: { nodes, edges } }) => ({
|
|
542
|
+
nodes,
|
|
543
|
+
edges
|
|
544
|
+
}) }), assign("newEdge", () => void 0), assign("updatingUI", () => false), action(({ pContext }) => {
|
|
456
545
|
pContext.generatedId = null;
|
|
457
|
-
}), action({ CONFIGURE: ({ payload: { nodes }, pContext
|
|
546
|
+
}), action({ CONFIGURE: ({ payload: { nodes, defaultData }, pContext }) => {
|
|
547
|
+
pContext.defaultData = defaultData;
|
|
458
548
|
nodes.forEach(({ id, position }) => {
|
|
459
|
-
dimensions[id] = calculateDimensions(position);
|
|
549
|
+
pContext.dimensions[id] = calculateDimensions(position);
|
|
460
550
|
});
|
|
461
551
|
} })),
|
|
552
|
+
setNodeData: assign("data.nodes", { SET_NODE_DATA: ({ context: { data }, payload: { id, data: newData } }) => {
|
|
553
|
+
return data?.nodes?.map((node) => {
|
|
554
|
+
if (node.id === id) return {
|
|
555
|
+
...node,
|
|
556
|
+
data: {
|
|
557
|
+
...node.data,
|
|
558
|
+
...newData
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
return node;
|
|
562
|
+
});
|
|
563
|
+
} }),
|
|
462
564
|
setBoard: assign("board", { SET_BOARD: ({ payload }) => payload }),
|
|
463
565
|
generateID: action(({ pContext }) => pContext.generatedId = nanoid()),
|
|
464
566
|
select: assign("selected", { SELECT: ({ payload }) => payload }),
|
|
465
567
|
clearNewEdge: erase("newEdge"),
|
|
466
|
-
deselect: erase("selected"),
|
|
568
|
+
deselect: batch(erase("selected"), erase("editing")),
|
|
569
|
+
edit: batch(assign("editing", { EDIT: ({ payload }) => payload }), assign("selected", { EDIT: ({ payload }) => payload })),
|
|
570
|
+
stopEdit: erase("editing"),
|
|
467
571
|
startNewEdge: assign("newEdge", { START_NEW_EDGE: ({ payload: from, pContext: { dimensions } }) => {
|
|
468
572
|
const { x, y } = dimensions[from].output;
|
|
469
573
|
return {
|
|
@@ -478,8 +582,9 @@ var machine = createMachine({
|
|
|
478
582
|
MOVE: ({ context: { data, edgesPositions }, payload, pContext: { dimensions } }) => {
|
|
479
583
|
const edges = data?.edges;
|
|
480
584
|
const dimension = dimensions[payload.id];
|
|
481
|
-
|
|
482
|
-
const
|
|
585
|
+
if (!dimension) return;
|
|
586
|
+
const outputOffset = dimension.outputOffset ?? getDefaultOutputOffset(dimension.width);
|
|
587
|
+
const inputOffset = dimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
483
588
|
const output = {
|
|
484
589
|
x: payload.x + outputOffset.x,
|
|
485
590
|
y: payload.y + outputOffset.y
|
|
@@ -488,24 +593,24 @@ var machine = createMachine({
|
|
|
488
593
|
x: payload.x + inputOffset.x,
|
|
489
594
|
y: payload.y + inputOffset.y
|
|
490
595
|
};
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
dimension.input = input;
|
|
494
|
-
}
|
|
596
|
+
dimension.output = output;
|
|
597
|
+
dimension.input = input;
|
|
495
598
|
edges?.forEach(({ from, to, id }) => {
|
|
599
|
+
const edgePosition = edgesPositions[id];
|
|
600
|
+
if (!edgePosition) return;
|
|
496
601
|
if (from === payload.id) {
|
|
497
|
-
|
|
498
|
-
|
|
602
|
+
edgePosition.x0 = output.x;
|
|
603
|
+
edgePosition.y0 = output.y;
|
|
499
604
|
}
|
|
500
605
|
if (to === payload.id) {
|
|
501
|
-
|
|
502
|
-
|
|
606
|
+
edgePosition.x1 = input.x;
|
|
607
|
+
edgePosition.y1 = input.y;
|
|
503
608
|
}
|
|
504
609
|
});
|
|
505
610
|
return edgesPositions;
|
|
506
611
|
},
|
|
507
612
|
MOVE_IMMEDIATE: ({ context: { data, edgesPositions }, payload, pContext: { dimensions } }) => {
|
|
508
|
-
|
|
613
|
+
data?.edges?.forEach(({ from, to, id }) => {
|
|
509
614
|
const dimension = dimensions[payload.id];
|
|
510
615
|
const edgePosition = edgesPositions[id];
|
|
511
616
|
if (!edgePosition || !dimension) return;
|
|
@@ -534,29 +639,47 @@ var machine = createMachine({
|
|
|
534
639
|
});
|
|
535
640
|
return edgesPositions;
|
|
536
641
|
},
|
|
537
|
-
else: ({ context: { data
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
edges.forEach(({ from, id, to }) => {
|
|
642
|
+
else: ({ context: { data }, pContext: { dimensions } }) => {
|
|
643
|
+
const nextEdgesPositions = {};
|
|
644
|
+
data?.edges?.forEach(({ from, id, to }) => {
|
|
541
645
|
const output = dimensions[from]?.output;
|
|
542
646
|
const input = dimensions[to]?.input;
|
|
543
|
-
if (output && input)
|
|
647
|
+
if (output && input) nextEdgesPositions[id] = {
|
|
544
648
|
x0: output.x,
|
|
545
649
|
y0: output.y,
|
|
546
650
|
x1: input.x,
|
|
547
651
|
y1: input.y
|
|
548
652
|
};
|
|
549
|
-
else delete edgesPositions[id];
|
|
550
653
|
});
|
|
551
|
-
return
|
|
654
|
+
return nextEdgesPositions;
|
|
552
655
|
}
|
|
553
656
|
}), assign("updatingUI", () => true)),
|
|
554
|
-
|
|
555
|
-
dimensions[id]
|
|
657
|
+
resize: action({ RESIZE: ({ payload: { id, size: { width, height } }, context: { data }, pContext: { dimensions } }) => {
|
|
658
|
+
const dimension = dimensions[id];
|
|
659
|
+
if (!dimension) return;
|
|
660
|
+
dimension.width = width;
|
|
661
|
+
dimension.height = height;
|
|
662
|
+
const node = data?.nodes?.find((n) => n.id === id);
|
|
663
|
+
const outputOffset = getDefaultOutputOffset(width);
|
|
664
|
+
const inputOffset = dimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
665
|
+
dimension.outputOffset = outputOffset;
|
|
666
|
+
dimension.inputOffset = inputOffset;
|
|
667
|
+
if (node) {
|
|
668
|
+
dimension.output = {
|
|
669
|
+
x: node.position.x + outputOffset.x,
|
|
670
|
+
y: node.position.y + outputOffset.y
|
|
671
|
+
};
|
|
672
|
+
dimension.input = {
|
|
673
|
+
x: node.position.x + inputOffset.x,
|
|
674
|
+
y: node.position.y + inputOffset.y
|
|
675
|
+
};
|
|
676
|
+
} else dimension.output = {
|
|
677
|
+
x: dimension.output.x,
|
|
678
|
+
y: dimension.output.y
|
|
679
|
+
};
|
|
556
680
|
} }),
|
|
557
|
-
linkChild: batch(assign("data.edges", { ADD_CHILD: ({ context: { data }, pContext, payload }) => {
|
|
558
|
-
const edges = toArray
|
|
559
|
-
const from = payload;
|
|
681
|
+
linkChild: batch(assign("data.edges", { ADD_CHILD: ({ context: { data }, pContext, payload: from }) => {
|
|
682
|
+
const edges = toArray.typed(data?.edges);
|
|
560
683
|
const generatedId = pContext?.generatedId;
|
|
561
684
|
const to = buildNodeID(generatedId);
|
|
562
685
|
const id = buildEdgeId(from, to);
|
|
@@ -568,7 +691,7 @@ var machine = createMachine({
|
|
|
568
691
|
return edges;
|
|
569
692
|
} }), assign("selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId))),
|
|
570
693
|
linkSibling: batch(assign("data.edges", { ADD_SIBLING: ({ pContext, payload, context: { data } }) => {
|
|
571
|
-
const edges = toArray
|
|
694
|
+
const edges = toArray.typed(data?.edges);
|
|
572
695
|
const generatedId = pContext?.generatedId;
|
|
573
696
|
const from = edges.find(({ to }) => to === payload)?.from;
|
|
574
697
|
if (!from) return edges;
|
|
@@ -596,7 +719,7 @@ var machine = createMachine({
|
|
|
596
719
|
} }),
|
|
597
720
|
delete: batch(filter("data.edges", { DELETE: ({ id, from, to }, _, { payload }) => {
|
|
598
721
|
return id !== payload && from !== payload && to !== payload;
|
|
599
|
-
} }), filter("data.nodes", { DELETE: ({ id }, _, { payload }) => id !== payload })),
|
|
722
|
+
} }), filter("data.nodes", { DELETE: ({ id }, _, { payload }) => id !== payload }), erase("editing")),
|
|
600
723
|
addEdge: batch(assign("data.edges", { ADD_EDGE: ({ context, payload: { from, to } }) => {
|
|
601
724
|
const edges = context.data?.edges ?? [];
|
|
602
725
|
const id = buildEdgeId(from, to);
|
|
@@ -608,8 +731,7 @@ var machine = createMachine({
|
|
|
608
731
|
}];
|
|
609
732
|
} }), erase("newEdge")),
|
|
610
733
|
zoom: assign("zoom", { ZOOM: ({ context: { zoom }, payload, pContext }) => {
|
|
611
|
-
const
|
|
612
|
-
const clamped = Math.min(Math.max(Number(next.toFixed(2)), .2), 3);
|
|
734
|
+
const clamped = clamp(zoom + payload, .1, 3);
|
|
613
735
|
pContext.previousZoom = void 0;
|
|
614
736
|
return clamped;
|
|
615
737
|
} }),
|
|
@@ -630,19 +752,18 @@ var machine = createMachine({
|
|
|
630
752
|
if (!parentNode) return nodes;
|
|
631
753
|
const parentDimension = pContext.dimensions[payload];
|
|
632
754
|
const id = `node-${pContext.generatedId}`;
|
|
633
|
-
const width = parentDimension?.width ??
|
|
634
|
-
const height = parentDimension?.height ??
|
|
755
|
+
const width = parentDimension?.width ?? DEFAULT_SIZE.width;
|
|
756
|
+
const height = parentDimension?.height ?? DEFAULT_SIZE.height;
|
|
635
757
|
const initialX = parentNode.position.x + width + 100;
|
|
636
758
|
const initialY = parentNode.position.y;
|
|
637
759
|
const position = pContext.clampPosition(board, initialX, initialY, width, height);
|
|
638
|
-
const
|
|
760
|
+
const defaultData = pContext.defaultData ?? DEFAULT_DATA;
|
|
639
761
|
nodes?.push({
|
|
640
762
|
id,
|
|
641
|
-
data: {
|
|
642
|
-
input: true,
|
|
763
|
+
data: { ...defaultData },
|
|
643
764
|
position
|
|
644
765
|
});
|
|
645
|
-
pContext.dimensions[id] =
|
|
766
|
+
pContext.dimensions[id] = pContext.calculateDimensions(position, parentDimension ?? DEFAULT_SIZE);
|
|
646
767
|
return nodes;
|
|
647
768
|
} }),
|
|
648
769
|
placeParent: assign("data.nodes", { ADD_PARENT: ({ context: { data, zoom = 1, board }, pContext }) => {
|
|
@@ -657,15 +778,14 @@ var machine = createMachine({
|
|
|
657
778
|
const currentZoom = zoom;
|
|
658
779
|
const x = (scrollLeft + width / 2) / currentZoom;
|
|
659
780
|
const y = (scrollTop + height / 2) / currentZoom;
|
|
660
|
-
const position = pContext.clampPosition(board, x, y);
|
|
661
|
-
const
|
|
781
|
+
const position = pContext.clampPosition(board, x, y, DEFAULT_SIZE.width, DEFAULT_SIZE.height);
|
|
782
|
+
const defaultData = pContext.defaultData ?? DEFAULT_DATA;
|
|
662
783
|
nodes?.push({
|
|
663
784
|
id,
|
|
664
|
-
data: {
|
|
665
|
-
input: false,
|
|
785
|
+
data: { ...defaultData },
|
|
666
786
|
position
|
|
667
787
|
});
|
|
668
|
-
pContext.dimensions[id] =
|
|
788
|
+
pContext.dimensions[id] = pContext.calculateDimensions(position, DEFAULT_SIZE);
|
|
669
789
|
return nodes;
|
|
670
790
|
} }),
|
|
671
791
|
placeSibling: assign("data.nodes", { ADD_SIBLING: ({ payload, context: { data, board }, pContext }) => {
|
|
@@ -678,19 +798,18 @@ var machine = createMachine({
|
|
|
678
798
|
if (!parentNode) return nodes;
|
|
679
799
|
const parentDimension = pContext.dimensions[parentID];
|
|
680
800
|
const id = `node-${pContext.generatedId}`;
|
|
681
|
-
const width = parentDimension?.width ??
|
|
682
|
-
const height = parentDimension?.height ??
|
|
801
|
+
const width = parentDimension?.width ?? DEFAULT_SIZE.width;
|
|
802
|
+
const height = parentDimension?.height ?? DEFAULT_SIZE.height;
|
|
683
803
|
const initialX = parentNode.position.x + width + 100;
|
|
684
804
|
const initialY = parentNode.position.y + 100;
|
|
685
805
|
const position = pContext.clampPosition(board, initialX, initialY, width, height);
|
|
686
|
-
const
|
|
806
|
+
const defaultData = pContext.defaultData ?? DEFAULT_DATA;
|
|
687
807
|
nodes?.push({
|
|
688
808
|
id,
|
|
689
|
-
data: {
|
|
690
|
-
input: true,
|
|
809
|
+
data: { ...defaultData },
|
|
691
810
|
position
|
|
692
811
|
});
|
|
693
|
-
pContext.dimensions[id] =
|
|
812
|
+
pContext.dimensions[id] = pContext.calculateDimensions(position, parentDimension ?? DEFAULT_SIZE);
|
|
694
813
|
return nodes;
|
|
695
814
|
} }),
|
|
696
815
|
moveNewEdge: assign("newEdge", { MOVE_NEW_EDGE: ({ context: { newEdge, board }, payload, pContext }) => {
|
|
@@ -712,7 +831,7 @@ var machine = createMachine({
|
|
|
712
831
|
*
|
|
713
832
|
* @see {@linkcode machine}, {@linkcode createContext}
|
|
714
833
|
*/
|
|
715
|
-
var [Provider, useFlow] = createContext
|
|
834
|
+
var [Provider, useFlow] = createContext(() => {
|
|
716
835
|
/** Shared service for flowchart state management. */
|
|
717
836
|
const service = interpret(machine, {
|
|
718
837
|
context: {
|
|
@@ -753,14 +872,15 @@ var [Provider, useFlow] = createContext$1(() => {
|
|
|
753
872
|
* {@linkcode Board}.
|
|
754
873
|
* @param x - Desired X position in pixels.
|
|
755
874
|
* @param y - Desired Y position in pixels.
|
|
756
|
-
* @param nodeWidth - Node width in pixels, defaults to `
|
|
757
|
-
* @param nodeHeight - Node height in pixels, defaults to
|
|
875
|
+
* @param nodeWidth - Node width in pixels, defaults to `DEFAULT_SIZE.width`.
|
|
876
|
+
* @param nodeHeight - Node height in pixels, defaults to
|
|
877
|
+
* `DEFAULT_SIZE.height`.
|
|
758
878
|
*
|
|
759
879
|
* @returns Clamped coordinate of type {@linkcode Point}.
|
|
760
880
|
*
|
|
761
|
-
* @see {@linkcode BOUNDS_CONSTRAINTS}
|
|
881
|
+
* @see {@linkcode BOUNDS_CONSTRAINTS}, {@linkcode DEFAULT_SIZE}
|
|
762
882
|
*/
|
|
763
|
-
clampPosition: (board, x, y, nodeWidth =
|
|
883
|
+
clampPosition: (board, x, y, nodeWidth = DEFAULT_SIZE.width, nodeHeight = DEFAULT_SIZE.height) => {
|
|
764
884
|
const container = board?.parent;
|
|
765
885
|
if (!container) return {
|
|
766
886
|
x,
|
|
@@ -772,8 +892,8 @@ var [Provider, useFlow] = createContext$1(() => {
|
|
|
772
892
|
const minY = container.scrollTop / currentZoom + BOUNDS_CONSTRAINTS.vertical;
|
|
773
893
|
const maxY = Math.max(minY, (container.scrollTop + container.height) / currentZoom - BOUNDS_CONSTRAINTS.vertical - nodeHeight);
|
|
774
894
|
return {
|
|
775
|
-
x:
|
|
776
|
-
y:
|
|
895
|
+
x: clamp(x, minX, maxX),
|
|
896
|
+
y: clamp(y, minY, maxY)
|
|
777
897
|
};
|
|
778
898
|
},
|
|
779
899
|
/**
|
|
@@ -784,17 +904,17 @@ var [Provider, useFlow] = createContext$1(() => {
|
|
|
784
904
|
*
|
|
785
905
|
* @returns Calculated dimension object of type {@linkcode Dimension}.
|
|
786
906
|
*
|
|
787
|
-
* @see {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode getDefaultOutputOffset}
|
|
907
|
+
* @see {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_SIZE}
|
|
788
908
|
*/
|
|
789
909
|
calculateDimensions: (position, parentDimension = {
|
|
790
|
-
width:
|
|
791
|
-
height:
|
|
910
|
+
width: DEFAULT_SIZE.width,
|
|
911
|
+
height: DEFAULT_SIZE.height,
|
|
792
912
|
inputOffset: DEFAULT_INPUT_OFFSET
|
|
793
913
|
}) => {
|
|
794
914
|
const width = parentDimension.width;
|
|
795
915
|
const height = parentDimension.height;
|
|
796
916
|
const outputOffset = parentDimension.outputOffset ?? getDefaultOutputOffset(width);
|
|
797
|
-
const inputOffset = parentDimension.inputOffset;
|
|
917
|
+
const inputOffset = parentDimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
798
918
|
return {
|
|
799
919
|
width,
|
|
800
920
|
height,
|
|
@@ -865,14 +985,14 @@ var DragBounds = () => {
|
|
|
865
985
|
};
|
|
866
986
|
//#endregion
|
|
867
987
|
//#region src/ui/components/EdgeComponent.tsx
|
|
868
|
-
var _tmpl$$
|
|
988
|
+
var _tmpl$$10 = [
|
|
869
989
|
"<path",
|
|
870
990
|
" class=\"",
|
|
871
991
|
"\" style=\"",
|
|
872
992
|
"\"",
|
|
873
993
|
"></path>"
|
|
874
994
|
];
|
|
875
|
-
var _tmpl$2$
|
|
995
|
+
var _tmpl$2$5 = [
|
|
876
996
|
"<g",
|
|
877
997
|
" cursor=\"pointer\" transform=\"",
|
|
878
998
|
"\" style=\"",
|
|
@@ -885,6 +1005,13 @@ var _tmpl$2$2 = [
|
|
|
885
1005
|
*
|
|
886
1006
|
* @returns Offset distance in pixels for bezier curvature.
|
|
887
1007
|
*/
|
|
1008
|
+
/**
|
|
1009
|
+
* Computes bezier curve control point offset based on horizontal distance.
|
|
1010
|
+
*
|
|
1011
|
+
* @param value - Absolute horizontal delta between start and end points.
|
|
1012
|
+
*
|
|
1013
|
+
* @returns Offset distance in pixels for bezier curvature.
|
|
1014
|
+
*/
|
|
888
1015
|
var calculateOffset = (value) => value * 100 / 200;
|
|
889
1016
|
/**
|
|
890
1017
|
* Generates an SVG cubic bezier path `d` string between coordinates `(x0, y0)` and
|
|
@@ -896,7 +1023,9 @@ var calculateOffset = (value) => value * 100 / 200;
|
|
|
896
1023
|
*
|
|
897
1024
|
* @see {@linkcode calculateOffset}
|
|
898
1025
|
*/
|
|
899
|
-
var draw = (
|
|
1026
|
+
var draw = (vector) => {
|
|
1027
|
+
if (!vector) return "";
|
|
1028
|
+
const { x0, y0, x1, y1 } = vector;
|
|
900
1029
|
return `M ${x0} ${y0} C ${x0 + calculateOffset(Math.abs(x1 - x0))} ${y0}, ${x1 - calculateOffset(Math.abs(x1 - x0))} ${y1}, ${x1} ${y1}`;
|
|
901
1030
|
};
|
|
902
1031
|
/**
|
|
@@ -922,23 +1051,32 @@ var EdgeComponent = (props) => {
|
|
|
922
1051
|
/** Computes the 2D midpoint coordinate of the edge curve for handle placement. */
|
|
923
1052
|
const middlePoint = () => {
|
|
924
1053
|
const v = vector();
|
|
1054
|
+
if (!v) return {
|
|
1055
|
+
x: 0,
|
|
1056
|
+
y: 0
|
|
1057
|
+
};
|
|
925
1058
|
return {
|
|
926
1059
|
x: v.x0 + (v.x1 - v.x0) / 2,
|
|
927
1060
|
y: v.y0 + (v.y1 - v.y0) / 2
|
|
928
1061
|
};
|
|
929
1062
|
};
|
|
930
|
-
return
|
|
1063
|
+
return createComponent(Show, {
|
|
931
1064
|
get when() {
|
|
932
|
-
return
|
|
1065
|
+
return vector();
|
|
933
1066
|
},
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1067
|
+
children: (v) => [ssr(_tmpl$$10, ssrHydrationKey(), `relative cursor-pointer fill-transparent ${!!props.isNew ? "stroke-[rgba(168,168,168,0.4)] stroke-3 z-200" : ""} ${selected() && !props.isNew ? "stroke-[rgba(168,168,168,1)] stroke-4 z-100" : ""} ${!selected() && !props.isNew ? "stroke-[rgba(168,168,168,0.8)] stroke-3" : ""}`, ssrStyleProperty("pointer-events:", props.isNew ? "none" : "all"), ssrAttribute("d", escape(draw(v()), true), false)), createComponent(Show, {
|
|
1068
|
+
get when() {
|
|
1069
|
+
return selected();
|
|
1070
|
+
},
|
|
1071
|
+
get children() {
|
|
1072
|
+
return ssr(_tmpl$2$5, ssrHydrationKey(), `translate(${escape(middlePoint().x, true)}, ${escape(middlePoint().y, true)})`, ssrStyleProperty("pointer-events:", "all") + ssrStyleProperty(";z-index:", "30"));
|
|
1073
|
+
}
|
|
1074
|
+
})]
|
|
1075
|
+
});
|
|
938
1076
|
};
|
|
939
1077
|
//#endregion
|
|
940
1078
|
//#region src/ui/components/EdgesBoard.tsx
|
|
941
|
-
var _tmpl$$
|
|
1079
|
+
var _tmpl$$9 = [
|
|
942
1080
|
"<svg",
|
|
943
1081
|
" class=\"pointer-events-none h-full w-full overflow-visible\"><!--$-->",
|
|
944
1082
|
"<!--/--><!--$-->",
|
|
@@ -956,10 +1094,10 @@ var EdgesBoard = () => {
|
|
|
956
1094
|
const service = useFlow();
|
|
957
1095
|
const hasNewEdge = createState(service, { selector: (s) => !!s.context.newEdge });
|
|
958
1096
|
const edgeIds = createState(service, {
|
|
959
|
-
selector: ({ context }) => Object.keys(context.edgesPositions),
|
|
1097
|
+
selector: ({ context }) => Object.keys(context.edgesPositions ?? {}),
|
|
960
1098
|
equals: (prev, next) => prev.length === next.length
|
|
961
1099
|
});
|
|
962
|
-
return ssr(_tmpl$$
|
|
1100
|
+
return ssr(_tmpl$$9, ssrHydrationKey(), escape(createComponent(Show, {
|
|
963
1101
|
get when() {
|
|
964
1102
|
return hasNewEdge();
|
|
965
1103
|
},
|
|
@@ -978,18 +1116,12 @@ var EdgesBoard = () => {
|
|
|
978
1116
|
};
|
|
979
1117
|
//#endregion
|
|
980
1118
|
//#region src/ui/components/NodeComponent.tsx
|
|
981
|
-
var _tmpl$$
|
|
1119
|
+
var _tmpl$$8 = [
|
|
982
1120
|
"<svg",
|
|
983
1121
|
" class=\"cursor-pointer overflow-visible rounded-full bg-green-500 p-0.5 text-center font-bold hover:bg-green-600\" style=\"",
|
|
984
1122
|
"\" viewBox=\"0 0 1024 1024\" preserveAspectRatio=\"xMaxYMax\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"white\"><g id=\"background\"><path d=\"M467.40667,277.66696c-0.05948,-14.53055 5.75527,-22.95613 -8.62044,-20.90487c-112.55699,16.0607 -222.1609,112.14558 -245.06161,239.85765c-46.52056,259.43466 231.33083,443.06705 449.51209,316.97506c117.31668,-67.80002 160.95215,-190.43324 151.34416,-288.29849c-5.92276,-60.32819 -27.80273,-107.95668 -53.44246,-144.25469l59.39269,-42.05363c111.72214,156.309 73.11535,351.55635 -25.06953,459.45565c-184.18877,202.4124 -470.46624,145.52064 -592.95027,-32.92123c-156.18269,-227.53604 -27.15324,-543.64371 261.18883,-582.44416c5.0579,-0.68061 3.56556,-7.04079 3.56442,-8.58985c-0.05594,-76.3354 -0.11021,-76.7687 1.10909,-77.24589c2.06886,-0.80969 151.41433,118.4561 151.92482,118.95524c4.65592,4.55233 -0.99548,7.829 -29.07828,30.50907c-120.49369,97.31245 -120.4977,98.55675 -123.0691,97.87586c-0.43639,-0.11555 -0.80698,-0.31322 -0.74442,-66.91571Z\"></path><path d=\"M316.61562,611.03414c0.11517,-90.16257 -0.25516,-99.92912 0.64739,-101.78856c1.56486,-3.22393 131.99102,0.91032 134.6959,-1.89763c2.21336,-2.2977 -0.59362,-129.97807 1.1376,-132.37034c0.7253,-1.00225 11.10552,-0.99175 12.07474,-0.99077c104.50336,0.10564 104.90098,-0.37811 105.967,0.85765c1.56461,1.81373 0.25596,114.18436 0.67852,129.81412c0.1322,4.88975 3.22386,3.28152 99.72028,3.4563c33.0841,0.05992 36.14259,-1.40368 36.21852,4.50462c0.11713,9.11348 1.41954,110.45369 -0.40274,113.92715c-1.81106,3.45208 -130.39967,-0.42618 -134.48289,1.62075c-2.29035,1.14816 -0.36989,101.12392 -1.11542,130.51904c-0.09548,3.76459 -2.13506,3.20617 -47.84854,3.17365c-69.30253,-0.0493 -69.31099,-0.25627 -69.65762,-0.42191c-3.77927,-1.80595 0.16287,-129.33555 -2.24266,-132.58994c-1.79931,-2.43424 -124.06108,-0.29118 -132.80252,-0.97392c-3.81102,-0.29766 -2.58229,-14.8847 -2.58758,-16.8402Z\"></path></g></svg>"
|
|
985
1123
|
];
|
|
986
|
-
var _tmpl$2$
|
|
987
|
-
"<div",
|
|
988
|
-
" id=\"inputs\" class=\"pointer-events-none absolute top-0 z-10 flex cursor-default flex-col\" style=\"",
|
|
989
|
-
"\"><div class=\"cursor-default rounded-full bg-[#e38b29] shadow-md\" style=\"",
|
|
990
|
-
"\"></div></div>"
|
|
991
|
-
];
|
|
992
|
-
var _tmpl$3$1 = [
|
|
1124
|
+
var _tmpl$2$4 = [
|
|
993
1125
|
"<div",
|
|
994
1126
|
" class=\"",
|
|
995
1127
|
"\" style=\"",
|
|
@@ -998,28 +1130,44 @@ var _tmpl$3$1 = [
|
|
|
998
1130
|
"\"><svg class=\"cursor-pointer rounded-full fill-[#a11111] opacity-100 transition-all duration-200 ease-in-out\" fill=\"currentColor\" stroke-width=\"2\" viewBox=\"4 4 16 16\" style=\"",
|
|
999
1131
|
"\"><path d=\"M12 4c-4.419 0-8 3.582-8 8s3.581 8 8 8 8-3.582 8-8-3.581-8-8-8zm3.707 10.293a.999.999 0 11-1.414 1.414L12 13.414l-2.293 2.293a.997.997 0 01-1.414 0 .999.999 0 010-1.414L10.586 12 8.293 9.707a.999.999 0 111.414-1.414L12 10.586l2.293-2.293a.999.999 0 111.414 1.414L13.414 12l2.293 2.293z\"></path></svg><!--$-->",
|
|
1000
1132
|
"<!--/--><svg class=\"flex cursor-pointer items-center justify-center rounded-lg bg-blue-500 p-0.5 text-center font-bold text-white hover:bg-blue-600\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" style=\"",
|
|
1001
|
-
"\"><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"></path></svg></div
|
|
1002
|
-
"
|
|
1003
|
-
"
|
|
1004
|
-
"
|
|
1133
|
+
"\"><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"></path></svg></div><div>",
|
|
1134
|
+
"</div><div id=\"inputs\" class=\"pointer-events-none absolute top-0 z-10 flex cursor-default flex-col\" style=\"",
|
|
1135
|
+
"\"><div class=\"cursor-default rounded-full bg-[#e38b29] shadow-md\" style=\"",
|
|
1136
|
+
"\"></div></div><div id=\"outputs\" class=\"pointer-events-none absolute top-0 z-10 flex flex-col\" style=\"",
|
|
1005
1137
|
"\"><div class=\"cursor-crosshair rounded-full bg-[#e38b29] shadow-md\" style=\"",
|
|
1006
1138
|
"\"></div></div></div>"
|
|
1007
1139
|
];
|
|
1140
|
+
var _tmpl$3$2 = [
|
|
1141
|
+
"<div",
|
|
1142
|
+
" class=\"p-3 select-none\"><!--$-->",
|
|
1143
|
+
"<!--/--><!--$-->",
|
|
1144
|
+
"<!--/--><!--$-->",
|
|
1145
|
+
"<!--/--></div>"
|
|
1146
|
+
];
|
|
1008
1147
|
var _tmpl$4 = [
|
|
1009
1148
|
"<span",
|
|
1010
|
-
" class=\"min-w-max border-b border-[#f0f0f0]
|
|
1149
|
+
" class=\"mb-2 block min-w-max border-b border-[#f0f0f0] pb-2 font-semibold whitespace-nowrap text-red-600 select-none\">",
|
|
1011
1150
|
"</span>"
|
|
1012
1151
|
];
|
|
1013
1152
|
var _tmpl$5 = [
|
|
1014
1153
|
"<div",
|
|
1015
|
-
" class=\"
|
|
1154
|
+
" class=\"select-none\">",
|
|
1016
1155
|
"</div>"
|
|
1017
1156
|
];
|
|
1157
|
+
var _tmpl$6 = [
|
|
1158
|
+
"<div",
|
|
1159
|
+
"><span class=\"font-semibold\"><!--$-->",
|
|
1160
|
+
"<!--/-->: </span><span>",
|
|
1161
|
+
"</span></div>"
|
|
1162
|
+
];
|
|
1018
1163
|
/**
|
|
1019
1164
|
* Interactive flowchart node component supporting dragging, selection, handle
|
|
1020
1165
|
* connections, and child/sibling creation.
|
|
1021
1166
|
*
|
|
1022
|
-
* @
|
|
1167
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
1168
|
+
* {@linkcode NodeData}.
|
|
1169
|
+
*
|
|
1170
|
+
* @param props - Node rendering properties of type {@linkcode NodeComponentProps}.
|
|
1023
1171
|
*
|
|
1024
1172
|
* @returns The rendered Solid component.
|
|
1025
1173
|
*
|
|
@@ -1031,13 +1179,11 @@ var NodeComponent = (props) => {
|
|
|
1031
1179
|
createDraggable(props.id);
|
|
1032
1180
|
const node = createState(service, {
|
|
1033
1181
|
selector: ({ context }) => {
|
|
1034
|
-
const item = toArray.typed(context.data?.nodes).find((n) => n.id === props.id);
|
|
1182
|
+
const item = toArray$1.typed(context.data?.nodes).find((n) => n.id === props.id);
|
|
1035
1183
|
return {
|
|
1036
|
-
x: item
|
|
1037
|
-
y: item
|
|
1038
|
-
|
|
1039
|
-
content: item.data.content ?? "",
|
|
1040
|
-
input: item.input
|
|
1184
|
+
x: item?.position.x ?? 0,
|
|
1185
|
+
y: item?.position.y ?? 0,
|
|
1186
|
+
data: item?.data ?? {}
|
|
1041
1187
|
};
|
|
1042
1188
|
},
|
|
1043
1189
|
equals: dequal
|
|
@@ -1048,39 +1194,115 @@ var NodeComponent = (props) => {
|
|
|
1048
1194
|
if (!edges) return false;
|
|
1049
1195
|
return edges.some(({ to }) => to === props.id);
|
|
1050
1196
|
} });
|
|
1051
|
-
return ssr(_tmpl$
|
|
1197
|
+
return ssr(_tmpl$2$4, ssrHydrationKey(), `flex flex-col absolute cursor-grab bg-white rounded-md shadow-md select-none transition-[border,box-shadow] duration-200 ease-in-out hover:shadow-lg draggable ${selected() ? "border border-[#e38c29] z-100" : ""} ${!selected() ? "border border-[#e6d4be] z-1" : ""} min-w-48`, ssrStyleProperty("top:", `${escape(node().y, true)}px`) + ssrStyleProperty(";left:", `${escape(node().x, true)}px`), ssrAttribute("id", escape(props.id, true), false), `pointer-events-none absolute flex items-center justify-end -top-7.5 right-0 transition-all duration-200 ease-in-out space-x-2 ${selected() ? "w-full opacity-100" : ""} ${!selected() ? "w-0 -right-3 opacity-0 overflow-hidden" : ""}`, ssrStyleProperty("overflow:", "visible") + ssrStyleProperty(";pointer-events:", "all") + ssrStyleProperty(";width:", `${escape(12, true) * 2}px`) + ssrStyleProperty(";height:", `${escape(12, true) * 2}px`), escape(createComponent(Show, {
|
|
1052
1198
|
get when() {
|
|
1053
1199
|
return hasParent();
|
|
1054
1200
|
},
|
|
1055
1201
|
get children() {
|
|
1056
|
-
return ssr(_tmpl$$
|
|
1202
|
+
return ssr(_tmpl$$8, ssrHydrationKey(), ssrStyleProperty("pointer-events:", "all") + ssrStyleProperty(";fill-rule:", "evenodd") + ssrStyleProperty(";clip-rule:", "evenodd") + ssrStyleProperty(";stroke-linejoin:", "round") + ssrStyleProperty(";stroke-miterlimit:", "2") + ssrStyleProperty(";width:", `${escape(12, true) * 2}px`) + ssrStyleProperty(";height:", `${escape(12, true) * 2}px`));
|
|
1057
1203
|
}
|
|
1058
1204
|
})), ssrStyleProperty("pointer-events:", "all") + ssrStyleProperty(";width:", `${escape(12, true) * 2}px`) + ssrStyleProperty(";height:", `${escape(12, true) * 2}px`), escape(createComponent(Show, {
|
|
1059
1205
|
get when() {
|
|
1060
|
-
return
|
|
1061
|
-
},
|
|
1062
|
-
keyed: true,
|
|
1063
|
-
children: (label) => ssr(_tmpl$4, ssrHydrationKey(), escape(label))
|
|
1064
|
-
})), escape(createComponent(Show, {
|
|
1065
|
-
get when() {
|
|
1066
|
-
return node().content;
|
|
1206
|
+
return props.children;
|
|
1067
1207
|
},
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1208
|
+
get fallback() {
|
|
1209
|
+
return ssr(_tmpl$3$2, ssrHydrationKey(), escape(createComponent(Show, {
|
|
1210
|
+
get when() {
|
|
1211
|
+
return node().data.label;
|
|
1212
|
+
},
|
|
1213
|
+
keyed: true,
|
|
1214
|
+
children: (label) => ssr(_tmpl$4, ssrHydrationKey(), escape(String(label)))
|
|
1215
|
+
})), escape(createComponent(Show, {
|
|
1216
|
+
get when() {
|
|
1217
|
+
return node().data.content;
|
|
1218
|
+
},
|
|
1219
|
+
keyed: true,
|
|
1220
|
+
children: (content) => ssr(_tmpl$5, ssrHydrationKey(), escape(String(content)))
|
|
1221
|
+
})), escape(createComponent(Show, {
|
|
1222
|
+
get when() {
|
|
1223
|
+
return memo(() => !!!node().data.label)() && !node().data.content;
|
|
1224
|
+
},
|
|
1225
|
+
get children() {
|
|
1226
|
+
return createComponent(For, {
|
|
1227
|
+
get each() {
|
|
1228
|
+
return Object.entries(node().data);
|
|
1229
|
+
},
|
|
1230
|
+
children: ([key, val]) => ssr(_tmpl$6, ssrHydrationKey(), escape(key), escape(String(val)))
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
})));
|
|
1073
1234
|
},
|
|
1074
1235
|
get children() {
|
|
1075
|
-
return
|
|
1236
|
+
return createComponent(Dynamic, mergeProps({ get component() {
|
|
1237
|
+
return props.children;
|
|
1238
|
+
} }, () => node().data));
|
|
1076
1239
|
}
|
|
1077
|
-
})), ssrStyleProperty("right:", `-${escape(18, true)}px`), ssrStyleProperty("width:", `${escape(12, true)}px`) + ssrStyleProperty(";height:", `${escape(12, true)}px`) + ssrStyleProperty(";margin-top:", `${escape(12, true)}px`) + ssrStyleProperty(";pointer-events:", "all"));
|
|
1240
|
+
})), ssrStyleProperty("left:", `-${escape(18, true)}px`), ssrStyleProperty("width:", `${escape(12, true)}px`) + ssrStyleProperty(";height:", `${escape(12, true)}px`) + ssrStyleProperty(";margin-top:", `${escape(12, true)}px`) + ssrStyleProperty(";pointer-events:", "all"), ssrStyleProperty("right:", `-${escape(18, true)}px`), ssrStyleProperty("width:", `${escape(12, true)}px`) + ssrStyleProperty(";height:", `${escape(12, true)}px`) + ssrStyleProperty(";margin-top:", `${escape(12, true)}px`) + ssrStyleProperty(";pointer-events:", "all"));
|
|
1241
|
+
};
|
|
1242
|
+
//#endregion
|
|
1243
|
+
//#region src/ui/components/Panels.tsx
|
|
1244
|
+
var _tmpl$$7 = [
|
|
1245
|
+
"<div",
|
|
1246
|
+
" class=\"absolute top-4 left-4 z-50\">",
|
|
1247
|
+
"</div>"
|
|
1248
|
+
];
|
|
1249
|
+
var _tmpl$2$3 = [
|
|
1250
|
+
"<div",
|
|
1251
|
+
" class=\"absolute top-4 right-4 z-50\">",
|
|
1252
|
+
"</div>"
|
|
1253
|
+
];
|
|
1254
|
+
var _tmpl$3$1 = [
|
|
1255
|
+
"<div",
|
|
1256
|
+
" class=\"absolute bottom-4 left-4 z-50\">",
|
|
1257
|
+
"</div>"
|
|
1258
|
+
];
|
|
1259
|
+
/**
|
|
1260
|
+
* Overlay container rendering custom panel slots positioned around the flowchart
|
|
1261
|
+
* canvas.
|
|
1262
|
+
*
|
|
1263
|
+
* @param props - Flow panels layout properties of type {@linkcode FlowPanels}.
|
|
1264
|
+
*
|
|
1265
|
+
* @returns Rendered overlay panels JSX elements.
|
|
1266
|
+
*/
|
|
1267
|
+
var Panels = (props) => {
|
|
1268
|
+
return [
|
|
1269
|
+
createComponent(Show, {
|
|
1270
|
+
get when() {
|
|
1271
|
+
return props.topLeft;
|
|
1272
|
+
},
|
|
1273
|
+
keyed: true,
|
|
1274
|
+
children: (Panel) => {
|
|
1275
|
+
const Component = typeof Panel === "function" ? createComponent(Panel, {}) : Panel;
|
|
1276
|
+
return ssr(_tmpl$$7, ssrHydrationKey(), escape(Component));
|
|
1277
|
+
}
|
|
1278
|
+
}),
|
|
1279
|
+
createComponent(Show, {
|
|
1280
|
+
get when() {
|
|
1281
|
+
return props.topRight;
|
|
1282
|
+
},
|
|
1283
|
+
keyed: true,
|
|
1284
|
+
children: (Panel) => {
|
|
1285
|
+
const Component = typeof Panel === "function" ? createComponent(Panel, {}) : Panel;
|
|
1286
|
+
return ssr(_tmpl$2$3, ssrHydrationKey(), escape(Component));
|
|
1287
|
+
}
|
|
1288
|
+
}),
|
|
1289
|
+
createComponent(Show, {
|
|
1290
|
+
get when() {
|
|
1291
|
+
return props.bottomLeft;
|
|
1292
|
+
},
|
|
1293
|
+
keyed: true,
|
|
1294
|
+
children: (Panel) => {
|
|
1295
|
+
const Component = typeof Panel === "function" ? createComponent(Panel, {}) : Panel;
|
|
1296
|
+
return ssr(_tmpl$3$1, ssrHydrationKey(), escape(Component));
|
|
1297
|
+
}
|
|
1298
|
+
})
|
|
1299
|
+
];
|
|
1078
1300
|
};
|
|
1079
1301
|
//#endregion
|
|
1080
1302
|
//#region src/ui/components/NodesBoard.tsx
|
|
1081
|
-
var _tmpl$$
|
|
1303
|
+
var _tmpl$$6 = [
|
|
1082
1304
|
"<div",
|
|
1083
|
-
" class=\"relative h-full w-full overflow-auto
|
|
1305
|
+
" class=\"relative h-full w-full overflow-auto\"><!--$-->",
|
|
1084
1306
|
"<!--/--><div class=\"",
|
|
1085
1307
|
"\" style=\"",
|
|
1086
1308
|
"\"><div class=\"relative h-full w-full\" style=\"",
|
|
@@ -1089,25 +1311,30 @@ var _tmpl$$1 = [
|
|
|
1089
1311
|
"<!--/--><!--$-->",
|
|
1090
1312
|
"<!--/--></div></div></div>"
|
|
1091
1313
|
];
|
|
1092
|
-
var _tmpl$2 = [
|
|
1314
|
+
var _tmpl$2$2 = [
|
|
1093
1315
|
"<div",
|
|
1094
1316
|
" class=\"absolute right-4 bottom-4 z-50 flex items-center gap-2 rounded-xl border border-gray-200 bg-white/90 p-2 shadow-lg backdrop-blur-md\"><button type=\"button\" class=\"flex size-9 cursor-pointer items-center justify-center rounded-lg bg-gray-100 text-lg font-bold text-gray-700 shadow-sm transition-all duration-150 hover:bg-gray-200 active:scale-95\" title=\"Zoom out\" aria-label=\"Zoom out\">-</button><button type=\"button\" class=\"h-9 cursor-pointer rounded-lg px-2 text-xs font-semibold text-gray-700 transition-colors hover:bg-gray-100\" title=\"Reset zoom\" aria-label=\"Reset zoom\"><!--$-->",
|
|
1095
1317
|
"<!--/-->%</button><button type=\"button\" class=\"flex size-9 cursor-pointer items-center justify-center rounded-lg bg-gray-100 text-lg font-bold text-gray-700 shadow-sm transition-all duration-150 hover:bg-gray-200 active:scale-95\" title=\"Zoom in\" aria-label=\"Zoom in\">+</button><div class=\"h-5 w-px bg-gray-300\"></div><button type=\"button\" class=\"flex size-9 cursor-pointer items-center justify-center rounded-lg bg-blue-600 text-white shadow transition-all duration-150 hover:bg-blue-700 active:scale-95\" title=\"Add parent node\" aria-label=\"Add parent node\"><svg class=\"size-5\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"></path></svg></button></div>"
|
|
1096
1318
|
];
|
|
1097
1319
|
var _tmpl$3 = [
|
|
1098
1320
|
"<div",
|
|
1099
|
-
" class=\"relative mx-auto h-
|
|
1321
|
+
" class=\"relative mx-auto h-full w-full overflow-hidden\">",
|
|
1100
1322
|
"</div>"
|
|
1101
1323
|
];
|
|
1102
1324
|
/**
|
|
1103
1325
|
* Interactive board component containing the drag-drop viewport, zoom controls,
|
|
1104
1326
|
* panning gestures, and rendered nodes/edges.
|
|
1105
1327
|
*
|
|
1328
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
1329
|
+
* {@linkcode NodeData}.
|
|
1330
|
+
*
|
|
1331
|
+
* @param props - Board component properties of type {@linkcode Props}.
|
|
1332
|
+
*
|
|
1106
1333
|
* @returns The rendered Solid component.
|
|
1107
1334
|
*
|
|
1108
1335
|
* @see {@linkcode DragBounds}, {@linkcode EdgesBoard}, {@linkcode NodeComponent}, {@linkcode useFlow}, {@linkcode CANVAS_FACTOR}, {@linkcode SCROLL_MULTIPLIER}
|
|
1109
1336
|
*/
|
|
1110
|
-
var NodesBoard = () => {
|
|
1337
|
+
var NodesBoard = (props) => {
|
|
1111
1338
|
let containerRef;
|
|
1112
1339
|
const [isPanning, setIsPanning] = createSignal(false);
|
|
1113
1340
|
const [transform, setTransform] = createSignal({
|
|
@@ -1161,7 +1388,7 @@ var NodesBoard = () => {
|
|
|
1161
1388
|
const selectedId = createState(service, { selector: (s) => s.context?.selected });
|
|
1162
1389
|
const nodeIds = createState(service, {
|
|
1163
1390
|
selector: ({ context }) => {
|
|
1164
|
-
return toArray.typed(context.data?.nodes).map((item) => item.id);
|
|
1391
|
+
return toArray$1.typed(context.data?.nodes).map((item) => item.id);
|
|
1165
1392
|
},
|
|
1166
1393
|
equals: (prev, next) => prev.length === next.length
|
|
1167
1394
|
});
|
|
@@ -1231,13 +1458,19 @@ var NodesBoard = () => {
|
|
|
1231
1458
|
},
|
|
1232
1459
|
get children() {
|
|
1233
1460
|
return [
|
|
1234
|
-
ssr(_tmpl$$
|
|
1461
|
+
ssr(_tmpl$$6, ssrHydrationKey(), escape(createComponent(DragDropSensors, {})), `relative cursor-crosshair overflow-hidden ${isPanning() ? "cursor-grabbing" : ""}`, ssrStyleProperty("height:", escape(cHeight(), true)) + ssrStyleProperty(";width:", escape(cWidth(), true)), ssrStyleProperty("scale:", escape(zoom(), true)) + ssrStyleProperty(";transform-origin:", "top left"), escape(createComponent(DragBounds, {})), escape(createComponent(EdgesBoard, {})), escape(createComponent(For, {
|
|
1235
1462
|
get each() {
|
|
1236
1463
|
return nodeIds();
|
|
1237
1464
|
},
|
|
1238
|
-
children: (id) => createComponent(NodeComponent, {
|
|
1465
|
+
children: (id) => createComponent(NodeComponent, {
|
|
1466
|
+
id,
|
|
1467
|
+
get children() {
|
|
1468
|
+
return props.component;
|
|
1469
|
+
}
|
|
1470
|
+
})
|
|
1239
1471
|
}))),
|
|
1240
|
-
|
|
1472
|
+
createComponent(Panels, mergeProps(() => props.panels)),
|
|
1473
|
+
ssr(_tmpl$2$2, ssrHydrationKey(), escape(Math.round(zoom() * 100))),
|
|
1241
1474
|
createComponent(Show, {
|
|
1242
1475
|
get when() {
|
|
1243
1476
|
return !selectedId();
|
|
@@ -1252,9 +1485,9 @@ var NodesBoard = () => {
|
|
|
1252
1485
|
};
|
|
1253
1486
|
//#endregion
|
|
1254
1487
|
//#region src/ui/components/FlowChart.tsx
|
|
1255
|
-
var _tmpl
|
|
1488
|
+
var _tmpl$$5 = [
|
|
1256
1489
|
"<div",
|
|
1257
|
-
" class=\"relative h-full w-full\"><div class=\"
|
|
1490
|
+
" class=\"relative h-full w-full\"><div class=\"h-full w-full\" style=\"",
|
|
1258
1491
|
"\">",
|
|
1259
1492
|
"</div></div>"
|
|
1260
1493
|
];
|
|
@@ -1262,6 +1495,9 @@ var _tmpl$ = [
|
|
|
1262
1495
|
* Flowchart board canvas component that renders interactive nodes, edges, pan/zoom,
|
|
1263
1496
|
* and toolbar controls.
|
|
1264
1497
|
*
|
|
1498
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
1499
|
+
* {@linkcode NodeData}.
|
|
1500
|
+
*
|
|
1265
1501
|
* @param props - Flowchart configuration and event handlers of type
|
|
1266
1502
|
* {@linkcode FlowProps}.
|
|
1267
1503
|
*
|
|
@@ -1281,27 +1517,496 @@ var FlowChart = (props) => {
|
|
|
1281
1517
|
type: "CONFIGURE",
|
|
1282
1518
|
payload: {
|
|
1283
1519
|
nodes: primaryNodes,
|
|
1284
|
-
edges: primaryEdges ?? []
|
|
1520
|
+
edges: primaryEdges ?? [],
|
|
1521
|
+
defaultData: props.defaultData
|
|
1285
1522
|
}
|
|
1286
1523
|
});
|
|
1287
1524
|
});
|
|
1288
|
-
return ssr(_tmpl
|
|
1525
|
+
return ssr(_tmpl$$5, ssrHydrationKey(), ssrStyleProperty("cursor:", hasNewEdge() ? "inherit" : "crosshair"), escape(createComponent(NodesBoard, {
|
|
1526
|
+
get panels() {
|
|
1527
|
+
return props.panels;
|
|
1528
|
+
},
|
|
1529
|
+
get component() {
|
|
1530
|
+
return props.component;
|
|
1531
|
+
}
|
|
1532
|
+
})));
|
|
1533
|
+
};
|
|
1534
|
+
//#endregion
|
|
1535
|
+
//#region src/ui/utils.ts
|
|
1536
|
+
/**
|
|
1537
|
+
* Merges conditional CSS class names using `clsx` and resolves Tailwind CSS class
|
|
1538
|
+
* conflicts with `twMerge`.
|
|
1539
|
+
*
|
|
1540
|
+
* @param inputs - Variable list of class values, objects, or arrays.
|
|
1541
|
+
*
|
|
1542
|
+
* @returns The resolved single class name string.
|
|
1543
|
+
*/
|
|
1544
|
+
function cn(...inputs) {
|
|
1545
|
+
return twMerge(clsx(inputs));
|
|
1546
|
+
}
|
|
1547
|
+
//#endregion
|
|
1548
|
+
//#region src/ui/globals/helpers/espace.ts
|
|
1549
|
+
/**
|
|
1550
|
+
* Returns a zero-width space if string is empty, preserving layout flow.
|
|
1551
|
+
*
|
|
1552
|
+
* @param newText - The input text string.
|
|
1553
|
+
*
|
|
1554
|
+
* @returns The input text or zero-width visible space placeholder.
|
|
1555
|
+
*/
|
|
1556
|
+
var espace = (newText) => {
|
|
1557
|
+
if (newText === "") return "";
|
|
1558
|
+
return newText;
|
|
1559
|
+
};
|
|
1560
|
+
//#endregion
|
|
1561
|
+
//#region src/ui/globals/signals/createTyping.ts
|
|
1562
|
+
/**
|
|
1563
|
+
* Creates a reactive typewriter effect signal with oscillatory typing delay and
|
|
1564
|
+
* optional rewind.
|
|
1565
|
+
*
|
|
1566
|
+
* @param props - Configuration properties of type {@linkcode Props}.
|
|
1567
|
+
*
|
|
1568
|
+
* @returns An object containing the current text signal, type trigger, and text
|
|
1569
|
+
* setter.
|
|
1570
|
+
*/
|
|
1571
|
+
var createTyping = ({ content, min, ...props }) => {
|
|
1572
|
+
const rewind = props.rewind ?? false;
|
|
1573
|
+
const rewindDelay = props.rewindDelay ?? 500;
|
|
1574
|
+
const OSCILLATION = Math.min(min / 10 + content.length / 10, 10);
|
|
1575
|
+
const [text, setText] = createSignal("");
|
|
1576
|
+
let timeoutId;
|
|
1577
|
+
let index = 0;
|
|
1578
|
+
let isTyping = true;
|
|
1579
|
+
const max = min + OSCILLATION;
|
|
1580
|
+
let interval = min;
|
|
1581
|
+
let intervalDirection = 1;
|
|
1582
|
+
const type = () => {
|
|
1583
|
+
if (isTyping) {
|
|
1584
|
+
if (index < content.length) {
|
|
1585
|
+
setText((prev) => prev + content[index]);
|
|
1586
|
+
index++;
|
|
1587
|
+
timeoutId = setTimeout(type, interval);
|
|
1588
|
+
} else if (rewind) {
|
|
1589
|
+
isTyping = false;
|
|
1590
|
+
intervalDirection = 1;
|
|
1591
|
+
timeoutId = setTimeout(type, rewindDelay);
|
|
1592
|
+
}
|
|
1593
|
+
} else if (index > 0) {
|
|
1594
|
+
index--;
|
|
1595
|
+
setText(espace(content.substring(0, index)));
|
|
1596
|
+
timeoutId = setTimeout(type, interval);
|
|
1597
|
+
} else {
|
|
1598
|
+
isTyping = true;
|
|
1599
|
+
intervalDirection = 1;
|
|
1600
|
+
timeoutId = setTimeout(type, rewindDelay);
|
|
1601
|
+
}
|
|
1602
|
+
interval += intervalDirection;
|
|
1603
|
+
if (interval >= max) intervalDirection = -1;
|
|
1604
|
+
else if (interval <= min) intervalDirection = 1;
|
|
1605
|
+
};
|
|
1606
|
+
onCleanup(() => {
|
|
1607
|
+
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
1608
|
+
});
|
|
1609
|
+
return {
|
|
1610
|
+
text,
|
|
1611
|
+
type,
|
|
1612
|
+
setText
|
|
1613
|
+
};
|
|
1614
|
+
};
|
|
1615
|
+
//#endregion
|
|
1616
|
+
//#region src/ui/globals/components/atoms/TypingText.tsx
|
|
1617
|
+
var _tmpl$$4 = [
|
|
1618
|
+
"<div",
|
|
1619
|
+
">",
|
|
1620
|
+
"</div>"
|
|
1621
|
+
];
|
|
1622
|
+
/**
|
|
1623
|
+
* Renders animated text with a typewriter keystroke animation effect.
|
|
1624
|
+
*
|
|
1625
|
+
* @param props - Component configuration properties of type {@linkcode Props}.
|
|
1626
|
+
*
|
|
1627
|
+
* @returns Rendered animated typing text JSX container.
|
|
1628
|
+
*/
|
|
1629
|
+
var TypingText = (props) => {
|
|
1630
|
+
const min = props.interval ?? 62;
|
|
1631
|
+
const rewind = props.rewind ?? false;
|
|
1632
|
+
const rewindDelay = props.rewindDelay ?? 500;
|
|
1633
|
+
const content = props.children;
|
|
1634
|
+
const disabled = createMemo(() => props.disabled ? props.disabled() : false, false);
|
|
1635
|
+
const { text, type, setText } = createTyping({
|
|
1636
|
+
content,
|
|
1637
|
+
min,
|
|
1638
|
+
rewind,
|
|
1639
|
+
rewindDelay
|
|
1640
|
+
});
|
|
1641
|
+
createEffect(on(disabled, () => setText("")));
|
|
1642
|
+
createEffect(() => {
|
|
1643
|
+
if (disabled()) setText(content);
|
|
1644
|
+
else type();
|
|
1645
|
+
});
|
|
1646
|
+
return ssr(_tmpl$$4, ssrHydrationKey() + ssrAttribute("class", escape(props.class, true), false), escape(text()));
|
|
1647
|
+
};
|
|
1648
|
+
//#endregion
|
|
1649
|
+
//#region src/ui/globals/components/molecules/FadingDots.tsx
|
|
1650
|
+
var _tmpl$$3 = [
|
|
1651
|
+
"<div",
|
|
1652
|
+
" class=\"mt-4 flex items-center justify-center space-x-4\">",
|
|
1653
|
+
"</div>"
|
|
1654
|
+
];
|
|
1655
|
+
/**
|
|
1656
|
+
* Loading animation component displaying animated pulsing dots.
|
|
1657
|
+
*
|
|
1658
|
+
* @param props - Fading dots configuration properties.
|
|
1659
|
+
* @param props.count - The number of dots to display.
|
|
1660
|
+
* @param props.duration - Animation duration in milliseconds. Defaults to 500.
|
|
1661
|
+
* @param props.innerProps - Additional properties and CSS styles applied to dot
|
|
1662
|
+
* elements.
|
|
1663
|
+
*
|
|
1664
|
+
* @returns Rendered animated dots container JSX element.
|
|
1665
|
+
*/
|
|
1666
|
+
var FadingDots = ({ count: length, innerProps = {}, duration = 500 }) => {
|
|
1667
|
+
const [local, rest] = splitProps(innerProps, ["class", "style"]);
|
|
1668
|
+
return ssr(_tmpl$$3, ssrHydrationKey(), escape(Array.from({ length }, (_, i) => ssrElement("span", mergeProps({
|
|
1669
|
+
get ["class"]() {
|
|
1670
|
+
return cn("rounded-full animate-out direction-alternate repeat-infinite fade-out-5 size-4 bg-gray-600", local.class);
|
|
1671
|
+
},
|
|
1672
|
+
get style() {
|
|
1673
|
+
return {
|
|
1674
|
+
...local.style,
|
|
1675
|
+
"animation-duration": `${duration}ms`,
|
|
1676
|
+
"animation-delay": `${duration / i}ms`
|
|
1677
|
+
};
|
|
1678
|
+
},
|
|
1679
|
+
"aria-hidden": "true"
|
|
1680
|
+
}, rest), void 0, true))));
|
|
1681
|
+
};
|
|
1682
|
+
//#endregion
|
|
1683
|
+
//#region src/ui/globals/components/organisms/LoadingFallback.tsx
|
|
1684
|
+
var _tmpl$$2 = [
|
|
1685
|
+
"<div",
|
|
1686
|
+
" role=\"status\" aria-live=\"polite\" aria-label=\"Chargement en cours\"><div class=\"relative\"><div",
|
|
1687
|
+
" aria-hidden=\"true\"></div><div",
|
|
1688
|
+
" aria-hidden=\"true\"></div></div><div class=\"text-center\"",
|
|
1689
|
+
"><!--$-->",
|
|
1690
|
+
"<!--/--><!--$-->",
|
|
1691
|
+
"<!--/--></div></div>"
|
|
1692
|
+
];
|
|
1693
|
+
/**
|
|
1694
|
+
* Fallback loading screen component displaying an animated spinner and typewriter
|
|
1695
|
+
* text.
|
|
1696
|
+
*
|
|
1697
|
+
* @example
|
|
1698
|
+
* ```tsx
|
|
1699
|
+
* <Show when={data()} fallback={<LoadingFallback />}>
|
|
1700
|
+
* <DataComponent data={data()!} />
|
|
1701
|
+
* </Show>;
|
|
1702
|
+
* ```;
|
|
1703
|
+
*
|
|
1704
|
+
* @param props - Loading fallback properties of type
|
|
1705
|
+
* {@linkcode LoadingFallbackProps}.
|
|
1706
|
+
*
|
|
1707
|
+
* @returns Rendered full-screen loading fallback JSX element.
|
|
1708
|
+
*/
|
|
1709
|
+
var LoadingFallback = (props) => {
|
|
1710
|
+
const message = props.message ?? "Chargement en cours...";
|
|
1711
|
+
const spinnerSizes = {
|
|
1712
|
+
sm: "w-8 h-8",
|
|
1713
|
+
md: "w-12 h-12",
|
|
1714
|
+
lg: "w-16 h-16",
|
|
1715
|
+
xl: "w-24 h-24"
|
|
1716
|
+
};
|
|
1717
|
+
const size = props.size ?? "lg";
|
|
1718
|
+
return ssr(_tmpl$$2, ssrHydrationKey() + ssrAttribute("class", escape(cn("flex flex-col items-center justify-center gap-6", "h-screen w-screen overflow-hidden p-4", props.class), true), false), ssrAttribute("class", escape(cn(spinnerSizes[size], "rounded-full border-4 border-[#4B9CAD]/20", "animate-spin", "border-t-[#4B9CAD]"), true), false), ssrAttribute("class", escape(cn("absolute inset-2", "rounded-full border-4 border-transparent", "border-b-[#4B9CAD]/40", "animate-spin", "animation-duration-[1.5s]", "direction-[reverse]"), true), false), ssrAttribute("aria-label", escape(message, true), false), escape(createComponent(TypingText, {
|
|
1719
|
+
"class": "text-lg font-medium text-gray-700 md:text-xl dark:text-gray-300",
|
|
1720
|
+
get interval() {
|
|
1721
|
+
return props.interval ?? 80;
|
|
1722
|
+
},
|
|
1723
|
+
get rewind() {
|
|
1724
|
+
return props.rewind ?? true;
|
|
1725
|
+
},
|
|
1726
|
+
get rewindDelay() {
|
|
1727
|
+
return props.rewindDelay ?? 2e3;
|
|
1728
|
+
},
|
|
1729
|
+
children: message
|
|
1730
|
+
})), escape(createComponent(FadingDots, {
|
|
1731
|
+
count: 5,
|
|
1732
|
+
innerProps: { class: "bg-[#3d8091]" }
|
|
1733
|
+
})));
|
|
1289
1734
|
};
|
|
1290
1735
|
//#endregion
|
|
1291
1736
|
//#region src/ui/Flow.tsx
|
|
1737
|
+
var _tmpl$$1 = [
|
|
1738
|
+
"<div",
|
|
1739
|
+
" style=\"",
|
|
1740
|
+
"\" class=\"relative flex h-full w-full rounded-lg border-2 border-gray-600 bg-white bg-size-[30px_30px]\">",
|
|
1741
|
+
"</div>"
|
|
1742
|
+
];
|
|
1743
|
+
var _tmpl$2$1 = [
|
|
1744
|
+
"<div",
|
|
1745
|
+
" class=\"relative flex flex-1 items-center justify-center\">",
|
|
1746
|
+
"</div>"
|
|
1747
|
+
];
|
|
1292
1748
|
/**
|
|
1293
1749
|
* Root Flow component wrapping the {@linkcode FlowChart} inside the flow context
|
|
1294
1750
|
* provider.
|
|
1295
1751
|
*
|
|
1752
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
1753
|
+
* {@linkcode NodeData}.
|
|
1754
|
+
*
|
|
1296
1755
|
* @param props - Flow chart configuration and callbacks of type
|
|
1297
1756
|
* {@linkcode FlowProps}.
|
|
1298
1757
|
*
|
|
1299
1758
|
* @returns The rendered Solid component.
|
|
1300
1759
|
*
|
|
1301
|
-
* @see {@linkcode Provider}
|
|
1760
|
+
* @see {@linkcode Provider}, {@linkcode FlowChart}
|
|
1302
1761
|
*/
|
|
1303
|
-
var Flow = (props) =>
|
|
1304
|
-
|
|
1305
|
-
|
|
1762
|
+
var Flow = (props) => {
|
|
1763
|
+
const [isMounted, setIsMounted] = createSignal(false);
|
|
1764
|
+
onMount(() => setTimeout(() => setIsMounted(true), props.delay));
|
|
1765
|
+
return ssr(_tmpl$$1, ssrHydrationKey(), ssrStyleProperty("background-image:", "radial-gradient(circle, #b8b8b8bf 1px, rgba(0, 0, 0, 0) 1px)"), escape(createComponent(Show, {
|
|
1766
|
+
get when() {
|
|
1767
|
+
return isMounted();
|
|
1768
|
+
},
|
|
1769
|
+
keyed: true,
|
|
1770
|
+
get fallback() {
|
|
1771
|
+
return ssr(_tmpl$2$1, ssrHydrationKey(), escape(createComponent(LoadingFallback, {
|
|
1772
|
+
message: "Chart is loading...",
|
|
1773
|
+
interval: 35,
|
|
1774
|
+
rewind: true,
|
|
1775
|
+
rewindDelay: 1e3
|
|
1776
|
+
})));
|
|
1777
|
+
},
|
|
1778
|
+
get children() {
|
|
1779
|
+
return createComponent(Provider, { get children() {
|
|
1780
|
+
return createComponent(FlowChart, props);
|
|
1781
|
+
} });
|
|
1782
|
+
}
|
|
1783
|
+
})));
|
|
1784
|
+
};
|
|
1785
|
+
//#endregion
|
|
1786
|
+
//#region src/ui/globals/directives/clickOutside.ts
|
|
1787
|
+
/**
|
|
1788
|
+
* Solid custom directive that triggers a callback when a click occurs outside the
|
|
1789
|
+
* bound element.
|
|
1790
|
+
*
|
|
1791
|
+
* @param el - The bound DOM element.
|
|
1792
|
+
* @param accessor - Accessor returning the callback function to execute.
|
|
1793
|
+
*/
|
|
1794
|
+
var clickOutside = (el, accessor) => {
|
|
1795
|
+
const onClick = (e) => {
|
|
1796
|
+
if (!el.contains(e.target)) accessor()?.();
|
|
1797
|
+
};
|
|
1798
|
+
document.body.addEventListener("click", onClick);
|
|
1799
|
+
onCleanup(() => document.body.removeEventListener("click", onClick));
|
|
1800
|
+
};
|
|
1801
|
+
//#endregion
|
|
1802
|
+
//#region src/ui/globals/directives/mouseOut.ts
|
|
1803
|
+
/**
|
|
1804
|
+
* Solid custom directive that triggers a callback when the mouse leaves the bound
|
|
1805
|
+
* element after a specified timer duration. If the user re-enters the component
|
|
1806
|
+
* before the timer expires, the timer is reset/cancelled.
|
|
1807
|
+
*
|
|
1808
|
+
* @param el - The bound DOM element.
|
|
1809
|
+
* @param accessor - Accessor returning a callback, tuple `[callback, delay]`, or
|
|
1810
|
+
* type {@linkcode MouseOutOptions}.
|
|
1811
|
+
*/
|
|
1812
|
+
var mouseOut = (el, accessor) => {
|
|
1813
|
+
let timer;
|
|
1814
|
+
const clear = () => {
|
|
1815
|
+
if (timer !== void 0) {
|
|
1816
|
+
clearTimeout(timer);
|
|
1817
|
+
timer = void 0;
|
|
1818
|
+
}
|
|
1819
|
+
};
|
|
1820
|
+
const onMouseEnter = () => {
|
|
1821
|
+
clear();
|
|
1822
|
+
};
|
|
1823
|
+
const onMouseLeave = (event) => {
|
|
1824
|
+
clear();
|
|
1825
|
+
const param = accessor();
|
|
1826
|
+
if (!param) return;
|
|
1827
|
+
let callback;
|
|
1828
|
+
let delay = 0;
|
|
1829
|
+
if (typeof param === "function") callback = param;
|
|
1830
|
+
else if (Array.isArray(param)) {
|
|
1831
|
+
callback = param[0];
|
|
1832
|
+
delay = param[1] ?? 0;
|
|
1833
|
+
} else if (typeof param === "object") {
|
|
1834
|
+
callback = param.callback ?? param.onMouseOut;
|
|
1835
|
+
delay = param.delay ?? 0;
|
|
1836
|
+
}
|
|
1837
|
+
if (!callback) return;
|
|
1838
|
+
if (delay > 0) timer = setTimeout(() => {
|
|
1839
|
+
callback?.(event);
|
|
1840
|
+
timer = void 0;
|
|
1841
|
+
}, delay);
|
|
1842
|
+
else callback(event);
|
|
1843
|
+
};
|
|
1844
|
+
el.addEventListener("mouseleave", onMouseLeave);
|
|
1845
|
+
el.addEventListener("mouseenter", onMouseEnter);
|
|
1846
|
+
onCleanup(() => {
|
|
1847
|
+
clear();
|
|
1848
|
+
el.removeEventListener("mouseleave", onMouseLeave);
|
|
1849
|
+
el.removeEventListener("mouseenter", onMouseEnter);
|
|
1850
|
+
});
|
|
1851
|
+
};
|
|
1852
|
+
//#endregion
|
|
1853
|
+
//#region src/ui/globals/directives/resize.ts
|
|
1854
|
+
/**
|
|
1855
|
+
* Creates a ResizeObserver hook attached to the node content container element,
|
|
1856
|
+
* dispatching RESIZE events to update node dimensions and edge positioning in
|
|
1857
|
+
* real-time.
|
|
1858
|
+
*
|
|
1859
|
+
* @param id - Unique identifier of the flowchart node.
|
|
1860
|
+
*
|
|
1861
|
+
* @returns Ref callback attaching and cleaning up the observer on unmount.
|
|
1862
|
+
*/
|
|
1863
|
+
var resize = (id) => (el) => {
|
|
1864
|
+
const service = useFlow();
|
|
1865
|
+
const resize = new ResizeObserver((entries) => {
|
|
1866
|
+
const entry = entries[0].target;
|
|
1867
|
+
if (!entry) return;
|
|
1868
|
+
const width = entry.clientWidth;
|
|
1869
|
+
const height = entry.clientHeight;
|
|
1870
|
+
if (width > 0 && height > 0) service.send({
|
|
1871
|
+
type: "RESIZE",
|
|
1872
|
+
payload: {
|
|
1873
|
+
id,
|
|
1874
|
+
size: {
|
|
1875
|
+
width,
|
|
1876
|
+
height
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
});
|
|
1881
|
+
resize.observe(el);
|
|
1882
|
+
return () => {
|
|
1883
|
+
resize.unobserve(el);
|
|
1884
|
+
resize.disconnect();
|
|
1885
|
+
};
|
|
1886
|
+
};
|
|
1887
|
+
//#endregion
|
|
1888
|
+
//#region src/ui/components/EditPanel.hooks.ts
|
|
1889
|
+
/**
|
|
1890
|
+
* Hook providing reactive state and mutation helpers for editing flowchart node
|
|
1891
|
+
* data.
|
|
1892
|
+
*
|
|
1893
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
1894
|
+
* {@linkcode NodeData}.
|
|
1895
|
+
*
|
|
1896
|
+
* @param timeout - Transition delay in milliseconds before closing the panel.
|
|
1897
|
+
* Defaults to `270`.
|
|
1898
|
+
*
|
|
1899
|
+
* @returns An object containing reactive accessors and mutation callbacks for the
|
|
1900
|
+
* active node.
|
|
1901
|
+
*
|
|
1902
|
+
* @see {@linkcode useFlow}
|
|
1903
|
+
*/
|
|
1904
|
+
var useHook = (timeout = 270) => {
|
|
1905
|
+
const service = useFlow();
|
|
1906
|
+
const directClose = () => service.send("STOP_EDIT");
|
|
1907
|
+
const [closing, setClosing] = createSignal(false);
|
|
1908
|
+
const senderData = service.sender("SET_NODE_DATA");
|
|
1909
|
+
const _editing = createState(service, {
|
|
1910
|
+
selector: ({ context }) => {
|
|
1911
|
+
const editingId = context.editing;
|
|
1912
|
+
if (!isDefined(editingId)) return;
|
|
1913
|
+
const item = context.data?.nodes?.find((n) => n.id === editingId);
|
|
1914
|
+
if (!isDefined(item)) return;
|
|
1915
|
+
return {
|
|
1916
|
+
id: item.id,
|
|
1917
|
+
data: item.data
|
|
1918
|
+
};
|
|
1919
|
+
},
|
|
1920
|
+
equals: deepEqual
|
|
1921
|
+
});
|
|
1922
|
+
const close = () => {
|
|
1923
|
+
setClosing(true);
|
|
1924
|
+
setTimeout(() => {
|
|
1925
|
+
directClose();
|
|
1926
|
+
setClosing(false);
|
|
1927
|
+
}, timeout);
|
|
1928
|
+
};
|
|
1929
|
+
const updateField = (field, value) => {
|
|
1930
|
+
const current = _editing();
|
|
1931
|
+
if (!current) return;
|
|
1932
|
+
return senderData({
|
|
1933
|
+
...current,
|
|
1934
|
+
data: {
|
|
1935
|
+
...current.data,
|
|
1936
|
+
[field]: value
|
|
1937
|
+
}
|
|
1938
|
+
});
|
|
1939
|
+
};
|
|
1940
|
+
const updateData = (data) => {
|
|
1941
|
+
const current = _editing();
|
|
1942
|
+
if (!current) return;
|
|
1943
|
+
return senderData({
|
|
1944
|
+
...current,
|
|
1945
|
+
data: {
|
|
1946
|
+
...current.data,
|
|
1947
|
+
...data
|
|
1948
|
+
}
|
|
1949
|
+
});
|
|
1950
|
+
};
|
|
1951
|
+
return {
|
|
1952
|
+
editing: _editing,
|
|
1953
|
+
updateField,
|
|
1954
|
+
updateData,
|
|
1955
|
+
close,
|
|
1956
|
+
closing,
|
|
1957
|
+
directClose
|
|
1958
|
+
};
|
|
1959
|
+
};
|
|
1960
|
+
//#endregion
|
|
1961
|
+
//#region src/ui/components/EditPanel.tsx
|
|
1962
|
+
var _tmpl$ = [
|
|
1963
|
+
"<div",
|
|
1964
|
+
" class=\"",
|
|
1965
|
+
"\" style=\"",
|
|
1966
|
+
"\"><div class=\"flex flex-col gap-3\"><!--$-->",
|
|
1967
|
+
"<!--/--><!--$-->",
|
|
1968
|
+
"<!--/--></div></div>"
|
|
1969
|
+
];
|
|
1970
|
+
var _tmpl$2 = [
|
|
1971
|
+
"<div",
|
|
1972
|
+
" class=\"flex items-center justify-between border-b border-gray-100 pb-2\"><div class=\"flex items-center gap-2\"><h3 class=\"text-sm font-bold text-gray-800\">Edit</h3><span class=\"font-mono text-[11px] text-gray-400\">",
|
|
1973
|
+
"</span></div><button type=\"button\" title=\"Close editor\" aria-label=\"Close editor\" class=\"cursor-pointer rounded-full p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-700\"><svg class=\"size-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 6L6 18M6 6l12 12\"></path></svg></button></div>"
|
|
1974
|
+
];
|
|
1975
|
+
/**
|
|
1976
|
+
* Generic overlay edit panel component for modifying the data of the currently
|
|
1977
|
+
* active/double-clicked flowchart node.
|
|
1978
|
+
*
|
|
1979
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
1980
|
+
* {@linkcode NodeData}.
|
|
1981
|
+
*
|
|
1982
|
+
* @param props - Edit panel configuration properties of type
|
|
1983
|
+
* {@linkcode EditPanelProps}.
|
|
1984
|
+
*
|
|
1985
|
+
* @returns The rendered Solid component or `null` when no node is being edited.
|
|
1986
|
+
*
|
|
1987
|
+
* @see {@linkcode useHook}, {@linkcode clickOutside}
|
|
1988
|
+
*/
|
|
1989
|
+
var EditPanel = (props) => {
|
|
1990
|
+
const hooks = useHook(props.timeout);
|
|
1991
|
+
const classList = () => props.classList instanceof Function ? props.classList(hooks) : props.classList;
|
|
1992
|
+
return createComponent(Show, {
|
|
1993
|
+
get when() {
|
|
1994
|
+
return hooks.editing();
|
|
1995
|
+
},
|
|
1996
|
+
children: (node) => ssr(_tmpl$, ssrHydrationKey(), `${escape(cn(`w-80 cursor-default rounded-2xl border border-gray-200 bg-white/95 p-4 shadow-xl backdrop-blur-md transition-all ${props.class ?? ""}`) || "", true)} ${escape(ssrClassList(classList()) || "", true)}`, ssrStyle(props.style), escape(createComponent(Show, {
|
|
1997
|
+
get when() {
|
|
1998
|
+
return props.header;
|
|
1999
|
+
},
|
|
2000
|
+
keyed: true,
|
|
2001
|
+
get fallback() {
|
|
2002
|
+
return ssr(_tmpl$2, ssrHydrationKey(), escape(node().id));
|
|
2003
|
+
},
|
|
2004
|
+
children: (header) => header({
|
|
2005
|
+
id: node().id,
|
|
2006
|
+
close: hooks.close
|
|
2007
|
+
})
|
|
2008
|
+
})), escape(props.children(hooks)))
|
|
2009
|
+
});
|
|
2010
|
+
};
|
|
1306
2011
|
//#endregion
|
|
1307
|
-
export { CLASSES, Flow };
|
|
2012
|
+
export { BOUNDS_CONSTRAINTS, CANVAS_FACTOR, CLASSES, CONTAINER_DIMENSIONS, DEFAULT_DATA, DEFAULT_INPUT_OFFSET, DEFAULT_INPUT_OFFSET_X, DEFAULT_INPUT_OFFSET_Y, DEFAULT_NODES, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, DEFAULT_SIZE, EditPanel, Flow, FlowChart, HANDLE_CENTER_X_OFFSET, HANDLE_CENTER_Y, HANDLE_CONTAINER_OFFSET_X, HANDLE_MARGIN_TOP, HANDLE_RADIUS, HANDLE_SIZE, NODE_BORDER_WIDTH, PARENT_CHILD_GAP_WIDTH, Panels, Provider, SCROLL_MULTIPLIER, TOOLBAR_BUFFER, TOOLBAR_TOP_OFFSET, board, clamp, clickOutside, createContext, data, dimension, edgeJSON, extremities, getDefaultOutputOffset, mouseOut, newEdge, nodeDataValue, nodeJSON, nodeOffset, point, resize, useFlow, vector };
|