@bemedev/mind-flow 0.3.2 → 1.1.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 +2464 -373
- package/lib/output.css +1 -1
- package/lib/server.cjs.js +1002 -262
- package/lib/server.es.js +968 -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 +31 -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
|
@@ -6,8 +6,11 @@ import { nanoid } from 'nanoid';
|
|
|
6
6
|
/** Type alias for drag-drop state extracted from {@linkcode useDragDropContext}. */
|
|
7
7
|
export type DragDropState = Exclude<ReturnType<typeof useDragDropContext>, null>[0];
|
|
8
8
|
|
|
9
|
+
import { clamp } from '..';
|
|
9
10
|
import {
|
|
11
|
+
DEFAULT_DATA,
|
|
10
12
|
DEFAULT_INPUT_OFFSET,
|
|
13
|
+
DEFAULT_SIZE,
|
|
11
14
|
getDefaultOutputOffset,
|
|
12
15
|
PARENT_CHILD_GAP_WIDTH,
|
|
13
16
|
} from './main.machine.data';
|
|
@@ -21,6 +24,7 @@ import {
|
|
|
21
24
|
edgeJSON,
|
|
22
25
|
extremities,
|
|
23
26
|
newEdge,
|
|
27
|
+
data,
|
|
24
28
|
nodeJSON,
|
|
25
29
|
point,
|
|
26
30
|
vector,
|
|
@@ -28,13 +32,14 @@ import {
|
|
|
28
32
|
type Dimension,
|
|
29
33
|
type Point,
|
|
30
34
|
type Board,
|
|
35
|
+
type Vector,
|
|
31
36
|
} from './main.machine.typings';
|
|
32
37
|
|
|
33
38
|
/**
|
|
34
39
|
* State machine managing flowchart state transitions, nodes, edges, selection, and
|
|
35
40
|
* layout actions.
|
|
36
41
|
*
|
|
37
|
-
* @see {@linkcode calculateDimensions}, {@linkcode buildEdgeId}, {@linkcode buildNodeID}, {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}
|
|
42
|
+
* @see {@linkcode calculateDimensions}, {@linkcode buildEdgeId}, {@linkcode buildNodeID}, {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode DEFAULT_SIZE}, {@linkcode DEFAULT_DATA}
|
|
38
43
|
*/
|
|
39
44
|
export const machine = createMachine(
|
|
40
45
|
{
|
|
@@ -44,7 +49,7 @@ export const machine = createMachine(
|
|
|
44
49
|
states: {
|
|
45
50
|
idle: {
|
|
46
51
|
on: {
|
|
47
|
-
CONFIGURE: { actions: ['configure'], target: '/
|
|
52
|
+
CONFIGURE: { actions: ['configure'], target: '/construction' },
|
|
48
53
|
CONFIGURE_EMPTY: '/working',
|
|
49
54
|
},
|
|
50
55
|
},
|
|
@@ -53,6 +58,7 @@ export const machine = createMachine(
|
|
|
53
58
|
|
|
54
59
|
working: {
|
|
55
60
|
on: {
|
|
61
|
+
CONFIGURE: { actions: ['configure'], target: '/construction' },
|
|
56
62
|
MOVE_IMMEDIATE: {
|
|
57
63
|
actions: [{ name: 'buildUI', description: 'Must be in the ui' }],
|
|
58
64
|
},
|
|
@@ -75,8 +81,6 @@ export const machine = createMachine(
|
|
|
75
81
|
target: '/construction',
|
|
76
82
|
},
|
|
77
83
|
|
|
78
|
-
ADD_DIMENSION: { actions: ['addDimension'] },
|
|
79
|
-
|
|
80
84
|
ADD_SIBLING: {
|
|
81
85
|
actions: [
|
|
82
86
|
'generateID',
|
|
@@ -86,6 +90,7 @@ export const machine = createMachine(
|
|
|
86
90
|
target: '/construction',
|
|
87
91
|
},
|
|
88
92
|
|
|
93
|
+
RESIZE: { actions: ['resize', 'buildUI'] },
|
|
89
94
|
MOVE: { actions: ['moveNode', 'buildUI'], target: '/construction' },
|
|
90
95
|
ADD_EDGE: { actions: ['addEdge'], target: '/construction' },
|
|
91
96
|
START_NEW_EDGE: { actions: ['startNewEdge'] },
|
|
@@ -97,15 +102,19 @@ export const machine = createMachine(
|
|
|
97
102
|
ZOOM: { actions: ['zoom'] },
|
|
98
103
|
TOGGLE_ZOOM: { actions: ['toggleZoom'] },
|
|
99
104
|
SET_BOARD: { actions: ['setBoard'] },
|
|
105
|
+
SET_NODE_DATA: { actions: ['setNodeData'] },
|
|
106
|
+
EDIT: { actions: ['edit'] },
|
|
107
|
+
STOP_EDIT: { actions: ['stopEdit'] },
|
|
100
108
|
},
|
|
101
109
|
},
|
|
102
110
|
},
|
|
103
111
|
},
|
|
104
112
|
{
|
|
105
|
-
eventsMap: type(({ intersection, use, array }) => ({
|
|
113
|
+
eventsMap: type(({ intersection, use, array, optional }) => ({
|
|
106
114
|
CONFIGURE: {
|
|
107
115
|
nodes: array(intersection(use(nodeJSON), { id: 'string' })),
|
|
108
116
|
edges: array(intersection(use(edgeJSON), { id: 'string' })),
|
|
117
|
+
defaultData: optional(use(data)),
|
|
109
118
|
},
|
|
110
119
|
|
|
111
120
|
SET_BOARD: use(board),
|
|
@@ -118,13 +127,16 @@ export const machine = createMachine(
|
|
|
118
127
|
DELETE: 'string',
|
|
119
128
|
SELECT: 'string',
|
|
120
129
|
DESELECT: 'never',
|
|
130
|
+
EDIT: 'string',
|
|
131
|
+
STOP_EDIT: 'never',
|
|
121
132
|
ADD_EDGE: use(extremities),
|
|
122
133
|
START_NEW_EDGE: 'string',
|
|
123
134
|
MOVE_NEW_EDGE: use(point),
|
|
124
135
|
CLEAR_NEW_EDGE: 'never',
|
|
125
136
|
ZOOM: 'number',
|
|
126
137
|
TOGGLE_ZOOM: 'never',
|
|
127
|
-
|
|
138
|
+
RESIZE: { id: 'string', size: { width: 'number', height: 'number' } },
|
|
139
|
+
SET_NODE_DATA: { id: 'string', data: use(data) },
|
|
128
140
|
})),
|
|
129
141
|
|
|
130
142
|
sync: true,
|
|
@@ -132,6 +144,7 @@ export const machine = createMachine(
|
|
|
132
144
|
generatedId: union('string', 'null'),
|
|
133
145
|
previousZoom: optional('number'),
|
|
134
146
|
dimensions: record(use(dimension)),
|
|
147
|
+
defaultData: optional(use(data)),
|
|
135
148
|
|
|
136
149
|
getBoardPosition:
|
|
137
150
|
custom<(clientX: number, clientY: number, board: Board) => Point>(),
|
|
@@ -176,6 +189,7 @@ export const machine = createMachine(
|
|
|
176
189
|
edgesPositions: record(use(vector)),
|
|
177
190
|
newEdge: optional(use(newEdge)),
|
|
178
191
|
selected: optional('string'),
|
|
192
|
+
editing: optional('string'),
|
|
179
193
|
updatingUI: optional('boolean'),
|
|
180
194
|
zoom: 'number',
|
|
181
195
|
bounds: use(point),
|
|
@@ -184,26 +198,45 @@ export const machine = createMachine(
|
|
|
184
198
|
).provideOptions(({ assign, batch, erase, filter, action }) => ({
|
|
185
199
|
actions: {
|
|
186
200
|
configure: batch(
|
|
187
|
-
assign('data', {
|
|
201
|
+
assign('data', {
|
|
202
|
+
CONFIGURE: ({ payload: { nodes, edges } }) => ({ nodes, edges }),
|
|
203
|
+
}),
|
|
188
204
|
assign('newEdge', () => undefined),
|
|
189
205
|
assign('updatingUI', () => false),
|
|
190
206
|
action(({ pContext }) => {
|
|
191
207
|
pContext.generatedId = null;
|
|
192
208
|
}),
|
|
193
209
|
action({
|
|
194
|
-
CONFIGURE: ({ payload: { nodes }, pContext
|
|
210
|
+
CONFIGURE: ({ payload: { nodes, defaultData }, pContext }) => {
|
|
211
|
+
pContext.defaultData = defaultData;
|
|
195
212
|
nodes.forEach(({ id, position }) => {
|
|
196
|
-
dimensions[id] = calculateDimensions(position);
|
|
213
|
+
pContext.dimensions[id] = calculateDimensions(position);
|
|
197
214
|
});
|
|
198
215
|
},
|
|
199
216
|
}),
|
|
200
217
|
),
|
|
201
218
|
|
|
219
|
+
setNodeData: assign('data.nodes', {
|
|
220
|
+
SET_NODE_DATA: ({ context: { data }, payload: { id, data: newData } }) => {
|
|
221
|
+
return data?.nodes?.map(node => {
|
|
222
|
+
if (node.id === id) {
|
|
223
|
+
return { ...node, data: { ...node.data, ...newData } };
|
|
224
|
+
}
|
|
225
|
+
return node;
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
}),
|
|
229
|
+
|
|
202
230
|
setBoard: assign('board', { SET_BOARD: ({ payload }) => payload }),
|
|
203
231
|
generateID: action(({ pContext }) => (pContext.generatedId = nanoid())),
|
|
204
232
|
select: assign('selected', { SELECT: ({ payload }) => payload }),
|
|
205
233
|
clearNewEdge: erase('newEdge'),
|
|
206
|
-
deselect: erase('selected'),
|
|
234
|
+
deselect: batch(erase('selected'), erase('editing')),
|
|
235
|
+
edit: batch(
|
|
236
|
+
assign('editing', { EDIT: ({ payload }) => payload }),
|
|
237
|
+
assign('selected', { EDIT: ({ payload }) => payload }),
|
|
238
|
+
),
|
|
239
|
+
stopEdit: erase('editing'),
|
|
207
240
|
|
|
208
241
|
startNewEdge: assign('newEdge', {
|
|
209
242
|
START_NEW_EDGE: ({ payload: from, pContext: { dimensions } }) => {
|
|
@@ -221,11 +254,12 @@ export const machine = createMachine(
|
|
|
221
254
|
}) => {
|
|
222
255
|
const edges = data?.edges;
|
|
223
256
|
const dimension = dimensions[payload.id];
|
|
257
|
+
if (!dimension) return;
|
|
224
258
|
|
|
225
259
|
const outputOffset =
|
|
226
|
-
dimension
|
|
260
|
+
dimension.outputOffset ?? getDefaultOutputOffset(dimension.width);
|
|
227
261
|
|
|
228
|
-
const inputOffset = dimension
|
|
262
|
+
const inputOffset = dimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
229
263
|
|
|
230
264
|
const output = {
|
|
231
265
|
x: payload.x + outputOffset.x,
|
|
@@ -237,19 +271,20 @@ export const machine = createMachine(
|
|
|
237
271
|
y: payload.y + inputOffset.y,
|
|
238
272
|
};
|
|
239
273
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
dimension.input = input;
|
|
243
|
-
}
|
|
274
|
+
dimension.output = output;
|
|
275
|
+
dimension.input = input;
|
|
244
276
|
|
|
245
277
|
edges?.forEach(({ from, to, id }) => {
|
|
278
|
+
const edgePosition = edgesPositions[id];
|
|
279
|
+
if (!edgePosition) return;
|
|
280
|
+
|
|
246
281
|
if (from === payload.id) {
|
|
247
|
-
|
|
248
|
-
|
|
282
|
+
edgePosition.x0 = output.x;
|
|
283
|
+
edgePosition.y0 = output.y;
|
|
249
284
|
}
|
|
250
285
|
if (to === payload.id) {
|
|
251
|
-
|
|
252
|
-
|
|
286
|
+
edgePosition.x1 = input.x;
|
|
287
|
+
edgePosition.y1 = input.y;
|
|
253
288
|
}
|
|
254
289
|
});
|
|
255
290
|
|
|
@@ -261,9 +296,7 @@ export const machine = createMachine(
|
|
|
261
296
|
payload,
|
|
262
297
|
pContext: { dimensions },
|
|
263
298
|
}) => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
edges?.forEach(({ from, to, id }) => {
|
|
299
|
+
data?.edges?.forEach(({ from, to, id }) => {
|
|
267
300
|
const dimension = dimensions[payload.id];
|
|
268
301
|
const edgePosition = edgesPositions[id];
|
|
269
302
|
if (!edgePosition || !dimension) return;
|
|
@@ -292,44 +325,71 @@ export const machine = createMachine(
|
|
|
292
325
|
return edgesPositions;
|
|
293
326
|
},
|
|
294
327
|
|
|
295
|
-
else: ({ context: { data
|
|
296
|
-
const
|
|
297
|
-
edgesPositions = {};
|
|
328
|
+
else: ({ context: { data }, pContext: { dimensions } }) => {
|
|
329
|
+
const nextEdgesPositions: Record<string, Vector> = {};
|
|
298
330
|
|
|
299
|
-
edges
|
|
331
|
+
data?.edges?.forEach(({ from, id, to }) => {
|
|
300
332
|
const output = dimensions[from]?.output;
|
|
301
333
|
const input = dimensions[to]?.input;
|
|
302
334
|
|
|
303
335
|
if (output && input) {
|
|
304
|
-
|
|
336
|
+
nextEdgesPositions[id] = {
|
|
305
337
|
x0: output.x,
|
|
306
338
|
y0: output.y,
|
|
307
339
|
x1: input.x,
|
|
308
340
|
y1: input.y,
|
|
309
341
|
};
|
|
310
|
-
} else {
|
|
311
|
-
delete edgesPositions[id];
|
|
312
342
|
}
|
|
313
343
|
});
|
|
314
344
|
|
|
315
|
-
return
|
|
345
|
+
return nextEdgesPositions;
|
|
316
346
|
},
|
|
317
347
|
}),
|
|
318
348
|
|
|
319
349
|
assign('updatingUI', () => true),
|
|
320
350
|
),
|
|
321
351
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
352
|
+
resize: action({
|
|
353
|
+
RESIZE: ({
|
|
354
|
+
payload: {
|
|
355
|
+
id,
|
|
356
|
+
size: { width, height },
|
|
357
|
+
},
|
|
358
|
+
context: { data },
|
|
359
|
+
pContext: { dimensions },
|
|
360
|
+
}) => {
|
|
361
|
+
const dimension = dimensions[id];
|
|
362
|
+
if (!dimension) return;
|
|
363
|
+
|
|
364
|
+
dimension.width = width;
|
|
365
|
+
dimension.height = height;
|
|
366
|
+
|
|
367
|
+
const node = data?.nodes?.find(n => n.id === id);
|
|
368
|
+
const outputOffset = getDefaultOutputOffset(width);
|
|
369
|
+
const inputOffset = dimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
370
|
+
|
|
371
|
+
dimension.outputOffset = outputOffset;
|
|
372
|
+
dimension.inputOffset = inputOffset;
|
|
373
|
+
|
|
374
|
+
if (node) {
|
|
375
|
+
dimension.output = {
|
|
376
|
+
x: node.position.x + outputOffset.x,
|
|
377
|
+
y: node.position.y + outputOffset.y,
|
|
378
|
+
};
|
|
379
|
+
dimension.input = {
|
|
380
|
+
x: node.position.x + inputOffset.x,
|
|
381
|
+
y: node.position.y + inputOffset.y,
|
|
382
|
+
};
|
|
383
|
+
} else {
|
|
384
|
+
dimension.output = { x: dimension.output.x, y: dimension.output.y };
|
|
385
|
+
}
|
|
325
386
|
},
|
|
326
387
|
}),
|
|
327
388
|
|
|
328
389
|
linkChild: batch(
|
|
329
390
|
assign('data.edges', {
|
|
330
|
-
ADD_CHILD: ({ context: { data }, pContext, payload }) => {
|
|
391
|
+
ADD_CHILD: ({ context: { data }, pContext, payload: from }) => {
|
|
331
392
|
const edges = toArray.typed(data?.edges);
|
|
332
|
-
const from = payload;
|
|
333
393
|
const generatedId = pContext?.generatedId;
|
|
334
394
|
const to = buildNodeID(generatedId);
|
|
335
395
|
const id = buildEdgeId(from, to);
|
|
@@ -384,6 +444,7 @@ export const machine = createMachine(
|
|
|
384
444
|
}),
|
|
385
445
|
|
|
386
446
|
filter('data.nodes', { DELETE: ({ id }, _, { payload }) => id !== payload }),
|
|
447
|
+
erase('editing'),
|
|
387
448
|
),
|
|
388
449
|
|
|
389
450
|
addEdge: batch(
|
|
@@ -397,13 +458,14 @@ export const machine = createMachine(
|
|
|
397
458
|
return out;
|
|
398
459
|
},
|
|
399
460
|
}),
|
|
461
|
+
|
|
400
462
|
erase('newEdge'),
|
|
401
463
|
),
|
|
402
464
|
|
|
403
465
|
zoom: assign('zoom', {
|
|
404
466
|
ZOOM: ({ context: { zoom }, payload, pContext }) => {
|
|
405
467
|
const next = zoom + payload;
|
|
406
|
-
const clamped =
|
|
468
|
+
const clamped = clamp(next, 0.1, 3);
|
|
407
469
|
pContext.previousZoom = undefined;
|
|
408
470
|
return clamped;
|
|
409
471
|
},
|
|
@@ -427,6 +489,7 @@ export const machine = createMachine(
|
|
|
427
489
|
placeChild: assign('data.nodes', {
|
|
428
490
|
ADD_CHILD: ({ payload, context: { data, board }, pContext }) => {
|
|
429
491
|
if (!board) return data?.nodes;
|
|
492
|
+
|
|
430
493
|
const nodes = data?.nodes;
|
|
431
494
|
if (!payload) return nodes;
|
|
432
495
|
|
|
@@ -434,12 +497,12 @@ export const machine = createMachine(
|
|
|
434
497
|
if (!parentNode) return nodes;
|
|
435
498
|
|
|
436
499
|
const parentDimension = pContext.dimensions[payload];
|
|
437
|
-
|
|
438
500
|
const id = `node-${pContext.generatedId}`;
|
|
439
|
-
const width = parentDimension?.width ??
|
|
440
|
-
const height = parentDimension?.height ??
|
|
501
|
+
const width = parentDimension?.width ?? DEFAULT_SIZE.width;
|
|
502
|
+
const height = parentDimension?.height ?? DEFAULT_SIZE.height;
|
|
441
503
|
const initialX = parentNode.position.x + width + PARENT_CHILD_GAP_WIDTH;
|
|
442
504
|
const initialY = parentNode.position.y;
|
|
505
|
+
|
|
443
506
|
const position = pContext.clampPosition(
|
|
444
507
|
board,
|
|
445
508
|
initialX,
|
|
@@ -447,15 +510,15 @@ export const machine = createMachine(
|
|
|
447
510
|
width,
|
|
448
511
|
height,
|
|
449
512
|
);
|
|
450
|
-
const dimension = pContext.calculateDimensions(position, parentDimension);
|
|
451
513
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
514
|
+
const defaultData = pContext.defaultData ?? DEFAULT_DATA;
|
|
515
|
+
|
|
516
|
+
nodes?.push({ id, data: { ...defaultData }, position });
|
|
517
|
+
|
|
518
|
+
pContext.dimensions[id] = pContext.calculateDimensions(
|
|
456
519
|
position,
|
|
457
|
-
|
|
458
|
-
|
|
520
|
+
parentDimension ?? DEFAULT_SIZE,
|
|
521
|
+
);
|
|
459
522
|
|
|
460
523
|
return nodes;
|
|
461
524
|
},
|
|
@@ -464,6 +527,7 @@ export const machine = createMachine(
|
|
|
464
527
|
placeParent: assign('data.nodes', {
|
|
465
528
|
ADD_PARENT: ({ context: { data, zoom = 1, board }, pContext }) => {
|
|
466
529
|
if (!board) return data?.nodes;
|
|
530
|
+
|
|
467
531
|
const nodes = data?.nodes;
|
|
468
532
|
const id = `node-${pContext.generatedId}`;
|
|
469
533
|
const container = board.parent;
|
|
@@ -474,17 +538,22 @@ export const machine = createMachine(
|
|
|
474
538
|
const currentZoom = zoom;
|
|
475
539
|
const x = (scrollLeft + width / 2) / currentZoom;
|
|
476
540
|
const y = (scrollTop + height / 2) / currentZoom;
|
|
477
|
-
const position = pContext.clampPosition(
|
|
478
|
-
|
|
541
|
+
const position = pContext.clampPosition(
|
|
542
|
+
board,
|
|
543
|
+
x,
|
|
544
|
+
y,
|
|
545
|
+
DEFAULT_SIZE.width,
|
|
546
|
+
DEFAULT_SIZE.height,
|
|
547
|
+
);
|
|
479
548
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
input: false,
|
|
484
|
-
position,
|
|
485
|
-
});
|
|
549
|
+
const defaultData = pContext.defaultData ?? DEFAULT_DATA;
|
|
550
|
+
|
|
551
|
+
nodes?.push({ id, data: { ...defaultData }, position });
|
|
486
552
|
|
|
487
|
-
pContext.dimensions[id] =
|
|
553
|
+
pContext.dimensions[id] = pContext.calculateDimensions(
|
|
554
|
+
position,
|
|
555
|
+
DEFAULT_SIZE,
|
|
556
|
+
);
|
|
488
557
|
return nodes;
|
|
489
558
|
},
|
|
490
559
|
}),
|
|
@@ -492,6 +561,7 @@ export const machine = createMachine(
|
|
|
492
561
|
placeSibling: assign('data.nodes', {
|
|
493
562
|
ADD_SIBLING: ({ payload, context: { data, board }, pContext }) => {
|
|
494
563
|
if (!board) return data?.nodes;
|
|
564
|
+
|
|
495
565
|
const edges = data?.edges;
|
|
496
566
|
const nodes = data?.nodes;
|
|
497
567
|
const parentID = edges?.find(edge => edge.to === payload)?.from;
|
|
@@ -502,10 +572,11 @@ export const machine = createMachine(
|
|
|
502
572
|
|
|
503
573
|
const parentDimension = pContext.dimensions[parentID];
|
|
504
574
|
const id = `node-${pContext.generatedId}`;
|
|
505
|
-
const width = parentDimension?.width ??
|
|
506
|
-
const height = parentDimension?.height ??
|
|
575
|
+
const width = parentDimension?.width ?? DEFAULT_SIZE.width;
|
|
576
|
+
const height = parentDimension?.height ?? DEFAULT_SIZE.height;
|
|
507
577
|
const initialX = parentNode.position.x + width + PARENT_CHILD_GAP_WIDTH;
|
|
508
578
|
const initialY = parentNode.position.y + PARENT_CHILD_GAP_WIDTH;
|
|
579
|
+
|
|
509
580
|
const position = pContext.clampPosition(
|
|
510
581
|
board,
|
|
511
582
|
initialX,
|
|
@@ -513,16 +584,16 @@ export const machine = createMachine(
|
|
|
513
584
|
width,
|
|
514
585
|
height,
|
|
515
586
|
);
|
|
516
|
-
const dimension = pContext.calculateDimensions(position, parentDimension);
|
|
517
587
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
588
|
+
const defaultData = pContext.defaultData ?? DEFAULT_DATA;
|
|
589
|
+
|
|
590
|
+
nodes?.push({ id, data: { ...defaultData }, position });
|
|
591
|
+
|
|
592
|
+
pContext.dimensions[id] = pContext.calculateDimensions(
|
|
522
593
|
position,
|
|
523
|
-
|
|
594
|
+
parentDimension ?? DEFAULT_SIZE,
|
|
595
|
+
);
|
|
524
596
|
|
|
525
|
-
pContext.dimensions[id] = dimension;
|
|
526
597
|
return nodes;
|
|
527
598
|
},
|
|
528
599
|
}),
|
|
@@ -12,25 +12,47 @@ export type Point = inferT<typeof point>;
|
|
|
12
12
|
*
|
|
13
13
|
* @see {@linkcode point}
|
|
14
14
|
*/
|
|
15
|
-
export const nodeOffset = type(({
|
|
16
|
-
input:
|
|
15
|
+
export const nodeOffset = type(({ use }) => ({
|
|
16
|
+
input: use(point),
|
|
17
17
|
output: use(point),
|
|
18
18
|
}));
|
|
19
19
|
|
|
20
20
|
/** Schema definition for edge extremities. */
|
|
21
21
|
export const extremities = type({ from: 'string', to: 'string' });
|
|
22
22
|
|
|
23
|
+
/** Schema definition for primitive values allowed in node data. */
|
|
24
|
+
export const nodeDataValue = type(({ union }) =>
|
|
25
|
+
union('string', 'boolean', 'number'),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Schema definition for serialized node data dictionary.
|
|
30
|
+
*
|
|
31
|
+
* @see {@linkcode nodeDataValue}
|
|
32
|
+
*/
|
|
33
|
+
export const data = type(({ record, use }) => record(use(nodeDataValue)));
|
|
34
|
+
|
|
35
|
+
/** Serialized node data dictionary type inferred from schema {@linkcode data}. */
|
|
36
|
+
export type NodeData = Record<string, string | boolean | number>;
|
|
37
|
+
|
|
23
38
|
/**
|
|
24
39
|
* Schema definition for a serialized flowchart node entity.
|
|
25
40
|
*
|
|
26
|
-
* @see {@linkcode point}
|
|
41
|
+
* @see {@linkcode point}, {@linkcode data}
|
|
27
42
|
*/
|
|
28
|
-
export const nodeJSON = type(({
|
|
43
|
+
export const nodeJSON = type(({ use }) => ({
|
|
29
44
|
position: use(point),
|
|
30
|
-
data:
|
|
31
|
-
input: 'boolean',
|
|
45
|
+
data: use(data),
|
|
32
46
|
}));
|
|
33
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Serialized node properties type inferred from schema {@linkcode nodeJSON}.
|
|
50
|
+
*
|
|
51
|
+
* @template | {@linkcode NodeData} `D` - Custom data properties type extending
|
|
52
|
+
* {@linkcode NodeData}.
|
|
53
|
+
*/
|
|
54
|
+
export type NodeProps<D extends NodeData = NodeData> = { position: Point; data: D };
|
|
55
|
+
|
|
34
56
|
/**
|
|
35
57
|
* Schema definition for a serialized flowchart edge entity.
|
|
36
58
|
*
|
|
@@ -38,6 +60,9 @@ export const nodeJSON = type(({ optional, use }) => ({
|
|
|
38
60
|
*/
|
|
39
61
|
export const edgeJSON = extremities;
|
|
40
62
|
|
|
63
|
+
/** Serialized edge properties type inferred from schema {@linkcode edgeJSON}. */
|
|
64
|
+
export type EdgeProps = inferT<typeof edgeJSON>;
|
|
65
|
+
|
|
41
66
|
/**
|
|
42
67
|
* Schema definition for layout dimensions and connection points of a node.
|
|
43
68
|
*
|
package/src/ui/Flow.tsx
CHANGED
|
@@ -1,21 +1,60 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { createSignal, onMount, Show, type JSX } from 'solid-js';
|
|
2
|
+
import {} from 'solid-js/web';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import type { NodeData } from '../services/main.machine.typings';
|
|
5
|
+
import { FlowChart } from './components/FlowChart';
|
|
4
6
|
import { Provider } from './components/FlowChart.context';
|
|
7
|
+
import type { FlowProps } from './components/FlowChart.types';
|
|
8
|
+
import { LoadingFallback } from './globals/components/organisms/LoadingFallback';
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Root Flow component wrapping the {@linkcode FlowChart} inside the flow context
|
|
8
12
|
* provider.
|
|
9
13
|
*
|
|
14
|
+
* @template | {@linkcode NodeData} `D` - Custom node data dictionary type extending
|
|
15
|
+
* {@linkcode NodeData}.
|
|
16
|
+
*
|
|
10
17
|
* @param props - Flow chart configuration and callbacks of type
|
|
11
18
|
* {@linkcode FlowProps}.
|
|
12
19
|
*
|
|
13
20
|
* @returns The rendered Solid component.
|
|
14
21
|
*
|
|
15
|
-
* @see {@linkcode Provider}
|
|
22
|
+
* @see {@linkcode Provider}, {@linkcode FlowChart}
|
|
16
23
|
*/
|
|
17
|
-
export const Flow
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
export const Flow = <D extends NodeData = NodeData>(
|
|
25
|
+
props: FlowProps<D>,
|
|
26
|
+
): JSX.Element => {
|
|
27
|
+
const [isMounted, setIsMounted] = createSignal(false);
|
|
28
|
+
|
|
29
|
+
// onMount never runs on the server, only in the browser
|
|
30
|
+
onMount(() => setTimeout(() => setIsMounted(true), props.delay));
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
style={{
|
|
34
|
+
'background-image':
|
|
35
|
+
'radial-gradient(circle, #b8b8b8bf 1px, rgba(0, 0, 0, 0) 1px)',
|
|
36
|
+
}}
|
|
37
|
+
|
|
38
|
+
class='relative flex h-full w-full rounded-lg border-2 border-gray-600 bg-white bg-size-[30px_30px]'
|
|
39
|
+
>
|
|
40
|
+
<Show
|
|
41
|
+
when={isMounted()}
|
|
42
|
+
keyed
|
|
43
|
+
fallback={
|
|
44
|
+
<div class='relative flex flex-1 items-center justify-center'>
|
|
45
|
+
<LoadingFallback
|
|
46
|
+
message='Chart is loading...'
|
|
47
|
+
interval={35}
|
|
48
|
+
rewind
|
|
49
|
+
rewindDelay={1_000}
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
}
|
|
53
|
+
>
|
|
54
|
+
<Provider>
|
|
55
|
+
<FlowChart {...props} />
|
|
56
|
+
</Provider>
|
|
57
|
+
</Show>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -17,9 +17,7 @@ import { useFlow } from './FlowChart.context';
|
|
|
17
17
|
*/
|
|
18
18
|
export const DragBounds: Component = () => {
|
|
19
19
|
const service = useFlow();
|
|
20
|
-
|
|
21
20
|
const zoom = createState(service, { selector: ({ context }) => context.zoom });
|
|
22
|
-
|
|
23
21
|
const board = createState(service, { selector: ({ context }) => context.board });
|
|
24
22
|
|
|
25
23
|
const [state, { addTransformer, removeTransformer, onDragStart, onDragEnd }] =
|