@nyaruka/temba-components 0.129.8 → 0.129.10

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 (282) hide show
  1. package/CHANGELOG.md +37 -3
  2. package/demo/data/flows/sample-flow.json +186 -96
  3. package/demo/test-colorpicker.html +30 -0
  4. package/dist/temba-components.js +1126 -1111
  5. package/dist/temba-components.js.map +1 -1
  6. package/out-tsc/src/events.js.map +1 -1
  7. package/out-tsc/src/excellent/helpers.js +2 -2
  8. package/out-tsc/src/excellent/helpers.js.map +1 -1
  9. package/out-tsc/src/flow/CanvasNode.js +25 -7
  10. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  11. package/out-tsc/src/flow/Editor.js +11 -1
  12. package/out-tsc/src/flow/Editor.js.map +1 -1
  13. package/out-tsc/src/flow/NodeEditor.js +133 -290
  14. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  15. package/out-tsc/src/flow/actions/add_input_labels.js +40 -0
  16. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  17. package/out-tsc/src/flow/actions/call_llm.js +56 -3
  18. package/out-tsc/src/flow/actions/call_llm.js.map +1 -1
  19. package/out-tsc/src/flow/actions/call_webhook.js +1 -1
  20. package/out-tsc/src/flow/actions/call_webhook.js.map +1 -1
  21. package/out-tsc/src/flow/actions/open_ticket.js +65 -3
  22. package/out-tsc/src/flow/actions/open_ticket.js.map +1 -1
  23. package/out-tsc/src/flow/actions/set_run_result.js +75 -0
  24. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  25. package/out-tsc/src/flow/config.js +4 -0
  26. package/out-tsc/src/flow/config.js.map +1 -1
  27. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +227 -0
  28. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -0
  29. package/out-tsc/src/flow/nodes/split_by_ticket.js +18 -0
  30. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -0
  31. package/out-tsc/src/flow/nodes/wait_for_response.js +27 -1
  32. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  33. package/out-tsc/src/flow/types.js +0 -65
  34. package/out-tsc/src/flow/types.js.map +1 -1
  35. package/out-tsc/src/form/ArrayEditor.js +63 -117
  36. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  37. package/out-tsc/src/form/BaseListEditor.js +4 -3
  38. package/out-tsc/src/form/BaseListEditor.js.map +1 -1
  39. package/out-tsc/src/form/Checkbox.js +77 -24
  40. package/out-tsc/src/form/Checkbox.js.map +1 -1
  41. package/out-tsc/src/form/ColorPicker.js +28 -40
  42. package/out-tsc/src/form/ColorPicker.js.map +1 -1
  43. package/out-tsc/src/form/Completion.js +44 -53
  44. package/out-tsc/src/form/Completion.js.map +1 -1
  45. package/out-tsc/src/form/Compose.js +7 -8
  46. package/out-tsc/src/form/Compose.js.map +1 -1
  47. package/out-tsc/src/form/ContactSearch.js +3 -4
  48. package/out-tsc/src/form/ContactSearch.js.map +1 -1
  49. package/out-tsc/src/form/DatePicker.js +29 -36
  50. package/out-tsc/src/form/DatePicker.js.map +1 -1
  51. package/out-tsc/src/form/{FormField.js → FieldElement.js} +81 -53
  52. package/out-tsc/src/form/FieldElement.js.map +1 -0
  53. package/out-tsc/src/form/FieldRenderer.js +306 -0
  54. package/out-tsc/src/form/FieldRenderer.js.map +1 -0
  55. package/out-tsc/src/form/ImagePicker.js +122 -126
  56. package/out-tsc/src/form/ImagePicker.js.map +1 -1
  57. package/out-tsc/src/form/KeyValueEditor.js +41 -37
  58. package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
  59. package/out-tsc/src/form/MessageEditor.js +55 -63
  60. package/out-tsc/src/form/MessageEditor.js.map +1 -1
  61. package/out-tsc/src/form/TembaSlider.js +3 -3
  62. package/out-tsc/src/form/TembaSlider.js.map +1 -1
  63. package/out-tsc/src/form/TemplateEditor.js +3 -3
  64. package/out-tsc/src/form/TemplateEditor.js.map +1 -1
  65. package/out-tsc/src/form/TextInput.js +23 -27
  66. package/out-tsc/src/form/TextInput.js.map +1 -1
  67. package/out-tsc/src/form/select/Select.js +57 -35
  68. package/out-tsc/src/form/select/Select.js.map +1 -1
  69. package/out-tsc/src/form/select/UserSelect.js +8 -9
  70. package/out-tsc/src/form/select/UserSelect.js.map +1 -1
  71. package/out-tsc/src/form/select/WorkspaceSelect.js +7 -8
  72. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -1
  73. package/out-tsc/src/live/ContactChat.js +62 -44
  74. package/out-tsc/src/live/ContactChat.js.map +1 -1
  75. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -1
  76. package/out-tsc/src/markdown.js +13 -11
  77. package/out-tsc/src/markdown.js.map +1 -1
  78. package/out-tsc/temba-modules.js +3 -2
  79. package/out-tsc/temba-modules.js.map +1 -1
  80. package/out-tsc/test/ActionHelper.js +2 -0
  81. package/out-tsc/test/ActionHelper.js.map +1 -1
  82. package/out-tsc/test/NodeHelper.js +148 -0
  83. package/out-tsc/test/NodeHelper.js.map +1 -0
  84. package/out-tsc/test/actions/call_llm.test.js +103 -0
  85. package/out-tsc/test/actions/call_llm.test.js.map +1 -0
  86. package/out-tsc/test/nodes/split_by_llm_categorize.test.js +532 -0
  87. package/out-tsc/test/nodes/split_by_llm_categorize.test.js.map +1 -0
  88. package/out-tsc/test/nodes/split_by_random.test.js +150 -0
  89. package/out-tsc/test/nodes/split_by_random.test.js.map +1 -0
  90. package/out-tsc/test/nodes/wait_for_digits.test.js +150 -0
  91. package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -0
  92. package/out-tsc/test/nodes/wait_for_response.test.js +171 -0
  93. package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -0
  94. package/out-tsc/test/temba-add-input-labels.test.js +70 -0
  95. package/out-tsc/test/temba-add-input-labels.test.js.map +1 -0
  96. package/out-tsc/test/temba-checkbox.test.js +16 -0
  97. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  98. package/out-tsc/test/temba-field-renderer.test.js +296 -0
  99. package/out-tsc/test/temba-field-renderer.test.js.map +1 -0
  100. package/out-tsc/test/temba-integration-markdown.test.js +2 -4
  101. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  102. package/out-tsc/test/temba-markdown.test.js +1 -1
  103. package/out-tsc/test/temba-markdown.test.js.map +1 -1
  104. package/out-tsc/test/temba-node-editor.test.js +400 -0
  105. package/out-tsc/test/temba-node-editor.test.js.map +1 -1
  106. package/out-tsc/test/temba-select.test.js +6 -3
  107. package/out-tsc/test/temba-select.test.js.map +1 -1
  108. package/out-tsc/test/temba-slider.test.js +0 -1
  109. package/out-tsc/test/temba-slider.test.js.map +1 -1
  110. package/out-tsc/test/temba-webchat.test.js +1 -1
  111. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  112. package/package.json +1 -1
  113. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  114. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  115. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  116. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  117. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  118. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  119. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  120. package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
  121. package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
  122. package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
  123. package/screenshots/truth/actions/call_llm/render/translation-task.png +0 -0
  124. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  125. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  126. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  127. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  128. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  129. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  130. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  131. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  132. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  133. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  134. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  135. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  136. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  137. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  138. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  139. package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
  140. package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
  141. package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
  142. package/screenshots/truth/checkbox/checked.png +0 -0
  143. package/screenshots/truth/checkbox/default.png +0 -0
  144. package/screenshots/truth/colorpicker/default.png +0 -0
  145. package/screenshots/truth/colorpicker/focused.png +0 -0
  146. package/screenshots/truth/colorpicker/initialized.png +0 -0
  147. package/screenshots/truth/colorpicker/selected.png +0 -0
  148. package/screenshots/truth/editor/router.png +0 -0
  149. package/screenshots/truth/editor/send_msg.png +0 -0
  150. package/screenshots/truth/editor/set_contact_language.png +0 -0
  151. package/screenshots/truth/editor/set_contact_name.png +0 -0
  152. package/screenshots/truth/editor/set_run_result.png +0 -0
  153. package/screenshots/truth/editor/wait.png +0 -0
  154. package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
  155. package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
  156. package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
  157. package/screenshots/truth/field-renderer/context-comparison.png +0 -0
  158. package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
  159. package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
  160. package/screenshots/truth/field-renderer/select-multi.png +0 -0
  161. package/screenshots/truth/field-renderer/select-no-label.png +0 -0
  162. package/screenshots/truth/field-renderer/select-with-label.png +0 -0
  163. package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
  164. package/screenshots/truth/field-renderer/text-no-label.png +0 -0
  165. package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
  166. package/screenshots/truth/field-renderer/text-with-label.png +0 -0
  167. package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
  168. package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
  169. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  170. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  171. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  172. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  173. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  174. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  175. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  176. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  177. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  178. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  179. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  180. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  181. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  182. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  183. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  184. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  185. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  186. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  187. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  188. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  189. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  190. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  191. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  192. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  193. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  194. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  195. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
  196. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  197. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  198. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  199. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  200. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  201. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  202. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  203. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  204. package/screenshots/truth/omnibox/selected.png +0 -0
  205. package/screenshots/truth/run-list/basic.png +0 -0
  206. package/screenshots/truth/select/functions.png +0 -0
  207. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  208. package/screenshots/truth/select/search-enabled.png +0 -0
  209. package/src/events.ts +12 -6
  210. package/src/excellent/helpers.ts +2 -2
  211. package/src/flow/CanvasNode.ts +22 -1
  212. package/src/flow/Editor.ts +12 -1
  213. package/src/flow/NodeEditor.ts +186 -374
  214. package/src/flow/actions/add_input_labels.ts +45 -0
  215. package/src/flow/actions/call_llm.ts +57 -3
  216. package/src/flow/actions/call_webhook.ts +1 -1
  217. package/src/flow/actions/open_ticket.ts +74 -3
  218. package/src/flow/actions/set_run_result.ts +83 -0
  219. package/src/flow/config.ts +4 -0
  220. package/src/flow/nodes/split_by_llm_categorize.ts +277 -0
  221. package/src/flow/nodes/split_by_ticket.ts +19 -0
  222. package/src/flow/nodes/wait_for_response.ts +28 -1
  223. package/src/flow/types.ts +26 -127
  224. package/src/form/ArrayEditor.ts +79 -139
  225. package/src/form/BaseListEditor.ts +4 -4
  226. package/src/form/Checkbox.ts +81 -24
  227. package/src/form/ColorPicker.ts +31 -43
  228. package/src/form/Completion.ts +49 -56
  229. package/src/form/Compose.ts +8 -8
  230. package/src/form/ContactSearch.ts +3 -4
  231. package/src/form/DatePicker.ts +32 -38
  232. package/src/form/{FormField.ts → FieldElement.ts} +108 -55
  233. package/src/form/FieldRenderer.ts +466 -0
  234. package/src/form/ImagePicker.ts +107 -110
  235. package/src/form/KeyValueEditor.ts +43 -39
  236. package/src/form/MessageEditor.ts +61 -67
  237. package/src/form/TembaSlider.ts +3 -3
  238. package/src/form/TemplateEditor.ts +3 -3
  239. package/src/form/TextInput.ts +26 -29
  240. package/src/form/select/Select.ts +63 -37
  241. package/src/form/select/UserSelect.ts +10 -11
  242. package/src/form/select/WorkspaceSelect.ts +9 -10
  243. package/src/live/ContactChat.ts +62 -47
  244. package/src/live/ContactFieldEditor.ts +2 -2
  245. package/src/markdown.ts +19 -11
  246. package/src/store/flow-definition.d.ts +5 -2
  247. package/static/api/labels.json +31 -0
  248. package/static/api/topics.json +24 -9
  249. package/static/api/users.json +35 -16
  250. package/static/css/temba-components.css +3 -3
  251. package/stress-test.js +18 -13
  252. package/temba-modules.ts +3 -2
  253. package/test/ActionHelper.ts +2 -0
  254. package/test/NodeHelper.ts +184 -0
  255. package/test/actions/call_llm.test.ts +137 -0
  256. package/test/nodes/README.md +78 -0
  257. package/test/nodes/split_by_llm_categorize.test.ts +698 -0
  258. package/test/nodes/split_by_random.test.ts +177 -0
  259. package/test/nodes/wait_for_digits.test.ts +176 -0
  260. package/test/nodes/wait_for_response.test.ts +206 -0
  261. package/test/temba-add-input-labels.test.ts +87 -0
  262. package/test/temba-checkbox.test.ts +26 -0
  263. package/test/temba-field-renderer.test.ts +482 -0
  264. package/test/temba-integration-markdown.test.ts +2 -4
  265. package/test/temba-markdown.test.ts +1 -1
  266. package/test/temba-node-editor.test.ts +496 -0
  267. package/test/temba-select.test.ts +6 -6
  268. package/test/temba-slider.test.ts +0 -1
  269. package/test/temba-webchat.test.ts +1 -1
  270. package/test-assets/contacts/history.json +7 -20
  271. package/test-assets/select/llms.json +18 -0
  272. package/web-dev-mock.mjs +96 -6
  273. package/web-dev-server.config.mjs +29 -7
  274. package/out-tsc/src/form/FormElement.js +0 -67
  275. package/out-tsc/src/form/FormElement.js.map +0 -1
  276. package/out-tsc/src/form/FormField.js.map +0 -1
  277. package/out-tsc/test/temba-formfield.test.js +0 -94
  278. package/out-tsc/test/temba-formfield.test.js.map +0 -1
  279. package/src/form/FormElement.ts +0 -69
  280. package/test/temba-flow-editor.test.ts.backup +0 -563
  281. package/test/temba-formfield.test.ts +0 -121
  282. package/test/temba-utils-index.test.ts.backup +0 -1737
@@ -3,120 +3,123 @@ import { html, css, PropertyValueMap } from 'lit';
3
3
  import { CroppieCSS } from './CroppieCSS';
4
4
  import { property } from 'lit/decorators.js';
5
5
  import { Icon } from '../Icons';
6
- import { FormElement } from './FormElement';
7
-
8
- export class ImagePicker extends FormElement {
9
- static styles = css`
10
- ${CroppieCSS}
11
-
12
- .croppie {
13
- max-width: 400px;
14
- border: 0px solid #ccc;
15
- border-radius: 0.5em;
16
- overflow: hidden;
17
- background: #fff;
18
- margin-top: -20%;
19
- box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);
20
- }
6
+ import { FieldElement } from './FieldElement';
7
+
8
+ export class ImagePicker extends FieldElement {
9
+ static get styles() {
10
+ return css`
11
+ ${super.styles}
12
+ ${CroppieCSS}
13
+
14
+ .croppie {
15
+ max-width: 400px;
16
+ border: 0px solid #ccc;
17
+ border-radius: 0.5em;
18
+ overflow: hidden;
19
+ background: #fff;
20
+ margin-top: -20%;
21
+ box-shadow: 0 0 15px 5px rgba(0, 0, 0, 0.1);
22
+ }
21
23
 
22
- .croppie .controls {
23
- display: flex;
24
- align-items: center;
25
- flex-direction: row;
26
- justify-content: center;
27
- position: absolute;
28
- z-index: 1;
29
- width: 400px;
30
- margin-top: -42px;
31
- }
24
+ .croppie .controls {
25
+ display: flex;
26
+ align-items: center;
27
+ flex-direction: row;
28
+ justify-content: center;
29
+ position: absolute;
30
+ z-index: 1;
31
+ width: 400px;
32
+ margin-top: -42px;
33
+ }
32
34
 
33
- .toggle {
34
- height: 110px;
35
- width: 110px;
36
- cursor: pointer;
37
- display: flex;
38
- align-items: center;
39
- justify-content: center;
40
- }
35
+ .toggle {
36
+ height: 110px;
37
+ width: 110px;
38
+ cursor: pointer;
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+ }
41
43
 
42
- .circle .toggle {
43
- border-radius: 50%;
44
- }
44
+ .circle .toggle {
45
+ border-radius: 50%;
46
+ }
45
47
 
46
- .toggle.set {
47
- box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
48
- rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);
49
- }
48
+ .toggle.set {
49
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
50
+ rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.1);
51
+ }
50
52
 
51
- .toggle.set:hover {
52
- box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
53
- rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);
54
- }
53
+ .toggle.set:hover {
54
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,
55
+ rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, inset 0 0 0 5px rgba(0, 0, 0, 0.2);
56
+ }
55
57
 
56
- .toggle temba-icon {
57
- color: rgba(0, 0, 0, 0.2);
58
- padding: 5px;
59
- }
58
+ .toggle temba-icon {
59
+ color: rgba(0, 0, 0, 0.2);
60
+ padding: 5px;
61
+ }
60
62
 
61
- toggle:hover temba-icon {
62
- color: rgba(0, 0, 0, 0.8);
63
- }
63
+ toggle:hover temba-icon {
64
+ color: rgba(0, 0, 0, 0.8);
65
+ }
64
66
 
65
- .toggle.set temba-icon {
66
- border-radius: 50%;
67
- margin-right: -90%;
68
- margin-bottom: -50%;
69
- background: rgba(240, 240, 240, 1);
70
- box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;
71
- }
67
+ .toggle.set temba-icon {
68
+ border-radius: 50%;
69
+ margin-right: -90%;
70
+ margin-bottom: -50%;
71
+ background: rgba(240, 240, 240, 1);
72
+ box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;
73
+ }
72
74
 
73
- .toggle.set:hover temba-icon {
74
- background: #fff;
75
- color: var(--color-primary-dark);
76
- }
75
+ .toggle.set:hover temba-icon {
76
+ background: #fff;
77
+ color: var(--color-primary-dark);
78
+ }
77
79
 
78
- .circle .toggle.set temba-icon {
79
- margin-right: -70%;
80
- margin-bottom: -70%;
81
- }
80
+ .circle .toggle.set temba-icon {
81
+ margin-right: -70%;
82
+ margin-bottom: -70%;
83
+ }
82
84
 
83
- .hidden {
84
- display: none;
85
- }
85
+ .hidden {
86
+ display: none;
87
+ }
86
88
 
87
- .controls temba-icon {
88
- margin: 0em 0.75em;
89
- background: rgba(255, 255, 255, 0.8);
90
- border-radius: 50%;
91
- padding: 6px;
92
- transition: all 0.1s ease-in-out;
93
- }
89
+ .controls temba-icon {
90
+ margin: 0em 0.75em;
91
+ background: rgba(255, 255, 255, 0.8);
92
+ border-radius: 50%;
93
+ padding: 6px;
94
+ transition: all 0.1s ease-in-out;
95
+ }
94
96
 
95
- .controls {
96
- pointer-events: none;
97
- display: flex;
98
- }
97
+ .controls {
98
+ pointer-events: none;
99
+ display: flex;
100
+ }
99
101
 
100
- .controls temba-icon {
101
- pointer-events: all;
102
- }
102
+ .controls temba-icon {
103
+ pointer-events: all;
104
+ }
103
105
 
104
- .controls temba-icon.close {
105
- color: rgba(0, 0, 0, 0.2);
106
- background: rgba(255, 255, 255, 0.2);
107
- }
106
+ .controls temba-icon.close {
107
+ color: rgba(0, 0, 0, 0.2);
108
+ background: rgba(255, 255, 255, 0.2);
109
+ }
108
110
 
109
- .controls temba-icon.submit {
110
- color: rgba(0, 0, 0, 0.2);
111
- box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
112
- }
111
+ .controls temba-icon.submit {
112
+ color: rgba(0, 0, 0, 0.2);
113
+ box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.1);
114
+ }
113
115
 
114
- .controls temba-icon:hover {
115
- color: white;
116
- cursor: pointer;
117
- background: var(--color-primary-dark);
118
- }
119
- `;
116
+ .controls temba-icon:hover {
117
+ color: white;
118
+ cursor: pointer;
119
+ background: var(--color-primary-dark);
120
+ }
121
+ `;
122
+ }
120
123
 
121
124
  @property({ type: String })
122
125
  tempImage: string;
@@ -221,18 +224,9 @@ export class ImagePicker extends FormElement {
221
224
  input.value = '';
222
225
  }
223
226
 
224
- protected render() {
227
+ protected renderWidget() {
225
228
  return html`
226
- <div class="wrapper ${this.shape} ${this.label ? 'label' : ''}">
227
- <temba-field
228
- name=${this.name}
229
- label=${this.label}
230
- .helpText=${this.helpText}
231
- .errors=${this.errors}
232
- .widgetOnly=${this.widgetOnly}
233
- .helpAlways=${true}
234
- ?disabled=${this.disabled}
235
- >
229
+ <div class="wrapper ${this.shape} ${this.label ? 'label' : ''}">
236
230
  <input class='hidden' type="file" accept="image/*" capture="camera" id="file" name="file" @change=${
237
231
  this.handleFileChanged
238
232
  }/>
@@ -261,8 +255,11 @@ export class ImagePicker extends FormElement {
261
255
  }></temba-icon>
262
256
  </div>
263
257
  </temba-mask>
264
- </temba-field>
265
- </div>
258
+ </div>
266
259
  `;
267
260
  }
261
+
262
+ public render() {
263
+ return this.renderField();
264
+ }
268
265
  }
@@ -31,13 +31,13 @@ export class KeyValueEditor extends BaseListEditor<KeyValueItem> {
31
31
 
32
32
  // External API uses array format to preserve duplicate keys
33
33
  @property({ type: Array })
34
- get value(): KeyValueItem[] {
34
+ get value(): KeyValueItem[] | any[] {
35
35
  return this._items.filter(
36
36
  ({ key, value }) => key.trim() !== '' || value.trim() !== ''
37
37
  );
38
38
  }
39
39
 
40
- set value(newValue: KeyValueItem[] | Record<string, string>) {
40
+ set value(newValue: KeyValueItem[] | Record<string, string> | any) {
41
41
  if (Array.isArray(newValue)) {
42
42
  this._items = [...newValue];
43
43
  } else {
@@ -206,46 +206,50 @@ export class KeyValueEditor extends BaseListEditor<KeyValueItem> {
206
206
  return 'key-value-editor';
207
207
  }
208
208
 
209
- static styles = css`
210
- .key-value-editor {
211
- display: flex;
212
- flex-direction: column;
213
- gap: 8px;
214
- }
209
+ static get styles() {
210
+ return css`
211
+ ${super.styles}
215
212
 
216
- .row {
217
- display: grid;
218
- grid-template-columns: 1fr 1fr auto;
219
- align-items: center;
220
- column-gap: 6px;
221
- }
213
+ .key-value-editor {
214
+ display: flex;
215
+ flex-direction: column;
216
+ gap: 8px;
217
+ }
222
218
 
223
- .remove-btn {
224
- width: 32px;
225
- height: 32px;
226
- border: 1px solid #ccc;
227
- border-radius: 4px;
228
- background: #f8f8f8;
229
- color: #666;
230
- cursor: pointer;
231
- display: flex;
232
- align-items: center;
233
- justify-content: center;
234
- font-size: 18px;
235
- }
219
+ .row {
220
+ display: grid;
221
+ grid-template-columns: 1fr 1fr auto;
222
+ align-items: center;
223
+ column-gap: 6px;
224
+ }
236
225
 
237
- .remove-btn:hover:not(:disabled) {
238
- background: #f0f0f0;
239
- }
226
+ .remove-btn {
227
+ width: 32px;
228
+ height: 32px;
229
+ border: 1px solid #ccc;
230
+ border-radius: 4px;
231
+ background: #f8f8f8;
232
+ color: #666;
233
+ cursor: pointer;
234
+ display: flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ font-size: 18px;
238
+ }
240
239
 
241
- .remove-btn:disabled {
242
- opacity: 0.5;
243
- cursor: not-allowed;
244
- }
240
+ .remove-btn:hover:not(:disabled) {
241
+ background: #f0f0f0;
242
+ }
245
243
 
246
- .remove-btn-spacer {
247
- width: 32px;
248
- height: 32px;
249
- }
250
- `;
244
+ .remove-btn:disabled {
245
+ opacity: 0.5;
246
+ cursor: not-allowed;
247
+ }
248
+
249
+ .remove-btn-spacer {
250
+ width: 32px;
251
+ height: 32px;
252
+ }
253
+ `;
254
+ }
251
255
  }
@@ -1,7 +1,7 @@
1
1
  import { TemplateResult, css, html } from 'lit';
2
2
  import { property } from 'lit/decorators.js';
3
3
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
- import { FormElement } from './FormElement';
4
+ import { FieldElement } from './FieldElement';
5
5
  import { Completion } from './Completion';
6
6
  import { MediaPicker } from './MediaPicker';
7
7
  import { Attachment } from '../interfaces';
@@ -12,9 +12,10 @@ import { Icon } from '../Icons';
12
12
  * MessageEditor is a composed component that combines temba-completion and temba-media-picker
13
13
  * for editing messages with text completion and file attachments
14
14
  */
15
- export class MessageEditor extends FormElement {
15
+ export class MessageEditor extends FieldElement {
16
16
  static get styles() {
17
17
  return css`
18
+ ${super.styles}
18
19
  :host {
19
20
  display: block;
20
21
  }
@@ -130,9 +131,6 @@ export class MessageEditor extends FormElement {
130
131
  @property({ type: String })
131
132
  name = '';
132
133
 
133
- @property({ type: String })
134
- value = '';
135
-
136
134
  @property({ type: String })
137
135
  placeholder = '';
138
136
 
@@ -373,77 +371,73 @@ export class MessageEditor extends FormElement {
373
371
  }
374
372
 
375
373
  public render(): TemplateResult {
374
+ return this.renderField();
375
+ }
376
+
377
+ protected renderWidget(): TemplateResult {
376
378
  const hasAttachments = this.hasStaticAttachments();
377
379
 
378
380
  return html`
379
- <temba-field
380
- name=${this.name}
381
- .label=${this.label}
382
- .helpText=${this.helpText}
383
- .errors=${this.errors}
384
- .widgetOnly=${this.widgetOnly}
381
+ <div
382
+ class=${getClasses({
383
+ 'message-editor-container': true,
384
+ highlight: this.pendingDrop,
385
+ 'has-attachments': hasAttachments
386
+ })}
387
+ @dragenter=${this.handleDragEnter}
388
+ @dragover=${this.handleDragOver}
389
+ @dragleave=${this.handleDragLeave}
390
+ @drop=${this.handleDrop}
385
391
  >
386
- <div
387
- class=${getClasses({
388
- 'message-editor-container': true,
389
- highlight: this.pendingDrop,
390
- 'has-attachments': hasAttachments
391
- })}
392
- @dragenter=${this.handleDragEnter}
393
- @dragover=${this.handleDragOver}
394
- @dragleave=${this.handleDragLeave}
395
- @drop=${this.handleDrop}
396
- >
397
- <div class="completion-wrapper">
398
- <temba-completion
399
- name=${this.name}
400
- .value=${this.value}
401
- placeholder=${this.placeholder}
402
- ?textarea=${this.textarea}
403
- ?autogrow=${this.autogrow}
404
- ?session=${this.session}
405
- ?submitOnEnter=${this.submitOnEnter}
406
- ?gsm=${this.gsm}
407
- ?disableCompletion=${this.disableCompletion}
408
- maxlength=${ifDefined(this.maxLength)}
409
- counter=${ifDefined(this.counter)}
410
- minHeight=${ifDefined(this.minHeight)}
411
- widgetOnly
412
- @change=${this.handleCompletionChange}
413
- ></temba-completion>
414
- </div>
415
-
416
- <div class="media-wrapper ">
417
- <temba-media-picker
392
+ <div class="completion-wrapper">
393
+ <temba-completion
394
+ name=${this.name}
395
+ .value=${this.value}
396
+ placeholder=${this.placeholder}
397
+ ?textarea=${this.textarea}
398
+ ?autogrow=${this.autogrow}
399
+ ?session=${this.session}
400
+ ?submitOnEnter=${this.submitOnEnter}
401
+ ?gsm=${this.gsm}
402
+ ?disableCompletion=${this.disableCompletion}
403
+ maxlength=${ifDefined(this.maxLength)}
404
+ counter=${ifDefined(this.counter)}
405
+ minHeight=${ifDefined(this.minHeight)}
406
+ widgetOnly
407
+ @change=${this.handleCompletionChange}
408
+ ></temba-completion>
409
+ </div>
410
+
411
+ <div class="media-wrapper ">
412
+ <temba-media-picker
413
+ .accept=${this.accept}
414
+ .max=${this.maxAttachments}
415
+ .endpoint=${this.endpoint}
416
+ @change=${this.handleMediaChange}
417
+ ignoreDrops
418
+ ></temba-media-picker>
419
+ </div>
420
+ <temba-icon
421
+ class="attachment-icon"
422
+ name=${Icon.attachment}
423
+ size="1.2"
424
+ @click=${this.handleAttachmentIconClick}
425
+ ></temba-icon>
426
+
427
+ <div class="drop-overlay"></div>
428
+
429
+ <!-- Hidden media picker for handling uploads when no attachments are shown -->
430
+ ${!hasAttachments
431
+ ? html`<temba-media-picker
432
+ style="display: none;"
418
433
  .accept=${this.accept}
419
434
  .max=${this.maxAttachments}
420
435
  .endpoint=${this.endpoint}
421
436
  @change=${this.handleMediaChange}
422
437
  ignoreDrops
423
- ></temba-media-picker>
424
- </div>
425
- <temba-icon
426
- class="attachment-icon"
427
- name=${Icon.attachment}
428
- size="1.2"
429
- @click=${this.handleAttachmentIconClick}
430
- ></temba-icon>
431
-
432
- <div class="drop-overlay"></div>
433
-
434
- <!-- Hidden media picker for handling uploads when no attachments are shown -->
435
- ${!hasAttachments
436
- ? html`<temba-media-picker
437
- style="display: none;"
438
- .accept=${this.accept}
439
- .max=${this.maxAttachments}
440
- .endpoint=${this.endpoint}
441
- @change=${this.handleMediaChange}
442
- ignoreDrops
443
- ></temba-media-picker>`
444
- : ''}
445
- </div>
446
- </temba-field>
438
+ ></temba-media-picker>`
439
+ : ''}
440
+ </div>
447
441
  `;
448
442
  }
449
443
  }
@@ -1,10 +1,10 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
2
  import { styleMap } from 'lit-html/directives/style-map.js';
3
3
  import { property } from 'lit/decorators.js';
4
- import { FormElement } from './FormElement';
4
+ import { FieldElement } from './FieldElement';
5
5
  import { getClasses } from '../utils';
6
6
 
7
- export class TembaSlider extends FormElement {
7
+ export class TembaSlider extends FieldElement {
8
8
  static get styles() {
9
9
  return css`
10
10
  :host {
@@ -142,7 +142,7 @@ export class TembaSlider extends FormElement {
142
142
  this.requestUpdate();
143
143
  }
144
144
 
145
- public render(): TemplateResult {
145
+ public renderWidget(): TemplateResult {
146
146
  return html` <div class="${getClasses({ grabbed: this.grabbed })}">
147
147
  <div
148
148
  style=${styleMap({ left: this.circleX + 'px' })}
@@ -1,9 +1,9 @@
1
1
  import { property } from 'lit/decorators.js';
2
- import { FormElement } from './FormElement';
3
2
  import { TemplateResult, html, css, LitElement } from 'lit';
4
3
  import { CustomEventType } from '../interfaces';
5
4
  import { MediaPicker } from './MediaPicker';
6
5
  import { getClasses } from '../utils';
6
+ import { FieldElement } from './FieldElement';
7
7
 
8
8
  interface Component {
9
9
  name: string;
@@ -28,7 +28,7 @@ interface Template {
28
28
  base_translation: Translation;
29
29
  }
30
30
 
31
- export class TemplateEditor extends FormElement {
31
+ export class TemplateEditor extends FieldElement {
32
32
  static shadowRootOptions = {
33
33
  ...LitElement.shadowRootOptions,
34
34
  delegatesFocus: true
@@ -457,7 +457,7 @@ export class TemplateEditor extends FormElement {
457
457
  </div>`;
458
458
  }
459
459
 
460
- public render(): TemplateResult {
460
+ public renderWidget(): TemplateResult {
461
461
  let content = null;
462
462
  if (this.translation) {
463
463
  content = this.renderComponents(this.translation.components);
@@ -2,7 +2,7 @@ import { TemplateResult, html, css } from 'lit';
2
2
  import { property } from 'lit/decorators.js';
3
3
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
4
  import { styleMap } from 'lit-html/directives/style-map.js';
5
- import { FormElement } from './FormElement';
5
+ import { FieldElement } from './FieldElement';
6
6
  import { Modax } from '../layout/Modax';
7
7
  import { sanitizeUnintendedUnicode } from '../utils';
8
8
  import { CharCount } from '../display/CharCount';
@@ -13,9 +13,10 @@ export enum InputType {
13
13
  Number = 'number'
14
14
  }
15
15
 
16
- export class TextInput extends FormElement {
16
+ export class TextInput extends FieldElement {
17
17
  static get styles() {
18
18
  return css`
19
+ ${super.styles}
19
20
  .input-container {
20
21
  border-radius: var(--curvature-widget);
21
22
  cursor: var(--input-cursor);
@@ -193,7 +194,7 @@ export class TextInput extends FormElement {
193
194
 
194
195
  this.inputElement = this.shadowRoot.querySelector('.textinput');
195
196
 
196
- if (changes.has('counter')) {
197
+ if (changes.has('counter') && this.counter && this.counter.trim()) {
197
198
  let root = this.getParentModax() as any;
198
199
  if (root) {
199
200
  root = root.shadowRoot;
@@ -368,9 +369,15 @@ export class TextInput extends FormElement {
368
369
 
369
370
  // TODO make this a formelement and have contactsearch set the root
370
371
  public render(): TemplateResult {
371
- const containerStyle = {
372
- height: `${this.textarea ? '100%' : 'auto'}`
373
- };
372
+ return this.renderField();
373
+ }
374
+
375
+ protected renderWidget() {
376
+ const containerStyle: any = {};
377
+ if (this.counter) {
378
+ containerStyle['--counter-background'] =
379
+ 'var(--color-widget-border, transparent)';
380
+ }
374
381
 
375
382
  const clear =
376
383
  this.clearable && this.inputElement && this.inputElement.value
@@ -474,31 +481,21 @@ export class TextInput extends FormElement {
474
481
  }
475
482
 
476
483
  return html`
477
- <temba-field
478
- name=${this.name}
479
- .label="${this.label}"
480
- .helpText="${this.helpText}"
481
- .errors=${this.errors}
482
- .widgetOnly=${this.widgetOnly}
483
- .hideLabel=${this.hideLabel}
484
- .disabled=${this.disabled}
484
+ <div
485
+ class="input-container"
486
+ style=${styleMap(containerStyle)}
487
+ @click=${this.handleContainerClick}
485
488
  >
486
- <div
487
- class="input-container"
488
- style=${styleMap(containerStyle)}
489
- @click=${this.handleContainerClick}
489
+ <slot name="prefix"></slot>
490
+
491
+ ${input} ${clear}
492
+ <slot name="type" class="type-icon"
493
+ >${this.type === InputType.Number
494
+ ? html`<temba-icon name="number"></temba-icon>`
495
+ : null}</slot
490
496
  >
491
- <slot name="prefix"></slot>
492
-
493
- ${input} ${clear}
494
- <slot name="type" class="type-icon"
495
- >${this.type === InputType.Number
496
- ? html`<temba-icon name="number"></temba-icon>`
497
- : null}</slot
498
- >
499
- <slot></slot>
500
- </div>
501
- </temba-field>
497
+ <slot></slot>
498
+ </div>
502
499
  `;
503
500
  }
504
501
  }