@flowuent-org/diagramming-core 1.3.10 → 1.4.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 (677) hide show
  1. package/.editorconfig +13 -13
  2. package/.eslintignore +1 -1
  3. package/.eslintrc.json +35 -35
  4. package/.prettierignore +3 -3
  5. package/.prettierrc +3 -3
  6. package/.vscode/settings.json +6 -6
  7. package/README.md +95 -95
  8. package/apps/authentication/tsconfig.app.json +23 -23
  9. package/apps/authentication/tsconfig.json +21 -21
  10. package/apps/authentication/tsconfig.spec.json +28 -28
  11. package/apps/diagramming/.eslintrc.json +18 -18
  12. package/apps/diagramming/index.html +16 -16
  13. package/apps/diagramming/project.json +53 -53
  14. package/apps/diagramming/public/aws-icons/compute/App Runner.svg +17 -17
  15. package/apps/diagramming/public/aws-icons/compute/Application Auto Scaling.svg +17 -17
  16. package/apps/diagramming/public/aws-icons/compute/Batch.svg +17 -17
  17. package/apps/diagramming/public/aws-icons/compute/Bottlerocket.svg +19 -19
  18. package/apps/diagramming/public/aws-icons/compute/Compute Optimizer.svg +17 -17
  19. package/apps/diagramming/public/aws-icons/compute/EC2 Auto Scaling.svg +17 -17
  20. package/apps/diagramming/public/aws-icons/compute/EC2 Image Builder.svg +17 -17
  21. package/apps/diagramming/public/aws-icons/compute/EC2.svg +17 -17
  22. package/apps/diagramming/public/aws-icons/compute/Elastic Beanstalk.svg +17 -17
  23. package/apps/diagramming/public/aws-icons/compute/Elastic Fabric Adapter.svg +17 -17
  24. package/apps/diagramming/public/aws-icons/compute/Fargate.svg +19 -19
  25. package/apps/diagramming/public/aws-icons/compute/Genomics CLI.svg +17 -17
  26. package/apps/diagramming/public/aws-icons/compute/Lambda.svg +17 -17
  27. package/apps/diagramming/public/aws-icons/compute/Local Zones.svg +17 -17
  28. package/apps/diagramming/public/aws-icons/compute/NICE DCV.svg +17 -17
  29. package/apps/diagramming/public/aws-icons/compute/NICE EnginFrame.svg +17 -17
  30. package/apps/diagramming/public/aws-icons/compute/Nitro Enclaves.svg +17 -17
  31. package/apps/diagramming/public/aws-icons/compute/Outposts family.svg +17 -17
  32. package/apps/diagramming/public/aws-icons/compute/Outposts rack.svg +17 -17
  33. package/apps/diagramming/public/aws-icons/compute/Outposts servers.svg +17 -17
  34. package/apps/diagramming/public/aws-icons/compute/ParallelCluster.svg +17 -17
  35. package/apps/diagramming/public/aws-icons/compute/Serverless Application Repository.svg +17 -17
  36. package/apps/diagramming/public/aws-icons/compute/SimSpace Weaver.svg +17 -17
  37. package/apps/diagramming/public/aws-icons/compute/Thinkbox Deadline.svg +17 -17
  38. package/apps/diagramming/public/aws-icons/compute/Thinkbox Frost.svg +17 -17
  39. package/apps/diagramming/public/aws-icons/compute/Thinkbox Sequoia.svg +17 -17
  40. package/apps/diagramming/public/aws-icons/compute/Thinkbox Stoke.svg +17 -17
  41. package/apps/diagramming/public/aws-icons/compute/Thinkbox XMesh.svg +17 -17
  42. package/apps/diagramming/public/aws-icons/compute/VMware Cloud on AWS.svg +17 -17
  43. package/apps/diagramming/public/aws-icons/compute/Wavelength.svg +17 -17
  44. package/apps/diagramming/public/aws-icons/container/ECS Anywhere.svg +17 -17
  45. package/apps/diagramming/public/aws-icons/container/EKS Anywhere.svg +17 -17
  46. package/apps/diagramming/public/aws-icons/container/EKS Cloud.svg +17 -17
  47. package/apps/diagramming/public/aws-icons/container/EKS Distro.svg +17 -17
  48. package/apps/diagramming/public/aws-icons/container/Elastic Container Registry.svg +17 -17
  49. package/apps/diagramming/public/aws-icons/container/Elastic Container Service.svg +17 -17
  50. package/apps/diagramming/public/aws-icons/container/Elastic Kubernetes Service.svg +17 -17
  51. package/apps/diagramming/public/aws-icons/container/Fargate.svg +19 -19
  52. package/apps/diagramming/public/aws-icons/container/Red Hat OpenShift Service on AWS.svg +17 -17
  53. package/apps/diagramming/public/aws-icons/database/Aurora.svg +17 -17
  54. package/apps/diagramming/public/aws-icons/database/Database Migration Service.svg +17 -17
  55. package/apps/diagramming/public/aws-icons/database/DocumentDB.svg +17 -17
  56. package/apps/diagramming/public/aws-icons/database/ElastiCache.svg +17 -17
  57. package/apps/diagramming/public/aws-icons/database/Keyspaces.svg +15 -15
  58. package/apps/diagramming/public/aws-icons/database/MemoryDB for Redis.svg +17 -17
  59. package/apps/diagramming/public/aws-icons/database/Neptune.svg +17 -17
  60. package/apps/diagramming/public/aws-icons/database/RDS on VMware.svg +17 -17
  61. package/apps/diagramming/public/aws-icons/database/RDS.svg +17 -17
  62. package/apps/diagramming/public/aws-icons/database/Timestream.svg +17 -17
  63. package/apps/diagramming/public/aws-icons/networking/App Mesh.svg +17 -17
  64. package/apps/diagramming/public/aws-icons/networking/Client VPN.svg +17 -17
  65. package/apps/diagramming/public/aws-icons/networking/Cloud Directory.svg +17 -17
  66. package/apps/diagramming/public/aws-icons/networking/Cloud Map.svg +17 -17
  67. package/apps/diagramming/public/aws-icons/networking/Cloud WAN.svg +17 -17
  68. package/apps/diagramming/public/aws-icons/networking/CloudFront.svg +17 -17
  69. package/apps/diagramming/public/aws-icons/networking/Direct Connect.svg +17 -17
  70. package/apps/diagramming/public/aws-icons/networking/Elastic Load Balancing.svg +17 -17
  71. package/apps/diagramming/public/aws-icons/networking/Global Accelerator.svg +17 -17
  72. package/apps/diagramming/public/aws-icons/networking/Private 5G.svg +17 -17
  73. package/apps/diagramming/public/aws-icons/networking/PrivateLink.svg +17 -17
  74. package/apps/diagramming/public/aws-icons/networking/Route 53.svg +17 -17
  75. package/apps/diagramming/public/aws-icons/networking/Site to Site VPN.svg +17 -17
  76. package/apps/diagramming/public/aws-icons/networking/Transit Gateway.svg +17 -17
  77. package/apps/diagramming/public/aws-icons/networking/VPC Lattice.svg +17 -17
  78. package/apps/diagramming/public/aws-icons/networking/Verified Access.svg +17 -17
  79. package/apps/diagramming/public/aws-icons/networking/Virtual Private Cloud.svg +17 -17
  80. package/apps/diagramming/public/aws-icons/security/Artifact.svg +17 -17
  81. package/apps/diagramming/public/aws-icons/security/Audit Manager.svg +17 -17
  82. package/apps/diagramming/public/aws-icons/security/Certificate Manager.svg +17 -17
  83. package/apps/diagramming/public/aws-icons/security/CloudHSM.svg +17 -17
  84. package/apps/diagramming/public/aws-icons/security/Cognito.svg +17 -17
  85. package/apps/diagramming/public/aws-icons/security/Detective.svg +17 -17
  86. package/apps/diagramming/public/aws-icons/security/Directory Service.svg +17 -17
  87. package/apps/diagramming/public/aws-icons/security/Firewall Manager.svg +17 -17
  88. package/apps/diagramming/public/aws-icons/security/GuardDuty.svg +17 -17
  89. package/apps/diagramming/public/aws-icons/security/IAM Identity Center.svg +17 -17
  90. package/apps/diagramming/public/aws-icons/security/Identity and Access Management.svg +17 -17
  91. package/apps/diagramming/public/aws-icons/security/Inspector.svg +17 -17
  92. package/apps/diagramming/public/aws-icons/security/Key Management Service.svg +17 -17
  93. package/apps/diagramming/public/aws-icons/security/Macie.svg +17 -17
  94. package/apps/diagramming/public/aws-icons/security/Network Firewall.svg +17 -17
  95. package/apps/diagramming/public/aws-icons/security/Resource Access Manager.svg +17 -17
  96. package/apps/diagramming/public/aws-icons/security/Secrets Manager.svg +17 -17
  97. package/apps/diagramming/public/aws-icons/security/Security Hub.svg +17 -17
  98. package/apps/diagramming/public/aws-icons/security/Security Lake.svg +17 -17
  99. package/apps/diagramming/public/aws-icons/security/Shield.svg +17 -17
  100. package/apps/diagramming/public/aws-icons/security/Signer.svg +17 -17
  101. package/apps/diagramming/public/aws-icons/security/Verified Permissions.svg +17 -17
  102. package/apps/diagramming/public/aws-icons/security/WAF.svg +17 -17
  103. package/apps/diagramming/public/aws-icons/storage/Backup.svg +17 -17
  104. package/apps/diagramming/public/aws-icons/storage/EFS.svg +17 -17
  105. package/apps/diagramming/public/aws-icons/storage/Elastic Block Store.svg +17 -17
  106. package/apps/diagramming/public/aws-icons/storage/Elastic Disaster Recovery.svg +15 -15
  107. package/apps/diagramming/public/aws-icons/storage/FSx for Lustre.svg +17 -17
  108. package/apps/diagramming/public/aws-icons/storage/FSx for NetApp ONTAP.svg +17 -17
  109. package/apps/diagramming/public/aws-icons/storage/FSx for OpenZFS.svg +17 -17
  110. package/apps/diagramming/public/aws-icons/storage/FSx for WFS.svg +17 -17
  111. package/apps/diagramming/public/aws-icons/storage/FSx.svg +17 -17
  112. package/apps/diagramming/public/aws-icons/storage/File Cache.svg +17 -17
  113. package/apps/diagramming/public/aws-icons/storage/S3 on Outposts.svg +17 -17
  114. package/apps/diagramming/public/aws-icons/storage/Simple Storage Service Glacier.svg +17 -17
  115. package/apps/diagramming/public/aws-icons/storage/Simple Storage Service.svg +17 -17
  116. package/apps/diagramming/public/aws-icons/storage/Snowball Edge.svg +17 -17
  117. package/apps/diagramming/public/aws-icons/storage/Snowball.svg +17 -17
  118. package/apps/diagramming/public/aws-icons/storage/Snowcone.svg +17 -17
  119. package/apps/diagramming/public/aws-icons/storage/Snowmobile.svg +17 -17
  120. package/apps/diagramming/public/aws-icons/storage/Storage Gateway.svg +17 -17
  121. package/apps/diagramming/public/azure-icons/compute/02112-icon-service-Automanaged-VM.svg +1 -1
  122. package/apps/diagramming/public/azure-icons/databases/02390-icon-service-Azure-SQL.svg +1 -1
  123. package/apps/diagramming/public/azure-icons/databases/02392-icon-service-SSIS-Lift-And-Shift-IR.svg +1 -1
  124. package/apps/diagramming/public/azure-icons/networking/02145-icon-service-Resource-Management-Private-Link.svg +1 -1
  125. package/apps/diagramming/public/azure-icons/security/02247-icon-service-Microsoft-Defender-for-IoT.svg +1 -1
  126. package/apps/diagramming/public/sample-node-complete.json +63 -63
  127. package/apps/diagramming/public/sample-node-data.json +63 -63
  128. package/apps/diagramming/src/AutomationDiagramData.ts +147 -480
  129. package/apps/diagramming/src/CollaborationDiagramData.ts +127 -127
  130. package/apps/diagramming/src/CustomIconExamples.ts +233 -233
  131. package/apps/diagramming/src/DiagramTabs.tsx +205 -205
  132. package/apps/diagramming/src/Pages/DevPlayground.tsx +3 -3
  133. package/apps/diagramming/src/Pages/Home.tsx +111 -111
  134. package/apps/diagramming/src/SequenceDiagramData.ts +215 -215
  135. package/apps/diagramming/src/StateMachineDiagramData.ts +64 -64
  136. package/apps/diagramming/src/UseCaseDiagramData.ts +52 -52
  137. package/apps/diagramming/src/cloud-data.ts +371 -371
  138. package/apps/diagramming/src/components/AddNodeView.tsx +252 -252
  139. package/apps/diagramming/src/createSelecors.tsx +17 -17
  140. package/apps/diagramming/src/index.scss +12 -12
  141. package/apps/diagramming/src/main.tsx +463 -463
  142. package/apps/diagramming/src/node-data.ts +664 -664
  143. package/apps/diagramming/src/sample-workflow-content.ts +55 -55
  144. package/apps/diagramming/src/stencil-items.ts +31 -31
  145. package/apps/diagramming/src/style.css +13 -13
  146. package/apps/diagramming/src/tabsStore.tsx +152 -152
  147. package/apps/diagramming/src/vite-env.d.ts +1 -1
  148. package/apps/diagramming/tsconfig.app.json +23 -23
  149. package/apps/diagramming/tsconfig.json +21 -21
  150. package/apps/diagramming/tsconfig.spec.json +28 -28
  151. package/apps/diagramming/vite.config.ts +34 -34
  152. package/apps/diagramming/webpack.config.js +13 -13
  153. package/apps/workflow/.eslintrc.json +18 -18
  154. package/apps/workflow/group/group-form-hooks/index.ts +3 -3
  155. package/apps/workflow/group/group-form-hooks/useFormValidation.ts +20 -20
  156. package/apps/workflow/group/group-form-schema/SettingsTabFormSchema.ts +7 -7
  157. package/apps/workflow/group/group-form-schema/index.ts +3 -3
  158. package/apps/workflow/i18n.ts +19 -19
  159. package/apps/workflow/index.html +16 -16
  160. package/apps/workflow/locales/en/translation.json +713 -713
  161. package/apps/workflow/project.json +8 -8
  162. package/apps/workflow/src/app/app.module.css +1 -1
  163. package/apps/workflow/src/app/app.spec.tsx +15 -15
  164. package/apps/workflow/src/app/app.tsx +370 -370
  165. package/apps/workflow/src/main.tsx +13 -13
  166. package/apps/workflow/src/styles.css +1 -1
  167. package/apps/workflow/src/theme/index.ts +546 -546
  168. package/apps/workflow/tsconfig.app.json +23 -23
  169. package/apps/workflow/tsconfig.json +21 -21
  170. package/apps/workflow/tsconfig.spec.json +28 -28
  171. package/apps/workflow/vite.config.ts +51 -51
  172. package/nx.json +58 -58
  173. package/package.json +1 -1
  174. package/packages/api/.babelrc +12 -12
  175. package/packages/api/.eslintrc.json +18 -18
  176. package/packages/api/README.md +7 -7
  177. package/packages/api/project.json +8 -8
  178. package/packages/api/src/index.ts +3 -3
  179. package/packages/api/src/lib/jsonPlaceholderService/endpoints.ts +3 -3
  180. package/packages/api/src/lib/jsonPlaceholderService/service.ts +13 -13
  181. package/packages/api/tsconfig.json +17 -17
  182. package/packages/api/tsconfig.lib.json +24 -24
  183. package/packages/atoms/.babelrc +12 -12
  184. package/packages/atoms/.eslintrc.json +18 -18
  185. package/packages/atoms/README.md +7 -7
  186. package/packages/atoms/forms/AuthenticationTabForm/authenticationTabForm.json +224 -224
  187. package/packages/atoms/forms/AuthenticationTabForm/index.tsx +255 -255
  188. package/packages/atoms/forms/SettingsTabForm/index.tsx +85 -85
  189. package/packages/atoms/forms/SettingsTabForm/settingTabForm.json +27 -27
  190. package/packages/atoms/forms/index.ts +4 -4
  191. package/packages/atoms/project.json +8 -8
  192. package/packages/atoms/src/index.ts +33 -33
  193. package/packages/atoms/src/lib/Accordion/Accordion.module.css +7 -7
  194. package/packages/atoms/src/lib/Accordion/Accordion.spec.tsx +13 -13
  195. package/packages/atoms/src/lib/Accordion/Accordion.tsx +29 -29
  196. package/packages/atoms/src/lib/Alert/Alert.module.css +7 -7
  197. package/packages/atoms/src/lib/Alert/Alert.spec.tsx +10 -10
  198. package/packages/atoms/src/lib/Alert/Alert.tsx +19 -19
  199. package/packages/atoms/src/lib/Avatar/Avatar.module.css +7 -7
  200. package/packages/atoms/src/lib/Avatar/Avatar.spec.tsx +10 -10
  201. package/packages/atoms/src/lib/Avatar/Avatar.tsx +22 -22
  202. package/packages/atoms/src/lib/Box/Box.module.css +7 -7
  203. package/packages/atoms/src/lib/Box/Box.spec.tsx +10 -10
  204. package/packages/atoms/src/lib/Box/Box.tsx +19 -19
  205. package/packages/atoms/src/lib/BulkEdit/BulkEdit.module.css +7 -7
  206. package/packages/atoms/src/lib/BulkEdit/BulkEdit.spec.tsx +10 -10
  207. package/packages/atoms/src/lib/BulkEdit/BulkEdit.tsx +15 -15
  208. package/packages/atoms/src/lib/Button/Button.module.css +7 -7
  209. package/packages/atoms/src/lib/Button/Button.spec.tsx +10 -10
  210. package/packages/atoms/src/lib/Button/Button.tsx +78 -78
  211. package/packages/atoms/src/lib/Card/Card.module.css +7 -7
  212. package/packages/atoms/src/lib/Card/Card.spec.tsx +10 -10
  213. package/packages/atoms/src/lib/Card/Card.tsx +19 -19
  214. package/packages/atoms/src/lib/CardContent/CardContent.module.css +7 -7
  215. package/packages/atoms/src/lib/CardContent/CardContent.spec.tsx +10 -10
  216. package/packages/atoms/src/lib/CardContent/CardContent.tsx +22 -22
  217. package/packages/atoms/src/lib/FormTextField/FormTextField.module.css +7 -7
  218. package/packages/atoms/src/lib/FormTextField/FormTextField.spec.tsx +10 -10
  219. package/packages/atoms/src/lib/FormTextField/FormTextField.tsx +35 -35
  220. package/packages/atoms/src/lib/Grid/Grid.module.css +7 -7
  221. package/packages/atoms/src/lib/Grid/Grid.spec.tsx +10 -10
  222. package/packages/atoms/src/lib/Grid/Grid.tsx +19 -19
  223. package/packages/atoms/src/lib/Stack/Stack.module.css +7 -7
  224. package/packages/atoms/src/lib/Stack/Stack.spec.tsx +10 -10
  225. package/packages/atoms/src/lib/Stack/Stack.tsx +19 -19
  226. package/packages/atoms/src/lib/Switch/Switch.module.css +7 -7
  227. package/packages/atoms/src/lib/Switch/Switch.spec.tsx +10 -10
  228. package/packages/atoms/src/lib/Switch/Switch.tsx +46 -46
  229. package/packages/atoms/src/lib/TableView/TableView.module.css +7 -7
  230. package/packages/atoms/src/lib/TableView/TableView.spec.tsx +10 -10
  231. package/packages/atoms/src/lib/TableView/TableView.tsx +88 -88
  232. package/packages/atoms/src/lib/TextField/TextField.module.css +7 -7
  233. package/packages/atoms/src/lib/TextField/TextField.spec.tsx +10 -10
  234. package/packages/atoms/src/lib/TextField/TextField.tsx +17 -17
  235. package/packages/atoms/src/lib/Typography/Typography.module.css +7 -7
  236. package/packages/atoms/src/lib/Typography/Typography.spec.tsx +10 -10
  237. package/packages/atoms/src/lib/Typography/Typography.tsx +22 -22
  238. package/packages/atoms/tsconfig.json +17 -17
  239. package/packages/atoms/tsconfig.lib.json +30 -30
  240. package/packages/common/.babelrc +12 -12
  241. package/packages/common/.eslintrc.json +18 -18
  242. package/packages/common/README.md +7 -7
  243. package/packages/common/project.json +8 -8
  244. package/packages/common/src/index.ts +4 -4
  245. package/packages/common/src/lib/generateRandomProfilePic.ts +3 -3
  246. package/packages/common/src/lib/generateValidationSchema.ts +46 -46
  247. package/packages/common/tsconfig.json +17 -17
  248. package/packages/common/tsconfig.lib.json +24 -24
  249. package/packages/contexts/.babelrc +12 -12
  250. package/packages/contexts/.eslintrc.json +18 -18
  251. package/packages/contexts/README.md +7 -7
  252. package/packages/contexts/project.json +8 -8
  253. package/packages/contexts/src/index.ts +2 -2
  254. package/packages/contexts/tsconfig.json +17 -17
  255. package/packages/contexts/tsconfig.lib.json +24 -24
  256. package/packages/diagrams/.babelrc +12 -12
  257. package/packages/diagrams/.ctirc +208 -208
  258. package/packages/diagrams/.eslintrc.json +17 -17
  259. package/packages/diagrams/CUSTOM_ICONS.md +232 -232
  260. package/packages/diagrams/GOOGLE_SHEETS_IMPLEMENTATION.md +233 -233
  261. package/packages/diagrams/NODE_DATA_UPDATE_API.md +430 -430
  262. package/packages/diagrams/README.md +7 -7
  263. package/packages/diagrams/UNDO_REDO_API.md +306 -306
  264. package/packages/diagrams/locales/en/translation.json +713 -713
  265. package/packages/diagrams/package.json +27 -27
  266. package/packages/diagrams/pnpm-lock.yaml +2606 -2606
  267. package/packages/diagrams/project.json +42 -42
  268. package/packages/diagrams/rollup.config.js +26 -26
  269. package/packages/diagrams/src/DiagramFlow.tsx +7 -7
  270. package/packages/diagrams/src/declarations.d.ts +7 -7
  271. package/packages/diagrams/src/index.ts +8 -1
  272. package/packages/diagrams/src/index.ts.bak +99 -99
  273. package/packages/diagrams/src/lib/assets/markers/markers.param.tsx +101 -101
  274. package/packages/diagrams/src/lib/assets/markers/markers.type.ts +10 -10
  275. package/packages/diagrams/src/lib/atoms/ActorNode.tsx +123 -123
  276. package/packages/diagrams/src/lib/atoms/AddParallelColButton.tsx +26 -26
  277. package/packages/diagrams/src/lib/atoms/BendpointNode.tsx +71 -71
  278. package/packages/diagrams/src/lib/atoms/CardBlockTypeSelector.tsx +35 -35
  279. package/packages/diagrams/src/lib/atoms/CardEditableTitle.tsx +76 -76
  280. package/packages/diagrams/src/lib/atoms/CardMainContent.tsx +19 -19
  281. package/packages/diagrams/src/lib/atoms/ConnectionPoints.tsx +149 -149
  282. package/packages/diagrams/src/lib/atoms/ContentAssist.tsx +341 -341
  283. package/packages/diagrams/src/lib/atoms/DiagramControls.tsx +56 -56
  284. package/packages/diagrams/src/lib/atoms/ExpressionInput.tsx +437 -437
  285. package/packages/diagrams/src/lib/atoms/FloatingConnectionLine.tsx +73 -73
  286. package/packages/diagrams/src/lib/atoms/LazyIcon.tsx +31 -31
  287. package/packages/diagrams/src/lib/atoms/MarkerSelector.tsx +106 -106
  288. package/packages/diagrams/src/lib/atoms/MultiSelectInput.tsx +87 -87
  289. package/packages/diagrams/src/lib/atoms/ParameterInput.tsx +199 -199
  290. package/packages/diagrams/src/lib/atoms/PropertyInput.tsx +114 -114
  291. package/packages/diagrams/src/lib/atoms/StyledBox.tsx +69 -69
  292. package/packages/diagrams/src/lib/atoms/ValidationError.tsx +37 -37
  293. package/packages/diagrams/src/lib/atoms/ValidationMessage.tsx +63 -63
  294. package/packages/diagrams/src/lib/components/AiButton.tsx +52 -52
  295. package/packages/diagrams/src/lib/components/ControlEdgeList.tsx +303 -303
  296. package/packages/diagrams/src/lib/components/CreateFunctionModal.tsx +264 -264
  297. package/packages/diagrams/src/lib/components/CustomCodeModal.tsx +287 -287
  298. package/packages/diagrams/src/lib/components/DiagramPanel.tsx +331 -331
  299. package/packages/diagrams/src/lib/components/FunctionModalTooltip.tsx +30 -30
  300. package/packages/diagrams/src/lib/components/GraphQLCustomCodeModal.tsx +210 -210
  301. package/packages/diagrams/src/lib/components/Header.tsx +143 -143
  302. package/packages/diagrams/src/lib/components/MiniMapCommon.tsx +24 -24
  303. package/packages/diagrams/src/lib/components/ResizeIcon.tsx +81 -81
  304. package/packages/diagrams/src/lib/components/SideBar.tsx +40 -40
  305. package/packages/diagrams/src/lib/components/automation/AISuggestionsModal.tsx +269 -269
  306. package/packages/diagrams/src/lib/components/automation/AISuggestionsPanel.tsx +28 -175
  307. package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +1 -1
  308. package/packages/diagrams/src/lib/components/automation/AutomationDecisionNode.tsx +94 -0
  309. package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +1 -1
  310. package/packages/diagrams/src/lib/components/automation/AutomationExecutionPanel.tsx +439 -439
  311. package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +1 -1
  312. package/packages/diagrams/src/lib/components/automation/AutomationInteractionNode.tsx +693 -693
  313. package/packages/diagrams/src/lib/components/automation/AutomationMonitoringNode.tsx +399 -399
  314. package/packages/diagrams/src/lib/components/automation/AutomationNavigationNode.tsx +1 -1
  315. package/packages/diagrams/src/lib/components/automation/AutomationNodeCard.tsx +414 -0
  316. package/packages/diagrams/src/lib/components/automation/AutomationSlackNode.tsx +694 -694
  317. package/packages/diagrams/src/lib/components/automation/AutomationSmsNode.tsx +62 -0
  318. package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +1 -1
  319. package/packages/diagrams/src/lib/components/automation/AutomationTelegramNode.tsx +664 -664
  320. package/packages/diagrams/src/lib/components/automation/AutomationVoiceCallNode.tsx +65 -0
  321. package/packages/diagrams/src/lib/components/automation/AutomationWorkflowNode.tsx +85 -0
  322. package/packages/diagrams/src/lib/components/automation/NodeAIAssistantPopup.tsx +504 -504
  323. package/packages/diagrams/src/lib/components/automation/index.ts +29 -19
  324. package/packages/diagrams/src/lib/components/automation/statusColors.ts +124 -124
  325. package/packages/diagrams/src/lib/contexts/CardDataProvider.tsx +111 -111
  326. package/packages/diagrams/src/lib/contexts/DiagramProvider.tsx +392 -391
  327. package/packages/diagrams/src/lib/contexts/diagramStoreTypes.tsx +134 -134
  328. package/packages/diagrams/src/lib/contexts/onConnect.ts +39 -39
  329. package/packages/diagrams/src/lib/contexts/onDragStart.ts +45 -45
  330. package/packages/diagrams/src/lib/contexts/onNodeDragEnd.ts +179 -179
  331. package/packages/diagrams/src/lib/contexts/onNodesChange.ts +406 -406
  332. package/packages/diagrams/src/lib/contexts/onReconnect.ts +59 -59
  333. package/packages/diagrams/src/lib/contexts/onWorkflowNodeDelete.ts +65 -65
  334. package/packages/diagrams/src/lib/contexts/setContentHeight.ts +14 -14
  335. package/packages/diagrams/src/lib/contexts/setDiagramType.ts +10 -10
  336. package/packages/diagrams/src/lib/contexts/setEdgeShapeType.ts +7 -7
  337. package/packages/diagrams/src/lib/contexts/setEdges.ts +9 -9
  338. package/packages/diagrams/src/lib/contexts/setLayoutDirection.ts +9 -9
  339. package/packages/diagrams/src/lib/contexts/setNodeSetting.ts +17 -17
  340. package/packages/diagrams/src/lib/contexts/setNodes.ts +10 -10
  341. package/packages/diagrams/src/lib/contexts/setPannable.ts +7 -7
  342. package/packages/diagrams/src/lib/contexts/setSelectedEdge.ts +7 -7
  343. package/packages/diagrams/src/lib/contexts/setSelectedNode.ts +7 -7
  344. package/packages/diagrams/src/lib/contexts/undo.ts +163 -163
  345. package/packages/diagrams/src/lib/contexts/updateNodeSetting.ts +17 -17
  346. package/packages/diagrams/src/lib/examples/TwilioWhatsAppConfigExample.ts +128 -128
  347. package/packages/diagrams/src/lib/externals.ts +4 -4
  348. package/packages/diagrams/src/lib/hooks/customUseReactFlow.tsx +90 -90
  349. package/packages/diagrams/src/lib/hooks/updateNodes.ts +45 -45
  350. package/packages/diagrams/src/lib/hooks/useAddChildButton.tsx +61 -61
  351. package/packages/diagrams/src/lib/hooks/useAddSwitchCase.ts +75 -75
  352. package/packages/diagrams/src/lib/hooks/useAutoRegisterFunctions.ts +135 -135
  353. package/packages/diagrams/src/lib/hooks/useAutoRegisterVariables.ts +286 -286
  354. package/packages/diagrams/src/lib/hooks/useDeleteNodeByEvent.ts +64 -64
  355. package/packages/diagrams/src/lib/hooks/useDragCallbacks.tsx +122 -122
  356. package/packages/diagrams/src/lib/hooks/useFormValidation.ts +349 -349
  357. package/packages/diagrams/src/lib/hooks/useFunctionFormCallbacks.ts +136 -136
  358. package/packages/diagrams/src/lib/hooks/useIsSelectedNode.ts +11 -11
  359. package/packages/diagrams/src/lib/hooks/useModalControls.ts +13 -13
  360. package/packages/diagrams/src/lib/hooks/useNodeDragHandlers.ts +43 -43
  361. package/packages/diagrams/src/lib/hooks/useNodeSelection.ts +55 -55
  362. package/packages/diagrams/src/lib/hooks/useRenderDividers.tsx +19 -19
  363. package/packages/diagrams/src/lib/hooks/useRenderPins.tsx +74 -74
  364. package/packages/diagrams/src/lib/hooks/useResizeObserver.ts +21 -21
  365. package/packages/diagrams/src/lib/hooks/useTreeChildNode.ts +536 -536
  366. package/packages/diagrams/src/lib/i18n.ts +42 -42
  367. package/packages/diagrams/src/lib/icons/icons.tsx +324 -0
  368. package/packages/diagrams/src/lib/icons/index.ts +29 -0
  369. package/packages/diagrams/src/lib/icons/types.ts +7 -0
  370. package/packages/diagrams/src/lib/molecules/AddingBlock.tsx +147 -147
  371. package/packages/diagrams/src/lib/molecules/AvailableVariablesDisplay.tsx +57 -57
  372. package/packages/diagrams/src/lib/molecules/Block.tsx +143 -143
  373. package/packages/diagrams/src/lib/molecules/BlockProvider.tsx +28 -28
  374. package/packages/diagrams/src/lib/molecules/BlockWrapper.tsx +14 -14
  375. package/packages/diagrams/src/lib/molecules/ConditionRule.tsx +131 -131
  376. package/packages/diagrams/src/lib/molecules/DraggablePane.tsx +198 -198
  377. package/packages/diagrams/src/lib/molecules/EntityNodeBlocks.tsx +66 -66
  378. package/packages/diagrams/src/lib/molecules/SideHandles.tsx +215 -215
  379. package/packages/diagrams/src/lib/molecules/StencilItem.tsx +85 -85
  380. package/packages/diagrams/src/lib/molecules/WorkflowNodeActionButtons.tsx +62 -62
  381. package/packages/diagrams/src/lib/molecules/animated-add-button.tsx +83 -83
  382. package/packages/diagrams/src/lib/molecules/json-viewer.tsx +107 -107
  383. package/packages/diagrams/src/lib/organisms/AddNodeView.tsx +102 -102
  384. package/packages/diagrams/src/lib/organisms/Card/EntityNode.tsx +259 -259
  385. package/packages/diagrams/src/lib/organisms/Card/card.params.ts +29 -29
  386. package/packages/diagrams/src/lib/organisms/Card/card.types.ts +5 -5
  387. package/packages/diagrams/src/lib/organisms/CodeModal.tsx +105 -105
  388. package/packages/diagrams/src/lib/organisms/ConditionRuleGroup.tsx +138 -138
  389. package/packages/diagrams/src/lib/organisms/CustomEdge/EdgeMarkers.tsx +51 -51
  390. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge-generator.tsx +135 -135
  391. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge.params.ts +6 -6
  392. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge.type.ts +15 -15
  393. package/packages/diagrams/src/lib/organisms/CustomEdge/useCreateBendPoint.tsx +121 -121
  394. package/packages/diagrams/src/lib/organisms/CustomEdge/useEdgeModal.ts +37 -37
  395. package/packages/diagrams/src/lib/organisms/CustomEdge/useEdgePath.tsx +99 -99
  396. package/packages/diagrams/src/lib/organisms/DownloadPanel.tsx +345 -345
  397. package/packages/diagrams/src/lib/organisms/EdgeModal.tsx +243 -243
  398. package/packages/diagrams/src/lib/organisms/HistoryPane.tsx +118 -118
  399. package/packages/diagrams/src/lib/organisms/NodeContextMenu.tsx +259 -259
  400. package/packages/diagrams/src/lib/organisms/PropertiesPane.tsx +276 -276
  401. package/packages/diagrams/src/lib/organisms/SmartDynamicForm.tsx +226 -226
  402. package/packages/diagrams/src/lib/organisms/Stencil.tsx +60 -60
  403. package/packages/diagrams/src/lib/organisms/UseDiagramStore.tsx +4 -4
  404. package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeActionButtons.tsx +45 -45
  405. package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeTypeDisplay.tsx +114 -114
  406. package/packages/diagrams/src/lib/organisms/WorkFlowNode/WorkflowNodeIcons.tsx +21 -23
  407. package/packages/diagrams/src/lib/organisms/WorkflowNode.tsx +484 -484
  408. package/packages/diagrams/src/lib/services/GoogleSheetsService.ts +961 -961
  409. package/packages/diagrams/src/lib/services/SlackService.ts +134 -134
  410. package/packages/diagrams/src/lib/services/TwilioWhatsAppService.ts +273 -273
  411. package/packages/diagrams/src/lib/styles.css +55 -55
  412. package/packages/diagrams/src/lib/templates/PageLinks.tsx +13 -13
  413. package/packages/diagrams/src/lib/templates/arch/ArchDiagram.tsx +793 -793
  414. package/packages/diagrams/src/lib/templates/arch/components/EdgeDialog.tsx +82 -82
  415. package/packages/diagrams/src/lib/templates/arch/components/EdgeSettings.tsx +81 -81
  416. package/packages/diagrams/src/lib/templates/arch/components/GroupControls.tsx +59 -59
  417. package/packages/diagrams/src/lib/templates/arch/components/GroupSizeDialog.tsx +81 -81
  418. package/packages/diagrams/src/lib/templates/arch/components/NodeDialog.tsx +214 -214
  419. package/packages/diagrams/src/lib/templates/arch/components/nodeTypes.ts +91 -91
  420. package/packages/diagrams/src/lib/templates/arch/controls/ArchDiagramControls.tsx +349 -349
  421. package/packages/diagrams/src/lib/templates/arch/data/templatee-data.ts +212 -212
  422. package/packages/diagrams/src/lib/templates/cloud-arch/components/CloudArchitectureDiagram.tsx +3912 -3912
  423. package/packages/diagrams/src/lib/templates/cloud-arch/components/FormatConverter.tsx +809 -809
  424. package/packages/diagrams/src/lib/templates/cloud-arch/components/FragmentImporter.tsx +276 -276
  425. package/packages/diagrams/src/lib/templates/cloud-arch/components/PropertiesPanel.tsx +1063 -1063
  426. package/packages/diagrams/src/lib/templates/cloud-arch/components/ServiceIconPicker.tsx +138 -138
  427. package/packages/diagrams/src/lib/templates/cloud-arch/components/SettingsSidebar.tsx +656 -656
  428. package/packages/diagrams/src/lib/templates/cloud-arch/components/SubnetSelector.tsx +468 -468
  429. package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/ServiceNode.tsx +310 -310
  430. package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/SubnetNode.tsx +475 -475
  431. package/packages/diagrams/src/lib/templates/cloud-arch/components/nodes/UsersNode.tsx +277 -277
  432. package/packages/diagrams/src/lib/templates/cloud-arch/data/diagramManager.ts +364 -364
  433. package/packages/diagrams/src/lib/templates/cloud-arch/data/types.ts +183 -183
  434. package/packages/diagrams/src/lib/templates/cloud-arch/integration/diagramValidator.ts +379 -379
  435. package/packages/diagrams/src/lib/templates/cloud-arch/messages/errorMessages.json +95 -95
  436. package/packages/diagrams/src/lib/templates/cloud-arch/types/localization.ts +368 -368
  437. package/packages/diagrams/src/lib/templates/cloud-arch/types/validation.ts +72 -72
  438. package/packages/diagrams/src/lib/templates/cloud-arch/utils/aws-icons.ts +557 -557
  439. package/packages/diagrams/src/lib/templates/cloud-arch/utils/awsValidation.ts +446 -446
  440. package/packages/diagrams/src/lib/templates/cloud-arch/utils/azure-icons.ts +802 -802
  441. package/packages/diagrams/src/lib/templates/cloud-arch/utils/azureValidation.ts +495 -495
  442. package/packages/diagrams/src/lib/templates/cloud-arch/utils/cloudValidation.ts +929 -929
  443. package/packages/diagrams/src/lib/templates/cloud-arch/utils/errorMessages.ts +283 -283
  444. package/packages/diagrams/src/lib/templates/cloud-arch/utils/gcp-icons.ts +186 -186
  445. package/packages/diagrams/src/lib/templates/cloud-arch/utils/gcpValidation.ts +312 -312
  446. package/packages/diagrams/src/lib/templates/cloud-arch/utils/genericValidation.ts +689 -689
  447. package/packages/diagrams/src/lib/templates/cloud-arch/utils/iconMapping.ts +383 -383
  448. package/packages/diagrams/src/lib/templates/cloud-arch/utils/idGenerator.ts +220 -220
  449. package/packages/diagrams/src/lib/templates/cloud-arch/utils/localizationManager.ts +300 -300
  450. package/packages/diagrams/src/lib/templates/cloud-arch/utils/restrictionEngine.ts +550 -550
  451. package/packages/diagrams/src/lib/templates/cloud-arch/utils/restrictionValidator.ts +400 -400
  452. package/packages/diagrams/src/lib/templates/cloud-arch/utils/serviceIcons.tsx +129 -129
  453. package/packages/diagrams/src/lib/templates/cloud-arch/utils/serviceMapping.ts +330 -330
  454. package/packages/diagrams/src/lib/templates/cloud-arch/utils/translations.ts +54 -54
  455. package/packages/diagrams/src/lib/templates/cloud-arch/utils/validationExtractor.ts +342 -342
  456. package/packages/diagrams/src/lib/templates/collaborationDiagram/CollaborationDiagram.tsx +15 -15
  457. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/AddCollabEdgeDialog.tsx +181 -181
  458. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollabLayout.ts +182 -182
  459. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollabObjectNodeSettings.tsx +86 -86
  460. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/CollaborationDiagramFlow.tsx +731 -731
  461. package/packages/diagrams/src/lib/templates/collaborationDiagram/components/DraggableEdgeLabel.tsx +123 -123
  462. package/packages/diagrams/src/lib/templates/collaborationDiagram/controls/CollaborationControls.tsx +131 -131
  463. package/packages/diagrams/src/lib/templates/collaborationDiagram/nodes/CollabEdge.tsx +170 -170
  464. package/packages/diagrams/src/lib/templates/collaborationDiagram/nodes/CollabObjectNode.tsx +178 -178
  465. package/packages/diagrams/src/lib/templates/home.style.css +16 -16
  466. package/packages/diagrams/src/lib/templates/node-forms/ApiForm.tsx +416 -416
  467. package/packages/diagrams/src/lib/templates/node-forms/CallForm.tsx +370 -370
  468. package/packages/diagrams/src/lib/templates/node-forms/ForLoopNode.tsx +313 -313
  469. package/packages/diagrams/src/lib/templates/node-forms/FunctionForm.tsx +211 -211
  470. package/packages/diagrams/src/lib/templates/node-forms/GraphQLForm.tsx +679 -679
  471. package/packages/diagrams/src/lib/templates/node-forms/IfNodeForm.tsx +97 -97
  472. package/packages/diagrams/src/lib/templates/node-forms/LetNodeForm.tsx +533 -533
  473. package/packages/diagrams/src/lib/templates/node-forms/LoopNode.tsx +149 -149
  474. package/packages/diagrams/src/lib/templates/node-forms/NodeForm.tsx +383 -383
  475. package/packages/diagrams/src/lib/templates/node-forms/ReturnNodeForm.tsx +96 -96
  476. package/packages/diagrams/src/lib/templates/node-forms/SetNodeForm.tsx +141 -141
  477. package/packages/diagrams/src/lib/templates/node-forms/SwitchNodeForm.tsx +249 -249
  478. package/packages/diagrams/src/lib/templates/node-forms/TryCatchForm.tsx +167 -167
  479. package/packages/diagrams/src/lib/templates/nodeFormSchema.json +84 -84
  480. package/packages/diagrams/src/lib/templates/sequence/SequenceDiagram.tsx +22 -22
  481. package/packages/diagrams/src/lib/templates/sequence/components/ActivationBarNode.tsx +33 -33
  482. package/packages/diagrams/src/lib/templates/sequence/components/AddMessageDialog.tsx +302 -302
  483. package/packages/diagrams/src/lib/templates/sequence/components/CombinedFragmentNode.tsx +65 -65
  484. package/packages/diagrams/src/lib/templates/sequence/components/EntitySettings.tsx +559 -559
  485. package/packages/diagrams/src/lib/templates/sequence/components/FragmentSettings.tsx +116 -116
  486. package/packages/diagrams/src/lib/templates/sequence/components/SequenceComponents.tsx +14 -14
  487. package/packages/diagrams/src/lib/templates/sequence/components/SequenceDiagramFlow.tsx +1361 -1361
  488. package/packages/diagrams/src/lib/templates/sequence/components/SequenceEntityNode.tsx +394 -394
  489. package/packages/diagrams/src/lib/templates/sequence/components/SequenceMessageEdge.tsx +272 -272
  490. package/packages/diagrams/src/lib/templates/sequence/components/SimpleEntitySettings.tsx +89 -89
  491. package/packages/diagrams/src/lib/templates/sequence/controls/DiagramControls.tsx +707 -707
  492. package/packages/diagrams/src/lib/templates/sequence/data/template-data.ts +635 -635
  493. package/packages/diagrams/src/lib/templates/stateMachine/StateMachineDiagram.tsx +66 -66
  494. package/packages/diagrams/src/lib/templates/stateMachine/components/CompositeStateNodeSettings.tsx +638 -638
  495. package/packages/diagrams/src/lib/templates/stateMachine/components/CustomEdge.tsx +220 -220
  496. package/packages/diagrams/src/lib/templates/stateMachine/components/EdgeSettings.tsx +193 -193
  497. package/packages/diagrams/src/lib/templates/stateMachine/components/SelfConnectingEdge.tsx +41 -41
  498. package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineComponents.tsx +49 -49
  499. package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineDiagramFlow.tsx +1238 -1238
  500. package/packages/diagrams/src/lib/templates/stateMachine/components/StateMachineLayout.ts +350 -350
  501. package/packages/diagrams/src/lib/templates/stateMachine/components/StateNodeSettings.tsx +188 -188
  502. package/packages/diagrams/src/lib/templates/stateMachine/components/useSelfTransition.ts +114 -114
  503. package/packages/diagrams/src/lib/templates/stateMachine/controls/StateDiagramControls.tsx +488 -488
  504. package/packages/diagrams/src/lib/templates/stateMachine/data/template-data.ts +4 -4
  505. package/packages/diagrams/src/lib/templates/stateMachine/nodes/ChoicePointNode.tsx +54 -54
  506. package/packages/diagrams/src/lib/templates/stateMachine/nodes/CompositeStateNode.tsx +225 -225
  507. package/packages/diagrams/src/lib/templates/stateMachine/nodes/EntryPointNode.tsx +31 -31
  508. package/packages/diagrams/src/lib/templates/stateMachine/nodes/ExitPointNode.tsx +44 -44
  509. package/packages/diagrams/src/lib/templates/stateMachine/nodes/FinalStateNode.tsx +41 -41
  510. package/packages/diagrams/src/lib/templates/stateMachine/nodes/ForkJoinNode.tsx +53 -53
  511. package/packages/diagrams/src/lib/templates/stateMachine/nodes/HistoryStateNode.tsx +36 -36
  512. package/packages/diagrams/src/lib/templates/stateMachine/nodes/InitialStateNode.tsx +29 -29
  513. package/packages/diagrams/src/lib/templates/stateMachine/nodes/JunctionPointNode.tsx +33 -33
  514. package/packages/diagrams/src/lib/templates/stateMachine/nodes/PinPointNode.tsx +111 -111
  515. package/packages/diagrams/src/lib/templates/stateMachine/nodes/StateNode.tsx +124 -124
  516. package/packages/diagrams/src/lib/templates/stateMachine/nodes/bendPoint.tsx +71 -71
  517. package/packages/diagrams/src/lib/templates/systemFlow/SystemFlowDiagram.tsx +67 -67
  518. package/packages/diagrams/src/lib/templates/systemFlow/components/EdgeSettings.tsx +330 -330
  519. package/packages/diagrams/src/lib/templates/systemFlow/components/FloatingEdge.tsx +219 -219
  520. package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowComponents.tsx +28 -28
  521. package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowDiagramFlow.tsx +1179 -1179
  522. package/packages/diagrams/src/lib/templates/systemFlow/components/SystemFlowNodeSettings.tsx +151 -151
  523. package/packages/diagrams/src/lib/templates/systemFlow/controls/SystemFlowControls.tsx +435 -435
  524. package/packages/diagrams/src/lib/templates/systemFlow/data/template-data.ts +308 -308
  525. package/packages/diagrams/src/lib/templates/systemFlow/demo.tsx +91 -91
  526. package/packages/diagrams/src/lib/templates/systemFlow/index.ts +5 -5
  527. package/packages/diagrams/src/lib/templates/systemFlow/nodes/BendpointNode.tsx +80 -80
  528. package/packages/diagrams/src/lib/templates/systemFlow/nodes/SystemNode.tsx +92 -92
  529. package/packages/diagrams/src/lib/templates/systemFlow/nodes/TreeSystemNode.tsx +755 -755
  530. package/packages/diagrams/src/lib/templates/useCaseDiagram/UseCaseDiagram.tsx +16 -16
  531. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/ActorNodeSettings.tsx +103 -103
  532. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/AddRelationshipDialog.tsx +186 -186
  533. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/PackageNodeSettings.tsx +205 -205
  534. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/UseCaseDiagramFlow.tsx +637 -637
  535. package/packages/diagrams/src/lib/templates/useCaseDiagram/components/UseCaseNodeSettings.tsx +120 -120
  536. package/packages/diagrams/src/lib/templates/useCaseDiagram/controls/UseCaseControls.tsx +289 -289
  537. package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/PackageNode.tsx +83 -83
  538. package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/UseCaseEdge.tsx +115 -115
  539. package/packages/diagrams/src/lib/templates/useCaseDiagram/nodes/UseCaseNode.tsx +230 -230
  540. package/packages/diagrams/src/lib/templates/validationSchema.json +277 -277
  541. package/packages/diagrams/src/lib/theme.ts +439 -439
  542. package/packages/diagrams/src/lib/types/FunctionSignature.ts +11 -11
  543. package/packages/diagrams/src/lib/types/SmartDynamicFormField.ts +37 -37
  544. package/packages/diagrams/src/lib/types/automation-node-data-types.ts +45 -131
  545. package/packages/diagrams/src/lib/types/available-variables.ts +18 -18
  546. package/packages/diagrams/src/lib/types/card-node.ts +68 -68
  547. package/packages/diagrams/src/lib/types/collaboration-types.ts +114 -114
  548. package/packages/diagrams/src/lib/types/colors.ts +25 -25
  549. package/packages/diagrams/src/lib/types/condition-builder.ts +18 -18
  550. package/packages/diagrams/src/lib/types/diagram-types.ts +14 -14
  551. package/packages/diagrams/src/lib/types/edge-types.ts +39 -39
  552. package/packages/diagrams/src/lib/types/function-execution.ts +35 -35
  553. package/packages/diagrams/src/lib/types/hooks.types.ts +6 -6
  554. package/packages/diagrams/src/lib/types/ndoe-form-types.ts +139 -139
  555. package/packages/diagrams/src/lib/types/node-types.ts +13 -23
  556. package/packages/diagrams/src/lib/types/sequence-types.ts +178 -178
  557. package/packages/diagrams/src/lib/types/shared-node-types.ts +21 -21
  558. package/packages/diagrams/src/lib/types/state-machine-types.ts +225 -225
  559. package/packages/diagrams/src/lib/types/stencil-item.ts +7 -7
  560. package/packages/diagrams/src/lib/types/structures.ts +80 -80
  561. package/packages/diagrams/src/lib/types/system-flow-types.ts +129 -129
  562. package/packages/diagrams/src/lib/types/usecase-types.ts +84 -84
  563. package/packages/diagrams/src/lib/types/validation-types.ts +134 -134
  564. package/packages/diagrams/src/lib/types/workflow-content-dynamic-form-type.ts +23 -23
  565. package/packages/diagrams/src/lib/types/workflow-node-data-types.ts +172 -172
  566. package/packages/diagrams/src/lib/utils/AutomationExecutionEngine.ts +658 -1179
  567. package/packages/diagrams/src/lib/utils/add-new-block.ts +34 -34
  568. package/packages/diagrams/src/lib/utils/add-new-node.ts +52 -52
  569. package/packages/diagrams/src/lib/utils/addToHistory.ts +15 -15
  570. package/packages/diagrams/src/lib/utils/automation-flow-processor.ts +556 -619
  571. package/packages/diagrams/src/lib/utils/closestPoint.ts +45 -45
  572. package/packages/diagrams/src/lib/utils/color-options.tsx +26 -26
  573. package/packages/diagrams/src/lib/utils/compress-img.ts +59 -59
  574. package/packages/diagrams/src/lib/utils/configLoader.ts +329 -329
  575. package/packages/diagrams/src/lib/utils/constant-lengths.ts +8 -8
  576. package/packages/diagrams/src/lib/utils/create-updated.tsx +40 -40
  577. package/packages/diagrams/src/lib/utils/createHistoryChange.ts +3 -3
  578. package/packages/diagrams/src/lib/utils/dividerUtils.tsx +59 -59
  579. package/packages/diagrams/src/lib/utils/edge-hooks.ts +53 -53
  580. package/packages/diagrams/src/lib/utils/elkLayout.ts +297 -297
  581. package/packages/diagrams/src/lib/utils/event-hooks.ts +69 -69
  582. package/packages/diagrams/src/lib/utils/event-store.ts +58 -58
  583. package/packages/diagrams/src/lib/utils/flow-node-hooks.ts +28 -28
  584. package/packages/diagrams/src/lib/utils/flow-to-js.ts +1465 -1465
  585. package/packages/diagrams/src/lib/utils/functionGenerator.ts +38 -38
  586. package/packages/diagrams/src/lib/utils/generateEdgesFromNodeOrder.ts +113 -113
  587. package/packages/diagrams/src/lib/utils/helpers.types.ts +10 -10
  588. package/packages/diagrams/src/lib/utils/highlightText.tsx +93 -93
  589. package/packages/diagrams/src/lib/utils/iconMapper.tsx +76 -76
  590. package/packages/diagrams/src/lib/utils/logger.ts +5 -5
  591. package/packages/diagrams/src/lib/utils/model-hooks.ts +129 -129
  592. package/packages/diagrams/src/lib/utils/node-hooks.ts +78 -78
  593. package/packages/diagrams/src/lib/utils/nodeAIAssistantConfig.ts +54 -54
  594. package/packages/diagrams/src/lib/utils/nodeOrderByEdges.ts +437 -437
  595. package/packages/diagrams/src/lib/utils/nodeutils.ts +242 -242
  596. package/packages/diagrams/src/lib/utils/object.ts +13 -13
  597. package/packages/diagrams/src/lib/utils/useDebounce.ts +19 -19
  598. package/packages/diagrams/src/lib/utils/utilities.ts +105 -105
  599. package/packages/diagrams/src/lib/utils/validationEngine.ts +610 -610
  600. package/packages/diagrams/src/lib/utils/vhToPixels.ts +9 -9
  601. package/packages/diagrams/tsconfig.json +21 -21
  602. package/packages/diagrams/tsconfig.lib.json +26 -25
  603. package/packages/diagrams/webpack.config.js +17 -17
  604. package/packages/interfaces/.babelrc +12 -12
  605. package/packages/interfaces/.eslintrc.json +18 -18
  606. package/packages/interfaces/README.md +7 -7
  607. package/packages/interfaces/project.json +8 -8
  608. package/packages/interfaces/src/index.ts +21 -21
  609. package/packages/interfaces/src/lib/Button.tsx +1 -1
  610. package/packages/interfaces/src/lib/DataGrid.ts +14 -14
  611. package/packages/interfaces/src/lib/StyledBox.tsx +1 -1
  612. package/packages/interfaces/src/lib/ToolbarItem.ts +7 -7
  613. package/packages/interfaces/src/lib/UserCard.ts +8 -8
  614. package/packages/interfaces/src/lib/yup.ts +3 -3
  615. package/packages/interfaces/tsconfig.json +17 -17
  616. package/packages/interfaces/tsconfig.lib.json +24 -24
  617. package/packages/molecules/.babelrc +12 -12
  618. package/packages/molecules/.eslintrc.json +18 -18
  619. package/packages/molecules/README.md +7 -7
  620. package/packages/molecules/project.json +8 -8
  621. package/packages/molecules/src/index.ts +47 -41
  622. package/packages/molecules/src/lib/ActionTextField/ActionTextField.module.css +7 -7
  623. package/packages/molecules/src/lib/ActionTextField/ActionTextField.spec.tsx +10 -10
  624. package/packages/molecules/src/lib/ActionTextField/ActionTextField.tsx +33 -33
  625. package/packages/molecules/src/lib/ClosableButton/CloseableButton.module.css +7 -7
  626. package/packages/molecules/src/lib/ClosableButton/CloseableButton.spec.tsx +11 -11
  627. package/packages/molecules/src/lib/ClosableButton/CloseableButton.tsx +69 -69
  628. package/packages/molecules/src/lib/EditorTab/EditorTab.module.css +7 -7
  629. package/packages/molecules/src/lib/EditorTab/EditorTab.spec.tsx +10 -10
  630. package/packages/molecules/src/lib/EditorTab/EditorTab.tsx +42 -42
  631. package/packages/molecules/src/lib/EditorTab/TabPanel.tsx +25 -25
  632. package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.module.css +7 -7
  633. package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.spec.tsx +10 -10
  634. package/packages/molecules/src/lib/ParamsActionField/ParamsActionField.tsx +24 -24
  635. package/packages/molecules/src/lib/SvgIcons/icons.tsx +323 -291
  636. package/packages/molecules/src/lib/SvgIcons/index.ts +31 -25
  637. package/packages/molecules/src/lib/SvgIcons/types.ts +7 -7
  638. package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.module.css +7 -7
  639. package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.spec.tsx +10 -10
  640. package/packages/molecules/src/lib/TableWithInlineView/TableWithInlineView.tsx +47 -47
  641. package/packages/molecules/src/lib/UserCard/UserCard.module.css +7 -7
  642. package/packages/molecules/src/lib/UserCard/UserCard.spec.tsx +11 -11
  643. package/packages/molecules/src/lib/UserCard/UserCard.tsx +22 -22
  644. package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.module.css +7 -7
  645. package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.spec.tsx +10 -10
  646. package/packages/molecules/src/lib/VerbSelection/HTTPVerbSelection.tsx +72 -72
  647. package/packages/molecules/tsconfig.json +17 -17
  648. package/packages/molecules/tsconfig.lib.json +30 -30
  649. package/packages/organisms/.babelrc +12 -12
  650. package/packages/organisms/.eslintrc.json +18 -18
  651. package/packages/organisms/README.md +7 -7
  652. package/packages/organisms/project.json +8 -8
  653. package/packages/organisms/src/index.ts +4 -4
  654. package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.module.css +7 -7
  655. package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.spec.tsx +10 -10
  656. package/packages/organisms/src/lib/EditorToolbar/EditorToolbar.tsx +117 -117
  657. package/packages/organisms/src/lib/EditorToolbar/SortableItem.tsx +51 -51
  658. package/packages/organisms/src/lib/UserList/UserList.module.css +7 -7
  659. package/packages/organisms/src/lib/UserList/UserList.spec.tsx +11 -11
  660. package/packages/organisms/src/lib/UserList/UserList.tsx +48 -48
  661. package/packages/organisms/src/lib/UserList/store.ts +49 -49
  662. package/packages/organisms/tsconfig.json +17 -17
  663. package/packages/organisms/tsconfig.lib.json +24 -24
  664. package/packages/zustand/.babelrc +12 -12
  665. package/packages/zustand/.eslintrc.json +18 -18
  666. package/packages/zustand/README.md +7 -7
  667. package/packages/zustand/project.json +8 -8
  668. package/packages/zustand/src/index.ts +4 -4
  669. package/packages/zustand/tsconfig.json +17 -17
  670. package/packages/zustand/tsconfig.lib.json +24 -24
  671. package/tsconfig.base.json +29 -29
  672. package/packages/diagrams/src/lib/components/automation/AutomationAISuggestionNode.tsx +0 -304
  673. package/packages/diagrams/src/lib/components/automation/AutomationEmailNode.tsx +0 -773
  674. package/packages/diagrams/src/lib/components/automation/AutomationGoogleServicesNode.tsx +0 -779
  675. package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +0 -422
  676. package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +0 -1135
  677. package/packages/diagrams/src/lib/examples/GoogleSheetsConfigurationExamples.ts +0 -306
@@ -1,1238 +1,1238 @@
1
- import React, {
2
- useCallback,
3
- useState,
4
- useRef,
5
- useEffect,
6
- useMemo,
7
- } from 'react';
8
-
9
- // Fullscreen API type extensions
10
- interface FullscreenElement extends HTMLElement {
11
- webkitRequestFullscreen?: () => Promise<void>;
12
- msRequestFullscreen?: () => Promise<void>;
13
- }
14
-
15
- interface FullscreenDocument extends Document {
16
- webkitExitFullscreen?: () => Promise<void>;
17
- msExitFullscreen?: () => Promise<void>;
18
- }
19
- import {
20
- ReactFlow,
21
- Background,
22
- useNodesState,
23
- useEdgesState,
24
- Panel,
25
- BackgroundVariant,
26
- Connection,
27
- NodeChange,
28
- applyNodeChanges,
29
- ReactFlowProvider,
30
- Node,
31
- Edge,
32
- NodeProps,
33
- } from '@xyflow/react';
34
- import '@xyflow/react/dist/style.css';
35
- import {
36
- StateMachineNode,
37
- StateMachineEdge,
38
- HistoryState,
39
- EditingState,
40
- StateNodeSettingsState,
41
- EdgeSettingsState,
42
- NodeSelectionContextType,
43
- LayoutDirection,
44
- Position,
45
- UpdateFunction,
46
- CloseFunction,
47
- DeleteFunction
48
- } from '../../../types/state-machine-types';
49
-
50
- import {
51
- Box,
52
- Button,
53
- Paper,
54
- ToggleButton,
55
- ToggleButtonGroup,
56
- Snackbar,
57
- Alert,
58
- } from '@mui/material';
59
- import DownloadIcon from '@mui/icons-material/Download';
60
- import UploadIcon from '@mui/icons-material/Upload';
61
- import FullscreenIcon from '@mui/icons-material/Fullscreen';
62
- import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
63
- import CloseIcon from '@mui/icons-material/Close';
64
- import UndoIcon from '@mui/icons-material/Undo';
65
- import RedoIcon from '@mui/icons-material/Redo';
66
- import ViewWeekIcon from '@mui/icons-material/ViewWeek';
67
- import ViewStreamIcon from '@mui/icons-material/ViewStream';
68
- import {
69
- stateMachineDefaultNodes,
70
- stateMachineDefaultEdges,
71
- } from '../data/template-data';
72
- import {
73
- stateMachineEdgeTypes,
74
- stateMachineNodeTypes as baseStateMachineNodeTypes,
75
- CompositeStateNode as CompositeStateNodeType,
76
- } from './StateMachineComponents';
77
- import DiagramControls from '../controls/StateDiagramControls';
78
- import { NodeSelectionContext } from '../controls/StateDiagramControls';
79
- import StateNodeSettings from './StateNodeSettings';
80
- import EdgeSettings from './EdgeSettings';
81
- import CompositeStateNodeSettings from './CompositeStateNodeSettings';
82
- import { useStateMachineLayout } from './StateMachineLayout';
83
- import DiagramPanel from '../../../components/DiagramPanel';
84
- import Sidebar from '../../../components/SideBar';
85
- import AiButton from '../../../components/AiButton';
86
- import MiniMapCommon from '../../../components/MiniMapCommon';
87
-
88
- interface StateMachineDiagramFlowProps {
89
- nodes: StateMachineNode[];
90
- setNodes: (nodes: StateMachineNode[] | ((prev: StateMachineNode[]) => StateMachineNode[])) => void;
91
- edges: StateMachineEdge[];
92
- setEdges: (edges: StateMachineEdge[] | ((prev: StateMachineEdge[]) => StateMachineEdge[])) => void;
93
- }
94
-
95
- interface CompositeStateNodeProps extends NodeProps {
96
- onToggleExpand?: (id: string, expanded: boolean) => void;
97
- onSettingsClick?: () => void;
98
- }
99
-
100
- // Utility: Deep compare node arrays by id, type, data, width, height
101
- const deepCompareNodes = (a: Node[], b: Node[]) => {
102
- if (a.length !== b.length) return false;
103
- for (let i = 0; i < a.length; i++) {
104
- const nodeA = a[i];
105
- const nodeB = b[i];
106
- if (
107
- nodeA.id !== nodeB.id ||
108
- nodeA.type !== nodeB.type ||
109
- JSON.stringify(nodeA.data) !== JSON.stringify(nodeB.data)
110
- ) {
111
- return false;
112
- }
113
- }
114
- return true;
115
- };
116
-
117
- // Utility: Deep compare edge arrays by id, source, target, type, data
118
- const deepCompareEdges = (a: Edge[], b: Edge[]) => {
119
- if (a.length !== b.length) return false;
120
- for (let i = 0; i < a.length; i++) {
121
- const edgeA = a[i];
122
- const edgeB = b[i];
123
- if (
124
- edgeA.id !== edgeB.id ||
125
- edgeA.source !== edgeB.source ||
126
- edgeA.target !== edgeB.target ||
127
- edgeA.type !== edgeB.type ||
128
- JSON.stringify(edgeA.data) !== JSON.stringify(edgeB.data)
129
- ) {
130
- return false;
131
- }
132
- }
133
- return true;
134
- };
135
-
136
- // Debounce utility
137
- const debounce = (fn: Function, delay: number) => {
138
- let timer: NodeJS.Timeout | null = null;
139
- return (...args: unknown[]) => {
140
- if (timer) clearTimeout(timer);
141
- timer = setTimeout(() => fn(...args), delay);
142
- };
143
- };
144
-
145
- // Helper to recursively collect all child node ids of collapsed composite nodes
146
- function getHiddenNodeIds(allNodes: Node[]): Set<string> {
147
- const hidden = new Set<string>();
148
- const collapsedComposites = allNodes.filter(
149
- (n) => n.type === 'CompositeStateNode' && !n.data.expanded,
150
- );
151
- const collectChildren = (parentId: string) => {
152
- allNodes.forEach((child) => {
153
- if (child.parentId === parentId) {
154
- hidden.add(child.id);
155
- if (child.type === 'CompositeStateNode') {
156
- collectChildren(child.id);
157
- }
158
- }
159
- });
160
- };
161
- collapsedComposites.forEach((comp) => collectChildren(comp.id));
162
- return hidden;
163
- }
164
-
165
- // Helper: get center position in diagram
166
- const getCenterPosition = (width: number, height: number) => {
167
- return { x: width / 2 - 75, y: height / 2 - 40 };
168
- };
169
-
170
- const StateMachineDiagramFlowContent: React.FC<
171
- StateMachineDiagramFlowProps
172
- > = ({
173
- nodes: initialNodes,
174
- setNodes: parentSetNodes,
175
- edges: initialEdges,
176
- setEdges: parentSetEdges,
177
- }) => {
178
- // State declarations
179
- const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes as Node[]);
180
- const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges as Edge[]);
181
- const [history, setHistory] = useState<HistoryState[]>([]);
182
- const [historyIndex, setHistoryIndex] = useState<number>(-1);
183
- const isUndoRedoAction = useRef(false);
184
- const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
185
- const diagramContainerRef = useRef<HTMLDivElement>(null);
186
- const [editing, setEditing] = useState<{
187
- nodeId?: string | null;
188
- edgeId?: string | null;
189
- label?: string;
190
- type?: 'node' | 'edge';
191
- }>({});
192
- const [stateNodeSettings, setStateNodeSettings] = useState<{
193
- id: string | null;
194
- }>({ id: null });
195
- const [edgeSettings, setEdgeSettings] = useState<{ id: string | null }>({
196
- id: null,
197
- });
198
- const [selectedCompositeStateNodeId, setSelectedCompositeStateNodeId] =
199
- useState<string | null>(null);
200
- const [isSettingsSidebarOpen, setIsSettingsSidebarOpen] = useState(false);
201
-
202
- // Add layout integration
203
- const { getLayoutedElements, layoutDirection, setLayoutDirection } =
204
- useStateMachineLayout(nodes as Node[], edges as StateMachineEdge[], setNodes);
205
-
206
- // Function declarations in correct order
207
- const handleToggleCompositeExpand = useCallback(
208
- (id: string, expanded: boolean) => {
209
- setNodes((nds: Node[]) =>
210
- nds.map((node: Node) =>
211
- node.id === id && node.type === 'CompositeStateNode'
212
- ? { ...node, data: { ...node.data, expanded } }
213
- : node,
214
- ),
215
- );
216
- },
217
- [setNodes],
218
- );
219
-
220
- const nodeTypes = useMemo(() => {
221
- return {
222
- ...baseStateMachineNodeTypes,
223
- CompositeStateNode: (props: NodeProps) => {
224
- const compositeProps: CompositeStateNodeProps = {
225
- ...props,
226
- onToggleExpand: handleToggleCompositeExpand,
227
- onSettingsClick: undefined,
228
- };
229
- return <CompositeStateNodeType {...compositeProps} />;
230
- },
231
- };
232
- }, [handleToggleCompositeExpand]);
233
-
234
- const saveLabel = useCallback(() => {
235
- if (editing.nodeId && editing.type === 'node') {
236
- setNodes((nds: Node[]) =>
237
- nds.map((node: Node) => {
238
- if (node.id === editing.nodeId) {
239
- return {
240
- ...node,
241
- data: {
242
- ...node.data,
243
- label: editing.label,
244
- },
245
- };
246
- }
247
- return node;
248
- }),
249
- );
250
- setEditing({
251
- nodeId: undefined,
252
- edgeId: undefined,
253
- label: undefined,
254
- type: undefined,
255
- });
256
- } else if (editing.edgeId && editing.type === 'edge') {
257
- setEdges((eds: Edge[]) =>
258
- eds.map((edge: Edge) => {
259
- if (edge.id === editing.edgeId) {
260
- return {
261
- ...edge,
262
- data: {
263
- ...edge.data,
264
- label: editing.label,
265
- },
266
- };
267
- }
268
- return edge;
269
- }),
270
- );
271
- setEditing({
272
- nodeId: undefined,
273
- edgeId: undefined,
274
- label: undefined,
275
- type: undefined,
276
- });
277
- }
278
- }, [editing, setNodes, setEdges]);
279
-
280
- const handleKeyDown = useCallback(
281
- (e: React.KeyboardEvent) => {
282
- if (e.key === 'Enter') {
283
- saveLabel();
284
- } else if (e.key === 'Escape') {
285
- setEditing({
286
- nodeId: undefined,
287
- edgeId: undefined,
288
- label: undefined,
289
- type: undefined,
290
- });
291
- }
292
- },
293
- [saveLabel],
294
- );
295
-
296
- const loadTemplateData = useCallback(
297
- (templateType: string) => {
298
- console.log(`Loading template: ${templateType}`);
299
- // For now, just load the default state machine nodes/edges
300
- setNodes(stateMachineDefaultNodes as Node[]);
301
- setEdges(stateMachineDefaultEdges as Edge[]);
302
- },
303
- [setNodes, setEdges],
304
- );
305
-
306
- // Initialize nodes and edges with our data
307
- useEffect(() => {
308
- // Only initialize if history is empty
309
- if (history.length === 0) {
310
- const initialState = {
311
- nodes: [...nodes],
312
- edges: [...edges],
313
- };
314
- setHistory([initialState]);
315
- setHistoryIndex(0);
316
- }
317
- }, []);
318
-
319
- // Save current state to history when nodes or edges change (debounced)
320
- const debouncedUpdateHistory = useRef(
321
- debounce(
322
- (
323
- nodes: Node[],
324
- edges: Edge[],
325
- history: HistoryState[],
326
- historyIndex: number,
327
- setHistory: React.Dispatch<React.SetStateAction<HistoryState[]>>,
328
- setHistoryIndex: React.Dispatch<React.SetStateAction<number>>,
329
- ) => {
330
- const newHistoryEntry = {
331
- nodes: [...nodes],
332
- edges: [...edges],
333
- };
334
- const currentState = history[historyIndex];
335
- if (
336
- currentState &&
337
- deepCompareNodes(currentState.nodes, newHistoryEntry.nodes) &&
338
- deepCompareEdges(currentState.edges, newHistoryEntry.edges)
339
- ) {
340
- return; // No change, don't add to history
341
- }
342
- // Trim future history if we're in the middle of the history stack
343
- let newHistory = history.slice(0, historyIndex + 1);
344
- newHistory.push(newHistoryEntry);
345
- // Limit to last 50 entries
346
- if (newHistory.length > 50) {
347
- newHistory = newHistory.slice(newHistory.length - 50);
348
- }
349
- setHistory(newHistory);
350
- setHistoryIndex(newHistory.length - 1);
351
- },
352
- 300,
353
- ),
354
- ).current;
355
-
356
- useEffect(() => {
357
- if (isUndoRedoAction.current || history.length === 0) {
358
- return;
359
- }
360
- debouncedUpdateHistory(
361
- nodes,
362
- edges,
363
- history,
364
- historyIndex,
365
- setHistory,
366
- setHistoryIndex,
367
- );
368
- // eslint-disable-next-line react-hooks/exhaustive-deps
369
- }, [nodes, edges]);
370
-
371
- // Function to perform undo operation
372
- const handleUndo = useCallback(() => {
373
- if (historyIndex > 0) {
374
- isUndoRedoAction.current = true;
375
- const prevState = history[historyIndex - 1];
376
- setNodes(prevState.nodes);
377
- setEdges(prevState.edges);
378
- setHistoryIndex(historyIndex - 1);
379
- setTimeout(() => {
380
- isUndoRedoAction.current = false;
381
- }, 0);
382
- }
383
- }, [history, historyIndex, setNodes, setEdges]);
384
-
385
- // Function to perform redo operation
386
- const handleRedo = useCallback(() => {
387
- if (historyIndex < history.length - 1) {
388
- isUndoRedoAction.current = true;
389
- const nextState = history[historyIndex + 1];
390
- setNodes(nextState.nodes);
391
- setEdges(nextState.edges);
392
- setHistoryIndex(historyIndex + 1);
393
- setTimeout(() => {
394
- isUndoRedoAction.current = false;
395
- }, 0);
396
- }
397
- }, [history, historyIndex, setNodes, setEdges]);
398
-
399
- // Clear handler
400
- const handleClear = useCallback(() => {
401
- const cleared = { nodes: [], edges: [] };
402
- const newHistory = history.slice(0, historyIndex + 1);
403
- newHistory.push(cleared);
404
- setNodes([]);
405
- setEdges([]);
406
- setHistory(newHistory);
407
- setHistoryIndex(newHistory.length - 1);
408
- }, [history, historyIndex, setNodes, setEdges]);
409
-
410
- // Listen for keyboard shortcuts
411
- useEffect(() => {
412
- const handleKeyDown = (e: KeyboardEvent) => {
413
- // Check for Ctrl+Z or Cmd+Z (undo)
414
- if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
415
- e.preventDefault();
416
- handleUndo();
417
- }
418
- // Check for Ctrl+Y or Cmd+Shift+Z (redo)
419
- if (
420
- ((e.ctrlKey || e.metaKey) && e.key === 'y') ||
421
- ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z')
422
- ) {
423
- e.preventDefault();
424
- handleRedo();
425
- }
426
- };
427
-
428
- window.addEventListener('keydown', handleKeyDown);
429
- return () => {
430
- window.removeEventListener('keydown', handleKeyDown);
431
- };
432
- }, [handleUndo, handleRedo]);
433
-
434
- // Node type map for state machine nodes
435
- const nodeTypeMap: Record<string, { type: string; data?: Record<string, unknown> }> = {
436
- StateNode: { type: 'StateNode', data: { label: 'State' } },
437
- InitialStateNode: { type: 'InitialStateNode', data: {} },
438
- FinalStateNode: { type: 'FinalStateNode', data: {} },
439
- CompositeStateNode: {
440
- type: 'CompositeStateNode',
441
- data: { label: 'Composite State', expanded: false },
442
- },
443
- HistoryStateNode: { type: 'HistoryStateNode', data: {} },
444
- JunctionPointNode: { type: 'JunctionPointNode', data: {} },
445
- ChoicePointNode: { type: 'ChoicePointNode', data: {} },
446
- EntryPointNode: { type: 'EntryPointNode', data: {} },
447
- ExitPointNode: { type: 'ExitPointNode', data: {} },
448
- ForkJoinNode: { type: 'ForkJoinNode', data: { orientation: 'horizontal' } },
449
- BendpointNode: { type: 'bendpoint', data: {} },
450
- };
451
-
452
- // Add node at center (internal)
453
- const addNodeAtCenter = useCallback(
454
- (nodeTypeId: string) => {
455
- const nodeInfo = nodeTypeMap[nodeTypeId];
456
- if (!nodeInfo) return;
457
- const { type, data } = nodeInfo;
458
- const width = diagramContainerRef.current?.offsetWidth || 1200;
459
- const height = diagramContainerRef.current?.offsetHeight || 800;
460
- const center = getCenterPosition(width, height);
461
- const newId = `${nodeTypeId}-${nodes.length + 1}`;
462
-
463
- // Add onResize handler to node data
464
- const onResize = (id: string, width: number, height: number) => {
465
- setNodes((nds) =>
466
- nds.map((node) =>
467
- node.id === id
468
- ? {
469
- ...node,
470
- measured: { width, height },
471
- width: width,
472
- height: height,
473
- }
474
- : node,
475
- ),
476
- );
477
- // Update all selfconnecting edges for this node with new size/position
478
- setEdges((eds) =>
479
- eds.map((edge) => {
480
- if (
481
- edge.type === 'selfconnecting' &&
482
- edge.source === id &&
483
- edge.target === id
484
- ) {
485
- // Find the node to get its position
486
- const node = nodes.find((n) => n.id === id);
487
- const nodeX = node?.position?.x ?? 0;
488
- const nodeY = node?.position?.y ?? 0;
489
- return {
490
- ...edge,
491
- data: {
492
- ...edge.data,
493
- nodeWidth: width,
494
- nodeHeight: height,
495
- nodeX,
496
- nodeY,
497
- },
498
- };
499
- }
500
- return edge;
501
- }),
502
- );
503
- };
504
-
505
- setNodes((nds: Node[]) => [
506
- ...nds,
507
- {
508
- id: newId,
509
- type,
510
- position: center,
511
- data: { ...data, onResize },
512
- draggable: true,
513
- },
514
- ]);
515
- },
516
- [nodes, setNodes, setEdges],
517
- );
518
-
519
- // Update onAddEntity to use internal addNodeAtCenter
520
- const handleAddEntity = useCallback(
521
- (nodeTypeId = 'StateNode') => {
522
- addNodeAtCenter(nodeTypeId);
523
- },
524
- [addNodeAtCenter],
525
- );
526
-
527
- // Function to export diagram as JSON
528
- const exportDiagram = useCallback(() => {
529
- const diagramData = {
530
- nodes: nodes,
531
- edges: edges,
532
- };
533
-
534
- const dataStr = JSON.stringify(diagramData, null, 2);
535
- const dataUri =
536
- 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
537
-
538
- const exportFileDefaultName = 'state-machine-diagram.json';
539
-
540
- const linkElement = document.createElement('a');
541
- linkElement.setAttribute('href', dataUri);
542
- linkElement.setAttribute('download', exportFileDefaultName);
543
- linkElement.click();
544
- }, [nodes, edges]);
545
-
546
- // Function to import diagram from JSON
547
- const importDiagram = useCallback(
548
- (event: React.ChangeEvent<HTMLInputElement>) => {
549
- if (!event.target.files || event.target.files.length === 0) return;
550
-
551
- const fileReader = new FileReader();
552
- fileReader.readAsText(event.target.files[0], 'UTF-8');
553
- fileReader.onload = (e) => {
554
- try {
555
- if (!e.target || typeof e.target.result !== 'string') return;
556
-
557
- const imported = JSON.parse(e.target.result);
558
- if (imported.nodes && imported.edges) {
559
- setNodes(imported.nodes);
560
- setEdges(imported.edges);
561
- }
562
- } catch (error) {
563
- console.error('Error importing diagram:', error);
564
- alert('Failed to import diagram. Invalid file format.');
565
- }
566
- };
567
- },
568
- [setNodes, setEdges],
569
- );
570
-
571
- // Toggle fullscreen mode
572
- const toggleFullscreen = useCallback(() => {
573
- if (!diagramContainerRef.current) return;
574
-
575
- if (!isFullscreen) {
576
- if (diagramContainerRef.current.requestFullscreen) {
577
- diagramContainerRef.current.requestFullscreen();
578
- } else if ((diagramContainerRef.current as FullscreenElement).webkitRequestFullscreen) {
579
- (diagramContainerRef.current as FullscreenElement).webkitRequestFullscreen?.();
580
- } else if ((diagramContainerRef.current as FullscreenElement).msRequestFullscreen) {
581
- (diagramContainerRef.current as FullscreenElement).msRequestFullscreen?.();
582
- }
583
- } else {
584
- if (document.exitFullscreen) {
585
- document.exitFullscreen();
586
- } else if ((document as FullscreenDocument).webkitExitFullscreen) {
587
- (document as FullscreenDocument).webkitExitFullscreen?.();
588
- } else if ((document as FullscreenDocument).msExitFullscreen) {
589
- (document as FullscreenDocument).msExitFullscreen?.();
590
- }
591
- }
592
-
593
- setIsFullscreen(!isFullscreen);
594
- }, [isFullscreen]);
595
-
596
- // Listen for fullscreen change events from browser
597
- useEffect(() => {
598
- const handleFullscreenChange = () => {
599
- setIsFullscreen(!!document.fullscreenElement);
600
- };
601
-
602
- document.addEventListener('fullscreenchange', handleFullscreenChange);
603
- document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
604
- document.addEventListener('mozfullscreenchange', handleFullscreenChange);
605
- document.addEventListener('MSFullscreenChange', handleFullscreenChange);
606
-
607
- return () => {
608
- document.removeEventListener('fullscreenchange', handleFullscreenChange);
609
- document.removeEventListener(
610
- 'webkitfullscreenchange',
611
- handleFullscreenChange,
612
- );
613
- document.removeEventListener(
614
- 'mozfullscreenchange',
615
- handleFullscreenChange,
616
- );
617
- document.removeEventListener(
618
- 'MSFullscreenChange',
619
- handleFullscreenChange,
620
- );
621
- };
622
- }, []);
623
-
624
- // Modified onConnect to open EdgeSettings after edge is created
625
- const onConnect = useCallback(
626
- (params: Connection) => {
627
- if (!params.source || !params.target) return;
628
- const sourceNode = nodes.find((n) => n.id === params.source);
629
- const targetNode = nodes.find((n) => n.id === params.target);
630
- if (!sourceNode || !targetNode) return;
631
-
632
- const newEdge = {
633
- id: `edge-${edges.length + 1}`,
634
- source: params.source,
635
- target: params.target,
636
- type: 'customEdge',
637
- sourceHandle: params.sourceHandle,
638
- targetHandle: params.targetHandle,
639
- data: {
640
- label: `Transition ${edges.length + 1}`,
641
- },
642
- animated: false,
643
- };
644
- setEdges((eds: Edge[]) => [...eds, newEdge]);
645
- setEdgeSettings({ id: newEdge.id });
646
- setIsSettingsSidebarOpen(true);
647
- },
648
- [nodes, edges, setEdges],
649
- );
650
-
651
- // Update onNodeClick function
652
- const onNodeClick = useCallback((event: React.MouseEvent, node: Node) => {
653
- if (node.type === 'bendpoint') {
654
- setStateNodeSettings({ id: null });
655
- setSelectedCompositeStateNodeId(null);
656
- return;
657
- }
658
-
659
- if (node.type === 'CompositeStateNode') {
660
- setSelectedCompositeStateNodeId(node.id);
661
- setStateNodeSettings({ id: null });
662
- setIsSettingsSidebarOpen(true);
663
- } else if (
664
- [
665
- 'StateNode',
666
- 'InitialStateNode',
667
- 'FinalStateNode',
668
- 'HistoryStateNode',
669
- 'JunctionPointNode',
670
- 'ChoicePointNode',
671
- 'EntryPointNode',
672
- 'ExitPointNode',
673
- 'ForkJoinNode',
674
- ].includes(node.type || '')
675
- ) {
676
- setStateNodeSettings({ id: node.id });
677
- setSelectedCompositeStateNodeId(null);
678
- setIsSettingsSidebarOpen(true);
679
- } else {
680
- setStateNodeSettings({ id: null });
681
- setSelectedCompositeStateNodeId(null);
682
- }
683
- }, []);
684
-
685
- // Update onNodeDoubleClick function
686
- const onNodeDoubleClick = useCallback(
687
- (event: React.MouseEvent, node: Node) => {
688
- event.preventDefault();
689
- event.stopPropagation();
690
- setEditing({
691
- nodeId: node.id,
692
- edgeId: null,
693
- label: (node.data?.label as string) || '',
694
- type: 'node',
695
- });
696
- },
697
- [setEditing],
698
- );
699
-
700
- // Open EdgeSettings on double click
701
- const onEdgeDoubleClick = useCallback(
702
- (event: React.MouseEvent, edge: Edge) => {
703
- event.preventDefault();
704
- event.stopPropagation();
705
- if (edge.type === 'customEdge') {
706
- setEdgeSettings({ id: edge.id });
707
- setIsSettingsSidebarOpen(true);
708
- }
709
- },
710
- [],
711
- );
712
-
713
- // Function to update selected state node
714
- const updateSelectedStateNode = useCallback(
715
- (updates: Record<string, unknown>) => {
716
- if (!stateNodeSettings.id) return;
717
- setNodes((nds: Node[]) =>
718
- nds.map((node: Node) => {
719
- if (node.id === stateNodeSettings.id) {
720
- return {
721
- ...node,
722
- data: {
723
- ...node.data,
724
- ...updates,
725
- },
726
- };
727
- }
728
- return node;
729
- }),
730
- );
731
- },
732
- [stateNodeSettings.id, setNodes],
733
- );
734
-
735
- // Close state node settings
736
- const closeStateNodeSettings = useCallback(() => {
737
- setStateNodeSettings({ id: null });
738
- setIsSettingsSidebarOpen(false);
739
- }, []);
740
-
741
- // Update edge from EdgeSettings
742
- const updateSelectedEdge = useCallback(
743
- (updates: Record<string, unknown>) => {
744
- if (!edgeSettings.id) return;
745
- setEdges((eds: Edge[]) =>
746
- eds.map((edge: Edge) => {
747
- if (edge.id === edgeSettings.id) {
748
- return {
749
- ...edge,
750
- source: typeof updates.source === 'string' ? updates.source : edge.source,
751
- target: typeof updates.target === 'string' ? updates.target : edge.target,
752
- data: {
753
- ...edge.data,
754
- ...updates,
755
- },
756
- };
757
- }
758
- return edge;
759
- }) as Edge[],
760
- );
761
- },
762
- [edgeSettings.id, setEdges],
763
- );
764
-
765
- // Close EdgeSettings
766
- const closeEdgeSettings = useCallback(() => {
767
- setEdgeSettings({ id: null });
768
- setIsSettingsSidebarOpen(false);
769
- }, []);
770
-
771
- // Close CompositeStateNodeSettings
772
- const closeCompositeStateNodeSettings = useCallback(() => {
773
- setSelectedCompositeStateNodeId(null);
774
- setIsSettingsSidebarOpen(false);
775
- }, []);
776
-
777
- // Function to update selected composite state node
778
- const updateSelectedCompositeStateNode = useCallback(
779
- (updates: Record<string, unknown>) => {
780
- if (!selectedCompositeStateNodeId) return;
781
- setNodes((nds: Node[]) =>
782
- nds.map((node: Node) => {
783
- if (node.id === selectedCompositeStateNodeId) {
784
- return {
785
- ...node,
786
- data: {
787
- ...node.data,
788
- ...updates,
789
- },
790
- };
791
- }
792
- return node;
793
- }),
794
- );
795
- },
796
- [selectedCompositeStateNodeId, setNodes],
797
- );
798
-
799
- // Collapse all composite nodes on pane click
800
- const handlePaneClick = useCallback(() => {
801
- setNodes((nds: Node[]) =>
802
- nds.map((node: Node) =>
803
- node.type === 'CompositeStateNode'
804
- ? { ...node, data: { ...node.data, expanded: false } }
805
- : node,
806
- ),
807
- );
808
- setSelectedCompositeStateNodeId(null);
809
- setStateNodeSettings({ id: null });
810
- }, [setNodes]);
811
-
812
- // Memoize hidden node ids
813
- const hiddenNodeIds = useMemo(() => getHiddenNodeIds(nodes), [nodes]);
814
- // Memoize filtered nodes
815
- const filteredNodes = useMemo(
816
- () => nodes.filter((n) => !hiddenNodeIds.has(n.id)),
817
- [nodes, hiddenNodeIds],
818
- );
819
- // Memoize collapsed composites
820
- const collapsedComposites = useMemo(
821
- () =>
822
- nodes.filter((n) => n.type === 'CompositeStateNode' && !n.data.expanded),
823
- [nodes],
824
- );
825
- // Memoize proxy edge logic (optimized for performance)
826
- const { filteredEdges } = useMemo(() => {
827
- // Precompute collapsed composite node ids for O(1) lookup
828
- const collapsedCompositeIds = new Set(
829
- nodes
830
- .filter((n) => n.type === 'CompositeStateNode' && !n.data.expanded)
831
- .map((n) => n.id),
832
- );
833
- // Precompute a map of nodeId -> node for O(1) lookup
834
- const nodeIdMap = new Map(nodes.map((n) => [n.id, n]));
835
- // Map childId to its collapsed composite parent
836
- const childToCollapsedParent: Record<string, string> = {};
837
- const collectChildren = (parentId: string) => {
838
- nodes.forEach((child) => {
839
- if (child.parentId === parentId) {
840
- childToCollapsedParent[child.id] = parentId;
841
- if (child.type === 'CompositeStateNode') {
842
- collectChildren(child.id);
843
- }
844
- }
845
- });
846
- };
847
- collapsedCompositeIds.forEach((compId) => collectChildren(compId));
848
- // Generate proxy edges for edges crossing collapsed composite boundaries
849
- const proxyEdges: Edge[] = [];
850
- const realEdges: Edge[] = [];
851
- edges.forEach((edge) => {
852
- const sourceHidden = hiddenNodeIds.has(edge.source);
853
- const targetHidden = hiddenNodeIds.has(edge.target);
854
-
855
- // Self-loop on composite node: hide if collapsed
856
- if (
857
- edge.source === edge.target &&
858
- collapsedCompositeIds.has(edge.source)
859
- ) {
860
- return; // skip this edge
861
- }
862
-
863
- // If both ends are hidden, skip (don't show)
864
- if (sourceHidden && targetHidden) return;
865
- // If neither end is hidden, show as normal
866
- if (!sourceHidden && !targetHidden) {
867
- realEdges.push(edge);
868
- return;
869
- }
870
- // If one end is hidden and the other is visible, create a proxy edge
871
- let proxySource = edge.source;
872
- let proxyTarget = edge.target;
873
- let proxyId = edge.id + '-proxy';
874
- // If source is hidden, map to its collapsed composite parent
875
- if (sourceHidden && childToCollapsedParent[edge.source]) {
876
- proxySource = childToCollapsedParent[edge.source];
877
- }
878
- // If target is hidden, map to its collapsed composite parent
879
- if (targetHidden && childToCollapsedParent[edge.target]) {
880
- proxyTarget = childToCollapsedParent[edge.target];
881
- }
882
- // Avoid proxying to the same node (self-loop)
883
- if (proxySource === proxyTarget) return;
884
- proxyEdges.push({
885
- ...edge,
886
- id: proxyId,
887
- source: proxySource,
888
- target: proxyTarget,
889
- style: { ...(edge.style || {}), strokeDasharray: '6 4', opacity: 0.7 },
890
- data: { ...(edge.data || {}), isProxy: true },
891
- });
892
- });
893
- return { filteredEdges: [...realEdges, ...proxyEdges] as Edge[] };
894
- }, [edges, nodes, hiddenNodeIds]);
895
-
896
- // Custom onNodesChange to snap PinPointNode to border of parent composite node
897
- const customOnNodesChange = useCallback(
898
- (changes: NodeChange[]) => {
899
- setNodes((nds) => {
900
- // Apply default node changes
901
- let updated = applyNodeChanges(changes, nds);
902
- // Snap PinPointNode nodes to border of parent composite node
903
- updated = updated.map((node) => {
904
- if (node.type === 'PinPointNode' && node.parentId) {
905
- const parent = nds.find((n) => n.id === node.parentId);
906
- if (!parent) return node;
907
- const width = (parent.data as Record<string, unknown>).width as number || 400;
908
- const height = (parent.data as Record<string, unknown>).height as number || 300;
909
- const size = 22;
910
- let { x, y } = node.position;
911
- // Calculate center
912
- const cx = x + size / 2;
913
- const cy = y + size / 2;
914
- // Find closest border (top, bottom, left, right)
915
- const dTop = Math.abs(cy - 0);
916
- const dBottom = Math.abs(cy - height);
917
- const dLeft = Math.abs(cx - 0);
918
- const dRight = Math.abs(cx - width);
919
- const minDist = Math.min(dTop, dBottom, dLeft, dRight);
920
- let newX = x,
921
- newY = y;
922
- if (minDist === dTop) {
923
- newX =
924
- Math.max(-size / 2, Math.min(width - size / 2, cx)) - size / 2;
925
- newY = -size / 2;
926
- } else if (minDist === dBottom) {
927
- newX =
928
- Math.max(-size / 2, Math.min(width - size / 2, cx)) - size / 2;
929
- newY = height - size / 2;
930
- } else if (minDist === dLeft) {
931
- newX = -size / 2;
932
- newY =
933
- Math.max(-size / 2, Math.min(height - size / 2, cy)) - size / 2;
934
- } else if (minDist === dRight) {
935
- newX = width - size / 2;
936
- newY =
937
- Math.max(-size / 2, Math.min(height - size / 2, cy)) - size / 2;
938
- }
939
- return { ...node, position: { x: newX, y: newY } };
940
- }
941
- return node;
942
- });
943
- return updated;
944
- });
945
- },
946
- [setNodes],
947
- );
948
-
949
- // Add layout direction change handler
950
- const handleLayoutDirectionChange = useCallback(
951
- (direction: 'DOWN' | 'RIGHT') => {
952
- setLayoutDirection(direction);
953
- getLayoutedElements();
954
- },
955
- [setLayoutDirection, getLayoutedElements],
956
- );
957
-
958
- // Add layout effect
959
- useEffect(() => {
960
- // Only layout if we have nodes/edges
961
- if (nodes.length > 0 || edges.length > 0) {
962
- getLayoutedElements();
963
- }
964
- }, [handleToggleCompositeExpand]);
965
-
966
- // Add edge edit handlers
967
- const handleEditEdge = useCallback((edge: Edge) => {
968
- setEdgeSettings({ id: edge.id });
969
- }, []);
970
-
971
- const handleUpdateEdgeLabel = useCallback(
972
- (edgeId: string, newLabel: string) => {
973
- setEdges((eds: Edge[]) =>
974
- eds.map((edge: Edge) =>
975
- edge.id === edgeId
976
- ? { ...edge, data: { ...edge.data, label: newLabel } }
977
- : edge,
978
- ),
979
- );
980
- },
981
- [setEdges],
982
- );
983
-
984
- const handleToggleEdgeArrowHead = useCallback(
985
- (edgeId: string, direction: 'left' | 'right') => {
986
- setEdges((eds: Edge[]) =>
987
- eds.map((edge: Edge) => {
988
- if (edge.id === edgeId) {
989
- const data = { ...edge.data };
990
- if (direction === 'left') {
991
- data.arrowHeadLeft = !data.arrowHeadLeft;
992
- } else {
993
- data.arrowHeadRight = !data.arrowHeadRight;
994
- }
995
- return { ...edge, data };
996
- }
997
- return edge;
998
- }),
999
- );
1000
- },
1001
- [setEdges],
1002
- );
1003
-
1004
- // Memoize node and edge maps for O(1) lookup
1005
- const nodeMap = useMemo(() => {
1006
- const map = new Map<string, Node>();
1007
- nodes.forEach((node) => map.set(node.id, node));
1008
- return map;
1009
- }, [nodes]);
1010
- const edgeMap = useMemo(() => {
1011
- const map = new Map<string, Edge>();
1012
- edges.forEach((edge) => map.set(edge.id, edge));
1013
- return map;
1014
- }, [edges]);
1015
-
1016
- return (
1017
- <Box sx={{ display: 'flex', height: '100vh' }}>
1018
- <Sidebar>
1019
- <NodeSelectionContext.Provider
1020
- value={{
1021
- selectedNodeType: null,
1022
- setSelectedNodeType: () => { },
1023
- addNodeAtCenter,
1024
- }}
1025
- >
1026
- <DiagramControls
1027
- onAddEntity={handleAddEntity}
1028
- onUndo={handleUndo}
1029
- onRedo={handleRedo}
1030
- canUndo={historyIndex > 0}
1031
- canRedo={historyIndex < history.length - 1}
1032
- onLoadTemplate={loadTemplateData}
1033
- edges={edges as StateMachineEdge[]}
1034
- nodes={nodes as StateMachineNode[]}
1035
- onEditEdge={handleEditEdge}
1036
- onUpdateEdgeLabel={handleUpdateEdgeLabel}
1037
- onToggleEdgeArrowHead={handleToggleEdgeArrowHead}
1038
- />
1039
- </NodeSelectionContext.Provider>
1040
- </Sidebar>
1041
-
1042
- <Box
1043
- sx={{
1044
- flexGrow: 1,
1045
- '& .react-flow__edge': {
1046
- zIndex: '5000 !important',
1047
- },
1048
- '& .react-flow__edge-path': {
1049
- pointerEvents: 'all !important',
1050
- },
1051
- '& .edge-path-selector': {
1052
- strokeWidth: 20,
1053
- fill: 'none',
1054
- stroke: 'transparent',
1055
- cursor: 'pointer',
1056
- },
1057
- '& .react-flow__edges': {
1058
- zIndex: '5000 !important',
1059
- },
1060
- '& .react-flow__node': {
1061
- pointerEvents: 'all !important',
1062
- cursor: 'grab',
1063
- '&:active': {
1064
- cursor: 'grabbing',
1065
- },
1066
- '& .react-flow__edge': {
1067
- zIndex: '5000 !important',
1068
- },
1069
- },
1070
- '& .react-flow__node.dragging': {
1071
- cursor: 'grabbing !important',
1072
- },
1073
- '& .react-flow.dragging': {
1074
- cursor: 'grabbing',
1075
- },
1076
- }}
1077
- >
1078
- <Box
1079
- sx={{
1080
- width: '100%',
1081
- height: '100%',
1082
- padding: '10px',
1083
- bgcolor: 'white',
1084
- }}
1085
- >
1086
- <ReactFlow
1087
- nodes={filteredNodes}
1088
- edges={filteredEdges}
1089
- onNodesChange={customOnNodesChange}
1090
- onEdgesChange={onEdgesChange}
1091
- onConnect={onConnect}
1092
- nodeTypes={nodeTypes}
1093
- edgeTypes={stateMachineEdgeTypes}
1094
- fitView
1095
- fitViewOptions={{
1096
- padding: 0.2,
1097
- minZoom: 0.5,
1098
- maxZoom: 2,
1099
- }}
1100
- minZoom={0.1}
1101
- maxZoom={2}
1102
- defaultViewport={{ x: 0, y: 0, zoom: 1 }}
1103
- style={{
1104
- background: '#f8f9fa',
1105
- }}
1106
- proOptions={{ hideAttribution: true }}
1107
- selectNodesOnDrag={false}
1108
- connectOnClick={false}
1109
- onNodeClick={onNodeClick}
1110
- onNodeDoubleClick={onNodeDoubleClick}
1111
- onEdgeDoubleClick={onEdgeDoubleClick}
1112
- onPaneClick={handlePaneClick}
1113
- >
1114
- <Background
1115
- color="#f8f9fa"
1116
- variant={BackgroundVariant.Dots}
1117
- gap={16}
1118
- />
1119
-
1120
- {/* MiniMap positioned at bottom-left */}
1121
- <MiniMapCommon />
1122
-
1123
- {/* Diagram Panel with all controls */}
1124
- <DiagramPanel
1125
- historyIndex={historyIndex}
1126
- historyLength={history.length}
1127
- onUndo={handleUndo}
1128
- onRedo={handleRedo}
1129
- onClear={handleClear}
1130
- onImport={(data) => {
1131
- setNodes(data.nodes || []);
1132
- setEdges(data.edges || []);
1133
- // Add to history
1134
- const newHistoryState = {
1135
- nodes: data.nodes || [],
1136
- edges: data.edges || [],
1137
- };
1138
- setHistory((prev) => [
1139
- ...prev.slice(0, historyIndex + 1),
1140
- newHistoryState,
1141
- ]);
1142
- setHistoryIndex((prev) => prev + 1);
1143
- }}
1144
- isSettingsOpen={isSettingsSidebarOpen}
1145
- onToggleSettings={() => setIsSettingsSidebarOpen(true)}
1146
- showCustomControls={true}
1147
- onGridLayout={() => handleLayoutDirectionChange('DOWN')}
1148
- onTreeLayout={() => handleLayoutDirectionChange('RIGHT')}
1149
- />
1150
-
1151
- {/* AI Button positioned at bottom-right */}
1152
- <AiButton />
1153
-
1154
- {/* Layout controls positioned at top-right */}
1155
-
1156
- {/* Fullscreen button positioned at top-left */}
1157
- </ReactFlow>
1158
- </Box>
1159
- </Box>
1160
-
1161
- {/* Settings panels */}
1162
- {stateNodeSettings.id && (
1163
- <StateNodeSettings
1164
- nodeId={stateNodeSettings.id}
1165
- data={nodeMap.get(stateNodeSettings.id)?.data || {}}
1166
- onUpdate={updateSelectedStateNode}
1167
- onClose={closeStateNodeSettings}
1168
- edges={edges as StateMachineEdge[]}
1169
- setEdges={(updater) => {
1170
- if (typeof updater === 'function') {
1171
- setEdges((prev) => updater(prev as StateMachineEdge[]) as Edge[]);
1172
- } else {
1173
- setEdges(updater as Edge[]);
1174
- }
1175
- }}
1176
- nodes={nodes as StateMachineNode[]}
1177
- />
1178
- )}
1179
-
1180
- {edgeSettings.id && (
1181
- <EdgeSettings
1182
- data={{
1183
- ...(edgeMap.get(edgeSettings.id)?.data || {}),
1184
- source: edgeMap.get(edgeSettings.id)?.source,
1185
- target: edgeMap.get(edgeSettings.id)?.target,
1186
- }}
1187
- nodes={nodes as StateMachineNode[]}
1188
- onUpdate={updateSelectedEdge}
1189
- onClose={closeEdgeSettings}
1190
- onDelete={() => {
1191
- setEdges((eds: Edge[]) =>
1192
- eds.filter((edge: Edge) => edge.id !== edgeSettings.id),
1193
- );
1194
- closeEdgeSettings();
1195
- }}
1196
- />
1197
- )}
1198
-
1199
- {selectedCompositeStateNodeId && (
1200
- <CompositeStateNodeSettings
1201
- nodeId={selectedCompositeStateNodeId}
1202
- data={nodeMap.get(selectedCompositeStateNodeId)?.data || {}}
1203
- nodes={nodes as StateMachineNode[]}
1204
- setNodes={(updater) => {
1205
- if (typeof updater === 'function') {
1206
- setNodes((prev) => updater(prev as StateMachineNode[]) as Node[]);
1207
- } else {
1208
- setNodes(updater as Node[]);
1209
- }
1210
- }}
1211
- onUpdate={updateSelectedCompositeStateNode}
1212
- onClose={closeCompositeStateNodeSettings}
1213
- edges={edges as StateMachineEdge[]}
1214
- setEdges={(updater) => {
1215
- if (typeof updater === 'function') {
1216
- setEdges((prev) => updater(prev as StateMachineEdge[]) as Edge[]);
1217
- } else {
1218
- setEdges(updater as Edge[]);
1219
- }
1220
- }}
1221
- />
1222
- )}
1223
- </Box>
1224
- );
1225
- };
1226
-
1227
- // Main wrapper component with ReactFlowProvider
1228
- const StateMachineDiagramFlow: React.FC<StateMachineDiagramFlowProps> = (
1229
- props,
1230
- ) => {
1231
- return (
1232
- <ReactFlowProvider>
1233
- <StateMachineDiagramFlowContent {...props} />
1234
- </ReactFlowProvider>
1235
- );
1236
- };
1237
-
1238
- export default StateMachineDiagramFlow;
1
+ import React, {
2
+ useCallback,
3
+ useState,
4
+ useRef,
5
+ useEffect,
6
+ useMemo,
7
+ } from 'react';
8
+
9
+ // Fullscreen API type extensions
10
+ interface FullscreenElement extends HTMLElement {
11
+ webkitRequestFullscreen?: () => Promise<void>;
12
+ msRequestFullscreen?: () => Promise<void>;
13
+ }
14
+
15
+ interface FullscreenDocument extends Document {
16
+ webkitExitFullscreen?: () => Promise<void>;
17
+ msExitFullscreen?: () => Promise<void>;
18
+ }
19
+ import {
20
+ ReactFlow,
21
+ Background,
22
+ useNodesState,
23
+ useEdgesState,
24
+ Panel,
25
+ BackgroundVariant,
26
+ Connection,
27
+ NodeChange,
28
+ applyNodeChanges,
29
+ ReactFlowProvider,
30
+ Node,
31
+ Edge,
32
+ NodeProps,
33
+ } from '@xyflow/react';
34
+ import '@xyflow/react/dist/style.css';
35
+ import {
36
+ StateMachineNode,
37
+ StateMachineEdge,
38
+ HistoryState,
39
+ EditingState,
40
+ StateNodeSettingsState,
41
+ EdgeSettingsState,
42
+ NodeSelectionContextType,
43
+ LayoutDirection,
44
+ Position,
45
+ UpdateFunction,
46
+ CloseFunction,
47
+ DeleteFunction
48
+ } from '../../../types/state-machine-types';
49
+
50
+ import {
51
+ Box,
52
+ Button,
53
+ Paper,
54
+ ToggleButton,
55
+ ToggleButtonGroup,
56
+ Snackbar,
57
+ Alert,
58
+ } from '@mui/material';
59
+ import DownloadIcon from '@mui/icons-material/Download';
60
+ import UploadIcon from '@mui/icons-material/Upload';
61
+ import FullscreenIcon from '@mui/icons-material/Fullscreen';
62
+ import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
63
+ import CloseIcon from '@mui/icons-material/Close';
64
+ import UndoIcon from '@mui/icons-material/Undo';
65
+ import RedoIcon from '@mui/icons-material/Redo';
66
+ import ViewWeekIcon from '@mui/icons-material/ViewWeek';
67
+ import ViewStreamIcon from '@mui/icons-material/ViewStream';
68
+ import {
69
+ stateMachineDefaultNodes,
70
+ stateMachineDefaultEdges,
71
+ } from '../data/template-data';
72
+ import {
73
+ stateMachineEdgeTypes,
74
+ stateMachineNodeTypes as baseStateMachineNodeTypes,
75
+ CompositeStateNode as CompositeStateNodeType,
76
+ } from './StateMachineComponents';
77
+ import DiagramControls from '../controls/StateDiagramControls';
78
+ import { NodeSelectionContext } from '../controls/StateDiagramControls';
79
+ import StateNodeSettings from './StateNodeSettings';
80
+ import EdgeSettings from './EdgeSettings';
81
+ import CompositeStateNodeSettings from './CompositeStateNodeSettings';
82
+ import { useStateMachineLayout } from './StateMachineLayout';
83
+ import DiagramPanel from '../../../components/DiagramPanel';
84
+ import Sidebar from '../../../components/SideBar';
85
+ import AiButton from '../../../components/AiButton';
86
+ import MiniMapCommon from '../../../components/MiniMapCommon';
87
+
88
+ interface StateMachineDiagramFlowProps {
89
+ nodes: StateMachineNode[];
90
+ setNodes: (nodes: StateMachineNode[] | ((prev: StateMachineNode[]) => StateMachineNode[])) => void;
91
+ edges: StateMachineEdge[];
92
+ setEdges: (edges: StateMachineEdge[] | ((prev: StateMachineEdge[]) => StateMachineEdge[])) => void;
93
+ }
94
+
95
+ interface CompositeStateNodeProps extends NodeProps {
96
+ onToggleExpand?: (id: string, expanded: boolean) => void;
97
+ onSettingsClick?: () => void;
98
+ }
99
+
100
+ // Utility: Deep compare node arrays by id, type, data, width, height
101
+ const deepCompareNodes = (a: Node[], b: Node[]) => {
102
+ if (a.length !== b.length) return false;
103
+ for (let i = 0; i < a.length; i++) {
104
+ const nodeA = a[i];
105
+ const nodeB = b[i];
106
+ if (
107
+ nodeA.id !== nodeB.id ||
108
+ nodeA.type !== nodeB.type ||
109
+ JSON.stringify(nodeA.data) !== JSON.stringify(nodeB.data)
110
+ ) {
111
+ return false;
112
+ }
113
+ }
114
+ return true;
115
+ };
116
+
117
+ // Utility: Deep compare edge arrays by id, source, target, type, data
118
+ const deepCompareEdges = (a: Edge[], b: Edge[]) => {
119
+ if (a.length !== b.length) return false;
120
+ for (let i = 0; i < a.length; i++) {
121
+ const edgeA = a[i];
122
+ const edgeB = b[i];
123
+ if (
124
+ edgeA.id !== edgeB.id ||
125
+ edgeA.source !== edgeB.source ||
126
+ edgeA.target !== edgeB.target ||
127
+ edgeA.type !== edgeB.type ||
128
+ JSON.stringify(edgeA.data) !== JSON.stringify(edgeB.data)
129
+ ) {
130
+ return false;
131
+ }
132
+ }
133
+ return true;
134
+ };
135
+
136
+ // Debounce utility
137
+ const debounce = (fn: Function, delay: number) => {
138
+ let timer: NodeJS.Timeout | null = null;
139
+ return (...args: unknown[]) => {
140
+ if (timer) clearTimeout(timer);
141
+ timer = setTimeout(() => fn(...args), delay);
142
+ };
143
+ };
144
+
145
+ // Helper to recursively collect all child node ids of collapsed composite nodes
146
+ function getHiddenNodeIds(allNodes: Node[]): Set<string> {
147
+ const hidden = new Set<string>();
148
+ const collapsedComposites = allNodes.filter(
149
+ (n) => n.type === 'CompositeStateNode' && !n.data.expanded,
150
+ );
151
+ const collectChildren = (parentId: string) => {
152
+ allNodes.forEach((child) => {
153
+ if (child.parentId === parentId) {
154
+ hidden.add(child.id);
155
+ if (child.type === 'CompositeStateNode') {
156
+ collectChildren(child.id);
157
+ }
158
+ }
159
+ });
160
+ };
161
+ collapsedComposites.forEach((comp) => collectChildren(comp.id));
162
+ return hidden;
163
+ }
164
+
165
+ // Helper: get center position in diagram
166
+ const getCenterPosition = (width: number, height: number) => {
167
+ return { x: width / 2 - 75, y: height / 2 - 40 };
168
+ };
169
+
170
+ const StateMachineDiagramFlowContent: React.FC<
171
+ StateMachineDiagramFlowProps
172
+ > = ({
173
+ nodes: initialNodes,
174
+ setNodes: parentSetNodes,
175
+ edges: initialEdges,
176
+ setEdges: parentSetEdges,
177
+ }) => {
178
+ // State declarations
179
+ const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes as Node[]);
180
+ const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges as Edge[]);
181
+ const [history, setHistory] = useState<HistoryState[]>([]);
182
+ const [historyIndex, setHistoryIndex] = useState<number>(-1);
183
+ const isUndoRedoAction = useRef(false);
184
+ const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
185
+ const diagramContainerRef = useRef<HTMLDivElement>(null);
186
+ const [editing, setEditing] = useState<{
187
+ nodeId?: string | null;
188
+ edgeId?: string | null;
189
+ label?: string;
190
+ type?: 'node' | 'edge';
191
+ }>({});
192
+ const [stateNodeSettings, setStateNodeSettings] = useState<{
193
+ id: string | null;
194
+ }>({ id: null });
195
+ const [edgeSettings, setEdgeSettings] = useState<{ id: string | null }>({
196
+ id: null,
197
+ });
198
+ const [selectedCompositeStateNodeId, setSelectedCompositeStateNodeId] =
199
+ useState<string | null>(null);
200
+ const [isSettingsSidebarOpen, setIsSettingsSidebarOpen] = useState(false);
201
+
202
+ // Add layout integration
203
+ const { getLayoutedElements, layoutDirection, setLayoutDirection } =
204
+ useStateMachineLayout(nodes as Node[], edges as StateMachineEdge[], setNodes);
205
+
206
+ // Function declarations in correct order
207
+ const handleToggleCompositeExpand = useCallback(
208
+ (id: string, expanded: boolean) => {
209
+ setNodes((nds: Node[]) =>
210
+ nds.map((node: Node) =>
211
+ node.id === id && node.type === 'CompositeStateNode'
212
+ ? { ...node, data: { ...node.data, expanded } }
213
+ : node,
214
+ ),
215
+ );
216
+ },
217
+ [setNodes],
218
+ );
219
+
220
+ const nodeTypes = useMemo(() => {
221
+ return {
222
+ ...baseStateMachineNodeTypes,
223
+ CompositeStateNode: (props: NodeProps) => {
224
+ const compositeProps: CompositeStateNodeProps = {
225
+ ...props,
226
+ onToggleExpand: handleToggleCompositeExpand,
227
+ onSettingsClick: undefined,
228
+ };
229
+ return <CompositeStateNodeType {...compositeProps} />;
230
+ },
231
+ };
232
+ }, [handleToggleCompositeExpand]);
233
+
234
+ const saveLabel = useCallback(() => {
235
+ if (editing.nodeId && editing.type === 'node') {
236
+ setNodes((nds: Node[]) =>
237
+ nds.map((node: Node) => {
238
+ if (node.id === editing.nodeId) {
239
+ return {
240
+ ...node,
241
+ data: {
242
+ ...node.data,
243
+ label: editing.label,
244
+ },
245
+ };
246
+ }
247
+ return node;
248
+ }),
249
+ );
250
+ setEditing({
251
+ nodeId: undefined,
252
+ edgeId: undefined,
253
+ label: undefined,
254
+ type: undefined,
255
+ });
256
+ } else if (editing.edgeId && editing.type === 'edge') {
257
+ setEdges((eds: Edge[]) =>
258
+ eds.map((edge: Edge) => {
259
+ if (edge.id === editing.edgeId) {
260
+ return {
261
+ ...edge,
262
+ data: {
263
+ ...edge.data,
264
+ label: editing.label,
265
+ },
266
+ };
267
+ }
268
+ return edge;
269
+ }),
270
+ );
271
+ setEditing({
272
+ nodeId: undefined,
273
+ edgeId: undefined,
274
+ label: undefined,
275
+ type: undefined,
276
+ });
277
+ }
278
+ }, [editing, setNodes, setEdges]);
279
+
280
+ const handleKeyDown = useCallback(
281
+ (e: React.KeyboardEvent) => {
282
+ if (e.key === 'Enter') {
283
+ saveLabel();
284
+ } else if (e.key === 'Escape') {
285
+ setEditing({
286
+ nodeId: undefined,
287
+ edgeId: undefined,
288
+ label: undefined,
289
+ type: undefined,
290
+ });
291
+ }
292
+ },
293
+ [saveLabel],
294
+ );
295
+
296
+ const loadTemplateData = useCallback(
297
+ (templateType: string) => {
298
+ console.log(`Loading template: ${templateType}`);
299
+ // For now, just load the default state machine nodes/edges
300
+ setNodes(stateMachineDefaultNodes as Node[]);
301
+ setEdges(stateMachineDefaultEdges as Edge[]);
302
+ },
303
+ [setNodes, setEdges],
304
+ );
305
+
306
+ // Initialize nodes and edges with our data
307
+ useEffect(() => {
308
+ // Only initialize if history is empty
309
+ if (history.length === 0) {
310
+ const initialState = {
311
+ nodes: [...nodes],
312
+ edges: [...edges],
313
+ };
314
+ setHistory([initialState]);
315
+ setHistoryIndex(0);
316
+ }
317
+ }, []);
318
+
319
+ // Save current state to history when nodes or edges change (debounced)
320
+ const debouncedUpdateHistory = useRef(
321
+ debounce(
322
+ (
323
+ nodes: Node[],
324
+ edges: Edge[],
325
+ history: HistoryState[],
326
+ historyIndex: number,
327
+ setHistory: React.Dispatch<React.SetStateAction<HistoryState[]>>,
328
+ setHistoryIndex: React.Dispatch<React.SetStateAction<number>>,
329
+ ) => {
330
+ const newHistoryEntry = {
331
+ nodes: [...nodes],
332
+ edges: [...edges],
333
+ };
334
+ const currentState = history[historyIndex];
335
+ if (
336
+ currentState &&
337
+ deepCompareNodes(currentState.nodes, newHistoryEntry.nodes) &&
338
+ deepCompareEdges(currentState.edges, newHistoryEntry.edges)
339
+ ) {
340
+ return; // No change, don't add to history
341
+ }
342
+ // Trim future history if we're in the middle of the history stack
343
+ let newHistory = history.slice(0, historyIndex + 1);
344
+ newHistory.push(newHistoryEntry);
345
+ // Limit to last 50 entries
346
+ if (newHistory.length > 50) {
347
+ newHistory = newHistory.slice(newHistory.length - 50);
348
+ }
349
+ setHistory(newHistory);
350
+ setHistoryIndex(newHistory.length - 1);
351
+ },
352
+ 300,
353
+ ),
354
+ ).current;
355
+
356
+ useEffect(() => {
357
+ if (isUndoRedoAction.current || history.length === 0) {
358
+ return;
359
+ }
360
+ debouncedUpdateHistory(
361
+ nodes,
362
+ edges,
363
+ history,
364
+ historyIndex,
365
+ setHistory,
366
+ setHistoryIndex,
367
+ );
368
+ // eslint-disable-next-line react-hooks/exhaustive-deps
369
+ }, [nodes, edges]);
370
+
371
+ // Function to perform undo operation
372
+ const handleUndo = useCallback(() => {
373
+ if (historyIndex > 0) {
374
+ isUndoRedoAction.current = true;
375
+ const prevState = history[historyIndex - 1];
376
+ setNodes(prevState.nodes);
377
+ setEdges(prevState.edges);
378
+ setHistoryIndex(historyIndex - 1);
379
+ setTimeout(() => {
380
+ isUndoRedoAction.current = false;
381
+ }, 0);
382
+ }
383
+ }, [history, historyIndex, setNodes, setEdges]);
384
+
385
+ // Function to perform redo operation
386
+ const handleRedo = useCallback(() => {
387
+ if (historyIndex < history.length - 1) {
388
+ isUndoRedoAction.current = true;
389
+ const nextState = history[historyIndex + 1];
390
+ setNodes(nextState.nodes);
391
+ setEdges(nextState.edges);
392
+ setHistoryIndex(historyIndex + 1);
393
+ setTimeout(() => {
394
+ isUndoRedoAction.current = false;
395
+ }, 0);
396
+ }
397
+ }, [history, historyIndex, setNodes, setEdges]);
398
+
399
+ // Clear handler
400
+ const handleClear = useCallback(() => {
401
+ const cleared = { nodes: [], edges: [] };
402
+ const newHistory = history.slice(0, historyIndex + 1);
403
+ newHistory.push(cleared);
404
+ setNodes([]);
405
+ setEdges([]);
406
+ setHistory(newHistory);
407
+ setHistoryIndex(newHistory.length - 1);
408
+ }, [history, historyIndex, setNodes, setEdges]);
409
+
410
+ // Listen for keyboard shortcuts
411
+ useEffect(() => {
412
+ const handleKeyDown = (e: KeyboardEvent) => {
413
+ // Check for Ctrl+Z or Cmd+Z (undo)
414
+ if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
415
+ e.preventDefault();
416
+ handleUndo();
417
+ }
418
+ // Check for Ctrl+Y or Cmd+Shift+Z (redo)
419
+ if (
420
+ ((e.ctrlKey || e.metaKey) && e.key === 'y') ||
421
+ ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z')
422
+ ) {
423
+ e.preventDefault();
424
+ handleRedo();
425
+ }
426
+ };
427
+
428
+ window.addEventListener('keydown', handleKeyDown);
429
+ return () => {
430
+ window.removeEventListener('keydown', handleKeyDown);
431
+ };
432
+ }, [handleUndo, handleRedo]);
433
+
434
+ // Node type map for state machine nodes
435
+ const nodeTypeMap: Record<string, { type: string; data?: Record<string, unknown> }> = {
436
+ StateNode: { type: 'StateNode', data: { label: 'State' } },
437
+ InitialStateNode: { type: 'InitialStateNode', data: {} },
438
+ FinalStateNode: { type: 'FinalStateNode', data: {} },
439
+ CompositeStateNode: {
440
+ type: 'CompositeStateNode',
441
+ data: { label: 'Composite State', expanded: false },
442
+ },
443
+ HistoryStateNode: { type: 'HistoryStateNode', data: {} },
444
+ JunctionPointNode: { type: 'JunctionPointNode', data: {} },
445
+ ChoicePointNode: { type: 'ChoicePointNode', data: {} },
446
+ EntryPointNode: { type: 'EntryPointNode', data: {} },
447
+ ExitPointNode: { type: 'ExitPointNode', data: {} },
448
+ ForkJoinNode: { type: 'ForkJoinNode', data: { orientation: 'horizontal' } },
449
+ BendpointNode: { type: 'bendpoint', data: {} },
450
+ };
451
+
452
+ // Add node at center (internal)
453
+ const addNodeAtCenter = useCallback(
454
+ (nodeTypeId: string) => {
455
+ const nodeInfo = nodeTypeMap[nodeTypeId];
456
+ if (!nodeInfo) return;
457
+ const { type, data } = nodeInfo;
458
+ const width = diagramContainerRef.current?.offsetWidth || 1200;
459
+ const height = diagramContainerRef.current?.offsetHeight || 800;
460
+ const center = getCenterPosition(width, height);
461
+ const newId = `${nodeTypeId}-${nodes.length + 1}`;
462
+
463
+ // Add onResize handler to node data
464
+ const onResize = (id: string, width: number, height: number) => {
465
+ setNodes((nds) =>
466
+ nds.map((node) =>
467
+ node.id === id
468
+ ? {
469
+ ...node,
470
+ measured: { width, height },
471
+ width: width,
472
+ height: height,
473
+ }
474
+ : node,
475
+ ),
476
+ );
477
+ // Update all selfconnecting edges for this node with new size/position
478
+ setEdges((eds) =>
479
+ eds.map((edge) => {
480
+ if (
481
+ edge.type === 'selfconnecting' &&
482
+ edge.source === id &&
483
+ edge.target === id
484
+ ) {
485
+ // Find the node to get its position
486
+ const node = nodes.find((n) => n.id === id);
487
+ const nodeX = node?.position?.x ?? 0;
488
+ const nodeY = node?.position?.y ?? 0;
489
+ return {
490
+ ...edge,
491
+ data: {
492
+ ...edge.data,
493
+ nodeWidth: width,
494
+ nodeHeight: height,
495
+ nodeX,
496
+ nodeY,
497
+ },
498
+ };
499
+ }
500
+ return edge;
501
+ }),
502
+ );
503
+ };
504
+
505
+ setNodes((nds: Node[]) => [
506
+ ...nds,
507
+ {
508
+ id: newId,
509
+ type,
510
+ position: center,
511
+ data: { ...data, onResize },
512
+ draggable: true,
513
+ },
514
+ ]);
515
+ },
516
+ [nodes, setNodes, setEdges],
517
+ );
518
+
519
+ // Update onAddEntity to use internal addNodeAtCenter
520
+ const handleAddEntity = useCallback(
521
+ (nodeTypeId = 'StateNode') => {
522
+ addNodeAtCenter(nodeTypeId);
523
+ },
524
+ [addNodeAtCenter],
525
+ );
526
+
527
+ // Function to export diagram as JSON
528
+ const exportDiagram = useCallback(() => {
529
+ const diagramData = {
530
+ nodes: nodes,
531
+ edges: edges,
532
+ };
533
+
534
+ const dataStr = JSON.stringify(diagramData, null, 2);
535
+ const dataUri =
536
+ 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
537
+
538
+ const exportFileDefaultName = 'state-machine-diagram.json';
539
+
540
+ const linkElement = document.createElement('a');
541
+ linkElement.setAttribute('href', dataUri);
542
+ linkElement.setAttribute('download', exportFileDefaultName);
543
+ linkElement.click();
544
+ }, [nodes, edges]);
545
+
546
+ // Function to import diagram from JSON
547
+ const importDiagram = useCallback(
548
+ (event: React.ChangeEvent<HTMLInputElement>) => {
549
+ if (!event.target.files || event.target.files.length === 0) return;
550
+
551
+ const fileReader = new FileReader();
552
+ fileReader.readAsText(event.target.files[0], 'UTF-8');
553
+ fileReader.onload = (e) => {
554
+ try {
555
+ if (!e.target || typeof e.target.result !== 'string') return;
556
+
557
+ const imported = JSON.parse(e.target.result);
558
+ if (imported.nodes && imported.edges) {
559
+ setNodes(imported.nodes);
560
+ setEdges(imported.edges);
561
+ }
562
+ } catch (error) {
563
+ console.error('Error importing diagram:', error);
564
+ alert('Failed to import diagram. Invalid file format.');
565
+ }
566
+ };
567
+ },
568
+ [setNodes, setEdges],
569
+ );
570
+
571
+ // Toggle fullscreen mode
572
+ const toggleFullscreen = useCallback(() => {
573
+ if (!diagramContainerRef.current) return;
574
+
575
+ if (!isFullscreen) {
576
+ if (diagramContainerRef.current.requestFullscreen) {
577
+ diagramContainerRef.current.requestFullscreen();
578
+ } else if ((diagramContainerRef.current as FullscreenElement).webkitRequestFullscreen) {
579
+ (diagramContainerRef.current as FullscreenElement).webkitRequestFullscreen?.();
580
+ } else if ((diagramContainerRef.current as FullscreenElement).msRequestFullscreen) {
581
+ (diagramContainerRef.current as FullscreenElement).msRequestFullscreen?.();
582
+ }
583
+ } else {
584
+ if (document.exitFullscreen) {
585
+ document.exitFullscreen();
586
+ } else if ((document as FullscreenDocument).webkitExitFullscreen) {
587
+ (document as FullscreenDocument).webkitExitFullscreen?.();
588
+ } else if ((document as FullscreenDocument).msExitFullscreen) {
589
+ (document as FullscreenDocument).msExitFullscreen?.();
590
+ }
591
+ }
592
+
593
+ setIsFullscreen(!isFullscreen);
594
+ }, [isFullscreen]);
595
+
596
+ // Listen for fullscreen change events from browser
597
+ useEffect(() => {
598
+ const handleFullscreenChange = () => {
599
+ setIsFullscreen(!!document.fullscreenElement);
600
+ };
601
+
602
+ document.addEventListener('fullscreenchange', handleFullscreenChange);
603
+ document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
604
+ document.addEventListener('mozfullscreenchange', handleFullscreenChange);
605
+ document.addEventListener('MSFullscreenChange', handleFullscreenChange);
606
+
607
+ return () => {
608
+ document.removeEventListener('fullscreenchange', handleFullscreenChange);
609
+ document.removeEventListener(
610
+ 'webkitfullscreenchange',
611
+ handleFullscreenChange,
612
+ );
613
+ document.removeEventListener(
614
+ 'mozfullscreenchange',
615
+ handleFullscreenChange,
616
+ );
617
+ document.removeEventListener(
618
+ 'MSFullscreenChange',
619
+ handleFullscreenChange,
620
+ );
621
+ };
622
+ }, []);
623
+
624
+ // Modified onConnect to open EdgeSettings after edge is created
625
+ const onConnect = useCallback(
626
+ (params: Connection) => {
627
+ if (!params.source || !params.target) return;
628
+ const sourceNode = nodes.find((n) => n.id === params.source);
629
+ const targetNode = nodes.find((n) => n.id === params.target);
630
+ if (!sourceNode || !targetNode) return;
631
+
632
+ const newEdge = {
633
+ id: `edge-${edges.length + 1}`,
634
+ source: params.source,
635
+ target: params.target,
636
+ type: 'customEdge',
637
+ sourceHandle: params.sourceHandle,
638
+ targetHandle: params.targetHandle,
639
+ data: {
640
+ label: `Transition ${edges.length + 1}`,
641
+ },
642
+ animated: false,
643
+ };
644
+ setEdges((eds: Edge[]) => [...eds, newEdge]);
645
+ setEdgeSettings({ id: newEdge.id });
646
+ setIsSettingsSidebarOpen(true);
647
+ },
648
+ [nodes, edges, setEdges],
649
+ );
650
+
651
+ // Update onNodeClick function
652
+ const onNodeClick = useCallback((event: React.MouseEvent, node: Node) => {
653
+ if (node.type === 'bendpoint') {
654
+ setStateNodeSettings({ id: null });
655
+ setSelectedCompositeStateNodeId(null);
656
+ return;
657
+ }
658
+
659
+ if (node.type === 'CompositeStateNode') {
660
+ setSelectedCompositeStateNodeId(node.id);
661
+ setStateNodeSettings({ id: null });
662
+ setIsSettingsSidebarOpen(true);
663
+ } else if (
664
+ [
665
+ 'StateNode',
666
+ 'InitialStateNode',
667
+ 'FinalStateNode',
668
+ 'HistoryStateNode',
669
+ 'JunctionPointNode',
670
+ 'ChoicePointNode',
671
+ 'EntryPointNode',
672
+ 'ExitPointNode',
673
+ 'ForkJoinNode',
674
+ ].includes(node.type || '')
675
+ ) {
676
+ setStateNodeSettings({ id: node.id });
677
+ setSelectedCompositeStateNodeId(null);
678
+ setIsSettingsSidebarOpen(true);
679
+ } else {
680
+ setStateNodeSettings({ id: null });
681
+ setSelectedCompositeStateNodeId(null);
682
+ }
683
+ }, []);
684
+
685
+ // Update onNodeDoubleClick function
686
+ const onNodeDoubleClick = useCallback(
687
+ (event: React.MouseEvent, node: Node) => {
688
+ event.preventDefault();
689
+ event.stopPropagation();
690
+ setEditing({
691
+ nodeId: node.id,
692
+ edgeId: null,
693
+ label: (node.data?.label as string) || '',
694
+ type: 'node',
695
+ });
696
+ },
697
+ [setEditing],
698
+ );
699
+
700
+ // Open EdgeSettings on double click
701
+ const onEdgeDoubleClick = useCallback(
702
+ (event: React.MouseEvent, edge: Edge) => {
703
+ event.preventDefault();
704
+ event.stopPropagation();
705
+ if (edge.type === 'customEdge') {
706
+ setEdgeSettings({ id: edge.id });
707
+ setIsSettingsSidebarOpen(true);
708
+ }
709
+ },
710
+ [],
711
+ );
712
+
713
+ // Function to update selected state node
714
+ const updateSelectedStateNode = useCallback(
715
+ (updates: Record<string, unknown>) => {
716
+ if (!stateNodeSettings.id) return;
717
+ setNodes((nds: Node[]) =>
718
+ nds.map((node: Node) => {
719
+ if (node.id === stateNodeSettings.id) {
720
+ return {
721
+ ...node,
722
+ data: {
723
+ ...node.data,
724
+ ...updates,
725
+ },
726
+ };
727
+ }
728
+ return node;
729
+ }),
730
+ );
731
+ },
732
+ [stateNodeSettings.id, setNodes],
733
+ );
734
+
735
+ // Close state node settings
736
+ const closeStateNodeSettings = useCallback(() => {
737
+ setStateNodeSettings({ id: null });
738
+ setIsSettingsSidebarOpen(false);
739
+ }, []);
740
+
741
+ // Update edge from EdgeSettings
742
+ const updateSelectedEdge = useCallback(
743
+ (updates: Record<string, unknown>) => {
744
+ if (!edgeSettings.id) return;
745
+ setEdges((eds: Edge[]) =>
746
+ eds.map((edge: Edge) => {
747
+ if (edge.id === edgeSettings.id) {
748
+ return {
749
+ ...edge,
750
+ source: typeof updates.source === 'string' ? updates.source : edge.source,
751
+ target: typeof updates.target === 'string' ? updates.target : edge.target,
752
+ data: {
753
+ ...edge.data,
754
+ ...updates,
755
+ },
756
+ };
757
+ }
758
+ return edge;
759
+ }) as Edge[],
760
+ );
761
+ },
762
+ [edgeSettings.id, setEdges],
763
+ );
764
+
765
+ // Close EdgeSettings
766
+ const closeEdgeSettings = useCallback(() => {
767
+ setEdgeSettings({ id: null });
768
+ setIsSettingsSidebarOpen(false);
769
+ }, []);
770
+
771
+ // Close CompositeStateNodeSettings
772
+ const closeCompositeStateNodeSettings = useCallback(() => {
773
+ setSelectedCompositeStateNodeId(null);
774
+ setIsSettingsSidebarOpen(false);
775
+ }, []);
776
+
777
+ // Function to update selected composite state node
778
+ const updateSelectedCompositeStateNode = useCallback(
779
+ (updates: Record<string, unknown>) => {
780
+ if (!selectedCompositeStateNodeId) return;
781
+ setNodes((nds: Node[]) =>
782
+ nds.map((node: Node) => {
783
+ if (node.id === selectedCompositeStateNodeId) {
784
+ return {
785
+ ...node,
786
+ data: {
787
+ ...node.data,
788
+ ...updates,
789
+ },
790
+ };
791
+ }
792
+ return node;
793
+ }),
794
+ );
795
+ },
796
+ [selectedCompositeStateNodeId, setNodes],
797
+ );
798
+
799
+ // Collapse all composite nodes on pane click
800
+ const handlePaneClick = useCallback(() => {
801
+ setNodes((nds: Node[]) =>
802
+ nds.map((node: Node) =>
803
+ node.type === 'CompositeStateNode'
804
+ ? { ...node, data: { ...node.data, expanded: false } }
805
+ : node,
806
+ ),
807
+ );
808
+ setSelectedCompositeStateNodeId(null);
809
+ setStateNodeSettings({ id: null });
810
+ }, [setNodes]);
811
+
812
+ // Memoize hidden node ids
813
+ const hiddenNodeIds = useMemo(() => getHiddenNodeIds(nodes), [nodes]);
814
+ // Memoize filtered nodes
815
+ const filteredNodes = useMemo(
816
+ () => nodes.filter((n) => !hiddenNodeIds.has(n.id)),
817
+ [nodes, hiddenNodeIds],
818
+ );
819
+ // Memoize collapsed composites
820
+ const collapsedComposites = useMemo(
821
+ () =>
822
+ nodes.filter((n) => n.type === 'CompositeStateNode' && !n.data.expanded),
823
+ [nodes],
824
+ );
825
+ // Memoize proxy edge logic (optimized for performance)
826
+ const { filteredEdges } = useMemo(() => {
827
+ // Precompute collapsed composite node ids for O(1) lookup
828
+ const collapsedCompositeIds = new Set(
829
+ nodes
830
+ .filter((n) => n.type === 'CompositeStateNode' && !n.data.expanded)
831
+ .map((n) => n.id),
832
+ );
833
+ // Precompute a map of nodeId -> node for O(1) lookup
834
+ const nodeIdMap = new Map(nodes.map((n) => [n.id, n]));
835
+ // Map childId to its collapsed composite parent
836
+ const childToCollapsedParent: Record<string, string> = {};
837
+ const collectChildren = (parentId: string) => {
838
+ nodes.forEach((child) => {
839
+ if (child.parentId === parentId) {
840
+ childToCollapsedParent[child.id] = parentId;
841
+ if (child.type === 'CompositeStateNode') {
842
+ collectChildren(child.id);
843
+ }
844
+ }
845
+ });
846
+ };
847
+ collapsedCompositeIds.forEach((compId) => collectChildren(compId));
848
+ // Generate proxy edges for edges crossing collapsed composite boundaries
849
+ const proxyEdges: Edge[] = [];
850
+ const realEdges: Edge[] = [];
851
+ edges.forEach((edge) => {
852
+ const sourceHidden = hiddenNodeIds.has(edge.source);
853
+ const targetHidden = hiddenNodeIds.has(edge.target);
854
+
855
+ // Self-loop on composite node: hide if collapsed
856
+ if (
857
+ edge.source === edge.target &&
858
+ collapsedCompositeIds.has(edge.source)
859
+ ) {
860
+ return; // skip this edge
861
+ }
862
+
863
+ // If both ends are hidden, skip (don't show)
864
+ if (sourceHidden && targetHidden) return;
865
+ // If neither end is hidden, show as normal
866
+ if (!sourceHidden && !targetHidden) {
867
+ realEdges.push(edge);
868
+ return;
869
+ }
870
+ // If one end is hidden and the other is visible, create a proxy edge
871
+ let proxySource = edge.source;
872
+ let proxyTarget = edge.target;
873
+ let proxyId = edge.id + '-proxy';
874
+ // If source is hidden, map to its collapsed composite parent
875
+ if (sourceHidden && childToCollapsedParent[edge.source]) {
876
+ proxySource = childToCollapsedParent[edge.source];
877
+ }
878
+ // If target is hidden, map to its collapsed composite parent
879
+ if (targetHidden && childToCollapsedParent[edge.target]) {
880
+ proxyTarget = childToCollapsedParent[edge.target];
881
+ }
882
+ // Avoid proxying to the same node (self-loop)
883
+ if (proxySource === proxyTarget) return;
884
+ proxyEdges.push({
885
+ ...edge,
886
+ id: proxyId,
887
+ source: proxySource,
888
+ target: proxyTarget,
889
+ style: { ...(edge.style || {}), strokeDasharray: '6 4', opacity: 0.7 },
890
+ data: { ...(edge.data || {}), isProxy: true },
891
+ });
892
+ });
893
+ return { filteredEdges: [...realEdges, ...proxyEdges] as Edge[] };
894
+ }, [edges, nodes, hiddenNodeIds]);
895
+
896
+ // Custom onNodesChange to snap PinPointNode to border of parent composite node
897
+ const customOnNodesChange = useCallback(
898
+ (changes: NodeChange[]) => {
899
+ setNodes((nds) => {
900
+ // Apply default node changes
901
+ let updated = applyNodeChanges(changes, nds);
902
+ // Snap PinPointNode nodes to border of parent composite node
903
+ updated = updated.map((node) => {
904
+ if (node.type === 'PinPointNode' && node.parentId) {
905
+ const parent = nds.find((n) => n.id === node.parentId);
906
+ if (!parent) return node;
907
+ const width = (parent.data as Record<string, unknown>).width as number || 400;
908
+ const height = (parent.data as Record<string, unknown>).height as number || 300;
909
+ const size = 22;
910
+ let { x, y } = node.position;
911
+ // Calculate center
912
+ const cx = x + size / 2;
913
+ const cy = y + size / 2;
914
+ // Find closest border (top, bottom, left, right)
915
+ const dTop = Math.abs(cy - 0);
916
+ const dBottom = Math.abs(cy - height);
917
+ const dLeft = Math.abs(cx - 0);
918
+ const dRight = Math.abs(cx - width);
919
+ const minDist = Math.min(dTop, dBottom, dLeft, dRight);
920
+ let newX = x,
921
+ newY = y;
922
+ if (minDist === dTop) {
923
+ newX =
924
+ Math.max(-size / 2, Math.min(width - size / 2, cx)) - size / 2;
925
+ newY = -size / 2;
926
+ } else if (minDist === dBottom) {
927
+ newX =
928
+ Math.max(-size / 2, Math.min(width - size / 2, cx)) - size / 2;
929
+ newY = height - size / 2;
930
+ } else if (minDist === dLeft) {
931
+ newX = -size / 2;
932
+ newY =
933
+ Math.max(-size / 2, Math.min(height - size / 2, cy)) - size / 2;
934
+ } else if (minDist === dRight) {
935
+ newX = width - size / 2;
936
+ newY =
937
+ Math.max(-size / 2, Math.min(height - size / 2, cy)) - size / 2;
938
+ }
939
+ return { ...node, position: { x: newX, y: newY } };
940
+ }
941
+ return node;
942
+ });
943
+ return updated;
944
+ });
945
+ },
946
+ [setNodes],
947
+ );
948
+
949
+ // Add layout direction change handler
950
+ const handleLayoutDirectionChange = useCallback(
951
+ (direction: 'DOWN' | 'RIGHT') => {
952
+ setLayoutDirection(direction);
953
+ getLayoutedElements();
954
+ },
955
+ [setLayoutDirection, getLayoutedElements],
956
+ );
957
+
958
+ // Add layout effect
959
+ useEffect(() => {
960
+ // Only layout if we have nodes/edges
961
+ if (nodes.length > 0 || edges.length > 0) {
962
+ getLayoutedElements();
963
+ }
964
+ }, [handleToggleCompositeExpand]);
965
+
966
+ // Add edge edit handlers
967
+ const handleEditEdge = useCallback((edge: Edge) => {
968
+ setEdgeSettings({ id: edge.id });
969
+ }, []);
970
+
971
+ const handleUpdateEdgeLabel = useCallback(
972
+ (edgeId: string, newLabel: string) => {
973
+ setEdges((eds: Edge[]) =>
974
+ eds.map((edge: Edge) =>
975
+ edge.id === edgeId
976
+ ? { ...edge, data: { ...edge.data, label: newLabel } }
977
+ : edge,
978
+ ),
979
+ );
980
+ },
981
+ [setEdges],
982
+ );
983
+
984
+ const handleToggleEdgeArrowHead = useCallback(
985
+ (edgeId: string, direction: 'left' | 'right') => {
986
+ setEdges((eds: Edge[]) =>
987
+ eds.map((edge: Edge) => {
988
+ if (edge.id === edgeId) {
989
+ const data = { ...edge.data };
990
+ if (direction === 'left') {
991
+ data.arrowHeadLeft = !data.arrowHeadLeft;
992
+ } else {
993
+ data.arrowHeadRight = !data.arrowHeadRight;
994
+ }
995
+ return { ...edge, data };
996
+ }
997
+ return edge;
998
+ }),
999
+ );
1000
+ },
1001
+ [setEdges],
1002
+ );
1003
+
1004
+ // Memoize node and edge maps for O(1) lookup
1005
+ const nodeMap = useMemo(() => {
1006
+ const map = new Map<string, Node>();
1007
+ nodes.forEach((node) => map.set(node.id, node));
1008
+ return map;
1009
+ }, [nodes]);
1010
+ const edgeMap = useMemo(() => {
1011
+ const map = new Map<string, Edge>();
1012
+ edges.forEach((edge) => map.set(edge.id, edge));
1013
+ return map;
1014
+ }, [edges]);
1015
+
1016
+ return (
1017
+ <Box sx={{ display: 'flex', height: '100vh' }}>
1018
+ <Sidebar>
1019
+ <NodeSelectionContext.Provider
1020
+ value={{
1021
+ selectedNodeType: null,
1022
+ setSelectedNodeType: () => { },
1023
+ addNodeAtCenter,
1024
+ }}
1025
+ >
1026
+ <DiagramControls
1027
+ onAddEntity={handleAddEntity}
1028
+ onUndo={handleUndo}
1029
+ onRedo={handleRedo}
1030
+ canUndo={historyIndex > 0}
1031
+ canRedo={historyIndex < history.length - 1}
1032
+ onLoadTemplate={loadTemplateData}
1033
+ edges={edges as StateMachineEdge[]}
1034
+ nodes={nodes as StateMachineNode[]}
1035
+ onEditEdge={handleEditEdge}
1036
+ onUpdateEdgeLabel={handleUpdateEdgeLabel}
1037
+ onToggleEdgeArrowHead={handleToggleEdgeArrowHead}
1038
+ />
1039
+ </NodeSelectionContext.Provider>
1040
+ </Sidebar>
1041
+
1042
+ <Box
1043
+ sx={{
1044
+ flexGrow: 1,
1045
+ '& .react-flow__edge': {
1046
+ zIndex: '5000 !important',
1047
+ },
1048
+ '& .react-flow__edge-path': {
1049
+ pointerEvents: 'all !important',
1050
+ },
1051
+ '& .edge-path-selector': {
1052
+ strokeWidth: 20,
1053
+ fill: 'none',
1054
+ stroke: 'transparent',
1055
+ cursor: 'pointer',
1056
+ },
1057
+ '& .react-flow__edges': {
1058
+ zIndex: '5000 !important',
1059
+ },
1060
+ '& .react-flow__node': {
1061
+ pointerEvents: 'all !important',
1062
+ cursor: 'grab',
1063
+ '&:active': {
1064
+ cursor: 'grabbing',
1065
+ },
1066
+ '& .react-flow__edge': {
1067
+ zIndex: '5000 !important',
1068
+ },
1069
+ },
1070
+ '& .react-flow__node.dragging': {
1071
+ cursor: 'grabbing !important',
1072
+ },
1073
+ '& .react-flow.dragging': {
1074
+ cursor: 'grabbing',
1075
+ },
1076
+ }}
1077
+ >
1078
+ <Box
1079
+ sx={{
1080
+ width: '100%',
1081
+ height: '100%',
1082
+ padding: '10px',
1083
+ bgcolor: 'white',
1084
+ }}
1085
+ >
1086
+ <ReactFlow
1087
+ nodes={filteredNodes}
1088
+ edges={filteredEdges}
1089
+ onNodesChange={customOnNodesChange}
1090
+ onEdgesChange={onEdgesChange}
1091
+ onConnect={onConnect}
1092
+ nodeTypes={nodeTypes}
1093
+ edgeTypes={stateMachineEdgeTypes}
1094
+ fitView
1095
+ fitViewOptions={{
1096
+ padding: 0.2,
1097
+ minZoom: 0.5,
1098
+ maxZoom: 2,
1099
+ }}
1100
+ minZoom={0.1}
1101
+ maxZoom={2}
1102
+ defaultViewport={{ x: 0, y: 0, zoom: 1 }}
1103
+ style={{
1104
+ background: '#f8f9fa',
1105
+ }}
1106
+ proOptions={{ hideAttribution: true }}
1107
+ selectNodesOnDrag={false}
1108
+ connectOnClick={false}
1109
+ onNodeClick={onNodeClick}
1110
+ onNodeDoubleClick={onNodeDoubleClick}
1111
+ onEdgeDoubleClick={onEdgeDoubleClick}
1112
+ onPaneClick={handlePaneClick}
1113
+ >
1114
+ <Background
1115
+ color="#f8f9fa"
1116
+ variant={BackgroundVariant.Dots}
1117
+ gap={16}
1118
+ />
1119
+
1120
+ {/* MiniMap positioned at bottom-left */}
1121
+ <MiniMapCommon />
1122
+
1123
+ {/* Diagram Panel with all controls */}
1124
+ <DiagramPanel
1125
+ historyIndex={historyIndex}
1126
+ historyLength={history.length}
1127
+ onUndo={handleUndo}
1128
+ onRedo={handleRedo}
1129
+ onClear={handleClear}
1130
+ onImport={(data) => {
1131
+ setNodes(data.nodes || []);
1132
+ setEdges(data.edges || []);
1133
+ // Add to history
1134
+ const newHistoryState = {
1135
+ nodes: data.nodes || [],
1136
+ edges: data.edges || [],
1137
+ };
1138
+ setHistory((prev) => [
1139
+ ...prev.slice(0, historyIndex + 1),
1140
+ newHistoryState,
1141
+ ]);
1142
+ setHistoryIndex((prev) => prev + 1);
1143
+ }}
1144
+ isSettingsOpen={isSettingsSidebarOpen}
1145
+ onToggleSettings={() => setIsSettingsSidebarOpen(true)}
1146
+ showCustomControls={true}
1147
+ onGridLayout={() => handleLayoutDirectionChange('DOWN')}
1148
+ onTreeLayout={() => handleLayoutDirectionChange('RIGHT')}
1149
+ />
1150
+
1151
+ {/* AI Button positioned at bottom-right */}
1152
+ <AiButton />
1153
+
1154
+ {/* Layout controls positioned at top-right */}
1155
+
1156
+ {/* Fullscreen button positioned at top-left */}
1157
+ </ReactFlow>
1158
+ </Box>
1159
+ </Box>
1160
+
1161
+ {/* Settings panels */}
1162
+ {stateNodeSettings.id && (
1163
+ <StateNodeSettings
1164
+ nodeId={stateNodeSettings.id}
1165
+ data={nodeMap.get(stateNodeSettings.id)?.data || {}}
1166
+ onUpdate={updateSelectedStateNode}
1167
+ onClose={closeStateNodeSettings}
1168
+ edges={edges as StateMachineEdge[]}
1169
+ setEdges={(updater) => {
1170
+ if (typeof updater === 'function') {
1171
+ setEdges((prev) => updater(prev as StateMachineEdge[]) as Edge[]);
1172
+ } else {
1173
+ setEdges(updater as Edge[]);
1174
+ }
1175
+ }}
1176
+ nodes={nodes as StateMachineNode[]}
1177
+ />
1178
+ )}
1179
+
1180
+ {edgeSettings.id && (
1181
+ <EdgeSettings
1182
+ data={{
1183
+ ...(edgeMap.get(edgeSettings.id)?.data || {}),
1184
+ source: edgeMap.get(edgeSettings.id)?.source,
1185
+ target: edgeMap.get(edgeSettings.id)?.target,
1186
+ }}
1187
+ nodes={nodes as StateMachineNode[]}
1188
+ onUpdate={updateSelectedEdge}
1189
+ onClose={closeEdgeSettings}
1190
+ onDelete={() => {
1191
+ setEdges((eds: Edge[]) =>
1192
+ eds.filter((edge: Edge) => edge.id !== edgeSettings.id),
1193
+ );
1194
+ closeEdgeSettings();
1195
+ }}
1196
+ />
1197
+ )}
1198
+
1199
+ {selectedCompositeStateNodeId && (
1200
+ <CompositeStateNodeSettings
1201
+ nodeId={selectedCompositeStateNodeId}
1202
+ data={nodeMap.get(selectedCompositeStateNodeId)?.data || {}}
1203
+ nodes={nodes as StateMachineNode[]}
1204
+ setNodes={(updater) => {
1205
+ if (typeof updater === 'function') {
1206
+ setNodes((prev) => updater(prev as StateMachineNode[]) as Node[]);
1207
+ } else {
1208
+ setNodes(updater as Node[]);
1209
+ }
1210
+ }}
1211
+ onUpdate={updateSelectedCompositeStateNode}
1212
+ onClose={closeCompositeStateNodeSettings}
1213
+ edges={edges as StateMachineEdge[]}
1214
+ setEdges={(updater) => {
1215
+ if (typeof updater === 'function') {
1216
+ setEdges((prev) => updater(prev as StateMachineEdge[]) as Edge[]);
1217
+ } else {
1218
+ setEdges(updater as Edge[]);
1219
+ }
1220
+ }}
1221
+ />
1222
+ )}
1223
+ </Box>
1224
+ );
1225
+ };
1226
+
1227
+ // Main wrapper component with ReactFlowProvider
1228
+ const StateMachineDiagramFlow: React.FC<StateMachineDiagramFlowProps> = (
1229
+ props,
1230
+ ) => {
1231
+ return (
1232
+ <ReactFlowProvider>
1233
+ <StateMachineDiagramFlowContent {...props} />
1234
+ </ReactFlowProvider>
1235
+ );
1236
+ };
1237
+
1238
+ export default StateMachineDiagramFlow;