@nyaruka/temba-components 0.141.1 → 0.142.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/static/svg/index.svg +1 -1
  3. package/dist/temba-components.js +849 -655
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/Icons.js +3 -1
  6. package/out-tsc/src/Icons.js.map +1 -1
  7. package/out-tsc/src/display/Button.js +2 -2
  8. package/out-tsc/src/display/Button.js.map +1 -1
  9. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  10. package/out-tsc/src/flow/CanvasMenu.js +24 -1
  11. package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
  12. package/out-tsc/src/flow/CanvasNode.js +7 -2
  13. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  14. package/out-tsc/src/flow/Editor.js +654 -66
  15. package/out-tsc/src/flow/Editor.js.map +1 -1
  16. package/out-tsc/src/flow/NodeEditor.js +8 -5
  17. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  18. package/out-tsc/src/flow/Plumber.js +40 -28
  19. package/out-tsc/src/flow/Plumber.js.map +1 -1
  20. package/out-tsc/src/flow/actions/send_msg.js +2 -1
  21. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  22. package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
  23. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  24. package/out-tsc/src/flow/reflow.js +393 -0
  25. package/out-tsc/src/flow/reflow.js.map +1 -0
  26. package/out-tsc/src/flow/types.js.map +1 -1
  27. package/out-tsc/src/flow/utils.js +18 -3
  28. package/out-tsc/src/flow/utils.js.map +1 -1
  29. package/out-tsc/src/form/Compose.js +5 -0
  30. package/out-tsc/src/form/Compose.js.map +1 -1
  31. package/out-tsc/src/form/FieldRenderer.js +1 -3
  32. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  33. package/out-tsc/src/layout/Dialog.js +2 -0
  34. package/out-tsc/src/layout/Dialog.js.map +1 -1
  35. package/out-tsc/src/list/SortableList.js +39 -19
  36. package/out-tsc/src/list/SortableList.js.map +1 -1
  37. package/out-tsc/test/temba-canvas-menu.test.js +44 -0
  38. package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
  39. package/out-tsc/test/temba-flow-collision.test.js +25 -0
  40. package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
  41. package/out-tsc/test/temba-flow-editor-zoom.test.js +491 -0
  42. package/out-tsc/test/temba-flow-editor-zoom.test.js.map +1 -0
  43. package/out-tsc/test/temba-flow-editor.test.js +145 -1
  44. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  45. package/out-tsc/test/temba-flow-node-drag.test.js +123 -0
  46. package/out-tsc/test/temba-flow-node-drag.test.js.map +1 -1
  47. package/out-tsc/test/temba-flow-plumber.test.js +31 -0
  48. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  49. package/out-tsc/test/temba-flow-reflow.test.js +472 -0
  50. package/out-tsc/test/temba-flow-reflow.test.js.map +1 -0
  51. package/out-tsc/test/temba-sortable-list.test.js +93 -0
  52. package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
  53. package/package.json +1 -1
  54. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  55. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  56. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  57. package/screenshots/truth/actions/add_contact_urn/editor/expression-facebook.png +0 -0
  58. package/screenshots/truth/actions/add_contact_urn/editor/expression-phone.png +0 -0
  59. package/screenshots/truth/actions/add_contact_urn/editor/facebook-id.png +0 -0
  60. package/screenshots/truth/actions/add_contact_urn/editor/instagram-handle.png +0 -0
  61. package/screenshots/truth/actions/add_contact_urn/editor/line-id.png +0 -0
  62. package/screenshots/truth/actions/add_contact_urn/editor/phone-number.png +0 -0
  63. package/screenshots/truth/actions/add_contact_urn/editor/telegram-id.png +0 -0
  64. package/screenshots/truth/actions/add_contact_urn/editor/viber-id.png +0 -0
  65. package/screenshots/truth/actions/add_contact_urn/editor/wechat-id.png +0 -0
  66. package/screenshots/truth/actions/add_contact_urn/editor/whatsapp.png +0 -0
  67. package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
  68. package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
  69. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  70. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  71. package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
  72. package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
  73. package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
  74. package/screenshots/truth/actions/send_broadcast/editor/contacts-only.png +0 -0
  75. package/screenshots/truth/actions/send_broadcast/editor/groups-and-contacts.png +0 -0
  76. package/screenshots/truth/actions/send_broadcast/editor/groups-only.png +0 -0
  77. package/screenshots/truth/actions/send_broadcast/editor/many-groups.png +0 -0
  78. package/screenshots/truth/actions/send_broadcast/editor/multiline-text.png +0 -0
  79. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  80. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  81. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  82. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  83. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  84. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  85. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  86. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  87. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  88. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  89. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  90. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  91. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  92. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  93. package/screenshots/truth/actions/set_contact_channel/editor/sms-channel.png +0 -0
  94. package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
  95. package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
  96. package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
  97. package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
  98. package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
  99. package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
  100. package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
  101. package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
  102. package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
  103. package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
  104. package/screenshots/truth/actions/start_session/editor/contact-query.png +0 -0
  105. package/screenshots/truth/actions/start_session/editor/contacts-only.png +0 -0
  106. package/screenshots/truth/actions/start_session/editor/create-contact.png +0 -0
  107. package/screenshots/truth/actions/start_session/editor/groups-and-contacts.png +0 -0
  108. package/screenshots/truth/actions/start_session/editor/groups-only.png +0 -0
  109. package/screenshots/truth/actions/start_session/editor/many-recipients.png +0 -0
  110. package/screenshots/truth/list/fields-dragging.png +0 -0
  111. package/screenshots/truth/list/sortable-dragging.png +0 -0
  112. package/screenshots/truth/modax/simple.png +0 -0
  113. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  114. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  115. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  116. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  117. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  118. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  119. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  120. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  121. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  122. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  123. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  124. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  125. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  126. package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
  127. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  128. package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
  129. package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
  130. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  131. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  132. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  133. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  134. package/src/Icons.ts +3 -1
  135. package/src/display/Button.ts +2 -2
  136. package/src/display/FloatingTab.ts +1 -1
  137. package/src/flow/CanvasMenu.ts +28 -3
  138. package/src/flow/CanvasNode.ts +7 -2
  139. package/src/flow/Editor.ts +755 -75
  140. package/src/flow/NodeEditor.ts +8 -4
  141. package/src/flow/Plumber.ts +65 -35
  142. package/src/flow/actions/send_msg.ts +2 -1
  143. package/src/flow/nodes/wait_for_response.ts +1 -1
  144. package/src/flow/reflow.ts +534 -0
  145. package/src/flow/types.ts +1 -0
  146. package/src/flow/utils.ts +19 -3
  147. package/src/form/Compose.ts +5 -0
  148. package/src/form/FieldRenderer.ts +1 -3
  149. package/src/layout/Dialog.ts +2 -0
  150. package/src/list/SortableList.ts +40 -19
  151. package/static/svg/index.svg +1 -1
  152. package/static/svg/work/traced/expand-06.svg +1 -0
  153. package/static/svg/work/used/expand-06.svg +3 -0
  154. package/test/temba-canvas-menu.test.ts +55 -0
  155. package/test/temba-flow-collision.test.ts +31 -0
  156. package/test/temba-flow-editor-zoom.test.ts +583 -0
  157. package/test/temba-flow-editor.test.ts +187 -1
  158. package/test/temba-flow-node-drag.test.ts +171 -0
  159. package/test/temba-flow-plumber.test.ts +38 -0
  160. package/test/temba-flow-reflow.test.ts +703 -0
  161. package/test/temba-sortable-list.test.ts +120 -0
  162. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  163. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  164. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  165. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  166. package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
  167. package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
  168. package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
  169. package/screenshots/truth/actions/call_llm/render/translation-task.png +0 -0
  170. package/screenshots/truth/actions/send_broadcast/editor/with-attachments.png +0 -0
  171. package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
  172. package/screenshots/truth/compose/attachments-with-failures.png +0 -0
  173. package/screenshots/truth/compose/attachments-with-files-and-failures.png +0 -0
  174. package/screenshots/truth/contacts/tickets-assignment.png +0 -0
  175. package/screenshots/truth/contacts/tickets.png +0 -0
  176. package/screenshots/truth/flow/editor-basic.png +0 -0
  177. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  178. package/screenshots/truth/formfield/no-errors.png +0 -0
  179. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  180. package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
  181. package/screenshots/truth/omnibox/selected.png +0 -0
  182. package/screenshots/truth/select/enabled-multi-selection.png +0 -0
  183. package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
  184. package/screenshots/truth/select/endpoint-initial-value.png +0 -0
  185. package/screenshots/truth/select/initial-value.png +0 -0
  186. package/screenshots/truth/select/multi-reorder-final.png +0 -0
  187. package/screenshots/truth/select/multi-reorder-initial.png +0 -0
  188. package/screenshots/truth/select/selected-multi-test.png +0 -0
  189. package/screenshots/truth/select/value-initial.png +0 -0
  190. package/screenshots/truth/wait-for-response/rules-editor.png +0 -0
  191. package/screenshots/truth/wait-for-response/timeout-editor-unchecked.png +0 -0
  192. package/screenshots/truth/wait-for-response/timeout-editor.png +0 -0
  193. package/screenshots/truth/webchat/connecting-state.png +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"temba-canvas-menu.test.js","sourceRoot":"","sources":["../../test/temba-canvas-menu.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;QAClC,MAAM,SAAS,GAAG,CAAC,MAAM,YAAY,CACnC,mBAAmB,EACnB,EAAE,EACF,EAAE,EACF,GAAG,EACH,GAAG,CACJ,CAAe,CAAC;QACjB,MAAM,SAAS,CAAC,cAAc,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IAEF,EAAE,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACtC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;;QAC1C,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAE9B,6BAA6B;QAC7B,MAAM,WAAW,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;;QACtC,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAEtC,gBAAgB;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE7B,0BAA0B;QAC1B,MAAM,WAAW,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;QAEnC,MAAM,gBAAgB,CAAC,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;;QACpC,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,SAAS,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAClE,MAAM,CAAC,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtC,yBAAyB;QACzB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAC5C,CAAC,IAAI,EAAE,EAAE,WAAC,OAAA,MAAA,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,0CAAE,WAAW,CAAA,EAAA,CAC9D,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YAC3B,YAAY;YACZ,WAAW;YACX,iBAAiB;SAClB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAE7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;;QAC/D,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,IAAI,eAAe,GAAG,IAAI,CAAC;QAE3B,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAC,KAAU,EAAE,EAAE;YACtD,cAAc,GAAG,IAAI,CAAC;YACtB,eAAe,GAAG,KAAK,CAAC,MAAM,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,mDAAmD;QACnD,MAAM,SAAS,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAG,CAAC,CAAgB,CAAC;QACjD,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAClC,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YACpC,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;SAC3B,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;;QAC/D,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAEtC,iDAAiD;QACjD,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC;QACxC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,mCAAmC;QAEtD,wDAAwD;QACxD,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE,EAAE,cAAc,GAAG,EAAE,EAAE;YACjD,CAAC,EAAE,GAAG;YACN,CAAC,EAAE,GAAG;SACP,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,+BAA+B;QAC/B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QACzD,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,WAAW,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,aAAa,CAAC,OAAO,CAAgB,CAAC;QAC3E,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;QAEnC,MAAM,QAAQ,GAAG,WAAW,CAAC,qBAAqB,EAAE,CAAC;QAErD,gDAAgD;QAChD,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,CAAC;QAC7D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,CAAC;QAE/D,oDAAoD;QACpD,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,IAAI,eAAe,GAAG,IAAI,CAAC;QAE3B,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAC,KAAU,EAAE,EAAE;YACtD,cAAc,GAAG,IAAI,CAAC;YACtB,eAAe,GAAG,KAAK,CAAC,MAAM,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAG,CAAC,CAAgB,CAAC;QACjD,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,IAAI,CAAC,cAAc,CAAC;QAE1B,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAClC,yCAAyC;QACzC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { CanvasMenu } from '../src/flow/CanvasMenu';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-canvas-menu', () => {\n const createCanvasMenu = async () => {\n const component = (await getComponent(\n 'temba-canvas-menu',\n {},\n '',\n 250,\n 250\n )) as CanvasMenu;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const menu = await createCanvasMenu();\n assert.instanceOf(menu, CanvasMenu);\n expect(menu.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const menu = await createCanvasMenu();\n expect(menu.open).to.be.false;\n\n // verify no menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.be.null;\n });\n\n it('shows menu when opened', async () => {\n const menu = await createCanvasMenu();\n\n // open the menu\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n expect(menu.x).to.equal(100);\n expect(menu.y).to.equal(100);\n\n // verify menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.not.be.null;\n\n await assertScreenshot('canvas-menu/open', getClip(menu));\n });\n\n it('has three menu items', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n // check menu item titles\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note'\n ]);\n });\n\n it('closes when close() is called', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n\n menu.close();\n await menu.updateComplete;\n\n expect(menu.open).to.be.false;\n });\n\n it('fires selection event when menu item is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on sticky note option (now the third item)\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const stickyItem = menuItems?.[2] as HTMLElement;\n stickyItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.deep.equal({\n action: 'sticky',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('adjusts position to stay within viewport bounds', async () => {\n const menu = await createCanvasMenu();\n\n // open menu at position that would go off screen\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const margin = 10; // matches the margin in CanvasMenu\n\n // position that would go off the right and bottom edges\n menu.show(viewportWidth - 50, viewportHeight - 50, {\n x: 100,\n y: 100\n });\n await menu.updateComplete;\n\n // wait for position adjustment\n await new Promise((resolve) => setTimeout(resolve, 100));\n await menu.updateComplete;\n\n const menuElement = menu.shadowRoot?.querySelector('.menu') as HTMLElement;\n expect(menuElement).to.not.be.null;\n\n const menuRect = menuElement.getBoundingClientRect();\n\n // verify menu stays within viewport with margin\n expect(menuRect.right).to.be.at.most(viewportWidth - margin);\n expect(menuRect.bottom).to.be.at.most(viewportHeight - margin);\n\n // verify click position is preserved (not adjusted)\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const actionItem = menuItems?.[0] as HTMLElement;\n actionItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n // click position should remain unchanged\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n });\n});\n"]}
1
+ {"version":3,"file":"temba-canvas-menu.test.js","sourceRoot":"","sources":["../../test/temba-canvas-menu.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { CanvasMenu } from '../src/flow/CanvasMenu';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-canvas-menu', () => {\n const createCanvasMenu = async () => {\n const component = (await getComponent(\n 'temba-canvas-menu',\n {},\n '',\n 250,\n 250\n )) as CanvasMenu;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const menu = await createCanvasMenu();\n assert.instanceOf(menu, CanvasMenu);\n expect(menu.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const menu = await createCanvasMenu();\n expect(menu.open).to.be.false;\n\n // verify no menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.be.null;\n });\n\n it('shows menu when opened', async () => {\n const menu = await createCanvasMenu();\n\n // open the menu\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n expect(menu.x).to.equal(100);\n expect(menu.y).to.equal(100);\n\n // verify menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.not.be.null;\n\n await assertScreenshot('canvas-menu/open', getClip(menu));\n });\n\n it('has three menu items', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n // check menu item titles\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note'\n ]);\n });\n\n it('closes when close() is called', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n\n menu.close();\n await menu.updateComplete;\n\n expect(menu.open).to.be.false;\n });\n\n it('fires selection event when menu item is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on sticky note option (now the third item)\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const stickyItem = menuItems?.[2] as HTMLElement;\n stickyItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.deep.equal({\n action: 'sticky',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('shows reflow option when showReflow is true', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(4);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note',\n 'Reflow'\n ]);\n });\n\n it('fires reflow selection event when reflow is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n let selectionDetail = null;\n menu.addEventListener('temba-selection', (event: any) => {\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const reflowItem = menuItems?.[3] as HTMLElement;\n reflowItem.click();\n await menu.updateComplete;\n\n expect(selectionDetail).to.deep.equal({\n action: 'reflow',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('hides reflow option by default', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.not.include('Reflow');\n });\n\n it('adjusts position to stay within viewport bounds', async () => {\n const menu = await createCanvasMenu();\n\n // open menu at position that would go off screen\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const margin = 10; // matches the margin in CanvasMenu\n\n // position that would go off the right and bottom edges\n menu.show(viewportWidth - 50, viewportHeight - 50, {\n x: 100,\n y: 100\n });\n await menu.updateComplete;\n\n // wait for position adjustment\n await new Promise((resolve) => setTimeout(resolve, 100));\n await menu.updateComplete;\n\n const menuElement = menu.shadowRoot?.querySelector('.menu') as HTMLElement;\n expect(menuElement).to.not.be.null;\n\n const menuRect = menuElement.getBoundingClientRect();\n\n // verify menu stays within viewport with margin\n expect(menuRect.right).to.be.at.most(viewportWidth - margin);\n expect(menuRect.bottom).to.be.at.most(viewportHeight - margin);\n\n // verify click position is preserved (not adjusted)\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const actionItem = menuItems?.[0] as HTMLElement;\n actionItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n // click position should remain unchanged\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n });\n});\n"]}
@@ -26,6 +26,31 @@ describe('Collision Detection Utilities', () => {
26
26
  expect(bounds.height).to.equal(150);
27
27
  document.body.removeChild(mockElement);
28
28
  });
29
+ it('uses layout-space dimensions unaffected by ancestor CSS transform', () => {
30
+ // Simulate zoom: ancestor has transform: scale(0.5)
31
+ const container = document.createElement('div');
32
+ container.style.transform = 'scale(0.5)';
33
+ container.style.transformOrigin = '0 0';
34
+ document.body.appendChild(container);
35
+ const mockElement = document.createElement('div');
36
+ mockElement.id = 'zoom-test-node';
37
+ mockElement.style.width = '200px';
38
+ mockElement.style.height = '150px';
39
+ container.appendChild(mockElement);
40
+ const position = { left: 100, top: 200 };
41
+ const bounds = getNodeBounds('zoom-test-node', position, mockElement);
42
+ // getNodeBounds uses offsetWidth/offsetHeight which are layout-space
43
+ expect(bounds).to.not.be.null;
44
+ expect(bounds.width).to.equal(200);
45
+ expect(bounds.height).to.equal(150);
46
+ expect(bounds.right).to.equal(300); // left + layout width
47
+ expect(bounds.bottom).to.equal(350); // top + layout height
48
+ // Verify that getBoundingClientRect WOULD return scaled values
49
+ const rect = mockElement.getBoundingClientRect();
50
+ expect(rect.width).to.equal(100); // 200 * 0.5 scale
51
+ expect(rect.height).to.equal(75); // 150 * 0.5 scale
52
+ container.remove();
53
+ });
29
54
  });
30
55
  describe('nodesOverlap', () => {
31
56
  it('detects overlapping nodes horizontally and vertically', () => {
@@ -1 +1 @@
1
- {"version":3,"file":"temba-flow-collision.test.js","sourceRoot":"","sources":["../../test/temba-flow-collision.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport {\n getNodeBounds,\n nodesOverlap,\n detectCollisions,\n calculateReflowPositions,\n NodeBounds\n} from '../src/flow/utils';\n\ndescribe('Collision Detection Utilities', () => {\n describe('getNodeBounds', () => {\n it('returns null when element not found', () => {\n const position = { left: 100, top: 200 };\n const bounds = getNodeBounds('nonexistent-uuid', position);\n expect(bounds).to.be.null;\n });\n\n it('calculates bounds correctly from element', () => {\n // Create a mock element\n const mockElement = document.createElement('div');\n mockElement.id = 'test-node';\n mockElement.style.width = '200px';\n mockElement.style.height = '150px';\n document.body.appendChild(mockElement);\n\n const position = { left: 100, top: 200 };\n const bounds = getNodeBounds('test-node', position, mockElement);\n\n expect(bounds).to.not.be.null;\n expect(bounds!.uuid).to.equal('test-node');\n expect(bounds!.left).to.equal(100);\n expect(bounds!.top).to.equal(200);\n expect(bounds!.right).to.equal(300); // left + width\n expect(bounds!.bottom).to.equal(350); // top + height\n expect(bounds!.width).to.equal(200);\n expect(bounds!.height).to.equal(150);\n\n document.body.removeChild(mockElement);\n });\n });\n\n describe('nodesOverlap', () => {\n it('detects overlapping nodes horizontally and vertically', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.true;\n });\n\n it('detects non-overlapping nodes to the right', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 300,\n top: 100,\n right: 400,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.false;\n });\n\n it('detects non-overlapping nodes below', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 100,\n top: 300,\n right: 200,\n bottom: 400,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.false;\n });\n\n it('detects edge touching as overlapping (within buffer)', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 200,\n top: 100,\n right: 300,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n // edges touching should be considered overlapping due to buffer\n expect(nodesOverlap(bounds1, bounds2)).to.be.true;\n });\n\n it('detects partial vertical overlap', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 150,\n top: 50,\n right: 250,\n bottom: 150,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.true;\n });\n });\n\n describe('detectCollisions', () => {\n it('returns empty array when no collisions', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n {\n uuid: 'node1',\n left: 300,\n top: 100,\n right: 400,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 100,\n top: 300,\n right: 200,\n bottom: 400,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(0);\n });\n\n it('detects single collision', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n {\n uuid: 'node1',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 300,\n top: 300,\n right: 400,\n bottom: 400,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(1);\n expect(collisions[0].uuid).to.equal('node1');\n });\n\n it('detects multiple collisions', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n {\n uuid: 'node1',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 50,\n top: 50,\n right: 150,\n bottom: 150,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(2);\n });\n\n it('excludes target node from collisions', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n targetBounds,\n {\n uuid: 'node1',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(1);\n expect(collisions[0].uuid).to.equal('node1');\n });\n });\n\n describe('calculateReflowPositions', () => {\n it('returns empty map when no collisions', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node1',\n left: 300,\n top: 100,\n right: 400,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['moved'], allBounds);\n expect(positions.size).to.equal(0);\n });\n\n it('moves colliding node out of the way', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node1',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['moved'], allBounds);\n\n expect(positions.size).to.equal(1);\n expect(positions.has('node1')).to.be.true;\n expect(positions.has('moved')).to.be.false;\n });\n\n it('sacred node never appears in returned positions', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'dropped',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'existing',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n expect(positions.has('dropped')).to.be.false;\n expect(positions.has('existing')).to.be.true;\n });\n\n it('prefers least-displacement direction', () => {\n // Sacred at (100,100)-(200,200), collider at (180,100)-(280,200)\n // Right requires only 60px displacement, down requires 140px\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 180,\n top: 100,\n right: 280,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move right (shorter) rather than down (longer)\n expect(newPos.left).to.be.greaterThan(200);\n expect(newPos.top).to.equal(100); // vertical position unchanged\n });\n\n it('prefers up when it is the shortest move', () => {\n // Sacred at (100,200)-(200,300), collider at (100,180)-(200,280)\n // Up: newTop=snapToGrid(200-100-30)=snapToGrid(70)=80, distance=100\n // Down: newTop=snapToGrid(300+30)=340, distance=160\n // Right: newLeft=snapToGrid(200+30)=240, distance=140\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 200,\n right: 200,\n bottom: 300,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 180,\n right: 200,\n bottom: 280,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move up (shortest displacement)\n expect(newPos.top).to.be.lessThan(200);\n expect(newPos.left).to.equal(100); // horizontal position unchanged\n });\n\n it('prefers axis-matching direction even with a cascade', () => {\n // Sacred at (100,100)-(200,200), collider at (100,150)-(200,250)\n // Overlap is 100w x 50h (wide) = vertical collision = prefer down\n // A blocker sits below at (100,280)-(200,380), so down causes a cascade\n // But axis bias still prefers down over moving right\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'blocker',\n left: 100,\n top: 280,\n right: 200,\n bottom: 380,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Axis bias prefers down (vertical) even though it cascades into blocker\n expect(newPos.top).to.be.greaterThan(200);\n expect(newPos.left).to.equal(100); // horizontal position unchanged\n });\n\n it('resolves cascading collisions', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node1',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 100,\n top: 200,\n right: 200,\n bottom: 300,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['moved'], allBounds);\n\n // At least one node should be repositioned\n expect(positions.size).to.be.greaterThan(0);\n\n // No node should overlap with the sacred node or each other after reflow\n // (verified by the algorithm's correctness guarantee)\n });\n\n it('handles multiple sacred nodes', () => {\n // Two sacred nodes with a non-sacred node overlapping one\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'sacred2',\n left: 100,\n top: 400,\n right: 200,\n bottom: 500,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(\n ['sacred1', 'sacred2'],\n allBounds\n );\n\n // Sacred nodes should never be moved\n expect(positions.has('sacred1')).to.be.false;\n expect(positions.has('sacred2')).to.be.false;\n // Collider should be moved\n expect(positions.has('collider')).to.be.true;\n });\n\n it('does not move a node into another sacred node', () => {\n // Two sacred nodes close together with a collider between them\n // Moving right would overlap sacred2, so it should choose another direction\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'sacred2',\n left: 240,\n top: 100,\n right: 340,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 150,\n top: 100,\n right: 250,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(\n ['sacred1', 'sacred2'],\n allBounds\n );\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should not overlap either sacred node after reflow\n const newBounds: NodeBounds = {\n uuid: 'collider',\n left: newPos.left,\n top: newPos.top,\n right: newPos.left + 100,\n bottom: newPos.top + 100,\n width: 100,\n height: 100\n };\n expect(nodesOverlap(newBounds, allBounds[0])).to.be.false;\n expect(nodesOverlap(newBounds, allBounds[1])).to.be.false;\n });\n\n it('snaps reflow positions to grid', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Both coordinates should be multiples of 20 (grid size)\n expect(newPos.left % 20).to.equal(0);\n expect(newPos.top % 20).to.equal(0);\n });\n\n it('clamps positions to zero (no negative coordinates)', () => {\n // Sacred node near top-left, collider above it\n // Moving up would go negative, so it should fall back\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 0,\n top: 0,\n right: 200,\n bottom: 200,\n width: 200,\n height: 200\n },\n {\n uuid: 'collider',\n left: 0,\n top: 100,\n right: 200,\n bottom: 200,\n width: 200,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n expect(newPos.left).to.be.at.least(0);\n expect(newPos.top).to.be.at.least(0);\n });\n\n it('does not move a lower node above the sacred node', () => {\n // Collider is below sacred (collider.top > sacred.top)\n // Up should be filtered, so collider goes down or to the side\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 180,\n right: 200,\n bottom: 280,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should NOT move above the sacred node's top\n expect(newPos.top).to.be.at.least(100);\n });\n\n it('does not move a right-of node left of the sacred node', () => {\n // Collider is to the right of sacred (collider.left > sacred.left)\n // Left should be filtered\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 180,\n top: 100,\n right: 280,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should NOT move left of the sacred node's left\n expect(newPos.left).to.be.at.least(100);\n });\n\n it('prefers vertical for wide overlap (vertical collision)', () => {\n // Nodes stacked: same horizontal position, slight vertical overlap\n // Overlap: 100w x 30h (wider than tall) = vertical collision = prefer up/down\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 170,\n right: 200,\n bottom: 270,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move vertically (down since collider is below)\n expect(newPos.top).to.be.greaterThan(200);\n expect(newPos.left).to.equal(100); // horizontal position unchanged\n });\n\n it('prefers horizontal for tall overlap (horizontal collision)', () => {\n // Nodes side-by-side: same vertical position, slight horizontal overlap\n // Overlap: 30w x 100h (taller than wide) = horizontal collision = prefer left/right\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 170,\n top: 100,\n right: 270,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move horizontally (right since collider is right of sacred)\n expect(newPos.left).to.be.greaterThan(200);\n expect(newPos.top).to.equal(100); // vertical position unchanged\n });\n\n it('axis bias tolerates a few cascading collisions', () => {\n // Sacred at (100,100)-(200,200), collider at (100,170)-(200,270)\n // Overlap: 100w x 30h = vertical collision = prefer down\n // Two blockers below: moving down causes 2 cascades\n // Moving right causes 0 cascades but is axis-mismatched\n // Axis bias should still prefer down with 2 cascades\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 170,\n right: 200,\n bottom: 270,\n width: 100,\n height: 100\n },\n {\n uuid: 'blocker1',\n left: 100,\n top: 260,\n right: 200,\n bottom: 360,\n width: 100,\n height: 100\n },\n {\n uuid: 'blocker2',\n left: 100,\n top: 350,\n right: 200,\n bottom: 450,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should still prefer down (axis match) despite 2 cascades\n expect(newPos.top).to.be.greaterThan(200);\n expect(newPos.left).to.equal(100);\n });\n\n it('sacred node yields to existing top node when dropped below its top', () => {\n // Existing node at top of canvas, sacred dropped overlapping from below\n const allBounds: NodeBounds[] = [\n {\n uuid: 'existing',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n },\n {\n uuid: 'dropped',\n left: 100,\n top: 50,\n right: 200,\n bottom: 150,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n // Sacred (dropped) should yield since it didn't drop above existing\n // and existing has no room to move up\n expect(positions.has('dropped')).to.be.true;\n expect(positions.has('existing')).to.be.false;\n\n const newPos = positions.get('dropped')!;\n expect(newPos.top).to.be.greaterThanOrEqual(100); // moved below existing\n });\n\n it('sacred keeps position when dropped above existing node', () => {\n // Sacred node dropped above existing node - sacred gets priority\n const allBounds: NodeBounds[] = [\n {\n uuid: 'existing',\n left: 100,\n top: 50,\n right: 200,\n bottom: 150,\n width: 100,\n height: 100\n },\n {\n uuid: 'dropped',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n // Sacred dropped above existing, so it keeps priority\n expect(positions.has('dropped')).to.be.false;\n expect(positions.has('existing')).to.be.true;\n });\n\n it('sacred keeps position when dropped at same top as existing node', () => {\n // Both at top=0 - sacred keeps priority since it's not below existing\n const allBounds: NodeBounds[] = [\n {\n uuid: 'existing',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n },\n {\n uuid: 'dropped',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n // Sacred at same top keeps priority - existing node moves\n expect(positions.has('dropped')).to.be.false;\n expect(positions.has('existing')).to.be.true;\n });\n });\n\n describe('edge cases', () => {\n it('handles empty allBounds array', () => {\n const positions = calculateReflowPositions(['moved'], []);\n expect(positions.size).to.equal(0);\n });\n\n it('handles single node (no other nodes to collide with)', () => {\n const movedBounds: NodeBounds = {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const positions = calculateReflowPositions(['moved'], [movedBounds]);\n expect(positions.size).to.equal(0);\n });\n\n it('prevents infinite loops with complex collisions', () => {\n const movedBounds: NodeBounds = {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n // Create a complex scenario with many overlapping nodes\n const allBounds: NodeBounds[] = [movedBounds];\n\n for (let i = 0; i < 20; i++) {\n allBounds.push({\n uuid: `node${i}`,\n left: 100 + i * 10,\n top: 100 + i * 10,\n right: 200 + i * 10,\n bottom: 200 + i * 10,\n width: 100,\n height: 100\n });\n }\n\n // Should complete without hanging\n const positions = calculateReflowPositions(['moved'], allBounds);\n\n // Should have resolved some collisions\n expect(positions.size).to.be.greaterThan(0);\n });\n });\n});\n"]}
1
+ {"version":3,"file":"temba-flow-collision.test.js","sourceRoot":"","sources":["../../test/temba-flow-collision.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport {\n getNodeBounds,\n nodesOverlap,\n detectCollisions,\n calculateReflowPositions,\n NodeBounds\n} from '../src/flow/utils';\n\ndescribe('Collision Detection Utilities', () => {\n describe('getNodeBounds', () => {\n it('returns null when element not found', () => {\n const position = { left: 100, top: 200 };\n const bounds = getNodeBounds('nonexistent-uuid', position);\n expect(bounds).to.be.null;\n });\n\n it('calculates bounds correctly from element', () => {\n // Create a mock element\n const mockElement = document.createElement('div');\n mockElement.id = 'test-node';\n mockElement.style.width = '200px';\n mockElement.style.height = '150px';\n document.body.appendChild(mockElement);\n\n const position = { left: 100, top: 200 };\n const bounds = getNodeBounds('test-node', position, mockElement);\n\n expect(bounds).to.not.be.null;\n expect(bounds!.uuid).to.equal('test-node');\n expect(bounds!.left).to.equal(100);\n expect(bounds!.top).to.equal(200);\n expect(bounds!.right).to.equal(300); // left + width\n expect(bounds!.bottom).to.equal(350); // top + height\n expect(bounds!.width).to.equal(200);\n expect(bounds!.height).to.equal(150);\n\n document.body.removeChild(mockElement);\n });\n\n it('uses layout-space dimensions unaffected by ancestor CSS transform', () => {\n // Simulate zoom: ancestor has transform: scale(0.5)\n const container = document.createElement('div');\n container.style.transform = 'scale(0.5)';\n container.style.transformOrigin = '0 0';\n document.body.appendChild(container);\n\n const mockElement = document.createElement('div');\n mockElement.id = 'zoom-test-node';\n mockElement.style.width = '200px';\n mockElement.style.height = '150px';\n container.appendChild(mockElement);\n\n const position = { left: 100, top: 200 };\n const bounds = getNodeBounds('zoom-test-node', position, mockElement);\n\n // getNodeBounds uses offsetWidth/offsetHeight which are layout-space\n expect(bounds).to.not.be.null;\n expect(bounds!.width).to.equal(200);\n expect(bounds!.height).to.equal(150);\n expect(bounds!.right).to.equal(300); // left + layout width\n expect(bounds!.bottom).to.equal(350); // top + layout height\n\n // Verify that getBoundingClientRect WOULD return scaled values\n const rect = mockElement.getBoundingClientRect();\n expect(rect.width).to.equal(100); // 200 * 0.5 scale\n expect(rect.height).to.equal(75); // 150 * 0.5 scale\n\n container.remove();\n });\n });\n\n describe('nodesOverlap', () => {\n it('detects overlapping nodes horizontally and vertically', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.true;\n });\n\n it('detects non-overlapping nodes to the right', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 300,\n top: 100,\n right: 400,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.false;\n });\n\n it('detects non-overlapping nodes below', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 100,\n top: 300,\n right: 200,\n bottom: 400,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.false;\n });\n\n it('detects edge touching as overlapping (within buffer)', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 200,\n top: 100,\n right: 300,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n // edges touching should be considered overlapping due to buffer\n expect(nodesOverlap(bounds1, bounds2)).to.be.true;\n });\n\n it('detects partial vertical overlap', () => {\n const bounds1: NodeBounds = {\n uuid: 'node1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const bounds2: NodeBounds = {\n uuid: 'node2',\n left: 150,\n top: 50,\n right: 250,\n bottom: 150,\n width: 100,\n height: 100\n };\n\n expect(nodesOverlap(bounds1, bounds2)).to.be.true;\n });\n });\n\n describe('detectCollisions', () => {\n it('returns empty array when no collisions', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n {\n uuid: 'node1',\n left: 300,\n top: 100,\n right: 400,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 100,\n top: 300,\n right: 200,\n bottom: 400,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(0);\n });\n\n it('detects single collision', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n {\n uuid: 'node1',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 300,\n top: 300,\n right: 400,\n bottom: 400,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(1);\n expect(collisions[0].uuid).to.equal('node1');\n });\n\n it('detects multiple collisions', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n {\n uuid: 'node1',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 50,\n top: 50,\n right: 150,\n bottom: 150,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(2);\n });\n\n it('excludes target node from collisions', () => {\n const targetBounds: NodeBounds = {\n uuid: 'target',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const allBounds: NodeBounds[] = [\n targetBounds,\n {\n uuid: 'node1',\n left: 150,\n top: 150,\n right: 250,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const collisions = detectCollisions(targetBounds, allBounds);\n expect(collisions).to.have.length(1);\n expect(collisions[0].uuid).to.equal('node1');\n });\n });\n\n describe('calculateReflowPositions', () => {\n it('returns empty map when no collisions', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node1',\n left: 300,\n top: 100,\n right: 400,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['moved'], allBounds);\n expect(positions.size).to.equal(0);\n });\n\n it('moves colliding node out of the way', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node1',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['moved'], allBounds);\n\n expect(positions.size).to.equal(1);\n expect(positions.has('node1')).to.be.true;\n expect(positions.has('moved')).to.be.false;\n });\n\n it('sacred node never appears in returned positions', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'dropped',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'existing',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n expect(positions.has('dropped')).to.be.false;\n expect(positions.has('existing')).to.be.true;\n });\n\n it('prefers least-displacement direction', () => {\n // Sacred at (100,100)-(200,200), collider at (180,100)-(280,200)\n // Right requires only 60px displacement, down requires 140px\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 180,\n top: 100,\n right: 280,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move right (shorter) rather than down (longer)\n expect(newPos.left).to.be.greaterThan(200);\n expect(newPos.top).to.equal(100); // vertical position unchanged\n });\n\n it('prefers up when it is the shortest move', () => {\n // Sacred at (100,200)-(200,300), collider at (100,180)-(200,280)\n // Up: newTop=snapToGrid(200-100-30)=snapToGrid(70)=80, distance=100\n // Down: newTop=snapToGrid(300+30)=340, distance=160\n // Right: newLeft=snapToGrid(200+30)=240, distance=140\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 200,\n right: 200,\n bottom: 300,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 180,\n right: 200,\n bottom: 280,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move up (shortest displacement)\n expect(newPos.top).to.be.lessThan(200);\n expect(newPos.left).to.equal(100); // horizontal position unchanged\n });\n\n it('prefers axis-matching direction even with a cascade', () => {\n // Sacred at (100,100)-(200,200), collider at (100,150)-(200,250)\n // Overlap is 100w x 50h (wide) = vertical collision = prefer down\n // A blocker sits below at (100,280)-(200,380), so down causes a cascade\n // But axis bias still prefers down over moving right\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'blocker',\n left: 100,\n top: 280,\n right: 200,\n bottom: 380,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Axis bias prefers down (vertical) even though it cascades into blocker\n expect(newPos.top).to.be.greaterThan(200);\n expect(newPos.left).to.equal(100); // horizontal position unchanged\n });\n\n it('resolves cascading collisions', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'node1',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n },\n {\n uuid: 'node2',\n left: 100,\n top: 200,\n right: 200,\n bottom: 300,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['moved'], allBounds);\n\n // At least one node should be repositioned\n expect(positions.size).to.be.greaterThan(0);\n\n // No node should overlap with the sacred node or each other after reflow\n // (verified by the algorithm's correctness guarantee)\n });\n\n it('handles multiple sacred nodes', () => {\n // Two sacred nodes with a non-sacred node overlapping one\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'sacred2',\n left: 100,\n top: 400,\n right: 200,\n bottom: 500,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(\n ['sacred1', 'sacred2'],\n allBounds\n );\n\n // Sacred nodes should never be moved\n expect(positions.has('sacred1')).to.be.false;\n expect(positions.has('sacred2')).to.be.false;\n // Collider should be moved\n expect(positions.has('collider')).to.be.true;\n });\n\n it('does not move a node into another sacred node', () => {\n // Two sacred nodes close together with a collider between them\n // Moving right would overlap sacred2, so it should choose another direction\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred1',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'sacred2',\n left: 240,\n top: 100,\n right: 340,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 150,\n top: 100,\n right: 250,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(\n ['sacred1', 'sacred2'],\n allBounds\n );\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should not overlap either sacred node after reflow\n const newBounds: NodeBounds = {\n uuid: 'collider',\n left: newPos.left,\n top: newPos.top,\n right: newPos.left + 100,\n bottom: newPos.top + 100,\n width: 100,\n height: 100\n };\n expect(nodesOverlap(newBounds, allBounds[0])).to.be.false;\n expect(nodesOverlap(newBounds, allBounds[1])).to.be.false;\n });\n\n it('snaps reflow positions to grid', () => {\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 150,\n right: 200,\n bottom: 250,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Both coordinates should be multiples of 20 (grid size)\n expect(newPos.left % 20).to.equal(0);\n expect(newPos.top % 20).to.equal(0);\n });\n\n it('clamps positions to zero (no negative coordinates)', () => {\n // Sacred node near top-left, collider above it\n // Moving up would go negative, so it should fall back\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 0,\n top: 0,\n right: 200,\n bottom: 200,\n width: 200,\n height: 200\n },\n {\n uuid: 'collider',\n left: 0,\n top: 100,\n right: 200,\n bottom: 200,\n width: 200,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n expect(newPos.left).to.be.at.least(0);\n expect(newPos.top).to.be.at.least(0);\n });\n\n it('does not move a lower node above the sacred node', () => {\n // Collider is below sacred (collider.top > sacred.top)\n // Up should be filtered, so collider goes down or to the side\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 180,\n right: 200,\n bottom: 280,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should NOT move above the sacred node's top\n expect(newPos.top).to.be.at.least(100);\n });\n\n it('does not move a right-of node left of the sacred node', () => {\n // Collider is to the right of sacred (collider.left > sacred.left)\n // Left should be filtered\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 180,\n top: 100,\n right: 280,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should NOT move left of the sacred node's left\n expect(newPos.left).to.be.at.least(100);\n });\n\n it('prefers vertical for wide overlap (vertical collision)', () => {\n // Nodes stacked: same horizontal position, slight vertical overlap\n // Overlap: 100w x 30h (wider than tall) = vertical collision = prefer up/down\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 170,\n right: 200,\n bottom: 270,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move vertically (down since collider is below)\n expect(newPos.top).to.be.greaterThan(200);\n expect(newPos.left).to.equal(100); // horizontal position unchanged\n });\n\n it('prefers horizontal for tall overlap (horizontal collision)', () => {\n // Nodes side-by-side: same vertical position, slight horizontal overlap\n // Overlap: 30w x 100h (taller than wide) = horizontal collision = prefer left/right\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 170,\n top: 100,\n right: 270,\n bottom: 200,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should move horizontally (right since collider is right of sacred)\n expect(newPos.left).to.be.greaterThan(200);\n expect(newPos.top).to.equal(100); // vertical position unchanged\n });\n\n it('axis bias tolerates a few cascading collisions', () => {\n // Sacred at (100,100)-(200,200), collider at (100,170)-(200,270)\n // Overlap: 100w x 30h = vertical collision = prefer down\n // Two blockers below: moving down causes 2 cascades\n // Moving right causes 0 cascades but is axis-mismatched\n // Axis bias should still prefer down with 2 cascades\n const allBounds: NodeBounds[] = [\n {\n uuid: 'sacred',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n },\n {\n uuid: 'collider',\n left: 100,\n top: 170,\n right: 200,\n bottom: 270,\n width: 100,\n height: 100\n },\n {\n uuid: 'blocker1',\n left: 100,\n top: 260,\n right: 200,\n bottom: 360,\n width: 100,\n height: 100\n },\n {\n uuid: 'blocker2',\n left: 100,\n top: 350,\n right: 200,\n bottom: 450,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['sacred'], allBounds);\n\n expect(positions.has('collider')).to.be.true;\n const newPos = positions.get('collider')!;\n // Should still prefer down (axis match) despite 2 cascades\n expect(newPos.top).to.be.greaterThan(200);\n expect(newPos.left).to.equal(100);\n });\n\n it('sacred node yields to existing top node when dropped below its top', () => {\n // Existing node at top of canvas, sacred dropped overlapping from below\n const allBounds: NodeBounds[] = [\n {\n uuid: 'existing',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n },\n {\n uuid: 'dropped',\n left: 100,\n top: 50,\n right: 200,\n bottom: 150,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n // Sacred (dropped) should yield since it didn't drop above existing\n // and existing has no room to move up\n expect(positions.has('dropped')).to.be.true;\n expect(positions.has('existing')).to.be.false;\n\n const newPos = positions.get('dropped')!;\n expect(newPos.top).to.be.greaterThanOrEqual(100); // moved below existing\n });\n\n it('sacred keeps position when dropped above existing node', () => {\n // Sacred node dropped above existing node - sacred gets priority\n const allBounds: NodeBounds[] = [\n {\n uuid: 'existing',\n left: 100,\n top: 50,\n right: 200,\n bottom: 150,\n width: 100,\n height: 100\n },\n {\n uuid: 'dropped',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n // Sacred dropped above existing, so it keeps priority\n expect(positions.has('dropped')).to.be.false;\n expect(positions.has('existing')).to.be.true;\n });\n\n it('sacred keeps position when dropped at same top as existing node', () => {\n // Both at top=0 - sacred keeps priority since it's not below existing\n const allBounds: NodeBounds[] = [\n {\n uuid: 'existing',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n },\n {\n uuid: 'dropped',\n left: 100,\n top: 0,\n right: 200,\n bottom: 100,\n width: 100,\n height: 100\n }\n ];\n\n const positions = calculateReflowPositions(['dropped'], allBounds);\n\n // Sacred at same top keeps priority - existing node moves\n expect(positions.has('dropped')).to.be.false;\n expect(positions.has('existing')).to.be.true;\n });\n });\n\n describe('edge cases', () => {\n it('handles empty allBounds array', () => {\n const positions = calculateReflowPositions(['moved'], []);\n expect(positions.size).to.equal(0);\n });\n\n it('handles single node (no other nodes to collide with)', () => {\n const movedBounds: NodeBounds = {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n const positions = calculateReflowPositions(['moved'], [movedBounds]);\n expect(positions.size).to.equal(0);\n });\n\n it('prevents infinite loops with complex collisions', () => {\n const movedBounds: NodeBounds = {\n uuid: 'moved',\n left: 100,\n top: 100,\n right: 200,\n bottom: 200,\n width: 100,\n height: 100\n };\n\n // Create a complex scenario with many overlapping nodes\n const allBounds: NodeBounds[] = [movedBounds];\n\n for (let i = 0; i < 20; i++) {\n allBounds.push({\n uuid: `node${i}`,\n left: 100 + i * 10,\n top: 100 + i * 10,\n right: 200 + i * 10,\n bottom: 200 + i * 10,\n width: 100,\n height: 100\n });\n }\n\n // Should complete without hanging\n const positions = calculateReflowPositions(['moved'], allBounds);\n\n // Should have resolved some collisions\n expect(positions.size).to.be.greaterThan(0);\n });\n });\n});\n"]}