@nyaruka/temba-components 0.62.2 → 0.63.0

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 (105) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/demo/index.html +0 -11
  3. package/dist/{ba373419.js → b745b4f0.js} +423 -256
  4. package/dist/index.js +423 -256
  5. package/dist/static/svg/index.svg +1 -1
  6. package/dist/sw.js +1 -1
  7. package/dist/sw.js.map +1 -1
  8. package/dist/templates/components-body.html +1 -1
  9. package/dist/templates/components-head.html +1 -1
  10. package/out-tsc/src/RapidElement.js +6 -0
  11. package/out-tsc/src/RapidElement.js.map +1 -1
  12. package/out-tsc/src/compose/Compose.js +190 -89
  13. package/out-tsc/src/compose/Compose.js.map +1 -1
  14. package/out-tsc/src/contacts/ContactChat.js +4 -5
  15. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  16. package/out-tsc/src/interfaces.js.map +1 -1
  17. package/out-tsc/src/lightbox/Lightbox.js +1 -0
  18. package/out-tsc/src/lightbox/Lightbox.js.map +1 -1
  19. package/out-tsc/src/select/Select.js +1 -1
  20. package/out-tsc/src/select/Select.js.map +1 -1
  21. package/out-tsc/src/tabpane/Tab.js.map +1 -1
  22. package/out-tsc/src/tabpane/TabPane.js +155 -25
  23. package/out-tsc/src/tabpane/TabPane.js.map +1 -1
  24. package/out-tsc/src/textinput/TextInput.js +1 -0
  25. package/out-tsc/src/textinput/TextInput.js.map +1 -1
  26. package/out-tsc/src/thumbnail/Thumbnail.js +121 -0
  27. package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -0
  28. package/out-tsc/src/utils/index.js +6 -0
  29. package/out-tsc/src/utils/index.js.map +1 -1
  30. package/out-tsc/src/vectoricon/index.js +2 -1
  31. package/out-tsc/src/vectoricon/index.js.map +1 -1
  32. package/out-tsc/temba-modules.js +2 -0
  33. package/out-tsc/temba-modules.js.map +1 -1
  34. package/out-tsc/test/temba-compose.test.js +2 -1
  35. package/out-tsc/test/temba-compose.test.js.map +1 -1
  36. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  37. package/package.json +1 -1
  38. package/screenshots/truth/compose/attachments-and-send-button.png +0 -0
  39. package/screenshots/truth/compose/attachments-no-send-button.png +0 -0
  40. package/screenshots/truth/compose/attachments-with-all-files-and-click-send.png +0 -0
  41. package/screenshots/truth/compose/attachments-with-all-files.png +0 -0
  42. package/screenshots/truth/compose/attachments-with-failure-files.png +0 -0
  43. package/screenshots/truth/compose/attachments-with-success-files-and-click-send.png +0 -0
  44. package/screenshots/truth/compose/attachments-with-success-files.png +0 -0
  45. package/screenshots/truth/compose/chatbox-attachments-counter-and-send-button.png +0 -0
  46. package/screenshots/truth/compose/chatbox-attachments-counter-no-send-button.png +0 -0
  47. package/screenshots/truth/compose/chatbox-attachments-no-counter-and-send-button.png +0 -0
  48. package/screenshots/truth/compose/chatbox-attachments-no-counter-no-send-button.png +0 -0
  49. package/screenshots/truth/compose/chatbox-counter-and-send-button.png +0 -0
  50. package/screenshots/truth/compose/chatbox-counter-no-send-button.png +0 -0
  51. package/screenshots/truth/compose/chatbox-no-counter-and-send-button.png +0 -0
  52. package/screenshots/truth/compose/chatbox-no-counter-no-send-button.png +0 -0
  53. package/screenshots/truth/compose/chatbox-no-text-attachments-with-all-files-and-click-send.png +0 -0
  54. package/screenshots/truth/compose/chatbox-no-text-attachments-with-all-files.png +0 -0
  55. package/screenshots/truth/compose/chatbox-no-text-attachments-with-failure-files.png +0 -0
  56. package/screenshots/truth/compose/chatbox-no-text-attachments-with-success-files-and-click-send.png +0 -0
  57. package/screenshots/truth/compose/chatbox-no-text-attachments-with-success-files.png +0 -0
  58. package/screenshots/truth/compose/chatbox-with-text-and-click-send.png +0 -0
  59. package/screenshots/truth/compose/chatbox-with-text-and-hit-enter.png +0 -0
  60. package/screenshots/truth/compose/chatbox-with-text-and-spaces.png +0 -0
  61. package/screenshots/truth/compose/chatbox-with-text-and-url.png +0 -0
  62. package/screenshots/truth/compose/chatbox-with-text-attachments-no-files-and-click-send.png +0 -0
  63. package/screenshots/truth/compose/chatbox-with-text-attachments-no-files-and-hit-enter.png +0 -0
  64. package/screenshots/truth/compose/chatbox-with-text-attachments-no-files.png +0 -0
  65. package/screenshots/truth/compose/chatbox-with-text-attachments-with-all-files-and-click-send.png +0 -0
  66. package/screenshots/truth/compose/chatbox-with-text-attachments-with-all-files-and-hit-enter.png +0 -0
  67. package/screenshots/truth/compose/chatbox-with-text-attachments-with-all-files.png +0 -0
  68. package/screenshots/truth/compose/chatbox-with-text-attachments-with-failure-files.png +0 -0
  69. package/screenshots/truth/compose/chatbox-with-text-attachments-with-success-files-and-click-send.png +0 -0
  70. package/screenshots/truth/compose/chatbox-with-text-attachments-with-success-files-and-hit-enter.png +0 -0
  71. package/screenshots/truth/compose/chatbox-with-text-attachments-with-success-files.png +0 -0
  72. package/screenshots/truth/compose/chatbox-with-text-no-spaces.png +0 -0
  73. package/screenshots/truth/compose/chatbox-with-text.png +0 -0
  74. package/screenshots/truth/contacts/compose-attachments-no-text-failure.png +0 -0
  75. package/screenshots/truth/contacts/compose-attachments-no-text-success.png +0 -0
  76. package/screenshots/truth/contacts/compose-text-and-attachments-failure-attachments.png +0 -0
  77. package/screenshots/truth/contacts/compose-text-and-attachments-failure-generic.png +0 -0
  78. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text-and-attachments.png +0 -0
  79. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text.png +0 -0
  80. package/screenshots/truth/contacts/compose-text-and-attachments-success.png +0 -0
  81. package/screenshots/truth/contacts/compose-text-no-attachments-failure.png +0 -0
  82. package/screenshots/truth/contacts/compose-text-no-attachments-success.png +0 -0
  83. package/screenshots/truth/contacts/contact-active-default.png +0 -0
  84. package/screenshots/truth/contacts/contact-active-show-chatbox.png +0 -0
  85. package/screenshots/truth/contacts/contact-archived-hide-chatbox.png +0 -0
  86. package/screenshots/truth/contacts/contact-blocked-hide-chatbox.png +0 -0
  87. package/screenshots/truth/contacts/contact-stopped-hide-chatbox.png +0 -0
  88. package/src/RapidElement.ts +7 -0
  89. package/src/compose/Compose.ts +200 -106
  90. package/src/contacts/ContactChat.ts +4 -5
  91. package/src/interfaces.ts +9 -0
  92. package/src/lightbox/Lightbox.ts +1 -0
  93. package/src/select/Select.ts +1 -1
  94. package/src/tabpane/Tab.ts +1 -1
  95. package/src/tabpane/TabPane.ts +154 -26
  96. package/src/textinput/TextInput.ts +1 -0
  97. package/src/thumbnail/Thumbnail.ts +119 -0
  98. package/src/utils/index.ts +8 -1
  99. package/src/vectoricon/index.ts +2 -1
  100. package/static/svg/index.svg +1 -1
  101. package/static/svg/work/traced/dotpoints-01.svg +1 -0
  102. package/static/svg/work/used/dotpoints-01.svg +3 -0
  103. package/temba-modules.ts +2 -0
  104. package/test/temba-compose.test.ts +8 -2
  105. package/test/temba-contact-chat.test.ts +2 -2
@@ -2,27 +2,20 @@ import { TemplateResult, html, css } from 'lit';
2
2
  import { FormElement } from '../FormElement';
3
3
  import { property } from 'lit/decorators.js';
4
4
  import { Icon } from '../vectoricon';
5
- import { CustomEventType, Language } from '../interfaces';
5
+ import { Attachment, CustomEventType, Language } from '../interfaces';
6
6
  import {
7
7
  formatFileSize,
8
- formatFileType,
9
8
  getClasses,
10
9
  postFormData,
11
10
  truncate,
12
11
  DEFAULT_MEDIA_ENDPOINT,
13
12
  WebResponse,
13
+ isImageAttachment,
14
14
  } from '../utils';
15
15
  import { Completion } from '../completion/Completion';
16
16
  import { Select } from '../select/Select';
17
-
18
- export interface Attachment {
19
- uuid: string;
20
- content_type: string;
21
- url: string;
22
- filename: string;
23
- size: number;
24
- error: string;
25
- }
17
+ import { TabPane } from '../tabpane/TabPane';
18
+ import { EventHandler } from '../RapidElement';
26
19
 
27
20
  export class Compose extends FormElement {
28
21
  static get styles() {
@@ -39,19 +32,13 @@ export class Compose extends FormElement {
39
32
  transition: all ease-in-out var(--transition-speed);
40
33
  box-shadow: var(--widget-box-shadow);
41
34
  caret-color: var(--input-caret);
42
- padding: var(--temba-textinput-padding);
43
- }
44
- .container:focus-within {
45
- border-color: var(--color-focus);
46
- background: var(--color-widget-bg-focused);
47
- box-shadow: var(--widget-box-shadow-focused);
48
35
  }
49
36
 
50
37
  .drop-mask {
51
38
  opacity: 0;
52
39
  pointer-events: none;
53
40
  position: absolute;
54
- z-index: 1;
41
+ z-index: 2;
55
42
  height: 100%;
56
43
  width: 100%;
57
44
  bottom: 0;
@@ -81,45 +68,47 @@ export class Compose extends FormElement {
81
68
  }
82
69
 
83
70
  .chatbox {
84
- margin-left: 0.3em;
85
- margin-top: 0.3em;
86
71
  --color-widget-border: none;
87
- --curvature-widget: none;
88
- --widget-box-shadow: none;
89
- --widget-box-shadow-focused: none;
90
- --temba-textinput-padding: 0;
72
+ --curvature-widget: var(--curvature) var(--curvature) 0px 0px;
73
+ --textarea-min-height: 4em;
91
74
  }
92
75
 
93
76
  .attachments {
94
- display: flex;
95
- flex-direction: column;
96
77
  }
97
78
  .attachments-list {
98
79
  display: flex;
99
80
  flex-direction: row;
100
81
  flex-wrap: wrap;
82
+ padding: 0.2em;
101
83
  }
102
84
  .attachment-item {
103
- background: rgba(100, 100, 100, 0.1);
104
- border-radius: 2px;
105
- margin: 0.3em;
106
- display: flex;
107
- color: var(--color-widget-text);
85
+ padding: 0.4em;
108
86
  }
109
87
  .attachment-item.error {
110
- background: rgba(250, 0, 0, 0.1);
88
+ background: #fff;
111
89
  color: rgba(250, 0, 0, 0.75);
90
+ padding: 0.2em;
91
+ margin: 0.3em 0.5em;
92
+ border-radius: var(--curvature);
93
+ display: block;
112
94
  }
95
+
113
96
  .remove-item {
114
- cursor: pointer !important;
115
- padding: 3px 6px;
116
- border-right: 1px solid rgba(100, 100, 100, 0.2);
117
- margin-top: 1px;
118
- background: rgba(100, 100, 100, 0.05);
97
+ position: absolute;
98
+ --icon-color: #ccc;
99
+ background: #fff;
100
+ border-radius: 99%;
101
+ transform: scale(0);
102
+ transition: transform 200ms linear;
103
+ }
104
+
105
+ .attachment-item:hover .remove-item {
106
+ transform: scale(1);
119
107
  }
120
108
 
121
109
  .remove-item:hover {
122
- background: rgba(100, 100, 100, 0.1);
110
+ --icon-color: #333;
111
+ cursor: pointer;
123
112
  }
124
113
 
125
114
  .remove-item.error:hover {
@@ -140,8 +129,11 @@ export class Compose extends FormElement {
140
129
  display: flex;
141
130
  justify-content: space-between;
142
131
  align-items: center;
143
- margin-left: 0.25em;
144
- padding: 0.2em;
132
+ padding: 0em;
133
+ background: #f9f9f9;
134
+ border-bottom-left-radius: var(--curvature);
135
+ border-bottom-right-radius: var(--curvature);
136
+ border-top: solid 1px var(--color-widget-border);
145
137
  }
146
138
 
147
139
  #upload-input {
@@ -179,10 +171,48 @@ export class Compose extends FormElement {
179
171
  .language {
180
172
  margin-bottom: 0.6em;
181
173
  display: block;
174
+ z-index: 2;
175
+ }
176
+
177
+ .top-right {
178
+ align-items: center;
179
+ display: flex;
180
+ }
181
+
182
+ #send-button {
183
+ margin: 0.3em;
184
+ }
185
+
186
+ temba-tabs {
187
+ --focused-tab-color: #f4f4f4;
188
+ }
189
+
190
+ .quick-replies {
191
+ margin: 0.8em;
192
+ }
193
+
194
+ .add-attachment {
195
+ padding: 1em;
196
+ background: #eee;
197
+ border-radius: var(--curvature);
198
+ color: #aaa;
199
+ margin: 0.5em;
200
+ }
201
+
202
+ .add-attachment:hover {
203
+ background: #e9e9e9;
204
+ cursor: pointer;
205
+ }
206
+
207
+ temba-loading {
208
+ margin: auto 1em;
182
209
  }
183
210
  `;
184
211
  }
185
212
 
213
+ @property({ type: Number })
214
+ index = 1;
215
+
186
216
  @property({ type: Number })
187
217
  maxAttachments = 3;
188
218
 
@@ -198,6 +228,9 @@ export class Compose extends FormElement {
198
228
  @property({ type: Boolean })
199
229
  attachments: boolean;
200
230
 
231
+ @property({ type: Boolean })
232
+ quickReplies: boolean;
233
+
201
234
  @property({ type: Boolean })
202
235
  counter: boolean;
203
236
 
@@ -228,6 +261,9 @@ export class Compose extends FormElement {
228
261
  @property({ type: Array })
229
262
  currentAttachments: Attachment[] = [];
230
263
 
264
+ @property({ type: Array })
265
+ currentQuickReplies: { name: string; value: string }[] = [];
266
+
231
267
  @property({ type: Array, attribute: false })
232
268
  failedAttachments: Attachment[] = [];
233
269
 
@@ -251,6 +287,7 @@ export class Compose extends FormElement {
251
287
  [lang: string]: {
252
288
  text: string;
253
289
  attachments: Attachment[];
290
+ quick_replies: string[];
254
291
  };
255
292
  } = {};
256
293
 
@@ -261,6 +298,25 @@ export class Compose extends FormElement {
261
298
  super();
262
299
  }
263
300
 
301
+ private handleTabChanged() {
302
+ const tabs = this.shadowRoot.querySelector('temba-tabs') as TabPane;
303
+ const tab = tabs.getCurrentTab();
304
+ if (tab) {
305
+ // check we are going for the first attachment
306
+ if (tab.icon == 'attachment') {
307
+ if (this.currentAttachments.length == 0) {
308
+ this.handleUploadFileIconClicked();
309
+ }
310
+ }
311
+ }
312
+ }
313
+
314
+ public getEventHandlers(): EventHandler[] {
315
+ return [
316
+ { event: CustomEventType.ContextChanged, method: this.handleTabChanged },
317
+ ];
318
+ }
319
+
264
320
  public firstUpdated(changes: Map<string, any>): void {
265
321
  super.firstUpdated(changes);
266
322
 
@@ -281,6 +337,7 @@ export class Compose extends FormElement {
281
337
  let langValue = {
282
338
  text: '',
283
339
  attachments: [],
340
+ quick_replies: [],
284
341
  };
285
342
 
286
343
  if (this.currentLanguage in this.langValues) {
@@ -290,6 +347,9 @@ export class Compose extends FormElement {
290
347
  this.currentText = langValue.text;
291
348
  this.initialText = langValue.text;
292
349
  this.currentAttachments = langValue.attachments;
350
+ this.currentQuickReplies = (langValue.quick_replies || []).map(value => {
351
+ return { name: value, value };
352
+ });
293
353
  this.setFocusOnChatbox();
294
354
 
295
355
  // TODO: this feels like it shouldn't be needed
@@ -297,25 +357,33 @@ export class Compose extends FormElement {
297
357
  if (chatbox) {
298
358
  chatbox.value = this.initialText;
299
359
  }
360
+ this.resetTabs();
361
+ this.requestUpdate('currentAttachments');
300
362
  }
301
363
 
302
364
  if (
303
365
  this.langValues &&
304
- (changes.has('currentText') || changes.has('currentAttachments'))
366
+ (changes.has('currentText') ||
367
+ changes.has('currentAttachments') ||
368
+ changes.has('currentQuickReplies'))
305
369
  ) {
306
370
  this.toggleButton();
307
371
 
308
372
  const trimmed = this.currentText ? this.currentText.trim() : '';
309
- if (trimmed || this.currentAttachments.length > 0) {
373
+ if (
374
+ trimmed ||
375
+ this.currentAttachments.length > 0 ||
376
+ this.currentQuickReplies.length > 0
377
+ ) {
310
378
  this.langValues[this.currentLanguage] = {
311
379
  text: trimmed,
312
380
  attachments: this.currentAttachments,
381
+ quick_replies: this.currentQuickReplies.map(option => option.value),
313
382
  };
314
- this.fireCustomEvent(CustomEventType.ContentChanged, this.langValues);
315
383
  } else {
316
384
  delete this.langValues[this.currentLanguage];
317
385
  }
318
-
386
+ this.fireCustomEvent(CustomEventType.ContentChanged, this.langValues);
319
387
  this.requestUpdate('langValues');
320
388
  this.setValue(this.langValues);
321
389
  }
@@ -329,6 +397,7 @@ export class Compose extends FormElement {
329
397
  if (completion) {
330
398
  window.setTimeout(() => {
331
399
  completion.focus();
400
+ // this.resetTabs();
332
401
  }, 0);
333
402
  }
334
403
  }
@@ -338,13 +407,14 @@ export class Compose extends FormElement {
338
407
  (this.shadowRoot.querySelector('.chatbox') as HTMLInputElement).value = '';
339
408
  this.initialText = '';
340
409
  this.currentText = '';
410
+ this.currentQuickReplies = [];
341
411
  this.currentAttachments = [];
342
412
  this.failedAttachments = [];
343
413
  this.buttonError = '';
344
414
  }
345
415
 
346
- private handleContainerClick(evt: Event) {
347
- this.setFocusOnChatbox();
416
+ private handleQuickReplyChange(event: InputEvent) {
417
+ this.requestUpdate('currentQuickReplies');
348
418
  }
349
419
 
350
420
  private handleChatboxChange(evt: Event) {
@@ -562,6 +632,10 @@ export class Compose extends FormElement {
562
632
  this.currentLanguage = select.values[0].iso;
563
633
  }
564
634
 
635
+ public resetTabs() {
636
+ (this.shadowRoot.querySelector('temba-tabs') as TabPane).index = -1;
637
+ }
638
+
565
639
  public render(): TemplateResult {
566
640
  return html`
567
641
  <temba-field
@@ -583,7 +657,6 @@ export class Compose extends FormElement {
583
657
 
584
658
  <div
585
659
  class=${getClasses({ container: true, highlight: this.pendingDrop })}
586
- @click="${this.handleContainerClick}"
587
660
  @dragenter="${this.handleDragEnter}"
588
661
  @dragover="${this.handleDragOver}"
589
662
  @dragleave="${this.handleDragLeave}"
@@ -592,11 +665,7 @@ export class Compose extends FormElement {
592
665
  <div class="drop-mask"><div>Upload Attachment</div></div>
593
666
 
594
667
  ${this.chatbox ? html`${this.getChatbox()}` : null}
595
- ${this.attachments
596
- ? html`<div class="items attachments">
597
- ${this.getAttachments()}
598
- </div>`
599
- : null}
668
+
600
669
  <div class="items actions">${this.getActions()}</div>
601
670
  </div>
602
671
  </temba-field>
@@ -635,33 +704,27 @@ export class Compose extends FormElement {
635
704
 
636
705
  private getAttachments(): TemplateResult {
637
706
  return html`
638
- ${(this.currentAttachments && this.currentAttachments.length > 0) ||
639
- (this.failedAttachments && this.failedAttachments.length > 0)
707
+ ${this.attachments
640
708
  ? html` <div class="attachments-list">
641
- ${this.currentAttachments.map(validAttachment => {
642
- return html` <div class="attachment-item">
643
- <div
644
- class="remove-item"
645
- @click="${this.handleRemoveFileClicked}"
646
- >
709
+ ${this.currentAttachments.map(validAttachment => {
710
+ return html` <div class="attachment-item">
647
711
  <temba-icon
712
+ class="remove-item"
713
+ @click="${this.handleRemoveFileClicked}"
648
714
  id="${validAttachment.uuid}"
649
715
  name="${Icon.delete_small}"
650
716
  ></temba-icon>
651
- </div>
652
- <div class="attachment-name">
653
- <span
654
- title="${validAttachment.filename} (${formatFileSize(
655
- validAttachment.size,
656
- 2
657
- )}) ${validAttachment.content_type}"
658
- >${truncate(validAttachment.filename, 25)}
659
- (${formatFileSize(validAttachment.size, 0)})
660
- ${formatFileType(validAttachment.content_type)}</span
661
- >
662
- </div>
663
- </div>`;
664
- })}
717
+ ${isImageAttachment(validAttachment)
718
+ ? html`<temba-thumbnail
719
+ url="${validAttachment.url}"
720
+ ></temba-thumbnail>`
721
+ : html`<temba-thumbnail
722
+ label="${validAttachment.content_type.split('/')[1]}"
723
+ ></temba-thumbnail>`}
724
+ </div>`;
725
+ })}
726
+ ${this.getUploader()}
727
+ </div>
665
728
  ${this.failedAttachments.map(invalidAttachment => {
666
729
  return html` <div class="attachment-item error">
667
730
  <div
@@ -684,25 +747,55 @@ export class Compose extends FormElement {
684
747
  >
685
748
  </div>
686
749
  </div>`;
687
- })}
688
- </div>`
750
+ })}`
689
751
  : null}
690
752
  `;
691
753
  }
692
754
 
693
755
  private getActions(): TemplateResult {
694
756
  return html`
695
- <div class="actions-left">
696
- ${this.canAcceptAttachments() ? this.getUploader() : null}
697
- </div>
698
- <div class="actions-center"></div>
699
- <div class="actions-right">
700
- ${this.buttonError
701
- ? html`<div class="send-error">${this.buttonError}</div>`
757
+ <temba-tabs
758
+ embedded
759
+ focusedname
760
+ bottom
761
+ refresh="${this.currentAttachments.length}|${this.index}|${this
762
+ .currentQuickReplies.length}"
763
+ >
764
+ ${this.attachments
765
+ ? html`<temba-tab
766
+ name="Attachments"
767
+ icon="attachment"
768
+ .count=${this.currentAttachments.length}
769
+ >
770
+ <div class="items attachments"></div>
771
+ </temba-tab>`
772
+ : null}
773
+ ${this.quickReplies
774
+ ? html`<temba-tab
775
+ name="Quick Replies"
776
+ icon="quick_replies"
777
+ .count=${this.currentQuickReplies.length}
778
+ >
779
+ <temba-select
780
+ @change=${this.handleQuickReplyChange}
781
+ .values=${this.currentQuickReplies}
782
+ class="quick-replies"
783
+ tags
784
+ multi
785
+ searchable
786
+ expressions
787
+ placeholder="Add Quick Reply"
788
+ ></temba-select>
789
+ </temba-tab>`
702
790
  : null}
703
- ${this.counter ? this.getCounter() : null}
704
- ${this.button ? this.getButton() : null}
705
- </div>
791
+ <div slot="tab-right" class="top-right">
792
+ ${this.buttonError
793
+ ? html`<div class="send-error">${this.buttonError}</div>`
794
+ : null}
795
+ ${this.counter ? this.getCounter() : null}
796
+ ${this.button ? this.getButton() : null}
797
+ </div>
798
+ </temba-tabs>
706
799
  `;
707
800
  }
708
801
 
@@ -710,26 +803,27 @@ export class Compose extends FormElement {
710
803
  if (this.uploading) {
711
804
  return html`<temba-loading units="3" size="12"></temba-loading>`;
712
805
  } else {
713
- return html` <input
714
- type="file"
715
- id="upload-input"
716
- multiple
717
- accept="${this.accept}"
718
- @change="${this.handleUploadFileInputChanged}"
719
- />
720
- <label
721
- id="upload-label"
722
- class="actions-left upload-label"
723
- for="upload-input"
724
- >
725
- <temba-icon
726
- id="upload-icon"
727
- class="upload-icon"
728
- name="${Icon.attachment}"
729
- @click="${this.handleUploadFileIconClicked}"
730
- clickable
731
- ></temba-icon>
732
- </label>`;
806
+ return this.currentAttachments.length < this.maxAttachments
807
+ ? html`<input
808
+ type="file"
809
+ id="upload-input"
810
+ multiple
811
+ accept="${this.accept}"
812
+ @change="${this.handleUploadFileInputChanged}"
813
+ />
814
+ <label
815
+ id="upload-label"
816
+ class="actions-left upload-label"
817
+ for="upload-input"
818
+ >
819
+ <div
820
+ class="add-attachment"
821
+ @click="${this.handleUploadFileIconClicked}"
822
+ >
823
+ <temba-icon name="add" size="1.5"></temba-icon>
824
+ </div>
825
+ </label>`
826
+ : null;
733
827
  }
734
828
  }
735
829
 
@@ -32,13 +32,13 @@ export class ContactChat extends ContactStoreElement {
32
32
  display: flex;
33
33
  flex-grow: 1;
34
34
  flex-direction: column;
35
- overflow: hidden;
35
+ background: #e9e9e9;
36
+
36
37
  min-height: 0;
37
- border-radius: var(--curvature);
38
38
  }
39
39
 
40
40
  temba-contact-history {
41
- border-bottom: 3px solid #e1e1e1;
41
+ border-bottom: 0px solid #f4f4f4;
42
42
  flex-grow: 1;
43
43
  display: flex;
44
44
  flex-direction: column;
@@ -46,8 +46,7 @@ export class ContactChat extends ContactStoreElement {
46
46
  }
47
47
 
48
48
  .chatbox {
49
- background: rgb(242, 242, 242);
50
- padding: 1em;
49
+ padding: 0.8em;
51
50
  display: flex;
52
51
  flex-direction: column;
53
52
  z-index: 3;
package/src/interfaces.ts CHANGED
@@ -13,6 +13,15 @@ export interface Language {
13
13
  name: string;
14
14
  }
15
15
 
16
+ export interface Attachment {
17
+ uuid: string;
18
+ content_type: string;
19
+ url: string;
20
+ filename: string;
21
+ size: number;
22
+ error: string;
23
+ }
24
+
16
25
  export enum DateStyle {
17
26
  DayFirst = 'day_first',
18
27
  MonthFirst = 'month_first',
@@ -80,6 +80,7 @@ export class Lightbox extends RapidElement {
80
80
 
81
81
  public showElement(ele: HTMLElement) {
82
82
  // size our matte according to the ele's boundaries
83
+ console.log(ele);
83
84
  const bounds = ele.getBoundingClientRect();
84
85
  this.ele = ele.cloneNode() as HTMLElement;
85
86
  this.left = bounds.left;
@@ -288,7 +288,7 @@ export class Select extends FormElement {
288
288
  .searchbox::placeholder {
289
289
  color: var(--color-placeholder);
290
290
  font-weight: 300;
291
- font-size: 1.1em;
291
+ font-size: 1em;
292
292
  line-height: var(--temba-select-selected-line-height);
293
293
  padding-left: 1px;
294
294
  }
@@ -1,4 +1,4 @@
1
- import { css, html, TemplateResult } from 'lit';
1
+ import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
2
  import { property } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
  import { getClasses } from '../utils';