@bemedev/mind-flow 0.1.1 → 0.3.1

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.
Files changed (51) hide show
  1. package/README.md +10 -10
  2. package/lib/helpers/createContext.d.ts +7 -2
  3. package/lib/helpers/createContext.d.ts.map +1 -1
  4. package/lib/index.cjs.js +1 -1
  5. package/lib/index.es.js +520 -493
  6. package/lib/output.css +1 -1
  7. package/lib/server.cjs.js +621 -413
  8. package/lib/server.es.js +625 -417
  9. package/lib/services/main.machine.d.ts +4857 -218
  10. package/lib/services/main.machine.d.ts.map +1 -1
  11. package/lib/{ui/components/FlowChart.data.d.ts → services/main.machine.data.d.ts} +4 -2
  12. package/lib/services/main.machine.data.d.ts.map +1 -0
  13. package/lib/services/main.machine.helpers.d.ts +32 -0
  14. package/lib/services/main.machine.helpers.d.ts.map +1 -0
  15. package/lib/services/main.machine.typings.d.ts +126 -0
  16. package/lib/services/main.machine.typings.d.ts.map +1 -0
  17. package/lib/ui/Flow.d.ts +2 -0
  18. package/lib/ui/Flow.d.ts.map +1 -1
  19. package/lib/ui/components/Bounds.d.ts +2 -0
  20. package/lib/ui/components/Bounds.d.ts.map +1 -1
  21. package/lib/ui/components/EdgeComponent.d.ts +3 -2
  22. package/lib/ui/components/EdgeComponent.d.ts.map +1 -1
  23. package/lib/ui/components/EdgesBoard.d.ts +2 -0
  24. package/lib/ui/components/EdgesBoard.d.ts.map +1 -1
  25. package/lib/ui/components/FlowChart.context.d.ts +5608 -996
  26. package/lib/ui/components/FlowChart.context.d.ts.map +1 -1
  27. package/lib/ui/components/FlowChart.d.ts +3 -1
  28. package/lib/ui/components/FlowChart.d.ts.map +1 -1
  29. package/lib/ui/components/NodeComponent.d.ts +2 -10
  30. package/lib/ui/components/NodeComponent.d.ts.map +1 -1
  31. package/lib/ui/components/NodesBoard.d.ts +2 -0
  32. package/lib/ui/components/NodesBoard.d.ts.map +1 -1
  33. package/package.json +10 -10
  34. package/src/helpers/createContext.ts +7 -2
  35. package/src/{ui/components/FlowChart.data.ts → services/main.machine.data.ts} +3 -1
  36. package/src/services/main.machine.helpers.ts +55 -0
  37. package/src/services/main.machine.ts +288 -70
  38. package/src/services/main.machine.typings.ts +98 -0
  39. package/src/ui/Flow.tsx +2 -0
  40. package/src/ui/components/Bounds.tsx +13 -8
  41. package/src/ui/components/EdgeComponent.tsx +30 -18
  42. package/src/ui/components/EdgesBoard.tsx +13 -36
  43. package/src/ui/components/FlowChart.context.ts +204 -310
  44. package/src/ui/components/FlowChart.tsx +16 -16
  45. package/src/ui/components/NodeComponent.tsx +59 -104
  46. package/src/ui/components/NodesBoard.tsx +74 -47
  47. package/src/ui/components/classes.ts +1 -1
  48. package/lib/services/main.typings.d.ts +0 -68
  49. package/lib/services/main.typings.d.ts.map +0 -1
  50. package/lib/ui/components/FlowChart.data.d.ts.map +0 -1
  51. package/src/services/main.typings.ts +0 -50
package/lib/server.cjs.js CHANGED
@@ -1,12 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let solid_js_web = require("solid-js/web");
3
+ let _bemedev_app_solidjs = require("@bemedev/app-solidjs");
3
4
  let solid_js = require("solid-js");
4
5
  let _bemedev_app = require("@bemedev/app");
5
- let dequal_lite = require("dequal/lite");
6
- let solid_js_store = require("solid-js/store");
7
6
  let _bemedev_app_bemedev = require("@bemedev/app/bemedev");
8
7
  let nanoid = require("nanoid");
9
- let _bemedev_app_solidjs = require("@bemedev/app-solidjs");
10
8
  let _thisbeyond_solid_dnd = require("@thisbeyond/solid-dnd");
11
9
  let dequal = require("dequal");
12
10
  //#region src/ui/components/classes.ts
@@ -35,7 +33,7 @@ var CLASSES = [
35
33
  "w-full",
36
34
  "h-full",
37
35
  "overflow-hidden",
38
- "overflow-scroll",
36
+ "overflow-auto",
39
37
  "h-[150vh]",
40
38
  "w-[2160px]",
41
39
  "bg-size-[30px_30px]",
@@ -95,6 +93,50 @@ var CLASSES = [
95
93
  "cursor-crosshair",
96
94
  "mt-3"
97
95
  ];
96
+ /** X-axis center offset in pixels from the node container edge. */
97
+ var HANDLE_CENTER_X_OFFSET = 10.5;
98
+ /** Default 2D offset coordinates for input connection handles. */
99
+ var DEFAULT_INPUT_OFFSET = {
100
+ x: -10.5,
101
+ y: 18
102
+ };
103
+ /**
104
+ * Computes default output handle offset coordinates given a node width.
105
+ *
106
+ * @param width - Node width in pixels, defaults to `0`.
107
+ *
108
+ * @returns 2D offset coordinates for the output handle.
109
+ *
110
+ * @see {@linkcode HANDLE_CENTER_X_OFFSET}, {@linkcode HANDLE_CENTER_Y}
111
+ */
112
+ var getDefaultOutputOffset = (width = 0) => ({
113
+ x: width + HANDLE_CENTER_X_OFFSET,
114
+ y: 18
115
+ });
116
+ /**
117
+ * Boundary padding constraints for node dragging and positioning within the
118
+ * viewport.
119
+ */
120
+ var BOUNDS_CONSTRAINTS = {
121
+ horizontal: 55,
122
+ vertical: 40
123
+ };
124
+ /**
125
+ * Default node items of type {@linkcode NodeProps} provided when no initial
126
+ * configuration is given.
127
+ */
128
+ var DEFAULT_NODES = [{
129
+ id: "node-0",
130
+ data: {
131
+ content: "Some text",
132
+ label: "Root node"
133
+ },
134
+ input: false,
135
+ position: {
136
+ x: 350,
137
+ y: 100
138
+ }
139
+ }];
98
140
  //#endregion
99
141
  //#region src/helpers/createContext.ts
100
142
  /**
@@ -106,8 +148,10 @@ var CLASSES = [
106
148
  * `NonNullable<T>`.
107
149
  * @param options - Optional context configuration of type {@linkcode Options}.
108
150
  *
109
- * @returns A tuple containing the Provider component of interface
151
+ * @returns A tuple containing the Provider component of type
110
152
  * {@linkcode ParentComponent}, the accessor hook, and the Solid context object.
153
+ *
154
+ * @see {@linkcode createSolidContext}, {@linkcode useContext}
111
155
  */
112
156
  var createContext = (context, options) => {
113
157
  const _context = (0, solid_js.createContext)(context(), options);
@@ -123,7 +167,66 @@ var createContext = (context, options) => {
123
167
  ];
124
168
  };
125
169
  //#endregion
126
- //#region src/services/main.typings.ts
170
+ //#region src/services/main.machine.helpers.ts
171
+ /**
172
+ * Constructs a unique edge identifier string from source and destination node IDs.
173
+ *
174
+ * @param out - The source node ID string.
175
+ * @param _in - The destination node ID string.
176
+ *
177
+ * @returns Formatted edge identifier string.
178
+ */
179
+ var buildEdgeId = (out, _in) => {
180
+ return `edge = ${out} => ${_in}`;
181
+ };
182
+ /**
183
+ * Constructs a formatted node identifier string from a generated ID.
184
+ *
185
+ * @param generated - The generated unique ID string or `null`/`undefined`.
186
+ *
187
+ * @returns Formatted node identifier string.
188
+ */
189
+ var buildNodeID = (generated) => {
190
+ return `node-${generated}`;
191
+ };
192
+ /**
193
+ * Calculates node dimensions, connection points, and handle offsets from position
194
+ * and optional parent dimension.
195
+ *
196
+ * @param position - Node position in board coordinates of type {@linkcode Point}.
197
+ * @param parentDimension - Optional parent node dimension of type
198
+ * {@linkcode Dimension} to inherit sizing and offsets from.
199
+ *
200
+ * @returns Node layout dimension object of type {@linkcode Dimension}.
201
+ *
202
+ * @see {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}
203
+ */
204
+ var calculateDimensions = (position, parentDimension = {
205
+ width: 192,
206
+ height: 50,
207
+ inputOffset: DEFAULT_INPUT_OFFSET
208
+ }) => {
209
+ const width = parentDimension.width;
210
+ const height = parentDimension.height;
211
+ const outputOffset = parentDimension.outputOffset ?? getDefaultOutputOffset(width);
212
+ const inputOffset = parentDimension.inputOffset;
213
+ return {
214
+ width,
215
+ height,
216
+ output: {
217
+ x: position.x + outputOffset.x,
218
+ y: position.y + outputOffset.y
219
+ },
220
+ input: {
221
+ x: position.x + inputOffset.x,
222
+ y: position.y + inputOffset.y
223
+ },
224
+ outputOffset,
225
+ inputOffset
226
+ };
227
+ };
228
+ //#endregion
229
+ //#region src/services/main.machine.typings.ts
127
230
  /** Schema definition for 2D coordinates `(x, y)`. */
128
231
  var point = (0, _bemedev_app_bemedev.type)({
129
232
  x: "number",
@@ -138,7 +241,11 @@ var extremities = (0, _bemedev_app_bemedev.type)({
138
241
  from: "string",
139
242
  to: "string"
140
243
  });
141
- /** Schema definition for a serialized flowchart node entity. */
244
+ /**
245
+ * Schema definition for a serialized flowchart node entity.
246
+ *
247
+ * @see {@linkcode point}
248
+ */
142
249
  var nodeJSON = (0, _bemedev_app_bemedev.type)(({ optional, use }) => ({
143
250
  position: use(point),
144
251
  data: {
@@ -147,50 +254,68 @@ var nodeJSON = (0, _bemedev_app_bemedev.type)(({ optional, use }) => ({
147
254
  },
148
255
  input: "boolean"
149
256
  }));
150
- /** Schema definition for a serialized flowchart edge entity. */
257
+ /**
258
+ * Schema definition for a serialized flowchart edge entity.
259
+ *
260
+ * @see {@linkcode extremities}
261
+ */
151
262
  var edgeJSON = extremities;
152
- (0, _bemedev_app_bemedev.type)(({ optional, use }) => ({
263
+ /**
264
+ * Schema definition for layout dimensions and connection points of a node.
265
+ *
266
+ * @see {@linkcode point}
267
+ */
268
+ var dimension = (0, _bemedev_app_bemedev.type)(({ optional, use }) => ({
153
269
  width: "number",
154
270
  height: "number",
155
- id: "string",
156
271
  output: use(point),
157
- input: optional(use(point))
272
+ input: optional(use(point)),
273
+ inputOffset: optional(use(point)),
274
+ outputOffset: optional(use(point))
158
275
  }));
159
- (0, _bemedev_app_bemedev.type)({
276
+ /**
277
+ * Schema definition for a 2D line vector representing edge coordinates `(x0, y0)` to
278
+ * `(x1, y1)`.
279
+ */
280
+ var vector = (0, _bemedev_app_bemedev.type)({
160
281
  x0: "number",
161
282
  y0: "number",
162
283
  x1: "number",
163
284
  y1: "number"
164
285
  });
165
- //#endregion
166
- //#region src/services/main.machine.ts
167
286
  /**
168
- * Constructs a unique edge identifier string from source and destination node IDs.
169
- *
170
- * @param out - The source node ID string.
171
- * @param _in - The destination node ID string.
172
- *
173
- * @returns Formatted edge identifier string.
174
- */
175
- var buildEdgeId = (out, _in) => {
176
- return `edge = ${out} => ${_in}`;
177
- };
178
- /**
179
- * Constructs a formatted node identifier string from a generated ID.
180
- *
181
- * @param generated - The generated unique ID string or `null`/`undefined`.
287
+ * Schema definition for an ongoing new connection edge creation preview between
288
+ * source node and cursor position.
182
289
  *
183
- * @returns Formatted node identifier string.
290
+ * @see {@linkcode vector}
184
291
  */
185
- var buildNodeID = (generated) => {
186
- return `node-${generated}`;
187
- };
292
+ var newEdge = (0, _bemedev_app_bemedev.type)(({ intersection, use }) => intersection({ from: "string" }, use(vector)));
293
+ /** Schema definition for flowchart board geometry and container scroll dimensions. */
294
+ var board = (0, _bemedev_app_bemedev.type)(({ optional }) => ({
295
+ self: {
296
+ left: "number",
297
+ top: "number",
298
+ width: "number",
299
+ height: "number"
300
+ },
301
+ parent: optional({
302
+ scrollLeft: "number",
303
+ scrollTop: "number",
304
+ height: "number",
305
+ width: "number"
306
+ })
307
+ }));
308
+ //#endregion
309
+ //#region src/services/main.machine.ts
188
310
  /**
189
311
  * State machine managing flowchart state transitions, nodes, edges, selection, and
190
312
  * layout actions.
313
+ *
314
+ * @see {@linkcode calculateDimensions}, {@linkcode buildEdgeId}, {@linkcode buildNodeID}, {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}
191
315
  */
192
316
  var machine = (0, _bemedev_app.createMachine)({
193
317
  initial: "idle",
318
+ on: { SET_BOARD: { actions: ["setBoard"] } },
194
319
  states: {
195
320
  idle: { on: {
196
321
  CONFIGURE: {
@@ -205,7 +330,7 @@ var machine = (0, _bemedev_app.createMachine)({
205
330
  } },
206
331
  working: { on: {
207
332
  MOVE_IMMEDIATE: { actions: [{
208
- name: "buildImmediateUI",
333
+ name: "buildUI",
209
334
  description: "Must be in the ui"
210
335
  }] },
211
336
  ADD_CHILD: {
@@ -230,6 +355,7 @@ var machine = (0, _bemedev_app.createMachine)({
230
355
  ],
231
356
  target: "/construction"
232
357
  },
358
+ ADD_DIMENSION: { actions: ["addDimension"] },
233
359
  ADD_SIBLING: {
234
360
  actions: [
235
361
  "generateID",
@@ -249,12 +375,18 @@ var machine = (0, _bemedev_app.createMachine)({
249
375
  actions: ["addEdge"],
250
376
  target: "/construction"
251
377
  },
378
+ START_NEW_EDGE: { actions: ["startNewEdge"] },
379
+ MOVE_NEW_EDGE: { actions: ["moveNewEdge"] },
380
+ CLEAR_NEW_EDGE: { actions: ["clearNewEdge"] },
252
381
  DELETE: {
253
382
  actions: ["delete"],
254
383
  target: "/construction"
255
384
  },
256
385
  SELECT: { actions: ["select"] },
257
- DESELECT: { actions: ["deselect"] }
386
+ DESELECT: { actions: ["deselect"] },
387
+ ZOOM: { actions: ["zoom"] },
388
+ TOGGLE_ZOOM: { actions: ["toggleZoom"] },
389
+ SET_BOARD: { actions: ["setBoard"] }
258
390
  } }
259
391
  }
260
392
  }, {
@@ -263,6 +395,7 @@ var machine = (0, _bemedev_app.createMachine)({
263
395
  nodes: array(intersection(use(nodeJSON), { id: "string" })),
264
396
  edges: array(intersection(use(edgeJSON), { id: "string" }))
265
397
  },
398
+ SET_BOARD: use(board),
266
399
  CONFIGURE_EMPTY: "never",
267
400
  MOVE: {
268
401
  id: "string",
@@ -280,11 +413,27 @@ var machine = (0, _bemedev_app.createMachine)({
280
413
  DELETE: "string",
281
414
  SELECT: "string",
282
415
  DESELECT: "never",
283
- ADD_EDGE: use(extremities)
416
+ ADD_EDGE: use(extremities),
417
+ START_NEW_EDGE: "string",
418
+ MOVE_NEW_EDGE: use(point),
419
+ CLEAR_NEW_EDGE: "never",
420
+ ZOOM: "number",
421
+ TOGGLE_ZOOM: "never",
422
+ ADD_DIMENSION: {
423
+ id: "string",
424
+ dimension: use(dimension)
425
+ }
284
426
  })),
285
427
  sync: true,
286
- pContext: (0, _bemedev_app_bemedev.type)(({ union }) => ({ generatedId: union("string", "null") })),
287
- context: (0, _bemedev_app_bemedev.type)(({ optional, use, array }) => ({
428
+ pContext: (0, _bemedev_app_bemedev.type)(({ union, optional, record, use, custom }) => ({
429
+ generatedId: union("string", "null"),
430
+ previousZoom: optional("number"),
431
+ dimensions: record(use(dimension)),
432
+ getBoardPosition: custom(),
433
+ clampPosition: custom(),
434
+ calculateDimensions: custom()
435
+ })),
436
+ context: (0, _bemedev_app_bemedev.type)(({ optional, use, array, record }) => ({
288
437
  data: optional({
289
438
  nodes: array({
290
439
  ...use(nodeJSON),
@@ -295,46 +444,145 @@ var machine = (0, _bemedev_app.createMachine)({
295
444
  id: "string"
296
445
  })
297
446
  }),
447
+ board: optional(use(board)),
448
+ edgesPositions: record(use(vector)),
449
+ newEdge: optional(use(newEdge)),
298
450
  selected: optional("string"),
299
- updatingUI: optional("boolean")
451
+ updatingUI: optional("boolean"),
452
+ zoom: "number",
453
+ bounds: use(point)
300
454
  }))
301
- }).provideOptions(({ assign, batch, erase }) => ({ actions: {
302
- configure: batch(assign("context.data", () => ({
303
- nodes: [],
304
- edges: []
305
- })), assign("context.data.nodes", { CONFIGURE: ({ payload: { nodes } }) => nodes }), assign("context.data.edges", { CONFIGURE: ({ payload: { edges } }) => edges }), assign("context.updatingUI", () => false), assign("pContext.generatedId", () => null)),
306
- generateID: assign("pContext.generatedId", () => (0, nanoid.nanoid)()),
307
- linkChild: batch(assign("context.data.edges", { ADD_CHILD: ({ context, pContext, payload }) => {
308
- const data = context.data;
455
+ }).provideOptions(({ assign, batch, erase, filter, action }) => ({ actions: {
456
+ configure: batch(assign("data", { CONFIGURE: ({ payload }) => payload }), assign("newEdge", () => void 0), assign("updatingUI", () => false), action(({ pContext }) => {
457
+ pContext.generatedId = null;
458
+ }), action({ CONFIGURE: ({ payload: { nodes }, pContext: { dimensions } }) => {
459
+ nodes.forEach(({ id, position }) => {
460
+ dimensions[id] = calculateDimensions(position);
461
+ });
462
+ } })),
463
+ startNewEdge: assign("newEdge", { START_NEW_EDGE: ({ payload: from, pContext: { dimensions } }) => {
464
+ const { x, y } = dimensions[from].output;
465
+ return {
466
+ from,
467
+ x0: x,
468
+ y0: y,
469
+ x1: x,
470
+ y1: y
471
+ };
472
+ } }),
473
+ setBoard: assign("board", { SET_BOARD: ({ payload }) => payload }),
474
+ buildUI: batch(assign("edgesPositions", {
475
+ MOVE: ({ context: { data, edgesPositions }, payload, pContext: { dimensions } }) => {
476
+ const edges = data?.edges;
477
+ const dimension = dimensions[payload.id];
478
+ const outputOffset = dimension?.outputOffset ?? getDefaultOutputOffset(dimension?.width);
479
+ const inputOffset = dimension?.inputOffset ?? DEFAULT_INPUT_OFFSET;
480
+ const output = {
481
+ x: payload.x + outputOffset.x,
482
+ y: payload.y + outputOffset.y
483
+ };
484
+ const input = {
485
+ x: payload.x + inputOffset.x,
486
+ y: payload.y + inputOffset.y
487
+ };
488
+ if (dimension) {
489
+ dimension.output = output;
490
+ dimension.input = input;
491
+ }
492
+ edges?.forEach(({ from, to, id }) => {
493
+ if (from === payload.id) {
494
+ edgesPositions[id].x0 = output.x;
495
+ edgesPositions[id].y0 = output.y;
496
+ }
497
+ if (to === payload.id) {
498
+ edgesPositions[id].x1 = input.x;
499
+ edgesPositions[id].y1 = input.y;
500
+ }
501
+ });
502
+ return edgesPositions;
503
+ },
504
+ MOVE_IMMEDIATE: ({ context: { data, edgesPositions }, payload, pContext: { dimensions } }) => {
505
+ (data?.edges)?.forEach(({ from, to, id }) => {
506
+ if (from === payload.id) {
507
+ const dimension = dimensions[payload.id];
508
+ const offset = dimension?.outputOffset ?? getDefaultOutputOffset(dimension?.width);
509
+ const x0 = payload.x + offset.x;
510
+ const y0 = payload.y + offset.y;
511
+ edgesPositions[id].x0 = x0;
512
+ edgesPositions[id].y0 = y0;
513
+ if (dimension) {
514
+ dimension.output.x = x0;
515
+ dimension.output.y = y0;
516
+ }
517
+ }
518
+ if (to === payload.id) {
519
+ const dimension = dimensions[payload.id];
520
+ const offset = dimension?.inputOffset ?? DEFAULT_INPUT_OFFSET;
521
+ const x1 = payload.x + offset.x;
522
+ const y1 = payload.y + offset.y;
523
+ edgesPositions[id].x1 = x1;
524
+ edgesPositions[id].y1 = y1;
525
+ if (dimension) dimension.input = {
526
+ x: x1,
527
+ y: y1
528
+ };
529
+ }
530
+ });
531
+ return edgesPositions;
532
+ },
533
+ else: ({ context: { data, edgesPositions }, pContext: { dimensions } }) => {
534
+ const edges = data?.edges ?? [];
535
+ edgesPositions = {};
536
+ edges.forEach(({ from, id, to }) => {
537
+ const output = dimensions[from]?.output;
538
+ const input = dimensions[to]?.input;
539
+ if (output && input) edgesPositions[id] = {
540
+ x0: output.x,
541
+ y0: output.y,
542
+ x1: input.x,
543
+ y1: input.y
544
+ };
545
+ else delete edgesPositions[id];
546
+ });
547
+ return edgesPositions;
548
+ }
549
+ }), assign("updatingUI", () => true)),
550
+ addDimension: action({ ADD_DIMENSION: ({ payload: { id, dimension }, pContext: { dimensions } }) => {
551
+ dimensions[id] = dimension;
552
+ } }),
553
+ generateID: action(({ pContext }) => {
554
+ pContext.generatedId = (0, nanoid.nanoid)();
555
+ }),
556
+ linkChild: batch(assign("data.edges", { ADD_CHILD: ({ context: { data }, pContext, payload }) => {
557
+ const edges = _bemedev_app_bemedev.toArray.typed(data?.edges);
309
558
  const from = payload;
310
559
  const generatedId = pContext?.generatedId;
311
560
  const to = buildNodeID(generatedId);
312
561
  const id = buildEdgeId(from, to);
313
- return [...data?.edges ?? [], {
562
+ edges.push({
314
563
  id,
315
564
  from,
316
565
  to
317
- }];
318
- } }), assign("context.selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId))),
319
- linkSibling: batch(assign("context.data.edges", { ADD_SIBLING: ({ pContext, payload, context }) => {
320
- const edges = context.data?.edges;
566
+ });
567
+ return edges;
568
+ } }), assign("selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId))),
569
+ linkSibling: batch(assign("data.edges", { ADD_SIBLING: ({ pContext, payload, context: { data } }) => {
570
+ const edges = _bemedev_app_bemedev.toArray.typed(data?.edges);
321
571
  const generatedId = pContext?.generatedId;
322
- const out = [...edges ?? []];
323
- const from = edges?.find(({ to }) => to === payload)?.from;
324
- if (!from) return out;
572
+ const from = edges.find(({ to }) => to === payload)?.from;
573
+ if (!from) return edges;
325
574
  const to = buildNodeID(generatedId);
326
575
  const id = buildEdgeId(from, to);
327
- out.push({
576
+ edges.push({
328
577
  from,
329
578
  to,
330
579
  id
331
580
  });
332
- return out;
333
- } }), assign("context.selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId))),
334
- selectParent: assign("context.selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId)),
335
- moveNode: assign("context.data.nodes", { MOVE: ({ context: { data }, payload }) => {
581
+ return edges;
582
+ } }), assign("selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId))),
583
+ selectParent: assign("selected", ({ pContext: { generatedId } }) => buildNodeID(generatedId)),
584
+ moveNode: assign("data.nodes", { MOVE: ({ context: { data }, payload }) => {
336
585
  const { id, x, y } = payload;
337
- if (!id) return data?.nodes ?? [];
338
586
  return data?.nodes?.map((d) => {
339
587
  if (d.id === id) return {
340
588
  ...d,
@@ -346,11 +594,11 @@ var machine = (0, _bemedev_app.createMachine)({
346
594
  return d;
347
595
  }) ?? [];
348
596
  } }),
349
- select: assign("context.selected", { SELECT: ({ payload }) => payload }),
350
- delete: assign(["context.data.nodes", "context.data.edges"], { DELETE: ({ context: { data }, payload }) => {
351
- return [data?.nodes?.filter(({ id }) => id !== payload), data?.edges?.filter(({ id, from, to }) => id !== payload && from !== payload && to !== payload)];
352
- } }),
353
- addEdge: assign("context.data.edges", { ADD_EDGE: ({ context, payload: { from, to } }) => {
597
+ select: assign("selected", { SELECT: ({ payload }) => payload }),
598
+ delete: batch(filter("data.edges", { DELETE: ({ id, from, to }, _, { payload }) => {
599
+ return id !== payload && from !== payload && to !== payload;
600
+ } }), filter("data.nodes", { DELETE: ({ id }, _, { payload }) => id !== payload })),
601
+ addEdge: batch(assign("data.edges", { ADD_EDGE: ({ context, payload: { from, to } }) => {
354
602
  const edges = context.data?.edges ?? [];
355
603
  const id = buildEdgeId(from, to);
356
604
  if (edges.some((e) => e.id === id)) return edges;
@@ -359,304 +607,218 @@ var machine = (0, _bemedev_app.createMachine)({
359
607
  from,
360
608
  to
361
609
  }];
610
+ } }), erase("newEdge")),
611
+ clearNewEdge: erase("newEdge"),
612
+ deselect: erase("selected"),
613
+ zoom: assign("zoom", { ZOOM: ({ context: { zoom }, payload, pContext }) => {
614
+ const next = zoom + payload;
615
+ const clamped = Math.min(Math.max(Number(next.toFixed(2)), .2), 3);
616
+ pContext.previousZoom = void 0;
617
+ return clamped;
362
618
  } }),
363
- deselect: erase("context.selected")
619
+ toggleZoom: assign("zoom", { TOGGLE_ZOOM: ({ context: { zoom }, pContext }) => {
620
+ const previous = pContext.previousZoom;
621
+ if (previous !== void 0) {
622
+ pContext.previousZoom = void 0;
623
+ return previous;
624
+ }
625
+ pContext.previousZoom = zoom;
626
+ return 1;
627
+ } })
364
628
  } }));
365
- /** X-axis center offset in pixels from the node container edge. */
366
- var HANDLE_CENTER_X_OFFSET = 10.5;
367
- /** Default 2D offset coordinates for input connection handles. */
368
- var DEFAULT_INPUT_OFFSET = {
369
- x: -10.5,
370
- y: 18
371
- };
372
- /**
373
- * Computes default output handle offset coordinates given a node width.
374
- *
375
- * @param width - Node width in pixels, defaults to `0`.
376
- *
377
- * @returns 2D offset coordinates for the output handle.
378
- */
379
- var getDefaultOutputOffset = (width = 0) => ({
380
- x: width + HANDLE_CENTER_X_OFFSET,
381
- y: 18
382
- });
383
- /**
384
- * Boundary padding constraints for node dragging and positioning within the
385
- * viewport.
386
- */
387
- var BOUNDS_CONSTRAINTS = {
388
- horizontal: 55,
389
- vertical: 40
390
- };
391
- /**
392
- * Default node items of type {@linkcode NodeProps} provided when no initial
393
- * configuration is given.
394
- */
395
- var DEFAULT_NODES = [{
396
- id: "node-0",
397
- data: {
398
- content: "Some text",
399
- label: "Root node"
400
- },
401
- input: false,
402
- position: {
403
- x: 350,
404
- y: 100
405
- }
406
- }];
407
629
  //#endregion
408
630
  //#region src/ui/components/FlowChart.context.ts
409
631
  /**
410
632
  * Solid Context Provider component and hook for accessing flowchart board state,
411
633
  * services, and zoom.
634
+ *
635
+ * @see {@linkcode machine}, {@linkcode createContext}
412
636
  */
413
637
  var [Provider, useFlow] = createContext(() => {
414
- /**
415
- * Shared state machine interpreter service instance for flowchart state
416
- * management.
417
- */
638
+ /** Shared service for flowchart state management. */
418
639
  const service = (0, _bemedev_app.interpret)(machine, {
419
- context: {},
420
- pContext: { generatedId: null }
640
+ context: {
641
+ zoom: 1,
642
+ edgesPositions: {},
643
+ bounds: {
644
+ x: 0,
645
+ y: 0
646
+ }
647
+ },
648
+ pContext: {
649
+ generatedId: null,
650
+ dimensions: {},
651
+ /**
652
+ * Converts viewport screen coordinates to unscaled board coordinates.
653
+ *
654
+ * @param clientX - Client X coordinate in pixels.
655
+ * @param clientY - Client Y coordinate in pixels.
656
+ * @param el - Board layout details of type {@linkcode Board}.
657
+ *
658
+ * @returns Calculated 2D coordinate of type {@linkcode Point}.
659
+ */
660
+ getBoardPosition(clientX, clientY, el) {
661
+ if (!el) return {
662
+ x: clientX,
663
+ y: clientY
664
+ };
665
+ const currentZoom = service.state.context.zoom;
666
+ return {
667
+ x: (clientX - el.self.left) / currentZoom,
668
+ y: (clientY - el.self.top) / currentZoom
669
+ };
670
+ },
671
+ /**
672
+ * Clamps given coordinates within board boundaries.
673
+ *
674
+ * @param board - Board layout and container details of type
675
+ * {@linkcode Board}.
676
+ * @param x - Desired X position in pixels.
677
+ * @param y - Desired Y position in pixels.
678
+ * @param nodeWidth - Node width in pixels, defaults to `192`.
679
+ * @param nodeHeight - Node height in pixels, defaults to `50`.
680
+ *
681
+ * @returns Clamped coordinate of type {@linkcode Point}.
682
+ *
683
+ * @see {@linkcode BOUNDS_CONSTRAINTS}
684
+ */
685
+ clampPosition(board, x, y, nodeWidth = 192, nodeHeight = 50) {
686
+ const container = board?.parent;
687
+ if (!container) return {
688
+ x,
689
+ y
690
+ };
691
+ const currentZoom = service.state.context.zoom ?? 1;
692
+ const minX = container.scrollLeft / currentZoom + BOUNDS_CONSTRAINTS.horizontal;
693
+ const maxX = Math.max(minX, (container.scrollLeft + container.width) / currentZoom - BOUNDS_CONSTRAINTS.horizontal - nodeWidth);
694
+ const minY = container.scrollTop / currentZoom + BOUNDS_CONSTRAINTS.vertical;
695
+ const maxY = Math.max(minY, (container.scrollTop + container.height) / currentZoom - BOUNDS_CONSTRAINTS.vertical - nodeHeight);
696
+ return {
697
+ x: Math.min(Math.max(x, minX), maxX),
698
+ y: Math.min(Math.max(y, minY), maxY)
699
+ };
700
+ },
701
+ /**
702
+ * Computes node dimension, connection points, and handle offsets.
703
+ *
704
+ * @param position - Node position of type {@linkcode Point}.
705
+ * @param parentDimension - Optional sizing and offsets to inherit.
706
+ *
707
+ * @returns Calculated dimension object of type {@linkcode Dimension}.
708
+ *
709
+ * @see {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode getDefaultOutputOffset}
710
+ */
711
+ calculateDimensions: (position, parentDimension = {
712
+ width: 192,
713
+ height: 50,
714
+ inputOffset: DEFAULT_INPUT_OFFSET
715
+ }) => {
716
+ const width = parentDimension.width;
717
+ const height = parentDimension.height;
718
+ const outputOffset = parentDimension.outputOffset ?? getDefaultOutputOffset(width);
719
+ const inputOffset = parentDimension.inputOffset;
720
+ return {
721
+ width,
722
+ height,
723
+ output: {
724
+ x: position.x + outputOffset.x,
725
+ y: position.y + outputOffset.y
726
+ },
727
+ input: {
728
+ x: position.x + inputOffset.x,
729
+ y: position.y + inputOffset.y
730
+ },
731
+ outputOffset,
732
+ inputOffset
733
+ };
734
+ }
735
+ }
421
736
  });
422
- const zoom = (0, solid_js.createSignal)(1);
423
- const newEdge = (0, solid_js.createSignal)();
424
- const [boardRef, setBoardRef] = (0, solid_js.createSignal)();
425
- const [dimensions, setDimensions] = (0, solid_js.createSignal)({}, { equals: dequal_lite.dequal });
426
- /**
427
- * Converts client viewport coordinates to board canvas coordinates adjusted for
428
- * zoom and scroll.
429
- *
430
- * @param clientX - Viewport horizontal coordinate.
431
- * @param clientY - Viewport vertical coordinate.
432
- *
433
- * @returns Board coordinate point of type {@linkcode Point}.
434
- */
435
- const getBoardPoint = (clientX, clientY) => {
436
- const el = boardRef();
437
- if (!el) return {
438
- x: clientX,
439
- y: clientY
440
- };
441
- const rect = el.getBoundingClientRect();
442
- const currentZoom = zoom[0]();
443
- return {
444
- x: clientX - rect.left / currentZoom,
445
- y: clientY - rect.top / currentZoom
446
- };
447
- };
448
- const [edgesPositions, setEdgesPositions] = (0, solid_js.createSignal)({}, { equals: false });
449
- /**
450
- * Clamps node coordinates within the visible container boundaries.
451
- *
452
- * @param x - Desired horizontal X coordinate.
453
- * @param y - Desired vertical Y coordinate.
454
- * @param nodeWidth - Width of the node element in pixels, defaults to `192`.
455
- * @param nodeHeight - Height of the node element in pixels, defaults to `50`.
456
- *
457
- * @returns Clamped coordinate point of type {@linkcode Point}.
458
- */
459
- const clampPosition = (x, y, nodeWidth = 192, nodeHeight = 50) => {
460
- const container = boardRef()?.parentElement;
461
- if (!container) return {
462
- x,
463
- y
464
- };
465
- const currentZoom = zoom[0]();
466
- const minX = container.scrollLeft / currentZoom + BOUNDS_CONSTRAINTS.horizontal;
467
- const maxX = Math.max(minX, (container.scrollLeft + container.clientWidth) / currentZoom - BOUNDS_CONSTRAINTS.horizontal - nodeWidth);
468
- const minY = container.scrollTop / currentZoom + BOUNDS_CONSTRAINTS.vertical;
469
- const maxY = Math.max(minY, (container.scrollTop + container.clientHeight) / currentZoom - BOUNDS_CONSTRAINTS.vertical - nodeHeight);
470
- return {
471
- x: Math.min(Math.max(x, minX), maxX),
472
- y: Math.min(Math.max(y, minY), maxY)
473
- };
474
- };
475
- service.addOptions(({ voidAction, batch, assign }) => ({ actions: {
476
- placeChild: assign("context.data.nodes", { ADD_CHILD: ({ payload, context: { data }, pContext: { generatedId } }) => {
477
- const nodes = data?.nodes ?? [];
737
+ service.addOptions(({ assign }) => ({ actions: {
738
+ placeChild: assign("data.nodes", { ADD_CHILD: ({ payload, context: { data, board }, pContext }) => {
739
+ if (!board) return data?.nodes;
740
+ const nodes = data?.nodes;
478
741
  if (!payload) return nodes;
479
- const parentNode = nodes.find((node) => node.id === payload);
742
+ const parentNode = nodes?.find((node) => node.id === payload);
480
743
  if (!parentNode) return nodes;
481
- const id = `node-${generatedId}`;
482
- const width = dimensions()[payload]?.width ?? 0;
483
- const height = dimensions()[payload]?.height ?? 0;
744
+ const parentDimension = pContext.dimensions[payload];
745
+ const id = `node-${pContext.generatedId}`;
746
+ const width = parentDimension?.width ?? 192;
747
+ const height = parentDimension?.height ?? 50;
484
748
  const initialX = parentNode.position.x + width + 100;
485
749
  const initialY = parentNode.position.y;
486
- const position = clampPosition(initialX, initialY, width, height);
487
- return [...nodes, {
750
+ const position = pContext.clampPosition(board, initialX, initialY, width, height);
751
+ const dimension = pContext.calculateDimensions(position, parentDimension);
752
+ nodes?.push({
488
753
  id,
489
754
  data: { content: "<Nouveau nœud>" },
490
755
  input: true,
491
756
  position
492
- }];
757
+ });
758
+ pContext.dimensions[id] = dimension;
759
+ return nodes;
493
760
  } }),
494
- placeParent: assign("context.data.nodes", { ADD_PARENT: ({ context: { data }, pContext: { generatedId } }) => {
495
- const nodes = data?.nodes ?? [];
496
- const id = `node-${generatedId}`;
497
- const container = boardRef()?.parentElement;
761
+ placeParent: assign("data.nodes", { ADD_PARENT: ({ context: { data, zoom = 1, board }, pContext }) => {
762
+ if (!board) return data?.nodes;
763
+ const nodes = data?.nodes;
764
+ const id = `node-${pContext.generatedId}`;
765
+ const container = board.parent;
498
766
  const scrollLeft = container?.scrollLeft ?? 0;
499
767
  const scrollTop = container?.scrollTop ?? 0;
500
- const width = container?.clientWidth ?? 0;
501
- const height = container?.clientHeight ?? 0;
502
- const currentZoom = zoom[0]();
768
+ const width = container?.width ?? 0;
769
+ const height = container?.height ?? 0;
770
+ const currentZoom = zoom;
503
771
  const x = (scrollLeft + width / 2) / currentZoom;
504
772
  const y = (scrollTop + height / 2) / currentZoom;
505
- return [...nodes, {
773
+ const position = pContext.clampPosition(board, x, y);
774
+ const dimension = pContext.calculateDimensions(position);
775
+ nodes?.push({
506
776
  id,
507
777
  data: { content: "<Nouveau nœud>" },
508
778
  input: false,
509
- position: {
510
- x,
511
- y
512
- }
513
- }];
779
+ position
780
+ });
781
+ pContext.dimensions[id] = dimension;
782
+ return nodes;
514
783
  } }),
515
- placeSibling: assign("context.data.nodes", { ADD_SIBLING: ({ payload, context: { data }, pContext: { generatedId } }) => {
516
- const edges = data?.edges ?? [];
517
- const nodes = data?.nodes ?? [];
518
- const parentID = edges.find((edge) => edge.to === payload)?.from;
784
+ placeSibling: assign("data.nodes", { ADD_SIBLING: ({ payload, context: { data, board }, pContext }) => {
785
+ if (!board) return data?.nodes;
786
+ const edges = data?.edges;
787
+ const nodes = data?.nodes;
788
+ const parentID = edges?.find((edge) => edge.to === payload)?.from;
519
789
  if (!parentID) return nodes;
520
- const parentNode = nodes.find((node) => node.id === parentID);
790
+ const parentNode = nodes?.find((node) => node.id === parentID);
521
791
  if (!parentNode) return nodes;
522
- const id = `node-${generatedId}`;
523
- const width = dimensions()[parentID]?.width ?? 0;
524
- const height = dimensions()[parentID]?.height ?? 0;
792
+ const parentDimension = pContext.dimensions[parentID];
793
+ const id = `node-${pContext.generatedId}`;
794
+ const width = parentDimension?.width ?? 192;
795
+ const height = parentDimension?.height ?? 50;
525
796
  const initialX = parentNode.position.x + width + 100;
526
797
  const initialY = parentNode.position.y + 100;
527
- const position = clampPosition(initialX, initialY, width, height);
528
- return [...nodes, {
798
+ const position = pContext.clampPosition(board, initialX, initialY, width, height);
799
+ const dimension = pContext.calculateDimensions(position, parentDimension);
800
+ nodes?.push({
529
801
  id,
530
802
  data: { content: "<Nouveau nœud>" },
531
803
  input: true,
532
804
  position
533
- }];
534
- } }),
535
- buildUI: batch(voidAction(({ context: { data } }) => {
536
- const edges = data?.edges ?? [];
537
- setEdgesPositions((data) => {
538
- const array = Object.entries({ ...data }).filter(([id]) => edges.some((edge) => edge.id === id));
539
- return Object.fromEntries(array);
540
805
  });
541
- }), voidAction({
542
- else: ({ context: { data } }) => {
543
- const edges = data?.edges ?? [];
544
- setEdgesPositions((0, solid_js_store.produce)((next) => {
545
- edges?.forEach(({ from, id, to }) => {
546
- const output = dimensions()[from]?.output;
547
- const input = dimensions()[to]?.input;
548
- if (output && input) next[id] = {
549
- x0: output.x,
550
- y0: output.y,
551
- x1: input.x,
552
- y1: input.y
553
- };
554
- });
555
- }));
556
- },
557
- MOVE: ({ context: { data }, payload }) => {
558
- const edges = data?.edges ?? [];
559
- setEdgesPositions((0, solid_js_store.produce)((next) => {
560
- edges?.forEach(({ from, to, id }) => {
561
- if (from === payload.id) {
562
- const offset = dimensions()[payload.id]?.outputOffset ?? getDefaultOutputOffset(dimensions()[payload.id]?.width);
563
- const x0 = payload.x + offset.x;
564
- const y0 = payload.y + offset.y;
565
- next[id] = {
566
- ...next[id],
567
- x0,
568
- y0
569
- };
570
- setDimensions((0, solid_js_store.produce)((data) => {
571
- if (data[payload.id]) data[payload.id] = {
572
- ...data[payload.id],
573
- output: {
574
- x: x0,
575
- y: y0
576
- }
577
- };
578
- }));
579
- }
580
- if (to === payload.id) {
581
- const offset = dimensions()[payload.id]?.inputOffset ?? DEFAULT_INPUT_OFFSET;
582
- const x1 = payload.x + offset.x;
583
- const y1 = payload.y + offset.y;
584
- next[id] = {
585
- ...next[id],
586
- x1,
587
- y1
588
- };
589
- setDimensions((0, solid_js_store.produce)((data) => {
590
- if (data[payload.id]) data[payload.id] = {
591
- ...data[payload.id],
592
- input: {
593
- x: x1,
594
- y: y1
595
- }
596
- };
597
- }));
598
- }
599
- });
600
- }));
601
- }
602
- }), assign("context.updatingUI", () => true)),
603
- buildImmediateUI: voidAction({ MOVE_IMMEDIATE: ({ context: { data }, payload }) => {
604
- const edges = data?.edges ?? [];
605
- setEdgesPositions((0, solid_js_store.produce)((next) => {
606
- edges?.forEach(({ from, to, id }) => {
607
- if (from === payload.id) {
608
- const offset = dimensions()[payload.id]?.outputOffset ?? getDefaultOutputOffset(dimensions()[payload.id]?.width);
609
- const x0 = payload.x + offset.x;
610
- const y0 = payload.y + offset.y;
611
- next[id] = {
612
- ...next[id],
613
- x0,
614
- y0
615
- };
616
- setDimensions((0, solid_js_store.produce)((data) => {
617
- if (data[payload.id]) data[payload.id] = {
618
- ...data[payload.id],
619
- output: {
620
- x: x0,
621
- y: y0
622
- }
623
- };
624
- }));
625
- }
626
- if (to === payload.id) {
627
- const offset = dimensions()[payload.id]?.inputOffset ?? DEFAULT_INPUT_OFFSET;
628
- const x1 = payload.x + offset.x;
629
- const y1 = payload.y + offset.y;
630
- next[id] = {
631
- ...next[id],
632
- x1,
633
- y1
634
- };
635
- setDimensions((0, solid_js_store.produce)((data) => {
636
- if (data[payload.id]) data[payload.id] = {
637
- ...data[payload.id],
638
- input: {
639
- x: x1,
640
- y: y1
641
- }
642
- };
643
- }));
644
- }
645
- });
646
- }));
806
+ pContext.dimensions[id] = dimension;
807
+ return nodes;
808
+ } }),
809
+ moveNewEdge: assign("newEdge", { MOVE_NEW_EDGE: ({ context: { newEdge, board }, payload, pContext }) => {
810
+ if (!board) return void 0;
811
+ if (!newEdge) return void 0;
812
+ const { x: x1, y: y1 } = pContext.getBoardPosition(payload.x, payload.y, board);
813
+ return {
814
+ ...newEdge,
815
+ x1,
816
+ y1
817
+ };
647
818
  } })
648
819
  } }));
649
820
  service.start();
650
- return {
651
- dimensions: [dimensions, setDimensions],
652
- newEdge,
653
- board: [boardRef, setBoardRef],
654
- getBoardPoint,
655
- edgesPositions: [edgesPositions, setEdgesPositions],
656
- service,
657
- zoom,
658
- clampPosition
659
- };
821
+ return service;
660
822
  }, { name: "FlowContext" });
661
823
  //#endregion
662
824
  //#region src/ui/components/Bounds.tsx
@@ -666,24 +828,28 @@ var [Provider, useFlow] = createContext(() => {
666
828
  *
667
829
  * @returns `null` as this component performs side-effect transformer registrations
668
830
  * only.
831
+ *
832
+ * @see {@linkcode useFlow}, {@linkcode BOUNDS_CONSTRAINTS}
669
833
  */
670
834
  var DragBounds = () => {
671
- const { board: [ref], zoom: [zoom] } = useFlow();
835
+ const service = useFlow();
836
+ const zoom = (0, _bemedev_app_solidjs.createState)(service, { selector: ({ context }) => context.zoom });
837
+ const board = (0, _bemedev_app_solidjs.createState)(service, { selector: ({ context }) => context.board });
672
838
  const [state, { addTransformer, removeTransformer, onDragStart, onDragEnd }] = (0, _thisbeyond_solid_dnd.useDragDropContext)();
673
839
  const transformer = {
674
840
  id: "clamp-to-container",
675
841
  order: 100,
676
842
  callback: (transform) => {
677
- const container = ref();
843
+ const container = board()?.self;
678
844
  const activeDraggable = state.active.draggable;
679
845
  if (!container || !activeDraggable) return transform;
680
846
  const node = activeDraggable.node;
681
847
  if (!node) return transform;
682
848
  const currentZoom = zoom();
683
849
  const minBoardX = BOUNDS_CONSTRAINTS.horizontal;
684
- const maxBoardX = Math.max(minBoardX, container.clientWidth / currentZoom - node.offsetWidth - BOUNDS_CONSTRAINTS.horizontal);
850
+ const maxBoardX = Math.max(minBoardX, container.width / currentZoom - node.offsetWidth - BOUNDS_CONSTRAINTS.horizontal);
685
851
  const minBoardY = BOUNDS_CONSTRAINTS.vertical;
686
- const maxBoardY = Math.max(minBoardY, container.clientHeight / currentZoom - node.offsetHeight - BOUNDS_CONSTRAINTS.vertical);
852
+ const maxBoardY = Math.max(minBoardY, container.height / currentZoom - node.offsetHeight - BOUNDS_CONSTRAINTS.vertical);
687
853
  const minTransformX = (minBoardX - node.offsetLeft) * currentZoom;
688
854
  const maxTransformX = (maxBoardX - node.offsetLeft) * currentZoom;
689
855
  const minTransformY = (minBoardY - node.offsetTop) * currentZoom;
@@ -732,6 +898,8 @@ var calculateOffset = (value) => value * 100 / 200;
732
898
  * @param vector - Vector coordinates of type {@linkcode Vector}.
733
899
  *
734
900
  * @returns SVG cubic bezier path string.
901
+ *
902
+ * @see {@linkcode calculateOffset}
735
903
  */
736
904
  var draw = ({ x0, y0, x1, y1 }) => {
737
905
  return `M ${x0} ${y0} C ${x0 + calculateOffset(Math.abs(x1 - x0))} ${y0}, ${x1 - calculateOffset(Math.abs(x1 - x0))} ${y1}, ${x1} ${y1}`;
@@ -743,23 +911,28 @@ var draw = ({ x0, y0, x1, y1 }) => {
743
911
  * @param props - Edge properties of type {@linkcode Props}.
744
912
  *
745
913
  * @returns The rendered SVG JSX elements.
914
+ *
915
+ * @see {@linkcode draw}, {@linkcode useFlow}
746
916
  */
747
917
  var EdgeComponent = (props) => {
748
- const [middlePoint, setMiddlePoint] = (0, solid_js.createSignal)({
749
- x: props.x0 + (props.x1 - props.x0) / 2,
750
- y: props.y0 + (props.y1 - props.y0) / 2
751
- });
752
- const { service } = useFlow();
753
- (0, solid_js.createEffect)(() => {
754
- const middleX = props.x0 + (props.x1 - props.x0) / 2;
755
- const middleY = props.y0 + (props.y1 - props.y0) / 2;
756
- setMiddlePoint({
757
- x: middleX,
758
- y: middleY
759
- });
918
+ const service = useFlow();
919
+ const vector = (0, _bemedev_app_solidjs.createState)(service, {
920
+ selector: ({ context: { newEdge, edgesPositions } }) => {
921
+ if (props.isNew) return newEdge;
922
+ return edgesPositions[props.id];
923
+ },
924
+ equals: dequal.dequal
760
925
  });
761
- const selected = (0, _bemedev_app_solidjs.useState)(service, { selector: (s) => s.context.selected === props.id });
762
- return [(0, solid_js_web.ssr)(_tmpl$$4, (0, solid_js_web.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" : ""}`, (0, solid_js_web.ssrStyleProperty)("pointer-events:", props.isNew ? "none" : "all"), (0, solid_js_web.ssrAttribute)("d", (0, solid_js_web.escape)(draw(props), true), false)), (0, solid_js_web.createComponent)(solid_js.Show, {
926
+ const selected = (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => s.context.selected === props.id });
927
+ /** Computes the 2D midpoint coordinate of the edge curve for handle placement. */
928
+ const middlePoint = () => {
929
+ const v = vector();
930
+ return {
931
+ x: v.x0 + (v.x1 - v.x0) / 2,
932
+ y: v.y0 + (v.y1 - v.y0) / 2
933
+ };
934
+ };
935
+ return [(0, solid_js_web.ssr)(_tmpl$$4, (0, solid_js_web.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" : ""}`, (0, solid_js_web.ssrStyleProperty)("pointer-events:", props.isNew ? "none" : "all"), (0, solid_js_web.ssrAttribute)("d", (0, solid_js_web.escape)(draw(vector()), true), false)), (0, solid_js_web.createComponent)(solid_js.Show, {
763
936
  get when() {
764
937
  return selected();
765
938
  },
@@ -781,44 +954,31 @@ var _tmpl$$3 = [
781
954
  * edge creation previews.
782
955
  *
783
956
  * @returns The rendered SVG JSX element.
957
+ *
958
+ * @see {@linkcode EdgeComponent}, {@linkcode useFlow}
784
959
  */
785
960
  var EdgesBoard = () => {
786
- const [selected, setSelected] = (0, solid_js.createSignal)();
787
- const { newEdge: [newEdge], edgesPositions: [edgesPositions] } = useFlow();
788
- const datas = (0, solid_js.createMemo)(() => {
789
- return Object.entries(edgesPositions()).map(([id, vector]) => ({
790
- id,
791
- ...vector
792
- }));
793
- });
794
- (0, solid_js.createEffect)(() => {
795
- if (selected() && newEdge()) setSelected();
961
+ const service = useFlow();
962
+ const hasNewEdge = (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => !!s.context.newEdge });
963
+ const edgeIds = (0, _bemedev_app_solidjs.createState)(service, {
964
+ selector: ({ context }) => Object.keys(context.edgesPositions),
965
+ equals: (prev, next) => prev.length === next.length
796
966
  });
797
967
  return (0, solid_js_web.ssr)(_tmpl$$3, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.Show, {
798
968
  get when() {
799
- return newEdge();
969
+ return hasNewEdge();
800
970
  },
801
- children: (value) => (0, solid_js_web.createComponent)(EdgeComponent, {
802
- id: "__#new-edge#__TEMP",
803
- isNew: true,
804
- get x0() {
805
- return value().x0;
806
- },
807
- get y0() {
808
- return value().y0;
809
- },
810
- get x1() {
811
- return value().x1;
812
- },
813
- get y1() {
814
- return value().y1;
815
- }
816
- })
971
+ get children() {
972
+ return (0, solid_js_web.createComponent)(EdgeComponent, {
973
+ id: "__#new-edge#__TEMP",
974
+ isNew: true
975
+ });
976
+ }
817
977
  })), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.For, {
818
978
  get each() {
819
- return datas();
979
+ return edgeIds();
820
980
  },
821
- children: EdgeComponent
981
+ children: (id) => (0, solid_js_web.createComponent)(EdgeComponent, { id })
822
982
  })));
823
983
  };
824
984
  //#endregion
@@ -838,11 +998,12 @@ var _tmpl$3$1 = [
838
998
  "<div",
839
999
  " class=\"",
840
1000
  "\" style=\"",
841
- "\"><div class=\"",
1001
+ "\"",
1002
+ "><div class=\"",
842
1003
  "\"><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=\"",
843
1004
  "\"><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><!--$-->",
844
- "<!--/--><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\" style=\"",
845
- "\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"></path></svg></div><!--$-->",
1005
+ "<!--/--><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=\"",
1006
+ "\"><path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"></path></svg></div><!--$-->",
846
1007
  "<!--/--><!--$-->",
847
1008
  "<!--/--><!--$-->",
848
1009
  "<!--/--><div id=\"inputs\" class=\"pointer-events-none absolute top-0 z-10 flex flex-col\" style=\"",
@@ -866,22 +1027,33 @@ var _tmpl$5 = [
866
1027
  * @param props - Node rendering properties of type {@linkcode Props}.
867
1028
  *
868
1029
  * @returns The rendered Solid component.
1030
+ *
1031
+ * @see {@linkcode useFlow}, {@linkcode HANDLE_CONTAINER_OFFSET_X}, {@linkcode HANDLE_MARGIN_TOP}, {@linkcode HANDLE_SIZE}
869
1032
  */
870
1033
  var NodeComponent = (props) => {
871
- const [ref, setRef] = (0, solid_js.createSignal)();
872
- const { dimensions: [dimensions, setDimensions], newEdge: [newEdge, setNewEdge], getBoardPoint, service, zoom: [zoom] } = useFlow();
873
- const selected = (0, _bemedev_app_solidjs.useState)(service, { selector: (s) => s.context.selected === props.id });
874
- (0, solid_js.onMount)(() => {
875
- ref();
876
- zoom();
1034
+ const service = useFlow();
1035
+ const node = (0, _bemedev_app_solidjs.createState)(service, {
1036
+ selector: ({ context }) => {
1037
+ const item = _bemedev_app.toArray.typed(context.data?.nodes).find((n) => n.id === props.id);
1038
+ return {
1039
+ x: item.position.x,
1040
+ y: item.position.y,
1041
+ label: item.data.label,
1042
+ content: item.data.content ?? "",
1043
+ input: item.input
1044
+ };
1045
+ },
1046
+ equals: dequal.dequal
877
1047
  });
878
- const hasParent = (0, _bemedev_app_solidjs.useState)(service, { selector: ({ context: { data } }) => {
1048
+ (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => s.context.newEdge });
1049
+ const selected = (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => s.context.selected === props.id });
1050
+ const hasParent = (0, _bemedev_app_solidjs.createState)(service, { selector: ({ context: { data } }) => {
879
1051
  const edges = data?.edges;
880
1052
  if (!edges) return false;
881
1053
  return edges.some(({ to }) => to === props.id);
882
1054
  } });
883
1055
  (0, _thisbeyond_solid_dnd.createDraggable)(props.id);
884
- return (0, solid_js_web.ssr)(_tmpl$3$1, (0, solid_js_web.ssrHydrationKey)() + (0, solid_js_web.ssrAttribute)("id", (0, solid_js_web.escape)(props.id, true), false), `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`, (0, solid_js_web.ssrStyleProperty)("top:", `${(0, solid_js_web.escape)(props.y, true)}px`) + (0, solid_js_web.ssrStyleProperty)(";left:", `${(0, solid_js_web.escape)(props.x, true)}px`), `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" : ""}`, (0, solid_js_web.ssrStyleProperty)("overflow:", "visible") + (0, solid_js_web.ssrStyleProperty)(";pointer-events:", "all") + (0, solid_js_web.ssrStyleProperty)(";width:", `${(0, solid_js_web.escape)(12, true) * 2}px`) + (0, solid_js_web.ssrStyleProperty)(";height:", `${(0, solid_js_web.escape)(12, true) * 2}px`), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.Show, {
1056
+ return (0, solid_js_web.ssr)(_tmpl$3$1, (0, solid_js_web.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`, (0, solid_js_web.ssrStyleProperty)("top:", `${(0, solid_js_web.escape)(node().y, true)}px`) + (0, solid_js_web.ssrStyleProperty)(";left:", `${(0, solid_js_web.escape)(node().x, true)}px`), (0, solid_js_web.ssrAttribute)("id", (0, solid_js_web.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" : ""}`, (0, solid_js_web.ssrStyleProperty)("overflow:", "visible") + (0, solid_js_web.ssrStyleProperty)(";pointer-events:", "all") + (0, solid_js_web.ssrStyleProperty)(";width:", `${(0, solid_js_web.escape)(12, true) * 2}px`) + (0, solid_js_web.ssrStyleProperty)(";height:", `${(0, solid_js_web.escape)(12, true) * 2}px`), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.Show, {
885
1057
  get when() {
886
1058
  return hasParent();
887
1059
  },
@@ -890,19 +1062,19 @@ var NodeComponent = (props) => {
890
1062
  }
891
1063
  })), (0, solid_js_web.ssrStyleProperty)("pointer-events:", "all") + (0, solid_js_web.ssrStyleProperty)(";width:", `${(0, solid_js_web.escape)(12, true) * 2}px`) + (0, solid_js_web.ssrStyleProperty)(";height:", `${(0, solid_js_web.escape)(12, true) * 2}px`), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.Show, {
892
1064
  get when() {
893
- return props.label;
1065
+ return node().label;
894
1066
  },
895
1067
  keyed: true,
896
1068
  children: (label) => (0, solid_js_web.ssr)(_tmpl$4, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.escape)(label))
897
1069
  })), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.Show, {
898
1070
  get when() {
899
- return props.content;
1071
+ return node().content;
900
1072
  },
901
1073
  keyed: true,
902
1074
  children: (content) => (0, solid_js_web.ssr)(_tmpl$5, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.escape)(content))
903
1075
  })), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.Show, {
904
1076
  get when() {
905
- return props.input || hasParent();
1077
+ return node().input || hasParent();
906
1078
  },
907
1079
  get children() {
908
1080
  return (0, solid_js_web.ssr)(_tmpl$2$1, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.ssrStyleProperty)("left:", `-${(0, solid_js_web.escape)(18, true)}px`), (0, solid_js_web.ssrStyleProperty)("width:", `${(0, solid_js_web.escape)(12, true)}px`) + (0, solid_js_web.ssrStyleProperty)(";height:", `${(0, solid_js_web.escape)(12, true)}px`) + (0, solid_js_web.ssrStyleProperty)(";margin-top:", `${(0, solid_js_web.escape)(12, true)}px`) + (0, solid_js_web.ssrStyleProperty)(";pointer-events:", "all"));
@@ -913,7 +1085,7 @@ var NodeComponent = (props) => {
913
1085
  //#region src/ui/components/NodesBoard.tsx
914
1086
  var _tmpl$$1 = [
915
1087
  "<div",
916
- " class=\"relative h-full w-full overflow-scroll rounded-lg border-2 border-gray-600\"><!--$-->",
1088
+ " class=\"relative h-full w-full overflow-auto rounded-lg border-2 border-gray-600\"><!--$-->",
917
1089
  "<!--/--><div class=\"",
918
1090
  "\" style=\"",
919
1091
  "\"><div class=\"relative h-full w-full\" style=\"",
@@ -937,6 +1109,8 @@ var _tmpl$3 = [
937
1109
  * panning gestures, and rendered nodes/edges.
938
1110
  *
939
1111
  * @returns The rendered Solid component.
1112
+ *
1113
+ * @see {@linkcode DragBounds}, {@linkcode EdgesBoard}, {@linkcode NodeComponent}, {@linkcode useFlow}, {@linkcode CANVAS_FACTOR}, {@linkcode SCROLL_MULTIPLIER}
940
1114
  */
941
1115
  var NodesBoard = () => {
942
1116
  let containerRef;
@@ -946,17 +1120,51 @@ var NodesBoard = () => {
946
1120
  y: 0
947
1121
  });
948
1122
  const [id, setId] = (0, solid_js.createSignal)("");
949
- const [previousZoom, setPreviousZoom] = (0, solid_js.createSignal)();
1123
+ const [ref, setRef] = (0, solid_js.createSignal)();
950
1124
  let percentX = 0;
951
1125
  let percentY = 0;
952
- const { board: [, setRef], service, newEdge: [newEdge], zoom: [zoom, setZoom] } = useFlow();
1126
+ const service = useFlow();
1127
+ (0, _bemedev_app_solidjs.createState)(service, {
1128
+ selector: (s) => s.context.newEdge,
1129
+ equals: dequal.dequal
1130
+ });
1131
+ const zoom = (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => s.context.zoom ?? 1 });
1132
+ /**
1133
+ * Dispatches the current board geometry and parent container dimensions to the
1134
+ * state machine service.
1135
+ */
1136
+ const sendBoard = () => {
1137
+ const el = ref();
1138
+ if (!el) return;
1139
+ const rect = el.getBoundingClientRect();
1140
+ const parent = () => ref()?.parentElement;
1141
+ const payload = {
1142
+ self: {
1143
+ left: rect.left,
1144
+ top: rect.top,
1145
+ width: el.clientWidth,
1146
+ height: el.clientHeight
1147
+ },
1148
+ parent: parent() ? {
1149
+ scrollLeft: parent().scrollLeft,
1150
+ scrollTop: parent().scrollTop,
1151
+ height: parent().clientHeight,
1152
+ width: parent().clientWidth
1153
+ } : void 0
1154
+ };
1155
+ service.send({
1156
+ type: "SET_BOARD",
1157
+ payload
1158
+ });
1159
+ };
953
1160
  (0, solid_js.createEffect)((0, solid_js.on)(zoom, () => {
954
1161
  const maxScrollX = containerRef.scrollWidth - containerRef.clientWidth;
955
1162
  const maxScrollY = containerRef.scrollHeight - containerRef.clientHeight;
956
1163
  if (maxScrollX > 0) containerRef.scrollLeft = percentX * maxScrollX;
957
1164
  if (maxScrollY > 0) containerRef.scrollTop = percentY * maxScrollY;
958
1165
  }, { defer: true }));
959
- const selectedId = (0, _bemedev_app_solidjs.useState)(service, { selector: (s) => s.context?.selected });
1166
+ (0, solid_js.onMount)(sendBoard);
1167
+ const selectedId = (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => s.context?.selected });
960
1168
  /**
961
1169
  * Determines whether the given element ID matches the currently selected entity.
962
1170
  *
@@ -965,23 +1173,18 @@ var NodesBoard = () => {
965
1173
  * @returns `true` if the item is currently selected, otherwise `false`.
966
1174
  */
967
1175
  const selected = (id) => selectedId() === id;
968
- const nodes = (0, _bemedev_app_solidjs.useState)(service, {
969
- selector: (s) => {
970
- return (s.context.data?.nodes ?? []).map((item) => ({
971
- id: item.id,
972
- x: item.position.x,
973
- y: item.position.y,
974
- label: item.data.label,
975
- content: item.data.content ?? "",
976
- input: item.input
977
- }));
1176
+ const nodeIds = (0, _bemedev_app_solidjs.createState)(service, {
1177
+ selector: ({ context }) => {
1178
+ return _bemedev_app.toArray.typed(context.data?.nodes).map((item) => item.id);
978
1179
  },
979
- equals: dequal.dequal
1180
+ equals: (prev, next) => prev.length === next.length
980
1181
  });
981
1182
  const CANVAS_SIZE = 500;
982
1183
  const MARGIN_X = 265;
983
1184
  const MARGIN_Y = 425;
1185
+ /** Computes the dynamic canvas width string in CSS units adjusted for zoom. */
984
1186
  const cWidth = () => `calc((${CANVAS_SIZE}vw - ${MARGIN_X}px) * ${zoom()})`;
1187
+ /** Computes the dynamic canvas height string in CSS units adjusted for zoom. */
985
1188
  const cHeight = () => `calc((${CANVAS_SIZE}vh - ${MARGIN_Y}px) * ${zoom()})`;
986
1189
  return (0, solid_js_web.ssr)(_tmpl$3, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(_thisbeyond_solid_dnd.DragDropProvider, {
987
1190
  onDragMove: ({ draggable: { transform: _transform, node, id } }) => {
@@ -1029,15 +1232,15 @@ var NodesBoard = () => {
1029
1232
  node.style.setProperty("top", Y + "px");
1030
1233
  node.style.setProperty("left", X + "px");
1031
1234
  node.style.removeProperty("transform");
1235
+ service.send({
1236
+ type: "MOVE",
1237
+ payload: {
1238
+ id: `${id}`,
1239
+ x: X,
1240
+ y: Y
1241
+ }
1242
+ });
1032
1243
  setTimeout(() => {
1033
- service.send({
1034
- type: "MOVE",
1035
- payload: {
1036
- id: `${id}`,
1037
- x: X,
1038
- y: Y
1039
- }
1040
- });
1041
1244
  setTransform({
1042
1245
  x: 0,
1043
1246
  y: 0
@@ -1048,9 +1251,9 @@ var NodesBoard = () => {
1048
1251
  return [
1049
1252
  (0, solid_js_web.ssr)(_tmpl$$1, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(_thisbeyond_solid_dnd.DragDropSensors, {})), `relative cursor-crosshair overflow-hidden ${isPanning() ? "cursor-grabbing" : ""}`, (0, solid_js_web.ssrStyleProperty)("height:", (0, solid_js_web.escape)(cHeight(), true)) + (0, solid_js_web.ssrStyleProperty)(";width:", (0, solid_js_web.escape)(cWidth(), true)), (0, solid_js_web.ssrStyleProperty)("scale:", (0, solid_js_web.escape)(zoom(), true)) + (0, solid_js_web.ssrStyleProperty)(";transform-origin:", "top left"), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(DragBounds, {})), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(EdgesBoard, {})), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(solid_js.For, {
1050
1253
  get each() {
1051
- return nodes();
1254
+ return nodeIds();
1052
1255
  },
1053
- children: NodeComponent
1256
+ children: (id) => (0, solid_js_web.createComponent)(NodeComponent, { id })
1054
1257
  }))),
1055
1258
  (0, solid_js_web.ssr)(_tmpl$2, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.escape)(Math.round(zoom() * 100))),
1056
1259
  (0, solid_js_web.createComponent)(solid_js.Show, {
@@ -1081,13 +1284,16 @@ var _tmpl$ = [
1081
1284
  * {@linkcode FlowProps}.
1082
1285
  *
1083
1286
  * @returns The rendered Solid component.
1287
+ *
1288
+ * @see {@linkcode NodesBoard}, {@linkcode useFlow}, {@linkcode DEFAULT_NODES}
1084
1289
  */
1085
1290
  var FlowChart = (props) => {
1086
1291
  const primaryNodes = props.config?.nodes ?? DEFAULT_NODES;
1087
1292
  const primaryEdges = props.config?.edges;
1088
- const { service, newEdge: [newEdge, setNewEdge], getBoardPoint } = useFlow();
1293
+ const service = useFlow();
1294
+ const hasNewEdge = (0, _bemedev_app_solidjs.createState)(service, { selector: (s) => !!s.context.newEdge });
1089
1295
  (0, solid_js.onMount)(() => {
1090
- service.start();
1296
+ service.resume();
1091
1297
  service.send({
1092
1298
  type: "CONFIGURE",
1093
1299
  payload: {
@@ -1096,8 +1302,8 @@ var FlowChart = (props) => {
1096
1302
  }
1097
1303
  });
1098
1304
  });
1099
- (0, solid_js.onCleanup)(service.stop);
1100
- return (0, solid_js_web.ssr)(_tmpl$, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.ssrStyleProperty)("cursor:", newEdge() ? "inherit" : "crosshair") + (0, solid_js_web.ssrStyleProperty)(";background-image:", "radial-gradient(circle, #b8b8b8bf 1px, rgba(0, 0, 0, 0) 1px)"), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(NodesBoard, {})));
1305
+ (0, solid_js.onCleanup)(service.pause);
1306
+ return (0, solid_js_web.ssr)(_tmpl$, (0, solid_js_web.ssrHydrationKey)(), (0, solid_js_web.ssrStyleProperty)("cursor:", hasNewEdge() ? "inherit" : "crosshair") + (0, solid_js_web.ssrStyleProperty)(";background-image:", "radial-gradient(circle, #b8b8b8bf 1px, rgba(0, 0, 0, 0) 1px)"), (0, solid_js_web.escape)((0, solid_js_web.createComponent)(NodesBoard, {})));
1101
1307
  };
1102
1308
  //#endregion
1103
1309
  //#region src/ui/Flow.tsx
@@ -1109,6 +1315,8 @@ var FlowChart = (props) => {
1109
1315
  * {@linkcode FlowProps}.
1110
1316
  *
1111
1317
  * @returns The rendered Solid component.
1318
+ *
1319
+ * @see {@linkcode Provider}
1112
1320
  */
1113
1321
  var Flow = (props) => (0, solid_js_web.createComponent)(Provider, { get children() {
1114
1322
  return (0, solid_js_web.createComponent)(FlowChart, props);