@bemedev/mind-flow 0.3.2 → 1.0.0

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