@nyaruka/temba-components 0.129.2 → 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 (524) hide show
  1. package/.github/workflows/build.yml +6 -5
  2. package/.github/workflows/coverage.yml +80 -0
  3. package/CHANGELOG.md +22 -0
  4. package/README.md +6 -0
  5. package/check-coverage.js +133 -0
  6. package/demo/data/flows/sample-flow.json +107 -100
  7. package/dist/temba-components.js +893 -476
  8. package/dist/temba-components.js.map +1 -1
  9. package/generate-coverage-badge.sh +69 -0
  10. package/out-tsc/src/{vectoricon/index.js → Icons.js} +1 -1
  11. package/out-tsc/src/Icons.js.map +1 -0
  12. package/out-tsc/src/display/Alert.js.map +1 -0
  13. package/out-tsc/src/display/Anchor.js.map +1 -0
  14. package/out-tsc/src/display/Button.js.map +1 -0
  15. package/out-tsc/src/{charcount → display}/CharCount.js +159 -2
  16. package/out-tsc/src/display/CharCount.js.map +1 -0
  17. package/out-tsc/src/display/Chat.js.map +1 -0
  18. package/out-tsc/src/display/ContactName.js.map +1 -0
  19. package/out-tsc/src/display/ContactUrn.js.map +1 -0
  20. package/out-tsc/src/display/Dropdown.js.map +1 -0
  21. package/out-tsc/src/{vectoricon/VectorIcon.js → display/Icon.js} +2 -2
  22. package/out-tsc/src/display/Icon.js.map +1 -0
  23. package/out-tsc/src/display/Label.js.map +1 -0
  24. package/out-tsc/src/{leafletmap → display}/LeafletMap.js +16 -1
  25. package/out-tsc/src/display/LeafletMap.js.map +1 -0
  26. package/out-tsc/src/display/Lightbox.js.map +1 -0
  27. package/out-tsc/src/{loading → display}/Loading.js.map +1 -1
  28. package/out-tsc/src/{options → display}/Options.js.map +1 -1
  29. package/out-tsc/src/display/ProgressBar.js.map +1 -0
  30. package/out-tsc/src/display/TembaDate.js.map +1 -0
  31. package/out-tsc/src/display/TembaUser.js.map +1 -0
  32. package/out-tsc/src/display/Thumbnail.js.map +1 -0
  33. package/out-tsc/src/{tip → display}/Tip.js +1 -2
  34. package/out-tsc/src/display/Tip.js.map +1 -0
  35. package/out-tsc/src/display/Toast.js.map +1 -0
  36. package/out-tsc/src/display/sms/gsmsplitter.js.map +1 -0
  37. package/out-tsc/src/display/sms/gsmvalidator.js.map +1 -0
  38. package/out-tsc/src/display/sms/index.js.map +1 -0
  39. package/out-tsc/src/display/sms/unicodesplitter.js.map +1 -0
  40. package/out-tsc/src/events.js +2 -0
  41. package/out-tsc/src/events.js.map +1 -0
  42. package/out-tsc/src/excellent/ExcellentParser.js.map +1 -0
  43. package/out-tsc/src/excellent/helpers.js.map +1 -0
  44. package/out-tsc/src/flow/Editor.js +533 -140
  45. package/out-tsc/src/flow/Editor.js.map +1 -1
  46. package/out-tsc/src/flow/EditorNode.js +287 -20
  47. package/out-tsc/src/flow/EditorNode.js.map +1 -1
  48. package/out-tsc/src/flow/Plumber.js +154 -74
  49. package/out-tsc/src/flow/Plumber.js.map +1 -1
  50. package/out-tsc/src/flow/StickyNote.js +153 -9
  51. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  52. package/out-tsc/src/flow/config.js +88 -18
  53. package/out-tsc/src/flow/config.js.map +1 -1
  54. package/out-tsc/src/flow/render.js +327 -10
  55. package/out-tsc/src/flow/render.js.map +1 -1
  56. package/out-tsc/src/{checkbox → form}/Checkbox.js +2 -2
  57. package/out-tsc/src/form/Checkbox.js.map +1 -0
  58. package/out-tsc/src/{colorpicker → form}/ColorPicker.js +1 -1
  59. package/out-tsc/src/form/ColorPicker.js.map +1 -0
  60. package/out-tsc/src/{completion → form}/Completion.js +2 -2
  61. package/out-tsc/src/form/Completion.js.map +1 -0
  62. package/out-tsc/src/{compose → form}/Compose.js +1 -1
  63. package/out-tsc/src/form/Compose.js.map +1 -0
  64. package/out-tsc/src/{contactsearch → form}/ContactSearch.js +2 -2
  65. package/out-tsc/src/form/ContactSearch.js.map +1 -0
  66. package/out-tsc/src/form/CroppieCSS.js.map +1 -0
  67. package/out-tsc/src/{datepicker → form}/DatePicker.js +1 -1
  68. package/out-tsc/src/form/DatePicker.js.map +1 -0
  69. package/out-tsc/src/{FormElement.js → form/FormElement.js} +1 -1
  70. package/out-tsc/src/form/FormElement.js.map +1 -0
  71. package/out-tsc/src/form/FormField.js.map +1 -0
  72. package/out-tsc/src/{imagepicker → form}/ImagePicker.js +2 -2
  73. package/out-tsc/src/form/ImagePicker.js.map +1 -0
  74. package/out-tsc/src/{mediapicker → form}/MediaPicker.js +1 -1
  75. package/out-tsc/src/form/MediaPicker.js.map +1 -0
  76. package/out-tsc/src/form/RangePicker.js.map +1 -0
  77. package/out-tsc/src/{slider → form}/TembaSlider.js +1 -1
  78. package/out-tsc/src/form/TembaSlider.js.map +1 -0
  79. package/out-tsc/src/{templates → form}/TemplateEditor.js +1 -1
  80. package/out-tsc/src/form/TemplateEditor.js.map +1 -0
  81. package/out-tsc/src/{textinput → form}/TextInput.js +3 -3
  82. package/out-tsc/src/form/TextInput.js.map +1 -0
  83. package/out-tsc/src/{omnibox → form/select}/Omnibox.js +2 -2
  84. package/out-tsc/src/form/select/Omnibox.js.map +1 -0
  85. package/out-tsc/src/{select → form/select}/PopupSelect.js +1 -1
  86. package/out-tsc/src/form/select/PopupSelect.js.map +1 -0
  87. package/out-tsc/src/{select → form/select}/Select.js +86 -87
  88. package/out-tsc/src/form/select/Select.js.map +1 -0
  89. package/out-tsc/src/{select → form/select}/UserSelect.js +1 -1
  90. package/out-tsc/src/form/select/UserSelect.js.map +1 -0
  91. package/out-tsc/src/{select → form/select}/WorkspaceSelect.js +1 -1
  92. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -0
  93. package/out-tsc/src/interfaces.js +1 -0
  94. package/out-tsc/src/interfaces.js.map +1 -1
  95. package/out-tsc/src/layout/Dialog.js.map +1 -0
  96. package/out-tsc/src/layout/Mask.js.map +1 -0
  97. package/out-tsc/src/{dialog → layout}/Modax.js.map +1 -1
  98. package/out-tsc/src/layout/Resizer.js.map +1 -0
  99. package/out-tsc/src/layout/Tab.js.map +1 -0
  100. package/out-tsc/src/layout/TabPane.js.map +1 -0
  101. package/out-tsc/src/list/NotificationList.js +1 -1
  102. package/out-tsc/src/list/NotificationList.js.map +1 -1
  103. package/out-tsc/src/list/RunList.js +1 -1
  104. package/out-tsc/src/list/RunList.js.map +1 -1
  105. package/out-tsc/src/list/ShortcutList.js.map +1 -1
  106. package/out-tsc/src/list/TembaMenu.js +1 -1
  107. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  108. package/out-tsc/src/list/TicketList.js +1 -1
  109. package/out-tsc/src/list/TicketList.js.map +1 -1
  110. package/out-tsc/src/{aliaseditor → live}/AliasEditor.js +1 -1
  111. package/out-tsc/src/live/AliasEditor.js.map +1 -0
  112. package/out-tsc/src/{contacts → live}/ContactBadges.js +1 -1
  113. package/out-tsc/src/live/ContactBadges.js.map +1 -0
  114. package/out-tsc/src/{contacts → live}/ContactChat.js +79 -3
  115. package/out-tsc/src/live/ContactChat.js.map +1 -0
  116. package/out-tsc/src/{contacts → live}/ContactDetails.js +1 -1
  117. package/out-tsc/src/live/ContactDetails.js.map +1 -0
  118. package/out-tsc/src/{contacts → live}/ContactFieldEditor.js +2 -2
  119. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -0
  120. package/out-tsc/src/live/ContactFields.js.map +1 -0
  121. package/out-tsc/src/live/ContactNameFetch.js.map +1 -0
  122. package/out-tsc/src/{contacts → live}/ContactNotepad.js +1 -1
  123. package/out-tsc/src/{contacts → live}/ContactNotepad.js.map +1 -1
  124. package/out-tsc/src/{contacts → live}/ContactPending.js +1 -1
  125. package/out-tsc/src/live/ContactPending.js.map +1 -0
  126. package/out-tsc/src/live/ContactStoreElement.js.map +1 -0
  127. package/out-tsc/src/live/FieldManager.js.map +1 -0
  128. package/out-tsc/src/live/StartProgress.js.map +1 -0
  129. package/out-tsc/src/live/TembaChart.js.map +1 -0
  130. package/out-tsc/src/store/AppState.js +54 -24
  131. package/out-tsc/src/store/AppState.js.map +1 -1
  132. package/out-tsc/src/store/Store.js +1 -1
  133. package/out-tsc/src/store/Store.js.map +1 -1
  134. package/out-tsc/src/{utils/index.js → utils.js} +22 -1
  135. package/out-tsc/src/utils.js.map +1 -0
  136. package/out-tsc/src/webchat/WebChat.js +1 -1
  137. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  138. package/out-tsc/temba-components.js +2 -2
  139. package/out-tsc/temba-components.js.map +1 -1
  140. package/out-tsc/temba-modules.js +54 -54
  141. package/out-tsc/temba-modules.js.map +1 -1
  142. package/out-tsc/temba-webchat.js +2 -2
  143. package/out-tsc/temba-webchat.js.map +1 -1
  144. package/out-tsc/test/temba-alert.test.js +1 -1
  145. package/out-tsc/test/temba-alert.test.js.map +1 -1
  146. package/out-tsc/test/temba-appstate-language.test.js +90 -0
  147. package/out-tsc/test/temba-appstate-language.test.js.map +1 -1
  148. package/out-tsc/test/temba-charcount.test.js.map +1 -1
  149. package/out-tsc/test/temba-chart.test.js +1 -1
  150. package/out-tsc/test/temba-chart.test.js.map +1 -1
  151. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  152. package/out-tsc/test/temba-color-picker.test.js +1 -1
  153. package/out-tsc/test/temba-color-picker.test.js.map +1 -1
  154. package/out-tsc/test/temba-completion.test.js +1 -1
  155. package/out-tsc/test/temba-completion.test.js.map +1 -1
  156. package/out-tsc/test/temba-compose.test.js +1 -1
  157. package/out-tsc/test/temba-compose.test.js.map +1 -1
  158. package/out-tsc/test/temba-contact-badges.test.js +1 -1
  159. package/out-tsc/test/temba-contact-badges.test.js.map +1 -1
  160. package/out-tsc/test/temba-contact-chat.test.js +3 -1
  161. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  162. package/out-tsc/test/temba-contact-details.test.js +1 -1
  163. package/out-tsc/test/temba-contact-details.test.js.map +1 -1
  164. package/out-tsc/test/temba-contact-fields.test.js +1 -1
  165. package/out-tsc/test/temba-contact-fields.test.js.map +1 -1
  166. package/out-tsc/test/temba-contact-search.test.js +1 -1
  167. package/out-tsc/test/temba-contact-search.test.js.map +1 -1
  168. package/out-tsc/test/temba-date.test.js +5 -1
  169. package/out-tsc/test/temba-date.test.js.map +1 -1
  170. package/out-tsc/test/temba-datepicker.test.js +1 -1
  171. package/out-tsc/test/temba-datepicker.test.js.map +1 -1
  172. package/out-tsc/test/temba-dialog.test.js +1 -1
  173. package/out-tsc/test/temba-dialog.test.js.map +1 -1
  174. package/out-tsc/test/temba-dropdown.test.js +1 -1
  175. package/out-tsc/test/temba-dropdown.test.js.map +1 -1
  176. package/out-tsc/test/temba-excellent-helpers.test.js +316 -0
  177. package/out-tsc/test/temba-excellent-helpers.test.js.map +1 -0
  178. package/out-tsc/test/temba-field-manager.test.js.map +1 -1
  179. package/out-tsc/test/temba-flow-editor-node.test.js +414 -1
  180. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  181. package/out-tsc/test/temba-flow-editor.test.js +185 -0
  182. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  183. package/out-tsc/test/temba-flow-plumber-connections.test.js +113 -0
  184. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -0
  185. package/out-tsc/test/temba-flow-plumber.test.js +73 -93
  186. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  187. package/out-tsc/test/temba-flow-render.test.js +624 -1
  188. package/out-tsc/test/temba-flow-render.test.js.map +1 -1
  189. package/out-tsc/test/temba-flow-self-routing.test.js +172 -0
  190. package/out-tsc/test/temba-flow-self-routing.test.js.map +1 -0
  191. package/out-tsc/test/temba-formfield.test.js.map +1 -1
  192. package/out-tsc/test/temba-icon.test.js +1 -1
  193. package/out-tsc/test/temba-icon.test.js.map +1 -1
  194. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  195. package/out-tsc/test/temba-label.test.js +1 -1
  196. package/out-tsc/test/temba-label.test.js.map +1 -1
  197. package/out-tsc/test/temba-lightbox.test.js +1 -1
  198. package/out-tsc/test/temba-lightbox.test.js.map +1 -1
  199. package/out-tsc/test/temba-markdown.test.js +127 -0
  200. package/out-tsc/test/temba-markdown.test.js.map +1 -0
  201. package/out-tsc/test/temba-menu.test.js +1 -1
  202. package/out-tsc/test/temba-menu.test.js.map +1 -1
  203. package/out-tsc/test/temba-modax.test.js +1 -1
  204. package/out-tsc/test/temba-modax.test.js.map +1 -1
  205. package/out-tsc/test/temba-modules.test.js +47 -0
  206. package/out-tsc/test/temba-modules.test.js.map +1 -0
  207. package/out-tsc/test/temba-omnibox.test.js +1 -1
  208. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  209. package/out-tsc/test/temba-options.test.js.map +1 -1
  210. package/out-tsc/test/temba-range-picker.test.js +9 -2
  211. package/out-tsc/test/temba-range-picker.test.js.map +1 -1
  212. package/out-tsc/test/temba-rapid-element.test.js +273 -0
  213. package/out-tsc/test/temba-rapid-element.test.js.map +1 -0
  214. package/out-tsc/test/temba-resize-element.test.js +85 -0
  215. package/out-tsc/test/temba-resize-element.test.js.map +1 -0
  216. package/out-tsc/test/temba-select.test.js +2 -2
  217. package/out-tsc/test/temba-select.test.js.map +1 -1
  218. package/out-tsc/test/temba-slider.test.js.map +1 -1
  219. package/out-tsc/test/temba-sticky-note.test.js +194 -0
  220. package/out-tsc/test/temba-sticky-note.test.js.map +1 -0
  221. package/out-tsc/test/temba-template-editor.test.js.map +1 -1
  222. package/out-tsc/test/temba-textinput.test.js +1 -1
  223. package/out-tsc/test/temba-textinput.test.js.map +1 -1
  224. package/out-tsc/test/temba-tip.test.js +1 -1
  225. package/out-tsc/test/temba-tip.test.js.map +1 -1
  226. package/out-tsc/test/temba-toast.test.js +1 -1
  227. package/out-tsc/test/temba-toast.test.js.map +1 -1
  228. package/out-tsc/test/temba-utils-index.test.js +1 -1
  229. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  230. package/out-tsc/test/temba-utils-uuid.test.js +38 -0
  231. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -0
  232. package/out-tsc/test/temba-webchat.test.js +28 -12
  233. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  234. package/out-tsc/test/utils.test.js +2 -6
  235. package/out-tsc/test/utils.test.js.map +1 -1
  236. package/package.json +18 -9
  237. package/rollup.components.mjs +1 -1
  238. package/screenshots/truth/datepicker/range-picker-all.png +0 -0
  239. package/screenshots/truth/datepicker/range-picker-button-states.png +0 -0
  240. package/screenshots/truth/datepicker/range-picker-default.png +0 -0
  241. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  242. package/screenshots/truth/datepicker/range-picker-initial-values.png +0 -0
  243. package/screenshots/truth/datepicker/range-picker-week.png +0 -0
  244. package/screenshots/truth/datepicker/range-picker-year.png +0 -0
  245. package/screenshots/truth/sticky-note/blue-color.png +0 -0
  246. package/screenshots/truth/sticky-note/blue.png +0 -0
  247. package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
  248. package/screenshots/truth/sticky-note/default.png +0 -0
  249. package/screenshots/truth/sticky-note/gray-color.png +0 -0
  250. package/screenshots/truth/sticky-note/gray.png +0 -0
  251. package/screenshots/truth/sticky-note/green-color.png +0 -0
  252. package/screenshots/truth/sticky-note/green.png +0 -0
  253. package/screenshots/truth/sticky-note/pink-color.png +0 -0
  254. package/screenshots/truth/sticky-note/pink.png +0 -0
  255. package/screenshots/truth/sticky-note/yellow-color.png +0 -0
  256. package/screenshots/truth/sticky-note/yellow.png +0 -0
  257. package/src/{charcount → display}/CharCount.ts +164 -2
  258. package/src/{vectoricon/VectorIcon.ts → display/Icon.ts} +1 -1
  259. package/src/{leafletmap → display}/LeafletMap.ts +19 -1
  260. package/src/{thumbnail → display}/Thumbnail.ts +1 -1
  261. package/src/{tip → display}/Tip.ts +1 -2
  262. package/src/{contacts/events.ts → events.ts} +1 -64
  263. package/src/flow/Editor.ts +655 -165
  264. package/src/flow/EditorNode.ts +337 -22
  265. package/src/flow/Plumber.ts +186 -79
  266. package/src/flow/StickyNote.ts +165 -9
  267. package/src/flow/config.ts +114 -18
  268. package/src/flow/render.ts +398 -11
  269. package/src/{checkbox → form}/Checkbox.ts +2 -2
  270. package/src/{colorpicker → form}/ColorPicker.ts +2 -2
  271. package/src/{completion → form}/Completion.ts +3 -3
  272. package/src/{compose → form}/Compose.ts +7 -7
  273. package/src/{contactsearch → form}/ContactSearch.ts +6 -6
  274. package/src/{datepicker → form}/DatePicker.ts +1 -1
  275. package/src/{FormElement.ts → form/FormElement.ts} +1 -1
  276. package/src/{imagepicker → form}/ImagePicker.ts +2 -2
  277. package/src/{mediapicker → form}/MediaPicker.ts +1 -1
  278. package/src/{slider → form}/TembaSlider.ts +1 -1
  279. package/src/{templates → form}/TemplateEditor.ts +2 -2
  280. package/src/{textinput → form}/TextInput.ts +5 -5
  281. package/src/{omnibox → form/select}/Omnibox.ts +2 -2
  282. package/src/{select → form/select}/PopupSelect.ts +1 -1
  283. package/src/{select → form/select}/Select.ts +124 -126
  284. package/src/{select → form/select}/UserSelect.ts +1 -1
  285. package/src/{select → form/select}/WorkspaceSelect.ts +1 -1
  286. package/src/interfaces.ts +2 -1
  287. package/src/{dialog → layout}/Dialog.ts +1 -1
  288. package/src/list/NotificationList.ts +2 -2
  289. package/src/list/RunList.ts +3 -3
  290. package/src/list/ShortcutList.ts +1 -1
  291. package/src/list/TembaMenu.ts +2 -2
  292. package/src/list/TicketList.ts +1 -1
  293. package/src/{aliaseditor → live}/AliasEditor.ts +3 -3
  294. package/src/{contacts → live}/ContactBadges.ts +1 -1
  295. package/src/{contacts → live}/ContactChat.ts +118 -8
  296. package/src/{contacts → live}/ContactDetails.ts +1 -1
  297. package/src/{contacts → live}/ContactFieldEditor.ts +4 -4
  298. package/src/{contacts → live}/ContactFields.ts +1 -1
  299. package/src/{contacts → live}/ContactNotepad.ts +1 -1
  300. package/src/{contacts → live}/ContactPending.ts +1 -1
  301. package/src/{chart → live}/TembaChart.ts +1 -1
  302. package/src/store/AppState.ts +75 -29
  303. package/src/store/Store.ts +1 -1
  304. package/src/store/flow-definition.d.ts +125 -0
  305. package/src/{utils/index.ts → utils.ts} +26 -10
  306. package/src/webchat/WebChat.ts +1 -1
  307. package/static/css/temba-components.css +1 -0
  308. package/svg.js +1 -4
  309. package/temba-components.ts +2 -2
  310. package/temba-modules.ts +54 -54
  311. package/temba-webchat.ts +2 -2
  312. package/test/temba-alert.test.ts +1 -1
  313. package/test/temba-appstate-language.test.ts +108 -0
  314. package/test/temba-charcount.test.ts +1 -1
  315. package/test/temba-chart.test.ts +1 -1
  316. package/test/temba-checkbox.test.ts +1 -1
  317. package/test/temba-color-picker.test.ts +1 -1
  318. package/test/temba-completion.test.ts +1 -1
  319. package/test/temba-compose.test.ts +1 -1
  320. package/test/temba-contact-badges.test.ts +1 -1
  321. package/test/temba-contact-chat.test.ts +6 -4
  322. package/test/temba-contact-details.test.ts +1 -1
  323. package/test/temba-contact-fields.test.ts +1 -1
  324. package/test/temba-contact-search.test.ts +2 -2
  325. package/test/temba-date.test.ts +8 -3
  326. package/test/temba-datepicker.test.ts +1 -1
  327. package/test/temba-dialog.test.ts +1 -1
  328. package/test/temba-dropdown.test.ts +1 -1
  329. package/test/temba-excellent-helpers.test.ts +417 -0
  330. package/test/temba-field-manager.test.ts +2 -2
  331. package/test/temba-flow-editor-node.test.ts +536 -1
  332. package/test/temba-flow-editor.test.ts +224 -0
  333. package/test/temba-flow-editor.test.ts.backup +563 -0
  334. package/test/temba-flow-plumber-connections.test.ts +142 -0
  335. package/test/temba-flow-plumber.test.ts +83 -120
  336. package/test/temba-flow-render.test.ts +787 -4
  337. package/test/temba-flow-self-routing.test.ts +215 -0
  338. package/test/temba-formfield.test.ts +1 -1
  339. package/test/temba-icon.test.ts +1 -1
  340. package/test/temba-integration-markdown.test.ts +1 -1
  341. package/test/temba-label.test.ts +1 -1
  342. package/test/temba-lightbox.test.ts +1 -1
  343. package/test/temba-markdown.test.ts +162 -0
  344. package/test/temba-menu.test.ts +1 -1
  345. package/test/temba-modax.test.ts +2 -2
  346. package/test/temba-modules.test.ts +56 -0
  347. package/test/temba-omnibox.test.ts +1 -1
  348. package/test/temba-options.test.ts +1 -1
  349. package/test/temba-range-picker.test.ts +17 -2
  350. package/test/temba-rapid-element.test.ts +341 -0
  351. package/test/temba-resize-element.test.ts +104 -0
  352. package/test/temba-select.test.ts +2 -2
  353. package/test/temba-slider.test.ts +1 -1
  354. package/test/temba-sticky-note.test.ts +281 -0
  355. package/test/temba-template-editor.test.ts +1 -1
  356. package/test/temba-textinput.test.ts +1 -1
  357. package/test/temba-tip.test.ts +1 -1
  358. package/test/temba-toast.test.ts +1 -1
  359. package/test/temba-utils-index.test.ts +1 -1
  360. package/test/temba-utils-index.test.ts.backup +1737 -0
  361. package/test/temba-utils-uuid.test.ts +48 -0
  362. package/test/temba-webchat.test.ts +30 -12
  363. package/test/utils.test.ts +5 -9
  364. package/web-dev-server.config.mjs +1 -1
  365. package/out-tsc/src/FormElement.js.map +0 -1
  366. package/out-tsc/src/alert/Alert.js.map +0 -1
  367. package/out-tsc/src/aliaseditor/AliasEditor.js.map +0 -1
  368. package/out-tsc/src/anchor/Anchor.js.map +0 -1
  369. package/out-tsc/src/button/Button.js.map +0 -1
  370. package/out-tsc/src/charcount/CharCount.js.map +0 -1
  371. package/out-tsc/src/charcount/helpers.js +0 -159
  372. package/out-tsc/src/charcount/helpers.js.map +0 -1
  373. package/out-tsc/src/chart/TembaChart.js.map +0 -1
  374. package/out-tsc/src/chat/Chat.js.map +0 -1
  375. package/out-tsc/src/checkbox/Checkbox.js.map +0 -1
  376. package/out-tsc/src/colorpicker/ColorPicker.js.map +0 -1
  377. package/out-tsc/src/completion/Completion.js.map +0 -1
  378. package/out-tsc/src/completion/ExcellentParser.js.map +0 -1
  379. package/out-tsc/src/completion/helpers.js.map +0 -1
  380. package/out-tsc/src/compose/Compose.js.map +0 -1
  381. package/out-tsc/src/contacts/ContactBadges.js.map +0 -1
  382. package/out-tsc/src/contacts/ContactChat.js.map +0 -1
  383. package/out-tsc/src/contacts/ContactDetails.js.map +0 -1
  384. package/out-tsc/src/contacts/ContactFieldEditor.js.map +0 -1
  385. package/out-tsc/src/contacts/ContactFields.js.map +0 -1
  386. package/out-tsc/src/contacts/ContactName.js.map +0 -1
  387. package/out-tsc/src/contacts/ContactNameFetch.js.map +0 -1
  388. package/out-tsc/src/contacts/ContactPending.js.map +0 -1
  389. package/out-tsc/src/contacts/ContactStoreElement.js.map +0 -1
  390. package/out-tsc/src/contacts/ContactUrn.js.map +0 -1
  391. package/out-tsc/src/contacts/events.js +0 -65
  392. package/out-tsc/src/contacts/events.js.map +0 -1
  393. package/out-tsc/src/contacts/helpers.js +0 -77
  394. package/out-tsc/src/contacts/helpers.js.map +0 -1
  395. package/out-tsc/src/contactsearch/ContactSearch.js.map +0 -1
  396. package/out-tsc/src/date/TembaDate.js.map +0 -1
  397. package/out-tsc/src/datepicker/DatePicker.js.map +0 -1
  398. package/out-tsc/src/datepicker/RangePicker.js.map +0 -1
  399. package/out-tsc/src/dialog/Dialog.js.map +0 -1
  400. package/out-tsc/src/dropdown/Dropdown.js.map +0 -1
  401. package/out-tsc/src/fields/FieldManager.js.map +0 -1
  402. package/out-tsc/src/formfield/FormField.js.map +0 -1
  403. package/out-tsc/src/imagepicker/CroppieCSS.js.map +0 -1
  404. package/out-tsc/src/imagepicker/ImagePicker.js.map +0 -1
  405. package/out-tsc/src/label/Label.js.map +0 -1
  406. package/out-tsc/src/leafletmap/LeafletMap.js.map +0 -1
  407. package/out-tsc/src/leafletmap/helpers.js +0 -17
  408. package/out-tsc/src/leafletmap/helpers.js.map +0 -1
  409. package/out-tsc/src/lightbox/Lightbox.js.map +0 -1
  410. package/out-tsc/src/mask/Mask.js.map +0 -1
  411. package/out-tsc/src/mediapicker/MediaPicker.js.map +0 -1
  412. package/out-tsc/src/omnibox/Omnibox.js.map +0 -1
  413. package/out-tsc/src/options/helpers.js +0 -28
  414. package/out-tsc/src/options/helpers.js.map +0 -1
  415. package/out-tsc/src/progress/ProgressBar.js.map +0 -1
  416. package/out-tsc/src/progress/StartProgress.js.map +0 -1
  417. package/out-tsc/src/resizer/Resizer.js.map +0 -1
  418. package/out-tsc/src/select/PopupSelect.js.map +0 -1
  419. package/out-tsc/src/select/Select.js.map +0 -1
  420. package/out-tsc/src/select/UserSelect.js.map +0 -1
  421. package/out-tsc/src/select/WorkspaceSelect.js.map +0 -1
  422. package/out-tsc/src/select/helpers.js +0 -1
  423. package/out-tsc/src/select/helpers.js.map +0 -1
  424. package/out-tsc/src/shadowless/Shadowless.js +0 -33
  425. package/out-tsc/src/shadowless/Shadowless.js.map +0 -1
  426. package/out-tsc/src/slider/TembaSlider.js.map +0 -1
  427. package/out-tsc/src/sms/gsmsplitter.js.map +0 -1
  428. package/out-tsc/src/sms/gsmvalidator.js.map +0 -1
  429. package/out-tsc/src/sms/index.js.map +0 -1
  430. package/out-tsc/src/sms/unicodesplitter.js.map +0 -1
  431. package/out-tsc/src/tabpane/Tab.js.map +0 -1
  432. package/out-tsc/src/tabpane/TabPane.js.map +0 -1
  433. package/out-tsc/src/templates/TemplateEditor.js.map +0 -1
  434. package/out-tsc/src/textinput/TextInput.js.map +0 -1
  435. package/out-tsc/src/textinput/helpers.js +0 -12
  436. package/out-tsc/src/textinput/helpers.js.map +0 -1
  437. package/out-tsc/src/thumbnail/Thumbnail.js.map +0 -1
  438. package/out-tsc/src/tip/Tip.js.map +0 -1
  439. package/out-tsc/src/tip/helpers.js +0 -7
  440. package/out-tsc/src/tip/helpers.js.map +0 -1
  441. package/out-tsc/src/toast/Toast.js.map +0 -1
  442. package/out-tsc/src/user/TembaUser.js.map +0 -1
  443. package/out-tsc/src/utils/index.js.map +0 -1
  444. package/out-tsc/src/vectoricon/VectorIcon.js.map +0 -1
  445. package/out-tsc/src/vectoricon/index.js.map +0 -1
  446. package/src/charcount/helpers.ts +0 -162
  447. package/src/contacts/helpers.ts +0 -103
  448. package/src/leafletmap/helpers.ts +0 -18
  449. package/src/options/helpers.ts +0 -37
  450. package/src/select/helpers.ts +0 -0
  451. package/src/shadowless/Shadowless.ts +0 -32
  452. package/src/textinput/helpers.ts +0 -11
  453. package/src/tip/helpers.ts +0 -7
  454. /package/out-tsc/src/{alert → display}/Alert.js +0 -0
  455. /package/out-tsc/src/{anchor → display}/Anchor.js +0 -0
  456. /package/out-tsc/src/{button → display}/Button.js +0 -0
  457. /package/out-tsc/src/{chat → display}/Chat.js +0 -0
  458. /package/out-tsc/src/{contacts → display}/ContactName.js +0 -0
  459. /package/out-tsc/src/{contacts → display}/ContactUrn.js +0 -0
  460. /package/out-tsc/src/{dropdown → display}/Dropdown.js +0 -0
  461. /package/out-tsc/src/{label → display}/Label.js +0 -0
  462. /package/out-tsc/src/{lightbox → display}/Lightbox.js +0 -0
  463. /package/out-tsc/src/{loading → display}/Loading.js +0 -0
  464. /package/out-tsc/src/{options → display}/Options.js +0 -0
  465. /package/out-tsc/src/{progress → display}/ProgressBar.js +0 -0
  466. /package/out-tsc/src/{date → display}/TembaDate.js +0 -0
  467. /package/out-tsc/src/{user → display}/TembaUser.js +0 -0
  468. /package/out-tsc/src/{thumbnail → display}/Thumbnail.js +0 -0
  469. /package/out-tsc/src/{toast → display}/Toast.js +0 -0
  470. /package/out-tsc/src/{sms → display/sms}/gsmsplitter.js +0 -0
  471. /package/out-tsc/src/{sms → display/sms}/gsmvalidator.js +0 -0
  472. /package/out-tsc/src/{sms → display/sms}/index.js +0 -0
  473. /package/out-tsc/src/{sms → display/sms}/unicodesplitter.js +0 -0
  474. /package/out-tsc/src/{completion → excellent}/ExcellentParser.js +0 -0
  475. /package/out-tsc/src/{completion → excellent}/helpers.js +0 -0
  476. /package/out-tsc/src/{imagepicker → form}/CroppieCSS.js +0 -0
  477. /package/out-tsc/src/{formfield → form}/FormField.js +0 -0
  478. /package/out-tsc/src/{datepicker → form}/RangePicker.js +0 -0
  479. /package/out-tsc/src/{dialog → layout}/Dialog.js +0 -0
  480. /package/out-tsc/src/{mask → layout}/Mask.js +0 -0
  481. /package/out-tsc/src/{dialog → layout}/Modax.js +0 -0
  482. /package/out-tsc/src/{resizer → layout}/Resizer.js +0 -0
  483. /package/out-tsc/src/{tabpane → layout}/Tab.js +0 -0
  484. /package/out-tsc/src/{tabpane → layout}/TabPane.js +0 -0
  485. /package/out-tsc/src/{contacts → live}/ContactFields.js +0 -0
  486. /package/out-tsc/src/{contacts → live}/ContactNameFetch.js +0 -0
  487. /package/out-tsc/src/{contacts → live}/ContactStoreElement.js +0 -0
  488. /package/out-tsc/src/{fields → live}/FieldManager.js +0 -0
  489. /package/out-tsc/src/{progress → live}/StartProgress.js +0 -0
  490. /package/out-tsc/src/{chart → live}/TembaChart.js +0 -0
  491. /package/src/{vectoricon/index.ts → Icons.ts} +0 -0
  492. /package/src/{alert → display}/Alert.ts +0 -0
  493. /package/src/{anchor → display}/Anchor.ts +0 -0
  494. /package/src/{button → display}/Button.ts +0 -0
  495. /package/src/{chat → display}/Chat.ts +0 -0
  496. /package/src/{contacts → display}/ContactName.ts +0 -0
  497. /package/src/{contacts → display}/ContactUrn.ts +0 -0
  498. /package/src/{dropdown → display}/Dropdown.ts +0 -0
  499. /package/src/{label → display}/Label.ts +0 -0
  500. /package/src/{lightbox → display}/Lightbox.ts +0 -0
  501. /package/src/{loading → display}/Loading.ts +0 -0
  502. /package/src/{options → display}/Options.ts +0 -0
  503. /package/src/{progress → display}/ProgressBar.ts +0 -0
  504. /package/src/{date → display}/TembaDate.ts +0 -0
  505. /package/src/{user → display}/TembaUser.ts +0 -0
  506. /package/src/{toast → display}/Toast.ts +0 -0
  507. /package/src/{sms → display/sms}/gsmsplitter.ts +0 -0
  508. /package/src/{sms → display/sms}/gsmvalidator.ts +0 -0
  509. /package/src/{sms → display/sms}/index.ts +0 -0
  510. /package/src/{sms → display/sms}/unicodesplitter.ts +0 -0
  511. /package/src/{completion → excellent}/ExcellentParser.ts +0 -0
  512. /package/src/{completion → excellent}/helpers.ts +0 -0
  513. /package/src/{imagepicker → form}/CroppieCSS.ts +0 -0
  514. /package/src/{formfield → form}/FormField.ts +0 -0
  515. /package/src/{datepicker → form}/RangePicker.ts +0 -0
  516. /package/src/{mask → layout}/Mask.ts +0 -0
  517. /package/src/{dialog → layout}/Modax.ts +0 -0
  518. /package/src/{resizer → layout}/Resizer.ts +0 -0
  519. /package/src/{tabpane → layout}/Tab.ts +0 -0
  520. /package/src/{tabpane → layout}/TabPane.ts +0 -0
  521. /package/src/{contacts → live}/ContactNameFetch.ts +0 -0
  522. /package/src/{contacts → live}/ContactStoreElement.ts +0 -0
  523. /package/src/{fields → live}/FieldManager.ts +0 -0
  524. /package/src/{progress → live}/StartProgress.ts +0 -0
@@ -0,0 +1,215 @@
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
+ import { stub, restore, useFakeTimers, SinonFakeTimers } from 'sinon';
3
+ import { Editor } from '../src/flow/Editor';
4
+ import { FlowDefinition } from '../src/store/flow-definition';
5
+
6
+ // Register the component
7
+ customElements.define('temba-flow-editor-test', Editor);
8
+
9
+ describe('Flow Editor Self-Routing Prevention', () => {
10
+ let editor: Editor;
11
+ let mockDefinition: FlowDefinition;
12
+ let clock: SinonFakeTimers;
13
+
14
+ beforeEach(() => {
15
+ restore();
16
+
17
+ // Use fake timers to control any async operations
18
+ clock = useFakeTimers({
19
+ shouldAdvanceTime: true,
20
+ advanceTimeDelta: 10
21
+ });
22
+
23
+ // Create a mock flow definition with test nodes and exits
24
+ mockDefinition = {
25
+ uuid: 'test-flow',
26
+ name: 'Test Flow',
27
+ nodes: [
28
+ {
29
+ uuid: 'node-1',
30
+ actions: [],
31
+ exits: [
32
+ { uuid: 'exit-1a', destination_uuid: undefined },
33
+ { uuid: 'exit-1b', destination_uuid: 'node-2' }
34
+ ]
35
+ },
36
+ {
37
+ uuid: 'node-2',
38
+ actions: [],
39
+ exits: [{ uuid: 'exit-2a', destination_uuid: undefined }]
40
+ }
41
+ ],
42
+ localization: {},
43
+ language: 'eng',
44
+ type: 'messaging',
45
+ revision: 1,
46
+ spec_version: '13.1.0',
47
+ _ui: {
48
+ nodes: {
49
+ 'node-1': { position: { left: 100, top: 100 } },
50
+ 'node-2': { position: { left: 300, top: 100 } }
51
+ },
52
+ languages: []
53
+ }
54
+ };
55
+ });
56
+
57
+ afterEach(() => {
58
+ restore();
59
+ if (clock) {
60
+ clock.restore();
61
+ }
62
+ });
63
+
64
+ describe('connection dragging behavior', () => {
65
+ let mockPlumber: any;
66
+
67
+ beforeEach(async () => {
68
+ editor = (await fixture(
69
+ html`<temba-flow-editor-test></temba-flow-editor-test>`
70
+ )) as Editor;
71
+
72
+ // Wait for element to be fully initialized
73
+ await editor.updateComplete;
74
+
75
+ // Mock the plumber
76
+ mockPlumber = {
77
+ connectionDragging: false,
78
+ on: stub(),
79
+ connectIds: stub(),
80
+ repaintEverything: stub()
81
+ };
82
+
83
+ // Set up editor state
84
+ (editor as any).plumber = mockPlumber;
85
+ (editor as any).definition = mockDefinition;
86
+ });
87
+
88
+ it('prevents connection when targeting same node', () => {
89
+ // Set up connection drag state
90
+ (editor as any).sourceId = 'exit-1a';
91
+ (editor as any).sourceNodeId = 'node-1';
92
+ (editor as any).targetId = 'node-1'; // Same node as source
93
+ (editor as any).isValidTarget = false;
94
+
95
+ // Test the validation logic directly without makeConnection
96
+ const shouldConnect =
97
+ (editor as any).sourceId &&
98
+ (editor as any).targetId &&
99
+ (editor as any).isValidTarget;
100
+
101
+ expect(shouldConnect).to.be.false;
102
+ });
103
+
104
+ it('allows connection when targeting different node', () => {
105
+ // Set up connection drag state
106
+ (editor as any).sourceId = 'exit-1a';
107
+ (editor as any).sourceNodeId = 'node-1';
108
+ (editor as any).targetId = 'node-2'; // Different node
109
+ (editor as any).isValidTarget = true;
110
+
111
+ // Test the validation logic directly without makeConnection
112
+ const shouldConnect =
113
+ (editor as any).sourceId &&
114
+ (editor as any).targetId &&
115
+ (editor as any).isValidTarget;
116
+
117
+ expect(shouldConnect).to.be.true;
118
+ });
119
+ });
120
+
121
+ describe('visual feedback during connection dragging', () => {
122
+ let mockTargetNode: HTMLElement;
123
+
124
+ beforeEach(async () => {
125
+ editor = (await fixture(
126
+ html`<temba-flow-editor-test></temba-flow-editor-test>`
127
+ )) as Editor;
128
+
129
+ // Wait for element to be fully initialized
130
+ await editor.updateComplete;
131
+
132
+ // Create mock target node
133
+ mockTargetNode = document.createElement('temba-flow-node');
134
+ mockTargetNode.setAttribute('uuid', 'node-2');
135
+ document.body.appendChild(mockTargetNode);
136
+
137
+ // Mock querySelector to return our mock node
138
+ stub(document, 'querySelector')
139
+ .withArgs('temba-flow-node:hover')
140
+ .returns(mockTargetNode);
141
+ stub(document, 'querySelectorAll')
142
+ .withArgs('temba-flow-node')
143
+ .returns({
144
+ forEach: (callback: (node: Element) => void) =>
145
+ callback(mockTargetNode)
146
+ } as any);
147
+
148
+ // Set up editor state
149
+ (editor as any).plumber = { connectionDragging: true };
150
+ (editor as any).definition = mockDefinition;
151
+ (editor as any).sourceId = 'exit-1a';
152
+ (editor as any).sourceNodeId = 'node-1';
153
+ (editor as any).dragFromNodeId = 'node-1'; // This is the key property used in validation
154
+ });
155
+
156
+ afterEach(() => {
157
+ if (document.body.contains(mockTargetNode)) {
158
+ document.body.removeChild(mockTargetNode);
159
+ }
160
+ });
161
+
162
+ it('adds valid target class when hovering over different node', async () => {
163
+ // Make sure other properties on the editor are correctly set up
164
+ (editor as any).targetId = 'node-2';
165
+ (editor as any).isValidTarget = true;
166
+
167
+ // Simulate mouse move over different node
168
+ (editor as any).handleMouseMove(new MouseEvent('mousemove'));
169
+ await editor.updateComplete;
170
+
171
+ // Allow time for DOM updates
172
+ clock.tick(50);
173
+
174
+ expect(mockTargetNode.classList.contains('connection-target-valid')).to.be
175
+ .true;
176
+ expect(mockTargetNode.classList.contains('connection-target-invalid')).to
177
+ .be.false;
178
+ });
179
+
180
+ it('adds invalid target class when hovering over same node', async () => {
181
+ // Change target to same node as source
182
+ mockTargetNode.setAttribute('uuid', 'node-1');
183
+
184
+ // Make sure other properties on the editor are correctly set up
185
+ (editor as any).targetId = 'node-1';
186
+ (editor as any).isValidTarget = false;
187
+
188
+ // Simulate mouse move over same node
189
+ (editor as any).handleMouseMove(new MouseEvent('mousemove'));
190
+ await editor.updateComplete;
191
+
192
+ // Allow time for DOM updates
193
+ clock.tick(50);
194
+
195
+ expect(mockTargetNode.classList.contains('connection-target-invalid')).to
196
+ .be.true;
197
+ expect(mockTargetNode.classList.contains('connection-target-valid')).to.be
198
+ .false;
199
+ });
200
+
201
+ it('cleans up visual feedback after connection attempt', async () => {
202
+ // Add classes to simulate active state
203
+ mockTargetNode.classList.add('connection-target-valid');
204
+
205
+ // Make connection (which should clean up)
206
+ (editor as any).makeConnection();
207
+ await editor.updateComplete;
208
+
209
+ expect(mockTargetNode.classList.contains('connection-target-valid')).to.be
210
+ .false;
211
+ expect(mockTargetNode.classList.contains('connection-target-invalid')).to
212
+ .be.false;
213
+ });
214
+ });
215
+ });
@@ -1,5 +1,5 @@
1
1
  import { html, fixture, expect } from '@open-wc/testing';
2
- import { FormField } from '../src/formfield/FormField';
2
+ import { FormField } from '../src/form/FormField';
3
3
  import { assertScreenshot, getClip } from './utils.test';
4
4
 
5
5
  describe('temba-field', () => {
@@ -1,5 +1,5 @@
1
1
  import { assert } from '@open-wc/testing';
2
- import { VectorIcon } from '../src/vectoricon/VectorIcon';
2
+ import { VectorIcon } from '../src/display/Icon';
3
3
  import { getComponent } from './utils.test';
4
4
 
5
5
  const TAG = 'temba-icon';
@@ -1,5 +1,5 @@
1
1
  import { html, fixture, expect } from '@open-wc/testing';
2
- import { Checkbox } from '../src/checkbox/Checkbox';
2
+ import { Checkbox } from '../src/form/Checkbox';
3
3
  import { assertScreenshot, getClip } from './utils.test';
4
4
 
5
5
  describe('FormElement markdown integration', () => {
@@ -1,5 +1,5 @@
1
1
  import { assert } from '@open-wc/testing';
2
- import Label from '../src/label/Label';
2
+ import Label from '../src/display/Label';
3
3
  import { assertScreenshot, getClip, getComponent } from './utils.test';
4
4
 
5
5
  const TAG = 'temba-label';
@@ -1,5 +1,5 @@
1
1
  import { fixture, assert } from '@open-wc/testing';
2
- import { Lightbox } from '../src/lightbox/Lightbox';
2
+ import { Lightbox } from '../src/display/Lightbox';
3
3
  import { assertScreenshot } from './utils.test';
4
4
 
5
5
  export const getHTML = () => {
@@ -0,0 +1,162 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { html, render } from 'lit';
3
+ import { markdown, renderMarkdown, RenderMarkdown } from '../src/markdown';
4
+ import { PartType } from 'lit/directive.js';
5
+
6
+ describe('markdown', () => {
7
+ describe('markdown instance', () => {
8
+ it('exports a Remarkable instance', () => {
9
+ expect(markdown).to.exist;
10
+ expect(typeof markdown.render).to.equal('function');
11
+ });
12
+
13
+ it('renders basic markdown', () => {
14
+ const result = markdown.render('# Hello World');
15
+ expect(result).to.include('<h1>Hello World</h1>');
16
+ });
17
+
18
+ it('renders markdown with emphasis', () => {
19
+ const result = markdown.render('**bold** and *italic*');
20
+ expect(result).to.include('<strong>bold</strong>');
21
+ expect(result).to.include('<em>italic</em>');
22
+ });
23
+
24
+ it('renders markdown lists', () => {
25
+ const result = markdown.render('- Item 1\n- Item 2');
26
+ expect(result).to.include('<ul>');
27
+ expect(result).to.include('<li>Item 1</li>');
28
+ expect(result).to.include('<li>Item 2</li>');
29
+ });
30
+
31
+ it('renders markdown links', () => {
32
+ const result = markdown.render('[Link](https://example.com)');
33
+ expect(result).to.include('<a href="https://example.com">Link</a>');
34
+ });
35
+ });
36
+
37
+ describe('RenderMarkdown directive', () => {
38
+ it('throws error for non-child part types', () => {
39
+ const invalidPartInfo = {
40
+ type: PartType.ATTRIBUTE
41
+ };
42
+
43
+ expect(() => new RenderMarkdown(invalidPartInfo as any)).to.throw(
44
+ 'renderMarkdown only supports child expressions'
45
+ );
46
+ });
47
+
48
+ it('creates directive for child part type', () => {
49
+ const validPartInfo = {
50
+ type: PartType.CHILD
51
+ };
52
+
53
+ expect(() => new RenderMarkdown(validPartInfo as any)).to.not.throw;
54
+ });
55
+
56
+ it('renders markdown content', () => {
57
+ const validPartInfo = {
58
+ type: PartType.CHILD
59
+ };
60
+
61
+ const directive = new RenderMarkdown(validPartInfo as any);
62
+ const result = directive.render('# Test Header');
63
+
64
+ // The result should be a TemplateResult
65
+ expect(result).to.exist;
66
+ expect(result.strings).to.exist;
67
+ });
68
+
69
+ it('updates correctly', () => {
70
+ const validPartInfo = {
71
+ type: PartType.CHILD
72
+ };
73
+
74
+ const directive = new RenderMarkdown(validPartInfo as any);
75
+ const mockPart = {} as any;
76
+
77
+ const result = directive.update(mockPart, ['# Updated Content']);
78
+
79
+ // Should return the same as render
80
+ expect(result).to.exist;
81
+ expect(result.strings).to.exist;
82
+ });
83
+ });
84
+
85
+ describe('renderMarkdown function', () => {
86
+ it('creates a directive that can be used in templates', () => {
87
+ const template = html`${renderMarkdown('# Test')}`;
88
+
89
+ // Should create a valid template
90
+ expect(template).to.exist;
91
+ expect(template.strings).to.exist;
92
+ });
93
+
94
+ it('renders markdown when used in a template', () => {
95
+ const container = document.createElement('div');
96
+ const template = html`${renderMarkdown('# Hello World')}`;
97
+
98
+ render(template, container);
99
+
100
+ // Check that the markdown was rendered to HTML
101
+ expect(container.innerHTML).to.include('<h1>Hello World</h1>');
102
+ });
103
+
104
+ it('handles empty markdown', () => {
105
+ const container = document.createElement('div');
106
+ const template = html`${renderMarkdown('')}`;
107
+
108
+ render(template, container);
109
+
110
+ // Should not throw - Lit may add HTML comments for template placeholders
111
+ expect(() => render(template, container)).to.not.throw;
112
+ });
113
+
114
+ it('handles markdown with special characters', () => {
115
+ const container = document.createElement('div');
116
+ const markdownWithSpecialChars =
117
+ '**Bold** text with <script>alert("xss")</script>';
118
+ const template = html`${renderMarkdown(markdownWithSpecialChars)}`;
119
+
120
+ render(template, container);
121
+
122
+ // Should render the markdown but the script tag should be escaped/handled
123
+ expect(container.innerHTML).to.include('<strong>Bold</strong>');
124
+ // The script tag should be rendered as text or escaped
125
+ expect(container.innerHTML).to.include('script');
126
+ });
127
+
128
+ it('renders complex markdown structures', () => {
129
+ const complexMarkdown = `
130
+ # Main Header
131
+
132
+ ## Sub Header
133
+
134
+ This is a paragraph with **bold** and *italic* text.
135
+
136
+ - List item 1
137
+ - List item 2
138
+ - Nested item
139
+
140
+ [A link](https://example.com)
141
+
142
+ \`\`\`
143
+ code block
144
+ \`\`\`
145
+ `;
146
+
147
+ const container = document.createElement('div');
148
+ const template = html`${renderMarkdown(complexMarkdown)}`;
149
+
150
+ render(template, container);
151
+
152
+ expect(container.innerHTML).to.include('<h1>Main Header</h1>');
153
+ expect(container.innerHTML).to.include('<h2>Sub Header</h2>');
154
+ expect(container.innerHTML).to.include('<strong>bold</strong>');
155
+ expect(container.innerHTML).to.include('<em>italic</em>');
156
+ expect(container.innerHTML).to.include('<ul>');
157
+ expect(container.innerHTML).to.include(
158
+ '<a href="https://example.com">A link</a>'
159
+ );
160
+ });
161
+ });
162
+ });
@@ -2,7 +2,7 @@ import { assert, expect } from '@open-wc/testing';
2
2
 
3
3
  import { TembaMenu } from '../src/list/TembaMenu';
4
4
  import { assertScreenshot, getClip, getComponent } from './utils.test';
5
- import { extractInitials } from '../src/utils/index';
5
+ import { extractInitials } from '../src/utils';
6
6
 
7
7
  const TAG = 'temba-menu';
8
8
  const getMenu = async (attrs: any = {}, width = 0) => {
@@ -1,7 +1,7 @@
1
1
  import { fixture, expect, assert } from '@open-wc/testing';
2
2
  import { useFakeTimers } from 'sinon';
3
- import { Button } from '../src/button/Button';
4
- import { Modax } from '../src/dialog/Modax';
3
+ import { Button } from '../src/display/Button';
4
+ import { Modax } from '../src/layout/Modax';
5
5
  import { CustomEventType } from '../src/interfaces';
6
6
  import { assertScreenshot, getClip, mockPOST } from './utils.test';
7
7
 
@@ -0,0 +1,56 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { addCustomElement } from '../temba-modules';
3
+
4
+ describe('temba-modules', () => {
5
+ describe('addCustomElement', () => {
6
+ it('defines a custom element when not already defined', () => {
7
+ // Create a mock component class
8
+ class TestComponent extends HTMLElement {}
9
+
10
+ // Ensure the element is not already defined
11
+ const elementName = 'test-custom-element-' + Date.now();
12
+ expect(window.customElements.get(elementName)).to.be.undefined;
13
+
14
+ // Define the element
15
+ addCustomElement(elementName, TestComponent);
16
+
17
+ // Verify it's now defined
18
+ expect(window.customElements.get(elementName)).to.equal(TestComponent);
19
+ });
20
+
21
+ it('does not redefine a custom element when already defined', () => {
22
+ // Create mock component classes
23
+ class FirstComponent extends HTMLElement {}
24
+ class SecondComponent extends HTMLElement {}
25
+
26
+ const elementName = 'test-existing-element-' + Date.now();
27
+
28
+ // Define the element first time
29
+ addCustomElement(elementName, FirstComponent);
30
+ expect(window.customElements.get(elementName)).to.equal(FirstComponent);
31
+
32
+ // Try to define again with different component
33
+ addCustomElement(elementName, SecondComponent);
34
+
35
+ // Should still be the first component
36
+ expect(window.customElements.get(elementName)).to.equal(FirstComponent);
37
+ expect(window.customElements.get(elementName)).to.not.equal(
38
+ SecondComponent
39
+ );
40
+ });
41
+
42
+ it('handles multiple different elements', () => {
43
+ class ComponentA extends HTMLElement {}
44
+ class ComponentB extends HTMLElement {}
45
+
46
+ const elementA = 'test-element-a-' + Date.now();
47
+ const elementB = 'test-element-b-' + Date.now();
48
+
49
+ addCustomElement(elementA, ComponentA);
50
+ addCustomElement(elementB, ComponentB);
51
+
52
+ expect(window.customElements.get(elementA)).to.equal(ComponentA);
53
+ expect(window.customElements.get(elementB)).to.equal(ComponentB);
54
+ });
55
+ });
56
+ });
@@ -1,5 +1,5 @@
1
1
  import { fixture, assert } from '@open-wc/testing';
2
- import { Omnibox } from '../src/omnibox/Omnibox';
2
+ import { Omnibox } from '../src/form/select/Omnibox';
3
3
  import { assertScreenshot, getClip, openAndClick } from './utils.test';
4
4
  import { useFakeTimers, spy } from 'sinon';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { fixture } from '@open-wc/testing';
2
- import { Options } from '../src/options/Options';
2
+ import { Options } from '../src/display/Options';
3
3
  import { assertScreenshot, getClip, getHTML } from './utils.test';
4
4
 
5
5
  const colors = [
@@ -1,7 +1,13 @@
1
1
  import { fixture, expect, assert } from '@open-wc/testing';
2
- import { RangePicker } from '../src/datepicker/RangePicker';
3
- import { assertScreenshot, getAttributes, getClip } from './utils.test';
2
+ import { RangePicker } from '../src/form/RangePicker';
3
+ import {
4
+ assertScreenshot,
5
+ getAttributes,
6
+ getClip,
7
+ mockNow
8
+ } from './utils.test';
4
9
  import { DateTime } from 'luxon';
10
+ import { SinonStub } from 'sinon';
5
11
 
6
12
  export const getRangePickerHTML = (attrs: any = {}) => {
7
13
  return `<temba-range-picker ${getAttributes(attrs)}></temba-range-picker>`;
@@ -16,6 +22,15 @@ export const createRangePicker = async (def: string) => {
16
22
  };
17
23
 
18
24
  describe('temba-range-picker', () => {
25
+ let mockedNow: SinonStub;
26
+ beforeEach(() => {
27
+ mockedNow = mockNow('2022-12-02T21:00:00.000000');
28
+ });
29
+
30
+ afterEach(() => {
31
+ mockedNow.restore();
32
+ });
33
+
19
34
  it('can create a range picker', async () => {
20
35
  const picker: RangePicker = await createRangePicker(getRangePickerHTML());
21
36
  assert.instanceOf(picker, RangePicker);