@nyaruka/temba-components 0.129.2 → 0.129.4

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 (773) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.github/workflows/build.yml +141 -8
  3. package/CHANGELOG.md +40 -0
  4. package/README.md +6 -0
  5. package/check-coverage.js +133 -0
  6. package/demo/data/flows/sample-flow.json +158 -128
  7. package/demo/field-config-demo.html +135 -0
  8. package/dist/temba-components.js +1750 -751
  9. package/dist/temba-components.js.map +1 -1
  10. package/docs/ActionEditor-Migration.md +118 -0
  11. package/generate-coverage-badge.sh +69 -0
  12. package/out-tsc/src/{vectoricon/index.js → Icons.js} +1 -1
  13. package/out-tsc/src/Icons.js.map +1 -0
  14. package/out-tsc/src/display/Alert.js.map +1 -0
  15. package/out-tsc/src/display/Anchor.js.map +1 -0
  16. package/out-tsc/src/display/Button.js.map +1 -0
  17. package/out-tsc/src/{charcount → display}/CharCount.js +159 -2
  18. package/out-tsc/src/display/CharCount.js.map +1 -0
  19. package/out-tsc/src/display/Chat.js.map +1 -0
  20. package/out-tsc/src/display/ContactName.js.map +1 -0
  21. package/out-tsc/src/display/ContactUrn.js.map +1 -0
  22. package/out-tsc/src/display/Dropdown.js.map +1 -0
  23. package/out-tsc/src/{vectoricon/VectorIcon.js → display/Icon.js} +2 -2
  24. package/out-tsc/src/display/Icon.js.map +1 -0
  25. package/out-tsc/src/display/Label.js.map +1 -0
  26. package/out-tsc/src/{leafletmap → display}/LeafletMap.js +16 -1
  27. package/out-tsc/src/display/LeafletMap.js.map +1 -0
  28. package/out-tsc/src/display/Lightbox.js.map +1 -0
  29. package/out-tsc/src/{loading → display}/Loading.js.map +1 -1
  30. package/out-tsc/src/{options → display}/Options.js.map +1 -1
  31. package/out-tsc/src/display/ProgressBar.js.map +1 -0
  32. package/out-tsc/src/display/TembaDate.js.map +1 -0
  33. package/out-tsc/src/display/TembaUser.js.map +1 -0
  34. package/out-tsc/src/display/Thumbnail.js.map +1 -0
  35. package/out-tsc/src/{tip → display}/Tip.js +1 -2
  36. package/out-tsc/src/display/Tip.js.map +1 -0
  37. package/out-tsc/src/display/Toast.js.map +1 -0
  38. package/out-tsc/src/display/sms/gsmsplitter.js.map +1 -0
  39. package/out-tsc/src/display/sms/gsmvalidator.js.map +1 -0
  40. package/out-tsc/src/display/sms/index.js.map +1 -0
  41. package/out-tsc/src/display/sms/unicodesplitter.js.map +1 -0
  42. package/out-tsc/src/events.js +2 -0
  43. package/out-tsc/src/events.js.map +1 -0
  44. package/out-tsc/src/excellent/ExcellentParser.js.map +1 -0
  45. package/out-tsc/src/excellent/helpers.js.map +1 -0
  46. package/out-tsc/src/flow/CanvasNode.js +861 -0
  47. package/out-tsc/src/flow/CanvasNode.js.map +1 -0
  48. package/out-tsc/src/flow/Editor.js +640 -143
  49. package/out-tsc/src/flow/Editor.js.map +1 -1
  50. package/out-tsc/src/flow/NodeEditor.js +1200 -0
  51. package/out-tsc/src/flow/NodeEditor.js.map +1 -0
  52. package/out-tsc/src/flow/Plumber.js +148 -74
  53. package/out-tsc/src/flow/Plumber.js.map +1 -1
  54. package/out-tsc/src/flow/StickyNote.js +153 -9
  55. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  56. package/out-tsc/src/flow/actions/add_contact_groups.js +40 -0
  57. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -0
  58. package/out-tsc/src/flow/actions/add_contact_urn.js +16 -0
  59. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -0
  60. package/out-tsc/src/flow/actions/add_input_labels.js +11 -0
  61. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -0
  62. package/out-tsc/src/flow/actions/call_classifier.js +11 -0
  63. package/out-tsc/src/flow/actions/call_classifier.js.map +1 -0
  64. package/out-tsc/src/flow/actions/call_llm.js +11 -0
  65. package/out-tsc/src/flow/actions/call_llm.js.map +1 -0
  66. package/out-tsc/src/flow/actions/call_resthook.js +11 -0
  67. package/out-tsc/src/flow/actions/call_resthook.js.map +1 -0
  68. package/out-tsc/src/flow/actions/call_webhook.js +122 -0
  69. package/out-tsc/src/flow/actions/call_webhook.js.map +1 -0
  70. package/out-tsc/src/flow/actions/enter_flow.js +14 -0
  71. package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
  72. package/out-tsc/src/flow/actions/open_ticket.js +11 -0
  73. package/out-tsc/src/flow/actions/open_ticket.js.map +1 -0
  74. package/out-tsc/src/flow/actions/play_audio.js +11 -0
  75. package/out-tsc/src/flow/actions/play_audio.js.map +1 -0
  76. package/out-tsc/src/flow/actions/remove_contact_groups.js +62 -0
  77. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -0
  78. package/out-tsc/src/flow/actions/request_optin.js +11 -0
  79. package/out-tsc/src/flow/actions/request_optin.js.map +1 -0
  80. package/out-tsc/src/flow/actions/say_msg.js +11 -0
  81. package/out-tsc/src/flow/actions/say_msg.js.map +1 -0
  82. package/out-tsc/src/flow/actions/send_broadcast.js +33 -0
  83. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -0
  84. package/out-tsc/src/flow/actions/send_email.js +56 -0
  85. package/out-tsc/src/flow/actions/send_email.js.map +1 -0
  86. package/out-tsc/src/flow/actions/send_msg.js +55 -0
  87. package/out-tsc/src/flow/actions/send_msg.js.map +1 -0
  88. package/out-tsc/src/flow/actions/set_contact_channel.js +12 -0
  89. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -0
  90. package/out-tsc/src/flow/actions/set_contact_field.js +12 -0
  91. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -0
  92. package/out-tsc/src/flow/actions/set_contact_language.js +10 -0
  93. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -0
  94. package/out-tsc/src/flow/actions/set_contact_name.js +10 -0
  95. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -0
  96. package/out-tsc/src/flow/actions/set_contact_status.js +10 -0
  97. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -0
  98. package/out-tsc/src/flow/actions/set_run_result.js +10 -0
  99. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -0
  100. package/out-tsc/src/flow/actions/split_by_expression_example.js +77 -0
  101. package/out-tsc/src/flow/actions/split_by_expression_example.js.map +1 -0
  102. package/out-tsc/src/flow/actions/start_session.js +11 -0
  103. package/out-tsc/src/flow/actions/start_session.js.map +1 -0
  104. package/out-tsc/src/flow/actions/transfer_airtime.js +11 -0
  105. package/out-tsc/src/flow/actions/transfer_airtime.js.map +1 -0
  106. package/out-tsc/src/flow/config.js +88 -123
  107. package/out-tsc/src/flow/config.js.map +1 -1
  108. package/out-tsc/src/flow/nodes/execute_actions.js +4 -0
  109. package/out-tsc/src/flow/nodes/execute_actions.js.map +1 -0
  110. package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -0
  111. package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -0
  112. package/out-tsc/src/flow/nodes/split_by_contact_field.js +7 -0
  113. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -0
  114. package/out-tsc/src/flow/nodes/split_by_expression.js +7 -0
  115. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -0
  116. package/out-tsc/src/flow/nodes/split_by_groups.js +7 -0
  117. package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -0
  118. package/out-tsc/src/flow/nodes/split_by_random.js +10 -0
  119. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -0
  120. package/out-tsc/src/flow/nodes/split_by_run_result.js +7 -0
  121. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -0
  122. package/out-tsc/src/flow/nodes/split_by_scheme.js +7 -0
  123. package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -0
  124. package/out-tsc/src/flow/nodes/split_by_subflow.js +9 -0
  125. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -0
  126. package/out-tsc/src/flow/nodes/split_by_webhook.js +18 -0
  127. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -0
  128. package/out-tsc/src/flow/nodes/wait_for_audio.js +7 -0
  129. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
  130. package/out-tsc/src/flow/nodes/wait_for_digits.js +7 -0
  131. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -0
  132. package/out-tsc/src/flow/nodes/wait_for_image.js +7 -0
  133. package/out-tsc/src/flow/nodes/wait_for_image.js.map +1 -0
  134. package/out-tsc/src/flow/nodes/wait_for_location.js +7 -0
  135. package/out-tsc/src/flow/nodes/wait_for_location.js.map +1 -0
  136. package/out-tsc/src/flow/nodes/wait_for_menu.js +7 -0
  137. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -0
  138. package/out-tsc/src/flow/nodes/wait_for_response.js +7 -0
  139. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -0
  140. package/out-tsc/src/flow/nodes/wait_for_video.js +7 -0
  141. package/out-tsc/src/flow/nodes/wait_for_video.js.map +1 -0
  142. package/out-tsc/src/flow/types.js +79 -0
  143. package/out-tsc/src/flow/types.js.map +1 -0
  144. package/out-tsc/src/flow/utils.js +65 -0
  145. package/out-tsc/src/flow/utils.js.map +1 -0
  146. package/out-tsc/src/form/ArrayEditor.js +199 -0
  147. package/out-tsc/src/form/ArrayEditor.js.map +1 -0
  148. package/out-tsc/src/form/BaseListEditor.js +128 -0
  149. package/out-tsc/src/form/BaseListEditor.js.map +1 -0
  150. package/out-tsc/src/{checkbox → form}/Checkbox.js +19 -4
  151. package/out-tsc/src/form/Checkbox.js.map +1 -0
  152. package/out-tsc/src/{colorpicker → form}/ColorPicker.js +1 -1
  153. package/out-tsc/src/form/ColorPicker.js.map +1 -0
  154. package/out-tsc/src/{completion → form}/Completion.js +8 -2
  155. package/out-tsc/src/form/Completion.js.map +1 -0
  156. package/out-tsc/src/{compose → form}/Compose.js +1 -1
  157. package/out-tsc/src/form/Compose.js.map +1 -0
  158. package/out-tsc/src/{contactsearch → form}/ContactSearch.js +2 -2
  159. package/out-tsc/src/form/ContactSearch.js.map +1 -0
  160. package/out-tsc/src/form/CroppieCSS.js.map +1 -0
  161. package/out-tsc/src/{datepicker → form}/DatePicker.js +1 -1
  162. package/out-tsc/src/form/DatePicker.js.map +1 -0
  163. package/out-tsc/src/{FormElement.js → form/FormElement.js} +1 -1
  164. package/out-tsc/src/form/FormElement.js.map +1 -0
  165. package/out-tsc/src/form/FormField.js +243 -0
  166. package/out-tsc/src/form/FormField.js.map +1 -0
  167. package/out-tsc/src/{imagepicker → form}/ImagePicker.js +2 -2
  168. package/out-tsc/src/form/ImagePicker.js.map +1 -0
  169. package/out-tsc/src/form/KeyValueEditor.js +223 -0
  170. package/out-tsc/src/form/KeyValueEditor.js.map +1 -0
  171. package/out-tsc/src/{mediapicker → form}/MediaPicker.js +1 -1
  172. package/out-tsc/src/form/MediaPicker.js.map +1 -0
  173. package/out-tsc/src/form/RangePicker.js.map +1 -0
  174. package/out-tsc/src/{slider → form}/TembaSlider.js +1 -1
  175. package/out-tsc/src/form/TembaSlider.js.map +1 -0
  176. package/out-tsc/src/{templates → form}/TemplateEditor.js +1 -1
  177. package/out-tsc/src/form/TemplateEditor.js.map +1 -0
  178. package/out-tsc/src/{textinput → form}/TextInput.js +3 -3
  179. package/out-tsc/src/form/TextInput.js.map +1 -0
  180. package/out-tsc/src/{omnibox → form/select}/Omnibox.js +2 -2
  181. package/out-tsc/src/form/select/Omnibox.js.map +1 -0
  182. package/out-tsc/src/{select → form/select}/PopupSelect.js +1 -1
  183. package/out-tsc/src/form/select/PopupSelect.js.map +1 -0
  184. package/out-tsc/src/{select → form/select}/Select.js +157 -113
  185. package/out-tsc/src/form/select/Select.js.map +1 -0
  186. package/out-tsc/src/{select → form/select}/UserSelect.js +1 -1
  187. package/out-tsc/src/form/select/UserSelect.js.map +1 -0
  188. package/out-tsc/src/{select → form/select}/WorkspaceSelect.js +1 -1
  189. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -0
  190. package/out-tsc/src/interfaces.js +7 -0
  191. package/out-tsc/src/interfaces.js.map +1 -1
  192. package/out-tsc/src/layout/Dialog.js.map +1 -0
  193. package/out-tsc/src/layout/Mask.js.map +1 -0
  194. package/out-tsc/src/{dialog → layout}/Modax.js.map +1 -1
  195. package/out-tsc/src/layout/Resizer.js.map +1 -0
  196. package/out-tsc/src/layout/Tab.js.map +1 -0
  197. package/out-tsc/src/layout/TabPane.js.map +1 -0
  198. package/out-tsc/src/list/NotificationList.js +1 -1
  199. package/out-tsc/src/list/NotificationList.js.map +1 -1
  200. package/out-tsc/src/list/RunList.js +1 -1
  201. package/out-tsc/src/list/RunList.js.map +1 -1
  202. package/out-tsc/src/list/ShortcutList.js.map +1 -1
  203. package/out-tsc/src/list/TembaMenu.js +1 -1
  204. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  205. package/out-tsc/src/list/TicketList.js +1 -1
  206. package/out-tsc/src/list/TicketList.js.map +1 -1
  207. package/out-tsc/src/{aliaseditor → live}/AliasEditor.js +1 -1
  208. package/out-tsc/src/live/AliasEditor.js.map +1 -0
  209. package/out-tsc/src/{contacts → live}/ContactBadges.js +1 -1
  210. package/out-tsc/src/live/ContactBadges.js.map +1 -0
  211. package/out-tsc/src/{contacts → live}/ContactChat.js +80 -78
  212. package/out-tsc/src/live/ContactChat.js.map +1 -0
  213. package/out-tsc/src/{contacts → live}/ContactDetails.js +1 -1
  214. package/out-tsc/src/live/ContactDetails.js.map +1 -0
  215. package/out-tsc/src/{contacts → live}/ContactFieldEditor.js +2 -2
  216. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -0
  217. package/out-tsc/src/live/ContactFields.js.map +1 -0
  218. package/out-tsc/src/live/ContactNameFetch.js.map +1 -0
  219. package/out-tsc/src/{contacts → live}/ContactNotepad.js +1 -1
  220. package/out-tsc/src/{contacts → live}/ContactNotepad.js.map +1 -1
  221. package/out-tsc/src/{contacts → live}/ContactPending.js +1 -1
  222. package/out-tsc/src/live/ContactPending.js.map +1 -0
  223. package/out-tsc/src/live/ContactStoreElement.js.map +1 -0
  224. package/out-tsc/src/live/FieldManager.js.map +1 -0
  225. package/out-tsc/src/live/StartProgress.js.map +1 -0
  226. package/out-tsc/src/live/TembaChart.js.map +1 -0
  227. package/out-tsc/src/store/AppState.js +54 -24
  228. package/out-tsc/src/store/AppState.js.map +1 -1
  229. package/out-tsc/src/store/Store.js +1 -1
  230. package/out-tsc/src/store/Store.js.map +1 -1
  231. package/out-tsc/src/{utils/index.js → utils.js} +22 -1
  232. package/out-tsc/src/utils.js.map +1 -0
  233. package/out-tsc/src/webchat/WebChat.js +1 -1
  234. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  235. package/out-tsc/temba-components.js +2 -2
  236. package/out-tsc/temba-components.js.map +1 -1
  237. package/out-tsc/temba-modules.js +63 -56
  238. package/out-tsc/temba-modules.js.map +1 -1
  239. package/out-tsc/temba-webchat.js +2 -2
  240. package/out-tsc/temba-webchat.js.map +1 -1
  241. package/out-tsc/test/ActionHelper.js +116 -0
  242. package/out-tsc/test/ActionHelper.js.map +1 -0
  243. package/out-tsc/test/actions/add_contact_groups.test.js +66 -0
  244. package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -0
  245. package/out-tsc/test/actions/remove_contact_groups.test.js +226 -0
  246. package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -0
  247. package/out-tsc/test/actions/send_email.test.js +160 -0
  248. package/out-tsc/test/actions/send_email.test.js.map +1 -0
  249. package/out-tsc/test/actions/send_msg.test.js +95 -0
  250. package/out-tsc/test/actions/send_msg.test.js.map +1 -0
  251. package/out-tsc/test/temba-action-editing-integration.test.js +183 -0
  252. package/out-tsc/test/temba-action-editing-integration.test.js.map +1 -0
  253. package/out-tsc/test/temba-alert.test.js +1 -1
  254. package/out-tsc/test/temba-alert.test.js.map +1 -1
  255. package/out-tsc/test/temba-appstate-language.test.js +90 -0
  256. package/out-tsc/test/temba-appstate-language.test.js.map +1 -1
  257. package/out-tsc/test/temba-charcount.test.js.map +1 -1
  258. package/out-tsc/test/temba-chart.test.js +1 -1
  259. package/out-tsc/test/temba-chart.test.js.map +1 -1
  260. package/out-tsc/test/temba-checkbox.test.js +1 -1
  261. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  262. package/out-tsc/test/temba-color-picker.test.js +1 -1
  263. package/out-tsc/test/temba-color-picker.test.js.map +1 -1
  264. package/out-tsc/test/temba-completion.test.js +1 -1
  265. package/out-tsc/test/temba-completion.test.js.map +1 -1
  266. package/out-tsc/test/temba-compose.test.js +1 -1
  267. package/out-tsc/test/temba-compose.test.js.map +1 -1
  268. package/out-tsc/test/temba-contact-badges.test.js +1 -1
  269. package/out-tsc/test/temba-contact-badges.test.js.map +1 -1
  270. package/out-tsc/test/temba-contact-chat.test.js +3 -1
  271. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  272. package/out-tsc/test/temba-contact-details.test.js +1 -1
  273. package/out-tsc/test/temba-contact-details.test.js.map +1 -1
  274. package/out-tsc/test/temba-contact-fields.test.js +1 -1
  275. package/out-tsc/test/temba-contact-fields.test.js.map +1 -1
  276. package/out-tsc/test/temba-contact-search.test.js +1 -1
  277. package/out-tsc/test/temba-contact-search.test.js.map +1 -1
  278. package/out-tsc/test/temba-date.test.js +5 -1
  279. package/out-tsc/test/temba-date.test.js.map +1 -1
  280. package/out-tsc/test/temba-datepicker.test.js +1 -1
  281. package/out-tsc/test/temba-datepicker.test.js.map +1 -1
  282. package/out-tsc/test/temba-dialog.test.js +1 -1
  283. package/out-tsc/test/temba-dialog.test.js.map +1 -1
  284. package/out-tsc/test/temba-dropdown.test.js +1 -1
  285. package/out-tsc/test/temba-dropdown.test.js.map +1 -1
  286. package/out-tsc/test/temba-excellent-helpers.test.js +316 -0
  287. package/out-tsc/test/temba-excellent-helpers.test.js.map +1 -0
  288. package/out-tsc/test/temba-field-config.test.js +133 -0
  289. package/out-tsc/test/temba-field-config.test.js.map +1 -0
  290. package/out-tsc/test/temba-field-manager.test.js.map +1 -1
  291. package/out-tsc/test/temba-flow-editor-node.test.js +426 -13
  292. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  293. package/out-tsc/test/temba-flow-editor.test.js +185 -0
  294. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  295. package/out-tsc/test/temba-flow-plumber-connections.test.js +113 -0
  296. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -0
  297. package/out-tsc/test/temba-flow-plumber.test.js +73 -93
  298. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  299. package/out-tsc/test/temba-flow-self-routing.test.js +172 -0
  300. package/out-tsc/test/temba-flow-self-routing.test.js.map +1 -0
  301. package/out-tsc/test/temba-formfield.test.js.map +1 -1
  302. package/out-tsc/test/temba-icon.test.js +1 -1
  303. package/out-tsc/test/temba-icon.test.js.map +1 -1
  304. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  305. package/out-tsc/test/temba-label.test.js +1 -1
  306. package/out-tsc/test/temba-label.test.js.map +1 -1
  307. package/out-tsc/test/temba-lightbox.test.js +1 -1
  308. package/out-tsc/test/temba-lightbox.test.js.map +1 -1
  309. package/out-tsc/test/temba-markdown.test.js +127 -0
  310. package/out-tsc/test/temba-markdown.test.js.map +1 -0
  311. package/out-tsc/test/temba-menu.test.js +1 -1
  312. package/out-tsc/test/temba-menu.test.js.map +1 -1
  313. package/out-tsc/test/temba-modax.test.js +1 -1
  314. package/out-tsc/test/temba-modax.test.js.map +1 -1
  315. package/out-tsc/test/temba-modules.test.js +47 -0
  316. package/out-tsc/test/temba-modules.test.js.map +1 -0
  317. package/out-tsc/test/temba-node-editor.test.js +283 -0
  318. package/out-tsc/test/temba-node-editor.test.js.map +1 -0
  319. package/out-tsc/test/temba-omnibox.test.js +1 -1
  320. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  321. package/out-tsc/test/temba-options.test.js.map +1 -1
  322. package/out-tsc/test/temba-range-picker.test.js +9 -2
  323. package/out-tsc/test/temba-range-picker.test.js.map +1 -1
  324. package/out-tsc/test/temba-rapid-element.test.js +273 -0
  325. package/out-tsc/test/temba-rapid-element.test.js.map +1 -0
  326. package/out-tsc/test/temba-resize-element.test.js +85 -0
  327. package/out-tsc/test/temba-resize-element.test.js.map +1 -0
  328. package/out-tsc/test/temba-select.test.js +87 -2
  329. package/out-tsc/test/temba-select.test.js.map +1 -1
  330. package/out-tsc/test/temba-slider.test.js.map +1 -1
  331. package/out-tsc/test/temba-sticky-note.test.js +194 -0
  332. package/out-tsc/test/temba-sticky-note.test.js.map +1 -0
  333. package/out-tsc/test/temba-template-editor.test.js.map +1 -1
  334. package/out-tsc/test/temba-textinput.test.js +1 -1
  335. package/out-tsc/test/temba-textinput.test.js.map +1 -1
  336. package/out-tsc/test/temba-tip.test.js +1 -1
  337. package/out-tsc/test/temba-tip.test.js.map +1 -1
  338. package/out-tsc/test/temba-toast.test.js +1 -1
  339. package/out-tsc/test/temba-toast.test.js.map +1 -1
  340. package/out-tsc/test/temba-utils-index.test.js +1 -1
  341. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  342. package/out-tsc/test/temba-utils-uuid.test.js +38 -0
  343. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -0
  344. package/out-tsc/test/temba-webchat.test.js +28 -12
  345. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  346. package/out-tsc/test/utils.test.js +2 -6
  347. package/out-tsc/test/utils.test.js.map +1 -1
  348. package/package.json +18 -9
  349. package/rollup.components.mjs +1 -1
  350. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  351. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  352. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  353. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  354. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  355. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  356. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  357. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  358. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  359. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  360. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  361. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  362. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  363. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  364. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  365. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  366. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  367. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  368. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  369. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  370. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  371. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  372. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  373. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  374. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  375. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  376. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  377. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  378. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  379. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  380. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  381. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  382. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  383. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  384. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  385. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  386. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  387. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  388. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  389. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  390. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  391. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  392. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  393. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  394. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  395. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  396. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  397. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  398. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  399. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  400. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  401. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  402. package/screenshots/truth/datepicker/range-picker-all.png +0 -0
  403. package/screenshots/truth/datepicker/range-picker-button-states.png +0 -0
  404. package/screenshots/truth/datepicker/range-picker-default.png +0 -0
  405. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  406. package/screenshots/truth/datepicker/range-picker-initial-values.png +0 -0
  407. package/screenshots/truth/datepicker/range-picker-week.png +0 -0
  408. package/screenshots/truth/datepicker/range-picker-year.png +0 -0
  409. package/screenshots/truth/editor/router.png +0 -0
  410. package/screenshots/truth/editor/send_msg.png +0 -0
  411. package/screenshots/truth/editor/set_contact_language.png +0 -0
  412. package/screenshots/truth/editor/set_contact_name.png +0 -0
  413. package/screenshots/truth/editor/set_run_result.png +0 -0
  414. package/screenshots/truth/editor/wait.png +0 -0
  415. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  416. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  417. package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
  418. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  419. package/screenshots/truth/sticky-note/blue-color.png +0 -0
  420. package/screenshots/truth/sticky-note/blue.png +0 -0
  421. package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
  422. package/screenshots/truth/sticky-note/default.png +0 -0
  423. package/screenshots/truth/sticky-note/gray-color.png +0 -0
  424. package/screenshots/truth/sticky-note/gray.png +0 -0
  425. package/screenshots/truth/sticky-note/green-color.png +0 -0
  426. package/screenshots/truth/sticky-note/green.png +0 -0
  427. package/screenshots/truth/sticky-note/pink-color.png +0 -0
  428. package/screenshots/truth/sticky-note/pink.png +0 -0
  429. package/screenshots/truth/sticky-note/yellow-color.png +0 -0
  430. package/screenshots/truth/sticky-note/yellow.png +0 -0
  431. package/src/{charcount → display}/CharCount.ts +164 -2
  432. package/src/{vectoricon/VectorIcon.ts → display/Icon.ts} +1 -1
  433. package/src/{leafletmap → display}/LeafletMap.ts +19 -1
  434. package/src/{thumbnail → display}/Thumbnail.ts +1 -1
  435. package/src/{tip → display}/Tip.ts +1 -2
  436. package/src/events.ts +108 -0
  437. package/src/flow/CanvasNode.ts +1009 -0
  438. package/src/flow/Editor.ts +795 -169
  439. package/src/flow/NodeEditor.ts +1443 -0
  440. package/src/flow/Plumber.ts +177 -79
  441. package/src/flow/StickyNote.ts +165 -9
  442. package/src/flow/actions/add_contact_groups.ts +42 -0
  443. package/src/flow/actions/add_contact_urn.ts +17 -0
  444. package/src/flow/actions/add_input_labels.ts +12 -0
  445. package/src/flow/actions/call_classifier.ts +12 -0
  446. package/src/flow/actions/call_llm.ts +12 -0
  447. package/src/flow/actions/call_resthook.ts +12 -0
  448. package/src/flow/actions/call_webhook.ts +133 -0
  449. package/src/flow/actions/enter_flow.ts +15 -0
  450. package/src/flow/actions/open_ticket.ts +12 -0
  451. package/src/flow/actions/play_audio.ts +12 -0
  452. package/src/flow/actions/remove_contact_groups.ts +66 -0
  453. package/src/flow/actions/request_optin.ts +12 -0
  454. package/src/flow/actions/say_msg.ts +12 -0
  455. package/src/flow/actions/send_broadcast.ts +35 -0
  456. package/src/flow/actions/send_email.ts +60 -0
  457. package/src/flow/actions/send_msg.ts +58 -0
  458. package/src/flow/actions/set_contact_channel.ts +13 -0
  459. package/src/flow/actions/set_contact_field.ts +13 -0
  460. package/src/flow/actions/set_contact_language.ts +11 -0
  461. package/src/flow/actions/set_contact_name.ts +11 -0
  462. package/src/flow/actions/set_contact_status.ts +11 -0
  463. package/src/flow/actions/set_run_result.ts +11 -0
  464. package/src/flow/actions/split_by_expression_example.ts +88 -0
  465. package/src/flow/actions/start_session.ts +12 -0
  466. package/src/flow/actions/transfer_airtime.ts +12 -0
  467. package/src/flow/config.ts +93 -136
  468. package/src/flow/nodes/execute_actions.ts +5 -0
  469. package/src/flow/nodes/split_by_airtime.ts +9 -0
  470. package/src/flow/nodes/split_by_contact_field.ts +7 -0
  471. package/src/flow/nodes/split_by_expression.ts +7 -0
  472. package/src/flow/nodes/split_by_groups.ts +7 -0
  473. package/src/flow/nodes/split_by_random.ts +10 -0
  474. package/src/flow/nodes/split_by_run_result.ts +7 -0
  475. package/src/flow/nodes/split_by_scheme.ts +7 -0
  476. package/src/flow/nodes/split_by_subflow.ts +9 -0
  477. package/src/flow/nodes/split_by_webhook.ts +19 -0
  478. package/src/flow/nodes/wait_for_audio.ts +7 -0
  479. package/src/flow/nodes/wait_for_digits.ts +7 -0
  480. package/src/flow/nodes/wait_for_image.ts +7 -0
  481. package/src/flow/nodes/wait_for_location.ts +7 -0
  482. package/src/flow/nodes/wait_for_menu.ts +7 -0
  483. package/src/flow/nodes/wait_for_response.ts +7 -0
  484. package/src/flow/nodes/wait_for_video.ts +7 -0
  485. package/src/flow/types.ts +352 -0
  486. package/src/flow/utils.ts +76 -0
  487. package/src/form/ArrayEditor.ts +240 -0
  488. package/src/form/BaseListEditor.ts +177 -0
  489. package/src/{checkbox → form}/Checkbox.ts +24 -5
  490. package/src/{colorpicker → form}/ColorPicker.ts +2 -2
  491. package/src/{completion → form}/Completion.ts +9 -3
  492. package/src/{compose → form}/Compose.ts +7 -7
  493. package/src/{contactsearch → form}/ContactSearch.ts +6 -6
  494. package/src/{datepicker → form}/DatePicker.ts +1 -1
  495. package/src/{FormElement.ts → form/FormElement.ts} +1 -1
  496. package/src/form/FormField.ts +238 -0
  497. package/src/{imagepicker → form}/ImagePicker.ts +2 -2
  498. package/src/form/KeyValueEditor.ts +251 -0
  499. package/src/{mediapicker → form}/MediaPicker.ts +1 -1
  500. package/src/{slider → form}/TembaSlider.ts +1 -1
  501. package/src/{templates → form}/TemplateEditor.ts +2 -2
  502. package/src/{textinput → form}/TextInput.ts +5 -5
  503. package/src/{omnibox → form/select}/Omnibox.ts +2 -2
  504. package/src/{select → form/select}/PopupSelect.ts +1 -1
  505. package/src/{select → form/select}/Select.ts +207 -152
  506. package/src/{select → form/select}/UserSelect.ts +1 -1
  507. package/src/{select → form/select}/WorkspaceSelect.ts +1 -1
  508. package/src/interfaces.ts +8 -2
  509. package/src/{dialog → layout}/Dialog.ts +1 -1
  510. package/src/list/NotificationList.ts +2 -2
  511. package/src/list/RunList.ts +3 -3
  512. package/src/list/ShortcutList.ts +1 -1
  513. package/src/list/TembaMenu.ts +2 -2
  514. package/src/list/TicketList.ts +1 -1
  515. package/src/{aliaseditor → live}/AliasEditor.ts +3 -3
  516. package/src/{contacts → live}/ContactBadges.ts +1 -1
  517. package/src/{contacts → live}/ContactChat.ts +120 -104
  518. package/src/{contacts → live}/ContactDetails.ts +1 -1
  519. package/src/{contacts → live}/ContactFieldEditor.ts +4 -4
  520. package/src/{contacts → live}/ContactFields.ts +1 -1
  521. package/src/{contacts → live}/ContactNotepad.ts +1 -1
  522. package/src/{contacts → live}/ContactPending.ts +1 -1
  523. package/src/{chart → live}/TembaChart.ts +1 -1
  524. package/src/store/AppState.ts +75 -29
  525. package/src/store/Store.ts +1 -1
  526. package/src/store/flow-definition.d.ts +131 -1
  527. package/src/{utils/index.ts → utils.ts} +26 -10
  528. package/src/webchat/WebChat.ts +1 -1
  529. package/static/api/contacts.json +30 -0
  530. package/static/api/groups.json +4 -426
  531. package/static/api/locations.json +24 -0
  532. package/static/api/media.json +5 -0
  533. package/static/api/optins.json +16 -0
  534. package/static/api/orgs.json +13 -0
  535. package/static/api/topics.json +21 -0
  536. package/static/api/users.json +26 -0
  537. package/static/css/temba-components.css +4 -6
  538. package/svg.js +1 -4
  539. package/temba-components.ts +2 -2
  540. package/temba-modules.ts +63 -56
  541. package/temba-webchat.ts +2 -2
  542. package/test/ActionHelper.ts +142 -0
  543. package/test/actions/add_contact_groups.test.ts +89 -0
  544. package/test/actions/remove_contact_groups.test.ts +265 -0
  545. package/test/actions/send_email.test.ts +214 -0
  546. package/test/actions/send_msg.test.ts +130 -0
  547. package/test/temba-action-editing-integration.test.ts +240 -0
  548. package/test/temba-alert.test.ts +1 -1
  549. package/test/temba-appstate-language.test.ts +108 -0
  550. package/test/temba-charcount.test.ts +1 -1
  551. package/test/temba-chart.test.ts +1 -1
  552. package/test/temba-checkbox.test.ts +2 -2
  553. package/test/temba-color-picker.test.ts +1 -1
  554. package/test/temba-completion.test.ts +1 -1
  555. package/test/temba-compose.test.ts +1 -1
  556. package/test/temba-contact-badges.test.ts +1 -1
  557. package/test/temba-contact-chat.test.ts +6 -4
  558. package/test/temba-contact-details.test.ts +1 -1
  559. package/test/temba-contact-fields.test.ts +1 -1
  560. package/test/temba-contact-search.test.ts +2 -2
  561. package/test/temba-date.test.ts +8 -3
  562. package/test/temba-datepicker.test.ts +1 -1
  563. package/test/temba-dialog.test.ts +1 -1
  564. package/test/temba-dropdown.test.ts +1 -1
  565. package/test/temba-excellent-helpers.test.ts +417 -0
  566. package/test/temba-field-config.test.ts +152 -0
  567. package/test/temba-field-manager.test.ts +2 -2
  568. package/test/temba-flow-editor-node.test.ts +551 -16
  569. package/test/temba-flow-editor.test.ts +224 -0
  570. package/test/temba-flow-editor.test.ts.backup +563 -0
  571. package/test/temba-flow-plumber-connections.test.ts +142 -0
  572. package/test/temba-flow-plumber.test.ts +83 -120
  573. package/test/temba-flow-self-routing.test.ts +215 -0
  574. package/test/temba-formfield.test.ts +1 -1
  575. package/test/temba-icon.test.ts +1 -1
  576. package/test/temba-integration-markdown.test.ts +1 -1
  577. package/test/temba-label.test.ts +1 -1
  578. package/test/temba-lightbox.test.ts +1 -1
  579. package/test/temba-markdown.test.ts +162 -0
  580. package/test/temba-menu.test.ts +1 -1
  581. package/test/temba-modax.test.ts +2 -2
  582. package/test/temba-modules.test.ts +56 -0
  583. package/test/temba-node-editor.test.ts +353 -0
  584. package/test/temba-omnibox.test.ts +1 -1
  585. package/test/temba-options.test.ts +1 -1
  586. package/test/temba-range-picker.test.ts +17 -2
  587. package/test/temba-rapid-element.test.ts +341 -0
  588. package/test/temba-resize-element.test.ts +104 -0
  589. package/test/temba-select.test.ts +129 -2
  590. package/test/temba-slider.test.ts +1 -1
  591. package/test/temba-sticky-note.test.ts +281 -0
  592. package/test/temba-template-editor.test.ts +1 -1
  593. package/test/temba-textinput.test.ts +1 -1
  594. package/test/temba-tip.test.ts +1 -1
  595. package/test/temba-toast.test.ts +1 -1
  596. package/test/temba-utils-index.test.ts +1 -1
  597. package/test/temba-utils-index.test.ts.backup +1737 -0
  598. package/test/temba-utils-uuid.test.ts +48 -0
  599. package/test/temba-webchat.test.ts +30 -12
  600. package/test/utils.test.ts +5 -9
  601. package/test-assets/contacts/history.json +11 -33
  602. package/web-dev-server.config.mjs +35 -1
  603. package/demo/sticky-note-demo.html +0 -155
  604. package/out-tsc/src/FormElement.js.map +0 -1
  605. package/out-tsc/src/alert/Alert.js.map +0 -1
  606. package/out-tsc/src/aliaseditor/AliasEditor.js.map +0 -1
  607. package/out-tsc/src/anchor/Anchor.js.map +0 -1
  608. package/out-tsc/src/button/Button.js.map +0 -1
  609. package/out-tsc/src/charcount/CharCount.js.map +0 -1
  610. package/out-tsc/src/charcount/helpers.js +0 -159
  611. package/out-tsc/src/charcount/helpers.js.map +0 -1
  612. package/out-tsc/src/chart/TembaChart.js.map +0 -1
  613. package/out-tsc/src/chat/Chat.js.map +0 -1
  614. package/out-tsc/src/checkbox/Checkbox.js.map +0 -1
  615. package/out-tsc/src/colorpicker/ColorPicker.js.map +0 -1
  616. package/out-tsc/src/completion/Completion.js.map +0 -1
  617. package/out-tsc/src/completion/ExcellentParser.js.map +0 -1
  618. package/out-tsc/src/completion/helpers.js.map +0 -1
  619. package/out-tsc/src/compose/Compose.js.map +0 -1
  620. package/out-tsc/src/contacts/ContactBadges.js.map +0 -1
  621. package/out-tsc/src/contacts/ContactChat.js.map +0 -1
  622. package/out-tsc/src/contacts/ContactDetails.js.map +0 -1
  623. package/out-tsc/src/contacts/ContactFieldEditor.js.map +0 -1
  624. package/out-tsc/src/contacts/ContactFields.js.map +0 -1
  625. package/out-tsc/src/contacts/ContactName.js.map +0 -1
  626. package/out-tsc/src/contacts/ContactNameFetch.js.map +0 -1
  627. package/out-tsc/src/contacts/ContactPending.js.map +0 -1
  628. package/out-tsc/src/contacts/ContactStoreElement.js.map +0 -1
  629. package/out-tsc/src/contacts/ContactUrn.js.map +0 -1
  630. package/out-tsc/src/contacts/events.js +0 -65
  631. package/out-tsc/src/contacts/events.js.map +0 -1
  632. package/out-tsc/src/contacts/helpers.js +0 -77
  633. package/out-tsc/src/contacts/helpers.js.map +0 -1
  634. package/out-tsc/src/contactsearch/ContactSearch.js.map +0 -1
  635. package/out-tsc/src/date/TembaDate.js.map +0 -1
  636. package/out-tsc/src/datepicker/DatePicker.js.map +0 -1
  637. package/out-tsc/src/datepicker/RangePicker.js.map +0 -1
  638. package/out-tsc/src/dialog/Dialog.js.map +0 -1
  639. package/out-tsc/src/dropdown/Dropdown.js.map +0 -1
  640. package/out-tsc/src/fields/FieldManager.js.map +0 -1
  641. package/out-tsc/src/flow/EditorNode.js +0 -291
  642. package/out-tsc/src/flow/EditorNode.js.map +0 -1
  643. package/out-tsc/src/flow/render.js +0 -41
  644. package/out-tsc/src/flow/render.js.map +0 -1
  645. package/out-tsc/src/formfield/FormField.js +0 -144
  646. package/out-tsc/src/formfield/FormField.js.map +0 -1
  647. package/out-tsc/src/imagepicker/CroppieCSS.js.map +0 -1
  648. package/out-tsc/src/imagepicker/ImagePicker.js.map +0 -1
  649. package/out-tsc/src/label/Label.js.map +0 -1
  650. package/out-tsc/src/leafletmap/LeafletMap.js.map +0 -1
  651. package/out-tsc/src/leafletmap/helpers.js +0 -17
  652. package/out-tsc/src/leafletmap/helpers.js.map +0 -1
  653. package/out-tsc/src/lightbox/Lightbox.js.map +0 -1
  654. package/out-tsc/src/mask/Mask.js.map +0 -1
  655. package/out-tsc/src/mediapicker/MediaPicker.js.map +0 -1
  656. package/out-tsc/src/omnibox/Omnibox.js.map +0 -1
  657. package/out-tsc/src/options/helpers.js +0 -28
  658. package/out-tsc/src/options/helpers.js.map +0 -1
  659. package/out-tsc/src/progress/ProgressBar.js.map +0 -1
  660. package/out-tsc/src/progress/StartProgress.js.map +0 -1
  661. package/out-tsc/src/resizer/Resizer.js.map +0 -1
  662. package/out-tsc/src/select/PopupSelect.js.map +0 -1
  663. package/out-tsc/src/select/Select.js.map +0 -1
  664. package/out-tsc/src/select/UserSelect.js.map +0 -1
  665. package/out-tsc/src/select/WorkspaceSelect.js.map +0 -1
  666. package/out-tsc/src/select/helpers.js +0 -1
  667. package/out-tsc/src/select/helpers.js.map +0 -1
  668. package/out-tsc/src/shadowless/Shadowless.js +0 -33
  669. package/out-tsc/src/shadowless/Shadowless.js.map +0 -1
  670. package/out-tsc/src/slider/TembaSlider.js.map +0 -1
  671. package/out-tsc/src/sms/gsmsplitter.js.map +0 -1
  672. package/out-tsc/src/sms/gsmvalidator.js.map +0 -1
  673. package/out-tsc/src/sms/index.js.map +0 -1
  674. package/out-tsc/src/sms/unicodesplitter.js.map +0 -1
  675. package/out-tsc/src/tabpane/Tab.js.map +0 -1
  676. package/out-tsc/src/tabpane/TabPane.js.map +0 -1
  677. package/out-tsc/src/templates/TemplateEditor.js.map +0 -1
  678. package/out-tsc/src/textinput/TextInput.js.map +0 -1
  679. package/out-tsc/src/textinput/helpers.js +0 -12
  680. package/out-tsc/src/textinput/helpers.js.map +0 -1
  681. package/out-tsc/src/thumbnail/Thumbnail.js.map +0 -1
  682. package/out-tsc/src/tip/Tip.js.map +0 -1
  683. package/out-tsc/src/tip/helpers.js +0 -7
  684. package/out-tsc/src/tip/helpers.js.map +0 -1
  685. package/out-tsc/src/toast/Toast.js.map +0 -1
  686. package/out-tsc/src/user/TembaUser.js.map +0 -1
  687. package/out-tsc/src/utils/index.js.map +0 -1
  688. package/out-tsc/src/vectoricon/VectorIcon.js.map +0 -1
  689. package/out-tsc/src/vectoricon/index.js.map +0 -1
  690. package/out-tsc/test/temba-flow-render.test.js +0 -171
  691. package/out-tsc/test/temba-flow-render.test.js.map +0 -1
  692. package/src/charcount/helpers.ts +0 -162
  693. package/src/contacts/events.ts +0 -210
  694. package/src/contacts/helpers.ts +0 -103
  695. package/src/flow/EditorNode.ts +0 -318
  696. package/src/flow/render.ts +0 -56
  697. package/src/formfield/FormField.ts +0 -134
  698. package/src/leafletmap/helpers.ts +0 -18
  699. package/src/options/helpers.ts +0 -37
  700. package/src/select/helpers.ts +0 -0
  701. package/src/shadowless/Shadowless.ts +0 -32
  702. package/src/textinput/helpers.ts +0 -11
  703. package/src/tip/helpers.ts +0 -7
  704. package/test/temba-flow-render.test.ts +0 -220
  705. /package/out-tsc/src/{alert → display}/Alert.js +0 -0
  706. /package/out-tsc/src/{anchor → display}/Anchor.js +0 -0
  707. /package/out-tsc/src/{button → display}/Button.js +0 -0
  708. /package/out-tsc/src/{chat → display}/Chat.js +0 -0
  709. /package/out-tsc/src/{contacts → display}/ContactName.js +0 -0
  710. /package/out-tsc/src/{contacts → display}/ContactUrn.js +0 -0
  711. /package/out-tsc/src/{dropdown → display}/Dropdown.js +0 -0
  712. /package/out-tsc/src/{label → display}/Label.js +0 -0
  713. /package/out-tsc/src/{lightbox → display}/Lightbox.js +0 -0
  714. /package/out-tsc/src/{loading → display}/Loading.js +0 -0
  715. /package/out-tsc/src/{options → display}/Options.js +0 -0
  716. /package/out-tsc/src/{progress → display}/ProgressBar.js +0 -0
  717. /package/out-tsc/src/{date → display}/TembaDate.js +0 -0
  718. /package/out-tsc/src/{user → display}/TembaUser.js +0 -0
  719. /package/out-tsc/src/{thumbnail → display}/Thumbnail.js +0 -0
  720. /package/out-tsc/src/{toast → display}/Toast.js +0 -0
  721. /package/out-tsc/src/{sms → display/sms}/gsmsplitter.js +0 -0
  722. /package/out-tsc/src/{sms → display/sms}/gsmvalidator.js +0 -0
  723. /package/out-tsc/src/{sms → display/sms}/index.js +0 -0
  724. /package/out-tsc/src/{sms → display/sms}/unicodesplitter.js +0 -0
  725. /package/out-tsc/src/{completion → excellent}/ExcellentParser.js +0 -0
  726. /package/out-tsc/src/{completion → excellent}/helpers.js +0 -0
  727. /package/out-tsc/src/{imagepicker → form}/CroppieCSS.js +0 -0
  728. /package/out-tsc/src/{datepicker → form}/RangePicker.js +0 -0
  729. /package/out-tsc/src/{dialog → layout}/Dialog.js +0 -0
  730. /package/out-tsc/src/{mask → layout}/Mask.js +0 -0
  731. /package/out-tsc/src/{dialog → layout}/Modax.js +0 -0
  732. /package/out-tsc/src/{resizer → layout}/Resizer.js +0 -0
  733. /package/out-tsc/src/{tabpane → layout}/Tab.js +0 -0
  734. /package/out-tsc/src/{tabpane → layout}/TabPane.js +0 -0
  735. /package/out-tsc/src/{contacts → live}/ContactFields.js +0 -0
  736. /package/out-tsc/src/{contacts → live}/ContactNameFetch.js +0 -0
  737. /package/out-tsc/src/{contacts → live}/ContactStoreElement.js +0 -0
  738. /package/out-tsc/src/{fields → live}/FieldManager.js +0 -0
  739. /package/out-tsc/src/{progress → live}/StartProgress.js +0 -0
  740. /package/out-tsc/src/{chart → live}/TembaChart.js +0 -0
  741. /package/src/{vectoricon/index.ts → Icons.ts} +0 -0
  742. /package/src/{alert → display}/Alert.ts +0 -0
  743. /package/src/{anchor → display}/Anchor.ts +0 -0
  744. /package/src/{button → display}/Button.ts +0 -0
  745. /package/src/{chat → display}/Chat.ts +0 -0
  746. /package/src/{contacts → display}/ContactName.ts +0 -0
  747. /package/src/{contacts → display}/ContactUrn.ts +0 -0
  748. /package/src/{dropdown → display}/Dropdown.ts +0 -0
  749. /package/src/{label → display}/Label.ts +0 -0
  750. /package/src/{lightbox → display}/Lightbox.ts +0 -0
  751. /package/src/{loading → display}/Loading.ts +0 -0
  752. /package/src/{options → display}/Options.ts +0 -0
  753. /package/src/{progress → display}/ProgressBar.ts +0 -0
  754. /package/src/{date → display}/TembaDate.ts +0 -0
  755. /package/src/{user → display}/TembaUser.ts +0 -0
  756. /package/src/{toast → display}/Toast.ts +0 -0
  757. /package/src/{sms → display/sms}/gsmsplitter.ts +0 -0
  758. /package/src/{sms → display/sms}/gsmvalidator.ts +0 -0
  759. /package/src/{sms → display/sms}/index.ts +0 -0
  760. /package/src/{sms → display/sms}/unicodesplitter.ts +0 -0
  761. /package/src/{completion → excellent}/ExcellentParser.ts +0 -0
  762. /package/src/{completion → excellent}/helpers.ts +0 -0
  763. /package/src/{imagepicker → form}/CroppieCSS.ts +0 -0
  764. /package/src/{datepicker → form}/RangePicker.ts +0 -0
  765. /package/src/{mask → layout}/Mask.ts +0 -0
  766. /package/src/{dialog → layout}/Modax.ts +0 -0
  767. /package/src/{resizer → layout}/Resizer.ts +0 -0
  768. /package/src/{tabpane → layout}/Tab.ts +0 -0
  769. /package/src/{tabpane → layout}/TabPane.ts +0 -0
  770. /package/src/{contacts → live}/ContactNameFetch.ts +0 -0
  771. /package/src/{contacts → live}/ContactStoreElement.ts +0 -0
  772. /package/src/{fields → live}/FieldManager.ts +0 -0
  773. /package/src/{progress → live}/StartProgress.ts +0 -0
@@ -0,0 +1,563 @@
1
+ import { html, fixture, expect } from '@open-wc/testing';
2
+ import { Editor } from '../src/flow/Editor';
3
+ import { Plumber } from '../src/flow/Plumber';
4
+ import { stub, restore } from 'sinon';
5
+
6
+ // Register the component
7
+ customElements.define('temba-flow-editor', Editor);
8
+
9
+ describe('Editor', () => {
10
+ let editor: Editor;
11
+
12
+ beforeEach(() => {
13
+ // Reset any stubs
14
+ restore();
15
+ });
16
+
17
+ afterEach(() => {
18
+ restore();
19
+ });
20
+
21
+ describe('basic functionality', () => {
22
+ it('creates render root as element itself', () => {
23
+ const editor = new Editor();
24
+ expect(editor.createRenderRoot()).to.equal(editor);
25
+ });
26
+
27
+ it('has correct CSS styles defined', () => {
28
+ const styles = Editor.styles;
29
+ expect(styles).to.exist;
30
+ expect(styles.cssText).to.contain('#editor');
31
+ expect(styles.cssText).to.contain('#grid');
32
+ expect(styles.cssText).to.contain('#canvas');
33
+ expect(styles.cssText).to.contain('.plumb-source');
34
+ expect(styles.cssText).to.contain('.plumb-target');
35
+ expect(styles.cssText).to.contain('.plumb-connector');
36
+ });
37
+
38
+ it('creates with default properties', () => {
39
+ editor = new Editor();
40
+ expect(editor.flow).to.be.undefined;
41
+ expect(editor.version).to.be.undefined;
42
+ });
43
+
44
+ it('accepts flow and version properties without getStore call', async () => {
45
+ editor = document.createElement('temba-flow-editor') as Editor;
46
+ editor.flow = 'test-flow-uuid';
47
+ editor.version = '1.0';
48
+
49
+ expect(editor.flow).to.equal('test-flow-uuid');
50
+ expect(editor.version).to.equal('1.0');
51
+ });
52
+ });
53
+
54
+ describe('lifecycle methods', () => {
55
+ it('calls firstUpdated and initializes plumber', async () => {
56
+ editor = await fixture(html`
57
+ <temba-flow-editor>
58
+ <div id="canvas"></div>
59
+ </temba-flow-editor>
60
+ `);
61
+
62
+ // Verify that plumber is initialized
63
+ expect((editor as any).plumber).to.be.instanceOf(Plumber);
64
+ });
65
+
66
+ it('verifies firstUpdated method exists and can be called', () => {
67
+ editor = new Editor();
68
+
69
+ // Mock canvas element
70
+ const mockCanvas = document.createElement('div');
71
+ mockCanvas.id = 'canvas';
72
+
73
+ // Mock querySelector to return our mock canvas
74
+ stub(editor, 'querySelector').returns(mockCanvas);
75
+
76
+ // Verify firstUpdated method exists
77
+ expect(typeof (editor as any).firstUpdated).to.equal('function');
78
+
79
+ // Test that calling firstUpdated doesn't throw (without getStore)
80
+ expect(() => {
81
+ // Only test the plumber initialization part
82
+ (editor as any).plumber = new Plumber(mockCanvas);
83
+ }).to.not.throw();
84
+ });
85
+
86
+ it('handles updated with canvasSize changes', async () => {
87
+ editor = await fixture(html`
88
+ <temba-flow-editor>
89
+ <div id="canvas"></div>
90
+ </temba-flow-editor>
91
+ `);
92
+
93
+ // Simulate canvasSize change
94
+ (editor as any).canvasSize = { width: 800, height: 600 };
95
+ const changes = new Map();
96
+ changes.set('canvasSize', true);
97
+
98
+ (editor as any).updated(changes);
99
+
100
+ // Verify the canvasSize was set correctly
101
+ expect((editor as any).canvasSize).to.deep.equal({
102
+ width: 800,
103
+ height: 600
104
+ });
105
+ });
106
+
107
+ it('handles updated without canvasSize changes', async () => {
108
+ editor = await fixture(html`
109
+ <temba-flow-editor>
110
+ <div id="canvas"></div>
111
+ </temba-flow-editor>
112
+ `);
113
+
114
+ const consoleStub = stub(console, 'log');
115
+
116
+ const changes = new Map();
117
+ changes.set('other', true);
118
+
119
+ (editor as any).updated(changes);
120
+
121
+ expect(consoleStub).to.not.have.been.called;
122
+
123
+ consoleStub.restore();
124
+ });
125
+ });
126
+
127
+ describe('render method', () => {
128
+ it('renders loading when no definition', async () => {
129
+ editor = await fixture(html`
130
+ <temba-flow-editor>
131
+ <div id="canvas"></div>
132
+ </temba-flow-editor>
133
+ `);
134
+
135
+ // Set canvas size to avoid undefined errors
136
+ (editor as any).canvasSize = { width: 800, height: 600 };
137
+ await editor.updateComplete;
138
+
139
+ const loadingElement = editor.querySelector('temba-loading');
140
+ expect(loadingElement).to.exist;
141
+ });
142
+
143
+ it('renders nodes when definition exists', async () => {
144
+ const mockDefinition = {
145
+ nodes: [
146
+ {
147
+ uuid: 'node-1',
148
+ actions: [],
149
+ exits: []
150
+ },
151
+ {
152
+ uuid: 'node-2',
153
+ actions: [],
154
+ exits: []
155
+ }
156
+ ],
157
+ _ui: {
158
+ nodes: {
159
+ 'node-1': { position: { left: 100, top: 200 } },
160
+ 'node-2': { position: { left: 300, top: 400 } }
161
+ }
162
+ }
163
+ };
164
+
165
+ editor = await fixture(html`
166
+ <temba-flow-editor>
167
+ <div id="canvas"></div>
168
+ </temba-flow-editor>
169
+ `);
170
+
171
+ // Set properties
172
+ (editor as any).definition = mockDefinition;
173
+ (editor as any).canvasSize = { width: 800, height: 600 };
174
+ await editor.updateComplete;
175
+
176
+ const flowNodes = editor.querySelectorAll('temba-flow-node');
177
+ expect(flowNodes).to.have.length(2);
178
+ });
179
+
180
+ it('includes style elements in light DOM', async () => {
181
+ editor = await fixture(html`
182
+ <temba-flow-editor>
183
+ <div id="canvas"></div>
184
+ </temba-flow-editor>
185
+ `);
186
+
187
+ // Set canvas size
188
+ (editor as any).canvasSize = { width: 800, height: 600 };
189
+ await editor.updateComplete;
190
+
191
+ const styleElements = editor.querySelectorAll('style');
192
+ expect(styleElements.length).to.be.greaterThan(0);
193
+ });
194
+
195
+ it('renders with correct grid dimensions', async () => {
196
+ editor = await fixture(html`
197
+ <temba-flow-editor>
198
+ <div id="canvas"></div>
199
+ </temba-flow-editor>
200
+ `);
201
+
202
+ // Set canvas size to specific dimensions
203
+ (editor as any).canvasSize = { width: 1200, height: 900 };
204
+ await editor.updateComplete;
205
+
206
+ const gridElement = editor.querySelector('#grid');
207
+ expect(gridElement).to.exist;
208
+
209
+ // Check that grid has correct dimensions
210
+ const gridStyle = gridElement.getAttribute('style');
211
+ expect(gridStyle).to.contain('width:1200px');
212
+ expect(gridStyle).to.contain('height:900px');
213
+ });
214
+ });
215
+
216
+ describe('multi-selection functionality', () => {
217
+ let mockDefinition: any;
218
+
219
+ beforeEach(() => {
220
+ mockDefinition = {
221
+ nodes: [
222
+ {
223
+ uuid: 'node-1',
224
+ actions: [],
225
+ exits: []
226
+ },
227
+ {
228
+ uuid: 'node-2',
229
+ actions: [],
230
+ exits: []
231
+ }
232
+ ],
233
+ _ui: {
234
+ nodes: {
235
+ 'node-1': { position: { left: 100, top: 200 } },
236
+ 'node-2': { position: { left: 300, top: 400 } }
237
+ },
238
+ stickies: {
239
+ 'sticky-1': {
240
+ position: { left: 200, top: 100 },
241
+ title: 'Test Sticky',
242
+ body: 'Test content',
243
+ color: 'yellow'
244
+ }
245
+ }
246
+ }
247
+ };
248
+ });
249
+
250
+ it('initializes with empty selection', async () => {
251
+ editor = await fixture(html`
252
+ <temba-flow-editor>
253
+ <div id="canvas"></div>
254
+ </temba-flow-editor>
255
+ `);
256
+
257
+ expect((editor as any).selectedItems.size).to.equal(0);
258
+ expect((editor as any).isSelecting).to.be.false;
259
+ expect((editor as any).selectionBox).to.be.null;
260
+ });
261
+
262
+ it('adds visual selection styling to selected items', async () => {
263
+ editor = await fixture(html`
264
+ <temba-flow-editor>
265
+ <div id="canvas"></div>
266
+ </temba-flow-editor>
267
+ `);
268
+
269
+ // Set up mock definition and selection
270
+ (editor as any).definition = mockDefinition;
271
+ (editor as any).canvasSize = { width: 800, height: 600 };
272
+ (editor as any).selectedItems = new Set(['node-1']);
273
+ await editor.updateComplete;
274
+
275
+ const selectedNode = editor.querySelector('temba-flow-node[uuid="node-1"]');
276
+ expect(selectedNode).to.exist;
277
+ expect(selectedNode.classList.contains('selected')).to.be.true;
278
+ });
279
+
280
+ it('renders selection box when selecting', async () => {
281
+ editor = await fixture(html`
282
+ <temba-flow-editor>
283
+ <div id="canvas"></div>
284
+ </temba-flow-editor>
285
+ `);
286
+
287
+ // Set up selection state
288
+ (editor as any).definition = mockDefinition;
289
+ (editor as any).canvasSize = { width: 800, height: 600 };
290
+ (editor as any).isSelecting = true;
291
+ (editor as any).selectionBox = {
292
+ startX: 50,
293
+ startY: 50,
294
+ endX: 150,
295
+ endY: 150
296
+ };
297
+ await editor.updateComplete;
298
+
299
+ const selectionBox = editor.querySelector('.selection-box');
300
+ expect(selectionBox).to.exist;
301
+
302
+ const style = selectionBox.getAttribute('style');
303
+ expect(style).to.contain('left: 50px');
304
+ expect(style).to.contain('top: 50px');
305
+ expect(style).to.contain('width: 100px');
306
+ expect(style).to.contain('height: 100px');
307
+ });
308
+
309
+ it('does not render selection box when not selecting', async () => {
310
+ editor = await fixture(html`
311
+ <temba-flow-editor>
312
+ <div id="canvas"></div>
313
+ </temba-flow-editor>
314
+ `);
315
+
316
+ (editor as any).definition = mockDefinition;
317
+ (editor as any).canvasSize = { width: 800, height: 600 };
318
+ (editor as any).isSelecting = false;
319
+ await editor.updateComplete;
320
+
321
+ const selectionBox = editor.querySelector('.selection-box');
322
+ expect(selectionBox).to.not.exist;
323
+ });
324
+
325
+ it('handles canvas mouse down for selection start', async () => {
326
+ editor = await fixture(html`
327
+ <temba-flow-editor>
328
+ <div id="canvas"></div>
329
+ </temba-flow-editor>
330
+ `);
331
+
332
+ (editor as any).definition = mockDefinition;
333
+ (editor as any).canvasSize = { width: 800, height: 600 };
334
+
335
+ // Pre-select an item
336
+ (editor as any).selectedItems.add('node-1');
337
+ await editor.updateComplete;
338
+
339
+ const canvas = editor.querySelector('#canvas');
340
+ const mockEvent = new MouseEvent('mousedown', {
341
+ clientX: 100,
342
+ clientY: 100,
343
+ bubbles: true
344
+ });
345
+
346
+ // Mock getBoundingClientRect for canvas
347
+ stub(canvas, 'getBoundingClientRect').returns({
348
+ left: 0,
349
+ top: 0,
350
+ width: 800,
351
+ height: 600
352
+ } as DOMRect);
353
+
354
+ // Set event target to canvas
355
+ Object.defineProperty(mockEvent, 'target', {
356
+ value: canvas,
357
+ writable: false
358
+ });
359
+
360
+ (editor as any).handleCanvasMouseDown(mockEvent);
361
+
362
+ // Should clear selection and start selection box
363
+ expect((editor as any).selectedItems.size).to.equal(0);
364
+ expect((editor as any).canvasMouseDown).to.be.true;
365
+ expect((editor as any).selectionBox).to.not.be.null;
366
+ });
367
+
368
+ it('handles keyboard delete key with confirmation', async () => {
369
+ editor = await fixture(html`
370
+ <temba-flow-editor>
371
+ <div id="canvas"></div>
372
+ </temba-flow-editor>
373
+ `);
374
+
375
+ // Mock window.confirm
376
+ const confirmStub = stub(window, 'confirm');
377
+ confirmStub.returns(true);
378
+
379
+ // Set up selection
380
+ (editor as any).selectedItems.add('node-1');
381
+
382
+ const mockEvent = new KeyboardEvent('keydown', { key: 'Delete' });
383
+ (editor as any).handleKeyDown(mockEvent);
384
+
385
+ expect(confirmStub).to.have.been.calledWith('Are you sure you want to delete 1 item?');
386
+
387
+ confirmStub.restore();
388
+ });
389
+
390
+ it('handles escape key to clear selection', async () => {
391
+ editor = await fixture(html`
392
+ <temba-flow-editor>
393
+ <div id="canvas"></div>
394
+ </temba-flow-editor>
395
+ `);
396
+
397
+ // Set up selection
398
+ (editor as any).selectedItems.add('node-1');
399
+ (editor as any).selectedItems.add('node-2');
400
+
401
+ const mockEvent = new KeyboardEvent('keydown', { key: 'Escape' });
402
+ (editor as any).handleKeyDown(mockEvent);
403
+
404
+ expect((editor as any).selectedItems.size).to.equal(0);
405
+ });
406
+
407
+ it('updates selection box coordinates during mouse move', async () => {
408
+ editor = await fixture(html`
409
+ <temba-flow-editor>
410
+ <div id="canvas"></div>
411
+ </temba-flow-editor>
412
+ `);
413
+
414
+ const canvas = editor.querySelector('#canvas');
415
+
416
+ // Mock getBoundingClientRect
417
+ stub(canvas, 'getBoundingClientRect').returns({
418
+ left: 0,
419
+ top: 0,
420
+ width: 800,
421
+ height: 600
422
+ } as DOMRect);
423
+
424
+ // Set up initial selection state
425
+ (editor as any).canvasMouseDown = true;
426
+ (editor as any).selectionBox = {
427
+ startX: 50,
428
+ startY: 50,
429
+ endX: 50,
430
+ endY: 50
431
+ };
432
+ (editor as any).definition = mockDefinition;
433
+
434
+ const mockEvent = new MouseEvent('mousemove', {
435
+ clientX: 150,
436
+ clientY: 150
437
+ });
438
+
439
+ (editor as any).updateSelectionBox(mockEvent);
440
+
441
+ expect((editor as any).selectionBox.endX).to.equal(150);
442
+ expect((editor as any).selectionBox.endY).to.equal(150);
443
+ });
444
+
445
+ it('calculates intersections correctly for node selection', async () => {
446
+ editor = await fixture(html`
447
+ <temba-flow-editor>
448
+ <div id="canvas"></div>
449
+ </temba-flow-editor>
450
+ `);
451
+
452
+ (editor as any).definition = mockDefinition;
453
+ (editor as any).canvasSize = { width: 800, height: 600 };
454
+ await editor.updateComplete;
455
+
456
+ // Mock node element and its bounding rect
457
+ const nodeElement = editor.querySelector('temba-flow-node[uuid="node-1"]');
458
+ stub(nodeElement, 'getBoundingClientRect').returns({
459
+ width: 200,
460
+ height: 100
461
+ } as DOMRect);
462
+
463
+ // Set selection box that intersects with node-1 (position: left: 100, top: 200)
464
+ (editor as any).selectionBox = {
465
+ startX: 50, // Selection box from 50,150 to 250,250
466
+ startY: 150, // This should intersect node-1 at 100,200 with size 200x100
467
+ endX: 250,
468
+ endY: 250
469
+ };
470
+
471
+ (editor as any).updateSelectedItemsFromBox();
472
+
473
+ expect((editor as any).selectedItems.has('node-1')).to.be.true;
474
+ });
475
+ });
476
+
477
+ describe('canvas initialization', () => {
478
+ <div id="canvas"></div>
479
+ </temba-flow-editor>
480
+ `);
481
+
482
+ (editor as any).canvasSize = { width: 800, height: 600 };
483
+ await editor.updateComplete;
484
+
485
+ const editorElement = editor.querySelector('#editor');
486
+ expect(editorElement).to.exist;
487
+
488
+ const gridElement = editor.querySelector('#grid');
489
+ expect(gridElement).to.exist;
490
+
491
+ const canvasElement = editor.querySelector('#canvas');
492
+ expect(canvasElement).to.exist;
493
+ });
494
+ });
495
+
496
+ describe('property handling', () => {
497
+ it('handles flow property change', async () => {
498
+ editor = await fixture(html`
499
+ <temba-flow-editor>
500
+ <div id="canvas"></div>
501
+ </temba-flow-editor>
502
+ `);
503
+
504
+ // Change flow property
505
+ editor.flow = 'new-flow-uuid';
506
+ await editor.updateComplete;
507
+
508
+ expect(editor.flow).to.equal('new-flow-uuid');
509
+ });
510
+
511
+ it('handles version property change', async () => {
512
+ editor = await fixture(html`
513
+ <temba-flow-editor>
514
+ <div id="canvas"></div>
515
+ </temba-flow-editor>
516
+ `);
517
+
518
+ editor.version = '2.0';
519
+ await editor.updateComplete;
520
+
521
+ expect(editor.version).to.equal('2.0');
522
+ });
523
+ });
524
+
525
+ describe('store integration', () => {
526
+ it('has fromStore decorators for definition and canvasSize', () => {
527
+ editor = new Editor();
528
+
529
+ // Check that the properties exist (they are private but we can verify they exist)
530
+ expect(editor).to.have.property('definition');
531
+ expect(editor).to.have.property('canvasSize');
532
+ });
533
+ });
534
+
535
+ describe('constructor behavior', () => {
536
+ it('calls super in constructor', () => {
537
+ // This mainly verifies the constructor doesn't throw
538
+ expect(() => {
539
+ new Editor();
540
+ }).to.not.throw();
541
+ });
542
+ });
543
+
544
+ describe('canvas initialization', () => {
545
+ it('initializes plumber with canvas element', async () => {
546
+ editor = await fixture(html`
547
+ <temba-flow-editor>
548
+ <div id="canvas"></div>
549
+ </temba-flow-editor>
550
+ `);
551
+
552
+ const plumber = (editor as any).plumber;
553
+ expect(plumber).to.be.instanceOf(Plumber);
554
+ });
555
+
556
+ it('handles missing canvas element gracefully', async () => {
557
+ editor = await fixture(html`<temba-flow-editor></temba-flow-editor>`);
558
+
559
+ // Should not throw even without canvas
560
+ expect((editor as any).plumber).to.be.instanceOf(Plumber);
561
+ });
562
+ });
563
+ });
@@ -0,0 +1,142 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { stub, useFakeTimers, SinonFakeTimers } from 'sinon';
3
+ import { Plumber } from '../src/flow/Plumber';
4
+
5
+ describe('Plumber - Connection Management', () => {
6
+ let plumber: Plumber;
7
+ let mockCanvas: HTMLElement;
8
+ let clock: SinonFakeTimers;
9
+
10
+ beforeEach(() => {
11
+ // Use fake timers to control setTimeout
12
+ clock = useFakeTimers();
13
+
14
+ // Create mock canvas and make getElementById return a mock element
15
+ mockCanvas = document.createElement('div');
16
+ const mockElement = document.createElement('div');
17
+ stub(document, 'getElementById').returns(mockElement);
18
+
19
+ // Create a new plumber instance
20
+ plumber = new Plumber(mockCanvas);
21
+
22
+ // Replace the internal jsPlumb instance with mocks
23
+ (plumber as any).jsPlumb = {
24
+ getConnections: stub().returns([]),
25
+ addClass: stub(),
26
+ removeClass: stub(),
27
+ batch: stub().callsFake((fn: any) => fn()),
28
+ addEndpoint: stub().returns({}),
29
+ connect: stub(),
30
+ selectEndpoints: stub().returns({
31
+ deleteAll: stub()
32
+ }),
33
+ deleteConnection: stub(),
34
+ removeAllEndpoints: stub(),
35
+ repaintEverything: stub()
36
+ };
37
+ });
38
+
39
+ afterEach(() => {
40
+ // Restore the original document.getElementById
41
+ (document.getElementById as any).restore?.();
42
+ clock.restore();
43
+ });
44
+
45
+ describe('setConnectionRemovingState', () => {
46
+ it('returns false when no connections are found', () => {
47
+ const result = plumber.setConnectionRemovingState('test-exit', true);
48
+ expect(result).to.be.false;
49
+ expect((plumber as any).jsPlumb.getConnections).to.have.been.called;
50
+ });
51
+
52
+ it('sets removing class on connections when isRemoving is true', () => {
53
+ const mockConnections = [
54
+ { id: 'conn1', addClass: stub() },
55
+ { id: 'conn2', addClass: stub() }
56
+ ];
57
+
58
+ (plumber as any).jsPlumb.getConnections = stub().returns(mockConnections);
59
+
60
+ const result = plumber.setConnectionRemovingState('test-exit', true);
61
+ expect(result).to.be.true;
62
+ expect(mockConnections[0].addClass).to.have.been.calledWith('removing');
63
+ expect(mockConnections[1].addClass).to.have.been.calledWith('removing');
64
+ });
65
+
66
+ it('removes removing class from connections when isRemoving is false', () => {
67
+ const mockConnections = [
68
+ { id: 'conn1', removeClass: stub() },
69
+ { id: 'conn2', removeClass: stub() }
70
+ ];
71
+
72
+ (plumber as any).jsPlumb.getConnections = stub().returns(mockConnections);
73
+
74
+ const result = plumber.setConnectionRemovingState('test-exit', false);
75
+ expect(result).to.be.true;
76
+ expect(mockConnections[0].removeClass).to.have.been.calledWith(
77
+ 'removing'
78
+ );
79
+ expect(mockConnections[1].removeClass).to.have.been.calledWith(
80
+ 'removing'
81
+ );
82
+ });
83
+ });
84
+
85
+ describe('connectIds and processPendingConnections', () => {
86
+ it('adds connection to pending connections', () => {
87
+ // Call connectIds which should add to pending connections
88
+ plumber.connectIds('test-node', 'test-from', 'test-to');
89
+
90
+ // Verify pendingConnections has the new connection
91
+ expect((plumber as any).pendingConnections.length).to.equal(1);
92
+
93
+ // Advance timer to trigger the timeout
94
+ clock.tick(51); // Just past the 50ms timeout
95
+
96
+ // Now the batch should have been called
97
+ expect((plumber as any).jsPlumb.batch).to.have.been.called;
98
+ expect((plumber as any).jsPlumb.addEndpoint).to.have.been.called;
99
+ expect((plumber as any).jsPlumb.connect).to.have.been.called;
100
+ });
101
+
102
+ it('clears previous timeout when called multiple times', () => {
103
+ // Set up spies for window.setTimeout and window.clearTimeout instead of global
104
+ const clearTimeoutSpy = stub(window, 'clearTimeout');
105
+ const setTimeoutSpy = stub(window, 'setTimeout').returns(123 as any);
106
+
107
+ // Call twice
108
+ plumber.processPendingConnections();
109
+ plumber.processPendingConnections();
110
+
111
+ // Should have called clearTimeout once and setTimeout twice
112
+ expect(clearTimeoutSpy).to.have.been.calledOnce;
113
+ expect(setTimeoutSpy).to.have.been.calledTwice;
114
+
115
+ // Clean up
116
+ clearTimeoutSpy.restore();
117
+ setTimeoutSpy.restore();
118
+ });
119
+ });
120
+
121
+ describe('removeExitConnection', () => {
122
+ it('removes connections for an exit', () => {
123
+ const mockConnections = [{ id: 'conn1' }, { id: 'conn2' }];
124
+ (plumber as any).jsPlumb.getConnections = stub().returns(mockConnections);
125
+
126
+ const result = plumber.removeExitConnection('test-exit');
127
+
128
+ expect(result).to.be.true;
129
+ expect((plumber as any).jsPlumb.deleteConnection).to.have.been
130
+ .calledTwice;
131
+ expect((plumber as any).jsPlumb.removeAllEndpoints).to.have.been.called;
132
+ });
133
+
134
+ it('returns false when no connections exist', () => {
135
+ (plumber as any).jsPlumb.getConnections = stub().returns([]);
136
+
137
+ const result = plumber.removeExitConnection('test-exit');
138
+
139
+ expect(result).to.be.false;
140
+ });
141
+ });
142
+ });