@nyaruka/temba-components 0.129.2 → 0.129.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (773) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.github/workflows/build.yml +141 -8
  3. package/CHANGELOG.md +40 -0
  4. package/README.md +6 -0
  5. package/check-coverage.js +133 -0
  6. package/demo/data/flows/sample-flow.json +158 -128
  7. package/demo/field-config-demo.html +135 -0
  8. package/dist/temba-components.js +1750 -751
  9. package/dist/temba-components.js.map +1 -1
  10. package/docs/ActionEditor-Migration.md +118 -0
  11. package/generate-coverage-badge.sh +69 -0
  12. package/out-tsc/src/{vectoricon/index.js → Icons.js} +1 -1
  13. package/out-tsc/src/Icons.js.map +1 -0
  14. package/out-tsc/src/display/Alert.js.map +1 -0
  15. package/out-tsc/src/display/Anchor.js.map +1 -0
  16. package/out-tsc/src/display/Button.js.map +1 -0
  17. package/out-tsc/src/{charcount → display}/CharCount.js +159 -2
  18. package/out-tsc/src/display/CharCount.js.map +1 -0
  19. package/out-tsc/src/display/Chat.js.map +1 -0
  20. package/out-tsc/src/display/ContactName.js.map +1 -0
  21. package/out-tsc/src/display/ContactUrn.js.map +1 -0
  22. package/out-tsc/src/display/Dropdown.js.map +1 -0
  23. package/out-tsc/src/{vectoricon/VectorIcon.js → display/Icon.js} +2 -2
  24. package/out-tsc/src/display/Icon.js.map +1 -0
  25. package/out-tsc/src/display/Label.js.map +1 -0
  26. package/out-tsc/src/{leafletmap → display}/LeafletMap.js +16 -1
  27. package/out-tsc/src/display/LeafletMap.js.map +1 -0
  28. package/out-tsc/src/display/Lightbox.js.map +1 -0
  29. package/out-tsc/src/{loading → display}/Loading.js.map +1 -1
  30. package/out-tsc/src/{options → display}/Options.js.map +1 -1
  31. package/out-tsc/src/display/ProgressBar.js.map +1 -0
  32. package/out-tsc/src/display/TembaDate.js.map +1 -0
  33. package/out-tsc/src/display/TembaUser.js.map +1 -0
  34. package/out-tsc/src/display/Thumbnail.js.map +1 -0
  35. package/out-tsc/src/{tip → display}/Tip.js +1 -2
  36. package/out-tsc/src/display/Tip.js.map +1 -0
  37. package/out-tsc/src/display/Toast.js.map +1 -0
  38. package/out-tsc/src/display/sms/gsmsplitter.js.map +1 -0
  39. package/out-tsc/src/display/sms/gsmvalidator.js.map +1 -0
  40. package/out-tsc/src/display/sms/index.js.map +1 -0
  41. package/out-tsc/src/display/sms/unicodesplitter.js.map +1 -0
  42. package/out-tsc/src/events.js +2 -0
  43. package/out-tsc/src/events.js.map +1 -0
  44. package/out-tsc/src/excellent/ExcellentParser.js.map +1 -0
  45. package/out-tsc/src/excellent/helpers.js.map +1 -0
  46. package/out-tsc/src/flow/CanvasNode.js +861 -0
  47. package/out-tsc/src/flow/CanvasNode.js.map +1 -0
  48. package/out-tsc/src/flow/Editor.js +640 -143
  49. package/out-tsc/src/flow/Editor.js.map +1 -1
  50. package/out-tsc/src/flow/NodeEditor.js +1200 -0
  51. package/out-tsc/src/flow/NodeEditor.js.map +1 -0
  52. package/out-tsc/src/flow/Plumber.js +148 -74
  53. package/out-tsc/src/flow/Plumber.js.map +1 -1
  54. package/out-tsc/src/flow/StickyNote.js +153 -9
  55. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  56. package/out-tsc/src/flow/actions/add_contact_groups.js +40 -0
  57. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -0
  58. package/out-tsc/src/flow/actions/add_contact_urn.js +16 -0
  59. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -0
  60. package/out-tsc/src/flow/actions/add_input_labels.js +11 -0
  61. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -0
  62. package/out-tsc/src/flow/actions/call_classifier.js +11 -0
  63. package/out-tsc/src/flow/actions/call_classifier.js.map +1 -0
  64. package/out-tsc/src/flow/actions/call_llm.js +11 -0
  65. package/out-tsc/src/flow/actions/call_llm.js.map +1 -0
  66. package/out-tsc/src/flow/actions/call_resthook.js +11 -0
  67. package/out-tsc/src/flow/actions/call_resthook.js.map +1 -0
  68. package/out-tsc/src/flow/actions/call_webhook.js +122 -0
  69. package/out-tsc/src/flow/actions/call_webhook.js.map +1 -0
  70. package/out-tsc/src/flow/actions/enter_flow.js +14 -0
  71. package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
  72. package/out-tsc/src/flow/actions/open_ticket.js +11 -0
  73. package/out-tsc/src/flow/actions/open_ticket.js.map +1 -0
  74. package/out-tsc/src/flow/actions/play_audio.js +11 -0
  75. package/out-tsc/src/flow/actions/play_audio.js.map +1 -0
  76. package/out-tsc/src/flow/actions/remove_contact_groups.js +62 -0
  77. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -0
  78. package/out-tsc/src/flow/actions/request_optin.js +11 -0
  79. package/out-tsc/src/flow/actions/request_optin.js.map +1 -0
  80. package/out-tsc/src/flow/actions/say_msg.js +11 -0
  81. package/out-tsc/src/flow/actions/say_msg.js.map +1 -0
  82. package/out-tsc/src/flow/actions/send_broadcast.js +33 -0
  83. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -0
  84. package/out-tsc/src/flow/actions/send_email.js +56 -0
  85. package/out-tsc/src/flow/actions/send_email.js.map +1 -0
  86. package/out-tsc/src/flow/actions/send_msg.js +55 -0
  87. package/out-tsc/src/flow/actions/send_msg.js.map +1 -0
  88. package/out-tsc/src/flow/actions/set_contact_channel.js +12 -0
  89. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -0
  90. package/out-tsc/src/flow/actions/set_contact_field.js +12 -0
  91. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -0
  92. package/out-tsc/src/flow/actions/set_contact_language.js +10 -0
  93. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -0
  94. package/out-tsc/src/flow/actions/set_contact_name.js +10 -0
  95. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -0
  96. package/out-tsc/src/flow/actions/set_contact_status.js +10 -0
  97. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -0
  98. package/out-tsc/src/flow/actions/set_run_result.js +10 -0
  99. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -0
  100. package/out-tsc/src/flow/actions/split_by_expression_example.js +77 -0
  101. package/out-tsc/src/flow/actions/split_by_expression_example.js.map +1 -0
  102. package/out-tsc/src/flow/actions/start_session.js +11 -0
  103. package/out-tsc/src/flow/actions/start_session.js.map +1 -0
  104. package/out-tsc/src/flow/actions/transfer_airtime.js +11 -0
  105. package/out-tsc/src/flow/actions/transfer_airtime.js.map +1 -0
  106. package/out-tsc/src/flow/config.js +88 -123
  107. package/out-tsc/src/flow/config.js.map +1 -1
  108. package/out-tsc/src/flow/nodes/execute_actions.js +4 -0
  109. package/out-tsc/src/flow/nodes/execute_actions.js.map +1 -0
  110. package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -0
  111. package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -0
  112. package/out-tsc/src/flow/nodes/split_by_contact_field.js +7 -0
  113. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -0
  114. package/out-tsc/src/flow/nodes/split_by_expression.js +7 -0
  115. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -0
  116. package/out-tsc/src/flow/nodes/split_by_groups.js +7 -0
  117. package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -0
  118. package/out-tsc/src/flow/nodes/split_by_random.js +10 -0
  119. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -0
  120. package/out-tsc/src/flow/nodes/split_by_run_result.js +7 -0
  121. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -0
  122. package/out-tsc/src/flow/nodes/split_by_scheme.js +7 -0
  123. package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -0
  124. package/out-tsc/src/flow/nodes/split_by_subflow.js +9 -0
  125. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -0
  126. package/out-tsc/src/flow/nodes/split_by_webhook.js +18 -0
  127. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -0
  128. package/out-tsc/src/flow/nodes/wait_for_audio.js +7 -0
  129. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
  130. package/out-tsc/src/flow/nodes/wait_for_digits.js +7 -0
  131. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -0
  132. package/out-tsc/src/flow/nodes/wait_for_image.js +7 -0
  133. package/out-tsc/src/flow/nodes/wait_for_image.js.map +1 -0
  134. package/out-tsc/src/flow/nodes/wait_for_location.js +7 -0
  135. package/out-tsc/src/flow/nodes/wait_for_location.js.map +1 -0
  136. package/out-tsc/src/flow/nodes/wait_for_menu.js +7 -0
  137. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -0
  138. package/out-tsc/src/flow/nodes/wait_for_response.js +7 -0
  139. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -0
  140. package/out-tsc/src/flow/nodes/wait_for_video.js +7 -0
  141. package/out-tsc/src/flow/nodes/wait_for_video.js.map +1 -0
  142. package/out-tsc/src/flow/types.js +79 -0
  143. package/out-tsc/src/flow/types.js.map +1 -0
  144. package/out-tsc/src/flow/utils.js +65 -0
  145. package/out-tsc/src/flow/utils.js.map +1 -0
  146. package/out-tsc/src/form/ArrayEditor.js +199 -0
  147. package/out-tsc/src/form/ArrayEditor.js.map +1 -0
  148. package/out-tsc/src/form/BaseListEditor.js +128 -0
  149. package/out-tsc/src/form/BaseListEditor.js.map +1 -0
  150. package/out-tsc/src/{checkbox → form}/Checkbox.js +19 -4
  151. package/out-tsc/src/form/Checkbox.js.map +1 -0
  152. package/out-tsc/src/{colorpicker → form}/ColorPicker.js +1 -1
  153. package/out-tsc/src/form/ColorPicker.js.map +1 -0
  154. package/out-tsc/src/{completion → form}/Completion.js +8 -2
  155. package/out-tsc/src/form/Completion.js.map +1 -0
  156. package/out-tsc/src/{compose → form}/Compose.js +1 -1
  157. package/out-tsc/src/form/Compose.js.map +1 -0
  158. package/out-tsc/src/{contactsearch → form}/ContactSearch.js +2 -2
  159. package/out-tsc/src/form/ContactSearch.js.map +1 -0
  160. package/out-tsc/src/form/CroppieCSS.js.map +1 -0
  161. package/out-tsc/src/{datepicker → form}/DatePicker.js +1 -1
  162. package/out-tsc/src/form/DatePicker.js.map +1 -0
  163. package/out-tsc/src/{FormElement.js → form/FormElement.js} +1 -1
  164. package/out-tsc/src/form/FormElement.js.map +1 -0
  165. package/out-tsc/src/form/FormField.js +243 -0
  166. package/out-tsc/src/form/FormField.js.map +1 -0
  167. package/out-tsc/src/{imagepicker → form}/ImagePicker.js +2 -2
  168. package/out-tsc/src/form/ImagePicker.js.map +1 -0
  169. package/out-tsc/src/form/KeyValueEditor.js +223 -0
  170. package/out-tsc/src/form/KeyValueEditor.js.map +1 -0
  171. package/out-tsc/src/{mediapicker → form}/MediaPicker.js +1 -1
  172. package/out-tsc/src/form/MediaPicker.js.map +1 -0
  173. package/out-tsc/src/form/RangePicker.js.map +1 -0
  174. package/out-tsc/src/{slider → form}/TembaSlider.js +1 -1
  175. package/out-tsc/src/form/TembaSlider.js.map +1 -0
  176. package/out-tsc/src/{templates → form}/TemplateEditor.js +1 -1
  177. package/out-tsc/src/form/TemplateEditor.js.map +1 -0
  178. package/out-tsc/src/{textinput → form}/TextInput.js +3 -3
  179. package/out-tsc/src/form/TextInput.js.map +1 -0
  180. package/out-tsc/src/{omnibox → form/select}/Omnibox.js +2 -2
  181. package/out-tsc/src/form/select/Omnibox.js.map +1 -0
  182. package/out-tsc/src/{select → form/select}/PopupSelect.js +1 -1
  183. package/out-tsc/src/form/select/PopupSelect.js.map +1 -0
  184. package/out-tsc/src/{select → form/select}/Select.js +157 -113
  185. package/out-tsc/src/form/select/Select.js.map +1 -0
  186. package/out-tsc/src/{select → form/select}/UserSelect.js +1 -1
  187. package/out-tsc/src/form/select/UserSelect.js.map +1 -0
  188. package/out-tsc/src/{select → form/select}/WorkspaceSelect.js +1 -1
  189. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -0
  190. package/out-tsc/src/interfaces.js +7 -0
  191. package/out-tsc/src/interfaces.js.map +1 -1
  192. package/out-tsc/src/layout/Dialog.js.map +1 -0
  193. package/out-tsc/src/layout/Mask.js.map +1 -0
  194. package/out-tsc/src/{dialog → layout}/Modax.js.map +1 -1
  195. package/out-tsc/src/layout/Resizer.js.map +1 -0
  196. package/out-tsc/src/layout/Tab.js.map +1 -0
  197. package/out-tsc/src/layout/TabPane.js.map +1 -0
  198. package/out-tsc/src/list/NotificationList.js +1 -1
  199. package/out-tsc/src/list/NotificationList.js.map +1 -1
  200. package/out-tsc/src/list/RunList.js +1 -1
  201. package/out-tsc/src/list/RunList.js.map +1 -1
  202. package/out-tsc/src/list/ShortcutList.js.map +1 -1
  203. package/out-tsc/src/list/TembaMenu.js +1 -1
  204. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  205. package/out-tsc/src/list/TicketList.js +1 -1
  206. package/out-tsc/src/list/TicketList.js.map +1 -1
  207. package/out-tsc/src/{aliaseditor → live}/AliasEditor.js +1 -1
  208. package/out-tsc/src/live/AliasEditor.js.map +1 -0
  209. package/out-tsc/src/{contacts → live}/ContactBadges.js +1 -1
  210. package/out-tsc/src/live/ContactBadges.js.map +1 -0
  211. package/out-tsc/src/{contacts → live}/ContactChat.js +80 -78
  212. package/out-tsc/src/live/ContactChat.js.map +1 -0
  213. package/out-tsc/src/{contacts → live}/ContactDetails.js +1 -1
  214. package/out-tsc/src/live/ContactDetails.js.map +1 -0
  215. package/out-tsc/src/{contacts → live}/ContactFieldEditor.js +2 -2
  216. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -0
  217. package/out-tsc/src/live/ContactFields.js.map +1 -0
  218. package/out-tsc/src/live/ContactNameFetch.js.map +1 -0
  219. package/out-tsc/src/{contacts → live}/ContactNotepad.js +1 -1
  220. package/out-tsc/src/{contacts → live}/ContactNotepad.js.map +1 -1
  221. package/out-tsc/src/{contacts → live}/ContactPending.js +1 -1
  222. package/out-tsc/src/live/ContactPending.js.map +1 -0
  223. package/out-tsc/src/live/ContactStoreElement.js.map +1 -0
  224. package/out-tsc/src/live/FieldManager.js.map +1 -0
  225. package/out-tsc/src/live/StartProgress.js.map +1 -0
  226. package/out-tsc/src/live/TembaChart.js.map +1 -0
  227. package/out-tsc/src/store/AppState.js +54 -24
  228. package/out-tsc/src/store/AppState.js.map +1 -1
  229. package/out-tsc/src/store/Store.js +1 -1
  230. package/out-tsc/src/store/Store.js.map +1 -1
  231. package/out-tsc/src/{utils/index.js → utils.js} +22 -1
  232. package/out-tsc/src/utils.js.map +1 -0
  233. package/out-tsc/src/webchat/WebChat.js +1 -1
  234. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  235. package/out-tsc/temba-components.js +2 -2
  236. package/out-tsc/temba-components.js.map +1 -1
  237. package/out-tsc/temba-modules.js +63 -56
  238. package/out-tsc/temba-modules.js.map +1 -1
  239. package/out-tsc/temba-webchat.js +2 -2
  240. package/out-tsc/temba-webchat.js.map +1 -1
  241. package/out-tsc/test/ActionHelper.js +116 -0
  242. package/out-tsc/test/ActionHelper.js.map +1 -0
  243. package/out-tsc/test/actions/add_contact_groups.test.js +66 -0
  244. package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -0
  245. package/out-tsc/test/actions/remove_contact_groups.test.js +226 -0
  246. package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -0
  247. package/out-tsc/test/actions/send_email.test.js +160 -0
  248. package/out-tsc/test/actions/send_email.test.js.map +1 -0
  249. package/out-tsc/test/actions/send_msg.test.js +95 -0
  250. package/out-tsc/test/actions/send_msg.test.js.map +1 -0
  251. package/out-tsc/test/temba-action-editing-integration.test.js +183 -0
  252. package/out-tsc/test/temba-action-editing-integration.test.js.map +1 -0
  253. package/out-tsc/test/temba-alert.test.js +1 -1
  254. package/out-tsc/test/temba-alert.test.js.map +1 -1
  255. package/out-tsc/test/temba-appstate-language.test.js +90 -0
  256. package/out-tsc/test/temba-appstate-language.test.js.map +1 -1
  257. package/out-tsc/test/temba-charcount.test.js.map +1 -1
  258. package/out-tsc/test/temba-chart.test.js +1 -1
  259. package/out-tsc/test/temba-chart.test.js.map +1 -1
  260. package/out-tsc/test/temba-checkbox.test.js +1 -1
  261. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  262. package/out-tsc/test/temba-color-picker.test.js +1 -1
  263. package/out-tsc/test/temba-color-picker.test.js.map +1 -1
  264. package/out-tsc/test/temba-completion.test.js +1 -1
  265. package/out-tsc/test/temba-completion.test.js.map +1 -1
  266. package/out-tsc/test/temba-compose.test.js +1 -1
  267. package/out-tsc/test/temba-compose.test.js.map +1 -1
  268. package/out-tsc/test/temba-contact-badges.test.js +1 -1
  269. package/out-tsc/test/temba-contact-badges.test.js.map +1 -1
  270. package/out-tsc/test/temba-contact-chat.test.js +3 -1
  271. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  272. package/out-tsc/test/temba-contact-details.test.js +1 -1
  273. package/out-tsc/test/temba-contact-details.test.js.map +1 -1
  274. package/out-tsc/test/temba-contact-fields.test.js +1 -1
  275. package/out-tsc/test/temba-contact-fields.test.js.map +1 -1
  276. package/out-tsc/test/temba-contact-search.test.js +1 -1
  277. package/out-tsc/test/temba-contact-search.test.js.map +1 -1
  278. package/out-tsc/test/temba-date.test.js +5 -1
  279. package/out-tsc/test/temba-date.test.js.map +1 -1
  280. package/out-tsc/test/temba-datepicker.test.js +1 -1
  281. package/out-tsc/test/temba-datepicker.test.js.map +1 -1
  282. package/out-tsc/test/temba-dialog.test.js +1 -1
  283. package/out-tsc/test/temba-dialog.test.js.map +1 -1
  284. package/out-tsc/test/temba-dropdown.test.js +1 -1
  285. package/out-tsc/test/temba-dropdown.test.js.map +1 -1
  286. package/out-tsc/test/temba-excellent-helpers.test.js +316 -0
  287. package/out-tsc/test/temba-excellent-helpers.test.js.map +1 -0
  288. package/out-tsc/test/temba-field-config.test.js +133 -0
  289. package/out-tsc/test/temba-field-config.test.js.map +1 -0
  290. package/out-tsc/test/temba-field-manager.test.js.map +1 -1
  291. package/out-tsc/test/temba-flow-editor-node.test.js +426 -13
  292. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  293. package/out-tsc/test/temba-flow-editor.test.js +185 -0
  294. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  295. package/out-tsc/test/temba-flow-plumber-connections.test.js +113 -0
  296. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -0
  297. package/out-tsc/test/temba-flow-plumber.test.js +73 -93
  298. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  299. package/out-tsc/test/temba-flow-self-routing.test.js +172 -0
  300. package/out-tsc/test/temba-flow-self-routing.test.js.map +1 -0
  301. package/out-tsc/test/temba-formfield.test.js.map +1 -1
  302. package/out-tsc/test/temba-icon.test.js +1 -1
  303. package/out-tsc/test/temba-icon.test.js.map +1 -1
  304. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  305. package/out-tsc/test/temba-label.test.js +1 -1
  306. package/out-tsc/test/temba-label.test.js.map +1 -1
  307. package/out-tsc/test/temba-lightbox.test.js +1 -1
  308. package/out-tsc/test/temba-lightbox.test.js.map +1 -1
  309. package/out-tsc/test/temba-markdown.test.js +127 -0
  310. package/out-tsc/test/temba-markdown.test.js.map +1 -0
  311. package/out-tsc/test/temba-menu.test.js +1 -1
  312. package/out-tsc/test/temba-menu.test.js.map +1 -1
  313. package/out-tsc/test/temba-modax.test.js +1 -1
  314. package/out-tsc/test/temba-modax.test.js.map +1 -1
  315. package/out-tsc/test/temba-modules.test.js +47 -0
  316. package/out-tsc/test/temba-modules.test.js.map +1 -0
  317. package/out-tsc/test/temba-node-editor.test.js +283 -0
  318. package/out-tsc/test/temba-node-editor.test.js.map +1 -0
  319. package/out-tsc/test/temba-omnibox.test.js +1 -1
  320. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  321. package/out-tsc/test/temba-options.test.js.map +1 -1
  322. package/out-tsc/test/temba-range-picker.test.js +9 -2
  323. package/out-tsc/test/temba-range-picker.test.js.map +1 -1
  324. package/out-tsc/test/temba-rapid-element.test.js +273 -0
  325. package/out-tsc/test/temba-rapid-element.test.js.map +1 -0
  326. package/out-tsc/test/temba-resize-element.test.js +85 -0
  327. package/out-tsc/test/temba-resize-element.test.js.map +1 -0
  328. package/out-tsc/test/temba-select.test.js +87 -2
  329. package/out-tsc/test/temba-select.test.js.map +1 -1
  330. package/out-tsc/test/temba-slider.test.js.map +1 -1
  331. package/out-tsc/test/temba-sticky-note.test.js +194 -0
  332. package/out-tsc/test/temba-sticky-note.test.js.map +1 -0
  333. package/out-tsc/test/temba-template-editor.test.js.map +1 -1
  334. package/out-tsc/test/temba-textinput.test.js +1 -1
  335. package/out-tsc/test/temba-textinput.test.js.map +1 -1
  336. package/out-tsc/test/temba-tip.test.js +1 -1
  337. package/out-tsc/test/temba-tip.test.js.map +1 -1
  338. package/out-tsc/test/temba-toast.test.js +1 -1
  339. package/out-tsc/test/temba-toast.test.js.map +1 -1
  340. package/out-tsc/test/temba-utils-index.test.js +1 -1
  341. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  342. package/out-tsc/test/temba-utils-uuid.test.js +38 -0
  343. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -0
  344. package/out-tsc/test/temba-webchat.test.js +28 -12
  345. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  346. package/out-tsc/test/utils.test.js +2 -6
  347. package/out-tsc/test/utils.test.js.map +1 -1
  348. package/package.json +18 -9
  349. package/rollup.components.mjs +1 -1
  350. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  351. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  352. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  353. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  354. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  355. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  356. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  357. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  358. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  359. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  360. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  361. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  362. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  363. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  364. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  365. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  366. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  367. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  368. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  369. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  370. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  371. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  372. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  373. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  374. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  375. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  376. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  377. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  378. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  379. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  380. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  381. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  382. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  383. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  384. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  385. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  386. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  387. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  388. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  389. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  390. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  391. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  392. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  393. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  394. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  395. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  396. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  397. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  398. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  399. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  400. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  401. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  402. package/screenshots/truth/datepicker/range-picker-all.png +0 -0
  403. package/screenshots/truth/datepicker/range-picker-button-states.png +0 -0
  404. package/screenshots/truth/datepicker/range-picker-default.png +0 -0
  405. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  406. package/screenshots/truth/datepicker/range-picker-initial-values.png +0 -0
  407. package/screenshots/truth/datepicker/range-picker-week.png +0 -0
  408. package/screenshots/truth/datepicker/range-picker-year.png +0 -0
  409. package/screenshots/truth/editor/router.png +0 -0
  410. package/screenshots/truth/editor/send_msg.png +0 -0
  411. package/screenshots/truth/editor/set_contact_language.png +0 -0
  412. package/screenshots/truth/editor/set_contact_name.png +0 -0
  413. package/screenshots/truth/editor/set_run_result.png +0 -0
  414. package/screenshots/truth/editor/wait.png +0 -0
  415. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  416. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  417. package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
  418. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  419. package/screenshots/truth/sticky-note/blue-color.png +0 -0
  420. package/screenshots/truth/sticky-note/blue.png +0 -0
  421. package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
  422. package/screenshots/truth/sticky-note/default.png +0 -0
  423. package/screenshots/truth/sticky-note/gray-color.png +0 -0
  424. package/screenshots/truth/sticky-note/gray.png +0 -0
  425. package/screenshots/truth/sticky-note/green-color.png +0 -0
  426. package/screenshots/truth/sticky-note/green.png +0 -0
  427. package/screenshots/truth/sticky-note/pink-color.png +0 -0
  428. package/screenshots/truth/sticky-note/pink.png +0 -0
  429. package/screenshots/truth/sticky-note/yellow-color.png +0 -0
  430. package/screenshots/truth/sticky-note/yellow.png +0 -0
  431. package/src/{charcount → display}/CharCount.ts +164 -2
  432. package/src/{vectoricon/VectorIcon.ts → display/Icon.ts} +1 -1
  433. package/src/{leafletmap → display}/LeafletMap.ts +19 -1
  434. package/src/{thumbnail → display}/Thumbnail.ts +1 -1
  435. package/src/{tip → display}/Tip.ts +1 -2
  436. package/src/events.ts +108 -0
  437. package/src/flow/CanvasNode.ts +1009 -0
  438. package/src/flow/Editor.ts +795 -169
  439. package/src/flow/NodeEditor.ts +1443 -0
  440. package/src/flow/Plumber.ts +177 -79
  441. package/src/flow/StickyNote.ts +165 -9
  442. package/src/flow/actions/add_contact_groups.ts +42 -0
  443. package/src/flow/actions/add_contact_urn.ts +17 -0
  444. package/src/flow/actions/add_input_labels.ts +12 -0
  445. package/src/flow/actions/call_classifier.ts +12 -0
  446. package/src/flow/actions/call_llm.ts +12 -0
  447. package/src/flow/actions/call_resthook.ts +12 -0
  448. package/src/flow/actions/call_webhook.ts +133 -0
  449. package/src/flow/actions/enter_flow.ts +15 -0
  450. package/src/flow/actions/open_ticket.ts +12 -0
  451. package/src/flow/actions/play_audio.ts +12 -0
  452. package/src/flow/actions/remove_contact_groups.ts +66 -0
  453. package/src/flow/actions/request_optin.ts +12 -0
  454. package/src/flow/actions/say_msg.ts +12 -0
  455. package/src/flow/actions/send_broadcast.ts +35 -0
  456. package/src/flow/actions/send_email.ts +60 -0
  457. package/src/flow/actions/send_msg.ts +58 -0
  458. package/src/flow/actions/set_contact_channel.ts +13 -0
  459. package/src/flow/actions/set_contact_field.ts +13 -0
  460. package/src/flow/actions/set_contact_language.ts +11 -0
  461. package/src/flow/actions/set_contact_name.ts +11 -0
  462. package/src/flow/actions/set_contact_status.ts +11 -0
  463. package/src/flow/actions/set_run_result.ts +11 -0
  464. package/src/flow/actions/split_by_expression_example.ts +88 -0
  465. package/src/flow/actions/start_session.ts +12 -0
  466. package/src/flow/actions/transfer_airtime.ts +12 -0
  467. package/src/flow/config.ts +93 -136
  468. package/src/flow/nodes/execute_actions.ts +5 -0
  469. package/src/flow/nodes/split_by_airtime.ts +9 -0
  470. package/src/flow/nodes/split_by_contact_field.ts +7 -0
  471. package/src/flow/nodes/split_by_expression.ts +7 -0
  472. package/src/flow/nodes/split_by_groups.ts +7 -0
  473. package/src/flow/nodes/split_by_random.ts +10 -0
  474. package/src/flow/nodes/split_by_run_result.ts +7 -0
  475. package/src/flow/nodes/split_by_scheme.ts +7 -0
  476. package/src/flow/nodes/split_by_subflow.ts +9 -0
  477. package/src/flow/nodes/split_by_webhook.ts +19 -0
  478. package/src/flow/nodes/wait_for_audio.ts +7 -0
  479. package/src/flow/nodes/wait_for_digits.ts +7 -0
  480. package/src/flow/nodes/wait_for_image.ts +7 -0
  481. package/src/flow/nodes/wait_for_location.ts +7 -0
  482. package/src/flow/nodes/wait_for_menu.ts +7 -0
  483. package/src/flow/nodes/wait_for_response.ts +7 -0
  484. package/src/flow/nodes/wait_for_video.ts +7 -0
  485. package/src/flow/types.ts +352 -0
  486. package/src/flow/utils.ts +76 -0
  487. package/src/form/ArrayEditor.ts +240 -0
  488. package/src/form/BaseListEditor.ts +177 -0
  489. package/src/{checkbox → form}/Checkbox.ts +24 -5
  490. package/src/{colorpicker → form}/ColorPicker.ts +2 -2
  491. package/src/{completion → form}/Completion.ts +9 -3
  492. package/src/{compose → form}/Compose.ts +7 -7
  493. package/src/{contactsearch → form}/ContactSearch.ts +6 -6
  494. package/src/{datepicker → form}/DatePicker.ts +1 -1
  495. package/src/{FormElement.ts → form/FormElement.ts} +1 -1
  496. package/src/form/FormField.ts +238 -0
  497. package/src/{imagepicker → form}/ImagePicker.ts +2 -2
  498. package/src/form/KeyValueEditor.ts +251 -0
  499. package/src/{mediapicker → form}/MediaPicker.ts +1 -1
  500. package/src/{slider → form}/TembaSlider.ts +1 -1
  501. package/src/{templates → form}/TemplateEditor.ts +2 -2
  502. package/src/{textinput → form}/TextInput.ts +5 -5
  503. package/src/{omnibox → form/select}/Omnibox.ts +2 -2
  504. package/src/{select → form/select}/PopupSelect.ts +1 -1
  505. package/src/{select → form/select}/Select.ts +207 -152
  506. package/src/{select → form/select}/UserSelect.ts +1 -1
  507. package/src/{select → form/select}/WorkspaceSelect.ts +1 -1
  508. package/src/interfaces.ts +8 -2
  509. package/src/{dialog → layout}/Dialog.ts +1 -1
  510. package/src/list/NotificationList.ts +2 -2
  511. package/src/list/RunList.ts +3 -3
  512. package/src/list/ShortcutList.ts +1 -1
  513. package/src/list/TembaMenu.ts +2 -2
  514. package/src/list/TicketList.ts +1 -1
  515. package/src/{aliaseditor → live}/AliasEditor.ts +3 -3
  516. package/src/{contacts → live}/ContactBadges.ts +1 -1
  517. package/src/{contacts → live}/ContactChat.ts +120 -104
  518. package/src/{contacts → live}/ContactDetails.ts +1 -1
  519. package/src/{contacts → live}/ContactFieldEditor.ts +4 -4
  520. package/src/{contacts → live}/ContactFields.ts +1 -1
  521. package/src/{contacts → live}/ContactNotepad.ts +1 -1
  522. package/src/{contacts → live}/ContactPending.ts +1 -1
  523. package/src/{chart → live}/TembaChart.ts +1 -1
  524. package/src/store/AppState.ts +75 -29
  525. package/src/store/Store.ts +1 -1
  526. package/src/store/flow-definition.d.ts +131 -1
  527. package/src/{utils/index.ts → utils.ts} +26 -10
  528. package/src/webchat/WebChat.ts +1 -1
  529. package/static/api/contacts.json +30 -0
  530. package/static/api/groups.json +4 -426
  531. package/static/api/locations.json +24 -0
  532. package/static/api/media.json +5 -0
  533. package/static/api/optins.json +16 -0
  534. package/static/api/orgs.json +13 -0
  535. package/static/api/topics.json +21 -0
  536. package/static/api/users.json +26 -0
  537. package/static/css/temba-components.css +4 -6
  538. package/svg.js +1 -4
  539. package/temba-components.ts +2 -2
  540. package/temba-modules.ts +63 -56
  541. package/temba-webchat.ts +2 -2
  542. package/test/ActionHelper.ts +142 -0
  543. package/test/actions/add_contact_groups.test.ts +89 -0
  544. package/test/actions/remove_contact_groups.test.ts +265 -0
  545. package/test/actions/send_email.test.ts +214 -0
  546. package/test/actions/send_msg.test.ts +130 -0
  547. package/test/temba-action-editing-integration.test.ts +240 -0
  548. package/test/temba-alert.test.ts +1 -1
  549. package/test/temba-appstate-language.test.ts +108 -0
  550. package/test/temba-charcount.test.ts +1 -1
  551. package/test/temba-chart.test.ts +1 -1
  552. package/test/temba-checkbox.test.ts +2 -2
  553. package/test/temba-color-picker.test.ts +1 -1
  554. package/test/temba-completion.test.ts +1 -1
  555. package/test/temba-compose.test.ts +1 -1
  556. package/test/temba-contact-badges.test.ts +1 -1
  557. package/test/temba-contact-chat.test.ts +6 -4
  558. package/test/temba-contact-details.test.ts +1 -1
  559. package/test/temba-contact-fields.test.ts +1 -1
  560. package/test/temba-contact-search.test.ts +2 -2
  561. package/test/temba-date.test.ts +8 -3
  562. package/test/temba-datepicker.test.ts +1 -1
  563. package/test/temba-dialog.test.ts +1 -1
  564. package/test/temba-dropdown.test.ts +1 -1
  565. package/test/temba-excellent-helpers.test.ts +417 -0
  566. package/test/temba-field-config.test.ts +152 -0
  567. package/test/temba-field-manager.test.ts +2 -2
  568. package/test/temba-flow-editor-node.test.ts +551 -16
  569. package/test/temba-flow-editor.test.ts +224 -0
  570. package/test/temba-flow-editor.test.ts.backup +563 -0
  571. package/test/temba-flow-plumber-connections.test.ts +142 -0
  572. package/test/temba-flow-plumber.test.ts +83 -120
  573. package/test/temba-flow-self-routing.test.ts +215 -0
  574. package/test/temba-formfield.test.ts +1 -1
  575. package/test/temba-icon.test.ts +1 -1
  576. package/test/temba-integration-markdown.test.ts +1 -1
  577. package/test/temba-label.test.ts +1 -1
  578. package/test/temba-lightbox.test.ts +1 -1
  579. package/test/temba-markdown.test.ts +162 -0
  580. package/test/temba-menu.test.ts +1 -1
  581. package/test/temba-modax.test.ts +2 -2
  582. package/test/temba-modules.test.ts +56 -0
  583. package/test/temba-node-editor.test.ts +353 -0
  584. package/test/temba-omnibox.test.ts +1 -1
  585. package/test/temba-options.test.ts +1 -1
  586. package/test/temba-range-picker.test.ts +17 -2
  587. package/test/temba-rapid-element.test.ts +341 -0
  588. package/test/temba-resize-element.test.ts +104 -0
  589. package/test/temba-select.test.ts +129 -2
  590. package/test/temba-slider.test.ts +1 -1
  591. package/test/temba-sticky-note.test.ts +281 -0
  592. package/test/temba-template-editor.test.ts +1 -1
  593. package/test/temba-textinput.test.ts +1 -1
  594. package/test/temba-tip.test.ts +1 -1
  595. package/test/temba-toast.test.ts +1 -1
  596. package/test/temba-utils-index.test.ts +1 -1
  597. package/test/temba-utils-index.test.ts.backup +1737 -0
  598. package/test/temba-utils-uuid.test.ts +48 -0
  599. package/test/temba-webchat.test.ts +30 -12
  600. package/test/utils.test.ts +5 -9
  601. package/test-assets/contacts/history.json +11 -33
  602. package/web-dev-server.config.mjs +35 -1
  603. package/demo/sticky-note-demo.html +0 -155
  604. package/out-tsc/src/FormElement.js.map +0 -1
  605. package/out-tsc/src/alert/Alert.js.map +0 -1
  606. package/out-tsc/src/aliaseditor/AliasEditor.js.map +0 -1
  607. package/out-tsc/src/anchor/Anchor.js.map +0 -1
  608. package/out-tsc/src/button/Button.js.map +0 -1
  609. package/out-tsc/src/charcount/CharCount.js.map +0 -1
  610. package/out-tsc/src/charcount/helpers.js +0 -159
  611. package/out-tsc/src/charcount/helpers.js.map +0 -1
  612. package/out-tsc/src/chart/TembaChart.js.map +0 -1
  613. package/out-tsc/src/chat/Chat.js.map +0 -1
  614. package/out-tsc/src/checkbox/Checkbox.js.map +0 -1
  615. package/out-tsc/src/colorpicker/ColorPicker.js.map +0 -1
  616. package/out-tsc/src/completion/Completion.js.map +0 -1
  617. package/out-tsc/src/completion/ExcellentParser.js.map +0 -1
  618. package/out-tsc/src/completion/helpers.js.map +0 -1
  619. package/out-tsc/src/compose/Compose.js.map +0 -1
  620. package/out-tsc/src/contacts/ContactBadges.js.map +0 -1
  621. package/out-tsc/src/contacts/ContactChat.js.map +0 -1
  622. package/out-tsc/src/contacts/ContactDetails.js.map +0 -1
  623. package/out-tsc/src/contacts/ContactFieldEditor.js.map +0 -1
  624. package/out-tsc/src/contacts/ContactFields.js.map +0 -1
  625. package/out-tsc/src/contacts/ContactName.js.map +0 -1
  626. package/out-tsc/src/contacts/ContactNameFetch.js.map +0 -1
  627. package/out-tsc/src/contacts/ContactPending.js.map +0 -1
  628. package/out-tsc/src/contacts/ContactStoreElement.js.map +0 -1
  629. package/out-tsc/src/contacts/ContactUrn.js.map +0 -1
  630. package/out-tsc/src/contacts/events.js +0 -65
  631. package/out-tsc/src/contacts/events.js.map +0 -1
  632. package/out-tsc/src/contacts/helpers.js +0 -77
  633. package/out-tsc/src/contacts/helpers.js.map +0 -1
  634. package/out-tsc/src/contactsearch/ContactSearch.js.map +0 -1
  635. package/out-tsc/src/date/TembaDate.js.map +0 -1
  636. package/out-tsc/src/datepicker/DatePicker.js.map +0 -1
  637. package/out-tsc/src/datepicker/RangePicker.js.map +0 -1
  638. package/out-tsc/src/dialog/Dialog.js.map +0 -1
  639. package/out-tsc/src/dropdown/Dropdown.js.map +0 -1
  640. package/out-tsc/src/fields/FieldManager.js.map +0 -1
  641. package/out-tsc/src/flow/EditorNode.js +0 -291
  642. package/out-tsc/src/flow/EditorNode.js.map +0 -1
  643. package/out-tsc/src/flow/render.js +0 -41
  644. package/out-tsc/src/flow/render.js.map +0 -1
  645. package/out-tsc/src/formfield/FormField.js +0 -144
  646. package/out-tsc/src/formfield/FormField.js.map +0 -1
  647. package/out-tsc/src/imagepicker/CroppieCSS.js.map +0 -1
  648. package/out-tsc/src/imagepicker/ImagePicker.js.map +0 -1
  649. package/out-tsc/src/label/Label.js.map +0 -1
  650. package/out-tsc/src/leafletmap/LeafletMap.js.map +0 -1
  651. package/out-tsc/src/leafletmap/helpers.js +0 -17
  652. package/out-tsc/src/leafletmap/helpers.js.map +0 -1
  653. package/out-tsc/src/lightbox/Lightbox.js.map +0 -1
  654. package/out-tsc/src/mask/Mask.js.map +0 -1
  655. package/out-tsc/src/mediapicker/MediaPicker.js.map +0 -1
  656. package/out-tsc/src/omnibox/Omnibox.js.map +0 -1
  657. package/out-tsc/src/options/helpers.js +0 -28
  658. package/out-tsc/src/options/helpers.js.map +0 -1
  659. package/out-tsc/src/progress/ProgressBar.js.map +0 -1
  660. package/out-tsc/src/progress/StartProgress.js.map +0 -1
  661. package/out-tsc/src/resizer/Resizer.js.map +0 -1
  662. package/out-tsc/src/select/PopupSelect.js.map +0 -1
  663. package/out-tsc/src/select/Select.js.map +0 -1
  664. package/out-tsc/src/select/UserSelect.js.map +0 -1
  665. package/out-tsc/src/select/WorkspaceSelect.js.map +0 -1
  666. package/out-tsc/src/select/helpers.js +0 -1
  667. package/out-tsc/src/select/helpers.js.map +0 -1
  668. package/out-tsc/src/shadowless/Shadowless.js +0 -33
  669. package/out-tsc/src/shadowless/Shadowless.js.map +0 -1
  670. package/out-tsc/src/slider/TembaSlider.js.map +0 -1
  671. package/out-tsc/src/sms/gsmsplitter.js.map +0 -1
  672. package/out-tsc/src/sms/gsmvalidator.js.map +0 -1
  673. package/out-tsc/src/sms/index.js.map +0 -1
  674. package/out-tsc/src/sms/unicodesplitter.js.map +0 -1
  675. package/out-tsc/src/tabpane/Tab.js.map +0 -1
  676. package/out-tsc/src/tabpane/TabPane.js.map +0 -1
  677. package/out-tsc/src/templates/TemplateEditor.js.map +0 -1
  678. package/out-tsc/src/textinput/TextInput.js.map +0 -1
  679. package/out-tsc/src/textinput/helpers.js +0 -12
  680. package/out-tsc/src/textinput/helpers.js.map +0 -1
  681. package/out-tsc/src/thumbnail/Thumbnail.js.map +0 -1
  682. package/out-tsc/src/tip/Tip.js.map +0 -1
  683. package/out-tsc/src/tip/helpers.js +0 -7
  684. package/out-tsc/src/tip/helpers.js.map +0 -1
  685. package/out-tsc/src/toast/Toast.js.map +0 -1
  686. package/out-tsc/src/user/TembaUser.js.map +0 -1
  687. package/out-tsc/src/utils/index.js.map +0 -1
  688. package/out-tsc/src/vectoricon/VectorIcon.js.map +0 -1
  689. package/out-tsc/src/vectoricon/index.js.map +0 -1
  690. package/out-tsc/test/temba-flow-render.test.js +0 -171
  691. package/out-tsc/test/temba-flow-render.test.js.map +0 -1
  692. package/src/charcount/helpers.ts +0 -162
  693. package/src/contacts/events.ts +0 -210
  694. package/src/contacts/helpers.ts +0 -103
  695. package/src/flow/EditorNode.ts +0 -318
  696. package/src/flow/render.ts +0 -56
  697. package/src/formfield/FormField.ts +0 -134
  698. package/src/leafletmap/helpers.ts +0 -18
  699. package/src/options/helpers.ts +0 -37
  700. package/src/select/helpers.ts +0 -0
  701. package/src/shadowless/Shadowless.ts +0 -32
  702. package/src/textinput/helpers.ts +0 -11
  703. package/src/tip/helpers.ts +0 -7
  704. package/test/temba-flow-render.test.ts +0 -220
  705. /package/out-tsc/src/{alert → display}/Alert.js +0 -0
  706. /package/out-tsc/src/{anchor → display}/Anchor.js +0 -0
  707. /package/out-tsc/src/{button → display}/Button.js +0 -0
  708. /package/out-tsc/src/{chat → display}/Chat.js +0 -0
  709. /package/out-tsc/src/{contacts → display}/ContactName.js +0 -0
  710. /package/out-tsc/src/{contacts → display}/ContactUrn.js +0 -0
  711. /package/out-tsc/src/{dropdown → display}/Dropdown.js +0 -0
  712. /package/out-tsc/src/{label → display}/Label.js +0 -0
  713. /package/out-tsc/src/{lightbox → display}/Lightbox.js +0 -0
  714. /package/out-tsc/src/{loading → display}/Loading.js +0 -0
  715. /package/out-tsc/src/{options → display}/Options.js +0 -0
  716. /package/out-tsc/src/{progress → display}/ProgressBar.js +0 -0
  717. /package/out-tsc/src/{date → display}/TembaDate.js +0 -0
  718. /package/out-tsc/src/{user → display}/TembaUser.js +0 -0
  719. /package/out-tsc/src/{thumbnail → display}/Thumbnail.js +0 -0
  720. /package/out-tsc/src/{toast → display}/Toast.js +0 -0
  721. /package/out-tsc/src/{sms → display/sms}/gsmsplitter.js +0 -0
  722. /package/out-tsc/src/{sms → display/sms}/gsmvalidator.js +0 -0
  723. /package/out-tsc/src/{sms → display/sms}/index.js +0 -0
  724. /package/out-tsc/src/{sms → display/sms}/unicodesplitter.js +0 -0
  725. /package/out-tsc/src/{completion → excellent}/ExcellentParser.js +0 -0
  726. /package/out-tsc/src/{completion → excellent}/helpers.js +0 -0
  727. /package/out-tsc/src/{imagepicker → form}/CroppieCSS.js +0 -0
  728. /package/out-tsc/src/{datepicker → form}/RangePicker.js +0 -0
  729. /package/out-tsc/src/{dialog → layout}/Dialog.js +0 -0
  730. /package/out-tsc/src/{mask → layout}/Mask.js +0 -0
  731. /package/out-tsc/src/{dialog → layout}/Modax.js +0 -0
  732. /package/out-tsc/src/{resizer → layout}/Resizer.js +0 -0
  733. /package/out-tsc/src/{tabpane → layout}/Tab.js +0 -0
  734. /package/out-tsc/src/{tabpane → layout}/TabPane.js +0 -0
  735. /package/out-tsc/src/{contacts → live}/ContactFields.js +0 -0
  736. /package/out-tsc/src/{contacts → live}/ContactNameFetch.js +0 -0
  737. /package/out-tsc/src/{contacts → live}/ContactStoreElement.js +0 -0
  738. /package/out-tsc/src/{fields → live}/FieldManager.js +0 -0
  739. /package/out-tsc/src/{progress → live}/StartProgress.js +0 -0
  740. /package/out-tsc/src/{chart → live}/TembaChart.js +0 -0
  741. /package/src/{vectoricon/index.ts → Icons.ts} +0 -0
  742. /package/src/{alert → display}/Alert.ts +0 -0
  743. /package/src/{anchor → display}/Anchor.ts +0 -0
  744. /package/src/{button → display}/Button.ts +0 -0
  745. /package/src/{chat → display}/Chat.ts +0 -0
  746. /package/src/{contacts → display}/ContactName.ts +0 -0
  747. /package/src/{contacts → display}/ContactUrn.ts +0 -0
  748. /package/src/{dropdown → display}/Dropdown.ts +0 -0
  749. /package/src/{label → display}/Label.ts +0 -0
  750. /package/src/{lightbox → display}/Lightbox.ts +0 -0
  751. /package/src/{loading → display}/Loading.ts +0 -0
  752. /package/src/{options → display}/Options.ts +0 -0
  753. /package/src/{progress → display}/ProgressBar.ts +0 -0
  754. /package/src/{date → display}/TembaDate.ts +0 -0
  755. /package/src/{user → display}/TembaUser.ts +0 -0
  756. /package/src/{toast → display}/Toast.ts +0 -0
  757. /package/src/{sms → display/sms}/gsmsplitter.ts +0 -0
  758. /package/src/{sms → display/sms}/gsmvalidator.ts +0 -0
  759. /package/src/{sms → display/sms}/index.ts +0 -0
  760. /package/src/{sms → display/sms}/unicodesplitter.ts +0 -0
  761. /package/src/{completion → excellent}/ExcellentParser.ts +0 -0
  762. /package/src/{completion → excellent}/helpers.ts +0 -0
  763. /package/src/{imagepicker → form}/CroppieCSS.ts +0 -0
  764. /package/src/{datepicker → form}/RangePicker.ts +0 -0
  765. /package/src/{mask → layout}/Mask.ts +0 -0
  766. /package/src/{dialog → layout}/Modax.ts +0 -0
  767. /package/src/{resizer → layout}/Resizer.ts +0 -0
  768. /package/src/{tabpane → layout}/Tab.ts +0 -0
  769. /package/src/{tabpane → layout}/TabPane.ts +0 -0
  770. /package/src/{contacts → live}/ContactNameFetch.ts +0 -0
  771. /package/src/{contacts → live}/ContactStoreElement.ts +0 -0
  772. /package/src/{fields → live}/FieldManager.ts +0 -0
  773. /package/src/{progress → live}/StartProgress.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"temba-datepicker.test.js","sourceRoot":"","sources":["../../test/temba-datepicker.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { fixture, expect, assert } from '@open-wc/testing';\nimport { DatePicker } from '../src/datepicker/DatePicker';\nimport { assertScreenshot, getAttributes, getClip } from './utils.test';\n\nexport const getPickerHTML = (attrs: any = {}) => {\n return `<temba-datepicker ${getAttributes(attrs)}></temba-datepicker>`;\n};\n\nexport const createPicker = async (def: string) => {\n const parentNode = document.createElement('div');\n parentNode.setAttribute('style', 'width: 400px;');\n parentNode.id = 'parent';\n const picker: DatePicker = await fixture(def, { parentNode });\n return picker;\n};\n\ndescribe('temba-datepicker', () => {\n it('can create a date picker', async () => {\n const picker: DatePicker = await createPicker(getPickerHTML());\n assert.instanceOf(picker, DatePicker);\n await assertScreenshot('datepicker/date', getClip(picker));\n });\n\n it('can create a datetime picker', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ time: true })\n );\n assert.instanceOf(picker, DatePicker);\n // await assertScreenshot('datepicker/datetime', getClip(picker));\n });\n\n it('can be initialized with an iso date', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20T14:00Z', time: true })\n );\n\n // default should be browser locale, which for our tests is UTC\n // expect(picker.timezone).to.equal('UTC');\n\n // we should display in the current locale\n // await assertScreenshot('datepicker/initial-value', getClip(picker));\n\n // but our value should be our original value as a full iso date\n expect(picker.value).is.equal('2020-01-20T14:00:00.000Z');\n });\n\n it('can be initialized with a timezone', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({\n value: '2020-01-20T14:00Z',\n timezone: 'America/New_York',\n time: true\n })\n );\n\n expect(picker.timezone).to.equal('America/New_York');\n\n // we should display in the eastern timezone\n await assertScreenshot('datepicker/initial-timezone', getClip(picker));\n expect(picker.value).to.equal('2020-01-20T14:00:00.000Z');\n });\n\n it('can be updated via keyboard', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20T14:00Z', id: 'picker', time: true })\n );\n\n // click into the picker and update the date\n await click('#picker');\n await typeInto('#picker', '01202024', false);\n\n // click away to update\n picker.blur();\n\n expect(picker.value).to.equal('2024-01-20T14:00:00.000Z');\n // await assertScreenshot('datepicker/updated-keyboard', getClip(picker));\n });\n\n it('can update date via keyboard', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20', id: 'picker' })\n );\n\n // click into the picker and update the date\n await click('#picker');\n await typeInto('#picker', '12252024', false);\n\n // click away to update\n picker.blur();\n\n expect(picker.value).to.equal('2024-12-25');\n await assertScreenshot('datepicker/updated-keyboard-date', getClip(picker));\n });\n\n it('truncates time on dates', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20 00:00:00' })\n );\n\n expect(picker.value).to.equal('2020-01-20');\n await assertScreenshot('datepicker/date-truncated-time', getClip(picker));\n });\n});\n"]}
1
+ {"version":3,"file":"temba-datepicker.test.js","sourceRoot":"","sources":["../../test/temba-datepicker.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { fixture, expect, assert } from '@open-wc/testing';\nimport { DatePicker } from '../src/form/DatePicker';\nimport { assertScreenshot, getAttributes, getClip } from './utils.test';\n\nexport const getPickerHTML = (attrs: any = {}) => {\n return `<temba-datepicker ${getAttributes(attrs)}></temba-datepicker>`;\n};\n\nexport const createPicker = async (def: string) => {\n const parentNode = document.createElement('div');\n parentNode.setAttribute('style', 'width: 400px;');\n parentNode.id = 'parent';\n const picker: DatePicker = await fixture(def, { parentNode });\n return picker;\n};\n\ndescribe('temba-datepicker', () => {\n it('can create a date picker', async () => {\n const picker: DatePicker = await createPicker(getPickerHTML());\n assert.instanceOf(picker, DatePicker);\n await assertScreenshot('datepicker/date', getClip(picker));\n });\n\n it('can create a datetime picker', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ time: true })\n );\n assert.instanceOf(picker, DatePicker);\n // await assertScreenshot('datepicker/datetime', getClip(picker));\n });\n\n it('can be initialized with an iso date', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20T14:00Z', time: true })\n );\n\n // default should be browser locale, which for our tests is UTC\n // expect(picker.timezone).to.equal('UTC');\n\n // we should display in the current locale\n // await assertScreenshot('datepicker/initial-value', getClip(picker));\n\n // but our value should be our original value as a full iso date\n expect(picker.value).is.equal('2020-01-20T14:00:00.000Z');\n });\n\n it('can be initialized with a timezone', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({\n value: '2020-01-20T14:00Z',\n timezone: 'America/New_York',\n time: true\n })\n );\n\n expect(picker.timezone).to.equal('America/New_York');\n\n // we should display in the eastern timezone\n await assertScreenshot('datepicker/initial-timezone', getClip(picker));\n expect(picker.value).to.equal('2020-01-20T14:00:00.000Z');\n });\n\n it('can be updated via keyboard', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20T14:00Z', id: 'picker', time: true })\n );\n\n // click into the picker and update the date\n await click('#picker');\n await typeInto('#picker', '01202024', false);\n\n // click away to update\n picker.blur();\n\n expect(picker.value).to.equal('2024-01-20T14:00:00.000Z');\n // await assertScreenshot('datepicker/updated-keyboard', getClip(picker));\n });\n\n it('can update date via keyboard', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20', id: 'picker' })\n );\n\n // click into the picker and update the date\n await click('#picker');\n await typeInto('#picker', '12252024', false);\n\n // click away to update\n picker.blur();\n\n expect(picker.value).to.equal('2024-12-25');\n await assertScreenshot('datepicker/updated-keyboard-date', getClip(picker));\n });\n\n it('truncates time on dates', async () => {\n const picker: DatePicker = await createPicker(\n getPickerHTML({ value: '2020-01-20 00:00:00' })\n );\n\n expect(picker.value).to.equal('2020-01-20');\n await assertScreenshot('datepicker/date-truncated-time', getClip(picker));\n });\n});\n"]}
@@ -1,6 +1,6 @@
1
1
  import { assert, expect, fixture } from '@open-wc/testing';
2
2
  import * as sinon from 'sinon';
3
- import { Dialog } from '../src/dialog/Dialog';
3
+ import { Dialog } from '../src/layout/Dialog';
4
4
  import { assertScreenshot, getClip } from './utils.test';
5
5
  const getDialogClip = (dialog) => {
6
6
  return getClip(dialog.shadowRoot.querySelector('.dialog-container'));
@@ -1 +1 @@
1
- {"version":3,"file":"temba-dialog.test.js","sourceRoot":"","sources":["../../test/temba-dialog.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, expect, fixture } from '@open-wc/testing';\nimport * as sinon from 'sinon';\nimport { Dialog } from '../src/dialog/Dialog';\nimport { assertScreenshot, getClip } from './utils.test';\n\nconst getDialogClip = (dialog: Dialog) => {\n return getClip(\n dialog.shadowRoot.querySelector('.dialog-container') as HTMLElement\n );\n};\n\nconst getDialogHTML = (hideOnClick = false) => {\n return `\n <temba-dialog header=\"Hello Dialog\" ${hideOnClick ? 'hideOnClick' : ''}>\n <input name=\"comment\" type=\"text\" style=\"margin: 10px\"/>\n </temba-dialog>\n `;\n};\n\nconst open = async (dialog: Dialog) => {\n const clock = sinon.useFakeTimers();\n dialog.open = true;\n\n await dialog.updateComplete;\n\n // our dialog will animate onto the screen\n clock.tick(400);\n await dialog.updateComplete;\n\n // gain focus for first text input\n clock.tick(100);\n await dialog.updateComplete;\n\n clock.restore();\n};\n\nconst close = async (dialog: Dialog) => {\n const clock = sinon.useFakeTimers();\n dialog.open = false;\n await dialog.updateComplete;\n\n // tick forward for close to complete\n clock.tick(400);\n\n clock.restore();\n};\n\ndescribe('temba-dialog', () => {\n it('can be created', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n assert.instanceOf(dialog, Dialog);\n });\n\n it('can be opened', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n expect(dialog.ready).to.equal(true);\n });\n\n it('can be closed by attribute', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n expect(dialog.ready).to.equal(true);\n dialog.open = false;\n });\n\n it('can be canceled', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n expect(dialog.ready).to.equal(true);\n\n dialog.getCancelButton().click();\n expect(dialog.open).to.equal(false);\n });\n\n it('restricts and restores background scrolling', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n const body = document.querySelector('body');\n expect(body.style.position).to.equal('fixed');\n\n await close(dialog);\n dialog.getCancelButton().click();\n await dialog.updateComplete;\n expect(body.style.position).to.equal('');\n });\n\n it('focuses the first text input', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n\n const input = dialog.querySelector('input');\n expect(document.activeElement).to.equal(input);\n await assertScreenshot('dialog/focused', getDialogClip(dialog));\n });\n\n it('hides on click', async () => {\n const dialog: Dialog = await fixture(getDialogHTML(true));\n await open(dialog);\n\n const mask: HTMLDivElement =\n dialog.shadowRoot.querySelector('#dialog-mask');\n mask.click();\n\n await dialog.updateComplete;\n expect(dialog.open).to.equal(false);\n });\n\n it('hides on escape', async () => {\n const dialog: Dialog = await fixture(getDialogHTML(true));\n await open(dialog);\n expect(dialog.open).to.equal(true);\n\n // simulate the escape key\n const element = dialog.shadowRoot.querySelector('.dialog-container');\n element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));\n expect(dialog.open).to.equal(false);\n });\n});\n"]}
1
+ {"version":3,"file":"temba-dialog.test.js","sourceRoot":"","sources":["../../test/temba-dialog.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, expect, fixture } from '@open-wc/testing';\nimport * as sinon from 'sinon';\nimport { Dialog } from '../src/layout/Dialog';\nimport { assertScreenshot, getClip } from './utils.test';\n\nconst getDialogClip = (dialog: Dialog) => {\n return getClip(\n dialog.shadowRoot.querySelector('.dialog-container') as HTMLElement\n );\n};\n\nconst getDialogHTML = (hideOnClick = false) => {\n return `\n <temba-dialog header=\"Hello Dialog\" ${hideOnClick ? 'hideOnClick' : ''}>\n <input name=\"comment\" type=\"text\" style=\"margin: 10px\"/>\n </temba-dialog>\n `;\n};\n\nconst open = async (dialog: Dialog) => {\n const clock = sinon.useFakeTimers();\n dialog.open = true;\n\n await dialog.updateComplete;\n\n // our dialog will animate onto the screen\n clock.tick(400);\n await dialog.updateComplete;\n\n // gain focus for first text input\n clock.tick(100);\n await dialog.updateComplete;\n\n clock.restore();\n};\n\nconst close = async (dialog: Dialog) => {\n const clock = sinon.useFakeTimers();\n dialog.open = false;\n await dialog.updateComplete;\n\n // tick forward for close to complete\n clock.tick(400);\n\n clock.restore();\n};\n\ndescribe('temba-dialog', () => {\n it('can be created', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n assert.instanceOf(dialog, Dialog);\n });\n\n it('can be opened', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n expect(dialog.ready).to.equal(true);\n });\n\n it('can be closed by attribute', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n expect(dialog.ready).to.equal(true);\n dialog.open = false;\n });\n\n it('can be canceled', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n expect(dialog.ready).to.equal(true);\n\n dialog.getCancelButton().click();\n expect(dialog.open).to.equal(false);\n });\n\n it('restricts and restores background scrolling', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n const body = document.querySelector('body');\n expect(body.style.position).to.equal('fixed');\n\n await close(dialog);\n dialog.getCancelButton().click();\n await dialog.updateComplete;\n expect(body.style.position).to.equal('');\n });\n\n it('focuses the first text input', async () => {\n const dialog: Dialog = await fixture(getDialogHTML());\n await open(dialog);\n\n const input = dialog.querySelector('input');\n expect(document.activeElement).to.equal(input);\n await assertScreenshot('dialog/focused', getDialogClip(dialog));\n });\n\n it('hides on click', async () => {\n const dialog: Dialog = await fixture(getDialogHTML(true));\n await open(dialog);\n\n const mask: HTMLDivElement =\n dialog.shadowRoot.querySelector('#dialog-mask');\n mask.click();\n\n await dialog.updateComplete;\n expect(dialog.open).to.equal(false);\n });\n\n it('hides on escape', async () => {\n const dialog: Dialog = await fixture(getDialogHTML(true));\n await open(dialog);\n expect(dialog.open).to.equal(true);\n\n // simulate the escape key\n const element = dialog.shadowRoot.querySelector('.dialog-container');\n element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));\n expect(dialog.open).to.equal(false);\n });\n});\n"]}
@@ -1,5 +1,5 @@
1
1
  import { assert, expect } from '@open-wc/testing';
2
- import { Dropdown } from '../src/dropdown/Dropdown';
2
+ import { Dropdown } from '../src/display/Dropdown';
3
3
  import { assertScreenshot, getClip, getComponent } from './utils.test';
4
4
  const TAG = 'temba-dropdown';
5
5
  // Helper function to wait for stable rendering
@@ -1 +1 @@
1
- {"version":3,"file":"temba-dropdown.test.js","sourceRoot":"","sources":["../../test/temba-dropdown.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, expect } from '@open-wc/testing';\nimport { Dropdown } from '../src/dropdown/Dropdown';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\nconst TAG = 'temba-dropdown';\n\n// Helper function to wait for stable rendering\nconst waitForStableRender = async (dropdown: Dropdown, timeoutMs = 100) => {\n await dropdown.updateComplete;\n // Double wait to ensure any async positioning is complete\n await new Promise((resolve) => setTimeout(resolve, timeoutMs));\n await dropdown.updateComplete;\n};\n\n// Helper function to get expanded clip that includes dropdown content when open\nconst getDropdownClip = (dropdown: Dropdown) => {\n if (!dropdown.open) {\n // If closed, use regular clipping\n return getClip(dropdown);\n }\n\n // For open dropdowns, include the positioned dropdown content\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const dropdownBounds = dropdownDiv.getBoundingClientRect();\n const componentBounds = dropdown.getBoundingClientRect();\n\n // If dropdown content has no meaningful size, fall back to regular clip\n if (dropdownBounds.width < 10 || dropdownBounds.height < 10) {\n return getClip(dropdown);\n }\n\n // Create a clipping region that includes both the component and the dropdown content\n const minX = Math.min(componentBounds.x, dropdownBounds.x);\n const minY = Math.min(componentBounds.y, dropdownBounds.y);\n const maxX = Math.max(componentBounds.right, dropdownBounds.right);\n const maxY = Math.max(componentBounds.bottom, dropdownBounds.bottom);\n\n // Clamp to reasonable bounds to avoid excessive screenshot sizes\n const x = Math.max(0, minX - 10);\n const y = Math.max(0, minY - 10);\n const width = Math.min(1000, maxX - minX + 20);\n const height = Math.min(800, maxY - minY + 20);\n\n return { x, y, width, height };\n};\n\nconst getDropdown = async (\n attrs: {\n open?: boolean;\n dormant?: boolean;\n arrowSize?: number;\n margin?: number;\n mask?: boolean;\n } = {},\n toggleSlot = '<button slot=\"toggle\">Toggle</button>',\n dropdownSlot = '<div slot=\"dropdown\">Dropdown content</div>'\n) => {\n const dropdown = (await getComponent(\n TAG,\n attrs,\n `${toggleSlot}${dropdownSlot}`,\n 400,\n 300\n )) as Dropdown;\n await dropdown.updateComplete;\n return dropdown;\n};\n\ndescribe(TAG, () => {\n it('can be created', async () => {\n const dropdown = await getDropdown();\n assert.instanceOf(dropdown, Dropdown);\n });\n\n it('has correct default properties', async () => {\n const dropdown = await getDropdown();\n\n // Test expected values first\n expect(dropdown.open).to.equal(false);\n expect(dropdown.dormant).to.equal(true);\n expect(dropdown.arrowSize).to.equal(8);\n expect(dropdown.margin).to.equal(10);\n expect(dropdown.mask).to.equal(false);\n // Position calculation happens automatically, so styles won't be empty\n expect(typeof dropdown.dropdownStyle).to.equal('object');\n expect(typeof dropdown.arrowStyle).to.equal('object');\n\n // Then screenshot\n await assertScreenshot('dropdown/default', getClip(dropdown));\n });\n\n it('renders with mask when enabled', async () => {\n const dropdown = await getDropdown({ mask: true });\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Test expected values first\n expect(dropdown.mask).to.equal(true);\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Then screenshot\n await assertScreenshot('dropdown/with-mask', getDropdownClip(dropdown));\n });\n\n it('handles toggle click and opens dropdown', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Verify initial state\n expect(dropdown.open).to.equal(false);\n expect(dropdown.dormant).to.equal(true);\n\n // Click the toggle\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Verify dropdown opened\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Screenshot the opened state with expanded clip\n await assertScreenshot('dropdown/opened', getDropdownClip(dropdown));\n });\n\n it('handles custom arrow size', async () => {\n const dropdown = await getDropdown({ arrowSize: 12 });\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Test expected values first\n expect(dropdown.arrowSize).to.equal(12);\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Then screenshot\n await assertScreenshot(\n 'dropdown/custom-arrow-size',\n getDropdownClip(dropdown)\n );\n });\n\n it('calculates position correctly', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await dropdown.updateComplete;\n\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify position styles were calculated\n expect(Object.keys(dropdown.dropdownStyle).length).to.be.greaterThan(0);\n expect(Object.keys(dropdown.arrowStyle).length).to.be.greaterThan(0);\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Screenshot positioned dropdown\n await assertScreenshot('dropdown/positioned', getDropdownClip(dropdown));\n });\n\n it('handles blur events to close dropdown', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown first\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n\n // Simulate blur event\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const blurEvent = new FocusEvent('blur', {\n bubbles: true,\n relatedTarget: document.body\n });\n dropdownDiv.dispatchEvent(blurEvent);\n\n // Check that dropdown is closed after a short delay\n await new Promise((resolve) => setTimeout(resolve, 300));\n expect(dropdown.open).to.equal(false);\n\n // Screenshot closed state\n await assertScreenshot('dropdown/after-blur', getClip(dropdown));\n });\n\n it('handles blur events when focus moves within dropdown', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown first\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n\n // Create an element within the dropdown\n const dropdownContent = dropdown.querySelector(\n '[slot=\"dropdown\"]'\n ) as HTMLElement;\n const internalButton = document.createElement('button');\n internalButton.textContent = 'Internal';\n dropdownContent.appendChild(internalButton);\n\n // Simulate blur event where focus moves to internal element\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const blurEvent = new FocusEvent('blur', {\n bubbles: true,\n relatedTarget: internalButton\n });\n dropdownDiv.dispatchEvent(blurEvent);\n await dropdown.updateComplete;\n\n // Dropdown should remain open since focus moved within it\n expect(dropdown.open).to.equal(true);\n });\n\n it('prevents opening when already open', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // First, open the dropdown normally\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Now try to click toggle again - should not call openDropdown again\n // since !dropdown.open is false\n const originalOpen = dropdown.open;\n toggle.click();\n await dropdown.updateComplete;\n\n // Should remain in the same state\n expect(dropdown.open).to.equal(originalOpen);\n });\n\n it('handles position calculation with right edge collision', async () => {\n // Create dropdown positioned near right edge\n const dropdown = await getDropdown(\n {},\n '<button slot=\"toggle\" style=\"position: fixed; right: 50px; top: 100px; width: 100px; height: 30px;\">Toggle</button>',\n '<div slot=\"dropdown\" style=\"width: 200px; height: 100px;\">Wide content</div>'\n );\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Get actual element bounds to simulate collision\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const originalGetBoundingClientRect = dropdownDiv.getBoundingClientRect;\n\n // Mock getBoundingClientRect to simulate right collision\n dropdownDiv.getBoundingClientRect = function () {\n return {\n bottom: 200,\n right: window.innerWidth + 100, // Extends beyond window\n top: 100,\n left: window.innerWidth - 50,\n width: 200,\n height: 100,\n x: window.innerWidth - 50,\n y: 100\n } as DOMRect;\n };\n\n try {\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify position was adjusted for right edge\n expect(dropdown.dropdownStyle).to.have.property('left');\n\n // Screenshot positioned dropdown\n await assertScreenshot(\n 'dropdown/right-edge-collision',\n getDropdownClip(dropdown)\n );\n } finally {\n // Restore original method\n dropdownDiv.getBoundingClientRect = originalGetBoundingClientRect;\n }\n });\n\n it('handles position calculation with bottom edge collision', async () => {\n // Create dropdown positioned near bottom edge\n const dropdown = await getDropdown(\n {},\n '<button slot=\"toggle\" style=\"position: fixed; left: 100px; bottom: 50px; width: 100px; height: 30px;\">Toggle</button>',\n '<div slot=\"dropdown\" style=\"width: 200px; height: 100px; position: absolute;\">Tall content</div>'\n );\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Get actual element bounds to simulate collision\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const originalGetBoundingClientRect = dropdownDiv.getBoundingClientRect;\n\n // Mock getBoundingClientRect to simulate bottom collision\n dropdownDiv.getBoundingClientRect = function () {\n return {\n bottom: window.innerHeight + 100, // Extends beyond window\n right: 300,\n top: window.innerHeight - 50,\n left: 100,\n width: 200,\n height: 100,\n x: 100,\n y: window.innerHeight - 50\n } as DOMRect;\n };\n\n try {\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify position was adjusted for bottom edge (bumped up)\n expect(dropdown.dropdownStyle).to.have.property('top');\n expect(dropdown.arrowStyle).to.have.property('transform');\n expect(dropdown.arrowStyle['transform']).to.include('rotate(180deg)');\n\n // Screenshot positioned dropdown\n await assertScreenshot(\n 'dropdown/bottom-edge-collision',\n getDropdownClip(dropdown)\n );\n } finally {\n // Restore original method\n dropdownDiv.getBoundingClientRect = originalGetBoundingClientRect;\n }\n });\n\n it('handles arrow positioning when toggle is very narrow', async () => {\n const dropdown = await getDropdown(\n {},\n '<button slot=\"toggle\" style=\"width: 5px;\">•</button>',\n '<div slot=\"dropdown\">Content</div>'\n );\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await dropdown.updateComplete;\n\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify arrow positioning was adjusted for narrow toggle\n expect(dropdown.dropdownStyle).to.have.property('marginLeft');\n expect(dropdown.dropdownStyle['marginLeft']).to.equal('-10px');\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Screenshot with adjusted arrow\n await assertScreenshot('dropdown/narrow-toggle', getDropdownClip(dropdown));\n });\n\n it('handles position calculation when toggle element is missing', async () => {\n const dropdown = await getDropdown(\n { open: true, dormant: false },\n '', // No toggle element\n '<div slot=\"dropdown\">Content</div>'\n );\n\n // Trigger position calculation - should handle gracefully\n dropdown.calculatePosition();\n await dropdown.updateComplete;\n\n // Should not crash and should have basic styles\n expect(typeof dropdown.dropdownStyle).to.equal('object');\n expect(typeof dropdown.arrowStyle).to.equal('object');\n });\n\n it('handles resetBlurHandler when activeFocus exists', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open dropdown to trigger resetBlurHandler for the first time\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n\n // Now open it again - this should trigger the activeFocus cleanup branch\n // First we need to close it\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const blurEvent = new FocusEvent('blur', {\n bubbles: true,\n relatedTarget: document.body\n });\n dropdownDiv.dispatchEvent(blurEvent);\n\n // Wait for close\n await new Promise((resolve) => setTimeout(resolve, 300));\n expect(dropdown.open).to.equal(false);\n expect(dropdown.dormant).to.equal(true);\n\n // Open again - this should trigger the cleanup in resetBlurHandler\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n });\n\n it('renders without mask by default', async () => {\n const dropdown = await getDropdown(); // No mask explicitly set\n\n // Test expected values first - mask should be false by default\n expect(dropdown.mask).to.equal(false);\n\n // Look for mask element in shadow DOM - should not exist when mask is false\n const maskElement = dropdown.shadowRoot.querySelector('.mask');\n expect(maskElement).to.be.null;\n\n // Screenshot default rendering\n await assertScreenshot('dropdown/no-mask', getClip(dropdown));\n });\n});\n"]}
1
+ {"version":3,"file":"temba-dropdown.test.js","sourceRoot":"","sources":["../../test/temba-dropdown.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, expect } from '@open-wc/testing';\nimport { Dropdown } from '../src/display/Dropdown';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\nconst TAG = 'temba-dropdown';\n\n// Helper function to wait for stable rendering\nconst waitForStableRender = async (dropdown: Dropdown, timeoutMs = 100) => {\n await dropdown.updateComplete;\n // Double wait to ensure any async positioning is complete\n await new Promise((resolve) => setTimeout(resolve, timeoutMs));\n await dropdown.updateComplete;\n};\n\n// Helper function to get expanded clip that includes dropdown content when open\nconst getDropdownClip = (dropdown: Dropdown) => {\n if (!dropdown.open) {\n // If closed, use regular clipping\n return getClip(dropdown);\n }\n\n // For open dropdowns, include the positioned dropdown content\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const dropdownBounds = dropdownDiv.getBoundingClientRect();\n const componentBounds = dropdown.getBoundingClientRect();\n\n // If dropdown content has no meaningful size, fall back to regular clip\n if (dropdownBounds.width < 10 || dropdownBounds.height < 10) {\n return getClip(dropdown);\n }\n\n // Create a clipping region that includes both the component and the dropdown content\n const minX = Math.min(componentBounds.x, dropdownBounds.x);\n const minY = Math.min(componentBounds.y, dropdownBounds.y);\n const maxX = Math.max(componentBounds.right, dropdownBounds.right);\n const maxY = Math.max(componentBounds.bottom, dropdownBounds.bottom);\n\n // Clamp to reasonable bounds to avoid excessive screenshot sizes\n const x = Math.max(0, minX - 10);\n const y = Math.max(0, minY - 10);\n const width = Math.min(1000, maxX - minX + 20);\n const height = Math.min(800, maxY - minY + 20);\n\n return { x, y, width, height };\n};\n\nconst getDropdown = async (\n attrs: {\n open?: boolean;\n dormant?: boolean;\n arrowSize?: number;\n margin?: number;\n mask?: boolean;\n } = {},\n toggleSlot = '<button slot=\"toggle\">Toggle</button>',\n dropdownSlot = '<div slot=\"dropdown\">Dropdown content</div>'\n) => {\n const dropdown = (await getComponent(\n TAG,\n attrs,\n `${toggleSlot}${dropdownSlot}`,\n 400,\n 300\n )) as Dropdown;\n await dropdown.updateComplete;\n return dropdown;\n};\n\ndescribe(TAG, () => {\n it('can be created', async () => {\n const dropdown = await getDropdown();\n assert.instanceOf(dropdown, Dropdown);\n });\n\n it('has correct default properties', async () => {\n const dropdown = await getDropdown();\n\n // Test expected values first\n expect(dropdown.open).to.equal(false);\n expect(dropdown.dormant).to.equal(true);\n expect(dropdown.arrowSize).to.equal(8);\n expect(dropdown.margin).to.equal(10);\n expect(dropdown.mask).to.equal(false);\n // Position calculation happens automatically, so styles won't be empty\n expect(typeof dropdown.dropdownStyle).to.equal('object');\n expect(typeof dropdown.arrowStyle).to.equal('object');\n\n // Then screenshot\n await assertScreenshot('dropdown/default', getClip(dropdown));\n });\n\n it('renders with mask when enabled', async () => {\n const dropdown = await getDropdown({ mask: true });\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Test expected values first\n expect(dropdown.mask).to.equal(true);\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Then screenshot\n await assertScreenshot('dropdown/with-mask', getDropdownClip(dropdown));\n });\n\n it('handles toggle click and opens dropdown', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Verify initial state\n expect(dropdown.open).to.equal(false);\n expect(dropdown.dormant).to.equal(true);\n\n // Click the toggle\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Verify dropdown opened\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Screenshot the opened state with expanded clip\n await assertScreenshot('dropdown/opened', getDropdownClip(dropdown));\n });\n\n it('handles custom arrow size', async () => {\n const dropdown = await getDropdown({ arrowSize: 12 });\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Test expected values first\n expect(dropdown.arrowSize).to.equal(12);\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Then screenshot\n await assertScreenshot(\n 'dropdown/custom-arrow-size',\n getDropdownClip(dropdown)\n );\n });\n\n it('calculates position correctly', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await dropdown.updateComplete;\n\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify position styles were calculated\n expect(Object.keys(dropdown.dropdownStyle).length).to.be.greaterThan(0);\n expect(Object.keys(dropdown.arrowStyle).length).to.be.greaterThan(0);\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Screenshot positioned dropdown\n await assertScreenshot('dropdown/positioned', getDropdownClip(dropdown));\n });\n\n it('handles blur events to close dropdown', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown first\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n\n // Simulate blur event\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const blurEvent = new FocusEvent('blur', {\n bubbles: true,\n relatedTarget: document.body\n });\n dropdownDiv.dispatchEvent(blurEvent);\n\n // Check that dropdown is closed after a short delay\n await new Promise((resolve) => setTimeout(resolve, 300));\n expect(dropdown.open).to.equal(false);\n\n // Screenshot closed state\n await assertScreenshot('dropdown/after-blur', getClip(dropdown));\n });\n\n it('handles blur events when focus moves within dropdown', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown first\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n\n // Create an element within the dropdown\n const dropdownContent = dropdown.querySelector(\n '[slot=\"dropdown\"]'\n ) as HTMLElement;\n const internalButton = document.createElement('button');\n internalButton.textContent = 'Internal';\n dropdownContent.appendChild(internalButton);\n\n // Simulate blur event where focus moves to internal element\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const blurEvent = new FocusEvent('blur', {\n bubbles: true,\n relatedTarget: internalButton\n });\n dropdownDiv.dispatchEvent(blurEvent);\n await dropdown.updateComplete;\n\n // Dropdown should remain open since focus moved within it\n expect(dropdown.open).to.equal(true);\n });\n\n it('prevents opening when already open', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // First, open the dropdown normally\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Now try to click toggle again - should not call openDropdown again\n // since !dropdown.open is false\n const originalOpen = dropdown.open;\n toggle.click();\n await dropdown.updateComplete;\n\n // Should remain in the same state\n expect(dropdown.open).to.equal(originalOpen);\n });\n\n it('handles position calculation with right edge collision', async () => {\n // Create dropdown positioned near right edge\n const dropdown = await getDropdown(\n {},\n '<button slot=\"toggle\" style=\"position: fixed; right: 50px; top: 100px; width: 100px; height: 30px;\">Toggle</button>',\n '<div slot=\"dropdown\" style=\"width: 200px; height: 100px;\">Wide content</div>'\n );\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Get actual element bounds to simulate collision\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const originalGetBoundingClientRect = dropdownDiv.getBoundingClientRect;\n\n // Mock getBoundingClientRect to simulate right collision\n dropdownDiv.getBoundingClientRect = function () {\n return {\n bottom: 200,\n right: window.innerWidth + 100, // Extends beyond window\n top: 100,\n left: window.innerWidth - 50,\n width: 200,\n height: 100,\n x: window.innerWidth - 50,\n y: 100\n } as DOMRect;\n };\n\n try {\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify position was adjusted for right edge\n expect(dropdown.dropdownStyle).to.have.property('left');\n\n // Screenshot positioned dropdown\n await assertScreenshot(\n 'dropdown/right-edge-collision',\n getDropdownClip(dropdown)\n );\n } finally {\n // Restore original method\n dropdownDiv.getBoundingClientRect = originalGetBoundingClientRect;\n }\n });\n\n it('handles position calculation with bottom edge collision', async () => {\n // Create dropdown positioned near bottom edge\n const dropdown = await getDropdown(\n {},\n '<button slot=\"toggle\" style=\"position: fixed; left: 100px; bottom: 50px; width: 100px; height: 30px;\">Toggle</button>',\n '<div slot=\"dropdown\" style=\"width: 200px; height: 100px; position: absolute;\">Tall content</div>'\n );\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await waitForStableRender(dropdown);\n\n // Get actual element bounds to simulate collision\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const originalGetBoundingClientRect = dropdownDiv.getBoundingClientRect;\n\n // Mock getBoundingClientRect to simulate bottom collision\n dropdownDiv.getBoundingClientRect = function () {\n return {\n bottom: window.innerHeight + 100, // Extends beyond window\n right: 300,\n top: window.innerHeight - 50,\n left: 100,\n width: 200,\n height: 100,\n x: 100,\n y: window.innerHeight - 50\n } as DOMRect;\n };\n\n try {\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify position was adjusted for bottom edge (bumped up)\n expect(dropdown.dropdownStyle).to.have.property('top');\n expect(dropdown.arrowStyle).to.have.property('transform');\n expect(dropdown.arrowStyle['transform']).to.include('rotate(180deg)');\n\n // Screenshot positioned dropdown\n await assertScreenshot(\n 'dropdown/bottom-edge-collision',\n getDropdownClip(dropdown)\n );\n } finally {\n // Restore original method\n dropdownDiv.getBoundingClientRect = originalGetBoundingClientRect;\n }\n });\n\n it('handles arrow positioning when toggle is very narrow', async () => {\n const dropdown = await getDropdown(\n {},\n '<button slot=\"toggle\" style=\"width: 5px;\">•</button>',\n '<div slot=\"dropdown\">Content</div>'\n );\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open the dropdown properly by clicking\n toggle.click();\n await dropdown.updateComplete;\n\n // Trigger position calculation\n dropdown.calculatePosition();\n await waitForStableRender(dropdown);\n\n // Verify arrow positioning was adjusted for narrow toggle\n expect(dropdown.dropdownStyle).to.have.property('marginLeft');\n expect(dropdown.dropdownStyle['marginLeft']).to.equal('-10px');\n expect(dropdown.open).to.equal(true);\n expect(dropdown.dormant).to.equal(false);\n\n // Screenshot with adjusted arrow\n await assertScreenshot('dropdown/narrow-toggle', getDropdownClip(dropdown));\n });\n\n it('handles position calculation when toggle element is missing', async () => {\n const dropdown = await getDropdown(\n { open: true, dormant: false },\n '', // No toggle element\n '<div slot=\"dropdown\">Content</div>'\n );\n\n // Trigger position calculation - should handle gracefully\n dropdown.calculatePosition();\n await dropdown.updateComplete;\n\n // Should not crash and should have basic styles\n expect(typeof dropdown.dropdownStyle).to.equal('object');\n expect(typeof dropdown.arrowStyle).to.equal('object');\n });\n\n it('handles resetBlurHandler when activeFocus exists', async () => {\n const dropdown = await getDropdown();\n const toggle = dropdown.querySelector('[slot=\"toggle\"]') as HTMLElement;\n\n // Open dropdown to trigger resetBlurHandler for the first time\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n\n // Now open it again - this should trigger the activeFocus cleanup branch\n // First we need to close it\n const dropdownDiv = dropdown.shadowRoot.querySelector(\n '.dropdown'\n ) as HTMLDivElement;\n const blurEvent = new FocusEvent('blur', {\n bubbles: true,\n relatedTarget: document.body\n });\n dropdownDiv.dispatchEvent(blurEvent);\n\n // Wait for close\n await new Promise((resolve) => setTimeout(resolve, 300));\n expect(dropdown.open).to.equal(false);\n expect(dropdown.dormant).to.equal(true);\n\n // Open again - this should trigger the cleanup in resetBlurHandler\n toggle.click();\n await dropdown.updateComplete;\n expect(dropdown.open).to.equal(true);\n });\n\n it('renders without mask by default', async () => {\n const dropdown = await getDropdown(); // No mask explicitly set\n\n // Test expected values first - mask should be false by default\n expect(dropdown.mask).to.equal(false);\n\n // Look for mask element in shadow DOM - should not exist when mask is false\n const maskElement = dropdown.shadowRoot.querySelector('.mask');\n expect(maskElement).to.be.null;\n\n // Screenshot default rendering\n await assertScreenshot('dropdown/no-mask', getClip(dropdown));\n });\n});\n"]}
@@ -0,0 +1,316 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { renderCompletionOption, getFunctions, getCompletions, getOffset, getVerticalScroll, getCompletionName, getCompletionSignature } from '../src/excellent/helpers';
3
+ describe('excellent/helpers', () => {
4
+ describe('renderCompletionOption', () => {
5
+ it('renders function option when selected', () => {
6
+ const option = {
7
+ signature: 'sum(values)',
8
+ summary: 'Calculates the sum of values'
9
+ };
10
+ const result = renderCompletionOption(option, true);
11
+ expect(result.strings).to.exist; // It's a TemplateResult
12
+ });
13
+ it('renders function option when not selected', () => {
14
+ const option = {
15
+ signature: 'sum(values)',
16
+ summary: 'Calculates the sum of values'
17
+ };
18
+ const result = renderCompletionOption(option, false);
19
+ expect(result.strings).to.exist;
20
+ });
21
+ it('renders property option when selected', () => {
22
+ const option = {
23
+ name: 'first_name',
24
+ summary: 'The contact first name'
25
+ };
26
+ const result = renderCompletionOption(option, true);
27
+ expect(result.strings).to.exist;
28
+ });
29
+ it('renders property option when not selected', () => {
30
+ const option = {
31
+ name: 'first_name',
32
+ summary: 'The contact first name'
33
+ };
34
+ const result = renderCompletionOption(option, false);
35
+ expect(result.strings).to.exist;
36
+ });
37
+ it('handles function with no summary', () => {
38
+ const option = {
39
+ signature: 'max(values)',
40
+ summary: ''
41
+ };
42
+ const result = renderCompletionOption(option, true);
43
+ expect(result.strings).to.exist;
44
+ });
45
+ it('handles property with no name', () => {
46
+ const option = {
47
+ summary: 'Some property'
48
+ };
49
+ const result = renderCompletionOption(option, false);
50
+ expect(result.strings).to.exist;
51
+ });
52
+ });
53
+ describe('getFunctions', () => {
54
+ const functions = [
55
+ { signature: 'sum(values)', summary: 'Sum function' },
56
+ { signature: 'max(values)', summary: 'Max function' },
57
+ { signature: 'min(values)', summary: 'Min function' },
58
+ { name: 'property', summary: 'Not a function' }
59
+ ];
60
+ it('returns all functions when no query provided', () => {
61
+ const result = getFunctions(functions, '');
62
+ expect(result).to.deep.equal(functions);
63
+ });
64
+ it('returns all functions when null query provided', () => {
65
+ const result = getFunctions(functions, null);
66
+ expect(result).to.deep.equal(functions);
67
+ });
68
+ it('filters functions by query prefix', () => {
69
+ const result = getFunctions(functions, 'su');
70
+ expect(result).to.have.length(1);
71
+ expect(result[0].signature).to.equal('sum(values)');
72
+ });
73
+ it('filters functions case-insensitively', () => {
74
+ const result = getFunctions(functions, 'MAX');
75
+ expect(result).to.have.length(1);
76
+ expect(result[0].signature).to.equal('max(values)');
77
+ });
78
+ it('returns empty array when no functions match', () => {
79
+ const result = getFunctions(functions, 'xyz');
80
+ expect(result).to.have.length(0);
81
+ });
82
+ it('ignores non-function options', () => {
83
+ const result = getFunctions(functions, 'prop');
84
+ expect(result).to.have.length(0);
85
+ });
86
+ it('handles empty functions array', () => {
87
+ const result = getFunctions([], 'sum');
88
+ expect(result).to.have.length(0);
89
+ });
90
+ it('handles partial matches', () => {
91
+ const result = getFunctions(functions, 'm');
92
+ expect(result).to.have.length(2); // max and min
93
+ });
94
+ });
95
+ describe('getCompletions', () => {
96
+ const mockSchema = {
97
+ types: [
98
+ {
99
+ name: 'contact',
100
+ properties: [
101
+ { key: 'first_name', help: 'First name', type: 'text' },
102
+ { key: 'last_name', help: 'Last name', type: 'text' },
103
+ { key: 'age', help: 'Age', type: 'number' }
104
+ ]
105
+ },
106
+ {
107
+ name: 'fields',
108
+ property_template: {
109
+ key: '{key}',
110
+ help: 'Field {key}',
111
+ type: 'text'
112
+ }
113
+ }
114
+ ],
115
+ root: [
116
+ { key: 'contact', help: 'Contact object', type: 'contact' },
117
+ { key: 'fields', help: 'Contact fields', type: 'fields' }
118
+ ],
119
+ root_no_session: [
120
+ { key: 'contact', help: 'Contact object', type: 'contact' }
121
+ ]
122
+ };
123
+ let mockStore;
124
+ beforeEach(() => {
125
+ mockStore = {
126
+ getCompletions: (type) => {
127
+ if (type === 'fields') {
128
+ return ['email', 'phone', 'city'];
129
+ }
130
+ return null;
131
+ }
132
+ };
133
+ });
134
+ it('returns root completions for empty query with session', () => {
135
+ const result = getCompletions(mockSchema, '', true, mockStore);
136
+ expect(result).to.have.length(2);
137
+ expect(result[0].name).to.equal('contact');
138
+ expect(result[1].name).to.equal('fields');
139
+ });
140
+ it('returns root completions for empty query without session', () => {
141
+ const result = getCompletions(mockSchema, '', false, mockStore);
142
+ expect(result).to.have.length(1);
143
+ expect(result[0].name).to.equal('contact');
144
+ });
145
+ it('returns contact properties for contact query', () => {
146
+ const result = getCompletions(mockSchema, 'contact', true, mockStore);
147
+ expect(result).to.have.length(3);
148
+ // Check that the result contains completion options with proper names
149
+ expect(result.map((r) => r.name)).to.include.members([
150
+ 'contact.first_name',
151
+ 'contact.last_name',
152
+ 'contact.age'
153
+ ]);
154
+ });
155
+ it('filters contact properties by partial match', () => {
156
+ const result = getCompletions(mockSchema, 'contact.first', true, mockStore);
157
+ expect(result).to.have.length(1);
158
+ expect(result[0].name).to.equal('contact.first_name');
159
+ });
160
+ it('returns empty array for invalid path', () => {
161
+ const result = getCompletions(mockSchema, 'invalid.path', true, mockStore);
162
+ expect(result).to.have.length(0);
163
+ });
164
+ it('handles template-based types with store completions', () => {
165
+ const result = getCompletions(mockSchema, 'fields', true, mockStore);
166
+ expect(result).to.have.length(3);
167
+ expect(result.map((r) => r.name)).to.include.members([
168
+ 'fields.email',
169
+ 'fields.phone',
170
+ 'fields.city'
171
+ ]);
172
+ });
173
+ it('handles template-based types without store completions', () => {
174
+ const noCompletionsStore = {
175
+ getCompletions: () => null
176
+ };
177
+ const result = getCompletions(mockSchema, 'fields', true, noCompletionsStore);
178
+ expect(result).to.have.length(0);
179
+ });
180
+ it('returns empty array when no schema root', () => {
181
+ const emptySchema = {
182
+ types: [],
183
+ root: null,
184
+ root_no_session: null
185
+ };
186
+ const result = getCompletions(emptySchema, '', true, mockStore);
187
+ expect(result).to.have.length(0);
188
+ });
189
+ it('filters root properties by query', () => {
190
+ const result = getCompletions(mockSchema, 'cont', true, mockStore);
191
+ expect(result).to.have.length(1);
192
+ expect(result[0].name).to.equal('contact');
193
+ });
194
+ it('handles nested property access', () => {
195
+ const result = getCompletions(mockSchema, 'contact.last_name', true, mockStore);
196
+ expect(result).to.have.length(1);
197
+ expect(result[0].name).to.equal('contact.last_name');
198
+ });
199
+ it('handles case-insensitive filtering', () => {
200
+ const result = getCompletions(mockSchema, 'contact.FIRST', true, mockStore);
201
+ expect(result).to.have.length(1);
202
+ expect(result[0].name).to.equal('contact.first_name');
203
+ });
204
+ });
205
+ describe('getOffset', () => {
206
+ it('calculates element offset including scroll', () => {
207
+ const element = document.createElement('div');
208
+ element.style.position = 'absolute';
209
+ element.style.top = '100px';
210
+ element.style.left = '50px';
211
+ element.style.width = '200px';
212
+ element.style.height = '150px';
213
+ document.body.appendChild(element);
214
+ const offset = getOffset(element);
215
+ expect(offset).to.have.property('top');
216
+ expect(offset).to.have.property('left');
217
+ expect(typeof offset.top).to.equal('number');
218
+ expect(typeof offset.left).to.equal('number');
219
+ document.body.removeChild(element);
220
+ });
221
+ it('handles elements without explicit positioning', () => {
222
+ const element = document.createElement('span');
223
+ element.textContent = 'test';
224
+ document.body.appendChild(element);
225
+ const offset = getOffset(element);
226
+ expect(offset).to.have.property('top');
227
+ expect(offset).to.have.property('left');
228
+ document.body.removeChild(element);
229
+ });
230
+ });
231
+ describe('getVerticalScroll', () => {
232
+ it('calculates vertical scroll for element', () => {
233
+ const element = document.createElement('div');
234
+ document.body.appendChild(element);
235
+ const scroll = getVerticalScroll(element);
236
+ // Function returns 0 as implemented (seems like stub implementation)
237
+ expect(typeof scroll).to.equal('number');
238
+ expect(scroll).to.equal(0);
239
+ document.body.removeChild(element);
240
+ });
241
+ it('handles element without parent', () => {
242
+ const element = document.createElement('div');
243
+ const scroll = getVerticalScroll(element);
244
+ expect(scroll).to.equal(0);
245
+ });
246
+ });
247
+ describe('getCompletionName', () => {
248
+ it('returns name property when available', () => {
249
+ const option = {
250
+ name: 'contact_name',
251
+ summary: 'Contact name'
252
+ };
253
+ const name = getCompletionName(option);
254
+ expect(name).to.equal('contact_name');
255
+ });
256
+ it('extracts name from signature when name not available', () => {
257
+ const option = {
258
+ signature: 'sum(values)',
259
+ summary: 'Sum function'
260
+ };
261
+ const name = getCompletionName(option);
262
+ expect(name).to.equal('sum');
263
+ });
264
+ it('handles complex function signatures', () => {
265
+ const option = {
266
+ signature: 'format_date(date, format)',
267
+ summary: 'Date formatting function'
268
+ };
269
+ const name = getCompletionName(option);
270
+ expect(name).to.equal('format_date');
271
+ });
272
+ it('handles signature without parentheses gracefully', () => {
273
+ const option = {
274
+ signature: 'invalid_signature',
275
+ summary: 'Invalid signature'
276
+ };
277
+ const name = getCompletionName(option);
278
+ expect(name).to.equal(''); // indexOf returns -1, substr(0, -1) returns empty string
279
+ });
280
+ });
281
+ describe('getCompletionSignature', () => {
282
+ it('extracts signature parameters', () => {
283
+ const option = {
284
+ signature: 'sum(values)',
285
+ summary: 'Sum function'
286
+ };
287
+ const signature = getCompletionSignature(option);
288
+ expect(signature).to.equal('(values)');
289
+ });
290
+ it('handles complex parameter signatures', () => {
291
+ const option = {
292
+ signature: 'format_date(date, format, timezone)',
293
+ summary: 'Date formatting function'
294
+ };
295
+ const signature = getCompletionSignature(option);
296
+ expect(signature).to.equal('(date, format, timezone)');
297
+ });
298
+ it('handles empty parameter signatures', () => {
299
+ const option = {
300
+ signature: 'now()',
301
+ summary: 'Current date function'
302
+ };
303
+ const signature = getCompletionSignature(option);
304
+ expect(signature).to.equal('()');
305
+ });
306
+ it('handles signature without parentheses', () => {
307
+ const option = {
308
+ signature: 'invalid',
309
+ summary: 'Invalid signature'
310
+ };
311
+ const signature = getCompletionSignature(option);
312
+ expect(signature).to.equal('d'); // substr from -1 on 'invalid' returns 'd'
313
+ });
314
+ });
315
+ });
316
+ //# sourceMappingURL=temba-excellent-helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temba-excellent-helpers.test.js","sourceRoot":"","sources":["../../test/temba-excellent-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport {\n renderCompletionOption,\n getFunctions,\n getCompletions,\n getOffset,\n getVerticalScroll,\n getCompletionName,\n getCompletionSignature\n} from '../src/excellent/helpers';\nimport { CompletionOption, CompletionSchema } from '../src/interfaces';\nimport { Store } from '../src/store/Store';\n\ndescribe('excellent/helpers', () => {\n describe('renderCompletionOption', () => {\n it('renders function option when selected', () => {\n const option: CompletionOption = {\n signature: 'sum(values)',\n summary: 'Calculates the sum of values'\n };\n\n const result = renderCompletionOption(option, true);\n expect(result.strings).to.exist; // It's a TemplateResult\n });\n\n it('renders function option when not selected', () => {\n const option: CompletionOption = {\n signature: 'sum(values)',\n summary: 'Calculates the sum of values'\n };\n\n const result = renderCompletionOption(option, false);\n expect(result.strings).to.exist;\n });\n\n it('renders property option when selected', () => {\n const option: CompletionOption = {\n name: 'first_name',\n summary: 'The contact first name'\n };\n\n const result = renderCompletionOption(option, true);\n expect(result.strings).to.exist;\n });\n\n it('renders property option when not selected', () => {\n const option: CompletionOption = {\n name: 'first_name',\n summary: 'The contact first name'\n };\n\n const result = renderCompletionOption(option, false);\n expect(result.strings).to.exist;\n });\n\n it('handles function with no summary', () => {\n const option: CompletionOption = {\n signature: 'max(values)',\n summary: ''\n };\n\n const result = renderCompletionOption(option, true);\n expect(result.strings).to.exist;\n });\n\n it('handles property with no name', () => {\n const option: CompletionOption = {\n summary: 'Some property'\n };\n\n const result = renderCompletionOption(option, false);\n expect(result.strings).to.exist;\n });\n });\n\n describe('getFunctions', () => {\n const functions: CompletionOption[] = [\n { signature: 'sum(values)', summary: 'Sum function' },\n { signature: 'max(values)', summary: 'Max function' },\n { signature: 'min(values)', summary: 'Min function' },\n { name: 'property', summary: 'Not a function' }\n ];\n\n it('returns all functions when no query provided', () => {\n const result = getFunctions(functions, '');\n expect(result).to.deep.equal(functions);\n });\n\n it('returns all functions when null query provided', () => {\n const result = getFunctions(functions, null);\n expect(result).to.deep.equal(functions);\n });\n\n it('filters functions by query prefix', () => {\n const result = getFunctions(functions, 'su');\n expect(result).to.have.length(1);\n expect(result[0].signature).to.equal('sum(values)');\n });\n\n it('filters functions case-insensitively', () => {\n const result = getFunctions(functions, 'MAX');\n expect(result).to.have.length(1);\n expect(result[0].signature).to.equal('max(values)');\n });\n\n it('returns empty array when no functions match', () => {\n const result = getFunctions(functions, 'xyz');\n expect(result).to.have.length(0);\n });\n\n it('ignores non-function options', () => {\n const result = getFunctions(functions, 'prop');\n expect(result).to.have.length(0);\n });\n\n it('handles empty functions array', () => {\n const result = getFunctions([], 'sum');\n expect(result).to.have.length(0);\n });\n\n it('handles partial matches', () => {\n const result = getFunctions(functions, 'm');\n expect(result).to.have.length(2); // max and min\n });\n });\n\n describe('getCompletions', () => {\n const mockSchema: CompletionSchema = {\n types: [\n {\n name: 'contact',\n properties: [\n { key: 'first_name', help: 'First name', type: 'text' },\n { key: 'last_name', help: 'Last name', type: 'text' },\n { key: 'age', help: 'Age', type: 'number' }\n ]\n },\n {\n name: 'fields',\n property_template: {\n key: '{key}',\n help: 'Field {key}',\n type: 'text'\n }\n }\n ],\n root: [\n { key: 'contact', help: 'Contact object', type: 'contact' },\n { key: 'fields', help: 'Contact fields', type: 'fields' }\n ],\n root_no_session: [\n { key: 'contact', help: 'Contact object', type: 'contact' }\n ]\n };\n\n let mockStore: Store;\n\n beforeEach(() => {\n mockStore = {\n getCompletions: (type: string) => {\n if (type === 'fields') {\n return ['email', 'phone', 'city'];\n }\n return null;\n }\n } as any;\n });\n\n it('returns root completions for empty query with session', () => {\n const result = getCompletions(mockSchema, '', true, mockStore);\n expect(result).to.have.length(2);\n expect(result[0].name).to.equal('contact');\n expect(result[1].name).to.equal('fields');\n });\n\n it('returns root completions for empty query without session', () => {\n const result = getCompletions(mockSchema, '', false, mockStore);\n expect(result).to.have.length(1);\n expect(result[0].name).to.equal('contact');\n });\n\n it('returns contact properties for contact query', () => {\n const result = getCompletions(mockSchema, 'contact', true, mockStore);\n expect(result).to.have.length(3);\n // Check that the result contains completion options with proper names\n expect(result.map((r) => r.name)).to.include.members([\n 'contact.first_name',\n 'contact.last_name',\n 'contact.age'\n ]);\n });\n\n it('filters contact properties by partial match', () => {\n const result = getCompletions(\n mockSchema,\n 'contact.first',\n true,\n mockStore\n );\n expect(result).to.have.length(1);\n expect(result[0].name).to.equal('contact.first_name');\n });\n\n it('returns empty array for invalid path', () => {\n const result = getCompletions(\n mockSchema,\n 'invalid.path',\n true,\n mockStore\n );\n expect(result).to.have.length(0);\n });\n\n it('handles template-based types with store completions', () => {\n const result = getCompletions(mockSchema, 'fields', true, mockStore);\n expect(result).to.have.length(3);\n expect(result.map((r) => r.name)).to.include.members([\n 'fields.email',\n 'fields.phone',\n 'fields.city'\n ]);\n });\n\n it('handles template-based types without store completions', () => {\n const noCompletionsStore = {\n getCompletions: () => null\n } as any;\n\n const result = getCompletions(\n mockSchema,\n 'fields',\n true,\n noCompletionsStore\n );\n expect(result).to.have.length(0);\n });\n\n it('returns empty array when no schema root', () => {\n const emptySchema: CompletionSchema = {\n types: [],\n root: null,\n root_no_session: null\n };\n\n const result = getCompletions(emptySchema, '', true, mockStore);\n expect(result).to.have.length(0);\n });\n\n it('filters root properties by query', () => {\n const result = getCompletions(mockSchema, 'cont', true, mockStore);\n expect(result).to.have.length(1);\n expect(result[0].name).to.equal('contact');\n });\n\n it('handles nested property access', () => {\n const result = getCompletions(\n mockSchema,\n 'contact.last_name',\n true,\n mockStore\n );\n expect(result).to.have.length(1);\n expect(result[0].name).to.equal('contact.last_name');\n });\n\n it('handles case-insensitive filtering', () => {\n const result = getCompletions(\n mockSchema,\n 'contact.FIRST',\n true,\n mockStore\n );\n expect(result).to.have.length(1);\n expect(result[0].name).to.equal('contact.first_name');\n });\n });\n\n describe('getOffset', () => {\n it('calculates element offset including scroll', () => {\n const element = document.createElement('div');\n element.style.position = 'absolute';\n element.style.top = '100px';\n element.style.left = '50px';\n element.style.width = '200px';\n element.style.height = '150px';\n document.body.appendChild(element);\n\n const offset = getOffset(element);\n\n expect(offset).to.have.property('top');\n expect(offset).to.have.property('left');\n expect(typeof offset.top).to.equal('number');\n expect(typeof offset.left).to.equal('number');\n\n document.body.removeChild(element);\n });\n\n it('handles elements without explicit positioning', () => {\n const element = document.createElement('span');\n element.textContent = 'test';\n document.body.appendChild(element);\n\n const offset = getOffset(element);\n\n expect(offset).to.have.property('top');\n expect(offset).to.have.property('left');\n\n document.body.removeChild(element);\n });\n });\n\n describe('getVerticalScroll', () => {\n it('calculates vertical scroll for element', () => {\n const element = document.createElement('div');\n document.body.appendChild(element);\n\n const scroll = getVerticalScroll(element);\n\n // Function returns 0 as implemented (seems like stub implementation)\n expect(typeof scroll).to.equal('number');\n expect(scroll).to.equal(0);\n\n document.body.removeChild(element);\n });\n\n it('handles element without parent', () => {\n const element = document.createElement('div');\n\n const scroll = getVerticalScroll(element);\n expect(scroll).to.equal(0);\n });\n });\n\n describe('getCompletionName', () => {\n it('returns name property when available', () => {\n const option: CompletionOption = {\n name: 'contact_name',\n summary: 'Contact name'\n };\n\n const name = getCompletionName(option);\n expect(name).to.equal('contact_name');\n });\n\n it('extracts name from signature when name not available', () => {\n const option: CompletionOption = {\n signature: 'sum(values)',\n summary: 'Sum function'\n };\n\n const name = getCompletionName(option);\n expect(name).to.equal('sum');\n });\n\n it('handles complex function signatures', () => {\n const option: CompletionOption = {\n signature: 'format_date(date, format)',\n summary: 'Date formatting function'\n };\n\n const name = getCompletionName(option);\n expect(name).to.equal('format_date');\n });\n\n it('handles signature without parentheses gracefully', () => {\n const option: CompletionOption = {\n signature: 'invalid_signature',\n summary: 'Invalid signature'\n };\n\n const name = getCompletionName(option);\n expect(name).to.equal(''); // indexOf returns -1, substr(0, -1) returns empty string\n });\n });\n\n describe('getCompletionSignature', () => {\n it('extracts signature parameters', () => {\n const option: CompletionOption = {\n signature: 'sum(values)',\n summary: 'Sum function'\n };\n\n const signature = getCompletionSignature(option);\n expect(signature).to.equal('(values)');\n });\n\n it('handles complex parameter signatures', () => {\n const option: CompletionOption = {\n signature: 'format_date(date, format, timezone)',\n summary: 'Date formatting function'\n };\n\n const signature = getCompletionSignature(option);\n expect(signature).to.equal('(date, format, timezone)');\n });\n\n it('handles empty parameter signatures', () => {\n const option: CompletionOption = {\n signature: 'now()',\n summary: 'Current date function'\n };\n\n const signature = getCompletionSignature(option);\n expect(signature).to.equal('()');\n });\n\n it('handles signature without parentheses', () => {\n const option: CompletionOption = {\n signature: 'invalid',\n summary: 'Invalid signature'\n };\n\n const signature = getCompletionSignature(option);\n expect(signature).to.equal('d'); // substr from -1 on 'invalid' returns 'd'\n });\n });\n});\n"]}