@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
@@ -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);