@nyaruka/temba-components 0.129.1 → 0.129.3

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 (583) hide show
  1. package/.github/workflows/build.yml +6 -5
  2. package/.github/workflows/coverage.yml +80 -0
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +6 -0
  5. package/check-coverage.js +133 -0
  6. package/demo/components/alert/example.html +71 -0
  7. package/demo/components/button/example.html +167 -0
  8. package/demo/{chart → components/chart}/example.html +3 -3
  9. package/demo/components/chart/horizontal-demo.html +160 -0
  10. package/demo/components/checkbox/example.html +68 -0
  11. package/demo/components/compose/example.html +69 -0
  12. package/demo/components/datepicker/example.html +3 -3
  13. package/demo/components/datepicker/range-picker-demo.html +2 -2
  14. package/demo/{dialog → components/dialog}/example.html +3 -3
  15. package/demo/components/dropdown/example.html +95 -0
  16. package/demo/{flow → components/flow}/example.html +1 -1
  17. package/demo/{misc → components/misc}/example.html +3 -3
  18. package/demo/components/progress/example.html +62 -0
  19. package/demo/components/select/drag-and-drop.html +162 -0
  20. package/demo/components/select/example.html +76 -0
  21. package/demo/components/select/multi.html +72 -0
  22. package/demo/components/slider/example.html +55 -0
  23. package/demo/{sortable-list → components/sortable-list}/example.html +3 -3
  24. package/demo/components/tabs/example.html +91 -0
  25. package/demo/{textinput → components/textinput}/completion.html +3 -3
  26. package/demo/components/textinput/example.html +141 -0
  27. package/demo/{webchat → components/webchat}/example.html +3 -3
  28. package/demo/data/flows/sample-flow.json +107 -100
  29. package/demo/index.html +21 -21
  30. package/demo/static/css/styles.css +253 -0
  31. package/demo/sticky-note-demo.html +88 -85
  32. package/demo/styles.css +24 -0
  33. package/dist/locales/es.js +5 -5
  34. package/dist/locales/es.js.map +1 -1
  35. package/dist/locales/fr.js +5 -5
  36. package/dist/locales/fr.js.map +1 -1
  37. package/dist/locales/locale-codes.js +2 -11
  38. package/dist/locales/locale-codes.js.map +1 -1
  39. package/dist/locales/pt.js +5 -5
  40. package/dist/locales/pt.js.map +1 -1
  41. package/dist/temba-components.js +893 -476
  42. package/dist/temba-components.js.map +1 -1
  43. package/generate-coverage-badge.sh +69 -0
  44. package/out-tsc/src/{vectoricon/index.js → Icons.js} +1 -1
  45. package/out-tsc/src/Icons.js.map +1 -0
  46. package/out-tsc/src/display/Alert.js.map +1 -0
  47. package/out-tsc/src/display/Anchor.js.map +1 -0
  48. package/out-tsc/src/display/Button.js.map +1 -0
  49. package/out-tsc/src/{charcount → display}/CharCount.js +159 -2
  50. package/out-tsc/src/display/CharCount.js.map +1 -0
  51. package/out-tsc/src/display/Chat.js.map +1 -0
  52. package/out-tsc/src/display/ContactName.js.map +1 -0
  53. package/out-tsc/src/display/ContactUrn.js.map +1 -0
  54. package/out-tsc/src/display/Dropdown.js.map +1 -0
  55. package/out-tsc/src/{vectoricon/VectorIcon.js → display/Icon.js} +2 -2
  56. package/out-tsc/src/display/Icon.js.map +1 -0
  57. package/out-tsc/src/display/Label.js.map +1 -0
  58. package/out-tsc/src/{leafletmap → display}/LeafletMap.js +16 -1
  59. package/out-tsc/src/display/LeafletMap.js.map +1 -0
  60. package/out-tsc/src/display/Lightbox.js.map +1 -0
  61. package/out-tsc/src/{loading → display}/Loading.js.map +1 -1
  62. package/out-tsc/src/{options → display}/Options.js.map +1 -1
  63. package/out-tsc/src/display/ProgressBar.js.map +1 -0
  64. package/out-tsc/src/display/TembaDate.js.map +1 -0
  65. package/out-tsc/src/display/TembaUser.js.map +1 -0
  66. package/out-tsc/src/display/Thumbnail.js.map +1 -0
  67. package/out-tsc/src/{tip → display}/Tip.js +1 -2
  68. package/out-tsc/src/display/Tip.js.map +1 -0
  69. package/out-tsc/src/display/Toast.js.map +1 -0
  70. package/out-tsc/src/display/sms/gsmsplitter.js.map +1 -0
  71. package/out-tsc/src/display/sms/gsmvalidator.js.map +1 -0
  72. package/out-tsc/src/display/sms/index.js.map +1 -0
  73. package/out-tsc/src/display/sms/unicodesplitter.js.map +1 -0
  74. package/out-tsc/src/events.js +2 -0
  75. package/out-tsc/src/events.js.map +1 -0
  76. package/out-tsc/src/excellent/ExcellentParser.js.map +1 -0
  77. package/out-tsc/src/excellent/helpers.js.map +1 -0
  78. package/out-tsc/src/flow/Editor.js +533 -140
  79. package/out-tsc/src/flow/Editor.js.map +1 -1
  80. package/out-tsc/src/flow/EditorNode.js +287 -20
  81. package/out-tsc/src/flow/EditorNode.js.map +1 -1
  82. package/out-tsc/src/flow/Plumber.js +154 -74
  83. package/out-tsc/src/flow/Plumber.js.map +1 -1
  84. package/out-tsc/src/flow/StickyNote.js +153 -9
  85. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  86. package/out-tsc/src/flow/config.js +88 -18
  87. package/out-tsc/src/flow/config.js.map +1 -1
  88. package/out-tsc/src/flow/render.js +327 -10
  89. package/out-tsc/src/flow/render.js.map +1 -1
  90. package/out-tsc/src/{checkbox → form}/Checkbox.js +2 -2
  91. package/out-tsc/src/form/Checkbox.js.map +1 -0
  92. package/out-tsc/src/{colorpicker → form}/ColorPicker.js +1 -1
  93. package/out-tsc/src/form/ColorPicker.js.map +1 -0
  94. package/out-tsc/src/{completion → form}/Completion.js +2 -2
  95. package/out-tsc/src/form/Completion.js.map +1 -0
  96. package/out-tsc/src/{compose → form}/Compose.js +1 -1
  97. package/out-tsc/src/form/Compose.js.map +1 -0
  98. package/out-tsc/src/{contactsearch → form}/ContactSearch.js +2 -2
  99. package/out-tsc/src/form/ContactSearch.js.map +1 -0
  100. package/out-tsc/src/form/CroppieCSS.js.map +1 -0
  101. package/out-tsc/src/{datepicker → form}/DatePicker.js +1 -1
  102. package/out-tsc/src/form/DatePicker.js.map +1 -0
  103. package/out-tsc/src/{FormElement.js → form/FormElement.js} +1 -1
  104. package/out-tsc/src/form/FormElement.js.map +1 -0
  105. package/out-tsc/src/form/FormField.js.map +1 -0
  106. package/out-tsc/src/{imagepicker → form}/ImagePicker.js +2 -2
  107. package/out-tsc/src/form/ImagePicker.js.map +1 -0
  108. package/out-tsc/src/{mediapicker → form}/MediaPicker.js +1 -1
  109. package/out-tsc/src/form/MediaPicker.js.map +1 -0
  110. package/out-tsc/src/{datepicker → form}/RangePicker.js +3 -2
  111. package/out-tsc/src/form/RangePicker.js.map +1 -0
  112. package/out-tsc/src/{slider → form}/TembaSlider.js +1 -1
  113. package/out-tsc/src/form/TembaSlider.js.map +1 -0
  114. package/out-tsc/src/{templates → form}/TemplateEditor.js +1 -1
  115. package/out-tsc/src/form/TemplateEditor.js.map +1 -0
  116. package/out-tsc/src/{textinput → form}/TextInput.js +3 -3
  117. package/out-tsc/src/form/TextInput.js.map +1 -0
  118. package/out-tsc/src/{omnibox → form/select}/Omnibox.js +2 -2
  119. package/out-tsc/src/form/select/Omnibox.js.map +1 -0
  120. package/out-tsc/src/{select → form/select}/PopupSelect.js +1 -1
  121. package/out-tsc/src/form/select/PopupSelect.js.map +1 -0
  122. package/out-tsc/src/{select → form/select}/Select.js +86 -87
  123. package/out-tsc/src/form/select/Select.js.map +1 -0
  124. package/out-tsc/src/{select → form/select}/UserSelect.js +1 -1
  125. package/out-tsc/src/form/select/UserSelect.js.map +1 -0
  126. package/out-tsc/src/{select → form/select}/WorkspaceSelect.js +1 -1
  127. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -0
  128. package/out-tsc/src/interfaces.js +1 -0
  129. package/out-tsc/src/interfaces.js.map +1 -1
  130. package/out-tsc/src/layout/Dialog.js.map +1 -0
  131. package/out-tsc/src/layout/Mask.js.map +1 -0
  132. package/out-tsc/src/{dialog → layout}/Modax.js.map +1 -1
  133. package/out-tsc/src/layout/Resizer.js.map +1 -0
  134. package/out-tsc/src/layout/Tab.js.map +1 -0
  135. package/out-tsc/src/layout/TabPane.js.map +1 -0
  136. package/out-tsc/src/list/NotificationList.js +1 -1
  137. package/out-tsc/src/list/NotificationList.js.map +1 -1
  138. package/out-tsc/src/list/RunList.js +1 -1
  139. package/out-tsc/src/list/RunList.js.map +1 -1
  140. package/out-tsc/src/list/ShortcutList.js.map +1 -1
  141. package/out-tsc/src/list/TembaMenu.js +1 -1
  142. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  143. package/out-tsc/src/list/TicketList.js +1 -1
  144. package/out-tsc/src/list/TicketList.js.map +1 -1
  145. package/out-tsc/src/{aliaseditor → live}/AliasEditor.js +1 -1
  146. package/out-tsc/src/live/AliasEditor.js.map +1 -0
  147. package/out-tsc/src/{contacts → live}/ContactBadges.js +1 -1
  148. package/out-tsc/src/live/ContactBadges.js.map +1 -0
  149. package/out-tsc/src/{contacts → live}/ContactChat.js +79 -3
  150. package/out-tsc/src/live/ContactChat.js.map +1 -0
  151. package/out-tsc/src/{contacts → live}/ContactDetails.js +1 -1
  152. package/out-tsc/src/live/ContactDetails.js.map +1 -0
  153. package/out-tsc/src/{contacts → live}/ContactFieldEditor.js +2 -2
  154. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -0
  155. package/out-tsc/src/live/ContactFields.js.map +1 -0
  156. package/out-tsc/src/live/ContactNameFetch.js.map +1 -0
  157. package/out-tsc/src/{contacts → live}/ContactNotepad.js +1 -1
  158. package/out-tsc/src/{contacts → live}/ContactNotepad.js.map +1 -1
  159. package/out-tsc/src/{contacts → live}/ContactPending.js +1 -1
  160. package/out-tsc/src/live/ContactPending.js.map +1 -0
  161. package/out-tsc/src/live/ContactStoreElement.js.map +1 -0
  162. package/out-tsc/src/live/FieldManager.js.map +1 -0
  163. package/out-tsc/src/live/StartProgress.js.map +1 -0
  164. package/out-tsc/src/{chart → live}/TembaChart.js +5 -1
  165. package/out-tsc/src/live/TembaChart.js.map +1 -0
  166. package/out-tsc/src/locales/es.js +5 -5
  167. package/out-tsc/src/locales/es.js.map +1 -1
  168. package/out-tsc/src/locales/fr.js +5 -5
  169. package/out-tsc/src/locales/fr.js.map +1 -1
  170. package/out-tsc/src/locales/locale-codes.js +2 -11
  171. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  172. package/out-tsc/src/locales/pt.js +5 -5
  173. package/out-tsc/src/locales/pt.js.map +1 -1
  174. package/out-tsc/src/store/AppState.js +54 -24
  175. package/out-tsc/src/store/AppState.js.map +1 -1
  176. package/out-tsc/src/store/Store.js +1 -1
  177. package/out-tsc/src/store/Store.js.map +1 -1
  178. package/out-tsc/src/{utils/index.js → utils.js} +22 -1
  179. package/out-tsc/src/utils.js.map +1 -0
  180. package/out-tsc/src/webchat/WebChat.js +1 -1
  181. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  182. package/out-tsc/temba-components.js +2 -2
  183. package/out-tsc/temba-components.js.map +1 -1
  184. package/out-tsc/temba-modules.js +54 -54
  185. package/out-tsc/temba-modules.js.map +1 -1
  186. package/out-tsc/temba-webchat.js +2 -2
  187. package/out-tsc/temba-webchat.js.map +1 -1
  188. package/out-tsc/test/temba-alert.test.js +1 -1
  189. package/out-tsc/test/temba-alert.test.js.map +1 -1
  190. package/out-tsc/test/temba-appstate-language.test.js +90 -0
  191. package/out-tsc/test/temba-appstate-language.test.js.map +1 -1
  192. package/out-tsc/test/temba-charcount.test.js.map +1 -1
  193. package/out-tsc/test/temba-chart.test.js +1 -1
  194. package/out-tsc/test/temba-chart.test.js.map +1 -1
  195. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  196. package/out-tsc/test/temba-color-picker.test.js +1 -1
  197. package/out-tsc/test/temba-color-picker.test.js.map +1 -1
  198. package/out-tsc/test/temba-completion.test.js +1 -1
  199. package/out-tsc/test/temba-completion.test.js.map +1 -1
  200. package/out-tsc/test/temba-compose.test.js +1 -1
  201. package/out-tsc/test/temba-compose.test.js.map +1 -1
  202. package/out-tsc/test/temba-contact-badges.test.js +1 -1
  203. package/out-tsc/test/temba-contact-badges.test.js.map +1 -1
  204. package/out-tsc/test/temba-contact-chat.test.js +3 -1
  205. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  206. package/out-tsc/test/temba-contact-details.test.js +1 -1
  207. package/out-tsc/test/temba-contact-details.test.js.map +1 -1
  208. package/out-tsc/test/temba-contact-fields.test.js +1 -1
  209. package/out-tsc/test/temba-contact-fields.test.js.map +1 -1
  210. package/out-tsc/test/temba-contact-search.test.js +1 -1
  211. package/out-tsc/test/temba-contact-search.test.js.map +1 -1
  212. package/out-tsc/test/temba-date.test.js +5 -1
  213. package/out-tsc/test/temba-date.test.js.map +1 -1
  214. package/out-tsc/test/temba-datepicker.test.js +1 -1
  215. package/out-tsc/test/temba-datepicker.test.js.map +1 -1
  216. package/out-tsc/test/temba-dialog.test.js +1 -1
  217. package/out-tsc/test/temba-dialog.test.js.map +1 -1
  218. package/out-tsc/test/temba-dropdown.test.js +1 -1
  219. package/out-tsc/test/temba-dropdown.test.js.map +1 -1
  220. package/out-tsc/test/temba-excellent-helpers.test.js +316 -0
  221. package/out-tsc/test/temba-excellent-helpers.test.js.map +1 -0
  222. package/out-tsc/test/temba-field-manager.test.js.map +1 -1
  223. package/out-tsc/test/temba-flow-editor-node.test.js +414 -1
  224. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  225. package/out-tsc/test/temba-flow-editor.test.js +185 -0
  226. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  227. package/out-tsc/test/temba-flow-plumber-connections.test.js +113 -0
  228. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -0
  229. package/out-tsc/test/temba-flow-plumber.test.js +73 -93
  230. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  231. package/out-tsc/test/temba-flow-render.test.js +624 -1
  232. package/out-tsc/test/temba-flow-render.test.js.map +1 -1
  233. package/out-tsc/test/temba-flow-self-routing.test.js +172 -0
  234. package/out-tsc/test/temba-flow-self-routing.test.js.map +1 -0
  235. package/out-tsc/test/temba-formfield.test.js.map +1 -1
  236. package/out-tsc/test/temba-icon.test.js +1 -1
  237. package/out-tsc/test/temba-icon.test.js.map +1 -1
  238. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  239. package/out-tsc/test/temba-label.test.js +1 -1
  240. package/out-tsc/test/temba-label.test.js.map +1 -1
  241. package/out-tsc/test/temba-lightbox.test.js +1 -1
  242. package/out-tsc/test/temba-lightbox.test.js.map +1 -1
  243. package/out-tsc/test/temba-markdown.test.js +127 -0
  244. package/out-tsc/test/temba-markdown.test.js.map +1 -0
  245. package/out-tsc/test/temba-menu.test.js +1 -1
  246. package/out-tsc/test/temba-menu.test.js.map +1 -1
  247. package/out-tsc/test/temba-modax.test.js +1 -1
  248. package/out-tsc/test/temba-modax.test.js.map +1 -1
  249. package/out-tsc/test/temba-modules.test.js +47 -0
  250. package/out-tsc/test/temba-modules.test.js.map +1 -0
  251. package/out-tsc/test/temba-omnibox.test.js +1 -1
  252. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  253. package/out-tsc/test/temba-options.test.js.map +1 -1
  254. package/out-tsc/test/temba-range-picker.test.js +9 -2
  255. package/out-tsc/test/temba-range-picker.test.js.map +1 -1
  256. package/out-tsc/test/temba-rapid-element.test.js +273 -0
  257. package/out-tsc/test/temba-rapid-element.test.js.map +1 -0
  258. package/out-tsc/test/temba-resize-element.test.js +85 -0
  259. package/out-tsc/test/temba-resize-element.test.js.map +1 -0
  260. package/out-tsc/test/temba-select.test.js +2 -2
  261. package/out-tsc/test/temba-select.test.js.map +1 -1
  262. package/out-tsc/test/temba-slider.test.js.map +1 -1
  263. package/out-tsc/test/temba-sticky-note.test.js +194 -0
  264. package/out-tsc/test/temba-sticky-note.test.js.map +1 -0
  265. package/out-tsc/test/temba-template-editor.test.js.map +1 -1
  266. package/out-tsc/test/temba-textinput.test.js +1 -1
  267. package/out-tsc/test/temba-textinput.test.js.map +1 -1
  268. package/out-tsc/test/temba-tip.test.js +1 -1
  269. package/out-tsc/test/temba-tip.test.js.map +1 -1
  270. package/out-tsc/test/temba-toast.test.js +1 -1
  271. package/out-tsc/test/temba-toast.test.js.map +1 -1
  272. package/out-tsc/test/temba-utils-index.test.js +1 -1
  273. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  274. package/out-tsc/test/temba-utils-uuid.test.js +38 -0
  275. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -0
  276. package/out-tsc/test/temba-webchat.test.js +28 -12
  277. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  278. package/out-tsc/test/utils.test.js +2 -6
  279. package/out-tsc/test/utils.test.js.map +1 -1
  280. package/package.json +18 -9
  281. package/rollup.components.mjs +1 -1
  282. package/screenshots/truth/datepicker/range-picker-all.png +0 -0
  283. package/screenshots/truth/datepicker/range-picker-button-states.png +0 -0
  284. package/screenshots/truth/datepicker/range-picker-default.png +0 -0
  285. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  286. package/screenshots/truth/datepicker/range-picker-initial-values.png +0 -0
  287. package/screenshots/truth/datepicker/range-picker-week.png +0 -0
  288. package/screenshots/truth/datepicker/range-picker-year.png +0 -0
  289. package/screenshots/truth/sticky-note/blue-color.png +0 -0
  290. package/screenshots/truth/sticky-note/blue.png +0 -0
  291. package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
  292. package/screenshots/truth/sticky-note/default.png +0 -0
  293. package/screenshots/truth/sticky-note/gray-color.png +0 -0
  294. package/screenshots/truth/sticky-note/gray.png +0 -0
  295. package/screenshots/truth/sticky-note/green-color.png +0 -0
  296. package/screenshots/truth/sticky-note/green.png +0 -0
  297. package/screenshots/truth/sticky-note/pink-color.png +0 -0
  298. package/screenshots/truth/sticky-note/pink.png +0 -0
  299. package/screenshots/truth/sticky-note/yellow-color.png +0 -0
  300. package/screenshots/truth/sticky-note/yellow.png +0 -0
  301. package/src/{charcount → display}/CharCount.ts +164 -2
  302. package/src/{vectoricon/VectorIcon.ts → display/Icon.ts} +1 -1
  303. package/src/{leafletmap → display}/LeafletMap.ts +19 -1
  304. package/src/{thumbnail → display}/Thumbnail.ts +1 -1
  305. package/src/{tip → display}/Tip.ts +1 -2
  306. package/src/{contacts/events.ts → events.ts} +1 -64
  307. package/src/flow/Editor.ts +655 -165
  308. package/src/flow/EditorNode.ts +337 -22
  309. package/src/flow/Plumber.ts +186 -79
  310. package/src/flow/StickyNote.ts +165 -9
  311. package/src/flow/config.ts +114 -18
  312. package/src/flow/render.ts +398 -11
  313. package/src/{checkbox → form}/Checkbox.ts +2 -2
  314. package/src/{colorpicker → form}/ColorPicker.ts +2 -2
  315. package/src/{completion → form}/Completion.ts +3 -3
  316. package/src/{compose → form}/Compose.ts +7 -7
  317. package/src/{contactsearch → form}/ContactSearch.ts +6 -6
  318. package/src/{datepicker → form}/DatePicker.ts +1 -1
  319. package/src/{FormElement.ts → form/FormElement.ts} +1 -1
  320. package/src/{imagepicker → form}/ImagePicker.ts +2 -2
  321. package/src/{mediapicker → form}/MediaPicker.ts +1 -1
  322. package/src/{datepicker → form}/RangePicker.ts +3 -2
  323. package/src/{slider → form}/TembaSlider.ts +1 -1
  324. package/src/{templates → form}/TemplateEditor.ts +2 -2
  325. package/src/{textinput → form}/TextInput.ts +5 -5
  326. package/src/{omnibox → form/select}/Omnibox.ts +2 -2
  327. package/src/{select → form/select}/PopupSelect.ts +1 -1
  328. package/src/{select → form/select}/Select.ts +124 -126
  329. package/src/{select → form/select}/UserSelect.ts +1 -1
  330. package/src/{select → form/select}/WorkspaceSelect.ts +1 -1
  331. package/src/interfaces.ts +2 -1
  332. package/src/{dialog → layout}/Dialog.ts +1 -1
  333. package/src/list/NotificationList.ts +2 -2
  334. package/src/list/RunList.ts +3 -3
  335. package/src/list/ShortcutList.ts +1 -1
  336. package/src/list/TembaMenu.ts +2 -2
  337. package/src/list/TicketList.ts +1 -1
  338. package/src/{aliaseditor → live}/AliasEditor.ts +3 -3
  339. package/src/{contacts → live}/ContactBadges.ts +1 -1
  340. package/src/{contacts → live}/ContactChat.ts +118 -8
  341. package/src/{contacts → live}/ContactDetails.ts +1 -1
  342. package/src/{contacts → live}/ContactFieldEditor.ts +4 -4
  343. package/src/{contacts → live}/ContactFields.ts +1 -1
  344. package/src/{contacts → live}/ContactNotepad.ts +1 -1
  345. package/src/{contacts → live}/ContactPending.ts +1 -1
  346. package/src/{chart → live}/TembaChart.ts +5 -2
  347. package/src/locales/es.ts +13 -18
  348. package/src/locales/fr.ts +13 -18
  349. package/src/locales/locale-codes.ts +2 -11
  350. package/src/locales/pt.ts +13 -18
  351. package/src/store/AppState.ts +75 -29
  352. package/src/store/Store.ts +1 -1
  353. package/src/store/flow-definition.d.ts +125 -0
  354. package/src/{utils/index.ts → utils.ts} +26 -10
  355. package/src/webchat/WebChat.ts +1 -1
  356. package/static/css/temba-components.css +1 -0
  357. package/svg.js +1 -4
  358. package/temba-components.ts +2 -2
  359. package/temba-modules.ts +54 -54
  360. package/temba-webchat.ts +2 -2
  361. package/test/temba-alert.test.ts +1 -1
  362. package/test/temba-appstate-language.test.ts +108 -0
  363. package/test/temba-charcount.test.ts +1 -1
  364. package/test/temba-chart.test.ts +1 -1
  365. package/test/temba-checkbox.test.ts +1 -1
  366. package/test/temba-color-picker.test.ts +1 -1
  367. package/test/temba-completion.test.ts +1 -1
  368. package/test/temba-compose.test.ts +1 -1
  369. package/test/temba-contact-badges.test.ts +1 -1
  370. package/test/temba-contact-chat.test.ts +6 -4
  371. package/test/temba-contact-details.test.ts +1 -1
  372. package/test/temba-contact-fields.test.ts +1 -1
  373. package/test/temba-contact-search.test.ts +2 -2
  374. package/test/temba-date.test.ts +8 -3
  375. package/test/temba-datepicker.test.ts +1 -1
  376. package/test/temba-dialog.test.ts +1 -1
  377. package/test/temba-dropdown.test.ts +1 -1
  378. package/test/temba-excellent-helpers.test.ts +417 -0
  379. package/test/temba-field-manager.test.ts +2 -2
  380. package/test/temba-flow-editor-node.test.ts +536 -1
  381. package/test/temba-flow-editor.test.ts +224 -0
  382. package/test/temba-flow-editor.test.ts.backup +563 -0
  383. package/test/temba-flow-plumber-connections.test.ts +142 -0
  384. package/test/temba-flow-plumber.test.ts +83 -120
  385. package/test/temba-flow-render.test.ts +787 -4
  386. package/test/temba-flow-self-routing.test.ts +215 -0
  387. package/test/temba-formfield.test.ts +1 -1
  388. package/test/temba-icon.test.ts +1 -1
  389. package/test/temba-integration-markdown.test.ts +1 -1
  390. package/test/temba-label.test.ts +1 -1
  391. package/test/temba-lightbox.test.ts +1 -1
  392. package/test/temba-markdown.test.ts +162 -0
  393. package/test/temba-menu.test.ts +1 -1
  394. package/test/temba-modax.test.ts +2 -2
  395. package/test/temba-modules.test.ts +56 -0
  396. package/test/temba-omnibox.test.ts +1 -1
  397. package/test/temba-options.test.ts +1 -1
  398. package/test/temba-range-picker.test.ts +17 -2
  399. package/test/temba-rapid-element.test.ts +341 -0
  400. package/test/temba-resize-element.test.ts +104 -0
  401. package/test/temba-select.test.ts +2 -2
  402. package/test/temba-slider.test.ts +1 -1
  403. package/test/temba-sticky-note.test.ts +281 -0
  404. package/test/temba-template-editor.test.ts +1 -1
  405. package/test/temba-textinput.test.ts +1 -1
  406. package/test/temba-tip.test.ts +1 -1
  407. package/test/temba-toast.test.ts +1 -1
  408. package/test/temba-utils-index.test.ts +1 -1
  409. package/test/temba-utils-index.test.ts.backup +1737 -0
  410. package/test/temba-utils-uuid.test.ts +48 -0
  411. package/test/temba-webchat.test.ts +30 -12
  412. package/test/utils.test.ts +5 -9
  413. package/web-dev-server.config.mjs +1 -1
  414. package/demo/alert/example.html +0 -65
  415. package/demo/button/example.html +0 -71
  416. package/demo/chart/horizontal-demo.html +0 -81
  417. package/demo/checkbox/example.html +0 -72
  418. package/demo/compose/example.html +0 -72
  419. package/demo/dropdown/example.html +0 -99
  420. package/demo/progress/example.html +0 -59
  421. package/demo/select/drag-and-drop.html +0 -142
  422. package/demo/select/example.html +0 -82
  423. package/demo/select/multi.html +0 -73
  424. package/demo/slider/example.html +0 -59
  425. package/demo/tabs/example.html +0 -91
  426. package/demo/textinput/example.html +0 -61
  427. package/out-tsc/src/FormElement.js.map +0 -1
  428. package/out-tsc/src/alert/Alert.js.map +0 -1
  429. package/out-tsc/src/aliaseditor/AliasEditor.js.map +0 -1
  430. package/out-tsc/src/anchor/Anchor.js.map +0 -1
  431. package/out-tsc/src/button/Button.js.map +0 -1
  432. package/out-tsc/src/charcount/CharCount.js.map +0 -1
  433. package/out-tsc/src/charcount/helpers.js +0 -159
  434. package/out-tsc/src/charcount/helpers.js.map +0 -1
  435. package/out-tsc/src/chart/TembaChart.js.map +0 -1
  436. package/out-tsc/src/chat/Chat.js.map +0 -1
  437. package/out-tsc/src/checkbox/Checkbox.js.map +0 -1
  438. package/out-tsc/src/colorpicker/ColorPicker.js.map +0 -1
  439. package/out-tsc/src/completion/Completion.js.map +0 -1
  440. package/out-tsc/src/completion/ExcellentParser.js.map +0 -1
  441. package/out-tsc/src/completion/helpers.js.map +0 -1
  442. package/out-tsc/src/compose/Compose.js.map +0 -1
  443. package/out-tsc/src/contacts/ContactBadges.js.map +0 -1
  444. package/out-tsc/src/contacts/ContactChat.js.map +0 -1
  445. package/out-tsc/src/contacts/ContactDetails.js.map +0 -1
  446. package/out-tsc/src/contacts/ContactFieldEditor.js.map +0 -1
  447. package/out-tsc/src/contacts/ContactFields.js.map +0 -1
  448. package/out-tsc/src/contacts/ContactName.js.map +0 -1
  449. package/out-tsc/src/contacts/ContactNameFetch.js.map +0 -1
  450. package/out-tsc/src/contacts/ContactPending.js.map +0 -1
  451. package/out-tsc/src/contacts/ContactStoreElement.js.map +0 -1
  452. package/out-tsc/src/contacts/ContactUrn.js.map +0 -1
  453. package/out-tsc/src/contacts/events.js +0 -65
  454. package/out-tsc/src/contacts/events.js.map +0 -1
  455. package/out-tsc/src/contacts/helpers.js +0 -77
  456. package/out-tsc/src/contacts/helpers.js.map +0 -1
  457. package/out-tsc/src/contactsearch/ContactSearch.js.map +0 -1
  458. package/out-tsc/src/date/TembaDate.js.map +0 -1
  459. package/out-tsc/src/datepicker/DatePicker.js.map +0 -1
  460. package/out-tsc/src/datepicker/RangePicker.js.map +0 -1
  461. package/out-tsc/src/dialog/Dialog.js.map +0 -1
  462. package/out-tsc/src/dropdown/Dropdown.js.map +0 -1
  463. package/out-tsc/src/fields/FieldManager.js.map +0 -1
  464. package/out-tsc/src/formfield/FormField.js.map +0 -1
  465. package/out-tsc/src/imagepicker/CroppieCSS.js.map +0 -1
  466. package/out-tsc/src/imagepicker/ImagePicker.js.map +0 -1
  467. package/out-tsc/src/label/Label.js.map +0 -1
  468. package/out-tsc/src/leafletmap/LeafletMap.js.map +0 -1
  469. package/out-tsc/src/leafletmap/helpers.js +0 -17
  470. package/out-tsc/src/leafletmap/helpers.js.map +0 -1
  471. package/out-tsc/src/lightbox/Lightbox.js.map +0 -1
  472. package/out-tsc/src/mask/Mask.js.map +0 -1
  473. package/out-tsc/src/mediapicker/MediaPicker.js.map +0 -1
  474. package/out-tsc/src/omnibox/Omnibox.js.map +0 -1
  475. package/out-tsc/src/options/helpers.js +0 -28
  476. package/out-tsc/src/options/helpers.js.map +0 -1
  477. package/out-tsc/src/progress/ProgressBar.js.map +0 -1
  478. package/out-tsc/src/progress/StartProgress.js.map +0 -1
  479. package/out-tsc/src/resizer/Resizer.js.map +0 -1
  480. package/out-tsc/src/select/PopupSelect.js.map +0 -1
  481. package/out-tsc/src/select/Select.js.map +0 -1
  482. package/out-tsc/src/select/UserSelect.js.map +0 -1
  483. package/out-tsc/src/select/WorkspaceSelect.js.map +0 -1
  484. package/out-tsc/src/select/helpers.js +0 -1
  485. package/out-tsc/src/select/helpers.js.map +0 -1
  486. package/out-tsc/src/shadowless/Shadowless.js +0 -33
  487. package/out-tsc/src/shadowless/Shadowless.js.map +0 -1
  488. package/out-tsc/src/slider/TembaSlider.js.map +0 -1
  489. package/out-tsc/src/sms/gsmsplitter.js.map +0 -1
  490. package/out-tsc/src/sms/gsmvalidator.js.map +0 -1
  491. package/out-tsc/src/sms/index.js.map +0 -1
  492. package/out-tsc/src/sms/unicodesplitter.js.map +0 -1
  493. package/out-tsc/src/tabpane/Tab.js.map +0 -1
  494. package/out-tsc/src/tabpane/TabPane.js.map +0 -1
  495. package/out-tsc/src/templates/TemplateEditor.js.map +0 -1
  496. package/out-tsc/src/textinput/TextInput.js.map +0 -1
  497. package/out-tsc/src/textinput/helpers.js +0 -12
  498. package/out-tsc/src/textinput/helpers.js.map +0 -1
  499. package/out-tsc/src/thumbnail/Thumbnail.js.map +0 -1
  500. package/out-tsc/src/tip/Tip.js.map +0 -1
  501. package/out-tsc/src/tip/helpers.js +0 -7
  502. package/out-tsc/src/tip/helpers.js.map +0 -1
  503. package/out-tsc/src/toast/Toast.js.map +0 -1
  504. package/out-tsc/src/user/TembaUser.js.map +0 -1
  505. package/out-tsc/src/utils/index.js.map +0 -1
  506. package/out-tsc/src/vectoricon/VectorIcon.js.map +0 -1
  507. package/out-tsc/src/vectoricon/index.js.map +0 -1
  508. package/src/charcount/helpers.ts +0 -162
  509. package/src/contacts/helpers.ts +0 -103
  510. package/src/leafletmap/helpers.ts +0 -18
  511. package/src/options/helpers.ts +0 -37
  512. package/src/select/helpers.ts +0 -0
  513. package/src/shadowless/Shadowless.ts +0 -32
  514. package/src/textinput/helpers.ts +0 -11
  515. package/src/tip/helpers.ts +0 -7
  516. /package/out-tsc/src/{alert → display}/Alert.js +0 -0
  517. /package/out-tsc/src/{anchor → display}/Anchor.js +0 -0
  518. /package/out-tsc/src/{button → display}/Button.js +0 -0
  519. /package/out-tsc/src/{chat → display}/Chat.js +0 -0
  520. /package/out-tsc/src/{contacts → display}/ContactName.js +0 -0
  521. /package/out-tsc/src/{contacts → display}/ContactUrn.js +0 -0
  522. /package/out-tsc/src/{dropdown → display}/Dropdown.js +0 -0
  523. /package/out-tsc/src/{label → display}/Label.js +0 -0
  524. /package/out-tsc/src/{lightbox → display}/Lightbox.js +0 -0
  525. /package/out-tsc/src/{loading → display}/Loading.js +0 -0
  526. /package/out-tsc/src/{options → display}/Options.js +0 -0
  527. /package/out-tsc/src/{progress → display}/ProgressBar.js +0 -0
  528. /package/out-tsc/src/{date → display}/TembaDate.js +0 -0
  529. /package/out-tsc/src/{user → display}/TembaUser.js +0 -0
  530. /package/out-tsc/src/{thumbnail → display}/Thumbnail.js +0 -0
  531. /package/out-tsc/src/{toast → display}/Toast.js +0 -0
  532. /package/out-tsc/src/{sms → display/sms}/gsmsplitter.js +0 -0
  533. /package/out-tsc/src/{sms → display/sms}/gsmvalidator.js +0 -0
  534. /package/out-tsc/src/{sms → display/sms}/index.js +0 -0
  535. /package/out-tsc/src/{sms → display/sms}/unicodesplitter.js +0 -0
  536. /package/out-tsc/src/{completion → excellent}/ExcellentParser.js +0 -0
  537. /package/out-tsc/src/{completion → excellent}/helpers.js +0 -0
  538. /package/out-tsc/src/{imagepicker → form}/CroppieCSS.js +0 -0
  539. /package/out-tsc/src/{formfield → form}/FormField.js +0 -0
  540. /package/out-tsc/src/{dialog → layout}/Dialog.js +0 -0
  541. /package/out-tsc/src/{mask → layout}/Mask.js +0 -0
  542. /package/out-tsc/src/{dialog → layout}/Modax.js +0 -0
  543. /package/out-tsc/src/{resizer → layout}/Resizer.js +0 -0
  544. /package/out-tsc/src/{tabpane → layout}/Tab.js +0 -0
  545. /package/out-tsc/src/{tabpane → layout}/TabPane.js +0 -0
  546. /package/out-tsc/src/{contacts → live}/ContactFields.js +0 -0
  547. /package/out-tsc/src/{contacts → live}/ContactNameFetch.js +0 -0
  548. /package/out-tsc/src/{contacts → live}/ContactStoreElement.js +0 -0
  549. /package/out-tsc/src/{fields → live}/FieldManager.js +0 -0
  550. /package/out-tsc/src/{progress → live}/StartProgress.js +0 -0
  551. /package/src/{vectoricon/index.ts → Icons.ts} +0 -0
  552. /package/src/{alert → display}/Alert.ts +0 -0
  553. /package/src/{anchor → display}/Anchor.ts +0 -0
  554. /package/src/{button → display}/Button.ts +0 -0
  555. /package/src/{chat → display}/Chat.ts +0 -0
  556. /package/src/{contacts → display}/ContactName.ts +0 -0
  557. /package/src/{contacts → display}/ContactUrn.ts +0 -0
  558. /package/src/{dropdown → display}/Dropdown.ts +0 -0
  559. /package/src/{label → display}/Label.ts +0 -0
  560. /package/src/{lightbox → display}/Lightbox.ts +0 -0
  561. /package/src/{loading → display}/Loading.ts +0 -0
  562. /package/src/{options → display}/Options.ts +0 -0
  563. /package/src/{progress → display}/ProgressBar.ts +0 -0
  564. /package/src/{date → display}/TembaDate.ts +0 -0
  565. /package/src/{user → display}/TembaUser.ts +0 -0
  566. /package/src/{toast → display}/Toast.ts +0 -0
  567. /package/src/{sms → display/sms}/gsmsplitter.ts +0 -0
  568. /package/src/{sms → display/sms}/gsmvalidator.ts +0 -0
  569. /package/src/{sms → display/sms}/index.ts +0 -0
  570. /package/src/{sms → display/sms}/unicodesplitter.ts +0 -0
  571. /package/src/{completion → excellent}/ExcellentParser.ts +0 -0
  572. /package/src/{completion → excellent}/helpers.ts +0 -0
  573. /package/src/{imagepicker → form}/CroppieCSS.ts +0 -0
  574. /package/src/{formfield → form}/FormField.ts +0 -0
  575. /package/src/{mask → layout}/Mask.ts +0 -0
  576. /package/src/{dialog → layout}/Modax.ts +0 -0
  577. /package/src/{resizer → layout}/Resizer.ts +0 -0
  578. /package/src/{tabpane → layout}/Tab.ts +0 -0
  579. /package/src/{tabpane → layout}/TabPane.ts +0 -0
  580. /package/src/{contacts → live}/ContactNameFetch.ts +0 -0
  581. /package/src/{contacts → live}/ContactStoreElement.ts +0 -0
  582. /package/src/{fields → live}/FieldManager.ts +0 -0
  583. /package/src/{progress → live}/StartProgress.ts +0 -0
@@ -5,13 +5,24 @@ import { property, state } from 'lit/decorators.js';
5
5
  import { getStore } from '../store/Store';
6
6
  import { fromStore, zustand } from '../store/AppState';
7
7
  import { RapidElement } from '../RapidElement';
8
+ import { repeat } from 'lit-html/directives/repeat.js';
8
9
  import { Plumber } from './Plumber';
9
10
  import { EditorNode } from './EditorNode';
10
11
  export function snapToGrid(value) {
11
- return Math.round(value / 20) * 20;
12
+ const snapped = Math.round(value / 20) * 20;
13
+ return Math.max(snapped, 0);
14
+ }
15
+ export function findNodeForExit(definition, exitUuid) {
16
+ for (const node of definition.nodes) {
17
+ const exit = node.exits.find((e) => e.uuid === exitUuid);
18
+ if (exit) {
19
+ return node.uuid;
20
+ }
21
+ }
22
+ return null;
12
23
  }
13
24
  const SAVE_QUIET_TIME = 500;
14
- const DRAG_THRESHOLD = 10;
25
+ const DRAG_THRESHOLD = 5;
15
26
  export class Editor extends RapidElement {
16
27
  // unfortunately, jsplumb requires that we be in light DOM
17
28
  createRenderRoot() {
@@ -27,41 +38,23 @@ export class Editor extends RapidElement {
27
38
  #grid {
28
39
  position: relative;
29
40
  background-color: #f9f9f9;
41
+ background-image: radial-gradient(
42
+ circle,
43
+ rgba(61, 177, 255, 0.3) 1px,
44
+ transparent 1px
45
+ );
46
+ background-size: 20px 20px;
30
47
  background-position: 10px 10px;
31
- background-image: linear-gradient(
32
- 0deg,
33
- transparent 24%,
34
- rgba(61, 177, 255, 0.15) 25%,
35
- rgba(61, 177, 255, 0.15) 26%,
36
- transparent 27%,
37
- transparent 74%,
38
- rgba(61, 177, 255, 0.15) 75%,
39
- rgba(61, 177, 255, 0.15) 76%,
40
- transparent 77%,
41
- transparent
42
- ),
43
- linear-gradient(
44
- 90deg,
45
- transparent 24%,
46
- rgba(61, 177, 255, 0.15) 25%,
47
- rgba(61, 177, 255, 0.15) 26%,
48
- transparent 27%,
49
- transparent 74%,
50
- rgba(61, 177, 255, 0.15) 75%,
51
- rgba(61, 177, 255, 0.15) 76%,
52
- transparent 77%,
53
- transparent
54
- );
55
- background-size: 40px 40px;
56
48
  box-shadow: inset -5px 0 10px rgba(0, 0, 0, 0.05);
57
49
  border-top: 1px solid #e0e0e0;
58
- display: inline-block;
59
50
  width: 100%;
51
+ display: flex;
60
52
  }
61
53
 
62
54
  #canvas {
63
55
  position: relative;
64
- padding: 20px;
56
+ padding: 0px;
57
+ flex-grow: 1;
65
58
  margin: 20px;
66
59
  }
67
60
 
@@ -71,7 +64,7 @@ export class Editor extends RapidElement {
71
64
  }
72
65
 
73
66
  #canvas > .dragging {
74
- z-index: 10000 !important;
67
+ z-index: 99999 !important;
75
68
  }
76
69
 
77
70
  body .jtk-endpoint {
@@ -81,70 +74,44 @@ export class Editor extends RapidElement {
81
74
 
82
75
  .jtk-endpoint {
83
76
  z-index: 600;
77
+ opacity: 0;
84
78
  }
85
79
 
86
80
  .plumb-source {
87
81
  z-index: 600;
88
- border: 0px solid var(--color-connectors);
82
+ cursor: pointer;
83
+ opacity: 0;
89
84
  }
90
85
 
91
86
  .plumb-source.connected {
92
- box-shadow: 0 3px 3px 0px rgba(0, 0, 0, 0.1);
93
87
  border-radius: 50%;
88
+ pointer-events: none;
94
89
  }
95
90
 
96
91
  .plumb-source circle {
97
- fill: tomato;
98
- }
99
-
100
- .plumb-source.connected circle {
101
- fill: #fff;
102
- }
103
-
104
- .plumb-source svg {
105
- fill: var(--color-connectors) !important;
106
- stroke: var(--color-connectors);
92
+ fill: purple;
107
93
  }
108
94
 
109
95
  .plumb-target {
110
- margin-top: -6px;
111
96
  z-index: 600;
112
97
  opacity: 0;
113
98
  cursor: pointer;
99
+ fill: transparent;
114
100
  }
115
101
 
116
- body .plumb-connector path {
102
+ body svg.jtk-connector.plumb-connector path {
117
103
  stroke: var(--color-connectors) !important;
118
104
  stroke-width: 3px;
119
- z-index: 10;
120
105
  }
121
106
 
122
107
  body .plumb-connector {
123
- z-index: 10;
124
- }
125
-
126
- body .plumb-connector.elevated {
127
- z-index: 550;
128
- }
129
-
130
- body .plumb-connector.elevated path {
131
- stroke: var(--color-connectors) !important;
132
- stroke-width: 3px;
133
- z-index: 550;
134
- }
135
-
136
- body .plumb-connector.elevated .plumb-arrow {
137
- fill: var(--color-connectors);
138
- stroke: var(--color-connectors);
139
- stroke-width: 0px;
140
- margin-top: 6px;
141
- z-index: 550;
108
+ z-index: 10 !important;
142
109
  }
143
110
 
144
111
  body .plumb-connector .plumb-arrow {
145
112
  fill: var(--color-connectors);
146
113
  stroke: var(--color-connectors);
147
- stroke-width: 0px;
114
+ stroke-width: 0px !important;
148
115
  margin-top: 6px;
149
116
  z-index: 10;
150
117
  }
@@ -159,6 +126,50 @@ export class Editor extends RapidElement {
159
126
  stroke-width: 0px;
160
127
  z-index: 10;
161
128
  }
129
+
130
+ /* Connection dragging feedback */
131
+ body svg.jtk-connector.jtk-dragging {
132
+ z-index: 99999 !important;
133
+ }
134
+
135
+ .katavorio-drag-no-select svg.jtk-connector path,
136
+ .katavorio-drag-no-select svg.jtk-endpoint path {
137
+ pointer-events: none !important;
138
+ border: 1px solid purple;
139
+ }
140
+
141
+ /* Connection target feedback */
142
+ temba-flow-node.connection-target-valid {
143
+ outline: 3px solid var(--color-success, #22c55e) !important;
144
+ outline-offset: 2px;
145
+ border-radius: var(--curvature);
146
+ }
147
+
148
+ temba-flow-node.connection-target-invalid {
149
+ outline: 3px solid var(--color-error, #ef4444) !important;
150
+ outline-offset: 2px;
151
+ border-radius: var(--curvature);
152
+ }
153
+
154
+ /* Selection box styles */
155
+ .selection-box {
156
+ position: absolute;
157
+ border: 2px dashed #6298f0ff;
158
+ background-color: rgba(59, 130, 246, 0.1);
159
+ z-index: 9999;
160
+ pointer-events: none;
161
+ }
162
+
163
+ /* Selected item styles */
164
+ .draggable.selected {
165
+ outline: 3px solid #6298f0ff;
166
+ outline-offset: 0px;
167
+ border-radius: var(--curvature);
168
+ }
169
+
170
+ .jtk-floating-endpoint {
171
+ pointer-events: none;
172
+ }
162
173
  `;
163
174
  }
164
175
  constructor() {
@@ -171,9 +182,21 @@ export class Editor extends RapidElement {
171
182
  this.dragStartPos = { x: 0, y: 0 };
172
183
  this.currentDragItem = null;
173
184
  this.startPos = { left: 0, top: 0 };
185
+ // Selection state
186
+ this.selectedItems = new Set();
187
+ this.isSelecting = false;
188
+ this.selectionBox = null;
189
+ this.targetId = null;
190
+ this.sourceId = null;
191
+ this.dragFromNodeId = null;
192
+ this.isValidTarget = true;
193
+ this.canvasMouseDown = false;
174
194
  // Bound event handlers to maintain proper 'this' context
175
195
  this.boundMouseMove = this.handleMouseMove.bind(this);
176
196
  this.boundMouseUp = this.handleMouseUp.bind(this);
197
+ this.boundGlobalMouseDown = this.handleGlobalMouseDown.bind(this);
198
+ this.boundKeyDown = this.handleKeyDown.bind(this);
199
+ this.boundCanvasDoubleClick = this.handleCanvasDoubleClick.bind(this);
177
200
  }
178
201
  firstUpdated(changes) {
179
202
  super.firstUpdated(changes);
@@ -182,6 +205,37 @@ export class Editor extends RapidElement {
182
205
  if (changes.has('flow')) {
183
206
  getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
184
207
  }
208
+ this.plumber.on('connection:drag', (info) => {
209
+ this.dragFromNodeId = document
210
+ .getElementById(info.sourceId)
211
+ .closest('.node').id;
212
+ this.sourceId = info.sourceId;
213
+ });
214
+ this.plumber.on('connection:abort', () => {
215
+ this.makeConnection();
216
+ });
217
+ this.plumber.on('connection:detach', () => {
218
+ this.makeConnection();
219
+ });
220
+ }
221
+ makeConnection() {
222
+ if (this.sourceId && this.targetId && this.isValidTarget) {
223
+ this.plumber.connectIds(this.dragFromNodeId, this.sourceId, this.targetId);
224
+ getStore()
225
+ .getState()
226
+ .updateConnection(this.dragFromNodeId, this.sourceId, this.targetId);
227
+ setTimeout(() => {
228
+ this.plumber.repaintEverything();
229
+ }, 100);
230
+ }
231
+ // Clean up visual feedback
232
+ document.querySelectorAll('temba-flow-node').forEach((node) => {
233
+ node.classList.remove('connection-target-valid', 'connection-target-invalid');
234
+ });
235
+ this.sourceId = null;
236
+ this.targetId = null;
237
+ this.dragFromNodeId = null;
238
+ this.isValidTarget = true;
185
239
  }
186
240
  updated(changes) {
187
241
  super.updated(changes);
@@ -227,10 +281,22 @@ export class Editor extends RapidElement {
227
281
  }
228
282
  document.removeEventListener('mousemove', this.boundMouseMove);
229
283
  document.removeEventListener('mouseup', this.boundMouseUp);
284
+ document.removeEventListener('mousedown', this.boundGlobalMouseDown);
285
+ document.removeEventListener('keydown', this.boundKeyDown);
286
+ const canvas = this.querySelector('#canvas');
287
+ if (canvas) {
288
+ canvas.removeEventListener('dblclick', this.boundCanvasDoubleClick);
289
+ }
230
290
  }
231
291
  setupGlobalEventListeners() {
232
292
  document.addEventListener('mousemove', this.boundMouseMove);
233
293
  document.addEventListener('mouseup', this.boundMouseUp);
294
+ document.addEventListener('mousedown', this.boundGlobalMouseDown);
295
+ document.addEventListener('keydown', this.boundKeyDown);
296
+ const canvas = this.querySelector('#canvas');
297
+ if (canvas) {
298
+ canvas.addEventListener('dblclick', this.boundCanvasDoubleClick);
299
+ }
234
300
  }
235
301
  getPosition(uuid, type) {
236
302
  var _a, _b, _c;
@@ -241,24 +307,10 @@ export class Editor extends RapidElement {
241
307
  return (_c = (_b = this.definition._ui.stickies) === null || _b === void 0 ? void 0 : _b[uuid]) === null || _c === void 0 ? void 0 : _c.position;
242
308
  }
243
309
  }
244
- updatePosition(uuid, type, position) {
245
- var _a;
246
- if (type === 'node') {
247
- getStore().getState().updateNodePosition(uuid, position);
248
- }
249
- else {
250
- const currentSticky = (_a = this.definition._ui.stickies) === null || _a === void 0 ? void 0 : _a[uuid];
251
- if (currentSticky) {
252
- getStore()
253
- .getState()
254
- .updateStickyNote(uuid, {
255
- ...currentSticky,
256
- position
257
- });
258
- }
259
- }
260
- }
261
310
  handleMouseDown(event) {
311
+ // ignore right clicks
312
+ if (event.button !== 0)
313
+ return;
262
314
  const element = event.currentTarget;
263
315
  // Only start dragging if clicking on the element itself, not on exits or other interactive elements
264
316
  const target = event.target;
@@ -270,7 +322,17 @@ export class Editor extends RapidElement {
270
322
  const position = this.getPosition(uuid, type);
271
323
  if (!position)
272
324
  return;
273
- // Set up potential drag state, but don't start dragging yet
325
+ // If clicking on a non-selected item, clear selection unless Ctrl/Cmd is held
326
+ if (!this.selectedItems.has(uuid) && !event.ctrlKey && !event.metaKey) {
327
+ this.selectedItems.clear();
328
+ // Don't add single items to selection - single clicks just clear existing selection
329
+ }
330
+ else if (!this.selectedItems.has(uuid)) {
331
+ // Add this item to selection only if Ctrl/Cmd is held
332
+ this.selectedItems.add(uuid);
333
+ }
334
+ // Always set up drag state regardless of selection status
335
+ // This allows single nodes to be dragged without being selected
274
336
  this.isMouseDown = true;
275
337
  this.dragStartPos = { x: event.clientX, y: event.clientY };
276
338
  this.startPos = { left: position.left, top: position.top };
@@ -283,7 +345,230 @@ export class Editor extends RapidElement {
283
345
  event.preventDefault();
284
346
  event.stopPropagation();
285
347
  }
348
+ handleGlobalMouseDown(event) {
349
+ var _a;
350
+ // ignore right clicks
351
+ if (event.button !== 0)
352
+ return;
353
+ // Check if the click is within our canvas
354
+ const canvasRect = (_a = this.querySelector('#grid')) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
355
+ if (!canvasRect)
356
+ return;
357
+ const isWithinCanvas = event.clientX >= canvasRect.left &&
358
+ event.clientX <= canvasRect.right &&
359
+ event.clientY >= canvasRect.top &&
360
+ event.clientY <= canvasRect.bottom;
361
+ if (!isWithinCanvas)
362
+ return;
363
+ // Check if we clicked on a draggable item (node or sticky)
364
+ const target = event.target;
365
+ const clickedOnDraggable = target.closest('.draggable');
366
+ if (clickedOnDraggable) {
367
+ // This is handled by the individual item mousedown handlers
368
+ return;
369
+ }
370
+ // We clicked on empty canvas space, start selection
371
+ this.handleCanvasMouseDown(event);
372
+ }
373
+ handleCanvasMouseDown(event) {
374
+ var _a;
375
+ const target = event.target;
376
+ if (target.id === 'canvas' || target.id === 'grid') {
377
+ // Ignore clicks on exits
378
+ // Start selection box
379
+ this.canvasMouseDown = true;
380
+ this.dragStartPos = { x: event.clientX, y: event.clientY };
381
+ const canvasRect = (_a = this.querySelector('#canvas')) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
382
+ if (canvasRect) {
383
+ // Clear current selection
384
+ this.selectedItems.clear();
385
+ const relativeX = event.clientX - canvasRect.left;
386
+ const relativeY = event.clientY - canvasRect.top;
387
+ this.selectionBox = {
388
+ startX: relativeX,
389
+ startY: relativeY,
390
+ endX: relativeX,
391
+ endY: relativeY
392
+ };
393
+ }
394
+ event.preventDefault();
395
+ }
396
+ }
397
+ handleKeyDown(event) {
398
+ if (event.key === 'Delete' || event.key === 'Backspace') {
399
+ if (this.selectedItems.size > 0) {
400
+ this.showDeleteConfirmation();
401
+ }
402
+ }
403
+ if (event.key === 'Escape') {
404
+ this.selectedItems.clear();
405
+ this.requestUpdate();
406
+ }
407
+ }
408
+ showDeleteConfirmation() {
409
+ const itemCount = this.selectedItems.size;
410
+ const itemType = itemCount === 1 ? 'item' : 'items';
411
+ // Create and show confirmation dialog
412
+ const dialog = document.createElement('temba-dialog');
413
+ dialog.header = 'Delete Items';
414
+ dialog.primaryButtonName = 'Delete';
415
+ dialog.cancelButtonName = 'Cancel';
416
+ dialog.destructive = true;
417
+ dialog.innerHTML = `<div style="padding: 20px;">Are you sure you want to delete ${itemCount} ${itemType}?</div>`;
418
+ dialog.addEventListener('temba-button-clicked', (event) => {
419
+ if (event.detail.button.name === 'Delete') {
420
+ this.deleteSelectedItems();
421
+ dialog.open = false;
422
+ }
423
+ });
424
+ // Add to document and show
425
+ document.body.appendChild(dialog);
426
+ dialog.open = true;
427
+ // Clean up dialog when closed
428
+ dialog.addEventListener('temba-dialog-hidden', () => {
429
+ document.body.removeChild(dialog);
430
+ });
431
+ }
432
+ deleteNodes(uuids) {
433
+ // Clean up jsPlumb connections for nodes before removing them
434
+ uuids.forEach((uuid) => {
435
+ this.plumber.removeNodeConnections(uuid);
436
+ });
437
+ // Now remove them from the definition
438
+ if (uuids.length > 0 && this.plumber) {
439
+ getStore().getState().removeNodes(uuids);
440
+ }
441
+ }
442
+ deleteSelectedItems() {
443
+ const nodes = Array.from(this.selectedItems).filter((uuid) => this.definition.nodes.some((node) => node.uuid === uuid));
444
+ this.deleteNodes(Array.from(nodes));
445
+ const stickies = Array.from(this.selectedItems).filter((uuid) => { var _a, _b; return (_b = (_a = this.definition._ui) === null || _a === void 0 ? void 0 : _a.stickies) === null || _b === void 0 ? void 0 : _b[uuid]; });
446
+ getStore().getState().removeStickyNotes(stickies);
447
+ // Clear selection
448
+ this.selectedItems.clear();
449
+ }
450
+ updateSelectionBox(event) {
451
+ var _a;
452
+ if (!this.selectionBox || !this.canvasMouseDown)
453
+ return;
454
+ const canvasRect = (_a = this.querySelector('#canvas')) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
455
+ if (!canvasRect)
456
+ return;
457
+ const relativeX = event.clientX - canvasRect.left;
458
+ const relativeY = event.clientY - canvasRect.top;
459
+ this.selectionBox = {
460
+ ...this.selectionBox,
461
+ endX: relativeX,
462
+ endY: relativeY
463
+ };
464
+ // Update selected items based on selection box
465
+ this.updateSelectedItemsFromBox();
466
+ }
467
+ updateSelectedItemsFromBox() {
468
+ var _a, _b, _c;
469
+ if (!this.selectionBox)
470
+ return;
471
+ const newSelection = new Set();
472
+ const boxLeft = Math.min(this.selectionBox.startX, this.selectionBox.endX);
473
+ const boxTop = Math.min(this.selectionBox.startY, this.selectionBox.endY);
474
+ const boxRight = Math.max(this.selectionBox.startX, this.selectionBox.endX);
475
+ const boxBottom = Math.max(this.selectionBox.startY, this.selectionBox.endY);
476
+ // Check nodes
477
+ (_a = this.definition) === null || _a === void 0 ? void 0 : _a.nodes.forEach((node) => {
478
+ var _a, _b;
479
+ const nodeElement = this.querySelector(`[id="${node.uuid}"]`);
480
+ if (nodeElement) {
481
+ const position = (_a = this.definition._ui.nodes[node.uuid]) === null || _a === void 0 ? void 0 : _a.position;
482
+ if (position) {
483
+ const rect = nodeElement.getBoundingClientRect();
484
+ const canvasRect = (_b = this.querySelector('#canvas')) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
485
+ if (canvasRect) {
486
+ const nodeLeft = position.left;
487
+ const nodeTop = position.top;
488
+ const nodeRight = nodeLeft + rect.width;
489
+ const nodeBottom = nodeTop + rect.height;
490
+ // Check if selection box intersects with node
491
+ if (boxLeft < nodeRight &&
492
+ boxRight > nodeLeft &&
493
+ boxTop < nodeBottom &&
494
+ boxBottom > nodeTop) {
495
+ newSelection.add(node.uuid);
496
+ }
497
+ }
498
+ }
499
+ }
500
+ });
501
+ // Check sticky notes
502
+ const stickies = ((_c = (_b = this.definition) === null || _b === void 0 ? void 0 : _b._ui) === null || _c === void 0 ? void 0 : _c.stickies) || {};
503
+ Object.entries(stickies).forEach(([uuid, sticky]) => {
504
+ if (sticky.position) {
505
+ const stickyElement = this.querySelector(`temba-sticky-note[uuid="${uuid}"]`);
506
+ if (stickyElement) {
507
+ // Use clientWidth/clientHeight instead of getBoundingClientRect() to get element dimensions
508
+ // This avoids the coordinate system mismatch between viewport and canvas coordinates
509
+ const width = stickyElement.clientWidth;
510
+ const height = stickyElement.clientHeight;
511
+ // Use the canvas coordinates from the sticky's position
512
+ const stickyLeft = sticky.position.left;
513
+ const stickyTop = sticky.position.top;
514
+ const stickyRight = stickyLeft + width;
515
+ const stickyBottom = stickyTop + height;
516
+ // Check if selection box intersects with sticky
517
+ if (boxLeft < stickyRight &&
518
+ boxRight > stickyLeft &&
519
+ boxTop < stickyBottom &&
520
+ boxBottom > stickyTop) {
521
+ newSelection.add(uuid);
522
+ }
523
+ }
524
+ }
525
+ });
526
+ this.selectedItems = newSelection;
527
+ }
528
+ renderSelectionBox() {
529
+ if (!this.selectionBox || !this.isSelecting)
530
+ return '';
531
+ const left = Math.min(this.selectionBox.startX, this.selectionBox.endX);
532
+ const top = Math.min(this.selectionBox.startY, this.selectionBox.endY);
533
+ const width = Math.abs(this.selectionBox.endX - this.selectionBox.startX);
534
+ const height = Math.abs(this.selectionBox.endY - this.selectionBox.startY);
535
+ return html `<div
536
+ class="selection-box"
537
+ style="left: ${left}px; top: ${top}px; width: ${width}px; height: ${height}px;"
538
+ ></div>`;
539
+ }
286
540
  handleMouseMove(event) {
541
+ // Handle selection box drawing
542
+ if (this.canvasMouseDown && !this.isMouseDown) {
543
+ this.isSelecting = true;
544
+ this.updateSelectionBox(event);
545
+ this.requestUpdate(); // Force re-render
546
+ return;
547
+ }
548
+ if (this.plumber.connectionDragging) {
549
+ const targetNode = document.querySelector('temba-flow-node:hover');
550
+ // Clear previous target styles
551
+ document.querySelectorAll('temba-flow-node').forEach((node) => {
552
+ node.classList.remove('connection-target-valid', 'connection-target-invalid');
553
+ });
554
+ if (targetNode) {
555
+ this.targetId = targetNode.getAttribute('uuid');
556
+ // Check if target is different from source node (prevent self-targeting)
557
+ this.isValidTarget = this.targetId !== this.dragFromNodeId;
558
+ // Apply visual feedback based on validity
559
+ if (this.isValidTarget) {
560
+ targetNode.classList.add('connection-target-valid');
561
+ }
562
+ else {
563
+ targetNode.classList.add('connection-target-invalid');
564
+ }
565
+ }
566
+ else {
567
+ this.targetId = null;
568
+ this.isValidTarget = true;
569
+ }
570
+ }
571
+ // Handle item dragging
287
572
  if (!this.isMouseDown || !this.currentDragItem)
288
573
  return;
289
574
  const deltaX = event.clientX - this.dragStartPos.x;
@@ -292,60 +577,96 @@ export class Editor extends RapidElement {
292
577
  // Only start dragging if we've moved beyond the threshold
293
578
  if (!this.isDragging && distance > DRAG_THRESHOLD) {
294
579
  this.isDragging = true;
295
- // If this is a node, elevate connections
296
- if (this.currentDragItem.type === 'node' && this.plumber) {
297
- this.plumber.elevateNodeConnections(this.currentDragItem.uuid);
298
- }
299
580
  }
300
581
  // If we're actually dragging, update positions
301
582
  if (this.isDragging) {
302
- const newLeft = this.startPos.left + deltaX;
303
- const newTop = this.startPos.top + deltaY;
304
- // Update the visual position during drag
305
- this.currentDragItem.element.style.left = `${newLeft}px`;
306
- this.currentDragItem.element.style.top = `${newTop}px`;
307
- // Repaint connections if this is a node
308
- if (this.currentDragItem.type === 'node' && this.plumber) {
309
- this.plumber.repaintEverything();
310
- }
583
+ // Determine what items to move
584
+ const itemsToMove = this.selectedItems.has(this.currentDragItem.uuid) &&
585
+ this.selectedItems.size > 1
586
+ ? Array.from(this.selectedItems)
587
+ : [this.currentDragItem.uuid];
588
+ itemsToMove.forEach((uuid) => {
589
+ const element = this.querySelector(`[uuid="${uuid}"]`);
590
+ if (element) {
591
+ const type = element.tagName === 'TEMBA-FLOW-NODE' ? 'node' : 'sticky';
592
+ const position = this.getPosition(uuid, type);
593
+ if (position) {
594
+ const newLeft = position.left + deltaX;
595
+ const newTop = position.top + deltaY;
596
+ // Update the visual position during drag
597
+ element.style.left = `${newLeft}px`;
598
+ element.style.top = `${newTop}px`;
599
+ // Add dragging class to ensure highest z-index
600
+ element.classList.add('dragging');
601
+ }
602
+ }
603
+ });
604
+ this.plumber.revalidate(itemsToMove);
311
605
  }
312
606
  }
313
607
  handleMouseUp(event) {
608
+ // Handle selection box completion
609
+ if (this.canvasMouseDown && this.isSelecting) {
610
+ this.isSelecting = false;
611
+ this.selectionBox = null;
612
+ this.canvasMouseDown = false;
613
+ this.requestUpdate();
614
+ return;
615
+ }
616
+ // Handle canvas click (clear selection)
617
+ if (this.canvasMouseDown && !this.isSelecting) {
618
+ this.canvasMouseDown = false;
619
+ return;
620
+ }
621
+ // Handle item drag completion
314
622
  if (!this.isMouseDown || !this.currentDragItem)
315
623
  return;
316
624
  // If we were actually dragging, handle the drag end
317
625
  if (this.isDragging) {
318
- // Restore normal z-index for node connections
319
- if (this.currentDragItem.type === 'node' && this.plumber) {
320
- this.plumber.restoreNodeConnections(this.currentDragItem.uuid);
321
- }
322
626
  const deltaX = event.clientX - this.dragStartPos.x;
323
627
  const deltaY = event.clientY - this.dragStartPos.y;
324
- const newLeft = this.startPos.left + deltaX;
325
- const newTop = this.startPos.top + deltaY;
326
- // Snap to 20px grid for final position
327
- const snappedLeft = snapToGrid(newLeft);
328
- const snappedTop = snapToGrid(newTop);
329
- const newPosition = { left: snappedLeft, top: snappedTop };
330
- // Update the store with the new snapped position
331
- this.updatePosition(this.currentDragItem.uuid, this.currentDragItem.type, newPosition);
332
- // Update canvas positions for nodes
333
- if (this.currentDragItem.type === 'node') {
334
- getStore()
335
- .getState()
336
- .updateCanvasPositions({
337
- [this.currentDragItem.uuid]: newPosition
338
- });
339
- }
340
- // Repaint connections if this is a node
341
- if (this.currentDragItem.type === 'node' && this.plumber) {
342
- this.plumber.repaintEverything();
628
+ // Determine what items were moved
629
+ const itemsToMove = this.selectedItems.has(this.currentDragItem.uuid) &&
630
+ this.selectedItems.size > 1
631
+ ? Array.from(this.selectedItems)
632
+ : [this.currentDragItem.uuid];
633
+ // Update positions for all moved items
634
+ const newPositions = {};
635
+ itemsToMove.forEach((uuid) => {
636
+ const type = this.definition.nodes.find((node) => node.uuid === uuid)
637
+ ? 'node'
638
+ : 'sticky';
639
+ const position = this.getPosition(uuid, type);
640
+ if (position) {
641
+ const newLeft = position.left + deltaX;
642
+ const newTop = position.top + deltaY;
643
+ // Snap to 20px grid for final position
644
+ const snappedLeft = snapToGrid(newLeft);
645
+ const snappedTop = snapToGrid(newTop);
646
+ const newPosition = { left: snappedLeft, top: snappedTop };
647
+ newPositions[uuid] = newPosition;
648
+ // Remove dragging class
649
+ const element = this.querySelector(`[uuid="${uuid}"]`);
650
+ if (element) {
651
+ element.classList.remove('dragging');
652
+ element.style.left = `${snappedLeft}px`;
653
+ element.style.top = `${snappedTop}px`;
654
+ }
655
+ }
656
+ });
657
+ if (Object.keys(newPositions).length > 0) {
658
+ getStore().getState().updateCanvasPositions(newPositions);
659
+ setTimeout(() => {
660
+ this.plumber.repaintEverything();
661
+ }, 0);
343
662
  }
663
+ this.selectedItems.clear();
344
664
  }
345
665
  // Reset all drag state
346
666
  this.isDragging = false;
347
667
  this.isMouseDown = false;
348
668
  this.currentDragItem = null;
669
+ this.canvasMouseDown = false;
349
670
  }
350
671
  updateCanvasSize() {
351
672
  var _a;
@@ -371,15 +692,54 @@ export class Editor extends RapidElement {
371
692
  });
372
693
  // Check sticky note positions
373
694
  const stickies = ((_a = this.definition._ui) === null || _a === void 0 ? void 0 : _a.stickies) || {};
374
- Object.values(stickies).forEach((sticky) => {
695
+ Object.entries(stickies).forEach(([uuid, sticky]) => {
375
696
  if (sticky.position) {
376
- maxWidth = Math.max(maxWidth, sticky.position.left + 200); // Sticky note width
377
- maxHeight = Math.max(maxHeight, sticky.position.top + 100); // Sticky note height
697
+ const stickyElement = this.querySelector(`temba-sticky-note[uuid="${uuid}"]`);
698
+ if (stickyElement) {
699
+ // Use clientWidth/clientHeight instead of getBoundingClientRect() to get element dimensions
700
+ // This avoids the coordinate system mismatch between viewport and canvas coordinates
701
+ const width = stickyElement.clientWidth;
702
+ const height = stickyElement.clientHeight;
703
+ // Both sticky.position and width/height are now in the same coordinate system
704
+ maxWidth = Math.max(maxWidth, sticky.position.left + width);
705
+ maxHeight = Math.max(maxHeight, sticky.position.top + height);
706
+ }
707
+ else {
708
+ // Fallback to default sizes if element not found
709
+ maxWidth = Math.max(maxWidth, sticky.position.left + 200);
710
+ maxHeight = Math.max(maxHeight, sticky.position.top + 100);
711
+ }
378
712
  }
379
713
  });
380
714
  // Update canvas size in store
381
715
  store.getState().expandCanvas(maxWidth, maxHeight);
382
716
  }
717
+ handleCanvasDoubleClick(event) {
718
+ // Check if we double-clicked on empty canvas space
719
+ const target = event.target;
720
+ if (target.id !== 'canvas') {
721
+ return;
722
+ }
723
+ // Get canvas position
724
+ const canvas = this.querySelector('#canvas');
725
+ if (!canvas) {
726
+ return;
727
+ }
728
+ const canvasRect = canvas.getBoundingClientRect();
729
+ const relativeX = event.clientX - canvasRect.left - 10;
730
+ const relativeY = event.clientY - canvasRect.top - 10;
731
+ // Snap position to grid
732
+ const snappedLeft = snapToGrid(relativeX);
733
+ const snappedTop = snapToGrid(relativeY);
734
+ // Create new sticky note
735
+ const store = getStore();
736
+ store.getState().createStickyNote({
737
+ left: snappedLeft,
738
+ top: snappedTop
739
+ });
740
+ event.preventDefault();
741
+ event.stopPropagation();
742
+ }
383
743
  render() {
384
744
  var _a, _b;
385
745
  // we have to embed our own style since we are in light DOM
@@ -397,35 +757,47 @@ export class Editor extends RapidElement {
397
757
  >
398
758
  <div id="canvas">
399
759
  ${this.definition
400
- ? this.definition.nodes.map((node) => {
760
+ ? repeat(this.definition.nodes, (node) => node.uuid, (node) => {
401
761
  var _a;
402
762
  const position = this.definition._ui.nodes[node.uuid].position;
403
- const dragging = this.isDragging && ((_a = this.currentDragItem) === null || _a === void 0 ? void 0 : _a.uuid) === node.uuid;
763
+ const dragging = this.isDragging &&
764
+ ((_a = this.currentDragItem) === null || _a === void 0 ? void 0 : _a.uuid) === node.uuid;
765
+ const selected = this.selectedItems.has(node.uuid);
404
766
  return html `<temba-flow-node
405
- class="draggable ${dragging ? 'dragging' : ''}"
406
- @mousedown=${this.handleMouseDown.bind(this)}
407
- uuid=${node.uuid}
408
- style="left:${position.left}px; top:${position.top}px"
409
- .plumber=${this.plumber}
410
- .node=${node}
411
- .ui=${this.definition._ui.nodes[node.uuid]}
412
- ></temba-flow-node>`;
767
+ class="draggable ${dragging ? 'dragging' : ''} ${selected
768
+ ? 'selected'
769
+ : ''}"
770
+ @mousedown=${this.handleMouseDown.bind(this)}
771
+ uuid=${node.uuid}
772
+ style="left:${position.left}px; top:${position.top}px"
773
+ .plumber=${this.plumber}
774
+ .node=${node}
775
+ .ui=${this.definition._ui.nodes[node.uuid]}
776
+ @temba-node-deleted=${(event) => {
777
+ this.deleteNodes([event.detail.uuid]);
778
+ }}
779
+ ></temba-flow-node>`;
413
780
  })
414
781
  : html `<temba-loading></temba-loading>`}
415
- ${Object.entries(stickies).map(([uuid, sticky]) => {
782
+ ${repeat(Object.entries(stickies), ([uuid]) => uuid, ([uuid, sticky]) => {
416
783
  var _a;
417
784
  const position = sticky.position || { left: 0, top: 0 };
418
785
  const dragging = this.isDragging && ((_a = this.currentDragItem) === null || _a === void 0 ? void 0 : _a.uuid) === uuid;
786
+ const selected = this.selectedItems.has(uuid);
419
787
  return html `<temba-sticky-note
420
- class="draggable ${dragging ? 'dragging' : ''}"
421
- @mousedown=${this.handleMouseDown.bind(this)}
422
- style="left:${position.left}px; top:${position.top}px; z-index: ${1000 +
788
+ class="draggable ${dragging ? 'dragging' : ''} ${selected
789
+ ? 'selected'
790
+ : ''}"
791
+ @mousedown=${this.handleMouseDown.bind(this)}
792
+ style="left:${position.left}px; top:${position.top}px; z-index: ${1000 +
423
793
  position.top}"
424
- uuid=${uuid}
425
- .data=${sticky}
426
- .dragging=${dragging}
427
- ></temba-sticky-note>`;
794
+ uuid=${uuid}
795
+ .data=${sticky}
796
+ .dragging=${dragging}
797
+ .selected=${selected}
798
+ ></temba-sticky-note>`;
428
799
  })}
800
+ ${this.renderSelectionBox()}
429
801
  </div>
430
802
  </div>
431
803
  </div>`;
@@ -452,4 +824,25 @@ __decorate([
452
824
  __decorate([
453
825
  state()
454
826
  ], Editor.prototype, "currentDragItem", void 0);
827
+ __decorate([
828
+ state()
829
+ ], Editor.prototype, "selectedItems", void 0);
830
+ __decorate([
831
+ state()
832
+ ], Editor.prototype, "isSelecting", void 0);
833
+ __decorate([
834
+ state()
835
+ ], Editor.prototype, "selectionBox", void 0);
836
+ __decorate([
837
+ state()
838
+ ], Editor.prototype, "targetId", void 0);
839
+ __decorate([
840
+ state()
841
+ ], Editor.prototype, "sourceId", void 0);
842
+ __decorate([
843
+ state()
844
+ ], Editor.prototype, "dragFromNodeId", void 0);
845
+ __decorate([
846
+ state()
847
+ ], Editor.prototype, "isValidTarget", void 0);
455
848
  //# sourceMappingURL=Editor.js.map