@redvars/peacock 3.5.1 → 3.6.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 (225) hide show
  1. package/dist/{BaseButton-DuASuVth.js → BaseButton-BNFAYn-S.js} +2 -2
  2. package/dist/{BaseButton-DuASuVth.js.map → BaseButton-BNFAYn-S.js.map} +1 -1
  3. package/dist/BaseInput-14YmcfK7.js +27 -0
  4. package/dist/BaseInput-14YmcfK7.js.map +1 -0
  5. package/dist/banner.js +2 -3
  6. package/dist/banner.js.map +1 -1
  7. package/dist/{button-DouvOfEU.js → button-colors-Ccys3hvS.js} +5 -294
  8. package/dist/button-colors-Ccys3hvS.js.map +1 -0
  9. package/dist/button-group.js +226 -6
  10. package/dist/button-group.js.map +1 -1
  11. package/dist/button.js +294 -8
  12. package/dist/button.js.map +1 -1
  13. package/dist/calendar-column-view.js +634 -0
  14. package/dist/calendar-column-view.js.map +1 -0
  15. package/dist/calendar-event-BrQ_SEKD.js +199 -0
  16. package/dist/calendar-event-BrQ_SEKD.js.map +1 -0
  17. package/dist/calendar-month-view.js +376 -0
  18. package/dist/calendar-month-view.js.map +1 -0
  19. package/dist/calendar.js +339 -0
  20. package/dist/calendar.js.map +1 -0
  21. package/dist/canvas.js +361 -0
  22. package/dist/canvas.js.map +1 -0
  23. package/dist/cb-compound-expression.js +125 -0
  24. package/dist/cb-compound-expression.js.map +1 -0
  25. package/dist/cb-divider.js +150 -0
  26. package/dist/cb-divider.js.map +1 -0
  27. package/dist/cb-expression.js +75 -0
  28. package/dist/cb-expression.js.map +1 -0
  29. package/dist/cb-predicate.js +137 -0
  30. package/dist/cb-predicate.js.map +1 -0
  31. package/dist/code-editor.js +2 -1
  32. package/dist/code-editor.js.map +1 -1
  33. package/dist/code-highlighter.js +1 -1
  34. package/dist/code-highlighter.js.map +1 -1
  35. package/dist/condition-builder.js +58 -0
  36. package/dist/condition-builder.js.map +1 -0
  37. package/dist/custom-elements-jsdocs.json +8479 -3965
  38. package/dist/custom-elements.json +15228 -7544
  39. package/dist/dropdown-button.js +216 -0
  40. package/dist/dropdown-button.js.map +1 -0
  41. package/dist/event-manager-D-QCmUgR.js +113 -0
  42. package/dist/event-manager-D-QCmUgR.js.map +1 -0
  43. package/dist/fab.js +1 -1
  44. package/dist/flow-designer-DvTUrDp5.js +1656 -0
  45. package/dist/flow-designer-DvTUrDp5.js.map +1 -0
  46. package/dist/flow-designer-node-BWrPuxAR.js +548 -0
  47. package/dist/flow-designer-node-BWrPuxAR.js.map +1 -0
  48. package/dist/flow-designer-node.js +4 -0
  49. package/dist/flow-designer-node.js.map +1 -0
  50. package/dist/flow-designer.js +16 -0
  51. package/dist/flow-designer.js.map +1 -0
  52. package/dist/html-editor.js +27516 -0
  53. package/dist/html-editor.js.map +1 -0
  54. package/dist/icon-button-CK1ZuE-2.js +247 -0
  55. package/dist/icon-button-CK1ZuE-2.js.map +1 -0
  56. package/dist/index.js +29 -6
  57. package/dist/index.js.map +1 -1
  58. package/dist/{is-dark-mode-DicqGkCJ.js → is-dark-mode-DOcaw4Yq.js} +2 -27
  59. package/dist/is-dark-mode-DOcaw4Yq.js.map +1 -0
  60. package/dist/modal.js +412 -0
  61. package/dist/modal.js.map +1 -0
  62. package/dist/{navigation-rail-Lxetd5-Z.js → navigation-rail-DTTkqohi.js} +1049 -2391
  63. package/dist/navigation-rail-DTTkqohi.js.map +1 -0
  64. package/dist/notification-manager.js +268 -0
  65. package/dist/notification-manager.js.map +1 -0
  66. package/dist/peacock-loader.js +93 -8
  67. package/dist/peacock-loader.js.map +1 -1
  68. package/dist/popover-NC7b1lTq.js +1971 -0
  69. package/dist/popover-NC7b1lTq.js.map +1 -0
  70. package/dist/popover-content.js +125 -0
  71. package/dist/popover-content.js.map +1 -0
  72. package/dist/popover.js +4 -0
  73. package/dist/popover.js.map +1 -0
  74. package/dist/split-button.js +388 -0
  75. package/dist/split-button.js.map +1 -0
  76. package/dist/src/__controllers/floating-controller.d.ts +35 -0
  77. package/dist/src/calendar/base-event.d.ts +10 -0
  78. package/dist/src/calendar/calendar-column-view.d.ts +41 -0
  79. package/dist/src/calendar/calendar-event.d.ts +7 -0
  80. package/dist/src/calendar/calendar-month-view.d.ts +31 -0
  81. package/dist/src/calendar/calendar.d.ts +65 -0
  82. package/dist/src/calendar/event-manager.d.ts +17 -0
  83. package/dist/src/calendar/index.d.ts +4 -0
  84. package/dist/src/calendar/types.d.ts +13 -0
  85. package/dist/src/calendar/utils.d.ts +31 -0
  86. package/dist/src/canvas/canvas.d.ts +92 -0
  87. package/dist/src/canvas/index.d.ts +2 -0
  88. package/dist/src/condition-builder/cb-compound-expression.d.ts +31 -0
  89. package/dist/src/condition-builder/cb-divider.d.ts +26 -0
  90. package/dist/src/condition-builder/cb-expression.d.ts +31 -0
  91. package/dist/src/condition-builder/cb-predicate.d.ts +30 -0
  92. package/dist/src/condition-builder/condition-builder.d.ts +27 -0
  93. package/dist/src/condition-builder/index.d.ts +5 -0
  94. package/dist/src/dropdown-button/dropdown-button.d.ts +68 -0
  95. package/dist/src/dropdown-button/index.d.ts +1 -0
  96. package/dist/src/flow-designer/commands.d.ts +66 -0
  97. package/dist/src/flow-designer/flow-designer-node.d.ts +46 -0
  98. package/dist/src/flow-designer/flow-designer.d.ts +133 -0
  99. package/dist/src/flow-designer/index.d.ts +7 -0
  100. package/dist/src/flow-designer/layout.d.ts +30 -0
  101. package/dist/src/flow-designer/types.d.ts +142 -0
  102. package/dist/src/flow-designer/validation.d.ts +43 -0
  103. package/dist/src/flow-designer/workflow-utils.d.ts +40 -0
  104. package/dist/src/html-editor/html-editor.d.ts +89 -0
  105. package/dist/src/html-editor/index.d.ts +2 -0
  106. package/dist/src/index.d.ts +15 -0
  107. package/dist/src/list/index.d.ts +2 -0
  108. package/dist/src/list/list-item.d.ts +35 -0
  109. package/dist/src/list/list.d.ts +28 -0
  110. package/dist/src/menu/menu/menu.d.ts +5 -7
  111. package/dist/src/menu/menu-item/menu-item.d.ts +14 -13
  112. package/dist/src/modal/index.d.ts +1 -0
  113. package/dist/src/modal/modal.d.ts +57 -0
  114. package/dist/src/navigation-rail/navigation-rail.d.ts +3 -7
  115. package/dist/src/notification-manager/index.d.ts +1 -0
  116. package/dist/src/notification-manager/notification-manager.d.ts +44 -0
  117. package/dist/src/number-field/number-field.d.ts +2 -2
  118. package/dist/src/popover/index.d.ts +2 -0
  119. package/dist/src/popover/popover-content.d.ts +29 -0
  120. package/dist/src/popover/popover.d.ts +62 -0
  121. package/dist/src/split-button/index.d.ts +1 -0
  122. package/dist/src/split-button/split-button.d.ts +72 -0
  123. package/dist/src/svg/index.d.ts +1 -0
  124. package/dist/src/svg/svg.d.ts +38 -0
  125. package/dist/src/toolbar/toolbar.d.ts +3 -3
  126. package/dist/src/tooltip/tooltip.d.ts +2 -15
  127. package/dist/test/flow-designer.test.d.ts +1 -0
  128. package/dist/toolbar.js +3 -3
  129. package/dist/toolbar.js.map +1 -1
  130. package/dist/tsconfig.tsbuildinfo +1 -1
  131. package/package.json +10 -2
  132. package/readme.md +3 -3
  133. package/src/__controllers/floating-controller.ts +237 -0
  134. package/src/banner/banner.scss +2 -3
  135. package/src/button/button/button.ts +1 -0
  136. package/src/calendar/base-event.ts +49 -0
  137. package/src/calendar/calendar-column-view.scss +326 -0
  138. package/src/calendar/calendar-column-view.ts +392 -0
  139. package/src/calendar/calendar-event.ts +20 -0
  140. package/src/calendar/calendar-month-view.scss +192 -0
  141. package/src/calendar/calendar-month-view.ts +244 -0
  142. package/src/calendar/calendar.scss +71 -0
  143. package/src/calendar/calendar.ts +298 -0
  144. package/src/calendar/event-manager.ts +117 -0
  145. package/src/calendar/index.ts +4 -0
  146. package/src/calendar/types.ts +14 -0
  147. package/src/calendar/utils.ts +180 -0
  148. package/src/canvas/canvas.scss +60 -0
  149. package/src/canvas/canvas.ts +391 -0
  150. package/src/canvas/index.ts +2 -0
  151. package/src/code-highlighter/code-highlighter.ts +1 -1
  152. package/src/condition-builder/cb-compound-expression.scss +37 -0
  153. package/src/condition-builder/cb-compound-expression.ts +80 -0
  154. package/src/condition-builder/cb-divider.scss +93 -0
  155. package/src/condition-builder/cb-divider.ts +56 -0
  156. package/src/condition-builder/cb-expression.scss +14 -0
  157. package/src/condition-builder/cb-expression.ts +49 -0
  158. package/src/condition-builder/cb-predicate.scss +35 -0
  159. package/src/condition-builder/cb-predicate.ts +102 -0
  160. package/src/condition-builder/condition-builder.scss +13 -0
  161. package/src/condition-builder/condition-builder.ts +38 -0
  162. package/src/condition-builder/index.ts +5 -0
  163. package/src/dropdown-button/demo/index.html +110 -0
  164. package/src/dropdown-button/dropdown-button.scss +22 -0
  165. package/src/dropdown-button/dropdown-button.ts +206 -0
  166. package/src/dropdown-button/index.ts +1 -0
  167. package/src/flow-designer/DEMO.md +239 -0
  168. package/src/flow-designer/commands.ts +278 -0
  169. package/src/flow-designer/flow-designer-node.ts +172 -0
  170. package/src/flow-designer/flow-designer.scss +457 -0
  171. package/src/flow-designer/flow-designer.ts +611 -0
  172. package/src/flow-designer/index.ts +41 -0
  173. package/src/flow-designer/layout.ts +357 -0
  174. package/src/flow-designer/types.ts +166 -0
  175. package/src/flow-designer/validation.ts +284 -0
  176. package/src/flow-designer/workflow-utils.ts +282 -0
  177. package/src/html-editor/html-editor.scss +188 -0
  178. package/src/html-editor/html-editor.ts +491 -0
  179. package/src/html-editor/index.ts +3 -0
  180. package/src/index.ts +27 -1
  181. package/src/list/index.ts +2 -0
  182. package/src/list/list-item.scss +111 -0
  183. package/src/list/list-item.ts +175 -0
  184. package/src/list/list.scss +24 -0
  185. package/src/list/list.ts +51 -0
  186. package/src/menu/menu/menu.scss +2 -2
  187. package/src/menu/menu/menu.ts +91 -101
  188. package/src/menu/menu-item/menu-item.scss +4 -0
  189. package/src/menu/menu-item/menu-item.ts +82 -78
  190. package/src/modal/index.ts +1 -0
  191. package/src/modal/modal.scss +206 -0
  192. package/src/modal/modal.ts +195 -0
  193. package/src/navigation-rail/navigation-rail-item.scss +7 -38
  194. package/src/navigation-rail/navigation-rail-item.ts +1 -2
  195. package/src/navigation-rail/navigation-rail.scss +17 -21
  196. package/src/navigation-rail/navigation-rail.ts +6 -9
  197. package/src/notification-manager/index.ts +1 -0
  198. package/src/notification-manager/notification-manager.scss +113 -0
  199. package/src/notification-manager/notification-manager.ts +199 -0
  200. package/src/number-field/number-field.ts +2 -2
  201. package/src/peacock-loader.ts +83 -0
  202. package/src/popover/index.ts +2 -0
  203. package/src/popover/popover-content.scss +69 -0
  204. package/src/popover/popover-content.ts +51 -0
  205. package/src/popover/popover.scss +7 -0
  206. package/src/popover/popover.ts +170 -0
  207. package/src/split-button/index.ts +1 -0
  208. package/src/split-button/split-button-colors.scss +56 -0
  209. package/src/split-button/split-button-sizes.scss +28 -0
  210. package/src/split-button/split-button.scss +79 -0
  211. package/src/split-button/split-button.ts +236 -0
  212. package/src/svg/index.ts +1 -0
  213. package/src/svg/svg.scss +91 -0
  214. package/src/svg/svg.ts +160 -0
  215. package/src/table/table.ts +2 -2
  216. package/src/toolbar/toolbar.ts +3 -3
  217. package/src/tooltip/tooltip.scss +4 -3
  218. package/src/tooltip/tooltip.ts +46 -104
  219. package/dist/button-DouvOfEU.js.map +0 -1
  220. package/dist/button-group-CEdMwvJJ.js +0 -464
  221. package/dist/button-group-CEdMwvJJ.js.map +0 -1
  222. package/dist/is-dark-mode-DicqGkCJ.js.map +0 -1
  223. package/dist/navigation-rail-Lxetd5-Z.js.map +0 -1
  224. package/dist/src/menu/menu/MenuSurfaceController.d.ts +0 -18
  225. package/src/menu/menu/MenuSurfaceController.ts +0 -61
@@ -0,0 +1,357 @@
1
+ import type { WorkflowNode, PositionedNode, SwimlaneConfig } from './types.js';
2
+ import { getAllNodes } from './workflow-utils.js';
3
+
4
+ /**
5
+ * Swimlane layout algorithm for flow designer
6
+ * Positions nodes in left-to-right swimlanes for parallel/branching flows
7
+ */
8
+
9
+ interface LayoutNode {
10
+ node: WorkflowNode;
11
+ parent: WorkflowNode | null;
12
+ lane: string;
13
+ depth: number;
14
+ branchPath?: string;
15
+ width: number;
16
+ height: number;
17
+ }
18
+
19
+ const NODE_WIDTH = 200;
20
+ const NODE_HEIGHT = 100;
21
+ const HORIZONTAL_GAP = 60; // Gap between depth levels (columns)
22
+ const VERTICAL_GAP = 40; // Gap between lanes
23
+ const LANE_HEIGHT = 140; // Height of each swimlane row
24
+ const LANE_HEADER_HEIGHT = 84; // Top offset so first row is not clipped by floating UI
25
+
26
+ export class SwimlaneLayout {
27
+ /**
28
+ * Calculate layout positions for all nodes in a workflow
29
+ */
30
+ static calculateLayout(rootNode: WorkflowNode): PositionedNode[] {
31
+ const layoutNodes: LayoutNode[] = [];
32
+ const lanes = new Map<string, LayoutNode[]>(); // lane -> nodes in that lane
33
+ const depthMap = new Map<string, number>(); // Track max depth per lane
34
+
35
+ // First pass: assign lanes and depths
36
+ this._traverseAndAssignLanes(rootNode, null, 'main', 0, layoutNodes, lanes);
37
+
38
+ // Second pass: calculate positions
39
+ const positionedNodes: PositionedNode[] = [];
40
+ const nodePositions = new Map<string, { x: number; y: number }>();
41
+
42
+ for (const layoutNode of layoutNodes) {
43
+ const x =
44
+ layoutNode.depth * (NODE_WIDTH + HORIZONTAL_GAP) + HORIZONTAL_GAP;
45
+ const laneIndex = Array.from(lanes.keys()).indexOf(layoutNode.lane);
46
+ const y = laneIndex * (LANE_HEIGHT + VERTICAL_GAP) + LANE_HEADER_HEIGHT;
47
+
48
+ nodePositions.set(layoutNode.node.id, { x, y });
49
+
50
+ const positioned: PositionedNode = {
51
+ node: layoutNode.node,
52
+ x,
53
+ y,
54
+ width: NODE_WIDTH,
55
+ height: NODE_HEIGHT,
56
+ lane: layoutNode.lane,
57
+ depth: layoutNode.depth,
58
+ branchPath: layoutNode.branchPath,
59
+ parentId: layoutNode.parent?.id,
60
+ connectorPoints: [],
61
+ };
62
+
63
+ positionedNodes.push(positioned);
64
+ }
65
+
66
+ // Third pass: calculate connector points
67
+ this._calculateConnectors(positionedNodes, nodePositions);
68
+
69
+ return positionedNodes;
70
+ }
71
+
72
+ /**
73
+ * Traverse workflow tree and assign lane/depth to each node
74
+ */
75
+ private static _traverseAndAssignLanes(
76
+ node: WorkflowNode,
77
+ parent: WorkflowNode | null,
78
+ baseLane: string,
79
+ depth: number,
80
+ layoutNodes: LayoutNode[],
81
+ lanes: Map<string, LayoutNode[]>
82
+ ): void {
83
+ const layoutNode: LayoutNode = {
84
+ node,
85
+ parent,
86
+ lane: baseLane,
87
+ depth,
88
+ width: NODE_WIDTH,
89
+ height: NODE_HEIGHT,
90
+ };
91
+
92
+ // Add to layout nodes
93
+ layoutNodes.push(layoutNode);
94
+
95
+ // Register in lanes map
96
+ if (!lanes.has(baseLane)) {
97
+ lanes.set(baseLane, []);
98
+ }
99
+ lanes.get(baseLane)!.push(layoutNode);
100
+
101
+ // Process children
102
+ if (node.children && node.children.length > 0) {
103
+ for (const child of node.children) {
104
+ this._traverseAndAssignLanes(
105
+ child,
106
+ node,
107
+ baseLane,
108
+ depth + 1,
109
+ layoutNodes,
110
+ lanes
111
+ );
112
+ }
113
+ }
114
+
115
+ // Process decision branches into separate swimlanes
116
+ if (node.branches) {
117
+ let branchIndex = 0;
118
+ for (const [branchKey, branchNodes] of Object.entries(node.branches)) {
119
+ const branchLane = `${baseLane}_${branchKey}_${branchIndex}`;
120
+
121
+ for (const branchNode of branchNodes) {
122
+ this._traverseAndAssignLanes(
123
+ branchNode,
124
+ node,
125
+ branchLane,
126
+ depth + 1,
127
+ layoutNodes,
128
+ lanes
129
+ );
130
+ }
131
+ branchIndex++;
132
+ }
133
+ }
134
+
135
+ // Process fork into parallel lanes
136
+ if (node.type === 'fork' && node.tasks) {
137
+ let taskIndex = 0;
138
+ for (const task of node.tasks) {
139
+ const parallelLane = `${baseLane}_parallel_${taskIndex}`;
140
+ this._traverseAndAssignLanes(
141
+ task,
142
+ node,
143
+ parallelLane,
144
+ depth + 1,
145
+ layoutNodes,
146
+ lanes
147
+ );
148
+ taskIndex++;
149
+ }
150
+ }
151
+
152
+ // Process fork join node
153
+ if (node.type === 'fork' && node.join) {
154
+ // Join node goes back to main lane at next depth
155
+ this._traverseAndAssignLanes(
156
+ node.join,
157
+ node,
158
+ baseLane,
159
+ depth + 2,
160
+ layoutNodes,
161
+ lanes
162
+ );
163
+ }
164
+
165
+ // Process task nodes (used in forks)
166
+ if (node.tasks && node.type !== 'fork') {
167
+ for (const task of node.tasks) {
168
+ this._traverseAndAssignLanes(
169
+ task,
170
+ node,
171
+ baseLane,
172
+ depth + 1,
173
+ layoutNodes,
174
+ lanes
175
+ );
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Calculate SVG connector points between nodes
182
+ */
183
+ private static _calculateConnectors(
184
+ positionedNodes: PositionedNode[],
185
+ nodePositions: Map<string, { x: number; y: number }>
186
+ ): void {
187
+ const nodeMap = new Map<string, PositionedNode>(
188
+ positionedNodes.map((n) => [n.node.id, n])
189
+ );
190
+
191
+ for (const positioned of positionedNodes) {
192
+ const connectors: PositionedNode['connectorPoints'] = [];
193
+ const nodeMiddleRight = {
194
+ x: positioned.x + positioned.width,
195
+ y: positioned.y + positioned.height / 2,
196
+ };
197
+
198
+ // Connect to children (sequential)
199
+ if (positioned.node.children && positioned.node.children.length > 0) {
200
+ for (const child of positioned.node.children) {
201
+ const childPos = nodeMap.get(child.id);
202
+ if (childPos) {
203
+ connectors.push({
204
+ from: nodeMiddleRight,
205
+ to: {
206
+ x: childPos.x,
207
+ y: childPos.y + childPos.height / 2,
208
+ },
209
+ type: 'straight',
210
+ });
211
+ }
212
+ }
213
+ }
214
+
215
+ // Connect to branches (decision)
216
+ if (positioned.node.branches) {
217
+ for (const branchNodes of Object.values(positioned.node.branches)) {
218
+
219
+ for (const branchNode of branchNodes) {
220
+ const childPos = nodeMap.get(branchNode.id);
221
+ if (childPos) {
222
+ // Curved path to branch
223
+ connectors.push({
224
+ from: nodeMiddleRight,
225
+ to: {
226
+ x: childPos.x,
227
+ y: childPos.y + childPos.height / 2,
228
+ },
229
+ type: 'branch',
230
+ });
231
+ }
232
+ }
233
+ }
234
+ }
235
+
236
+ // Connect fork to parallel tasks
237
+ if (positioned.node.type === 'fork' && positioned.node.tasks) {
238
+ for (const task of positioned.node.tasks) {
239
+ const taskPos = nodeMap.get(task.id);
240
+ if (taskPos) {
241
+ connectors.push({
242
+ from: nodeMiddleRight,
243
+ to: {
244
+ x: taskPos.x,
245
+ y: taskPos.y + taskPos.height / 2,
246
+ },
247
+ type: 'fork',
248
+ });
249
+ }
250
+ }
251
+ }
252
+
253
+ // Connect to join
254
+ if (positioned.node.type === 'fork' && positioned.node.join) {
255
+ const joinPos = nodeMap.get(positioned.node.join.id);
256
+ if (joinPos) {
257
+ connectors.push({
258
+ from: nodeMiddleRight,
259
+ to: {
260
+ x: joinPos.x,
261
+ y: joinPos.y + joinPos.height / 2,
262
+ },
263
+ type: 'join',
264
+ });
265
+ }
266
+ }
267
+
268
+ // Connect loop back
269
+ if (positioned.node.type === 'loop_end' && positioned.node.target_id) {
270
+ const targetPos = nodeMap.get(positioned.node.target_id);
271
+ if (targetPos) {
272
+ connectors.push({
273
+ from: {
274
+ x: positioned.x + positioned.width,
275
+ y: positioned.y + positioned.height / 2,
276
+ },
277
+ to: {
278
+ x: targetPos.x,
279
+ y: targetPos.y + targetPos.height / 2,
280
+ },
281
+ type: 'curved',
282
+ });
283
+ }
284
+ }
285
+
286
+ positioned.connectorPoints = connectors;
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Get swimlane configurations for rendering
292
+ */
293
+ static getSwimlanes(positionedNodes: PositionedNode[]): SwimlaneConfig[] {
294
+ const swimlanesMap = new Map<string, PositionedNode[]>();
295
+
296
+ for (const node of positionedNodes) {
297
+ if (!swimlanesMap.has(node.lane)) {
298
+ swimlanesMap.set(node.lane, []);
299
+ }
300
+ swimlanesMap.get(node.lane)!.push(node);
301
+ }
302
+
303
+ const swimlanes: SwimlaneConfig[] = [];
304
+ for (const [laneId, nodes] of swimlanesMap.entries()) {
305
+ const isParallel = laneId.includes('parallel');
306
+ const name = this._getSwimlaneName(laneId);
307
+
308
+ swimlanes.push({
309
+ id: laneId,
310
+ name,
311
+ nodes,
312
+ isParallel,
313
+ });
314
+ }
315
+
316
+ return swimlanes;
317
+ }
318
+
319
+ /**
320
+ * Generate human-readable swimlane name
321
+ */
322
+ private static _getSwimlaneName(laneId: string): string {
323
+ if (laneId === 'main') return 'Main Flow';
324
+ if (laneId.includes('yes')) return 'Yes Path';
325
+ if (laneId.includes('no')) return 'No Path';
326
+ if (laneId.includes('parallel')) {
327
+ const match = laneId.match(/parallel_(\d+)/);
328
+ if (match) return `Parallel Task ${parseInt(match[1]) + 1}`;
329
+ }
330
+ return laneId;
331
+ }
332
+
333
+ /**
334
+ * Calculate canvas bounds for sizing
335
+ */
336
+ static getCanvasBounds(positionedNodes: PositionedNode[]): {
337
+ width: number;
338
+ height: number;
339
+ } {
340
+ if (positionedNodes.length === 0) {
341
+ return { width: 600, height: 400 };
342
+ }
343
+
344
+ let maxX = 0;
345
+ let maxY = 0;
346
+
347
+ for (const node of positionedNodes) {
348
+ maxX = Math.max(maxX, node.x + node.width + HORIZONTAL_GAP);
349
+ maxY = Math.max(maxY, node.y + node.height + VERTICAL_GAP);
350
+ }
351
+
352
+ return {
353
+ width: Math.max(600, maxX),
354
+ height: Math.max(400, maxY),
355
+ };
356
+ }
357
+ }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Workflow Data Types for Flow Designer
3
+ * Defines the structure for low-code business process workflows
4
+ */
5
+
6
+ /**
7
+ * Supported node types in a workflow
8
+ */
9
+ export type NodeType =
10
+ | 'trigger'
11
+ | 'action'
12
+ | 'decision'
13
+ | 'loop_start'
14
+ | 'loop_end'
15
+ | 'fork'
16
+ | 'join';
17
+
18
+ /**
19
+ * Payload for workflow-changed event
20
+ */
21
+ export interface WorkflowChangeEvent {
22
+ type:
23
+ | 'node-added'
24
+ | 'node-deleted'
25
+ | 'node-edited'
26
+ | 'node-moved'
27
+ | 'undo'
28
+ | 'redo';
29
+ nodeId?: string;
30
+ workflow: Workflow;
31
+ }
32
+
33
+ /**
34
+ * Core workflow node structure
35
+ */
36
+ export interface WorkflowNode {
37
+ id: string;
38
+ type: NodeType;
39
+ label: string;
40
+ description?: string;
41
+ icon?: string;
42
+ /**
43
+ * For sequential nodes in parallel execution (fork tasks)
44
+ */
45
+ tasks?: WorkflowNode[];
46
+ /**
47
+ * For conditional branching (decision nodes)
48
+ * Keys are branch conditions like "yes", "no"
49
+ */
50
+ branches?: Record<string, WorkflowNode[]>;
51
+ /**
52
+ * Child nodes for sequential flow
53
+ */
54
+ children?: WorkflowNode[];
55
+ /**
56
+ * For loop_end: points to the loop_start node id to repeat
57
+ */
58
+ target_id?: string;
59
+ /**
60
+ * For fork: join node that collects parallel paths
61
+ */
62
+ join?: WorkflowNode;
63
+ /**
64
+ * Custom metadata - can store domain-specific data
65
+ */
66
+ metadata?: Record<string, any>;
67
+ }
68
+
69
+ /**
70
+ * Complete workflow definition
71
+ */
72
+ export interface Workflow {
73
+ workflow_id: string;
74
+ nodes: WorkflowNode; // Root node (usually trigger)
75
+ metadata?: Record<string, any>;
76
+ }
77
+
78
+ /**
79
+ * Layout engine output - node with calculated position
80
+ */
81
+ export interface PositionedNode {
82
+ node: WorkflowNode;
83
+ x: number; // Pixel X coordinate
84
+ y: number; // Pixel Y coordinate
85
+ width: number; // Node card width
86
+ height: number; // Node card height
87
+ lane: string; // Swimlane identifier (e.g., "yes_lane", "no_lane", "parallel_0")
88
+ depth: number; // Horizontal depth in layout
89
+ branchPath?: string; // For connectors: "yes" or "no" or branch name
90
+ parentId?: string; // Reference to parent node id
91
+ connectorPoints?: {
92
+ // For canvas connector rendering
93
+ from: { x: number; y: number };
94
+ to: { x: number; y: number };
95
+ type: 'straight' | 'curved' | 'branch' | 'fork' | 'join';
96
+ }[];
97
+ }
98
+
99
+ /**
100
+ * Validation error result
101
+ */
102
+ export interface ValidationError {
103
+ nodeId: string;
104
+ type:
105
+ | 'circular_loop'
106
+ | 'orphaned_node'
107
+ | 'invalid_branch'
108
+ | 'missing_target'
109
+ | 'invalid_fork_join';
110
+ message: string;
111
+ severity: 'error' | 'warning';
112
+ }
113
+
114
+ /**
115
+ * State for a single undo/redo operation
116
+ */
117
+ export interface HistoryEntry {
118
+ command: WorkflowCommand;
119
+ workflow: Workflow;
120
+ timestamp: number;
121
+ }
122
+
123
+ /**
124
+ * Command interface for undo/redo pattern
125
+ */
126
+ export interface WorkflowCommand {
127
+ execute(workflow: Workflow): Workflow;
128
+ undo(workflow: Workflow): Workflow;
129
+ description: string;
130
+ }
131
+
132
+ /**
133
+ * Swimlane configuration
134
+ */
135
+ export interface SwimlaneConfig {
136
+ id: string;
137
+ name: string;
138
+ nodes: PositionedNode[];
139
+ isParallel: boolean;
140
+ }
141
+
142
+ /**
143
+ * Editor state
144
+ */
145
+ export interface EditorState {
146
+ selectedNodeId: string | null;
147
+ isEditing: boolean;
148
+ editingNode: Partial<WorkflowNode> | null;
149
+ hoveredNodeId: string | null;
150
+ isDragging: boolean;
151
+ draggedNodeId: string | null;
152
+ zoom: number;
153
+ panX: number;
154
+ panY: number;
155
+ }
156
+
157
+ /**
158
+ * Node template configuration for slots
159
+ */
160
+ export interface NodeTemplate {
161
+ type: NodeType;
162
+ defaultIcon?: string;
163
+ defaultHeight?: number;
164
+ allowedChildren?: NodeType[];
165
+ allowedBranches?: string[];
166
+ }