@nyaruka/temba-components 0.129.9 → 0.129.11

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 (323) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/demo/data/flows/sample-flow.json +96 -56
  3. package/demo/test-colorpicker.html +30 -0
  4. package/dist/temba-components.js +896 -934
  5. package/dist/temba-components.js.map +1 -1
  6. package/out-tsc/src/events.js.map +1 -1
  7. package/out-tsc/src/flow/Editor.js +9 -6
  8. package/out-tsc/src/flow/Editor.js.map +1 -1
  9. package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
  10. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  11. package/out-tsc/src/flow/actions/set_contact_field.js +1 -1
  12. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  13. package/out-tsc/src/flow/actions/set_contact_language.js +1 -1
  14. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  15. package/out-tsc/src/flow/actions/set_contact_status.js +1 -1
  16. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  17. package/out-tsc/src/flow/config.js +2 -8
  18. package/out-tsc/src/flow/config.js.map +1 -1
  19. package/out-tsc/src/flow/nodes/split_by_llm.js +101 -0
  20. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -0
  21. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +4 -89
  22. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  23. package/out-tsc/src/flow/nodes/split_by_subflow.js +123 -3
  24. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  25. package/out-tsc/src/flow/nodes/split_by_ticket.js +115 -13
  26. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  27. package/out-tsc/src/flow/nodes/split_by_webhook.js +160 -12
  28. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  29. package/out-tsc/src/form/ArrayEditor.js +45 -56
  30. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  31. package/out-tsc/src/form/BaseListEditor.js +4 -3
  32. package/out-tsc/src/form/BaseListEditor.js.map +1 -1
  33. package/out-tsc/src/form/Checkbox.js +77 -24
  34. package/out-tsc/src/form/Checkbox.js.map +1 -1
  35. package/out-tsc/src/form/ColorPicker.js +28 -40
  36. package/out-tsc/src/form/ColorPicker.js.map +1 -1
  37. package/out-tsc/src/form/Completion.js +44 -53
  38. package/out-tsc/src/form/Completion.js.map +1 -1
  39. package/out-tsc/src/form/Compose.js +7 -8
  40. package/out-tsc/src/form/Compose.js.map +1 -1
  41. package/out-tsc/src/form/ContactSearch.js +3 -4
  42. package/out-tsc/src/form/ContactSearch.js.map +1 -1
  43. package/out-tsc/src/form/DatePicker.js +29 -36
  44. package/out-tsc/src/form/DatePicker.js.map +1 -1
  45. package/out-tsc/src/form/{FormField.js → FieldElement.js} +78 -50
  46. package/out-tsc/src/form/FieldElement.js.map +1 -0
  47. package/out-tsc/src/form/FieldRenderer.js +2 -1
  48. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  49. package/out-tsc/src/form/ImagePicker.js +122 -126
  50. package/out-tsc/src/form/ImagePicker.js.map +1 -1
  51. package/out-tsc/src/form/KeyValueEditor.js +41 -37
  52. package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
  53. package/out-tsc/src/form/MessageEditor.js +55 -63
  54. package/out-tsc/src/form/MessageEditor.js.map +1 -1
  55. package/out-tsc/src/form/TembaSlider.js +3 -3
  56. package/out-tsc/src/form/TembaSlider.js.map +1 -1
  57. package/out-tsc/src/form/TemplateEditor.js +3 -3
  58. package/out-tsc/src/form/TemplateEditor.js.map +1 -1
  59. package/out-tsc/src/form/TextInput.js +22 -26
  60. package/out-tsc/src/form/TextInput.js.map +1 -1
  61. package/out-tsc/src/form/select/Select.js +9 -15
  62. package/out-tsc/src/form/select/Select.js.map +1 -1
  63. package/out-tsc/src/form/select/UserSelect.js +8 -9
  64. package/out-tsc/src/form/select/UserSelect.js.map +1 -1
  65. package/out-tsc/src/form/select/WorkspaceSelect.js +7 -8
  66. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -1
  67. package/out-tsc/src/live/ContactChat.js +73 -99
  68. package/out-tsc/src/live/ContactChat.js.map +1 -1
  69. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -1
  70. package/out-tsc/src/utils.js +115 -0
  71. package/out-tsc/src/utils.js.map +1 -1
  72. package/out-tsc/temba-modules.js +3 -2
  73. package/out-tsc/temba-modules.js.map +1 -1
  74. package/out-tsc/test/nodes/split_by_llm.test.js +174 -0
  75. package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -0
  76. package/out-tsc/test/temba-checkbox.test.js +16 -0
  77. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  78. package/out-tsc/test/temba-integration-markdown.test.js +2 -4
  79. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  80. package/out-tsc/test/temba-slider.test.js +0 -1
  81. package/out-tsc/test/temba-slider.test.js.map +1 -1
  82. package/package.json +1 -1
  83. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  84. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  85. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  86. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  87. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  88. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  89. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  90. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  91. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  92. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  93. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  94. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  95. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  96. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  97. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  98. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  99. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  100. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  101. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  102. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  103. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  104. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  105. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  106. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  107. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  108. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  109. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  110. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  111. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  112. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  113. package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
  114. package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
  115. package/screenshots/truth/checkbox/checkbox-whitespace-label-no-background-hover.png +0 -0
  116. package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
  117. package/screenshots/truth/checkbox/checked.png +0 -0
  118. package/screenshots/truth/checkbox/default.png +0 -0
  119. package/screenshots/truth/colorpicker/default.png +0 -0
  120. package/screenshots/truth/colorpicker/focused.png +0 -0
  121. package/screenshots/truth/colorpicker/initialized.png +0 -0
  122. package/screenshots/truth/colorpicker/selected.png +0 -0
  123. package/screenshots/truth/compose/attachments-tab.png +0 -0
  124. package/screenshots/truth/compose/attachments-with-files.png +0 -0
  125. package/screenshots/truth/compose/intial-text.png +0 -0
  126. package/screenshots/truth/compose/no-counter.png +0 -0
  127. package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
  128. package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
  129. package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
  130. package/screenshots/truth/contacts/chat-failure.png +0 -0
  131. package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
  132. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  133. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  134. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  135. package/screenshots/truth/counter/summary.png +0 -0
  136. package/screenshots/truth/counter/text.png +0 -0
  137. package/screenshots/truth/counter/unicode-variables.png +0 -0
  138. package/screenshots/truth/counter/unicode.png +0 -0
  139. package/screenshots/truth/counter/variable.png +0 -0
  140. package/screenshots/truth/datepicker/date-truncated-time.png +0 -0
  141. package/screenshots/truth/datepicker/date.png +0 -0
  142. package/screenshots/truth/datepicker/initial-timezone.png +0 -0
  143. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  144. package/screenshots/truth/datepicker/updated-keyboard-date.png +0 -0
  145. package/screenshots/truth/dialog/focused.png +0 -0
  146. package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
  147. package/screenshots/truth/editor/router.png +0 -0
  148. package/screenshots/truth/editor/send_msg.png +0 -0
  149. package/screenshots/truth/editor/set_contact_language.png +0 -0
  150. package/screenshots/truth/editor/set_contact_name.png +0 -0
  151. package/screenshots/truth/editor/set_run_result.png +0 -0
  152. package/screenshots/truth/editor/wait.png +0 -0
  153. package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
  154. package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
  155. package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
  156. package/screenshots/truth/field-renderer/context-comparison.png +0 -0
  157. package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
  158. package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
  159. package/screenshots/truth/field-renderer/select-multi.png +0 -0
  160. package/screenshots/truth/field-renderer/select-no-label.png +0 -0
  161. package/screenshots/truth/field-renderer/select-with-label.png +0 -0
  162. package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
  163. package/screenshots/truth/field-renderer/text-no-label.png +0 -0
  164. package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
  165. package/screenshots/truth/field-renderer/text-with-label.png +0 -0
  166. package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
  167. package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
  168. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  169. package/screenshots/truth/list/fields-dragging.png +0 -0
  170. package/screenshots/truth/list/fields-filtered.png +0 -0
  171. package/screenshots/truth/list/fields-hovered.png +0 -0
  172. package/screenshots/truth/list/fields.png +0 -0
  173. package/screenshots/truth/list/items-selected.png +0 -0
  174. package/screenshots/truth/list/items-updated.png +0 -0
  175. package/screenshots/truth/list/items.png +0 -0
  176. package/screenshots/truth/menu/menu-focused-with items.png +0 -0
  177. package/screenshots/truth/menu/menu-refresh-1.png +0 -0
  178. package/screenshots/truth/menu/menu-refresh-2.png +0 -0
  179. package/screenshots/truth/menu/menu-submenu.png +0 -0
  180. package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
  181. package/screenshots/truth/menu/menu-tasks.png +0 -0
  182. package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
  183. package/screenshots/truth/message-editor/default.png +0 -0
  184. package/screenshots/truth/message-editor/drag-highlight.png +0 -0
  185. package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
  186. package/screenshots/truth/message-editor/with-completion.png +0 -0
  187. package/screenshots/truth/message-editor/with-properties.png +0 -0
  188. package/screenshots/truth/modax/form.png +0 -0
  189. package/screenshots/truth/modax/simple.png +0 -0
  190. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  191. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  192. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  193. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  194. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  195. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  196. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  197. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  198. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  199. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  200. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  201. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  202. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  203. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  204. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  205. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  206. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  207. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  208. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  209. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  210. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  211. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  212. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  213. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  214. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  215. package/screenshots/truth/omnibox/selected.png +0 -0
  216. package/screenshots/truth/options/block.png +0 -0
  217. package/screenshots/truth/run-list/basic.png +0 -0
  218. package/screenshots/truth/select/disabled-multi-selection.png +0 -0
  219. package/screenshots/truth/select/disabled-selection.png +0 -0
  220. package/screenshots/truth/select/disabled.png +0 -0
  221. package/screenshots/truth/select/embedded.png +0 -0
  222. package/screenshots/truth/select/empty-options.png +0 -0
  223. package/screenshots/truth/select/expression-selected.png +0 -0
  224. package/screenshots/truth/select/expressions.png +0 -0
  225. package/screenshots/truth/select/functions.png +0 -0
  226. package/screenshots/truth/select/local-options.png +0 -0
  227. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  228. package/screenshots/truth/select/multiple-initial-values.png +0 -0
  229. package/screenshots/truth/select/remote-options.png +0 -0
  230. package/screenshots/truth/select/search-enabled.png +0 -0
  231. package/screenshots/truth/select/search-multi-no-matches.png +0 -0
  232. package/screenshots/truth/select/search-selected-focus.png +0 -0
  233. package/screenshots/truth/select/search-selected.png +0 -0
  234. package/screenshots/truth/select/search-with-selected.png +0 -0
  235. package/screenshots/truth/select/searching.png +0 -0
  236. package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
  237. package/screenshots/truth/select/selected-multi.png +0 -0
  238. package/screenshots/truth/select/selected-single.png +0 -0
  239. package/screenshots/truth/select/selection-clearable.png +0 -0
  240. package/screenshots/truth/select/static-initial-value.png +0 -0
  241. package/screenshots/truth/select/static-initial-via-selected.png +0 -0
  242. package/screenshots/truth/select/truncated-selection.png +0 -0
  243. package/screenshots/truth/select/with-placeholder.png +0 -0
  244. package/screenshots/truth/select/without-placeholder.png +0 -0
  245. package/screenshots/truth/slider/update-slider-on-circle-dragged.png +0 -0
  246. package/screenshots/truth/templates/default.png +0 -0
  247. package/screenshots/truth/templates/unapproved.png +0 -0
  248. package/screenshots/truth/textinput/autogrow-initial.png +0 -0
  249. package/screenshots/truth/textinput/input-disabled.png +0 -0
  250. package/screenshots/truth/textinput/input-focused.png +0 -0
  251. package/screenshots/truth/textinput/input-form.png +0 -0
  252. package/screenshots/truth/textinput/input-inserted.png +0 -0
  253. package/screenshots/truth/textinput/input-placeholder.png +0 -0
  254. package/screenshots/truth/textinput/input-updated.png +0 -0
  255. package/screenshots/truth/textinput/input.png +0 -0
  256. package/screenshots/truth/textinput/textarea-focused.png +0 -0
  257. package/screenshots/truth/textinput/textarea.png +0 -0
  258. package/src/events.ts +9 -8
  259. package/src/flow/Editor.ts +6 -3
  260. package/src/flow/actions/set_contact_channel.ts +1 -1
  261. package/src/flow/actions/set_contact_field.ts +1 -1
  262. package/src/flow/actions/set_contact_language.ts +1 -1
  263. package/src/flow/actions/set_contact_status.ts +1 -1
  264. package/src/flow/config.ts +2 -8
  265. package/src/flow/nodes/split_by_llm.ts +119 -0
  266. package/src/flow/nodes/split_by_llm_categorize.ts +13 -116
  267. package/src/flow/nodes/split_by_subflow.ts +153 -3
  268. package/src/flow/nodes/split_by_ticket.ts +135 -12
  269. package/src/flow/nodes/split_by_webhook.ts +187 -12
  270. package/src/form/ArrayEditor.ts +45 -57
  271. package/src/form/BaseListEditor.ts +4 -4
  272. package/src/form/Checkbox.ts +81 -24
  273. package/src/form/ColorPicker.ts +31 -43
  274. package/src/form/Completion.ts +49 -56
  275. package/src/form/Compose.ts +8 -8
  276. package/src/form/ContactSearch.ts +3 -4
  277. package/src/form/DatePicker.ts +32 -38
  278. package/src/form/{FormField.ts → FieldElement.ts} +105 -52
  279. package/src/form/FieldRenderer.ts +2 -1
  280. package/src/form/ImagePicker.ts +107 -110
  281. package/src/form/KeyValueEditor.ts +43 -39
  282. package/src/form/MessageEditor.ts +61 -67
  283. package/src/form/TembaSlider.ts +3 -3
  284. package/src/form/TemplateEditor.ts +3 -3
  285. package/src/form/TextInput.ts +25 -28
  286. package/src/form/select/Select.ts +12 -17
  287. package/src/form/select/UserSelect.ts +10 -11
  288. package/src/form/select/WorkspaceSelect.ts +9 -10
  289. package/src/live/ContactChat.ts +81 -92
  290. package/src/live/ContactFieldEditor.ts +2 -2
  291. package/src/store/flow-definition.d.ts +2 -1
  292. package/src/utils.ts +192 -0
  293. package/temba-modules.ts +3 -2
  294. package/test/nodes/split_by_llm.test.ts +232 -0
  295. package/test/temba-checkbox.test.ts +26 -0
  296. package/test/temba-integration-markdown.test.ts +2 -4
  297. package/test/temba-slider.test.ts +0 -1
  298. package/test-assets/contacts/history.json +7 -20
  299. package/test-assets/style.css +36 -234
  300. package/web-dev-server.config.mjs +26 -0
  301. package/web-test-runner.config.mjs +1 -1
  302. package/out-tsc/src/flow/actions/call_llm.js +0 -64
  303. package/out-tsc/src/flow/actions/call_llm.js.map +0 -1
  304. package/out-tsc/src/flow/actions/call_webhook.js +0 -131
  305. package/out-tsc/src/flow/actions/call_webhook.js.map +0 -1
  306. package/out-tsc/src/flow/actions/enter_flow.js +0 -14
  307. package/out-tsc/src/flow/actions/enter_flow.js.map +0 -1
  308. package/out-tsc/src/flow/actions/open_ticket.js +0 -73
  309. package/out-tsc/src/flow/actions/open_ticket.js.map +0 -1
  310. package/out-tsc/src/form/FormElement.js +0 -67
  311. package/out-tsc/src/form/FormElement.js.map +0 -1
  312. package/out-tsc/src/form/FormField.js.map +0 -1
  313. package/out-tsc/test/actions/call_llm.test.js +0 -103
  314. package/out-tsc/test/actions/call_llm.test.js.map +0 -1
  315. package/out-tsc/test/temba-formfield.test.js +0 -94
  316. package/out-tsc/test/temba-formfield.test.js.map +0 -1
  317. package/src/flow/actions/call_llm.ts +0 -66
  318. package/src/flow/actions/call_webhook.ts +0 -143
  319. package/src/flow/actions/enter_flow.ts +0 -15
  320. package/src/flow/actions/open_ticket.ts +0 -83
  321. package/src/form/FormElement.ts +0 -69
  322. package/test/actions/call_llm.test.ts +0 -137
  323. package/test/temba-formfield.test.ts +0 -121
@@ -1 +1 @@
1
- {"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../../../src/form/ImagePicker.ts"],"names":[],"mappings":";AAAA,qDAAqD;AACrD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAoB,MAAM,KAAK,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,OAAO,WAAY,SAAQ,WAAW;IAA5C;;QAwHE,UAAK,GAAG,QAAQ,CAAC;QAGjB,gBAAW,GAAG,KAAK,CAAC;QAEpB,iBAAY,GAAG,IAAI,UAAU,EAAE,CAAC;IAuIlC,CAAC;IApIW,YAAY,CACpB,OAA0D;QAE1D,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC;QAEpB,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG;YACzB,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,MAAa,CAAC,CAAC;QAC1D,CAAC,CAAC;IACJ,CAAC;IAEM,OAAO,CAAC,OAAyB;QACtC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,GAAW;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAEzB,MAAM,OAAO,GAAI,MAAc,CAAC,OAAO,CAAC;QACxC,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;YAC9B,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE;gBACR,KAAK,EAAE,GAAG;gBACV,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,IAAI,CAAC,KAAK;aACjB;YACD,QAAQ,EAAE;gBACR,KAAK,EAAE,GAAG;gBACV,MAAM,EAAE,GAAG;aACZ;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,CAAC;IAEO,UAAU;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,OAAO;aACT,MAAM,CAAC;YACN,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,KAAK;SACd,CAAC;aACD,IAAI,CAAC,UAAU,IAAS;YACvB,MAAM,IAAI,GAAG,IAAI,CAAC;YAClB,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAEvC,oCAAoC;YACpC,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC1B,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;YAE9C,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;YAClB,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,mBAAmB;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACxD,SAAiB,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAEO,iBAAiB,CAAC,CAAQ;QAChC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAa,CAAC;QAC9B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QACD,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;IACnB,CAAC;IAES,MAAM;QACd,OAAO,IAAI,CAAA;0BACW,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;;eAElD,IAAI,CAAC,IAAI;gBACR,IAAI,CAAC,KAAK;oBACN,IAAI,CAAC,QAAQ;kBACf,IAAI,CAAC,MAAM;sBACP,IAAI,CAAC,UAAU;sBACf,IAAI;oBACN,IAAI,CAAC,QAAQ;;4GAGvB,IAAI,CAAC,iBACP;6BACqB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAC5C,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAChC,YAAY,IAAI,CAAC,mBAAmB,uBAClC,IAAI,CAAC,GAAG;YACN,CAAC,CAAC,QAAQ,IAAI,CAAC,GAAG,+BAA+B;YACjD,CAAC,CAAC,oBACN;6BACyB,IAAI,CAAC,YAAY;;;4BAGlB,IAAI,CAAC,WAAW,WACtC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EACjC;;;;wDAIoD,IAAI,CAAC,KAAK,WAC5D,IAAI,CAAC,YACP;;yDAEqD,IAAI,CAAC,MAAM,WAC9D,IAAI,CAAC,UACP;;;;;KAKC,CAAC;IACJ,CAAC;;AAlQM,kBAAM,GAAG,GAAG,CAAA;MACf,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6Gb,AA9GY,CA8GX;AAGF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;8CACT;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCACf;AAGZ;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CACV;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;gDAC1B","sourcesContent":["/* eslint-disable @typescript-eslint/no-this-alias */\nimport { html, css, PropertyValueMap } from 'lit';\nimport { CroppieCSS } from './CroppieCSS';\nimport { property } from 'lit/decorators.js';\nimport { Icon } from '../Icons';\nimport { FormElement } from './FormElement';\n\nexport class ImagePicker extends FormElement {\n static styles = css`\n ${CroppieCSS}\n\n .croppie {\n max-width: 400px;\n border: 0px solid #ccc;\n border-radius: 0.5em;\n overflow: hidden;\n background: #fff;\n margin-top: -20%;\n box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);\n }\n\n .croppie .controls {\n display: flex;\n align-items: center;\n flex-direction: row;\n justify-content: center;\n position: absolute;\n z-index: 1;\n width: 400px;\n margin-top: -42px;\n }\n\n .toggle {\n height: 110px;\n width: 110px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .circle .toggle {\n border-radius: 50%;\n }\n\n .toggle.set {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);\n }\n\n .toggle.set:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);\n }\n\n .toggle temba-icon {\n color: rgba(0, 0, 0, 0.2);\n padding: 5px;\n }\n\n toggle:hover temba-icon {\n color: rgba(0, 0, 0, 0.8);\n }\n\n .toggle.set temba-icon {\n border-radius: 50%;\n margin-right: -90%;\n margin-bottom: -50%;\n background: rgba(240, 240, 240, 1);\n box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n }\n\n .toggle.set:hover temba-icon {\n background: #fff;\n color: var(--color-primary-dark);\n }\n\n .circle .toggle.set temba-icon {\n margin-right: -70%;\n margin-bottom: -70%;\n }\n\n .hidden {\n display: none;\n }\n\n .controls temba-icon {\n margin: 0em 0.75em;\n background: rgba(255, 255, 255, 0.8);\n border-radius: 50%;\n padding: 6px;\n transition: all 0.1s ease-in-out;\n }\n\n .controls {\n pointer-events: none;\n display: flex;\n }\n\n .controls temba-icon {\n pointer-events: all;\n }\n\n .controls temba-icon.close {\n color: rgba(0, 0, 0, 0.2);\n background: rgba(255, 255, 255, 0.2);\n }\n\n .controls temba-icon.submit {\n color: rgba(0, 0, 0, 0.2);\n box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);\n }\n\n .controls temba-icon:hover {\n color: white;\n cursor: pointer;\n background: var(--color-primary-dark);\n }\n `;\n\n @property({ type: String })\n tempImage: string;\n\n @property({ type: String })\n url: string;\n\n @property({ type: String })\n shape = 'square';\n\n @property({ type: Boolean, attribute: false })\n showCroppie = false;\n\n uploadReader = new FileReader();\n croppie: any;\n\n protected firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const picker = this;\n\n this.uploadReader.onload = function () {\n picker.launchCroppie(picker.uploadReader.result as any);\n };\n }\n\n public updated(changed: Map<string, any>): void {\n super.updated(changed);\n if (changed.has('url')) {\n this.setAttribute('url', this.url);\n }\n }\n\n private closeCroppie() {\n this.showCroppie = false;\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n }\n\n private launchCroppie(url: string) {\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n this.showCroppie = true;\n const ele = document.createElement('div');\n wrapper.appendChild(ele);\n\n const Croppie = (window as any).Croppie;\n this.croppie = new Croppie(ele, {\n enableExif: true,\n viewport: {\n width: 300,\n height: 300,\n type: this.shape\n },\n boundary: {\n width: 400,\n height: 400\n }\n });\n\n this.croppie.bind({ url });\n }\n\n private saveResult() {\n const picker = this;\n this.croppie\n .result({\n type: 'blob',\n size: 'viewport',\n format: 'webp',\n quality: 1,\n circle: false\n })\n .then(function (resp: any) {\n const blob = resp;\n picker.url = URL.createObjectURL(blob);\n\n // const blob = dataURItoBlob(resp);\n const fd = new FormData();\n fd.append(picker.name, blob, 'filename.webp');\n\n picker.value = fd;\n picker.closeCroppie();\n });\n }\n\n private handleToggleClicked() {\n const fileInput = this.shadowRoot.querySelector('#file');\n (fileInput as any).click();\n }\n\n private handleFileChanged(e: Event) {\n const input = e.target as any;\n if (input.files.length > 0) {\n this.uploadReader.readAsDataURL(input.files[0]);\n }\n input.value = '';\n }\n\n protected render() {\n return html`\n <div class=\"wrapper ${this.shape} ${this.label ? 'label' : ''}\">\n <temba-field\n name=${this.name}\n label=${this.label}\n .helpText=${this.helpText}\n .errors=${this.errors}\n .widgetOnly=${this.widgetOnly}\n .helpAlways=${true}\n ?disabled=${this.disabled}\n >\n <input class='hidden' type=\"file\" accept=\"image/*\" capture=\"camera\" id=\"file\" name=\"file\" @change=${\n this.handleFileChanged\n }/>\n <div class='toggle ${this.url ? 'set' : ''} ${\n this.showCroppie ? 'hidden' : ''\n }' @click=${this.handleToggleClicked} style=\"background: ${\n this.url\n ? `url('${this.url}') center / contain no-repeat`\n : 'rgba(0, 0, 0, 0.1)'\n }\">\n <temba-icon name=${Icon.upload_image} size=\"1.5\"></temba-icon>\n </div>\n \n <temba-mask ?show=${this.showCroppie} class=\"${\n this.showCroppie ? 'editing' : ''\n }\">\n <div class='croppie'>\n <div class='embed'></div>\n <div class='controls'>\n <temba-icon class=\"close\" size=\"1\" name=${Icon.close} @click=${\n this.closeCroppie\n }></temba-icon>\n <div style=\"flex-grow:1\"></div>\n <temba-icon class=\"submit\" size=\"1\" name=${Icon.submit} @click=${\n this.saveResult\n }></temba-icon>\n </div>\n </temba-mask>\n </temba-field>\n </div>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../../../src/form/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-this-alias */\nimport { html, css, PropertyValueMap } from 'lit';\nimport { CroppieCSS } from './CroppieCSS';\nimport { property } from 'lit/decorators.js';\nimport { Icon } from '../Icons';\nimport { FieldElement } from './FieldElement';\n\nexport class ImagePicker extends FieldElement {\n static get styles() {\n return css`\n ${super.styles}\n ${CroppieCSS}\n\n .croppie {\n max-width: 400px;\n border: 0px solid #ccc;\n border-radius: 0.5em;\n overflow: hidden;\n background: #fff;\n margin-top: -20%;\n box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);\n }\n\n .croppie .controls {\n display: flex;\n align-items: center;\n flex-direction: row;\n justify-content: center;\n position: absolute;\n z-index: 1;\n width: 400px;\n margin-top: -42px;\n }\n\n .toggle {\n height: 110px;\n width: 110px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .circle .toggle {\n border-radius: 50%;\n }\n\n .toggle.set {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);\n }\n\n .toggle.set:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);\n }\n\n .toggle temba-icon {\n color: rgba(0, 0, 0, 0.2);\n padding: 5px;\n }\n\n toggle:hover temba-icon {\n color: rgba(0, 0, 0, 0.8);\n }\n\n .toggle.set temba-icon {\n border-radius: 50%;\n margin-right: -90%;\n margin-bottom: -50%;\n background: rgba(240, 240, 240, 1);\n box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n }\n\n .toggle.set:hover temba-icon {\n background: #fff;\n color: var(--color-primary-dark);\n }\n\n .circle .toggle.set temba-icon {\n margin-right: -70%;\n margin-bottom: -70%;\n }\n\n .hidden {\n display: none;\n }\n\n .controls temba-icon {\n margin: 0em 0.75em;\n background: rgba(255, 255, 255, 0.8);\n border-radius: 50%;\n padding: 6px;\n transition: all 0.1s ease-in-out;\n }\n\n .controls {\n pointer-events: none;\n display: flex;\n }\n\n .controls temba-icon {\n pointer-events: all;\n }\n\n .controls temba-icon.close {\n color: rgba(0, 0, 0, 0.2);\n background: rgba(255, 255, 255, 0.2);\n }\n\n .controls temba-icon.submit {\n color: rgba(0, 0, 0, 0.2);\n box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);\n }\n\n .controls temba-icon:hover {\n color: white;\n cursor: pointer;\n background: var(--color-primary-dark);\n }\n `;\n }\n\n @property({ type: String })\n tempImage: string;\n\n @property({ type: String })\n url: string;\n\n @property({ type: String })\n shape = 'square';\n\n @property({ type: Boolean, attribute: false })\n showCroppie = false;\n\n uploadReader = new FileReader();\n croppie: any;\n\n protected firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const picker = this;\n\n this.uploadReader.onload = function () {\n picker.launchCroppie(picker.uploadReader.result as any);\n };\n }\n\n public updated(changed: Map<string, any>): void {\n super.updated(changed);\n if (changed.has('url')) {\n this.setAttribute('url', this.url);\n }\n }\n\n private closeCroppie() {\n this.showCroppie = false;\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n }\n\n private launchCroppie(url: string) {\n const wrapper = this.shadowRoot.querySelector('.croppie .embed');\n if (wrapper.firstChild) {\n wrapper.removeChild(wrapper.firstChild);\n }\n this.showCroppie = true;\n const ele = document.createElement('div');\n wrapper.appendChild(ele);\n\n const Croppie = (window as any).Croppie;\n this.croppie = new Croppie(ele, {\n enableExif: true,\n viewport: {\n width: 300,\n height: 300,\n type: this.shape\n },\n boundary: {\n width: 400,\n height: 400\n }\n });\n\n this.croppie.bind({ url });\n }\n\n private saveResult() {\n const picker = this;\n this.croppie\n .result({\n type: 'blob',\n size: 'viewport',\n format: 'webp',\n quality: 1,\n circle: false\n })\n .then(function (resp: any) {\n const blob = resp;\n picker.url = URL.createObjectURL(blob);\n\n // const blob = dataURItoBlob(resp);\n const fd = new FormData();\n fd.append(picker.name, blob, 'filename.webp');\n\n picker.value = fd;\n picker.closeCroppie();\n });\n }\n\n private handleToggleClicked() {\n const fileInput = this.shadowRoot.querySelector('#file');\n (fileInput as any).click();\n }\n\n private handleFileChanged(e: Event) {\n const input = e.target as any;\n if (input.files.length > 0) {\n this.uploadReader.readAsDataURL(input.files[0]);\n }\n input.value = '';\n }\n\n protected renderWidget() {\n return html`\n <div class=\"wrapper ${this.shape} ${this.label ? 'label' : ''}\">\n <input class='hidden' type=\"file\" accept=\"image/*\" capture=\"camera\" id=\"file\" name=\"file\" @change=${\n this.handleFileChanged\n }/>\n <div class='toggle ${this.url ? 'set' : ''} ${\n this.showCroppie ? 'hidden' : ''\n }' @click=${this.handleToggleClicked} style=\"background: ${\n this.url\n ? `url('${this.url}') center / contain no-repeat`\n : 'rgba(0, 0, 0, 0.1)'\n }\">\n <temba-icon name=${Icon.upload_image} size=\"1.5\"></temba-icon>\n </div>\n \n <temba-mask ?show=${this.showCroppie} class=\"${\n this.showCroppie ? 'editing' : ''\n }\">\n <div class='croppie'>\n <div class='embed'></div>\n <div class='controls'>\n <temba-icon class=\"close\" size=\"1\" name=${Icon.close} @click=${\n this.closeCroppie\n }></temba-icon>\n <div style=\"flex-grow:1\"></div>\n <temba-icon class=\"submit\" size=\"1\" name=${Icon.submit} @click=${\n this.saveResult\n }></temba-icon>\n </div>\n </temba-mask>\n </div>\n `;\n }\n\n public render() {\n return this.renderField();\n }\n}\n"]}
@@ -158,49 +158,53 @@ let KeyValueEditor = class KeyValueEditor extends BaseListEditor {
158
158
  getContainerClass() {
159
159
  return 'key-value-editor';
160
160
  }
161
- };
162
- KeyValueEditor.styles = css `
163
- .key-value-editor {
164
- display: flex;
165
- flex-direction: column;
166
- gap: 8px;
167
- }
161
+ static get styles() {
162
+ return css `
163
+ ${super.styles}
168
164
 
169
- .row {
170
- display: grid;
171
- grid-template-columns: 1fr 1fr auto;
172
- align-items: center;
173
- column-gap: 6px;
174
- }
165
+ .key-value-editor {
166
+ display: flex;
167
+ flex-direction: column;
168
+ gap: 8px;
169
+ }
175
170
 
176
- .remove-btn {
177
- width: 32px;
178
- height: 32px;
179
- border: 1px solid #ccc;
180
- border-radius: 4px;
181
- background: #f8f8f8;
182
- color: #666;
183
- cursor: pointer;
184
- display: flex;
185
- align-items: center;
186
- justify-content: center;
187
- font-size: 18px;
188
- }
171
+ .row {
172
+ display: grid;
173
+ grid-template-columns: 1fr 1fr auto;
174
+ align-items: center;
175
+ column-gap: 6px;
176
+ }
189
177
 
190
- .remove-btn:hover:not(:disabled) {
191
- background: #f0f0f0;
192
- }
178
+ .remove-btn {
179
+ width: 32px;
180
+ height: 32px;
181
+ border: 1px solid #ccc;
182
+ border-radius: 4px;
183
+ background: #f8f8f8;
184
+ color: #666;
185
+ cursor: pointer;
186
+ display: flex;
187
+ align-items: center;
188
+ justify-content: center;
189
+ font-size: 18px;
190
+ }
193
191
 
194
- .remove-btn:disabled {
195
- opacity: 0.5;
196
- cursor: not-allowed;
197
- }
192
+ .remove-btn:hover:not(:disabled) {
193
+ background: #f0f0f0;
194
+ }
195
+
196
+ .remove-btn:disabled {
197
+ opacity: 0.5;
198
+ cursor: not-allowed;
199
+ }
198
200
 
199
- .remove-btn-spacer {
200
- width: 32px;
201
- height: 32px;
201
+ .remove-btn-spacer {
202
+ width: 32px;
203
+ height: 32px;
204
+ }
205
+ `;
202
206
  }
203
- `;
207
+ };
204
208
  __decorate([
205
209
  property({ type: String })
206
210
  ], KeyValueEditor.prototype, "keyPlaceholder", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"KeyValueEditor.js","sourceRoot":"","sources":["../../../src/form/KeyValueEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, TemplateResult } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { BaseListEditor, ListItem } from './BaseListEditor';\n\ninterface KeyValueItem extends ListItem {\n key: string;\n value: string;\n}\n\n@customElement('temba-key-value-editor')\nexport class KeyValueEditor extends BaseListEditor<KeyValueItem> {\n @property({ type: String })\n keyPlaceholder = 'Key';\n\n @property({ type: String })\n valuePlaceholder = 'Value';\n\n @property({ type: Boolean })\n showValidation = true;\n\n @state()\n private keyErrors: { [index: number]: string } = {};\n\n // Configure to maintain empty items\n maintainEmptyItem = true;\n\n constructor() {\n super();\n this._items = [];\n }\n\n // External API uses array format to preserve duplicate keys\n @property({ type: Array })\n get value(): KeyValueItem[] {\n return this._items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n set value(newValue: KeyValueItem[] | Record<string, string>) {\n if (Array.isArray(newValue)) {\n this._items = [...newValue];\n } else {\n // Convert Record to array format\n this._items = Object.entries(newValue || {}).map(([key, value]) => ({\n key,\n value: typeof value === 'string' ? value : String(value)\n }));\n }\n this.requestUpdate();\n }\n\n // Implement abstract methods\n isEmptyItem(item: KeyValueItem): boolean {\n return item.key.trim() === '' && item.value.trim() === '';\n }\n\n createEmptyItem(): KeyValueItem {\n return { key: '', value: '' };\n }\n\n // Override cleanItems to return array format to preserve duplicate keys\n protected cleanItems(items: KeyValueItem[]): KeyValueItem[] {\n return items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n // Method to convert to Record format for final form submission\n toRecord(): Record<string, string> {\n const result: Record<string, string> = {};\n this._items.forEach(({ key, value }) => {\n if (key.trim() !== '' || value.trim() !== '') {\n result[key] = value;\n }\n });\n return result;\n }\n\n // Method to validate and set key errors for duplicates and empty keys with values\n validateKeys(): boolean {\n const newKeyErrors: { [index: number]: string } = {};\n\n // Check for empty keys with values\n this._items.forEach(({ key, value }, index) => {\n if (key.trim() === '' && value.trim() !== '') {\n newKeyErrors[index] = 'Key is required when value is provided';\n }\n });\n\n // Check for duplicate keys (only non-empty ones)\n const nonEmptyKeys = this._items\n .map(({ key }, index) => ({ key: key.trim(), index }))\n .filter(({ key }) => key !== '');\n\n const keyCount = new Map<string, number[]>();\n nonEmptyKeys.forEach(({ key, index }) => {\n if (!keyCount.has(key)) {\n keyCount.set(key, []);\n }\n keyCount.get(key)!.push(index);\n });\n\n // Mark duplicate keys with errors\n keyCount.forEach((indices, key) => {\n if (indices.length > 1) {\n indices.forEach((index) => {\n // Only show duplicate error if there's no empty key error already\n if (!newKeyErrors[index]) {\n newKeyErrors[index] = `Duplicate key \"${key}\"`;\n }\n });\n }\n });\n\n this.keyErrors = newKeyErrors;\n return Object.keys(newKeyErrors).length === 0;\n }\n\n // Clear key errors\n clearKeyErrors(): void {\n this.keyErrors = {};\n }\n\n // Override updateValue to emit array format and validate keys\n protected updateValue(newValue: KeyValueItem[]) {\n this._items = newValue;\n\n // Clear errors and re-validate when items change\n this.clearKeyErrors();\n this.validateKeys();\n\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: { value: this.cleanItems(newValue) },\n bubbles: true\n })\n );\n this.requestUpdate();\n }\n\n private handleKeyChange(index: number, newKey: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when it's modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: newKey,\n value: currentItem.value\n });\n }\n\n private handleValueChange(index: number, newValue: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when value is modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: currentItem.key,\n value: newValue\n });\n }\n\n renderItem(item: KeyValueItem, index: number): TemplateResult {\n const canRemove = this.canRemoveItem(index);\n const keyError =\n this.showValidation && this.keyErrors[index] ? this.keyErrors[index] : '';\n\n return html`\n <div class=\"row\">\n <temba-textinput\n .value=${item.key}\n .placeholder=${this.keyPlaceholder}\n .errors=${keyError ? [keyError] : []}\n @change=${(e: any) => this.handleKeyChange(index, e.target.value)}\n ></temba-textinput>\n <temba-textinput\n .value=${item.value}\n .placeholder=${this.valuePlaceholder}\n @change=${(e: any) => this.handleValueChange(index, e.target.value)}\n ></temba-textinput>\n ${canRemove\n ? html`\n <button class=\"remove-btn\" @click=${() => this.removeItem(index)}>\n ×\n </button>\n `\n : html`<div class=\"remove-btn-spacer\"></div>`}\n </div>\n `;\n }\n\n protected getContainerClass(): string {\n return 'key-value-editor';\n }\n\n static styles = css`\n .key-value-editor {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .row {\n display: grid;\n grid-template-columns: 1fr 1fr auto;\n align-items: center;\n column-gap: 6px;\n }\n\n .remove-btn {\n width: 32px;\n height: 32px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: #f8f8f8;\n color: #666;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n }\n\n .remove-btn:hover:not(:disabled) {\n background: #f0f0f0;\n }\n\n .remove-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .remove-btn-spacer {\n width: 32px;\n height: 32px;\n }\n `;\n}\n"]}
1
+ {"version":3,"file":"KeyValueEditor.js","sourceRoot":"","sources":["../../../src/form/KeyValueEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, TemplateResult } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { BaseListEditor, ListItem } from './BaseListEditor';\n\ninterface KeyValueItem extends ListItem {\n key: string;\n value: string;\n}\n\n@customElement('temba-key-value-editor')\nexport class KeyValueEditor extends BaseListEditor<KeyValueItem> {\n @property({ type: String })\n keyPlaceholder = 'Key';\n\n @property({ type: String })\n valuePlaceholder = 'Value';\n\n @property({ type: Boolean })\n showValidation = true;\n\n @state()\n private keyErrors: { [index: number]: string } = {};\n\n // Configure to maintain empty items\n maintainEmptyItem = true;\n\n constructor() {\n super();\n this._items = [];\n }\n\n // External API uses array format to preserve duplicate keys\n @property({ type: Array })\n get value(): KeyValueItem[] | any[] {\n return this._items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n set value(newValue: KeyValueItem[] | Record<string, string> | any) {\n if (Array.isArray(newValue)) {\n this._items = [...newValue];\n } else {\n // Convert Record to array format\n this._items = Object.entries(newValue || {}).map(([key, value]) => ({\n key,\n value: typeof value === 'string' ? value : String(value)\n }));\n }\n this.requestUpdate();\n }\n\n // Implement abstract methods\n isEmptyItem(item: KeyValueItem): boolean {\n return item.key.trim() === '' && item.value.trim() === '';\n }\n\n createEmptyItem(): KeyValueItem {\n return { key: '', value: '' };\n }\n\n // Override cleanItems to return array format to preserve duplicate keys\n protected cleanItems(items: KeyValueItem[]): KeyValueItem[] {\n return items.filter(\n ({ key, value }) => key.trim() !== '' || value.trim() !== ''\n );\n }\n\n // Method to convert to Record format for final form submission\n toRecord(): Record<string, string> {\n const result: Record<string, string> = {};\n this._items.forEach(({ key, value }) => {\n if (key.trim() !== '' || value.trim() !== '') {\n result[key] = value;\n }\n });\n return result;\n }\n\n // Method to validate and set key errors for duplicates and empty keys with values\n validateKeys(): boolean {\n const newKeyErrors: { [index: number]: string } = {};\n\n // Check for empty keys with values\n this._items.forEach(({ key, value }, index) => {\n if (key.trim() === '' && value.trim() !== '') {\n newKeyErrors[index] = 'Key is required when value is provided';\n }\n });\n\n // Check for duplicate keys (only non-empty ones)\n const nonEmptyKeys = this._items\n .map(({ key }, index) => ({ key: key.trim(), index }))\n .filter(({ key }) => key !== '');\n\n const keyCount = new Map<string, number[]>();\n nonEmptyKeys.forEach(({ key, index }) => {\n if (!keyCount.has(key)) {\n keyCount.set(key, []);\n }\n keyCount.get(key)!.push(index);\n });\n\n // Mark duplicate keys with errors\n keyCount.forEach((indices, key) => {\n if (indices.length > 1) {\n indices.forEach((index) => {\n // Only show duplicate error if there's no empty key error already\n if (!newKeyErrors[index]) {\n newKeyErrors[index] = `Duplicate key \"${key}\"`;\n }\n });\n }\n });\n\n this.keyErrors = newKeyErrors;\n return Object.keys(newKeyErrors).length === 0;\n }\n\n // Clear key errors\n clearKeyErrors(): void {\n this.keyErrors = {};\n }\n\n // Override updateValue to emit array format and validate keys\n protected updateValue(newValue: KeyValueItem[]) {\n this._items = newValue;\n\n // Clear errors and re-validate when items change\n this.clearKeyErrors();\n this.validateKeys();\n\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: { value: this.cleanItems(newValue) },\n bubbles: true\n })\n );\n this.requestUpdate();\n }\n\n private handleKeyChange(index: number, newKey: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when it's modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: newKey,\n value: currentItem.value\n });\n }\n\n private handleValueChange(index: number, newValue: string) {\n const items = this.displayItems;\n const currentItem = items[index];\n\n // Clear any existing error for this key when value is modified\n if (this.keyErrors[index]) {\n const newKeyErrors = { ...this.keyErrors };\n delete newKeyErrors[index];\n this.keyErrors = newKeyErrors;\n }\n\n this.handleItemChange(index, {\n key: currentItem.key,\n value: newValue\n });\n }\n\n renderItem(item: KeyValueItem, index: number): TemplateResult {\n const canRemove = this.canRemoveItem(index);\n const keyError =\n this.showValidation && this.keyErrors[index] ? this.keyErrors[index] : '';\n\n return html`\n <div class=\"row\">\n <temba-textinput\n .value=${item.key}\n .placeholder=${this.keyPlaceholder}\n .errors=${keyError ? [keyError] : []}\n @change=${(e: any) => this.handleKeyChange(index, e.target.value)}\n ></temba-textinput>\n <temba-textinput\n .value=${item.value}\n .placeholder=${this.valuePlaceholder}\n @change=${(e: any) => this.handleValueChange(index, e.target.value)}\n ></temba-textinput>\n ${canRemove\n ? html`\n <button class=\"remove-btn\" @click=${() => this.removeItem(index)}>\n ×\n </button>\n `\n : html`<div class=\"remove-btn-spacer\"></div>`}\n </div>\n `;\n }\n\n protected getContainerClass(): string {\n return 'key-value-editor';\n }\n\n static get styles() {\n return css`\n ${super.styles}\n\n .key-value-editor {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .row {\n display: grid;\n grid-template-columns: 1fr 1fr auto;\n align-items: center;\n column-gap: 6px;\n }\n\n .remove-btn {\n width: 32px;\n height: 32px;\n border: 1px solid #ccc;\n border-radius: 4px;\n background: #f8f8f8;\n color: #666;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n }\n\n .remove-btn:hover:not(:disabled) {\n background: #f0f0f0;\n }\n\n .remove-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .remove-btn-spacer {\n width: 32px;\n height: 32px;\n }\n `;\n }\n}\n"]}
@@ -2,18 +2,17 @@ import { __decorate } from "tslib";
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit-html/directives/if-defined.js';
5
- import { FormElement } from './FormElement';
5
+ import { FieldElement } from './FieldElement';
6
6
  import { getClasses } from '../utils';
7
7
  import { Icon } from '../Icons';
8
8
  /**
9
9
  * MessageEditor is a composed component that combines temba-completion and temba-media-picker
10
10
  * for editing messages with text completion and file attachments
11
11
  */
12
- export class MessageEditor extends FormElement {
12
+ export class MessageEditor extends FieldElement {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.name = '';
16
- this.value = '';
17
16
  this.placeholder = '';
18
17
  this.textarea = true;
19
18
  this.autogrow = true;
@@ -28,6 +27,7 @@ export class MessageEditor extends FormElement {
28
27
  }
29
28
  static get styles() {
30
29
  return css `
30
+ ${super.styles}
31
31
  :host {
32
32
  display: block;
33
33
  }
@@ -292,85 +292,77 @@ export class MessageEditor extends FormElement {
292
292
  }
293
293
  }
294
294
  render() {
295
+ return this.renderField();
296
+ }
297
+ renderWidget() {
295
298
  const hasAttachments = this.hasStaticAttachments();
296
299
  return html `
297
- <temba-field
298
- name=${this.name}
299
- .label=${this.label}
300
- .helpText=${this.helpText}
301
- .errors=${this.errors}
302
- .widgetOnly=${this.widgetOnly}
303
- >
304
- <div
305
- class=${getClasses({
300
+ <div
301
+ class=${getClasses({
306
302
  'message-editor-container': true,
307
303
  highlight: this.pendingDrop,
308
304
  'has-attachments': hasAttachments
309
305
  })}
310
- @dragenter=${this.handleDragEnter}
311
- @dragover=${this.handleDragOver}
312
- @dragleave=${this.handleDragLeave}
313
- @drop=${this.handleDrop}
314
- >
315
- <div class="completion-wrapper">
316
- <temba-completion
317
- name=${this.name}
318
- .value=${this.value}
319
- placeholder=${this.placeholder}
320
- ?textarea=${this.textarea}
321
- ?autogrow=${this.autogrow}
322
- ?session=${this.session}
323
- ?submitOnEnter=${this.submitOnEnter}
324
- ?gsm=${this.gsm}
325
- ?disableCompletion=${this.disableCompletion}
326
- maxlength=${ifDefined(this.maxLength)}
327
- counter=${ifDefined(this.counter)}
328
- minHeight=${ifDefined(this.minHeight)}
329
- widgetOnly
330
- @change=${this.handleCompletionChange}
331
- ></temba-completion>
332
- </div>
306
+ @dragenter=${this.handleDragEnter}
307
+ @dragover=${this.handleDragOver}
308
+ @dragleave=${this.handleDragLeave}
309
+ @drop=${this.handleDrop}
310
+ >
311
+ <div class="completion-wrapper">
312
+ <temba-completion
313
+ name=${this.name}
314
+ .value=${this.value}
315
+ placeholder=${this.placeholder}
316
+ ?textarea=${this.textarea}
317
+ ?autogrow=${this.autogrow}
318
+ ?session=${this.session}
319
+ ?submitOnEnter=${this.submitOnEnter}
320
+ ?gsm=${this.gsm}
321
+ ?disableCompletion=${this.disableCompletion}
322
+ maxlength=${ifDefined(this.maxLength)}
323
+ counter=${ifDefined(this.counter)}
324
+ minHeight=${ifDefined(this.minHeight)}
325
+ widgetOnly
326
+ @change=${this.handleCompletionChange}
327
+ ></temba-completion>
328
+ </div>
329
+
330
+ <div class="media-wrapper ">
331
+ <temba-media-picker
332
+ .accept=${this.accept}
333
+ .max=${this.maxAttachments}
334
+ .endpoint=${this.endpoint}
335
+ @change=${this.handleMediaChange}
336
+ ignoreDrops
337
+ ></temba-media-picker>
338
+ </div>
339
+ <temba-icon
340
+ class="attachment-icon"
341
+ name=${Icon.attachment}
342
+ size="1.2"
343
+ @click=${this.handleAttachmentIconClick}
344
+ ></temba-icon>
345
+
346
+ <div class="drop-overlay"></div>
333
347
 
334
- <div class="media-wrapper ">
335
- <temba-media-picker
348
+ <!-- Hidden media picker for handling uploads when no attachments are shown -->
349
+ ${!hasAttachments
350
+ ? html `<temba-media-picker
351
+ style="display: none;"
336
352
  .accept=${this.accept}
337
353
  .max=${this.maxAttachments}
338
354
  .endpoint=${this.endpoint}
339
355
  @change=${this.handleMediaChange}
340
356
  ignoreDrops
341
- ></temba-media-picker>
342
- </div>
343
- <temba-icon
344
- class="attachment-icon"
345
- name=${Icon.attachment}
346
- size="1.2"
347
- @click=${this.handleAttachmentIconClick}
348
- ></temba-icon>
349
-
350
- <div class="drop-overlay"></div>
351
-
352
- <!-- Hidden media picker for handling uploads when no attachments are shown -->
353
- ${!hasAttachments
354
- ? html `<temba-media-picker
355
- style="display: none;"
356
- .accept=${this.accept}
357
- .max=${this.maxAttachments}
358
- .endpoint=${this.endpoint}
359
- @change=${this.handleMediaChange}
360
- ignoreDrops
361
- ></temba-media-picker>`
357
+ ></temba-media-picker>`
362
358
  : ''}
363
- </div>
364
- </temba-field>
359
+ </div>
365
360
  `;
366
361
  }
367
362
  }
368
363
  __decorate([
369
364
  property({ type: String })
370
365
  ], MessageEditor.prototype, "name", void 0);
371
- __decorate([
372
- property({ type: String })
373
- ], MessageEditor.prototype, "value", void 0);
374
366
  __decorate([
375
367
  property({ type: String })
376
368
  ], MessageEditor.prototype, "placeholder", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"MessageEditor.js","sourceRoot":"","sources":["../../../src/form/MessageEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, css, html } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit-html/directives/if-defined.js';\nimport { FormElement } from './FormElement';\nimport { Completion } from './Completion';\nimport { MediaPicker } from './MediaPicker';\nimport { Attachment } from '../interfaces';\nimport { getClasses } from '../utils';\nimport { Icon } from '../Icons';\n\n/**\n * MessageEditor is a composed component that combines temba-completion and temba-media-picker\n * for editing messages with text completion and file attachments\n */\nexport class MessageEditor extends FormElement {\n static get styles() {\n return css`\n :host {\n display: block;\n }\n\n .message-editor-container {\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature-widget);\n background: #fff;\n position: relative;\n transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;\n }\n\n .message-editor-container:focus-within {\n border-color: var(--color-focus);\n box-shadow: var(--widget-box-shadow-focused);\n }\n\n .message-editor-container.highlight {\n border-color: rgba(156, 222, 106, 0.88);\n }\n\n /* Hide the completion field border since we draw our own */\n .message-editor-container temba-completion::part(field) {\n border: none;\n box-shadow: none;\n border-radius: 0;\n }\n\n .message-editor-container temba-completion {\n --widget-box-shadow: none;\n --widget-box-shadow-focused: none;\n --widget-box-shadow-focused: none;\n --color-widget-border: transparent;\n --color-focus: transparent;\n }\n\n .completion-wrapper {\n }\n\n .media-wrapper {\n padding: 4px 8px;\n background: rgba(0, 0, 0, 0.03);\n border-top: 1px solid var(--color-widget-border);\n border-radius: 0 0 var(--curvature-widget) var(--curvature-widget);\n box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.05);\n margin-top: 3px;\n display: none;\n }\n .has-attachments .media-wrapper {\n display: flex;\n }\n\n /* Override media picker styles to integrate better */\n .media-wrapper temba-media-picker {\n --color-widget-border: transparent;\n }\n\n .media-wrapper .attachments-list {\n padding: 0.2em 0;\n }\n\n .drop-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(210, 243, 184, 0.5);\n border-radius: var(--curvature-widget);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease-in-out;\n z-index: 10;\n }\n\n .message-editor-container.highlight .drop-overlay {\n opacity: 1;\n }\n\n .drop-message {\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 12px 24px;\n border-radius: var(--curvature);\n font-weight: 500;\n }\n\n .attachment-icon {\n position: absolute;\n bottom: 4px;\n right: 4px;\n color: var(--color-text-dark);\n cursor: pointer;\n padding: 6px;\n border-radius: var(--curvature);\n transition: background-color 0.2s ease-in-out;\n display: block;\n }\n\n .has-attachments .attachment-icon {\n display: none;\n }\n\n .attachment-icon:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n `;\n }\n\n @property({ type: String })\n name = '';\n\n @property({ type: String })\n value = '';\n\n @property({ type: String })\n placeholder = '';\n\n @property({ type: Boolean })\n textarea = true;\n\n @property({ type: Boolean })\n autogrow = true;\n\n @property({ type: Number })\n minHeight = 60;\n\n @property({ type: Number })\n maxLength: number;\n\n @property({ type: Boolean })\n session: boolean;\n\n @property({ type: Boolean })\n submitOnEnter = false;\n\n @property({ type: Boolean })\n gsm: boolean;\n\n @property({ type: Boolean })\n disableCompletion: boolean;\n\n @property({ type: String })\n counter: string;\n\n @property({ type: Array })\n attachments: (Attachment | string)[] = [];\n\n @property({ type: String })\n accept = '';\n\n @property({ type: Number, attribute: 'max-attachments' })\n maxAttachments = 3;\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Boolean, attribute: false })\n pendingDrop = false;\n\n @property({ type: Boolean, attribute: false })\n uploading = false;\n\n private completionElement: Completion;\n private mediaPickerElement: MediaPicker;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n\n this.completionElement = this.shadowRoot.querySelector(\n 'temba-completion'\n ) as Completion;\n\n // Get the visible media picker (either in media-wrapper or the hidden one)\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n\n // Set up proper attachment filtering and parsing\n this.parseAndFilterAttachments();\n }\n\n /**\n * Parse attachments and filter out runtime attachments for media picker\n */\n private parseAndFilterAttachments() {\n if (!this.attachments) return;\n\n // Filter out runtime attachments (those without '/' in content type)\n const staticAttachments = this.attachments.filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n\n // Convert string attachments to Attachment objects for media picker\n const mediaAttachments = staticAttachments.map((attachment) => {\n if (typeof attachment === 'string') {\n // split into content type and URL\n // e.g. \"image/jpeg:http://example.com/image.jpg\"\n const colonIndex = attachment.indexOf(':');\n const contentType = attachment.substring(0, colonIndex);\n const url = attachment.substring(colonIndex + 1);\n return {\n content_type: contentType,\n url: url,\n filename: this.getFilenameFromUrl(url),\n size: 0\n } as Attachment;\n }\n return attachment;\n });\n\n if (this.mediaPickerElement) {\n this.mediaPickerElement.attachments = mediaAttachments;\n }\n }\n\n /**\n * Check if there are any static attachments (excluding runtime attachments)\n */\n private hasStaticAttachments(): boolean {\n if (!this.attachments || this.attachments.length === 0) return false;\n\n return this.attachments.some((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n }\n\n private getFilenameFromUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n return pathname.substring(pathname.lastIndexOf('/') + 1) || 'attachment';\n } catch {\n return 'attachment';\n }\n }\n\n private handleCompletionChange(event: Event) {\n event.stopPropagation();\n const completion = event.target as Completion;\n this.value = completion.value;\n this.fireEvent('change');\n }\n\n private handleMediaChange(event: Event) {\n event.stopPropagation();\n const mediaPicker = event.target as MediaPicker;\n // Convert media picker attachments back to the format expected by the form\n const formattedAttachments = mediaPicker.attachments.map((attachment) => {\n return `${attachment.content_type}:${attachment.url}`;\n });\n\n // Merge with any runtime attachments that were filtered out\n const runtimeAttachments = (this.attachments || []).filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return !contentType.includes('/');\n }\n return false;\n }) as string[];\n\n this.attachments = [...runtimeAttachments, ...formattedAttachments];\n this.fireEvent('change');\n }\n\n private handleDragEnter(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragOver(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragLeave(evt: DragEvent): void {\n this.unhighlight(evt);\n }\n\n private handleDrop(evt: DragEvent): void {\n this.unhighlight(evt);\n\n // Forward to media picker\n if (this.mediaPickerElement) {\n const files = [...evt.dataTransfer.files];\n this.mediaPickerElement.uploadFiles(files);\n }\n }\n\n private handleAttachmentIconClick(): void {\n // Trigger the file picker on the media picker\n if (this.mediaPickerElement) {\n const uploadInput = this.mediaPickerElement.shadowRoot.querySelector(\n '#upload-input'\n ) as HTMLInputElement;\n if (uploadInput) {\n uploadInput.click();\n }\n }\n }\n\n private highlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n\n // Always allow highlight for testing purposes, but in real usage check media picker\n this.pendingDrop = true;\n }\n\n private unhighlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n this.pendingDrop = false;\n }\n\n public updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('attachments')) {\n // Re-query media picker since the DOM structure may have changed\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n }\n\n if (changedProperties.has('uploading')) {\n this.dispatchEvent(\n new CustomEvent('loading', {\n detail: { loading: this.uploading }\n })\n );\n }\n }\n\n public focus() {\n super.focus();\n if (this.completionElement) {\n this.completionElement.focus();\n }\n }\n\n public click() {\n super.click();\n if (this.completionElement) {\n this.completionElement.click();\n }\n }\n\n public render(): TemplateResult {\n const hasAttachments = this.hasStaticAttachments();\n\n return html`\n <temba-field\n name=${this.name}\n .label=${this.label}\n .helpText=${this.helpText}\n .errors=${this.errors}\n .widgetOnly=${this.widgetOnly}\n >\n <div\n class=${getClasses({\n 'message-editor-container': true,\n highlight: this.pendingDrop,\n 'has-attachments': hasAttachments\n })}\n @dragenter=${this.handleDragEnter}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n <div class=\"completion-wrapper\">\n <temba-completion\n name=${this.name}\n .value=${this.value}\n placeholder=${this.placeholder}\n ?textarea=${this.textarea}\n ?autogrow=${this.autogrow}\n ?session=${this.session}\n ?submitOnEnter=${this.submitOnEnter}\n ?gsm=${this.gsm}\n ?disableCompletion=${this.disableCompletion}\n maxlength=${ifDefined(this.maxLength)}\n counter=${ifDefined(this.counter)}\n minHeight=${ifDefined(this.minHeight)}\n widgetOnly\n @change=${this.handleCompletionChange}\n ></temba-completion>\n </div>\n\n <div class=\"media-wrapper \">\n <temba-media-picker\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>\n </div>\n <temba-icon\n class=\"attachment-icon\"\n name=${Icon.attachment}\n size=\"1.2\"\n @click=${this.handleAttachmentIconClick}\n ></temba-icon>\n\n <div class=\"drop-overlay\"></div>\n\n <!-- Hidden media picker for handling uploads when no attachments are shown -->\n ${!hasAttachments\n ? html`<temba-media-picker\n style=\"display: none;\"\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>`\n : ''}\n </div>\n </temba-field>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"MessageEditor.js","sourceRoot":"","sources":["../../../src/form/MessageEditor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAkB,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI9C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,YAAY;IAA/C;;QAqHE,SAAI,GAAG,EAAE,CAAC;QAGV,gBAAW,GAAG,EAAE,CAAC;QAGjB,aAAQ,GAAG,IAAI,CAAC;QAGhB,aAAQ,GAAG,IAAI,CAAC;QAGhB,cAAS,GAAG,EAAE,CAAC;QASf,kBAAa,GAAG,KAAK,CAAC;QAYtB,gBAAW,GAA4B,EAAE,CAAC;QAG1C,WAAM,GAAG,EAAE,CAAC;QAGZ,mBAAc,GAAG,CAAC,CAAC;QAGnB,aAAQ,GAAG,EAAE,CAAC;QAGd,gBAAW,GAAG,KAAK,CAAC;QAGpB,cAAS,GAAG,KAAK,CAAC;IAuQpB,CAAC;IA3aC,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;QACN,KAAK,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8Gf,CAAC;IACJ,CAAC;IAwDM,YAAY,CAAC,OAAyB;QAC3C,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE5B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CACpD,kBAAkB,CACL,CAAC;QAEhB,2EAA2E;QAC3E,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CACrD,oBAAoB,CACN,CAAC;QAEjB,iDAAiD;QACjD,IAAI,CAAC,yBAAyB,EAAE,CAAC;IACnC,CAAC;IAED;;OAEG;IACK,yBAAyB;QAC/B,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAE9B,qEAAqE;QACrE,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;YAC/D,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBACnC,MAAM,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,oEAAoE;QACpE,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;YAC5D,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBACnC,kCAAkC;gBAClC,iDAAiD;gBACjD,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC3C,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;gBACxD,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;gBACjD,OAAO;oBACL,YAAY,EAAE,WAAW;oBACzB,GAAG,EAAE,GAAG;oBACR,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC;oBACtC,IAAI,EAAE,CAAC;iBACM,CAAC;YAClB,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,IAAI,CAAC,kBAAkB,CAAC,WAAW,GAAG,gBAAgB,CAAC;QACzD,CAAC;IACH,CAAC;IAED;;OAEG;IACK,oBAAoB;QAC1B,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAErE,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;YAC1C,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBACnC,MAAM,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,kBAAkB,CAAC,GAAW;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACjC,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,YAAY,CAAC;QAC3E,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,KAAY;QACzC,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,KAAK,CAAC,MAAoB,CAAC;QAC9C,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IAEO,iBAAiB,CAAC,KAAY;QACpC,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,KAAK,CAAC,MAAqB,CAAC;QAChD,2EAA2E;QAC3E,MAAM,oBAAoB,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;YACtE,OAAO,GAAG,UAAU,CAAC,YAAY,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,4DAA4D;QAC5D,MAAM,kBAAkB,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;YACxE,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBACnC,MAAM,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC5C,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACpC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAa,CAAC;QAEf,IAAI,CAAC,WAAW,GAAG,CAAC,GAAG,kBAAkB,EAAE,GAAG,oBAAoB,CAAC,CAAC;QACpE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IAEO,eAAe,CAAC,GAAc;QACpC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAEO,cAAc,CAAC,GAAc;QACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAEO,eAAe,CAAC,GAAc;QACpC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAEO,UAAU,CAAC,GAAc;QAC/B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAEtB,0BAA0B;QAC1B,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAC1C,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAEO,yBAAyB;QAC/B,8CAA8C;QAC9C,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,aAAa,CAClE,eAAe,CACI,CAAC;YACtB,IAAI,WAAW,EAAE,CAAC;gBAChB,WAAW,CAAC,KAAK,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,GAAc;QAC9B,GAAG,CAAC,cAAc,EAAE,CAAC;QACrB,GAAG,CAAC,eAAe,EAAE,CAAC;QAEtB,oFAAoF;QACpF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAEO,WAAW,CAAC,GAAc;QAChC,GAAG,CAAC,cAAc,EAAE,CAAC;QACrB,GAAG,CAAC,eAAe,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IAEM,OAAO,CAAC,iBAAmC;QAChD,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAEjC,IAAI,iBAAiB,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YACzC,iEAAiE;YACjE,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CACrD,oBAAoB,CACN,CAAC;QACnB,CAAC;QAED,IAAI,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,SAAS,EAAE;gBACzB,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE;aACpC,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAEM,KAAK;QACV,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QACjC,CAAC;IACH,CAAC;IAEM,KAAK;QACV,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QACjC,CAAC;IACH,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;IAES,YAAY;QACpB,MAAM,cAAc,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAEnD,OAAO,IAAI,CAAA;;gBAEC,UAAU,CAAC;YACjB,0BAA0B,EAAE,IAAI;YAChC,SAAS,EAAE,IAAI,CAAC,WAAW;YAC3B,iBAAiB,EAAE,cAAc;SAClC,CAAC;qBACW,IAAI,CAAC,eAAe;oBACrB,IAAI,CAAC,cAAc;qBAClB,IAAI,CAAC,eAAe;gBACzB,IAAI,CAAC,UAAU;;;;mBAIZ,IAAI,CAAC,IAAI;qBACP,IAAI,CAAC,KAAK;0BACL,IAAI,CAAC,WAAW;wBAClB,IAAI,CAAC,QAAQ;wBACb,IAAI,CAAC,QAAQ;uBACd,IAAI,CAAC,OAAO;6BACN,IAAI,CAAC,aAAa;mBAC5B,IAAI,CAAC,GAAG;iCACM,IAAI,CAAC,iBAAiB;wBAC/B,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;sBAC3B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;wBACrB,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;;sBAE3B,IAAI,CAAC,sBAAsB;;;;;;sBAM3B,IAAI,CAAC,MAAM;mBACd,IAAI,CAAC,cAAc;wBACd,IAAI,CAAC,QAAQ;sBACf,IAAI,CAAC,iBAAiB;;;;;;iBAM3B,IAAI,CAAC,UAAU;;mBAEb,IAAI,CAAC,yBAAyB;;;;;;UAMvC,CAAC,cAAc;YACf,CAAC,CAAC,IAAI,CAAA;;wBAEQ,IAAI,CAAC,MAAM;qBACd,IAAI,CAAC,cAAc;0BACd,IAAI,CAAC,QAAQ;wBACf,IAAI,CAAC,iBAAiB;;mCAEX;YACzB,CAAC,CAAC,EAAE;;KAET,CAAC;IACJ,CAAC;CACF;AAvTC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CACjB;AAGV;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;kDACV;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;+CACZ;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;+CACZ;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDACZ;AAGf;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDACT;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;8CACX;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;oDACN;AAGtB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;0CACf;AAGb;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;wDACD;AAG3B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;8CACX;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;kDACgB;AAG1C;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CACf;AAGZ;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;qDACtC;AAGnB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CACb;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;kDAC1B;AAGpB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;gDAC5B","sourcesContent":["import { TemplateResult, css, html } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit-html/directives/if-defined.js';\nimport { FieldElement } from './FieldElement';\nimport { Completion } from './Completion';\nimport { MediaPicker } from './MediaPicker';\nimport { Attachment } from '../interfaces';\nimport { getClasses } from '../utils';\nimport { Icon } from '../Icons';\n\n/**\n * MessageEditor is a composed component that combines temba-completion and temba-media-picker\n * for editing messages with text completion and file attachments\n */\nexport class MessageEditor extends FieldElement {\n static get styles() {\n return css`\n ${super.styles}\n :host {\n display: block;\n }\n\n .message-editor-container {\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature-widget);\n background: #fff;\n position: relative;\n transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;\n }\n\n .message-editor-container:focus-within {\n border-color: var(--color-focus);\n box-shadow: var(--widget-box-shadow-focused);\n }\n\n .message-editor-container.highlight {\n border-color: rgba(156, 222, 106, 0.88);\n }\n\n /* Hide the completion field border since we draw our own */\n .message-editor-container temba-completion::part(field) {\n border: none;\n box-shadow: none;\n border-radius: 0;\n }\n\n .message-editor-container temba-completion {\n --widget-box-shadow: none;\n --widget-box-shadow-focused: none;\n --widget-box-shadow-focused: none;\n --color-widget-border: transparent;\n --color-focus: transparent;\n }\n\n .completion-wrapper {\n }\n\n .media-wrapper {\n padding: 4px 8px;\n background: rgba(0, 0, 0, 0.03);\n border-top: 1px solid var(--color-widget-border);\n border-radius: 0 0 var(--curvature-widget) var(--curvature-widget);\n box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.05);\n margin-top: 3px;\n display: none;\n }\n .has-attachments .media-wrapper {\n display: flex;\n }\n\n /* Override media picker styles to integrate better */\n .media-wrapper temba-media-picker {\n --color-widget-border: transparent;\n }\n\n .media-wrapper .attachments-list {\n padding: 0.2em 0;\n }\n\n .drop-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(210, 243, 184, 0.5);\n border-radius: var(--curvature-widget);\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease-in-out;\n z-index: 10;\n }\n\n .message-editor-container.highlight .drop-overlay {\n opacity: 1;\n }\n\n .drop-message {\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 12px 24px;\n border-radius: var(--curvature);\n font-weight: 500;\n }\n\n .attachment-icon {\n position: absolute;\n bottom: 4px;\n right: 4px;\n color: var(--color-text-dark);\n cursor: pointer;\n padding: 6px;\n border-radius: var(--curvature);\n transition: background-color 0.2s ease-in-out;\n display: block;\n }\n\n .has-attachments .attachment-icon {\n display: none;\n }\n\n .attachment-icon:hover {\n background-color: rgba(0, 0, 0, 0.05);\n }\n `;\n }\n\n @property({ type: String })\n name = '';\n\n @property({ type: String })\n placeholder = '';\n\n @property({ type: Boolean })\n textarea = true;\n\n @property({ type: Boolean })\n autogrow = true;\n\n @property({ type: Number })\n minHeight = 60;\n\n @property({ type: Number })\n maxLength: number;\n\n @property({ type: Boolean })\n session: boolean;\n\n @property({ type: Boolean })\n submitOnEnter = false;\n\n @property({ type: Boolean })\n gsm: boolean;\n\n @property({ type: Boolean })\n disableCompletion: boolean;\n\n @property({ type: String })\n counter: string;\n\n @property({ type: Array })\n attachments: (Attachment | string)[] = [];\n\n @property({ type: String })\n accept = '';\n\n @property({ type: Number, attribute: 'max-attachments' })\n maxAttachments = 3;\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Boolean, attribute: false })\n pendingDrop = false;\n\n @property({ type: Boolean, attribute: false })\n uploading = false;\n\n private completionElement: Completion;\n private mediaPickerElement: MediaPicker;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n\n this.completionElement = this.shadowRoot.querySelector(\n 'temba-completion'\n ) as Completion;\n\n // Get the visible media picker (either in media-wrapper or the hidden one)\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n\n // Set up proper attachment filtering and parsing\n this.parseAndFilterAttachments();\n }\n\n /**\n * Parse attachments and filter out runtime attachments for media picker\n */\n private parseAndFilterAttachments() {\n if (!this.attachments) return;\n\n // Filter out runtime attachments (those without '/' in content type)\n const staticAttachments = this.attachments.filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n\n // Convert string attachments to Attachment objects for media picker\n const mediaAttachments = staticAttachments.map((attachment) => {\n if (typeof attachment === 'string') {\n // split into content type and URL\n // e.g. \"image/jpeg:http://example.com/image.jpg\"\n const colonIndex = attachment.indexOf(':');\n const contentType = attachment.substring(0, colonIndex);\n const url = attachment.substring(colonIndex + 1);\n return {\n content_type: contentType,\n url: url,\n filename: this.getFilenameFromUrl(url),\n size: 0\n } as Attachment;\n }\n return attachment;\n });\n\n if (this.mediaPickerElement) {\n this.mediaPickerElement.attachments = mediaAttachments;\n }\n }\n\n /**\n * Check if there are any static attachments (excluding runtime attachments)\n */\n private hasStaticAttachments(): boolean {\n if (!this.attachments || this.attachments.length === 0) return false;\n\n return this.attachments.some((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return contentType.includes('/');\n }\n return true;\n });\n }\n\n private getFilenameFromUrl(url: string): string {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n return pathname.substring(pathname.lastIndexOf('/') + 1) || 'attachment';\n } catch {\n return 'attachment';\n }\n }\n\n private handleCompletionChange(event: Event) {\n event.stopPropagation();\n const completion = event.target as Completion;\n this.value = completion.value;\n this.fireEvent('change');\n }\n\n private handleMediaChange(event: Event) {\n event.stopPropagation();\n const mediaPicker = event.target as MediaPicker;\n // Convert media picker attachments back to the format expected by the form\n const formattedAttachments = mediaPicker.attachments.map((attachment) => {\n return `${attachment.content_type}:${attachment.url}`;\n });\n\n // Merge with any runtime attachments that were filtered out\n const runtimeAttachments = (this.attachments || []).filter((attachment) => {\n if (typeof attachment === 'string') {\n const [contentType] = attachment.split(':');\n return !contentType.includes('/');\n }\n return false;\n }) as string[];\n\n this.attachments = [...runtimeAttachments, ...formattedAttachments];\n this.fireEvent('change');\n }\n\n private handleDragEnter(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragOver(evt: DragEvent): void {\n this.highlight(evt);\n }\n\n private handleDragLeave(evt: DragEvent): void {\n this.unhighlight(evt);\n }\n\n private handleDrop(evt: DragEvent): void {\n this.unhighlight(evt);\n\n // Forward to media picker\n if (this.mediaPickerElement) {\n const files = [...evt.dataTransfer.files];\n this.mediaPickerElement.uploadFiles(files);\n }\n }\n\n private handleAttachmentIconClick(): void {\n // Trigger the file picker on the media picker\n if (this.mediaPickerElement) {\n const uploadInput = this.mediaPickerElement.shadowRoot.querySelector(\n '#upload-input'\n ) as HTMLInputElement;\n if (uploadInput) {\n uploadInput.click();\n }\n }\n }\n\n private highlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n\n // Always allow highlight for testing purposes, but in real usage check media picker\n this.pendingDrop = true;\n }\n\n private unhighlight(evt: DragEvent): void {\n evt.preventDefault();\n evt.stopPropagation();\n this.pendingDrop = false;\n }\n\n public updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n\n if (changedProperties.has('attachments')) {\n // Re-query media picker since the DOM structure may have changed\n this.mediaPickerElement = this.shadowRoot.querySelector(\n 'temba-media-picker'\n ) as MediaPicker;\n }\n\n if (changedProperties.has('uploading')) {\n this.dispatchEvent(\n new CustomEvent('loading', {\n detail: { loading: this.uploading }\n })\n );\n }\n }\n\n public focus() {\n super.focus();\n if (this.completionElement) {\n this.completionElement.focus();\n }\n }\n\n public click() {\n super.click();\n if (this.completionElement) {\n this.completionElement.click();\n }\n }\n\n public render(): TemplateResult {\n return this.renderField();\n }\n\n protected renderWidget(): TemplateResult {\n const hasAttachments = this.hasStaticAttachments();\n\n return html`\n <div\n class=${getClasses({\n 'message-editor-container': true,\n highlight: this.pendingDrop,\n 'has-attachments': hasAttachments\n })}\n @dragenter=${this.handleDragEnter}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n <div class=\"completion-wrapper\">\n <temba-completion\n name=${this.name}\n .value=${this.value}\n placeholder=${this.placeholder}\n ?textarea=${this.textarea}\n ?autogrow=${this.autogrow}\n ?session=${this.session}\n ?submitOnEnter=${this.submitOnEnter}\n ?gsm=${this.gsm}\n ?disableCompletion=${this.disableCompletion}\n maxlength=${ifDefined(this.maxLength)}\n counter=${ifDefined(this.counter)}\n minHeight=${ifDefined(this.minHeight)}\n widgetOnly\n @change=${this.handleCompletionChange}\n ></temba-completion>\n </div>\n\n <div class=\"media-wrapper \">\n <temba-media-picker\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>\n </div>\n <temba-icon\n class=\"attachment-icon\"\n name=${Icon.attachment}\n size=\"1.2\"\n @click=${this.handleAttachmentIconClick}\n ></temba-icon>\n\n <div class=\"drop-overlay\"></div>\n\n <!-- Hidden media picker for handling uploads when no attachments are shown -->\n ${!hasAttachments\n ? html`<temba-media-picker\n style=\"display: none;\"\n .accept=${this.accept}\n .max=${this.maxAttachments}\n .endpoint=${this.endpoint}\n @change=${this.handleMediaChange}\n ignoreDrops\n ></temba-media-picker>`\n : ''}\n </div>\n `;\n }\n}\n"]}
@@ -2,9 +2,9 @@ import { __decorate } from "tslib";
2
2
  import { css, html } from 'lit';
3
3
  import { styleMap } from 'lit-html/directives/style-map.js';
4
4
  import { property } from 'lit/decorators.js';
5
- import { FormElement } from './FormElement';
5
+ import { FieldElement } from './FieldElement';
6
6
  import { getClasses } from '../utils';
7
- export class TembaSlider extends FormElement {
7
+ export class TembaSlider extends FieldElement {
8
8
  constructor() {
9
9
  super(...arguments);
10
10
  this.range = false;
@@ -128,7 +128,7 @@ export class TembaSlider extends FormElement {
128
128
  this.circleX = pctAsPixels + (pre ? pre.offsetWidth : 0);
129
129
  this.requestUpdate();
130
130
  }
131
- render() {
131
+ renderWidget() {
132
132
  return html ` <div class="${getClasses({ grabbed: this.grabbed })}">
133
133
  <div
134
134
  style=${styleMap({ left: this.circleX + 'px' })}
@@ -1 +1 @@
1
- {"version":3,"file":"TembaSlider.js","sourceRoot":"","sources":["../../../src/form/TembaSlider.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { styleMap } from 'lit-html/directives/style-map.js';\nimport { property } from 'lit/decorators.js';\nimport { FormElement } from './FormElement';\nimport { getClasses } from '../utils';\n\nexport class TembaSlider extends FormElement {\n static get styles() {\n return css`\n :host {\n display: block;\n }\n\n .track {\n height: 2px;\n border-top: 0.5em solid #fff;\n border-bottom: 0.5em solid #fff;\n background: #ddd;\n flex-grow: 1;\n }\n\n .circle {\n margin-bottom: -1.05em;\n margin-left: -0.5em;\n width: 0.75em;\n height: 0.75em;\n border: 2px solid #999;\n border-radius: 999px;\n position: relative;\n background: #fff;\n box-shadow: 0 0 0 4px rgb(255, 255, 255);\n transition: transform 200ms ease-in-out;\n }\n\n .grabbed .track {\n cursor: pointer;\n }\n\n :hover .circle {\n border-color: #777;\n cursor: pointer;\n }\n\n .grabbed .circle {\n border-color: var(--color-primary-dark);\n background: #fff;\n }\n\n .grabbed .circle {\n transform: scale(1.2);\n }\n\n .wrapper {\n display: flex;\n align-items: center;\n }\n\n .pre,\n .post {\n font-size: 0.9em;\n color: #999;\n padding: 0em 1em;\n }\n `;\n }\n\n @property({ type: Boolean })\n range = false;\n\n @property({ type: Number })\n min = 0;\n\n @property({ type: Number })\n max = 100;\n\n circleX = 0;\n grabbed = false;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n if (changedProperties.has('value')) {\n this.updateCircle();\n }\n }\n\n public updateValue(evt: MouseEvent) {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const left = evt.pageX - track.offsetLeft;\n const pct = left / track.offsetWidth;\n\n const range = this.max - this.min;\n const pctAsValue = range * pct + this.min;\n this.value =\n '' + Math.max(this.min, Math.min(Math.round(pctAsValue), this.max));\n }\n\n public handleMouseMove(evt: MouseEvent) {\n if (this.grabbed) {\n this.updateValue(evt);\n }\n }\n\n public handleTrackDown(evt: MouseEvent) {\n this.grabbed = true;\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.add('dragging');\n this.updateValue(evt);\n this.requestUpdate();\n }\n\n public handleMouseUp(evt: MouseEvent) {\n this.grabbed = false;\n this.updateValue(evt);\n this.requestUpdate();\n\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.remove('dragging');\n }\n\n public updateCircle() {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const pre = this.shadowRoot.querySelector('.pre') as HTMLDivElement;\n const range = this.max - this.min;\n let cValue = parseInt(this.value);\n if (!cValue || cValue < this.min) {\n cValue = this.min;\n } else if (cValue > this.max) {\n cValue = this.max;\n }\n this.value = '' + cValue;\n const pct = (cValue - this.min) / range;\n const pctAsPixels = track.offsetWidth * pct;\n\n this.circleX = pctAsPixels + (pre ? pre.offsetWidth : 0);\n this.requestUpdate();\n }\n\n public render(): TemplateResult {\n return html` <div class=\"${getClasses({ grabbed: this.grabbed })}\">\n <div\n style=${styleMap({ left: this.circleX + 'px' })}\n class=\"circle\"\n @mousedown=${this.handleTrackDown}\n ></div>\n <div class=\"wrapper\">\n ${this.range ? html`<div class=\"pre\">${this.min}</div>` : null}\n <div class=\"track\" @mousedown=${this.handleTrackDown}></div>\n ${this.range ? html`<div class=\"post\">${this.max}</div>` : null}\n </div>\n </div>`;\n }\n}\n"]}
1
+ {"version":3,"file":"TembaSlider.js","sourceRoot":"","sources":["../../../src/form/TembaSlider.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, TemplateResult } from 'lit';\nimport { styleMap } from 'lit-html/directives/style-map.js';\nimport { property } from 'lit/decorators.js';\nimport { FieldElement } from './FieldElement';\nimport { getClasses } from '../utils';\n\nexport class TembaSlider extends FieldElement {\n static get styles() {\n return css`\n :host {\n display: block;\n }\n\n .track {\n height: 2px;\n border-top: 0.5em solid #fff;\n border-bottom: 0.5em solid #fff;\n background: #ddd;\n flex-grow: 1;\n }\n\n .circle {\n margin-bottom: -1.05em;\n margin-left: -0.5em;\n width: 0.75em;\n height: 0.75em;\n border: 2px solid #999;\n border-radius: 999px;\n position: relative;\n background: #fff;\n box-shadow: 0 0 0 4px rgb(255, 255, 255);\n transition: transform 200ms ease-in-out;\n }\n\n .grabbed .track {\n cursor: pointer;\n }\n\n :hover .circle {\n border-color: #777;\n cursor: pointer;\n }\n\n .grabbed .circle {\n border-color: var(--color-primary-dark);\n background: #fff;\n }\n\n .grabbed .circle {\n transform: scale(1.2);\n }\n\n .wrapper {\n display: flex;\n align-items: center;\n }\n\n .pre,\n .post {\n font-size: 0.9em;\n color: #999;\n padding: 0em 1em;\n }\n `;\n }\n\n @property({ type: Boolean })\n range = false;\n\n @property({ type: Number })\n min = 0;\n\n @property({ type: Number })\n max = 100;\n\n circleX = 0;\n grabbed = false;\n\n public firstUpdated(changes: Map<string, any>) {\n super.firstUpdated(changes);\n this.handleMouseMove = this.handleMouseMove.bind(this);\n this.handleMouseUp = this.handleMouseUp.bind(this);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n if (changedProperties.has('value')) {\n this.updateCircle();\n }\n }\n\n public updateValue(evt: MouseEvent) {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const left = evt.pageX - track.offsetLeft;\n const pct = left / track.offsetWidth;\n\n const range = this.max - this.min;\n const pctAsValue = range * pct + this.min;\n this.value =\n '' + Math.max(this.min, Math.min(Math.round(pctAsValue), this.max));\n }\n\n public handleMouseMove(evt: MouseEvent) {\n if (this.grabbed) {\n this.updateValue(evt);\n }\n }\n\n public handleTrackDown(evt: MouseEvent) {\n this.grabbed = true;\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.add('dragging');\n this.updateValue(evt);\n this.requestUpdate();\n }\n\n public handleMouseUp(evt: MouseEvent) {\n this.grabbed = false;\n this.updateValue(evt);\n this.requestUpdate();\n\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n document.querySelector('html').classList.remove('dragging');\n }\n\n public updateCircle() {\n const track = this.shadowRoot.querySelector('.track') as HTMLDivElement;\n const pre = this.shadowRoot.querySelector('.pre') as HTMLDivElement;\n const range = this.max - this.min;\n let cValue = parseInt(this.value);\n if (!cValue || cValue < this.min) {\n cValue = this.min;\n } else if (cValue > this.max) {\n cValue = this.max;\n }\n this.value = '' + cValue;\n const pct = (cValue - this.min) / range;\n const pctAsPixels = track.offsetWidth * pct;\n\n this.circleX = pctAsPixels + (pre ? pre.offsetWidth : 0);\n this.requestUpdate();\n }\n\n public renderWidget(): TemplateResult {\n return html` <div class=\"${getClasses({ grabbed: this.grabbed })}\">\n <div\n style=${styleMap({ left: this.circleX + 'px' })}\n class=\"circle\"\n @mousedown=${this.handleTrackDown}\n ></div>\n <div class=\"wrapper\">\n ${this.range ? html`<div class=\"pre\">${this.min}</div>` : null}\n <div class=\"track\" @mousedown=${this.handleTrackDown}></div>\n ${this.range ? html`<div class=\"post\">${this.max}</div>` : null}\n </div>\n </div>`;\n }\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { property } from 'lit/decorators.js';
3
- import { FormElement } from './FormElement';
4
3
  import { html, css, LitElement } from 'lit';
5
4
  import { CustomEventType } from '../interfaces';
6
5
  import { getClasses } from '../utils';
7
- export class TemplateEditor extends FormElement {
6
+ import { FieldElement } from './FieldElement';
7
+ export class TemplateEditor extends FieldElement {
8
8
  constructor() {
9
9
  super(...arguments);
10
10
  this.pickersLoading = {};
@@ -373,7 +373,7 @@ export class TemplateEditor extends FormElement {
373
373
  <div class="buttons">${buttons}</div>
374
374
  </div>`;
375
375
  }
376
- render() {
376
+ renderWidget() {
377
377
  let content = null;
378
378
  if (this.translation) {
379
379
  content = this.renderComponents(this.translation.components);