@nyaruka/temba-components 0.136.1 → 0.138.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 (73) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/demo/components/webchat/example.html +2 -2
  3. package/dist/temba-components.js +692 -622
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/display/Chat.js +123 -44
  6. package/out-tsc/src/display/Chat.js.map +1 -1
  7. package/out-tsc/src/display/FloatingTab.js +2 -2
  8. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  9. package/out-tsc/src/events/eventRenderers.js +442 -0
  10. package/out-tsc/src/events/eventRenderers.js.map +1 -0
  11. package/out-tsc/src/flow/CanvasNode.js +45 -24
  12. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  13. package/out-tsc/src/flow/Editor.js +308 -18
  14. package/out-tsc/src/flow/Editor.js.map +1 -1
  15. package/out-tsc/src/flow/NodeEditor.js +0 -1
  16. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  17. package/out-tsc/src/flow/Plumber.js +110 -64
  18. package/out-tsc/src/flow/Plumber.js.map +1 -1
  19. package/out-tsc/src/list/ShortcutList.js +1 -1
  20. package/out-tsc/src/list/ShortcutList.js.map +1 -1
  21. package/out-tsc/src/live/ContactChat.js +12 -321
  22. package/out-tsc/src/live/ContactChat.js.map +1 -1
  23. package/out-tsc/src/simulator/Simulator.js +439 -575
  24. package/out-tsc/src/simulator/Simulator.js.map +1 -1
  25. package/out-tsc/src/store/AppState.js +12 -2
  26. package/out-tsc/src/store/AppState.js.map +1 -1
  27. package/out-tsc/test/temba-flow-editor-node.test.js +2 -1
  28. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  29. package/out-tsc/test/temba-flow-editor-revisions.test.js +106 -0
  30. package/out-tsc/test/temba-flow-editor-revisions.test.js.map +1 -0
  31. package/out-tsc/test/temba-flow-editor.test.js +14 -10
  32. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  33. package/out-tsc/test/temba-flow-plumber-connections.test.js +7 -1
  34. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
  35. package/out-tsc/test/temba-flow-plumber.test.js +6 -0
  36. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  37. package/out-tsc/test/temba-simulator.test.js +51 -32
  38. package/out-tsc/test/temba-simulator.test.js.map +1 -1
  39. package/package.json +1 -1
  40. package/screenshots/truth/contacts/chat-failure.png +0 -0
  41. package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
  42. package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
  43. package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
  44. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  45. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  46. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  47. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  48. package/screenshots/truth/simulator/after-message-sent.png +0 -0
  49. package/screenshots/truth/simulator/after-reset.png +0 -0
  50. package/screenshots/truth/simulator/attachment-menu.png +0 -0
  51. package/screenshots/truth/simulator/context-expanded.png +0 -0
  52. package/screenshots/truth/simulator/context-explorer-open.png +0 -0
  53. package/screenshots/truth/simulator/event-info.png +0 -0
  54. package/screenshots/truth/simulator/image-attachment.png +0 -0
  55. package/screenshots/truth/simulator/open-initial.png +0 -0
  56. package/screenshots/truth/simulator/quick-replies.png +0 -0
  57. package/src/display/Chat.ts +123 -44
  58. package/src/display/FloatingTab.ts +2 -2
  59. package/src/events/eventRenderers.ts +527 -0
  60. package/src/flow/CanvasNode.ts +54 -29
  61. package/src/flow/Editor.ts +360 -19
  62. package/src/flow/NodeEditor.ts +0 -1
  63. package/src/flow/Plumber.ts +123 -69
  64. package/src/list/ShortcutList.ts +1 -1
  65. package/src/live/ContactChat.ts +17 -376
  66. package/src/simulator/Simulator.ts +498 -617
  67. package/src/store/AppState.ts +13 -2
  68. package/test/temba-flow-editor-node.test.ts +2 -1
  69. package/test/temba-flow-editor-revisions.test.ts +134 -0
  70. package/test/temba-flow-editor.test.ts +16 -10
  71. package/test/temba-flow-plumber-connections.test.ts +7 -1
  72. package/test/temba-flow-plumber.test.ts +6 -0
  73. package/test/temba-simulator.test.ts +64 -34
@@ -71,11 +71,13 @@ export class Chat extends RapidElement {
71
71
  this.hideBottomScroll = true;
72
72
  this.defaultAvatar = DEFAULT_AVATAR;
73
73
  this.agent = false;
74
+ this.avatars = false;
74
75
  this.endOfHistory = false;
75
76
  this.oldestEventDate = null;
76
77
  this.showNewMessageNotification = false;
77
78
  this.showMessageLogsAfter = null;
78
79
  this.hasFooter = false;
80
+ this.showTimestamps = true;
79
81
  this.msgMap = new Map();
80
82
  this.metadataCache = new Map();
81
83
  }
@@ -169,7 +171,13 @@ export class Chat extends RapidElement {
169
171
  display: flex;
170
172
  flex-direction: row;
171
173
  align-items: flex-start;
172
- margin-bottom: 0.25em;
174
+ margin-bottom: 8px;
175
+ }
176
+
177
+ .row.is-event {
178
+ margin-bottom: 2px;
179
+ margin-left: 0px !important;
180
+ margin-right: 4px !important;
173
181
  }
174
182
 
175
183
  .input-panel {
@@ -213,10 +221,9 @@ export class Chat extends RapidElement {
213
221
  }
214
222
 
215
223
  .bubble {
216
- padding: 0.75em;
217
- padding-bottom: 0.25em;
218
- background: var(--color-chat-in, #f1f1f1);
219
- border-radius: var(--curvature);
224
+ padding: 10px 14px;
225
+ background: var(--color-chat-in, #e5e5ea);
226
+ border-radius: 18px;
220
227
  border: var(--chat-border-in, none);
221
228
  }
222
229
 
@@ -228,7 +235,7 @@ export class Chat extends RapidElement {
228
235
  }
229
236
 
230
237
  .outgoing .latest .bubble {
231
- border-bottom-left-radius: 0;
238
+ border-bottom-left-radius: 4px;
232
239
  }
233
240
 
234
241
  .incoming .bubble-wrap {
@@ -236,13 +243,13 @@ export class Chat extends RapidElement {
236
243
  }
237
244
 
238
245
  .incoming .bubble {
239
- background: var(--color-chat-out, #3c92dd);
246
+ background: var(--color-chat-out, #007aff);
240
247
  border: var(--chat-border-out, none);
241
248
  color: white;
242
249
  }
243
250
 
244
251
  .incoming .latest .bubble {
245
- border-bottom-right-radius: 0;
252
+ border-bottom-right-radius: 4px;
246
253
  }
247
254
 
248
255
  .incoming .bubble .name {
@@ -258,16 +265,26 @@ export class Chat extends RapidElement {
258
265
  color: rgba(0, 0, 0, 0.5);
259
266
  }
260
267
 
268
+ .warning .bubble {
269
+ background: #fef3c7;
270
+ color: rgba(125, 87, 18, 0.8);
271
+ border: none;
272
+ }
273
+
274
+ .warning .bubble .name {
275
+ color: rgba(125, 87, 18, 0.6);
276
+ }
277
+
261
278
  .failed .bubble,
262
279
  .error .bubble {
263
- border: 1px solid var(--color-error);
264
- background: #ffe6e6;
265
- color: #ad4747ff;
280
+ border: none;
281
+ background: #fee3e3;
282
+ color: #c01829;
266
283
  }
267
284
 
268
285
  .error .bubble .name,
269
286
  .failed .bubble .name {
270
- color: #ad47479a;
287
+ color: rgba(192, 24, 41, 0.6);
271
288
  }
272
289
 
273
290
  .deleted .bubble {
@@ -282,15 +299,48 @@ export class Chat extends RapidElement {
282
299
 
283
300
  .message-text {
284
301
  white-space: pre-wrap;
285
- margin-bottom: 0.5em;
286
- line-height: 1.2em;
302
+ margin-bottom: 0;
303
+ line-height: 1.2;
287
304
  word-break: break-word;
305
+ font-size: 13px;
288
306
  }
289
307
 
290
308
  .message-deleted {
291
309
  font-style: italic;
292
- margin-bottom: 0.5em;
293
- line-height: 1.2em;
310
+ margin-bottom: 0;
311
+ line-height: 1.2;
312
+ font-size: 13px;
313
+ }
314
+
315
+ .quick-replies {
316
+ display: flex;
317
+ flex-wrap: wrap;
318
+ justify-content: center;
319
+ gap: 6px;
320
+ padding: 8px 0;
321
+ margin: 0 auto;
322
+ max-width: 90%;
323
+ }
324
+
325
+ .quick-reply-btn {
326
+ padding: 4px 8px;
327
+ border-radius: 18px;
328
+ border: 1px solid var(--color-chat-out, #007aff);
329
+ background: white;
330
+ color: var(--color-chat-out, #007aff);
331
+ font-size: 11px;
332
+ cursor: pointer;
333
+ transition: all 0.2s ease;
334
+ }
335
+
336
+ .quick-reply-btn:hover:not(:disabled) {
337
+ background: var(--color-chat-out, #007aff);
338
+ color: white;
339
+ }
340
+
341
+ .quick-reply-btn:disabled {
342
+ opacity: 0.5;
343
+ cursor: not-allowed;
294
344
  }
295
345
 
296
346
  .chat {
@@ -331,12 +381,21 @@ export class Chat extends RapidElement {
331
381
  overflow-x: hidden;
332
382
  -webkit-overflow-scrolling: touch;
333
383
  overflow-scrolling: touch;
334
- padding: 1em 1em 1em 1em;
335
- padding-bottom: 2.5em;
384
+ padding: var(--chat-top-padding, 1em) 1em
385
+ var(--chat-bottom-padding, 2.5em) 1em;
336
386
  display: flex;
337
387
  flex-direction: column-reverse;
338
388
  }
339
389
 
390
+ :host(.phone-screen) .scroll {
391
+ scrollbar-width: none;
392
+ -ms-overflow-style: none;
393
+ }
394
+
395
+ :host(.phone-screen) .scroll::-webkit-scrollbar {
396
+ display: none;
397
+ }
398
+
340
399
  .messages:before {
341
400
  content: '';
342
401
  background: radial-gradient(
@@ -470,6 +529,9 @@ export class Chat extends RapidElement {
470
529
  display: flex;
471
530
  flex-direction: column;
472
531
  align-items: center;
532
+ text-align: center;
533
+ font-size: 11px;
534
+ color: #8e8e93;
473
535
  }
474
536
 
475
537
  .event p {
@@ -791,10 +853,11 @@ export class Chat extends RapidElement {
791
853
  ? currentMsg.type !== 'msg_received'
792
854
  : currentMsg.type === 'msg_received';
793
855
  const name = (_a = currentMsg._user) === null || _a === void 0 ? void 0 : _a.name;
794
- const showAvatar = ((currentMsg.type === 'msg_received' ||
795
- currentMsg.type === 'msg_created') &&
796
- this.agent) ||
797
- !incoming;
856
+ const showAvatar = this.avatars &&
857
+ (((currentMsg.type === 'msg_received' ||
858
+ currentMsg.type === 'msg_created') &&
859
+ this.agent) ||
860
+ !incoming);
798
861
  const isSystem = !((_b = currentMsg._user) === null || _b === void 0 ? void 0 : _b.uuid);
799
862
  const reasonLabel = this.getReasonLabel(group.reason);
800
863
  const showReason = false; // reasonLabel && idx > 0;
@@ -843,8 +906,10 @@ export class Chat extends RapidElement {
843
906
  (statusClass === 'failed' || statusClass === 'errored'));
844
907
  const unsendableClass = hasError ? 'error' : '';
845
908
  const deletedClass = msgEvent._deleted ? 'deleted' : '';
909
+ const latestClass = index === msgIds.length - 1 ? 'latest' : '';
910
+ const eventClass = msg._rendered ? 'is-event' : '';
846
911
  return html `<div
847
- class="row message ${statusClass} ${unsendableClass} ${deletedClass}"
912
+ class="row message ${statusClass} ${unsendableClass} ${deletedClass} ${latestClass} ${eventClass}"
848
913
  >
849
914
  ${this.renderMessage(msg, index == 0 ? name : null)}
850
915
  </div>`;
@@ -875,6 +940,10 @@ export class Chat extends RapidElement {
875
940
  return html `<div class="event">${event._rendered.html}</div>`;
876
941
  }
877
942
  const message = event;
943
+ // safety check: if msg doesn't exist, return nothing
944
+ if (!message.msg) {
945
+ return html ``;
946
+ }
878
947
  const unsendableReason = (_a = message.msg) === null || _a === void 0 ? void 0 : _a.unsendable_reason;
879
948
  const statusReason = (_b = message._status) === null || _b === void 0 ? void 0 : _b.reason;
880
949
  const errorMessage = unsendableReason
@@ -901,28 +970,32 @@ export class Chat extends RapidElement {
901
970
  /^-?\d+\.?\d*\s*,\s*-?\d+\.?\d*$/.test(message.msg.text.trim());
902
971
  return html `
903
972
  <div class="bubble-wrap">
904
- <div class="popup" style="white-space: nowrap;">
905
- ${errorMessage
906
- ? html `<div style="color: var(--color-error); margin-right: 1em;">
907
- ${errorMessage}
908
- </div>`
909
- : null}
910
- <temba-date
911
- value="${message.created_on.toISOString()}"
912
- display="relative"
913
- ></temba-date>
914
- ${logsURL
915
- ? html `<a
916
- style="margin-left: 1em; color: var(--color-primary-dark);"
917
- href="${logsURL}"
918
- target="_blank"
919
- rel="noopener noreferrer"
920
- ><temba-icon name="log"></temba-icon
921
- ></a>`
922
- : null}
973
+ ${this.showTimestamps
974
+ ? html `<div class="popup" style="white-space: nowrap;">
975
+ ${errorMessage
976
+ ? html `<div
977
+ style="color: var(--color-error); margin-right: 1em;"
978
+ >
979
+ ${errorMessage}
980
+ </div>`
981
+ : null}
982
+ <temba-date
983
+ value="${message.created_on.toISOString()}"
984
+ display="relative"
985
+ ></temba-date>
986
+ ${logsURL
987
+ ? html `<a
988
+ style="margin-left: 1em; color: var(--color-primary-dark);"
989
+ href="${logsURL}"
990
+ target="_blank"
991
+ rel="noopener noreferrer"
992
+ ><temba-icon name="log"></temba-icon
993
+ ></a>`
994
+ : null}
923
995
 
924
- <div class="arrow">▼</div>
925
- </div>
996
+ <div class="arrow">▼</div>
997
+ </div>`
998
+ : null}
926
999
  ${isDeleted
927
1000
  ? html `<div class="bubble">
928
1001
  ${name ? html `<div class="name">${name}</div>` : null}
@@ -1024,6 +1097,9 @@ __decorate([
1024
1097
  __decorate([
1025
1098
  property({ type: Boolean })
1026
1099
  ], Chat.prototype, "agent", void 0);
1100
+ __decorate([
1101
+ property({ type: Boolean })
1102
+ ], Chat.prototype, "avatars", void 0);
1027
1103
  __decorate([
1028
1104
  property({ type: Boolean, attribute: false })
1029
1105
  ], Chat.prototype, "endOfHistory", void 0);
@@ -1039,4 +1115,7 @@ __decorate([
1039
1115
  __decorate([
1040
1116
  property({ type: Boolean })
1041
1117
  ], Chat.prototype, "hasFooter", void 0);
1118
+ __decorate([
1119
+ property({ type: Boolean })
1120
+ ], Chat.prototype, "showTimestamps", void 0);
1042
1121
  //# sourceMappingURL=Chat.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.js","sourceRoot":"","sources":["../../../src/display/Chat.ts"],"names":[],"mappings":"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","sourcesContent":["import { TemplateResult, html, PropertyValueMap, css } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { DEFAULT_AVATAR } from '../webchat/assets';\n\nconst BATCH_TIME_WINDOW = 60 * 60 * 1000;\nconst SCROLL_FETCH_BUFFER = 200; // pixels from top\nconst MIN_FETCH_TIME = 250;\n\nconst getUnsendableReasonMessage = (reason: string): string => {\n switch (reason) {\n case 'no_route':\n return 'No channel available to send message';\n case 'contact_blocked':\n return 'Contact has been blocked';\n case 'contact_stopped':\n return 'Contact has been stopped';\n case 'contact_archived':\n return 'Contact is archived';\n case 'org_suspended':\n return 'Workspace is suspended';\n case 'looping':\n return 'Message loop detected';\n default:\n return 'Unable to send message';\n }\n};\n\nconst getStatusReasonMessage = (reason: string): string => {\n switch (reason) {\n case 'error_limit':\n return 'Error limit reached';\n case 'too_old':\n return 'Message is too old to send';\n case 'channel_removed':\n return 'Channel was removed';\n default:\n return 'Message failed to send';\n }\n};\n\nexport enum MessageType {\n Inline = 'inline',\n Error = 'error',\n Collapse = 'collapse',\n Note = 'note'\n}\n\nexport type GroupReason =\n | 'time_elapsed'\n | 'new_author'\n | 'new_type'\n | 'initial';\n\nexport interface MessageGroup {\n messages: string[];\n reason: GroupReason;\n}\n\nexport interface ObjectReference {\n uuid: string;\n name: string;\n}\n\ninterface User extends ObjectReference {\n avatar?: string;\n email: string;\n}\n\nexport interface Msg {\n text: string;\n channel: ObjectReference;\n quick_replies: string[];\n urn: string;\n direction: string;\n type: string;\n attachments: string[];\n unsendable_reason?:\n | 'no_route'\n | 'contact_blocked'\n | 'contact_stopped'\n | 'contact_archived'\n | 'org_suspended'\n | 'looping';\n}\n\nexport interface ContactEvent {\n uuid?: string;\n type: string;\n created_on: Date;\n _user?: User;\n _rendered?: { html: TemplateResult; type: MessageType };\n}\n\nexport interface MsgEvent extends ContactEvent {\n msg: Msg;\n optin?: ObjectReference;\n _status?: {\n created_on: string;\n status: 'wired' | 'sent' | 'delivered' | 'read' | 'errored' | 'failed';\n reason: 'error_limit' | 'too_old' | 'channel_removed';\n };\n _deleted?: {\n created_on: string;\n by_contact: boolean;\n user?: { name: string; uuid: string };\n };\n _logs_url?: string;\n}\n\nconst TIME_FORMAT = { hour: 'numeric', minute: '2-digit' } as any;\nconst VERBOSE_FORMAT = {\n weekday: undefined,\n year: undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n} as any;\nconst VERBOSE_FORMAT_WITH_YEAR = {\n weekday: undefined,\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n} as any;\n\nexport class Chat extends RapidElement {\n static get styles() {\n return css`\n :host {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n position: relative;\n z-index: 1;\n }\n\n slot[name='header'] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n slot[name='footer'] {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n .block {\n margin-bottom: 1em;\n display: flex;\n flex-direction: row;\n }\n\n .block.outgoing {\n flex-direction: row-reverse;\n }\n\n .block.collapse {\n margin: 0;\n align-items: center;\n display: flex;\n flex-direction: column;\n margin-bottom: 0.5em;\n }\n\n .block.collapse .messsage {\n transform: scaleY(0);\n margin: 0;\n padding: 0;\n line-height: 0;\n }\n\n .time {\n text-align: center;\n font-size: 0.8em;\n color: #999;\n margin-bottom: 2em;\n margin-top: 1em;\n border-top: 1px solid #e9e9e9;\n padding: 1em;\n margin-left: 10%;\n margin-right: 10%;\n }\n\n .time.first {\n border-top: none;\n margin-top: 0;\n border-bottom: 1px solid #e9e9e9;\n margin-bottom: 2em;\n }\n\n .first .time {\n margin-top: 0;\n border-top: none;\n padding-top: 0;\n }\n\n .group-reason {\n text-align: center;\n font-size: 0.75em;\n color: #999;\n margin-bottom: 1em;\n margin-top: 0.5em;\n padding: 0.5em 1em;\n font-style: italic;\n }\n\n .row {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n margin-bottom: 0.25em;\n }\n\n .input-panel {\n padding: 1em;\n background: #fff;\n }\n\n temba-user {\n margin-right: 0.6em;\n margin-left: 0.6em;\n width: 2em;\n align-self: flex-end;\n }\n\n .toggle {\n flex-shrink: 0;\n width: 4em;\n height: 4em;\n overflow: hidden;\n border-radius: 100%;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.1);\n cursor: pointer;\n transition: box-shadow var(--toggle-speed, 200ms) ease-out;\n position: absolute;\n bottom: 1em;\n right: 1em;\n }\n\n .toggle:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.4) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.2);\n }\n\n .incoming .row {\n flex-direction: row-reverse;\n margin-left: 1em;\n margin-right: 1em;\n }\n\n .bubble {\n padding: 0.75em;\n padding-bottom: 0.25em;\n background: var(--color-chat-in, #f1f1f1);\n border-radius: var(--curvature);\n border: var(--chat-border-in, none);\n }\n\n .bubble .name {\n font-size: 0.95em;\n font-weight: 400;\n color: rgba(0, 0, 0, 0.4);\n margin-bottom: 0.25em;\n }\n\n .outgoing .latest .bubble {\n border-bottom-left-radius: 0;\n }\n\n .incoming .bubble-wrap {\n align-items: flex-end;\n }\n\n .incoming .bubble {\n background: var(--color-chat-out, #3c92dd);\n border: var(--chat-border-out, none);\n color: white;\n }\n\n .incoming .latest .bubble {\n border-bottom-right-radius: 0;\n }\n\n .incoming .bubble .name {\n color: rgba(255, 255, 255, 0.7);\n }\n\n .note .bubble {\n background: #fffac3;\n color: rgba(0, 0, 0, 0.7);\n }\n\n .note .bubble .name {\n color: rgba(0, 0, 0, 0.5);\n }\n\n .failed .bubble,\n .error .bubble {\n border: 1px solid var(--color-error);\n background: #ffe6e6;\n color: #ad4747ff;\n }\n\n .error .bubble .name,\n .failed .bubble .name {\n color: #ad47479a;\n }\n\n .deleted .bubble {\n background: #fff;\n color: #999;\n border: 1px solid #e0e0e0;\n }\n\n .deleted .bubble .name {\n color: #aaa;\n }\n\n .message-text {\n white-space: pre-wrap;\n margin-bottom: 0.5em;\n line-height: 1.2em;\n word-break: break-word;\n }\n\n .message-deleted {\n font-style: italic;\n margin-bottom: 0.5em;\n line-height: 1.2em;\n }\n\n .chat {\n width: 28rem;\n border-radius: var(--curvature);\n overflow: hidden;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, rgba(0, 0, 0, 0.1) 5em 5em 5em 5em;\n position: absolute;\n bottom: 3em;\n right: 1em;\n transition: all var(--toggle-speed, 200ms) ease-out;\n transform: scale(0.9);\n pointer-events: none;\n opacity: 0;\n }\n\n .chat.open {\n bottom: 6em;\n opacity: 1;\n transform: scale(1);\n pointer-events: initial;\n }\n\n .messages {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n }\n\n .scroll {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overflow-scrolling: touch;\n padding: 1em 1em 1em 1em;\n padding-bottom: 2.5em;\n display: flex;\n flex-direction: column-reverse;\n }\n\n .messages:before {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 0,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center top;\n height: 10px;\n display: block;\n position: absolute;\n width: 100%;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .messages:after {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 100%,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center bottom;\n height: 10px;\n display: block;\n position: absolute;\n bottom: 0;\n margin-top: -10px;\n width: 100%;\n margin-right: 5em;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .bubble-wrap {\n position: relative;\n max-width: 70%;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n }\n\n .scroll-at-top.messages:before {\n opacity: 0;\n }\n\n .scroll-at-bottom.messages:after {\n opacity: 0;\n }\n\n .input {\n border: none;\n flex-grow: 1;\n color: #333;\n font-size: 1em;\n }\n\n .input:focus {\n outline: none;\n }\n\n input::placeholder {\n opacity: 0.3;\n }\n\n .input.inactive {\n // pointer-events: none;\n // opacity: 0.3;\n }\n\n .active {\n }\n\n .send-icon {\n color: #eee;\n pointer-events: none;\n transform: rotate(-45deg);\n transition: transform 0.2s ease-out;\n }\n\n .pending .send-icon {\n color: var(--color-primary-dark);\n pointer-events: initial;\n transform: rotate(0deg);\n }\n\n .notice {\n padding: 1em;\n background: #f8f8f8;\n color: #666;\n text-align: center;\n cursor: pointer;\n }\n\n .connecting .notice {\n display: flex;\n justify-content: center;\n }\n\n .connecting .notice temba-icon {\n margin-left: 0.5em;\n }\n\n .reconnect {\n color: var(--color-primary-dark);\n text-decoration: underline;\n font-size: 0.9em;\n }\n\n .input:disabled {\n background: transparent !important;\n }\n\n temba-loading {\n justify-content: center;\n margin: 0.5em auto;\n margin-bottom: 2em;\n }\n\n temba-loading.hidden {\n display: none;\n }\n\n .inline {\n }\n\n .event {\n flex-grow: 1;\n align-self: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n\n .event p {\n margin: 0;\n padding: 0;\n }\n\n .collapse {\n }\n\n a {\n color: var(--color-primary-dark);\n }\n\n .attachments {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n align-self: flex-start;\n }\n\n .incoming .attachments {\n align-self: flex-end;\n }\n\n temba-thumbnail {\n margin: 0.4em;\n border-radius: var(--curvature);\n }\n\n .failed temba-thumbnail,\n .error temba-thumbnail {\n --thumb-background: #ffe6e6;\n --thumb-border: var(--color-error);\n border: 1px solid var(--color-error);\n color: #ad4747a8;\n }\n\n .outgoing .popup {\n justify-content: left;\n }\n\n .incoming .popup {\n justify-content: right;\n }\n\n .popup {\n display: flex;\n position: absolute;\n background: #fff;\n margin: 0;\n padding: 0.5em 1em;\n border-radius: var(--curvature);\n box-shadow: rgba(0, 0, 0, 0.05) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n border: 1px solid #f3f3f3;\n opacity: 0;\n z-index: 2;\n }\n\n .popup .arrow {\n z-index: 1;\n text-shadow: 0px 3px 3px rgba(0, 0, 0, 0.1);\n position: absolute;\n justify-content: center;\n text-align: center;\n font-size: 1.3em;\n transform: translateY(0.7em) scale(1);\n color: #fff;\n bottom: 0;\n }\n\n .bubble-wrap:hover .popup {\n opacity: 1;\n transition-delay: 1s;\n top: -35px;\n }\n\n .new-message-notification {\n position: absolute;\n bottom: 1em;\n left: 50%;\n transform: translateX(-50%) translateY(100px);\n background: var(--color-primary-dark, #3c92dd);\n color: white;\n padding: 0.75em 1.5em;\n border-radius: var(--curvature);\n box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.3) 0px 1px 2px 0px;\n cursor: pointer;\n opacity: 0;\n transition: all 0.3s ease-out;\n z-index: 100;\n font-weight: 500;\n pointer-events: none;\n }\n\n .new-message-notification.visible {\n transform: translateX(-50%) translateY(0);\n opacity: 1;\n pointer-events: auto;\n }\n\n .new-message-notification:hover {\n background: var(--color-primary-darker, #2b7ac4);\n box-shadow: rgba(0, 0, 0, 0.3) 0px 4px 10px 0px,\n rgba(0, 0, 0, 0.4) 0px 2px 4px 0px;\n }\n `;\n }\n\n @property({ type: Array })\n messageGroups: MessageGroup[] = [];\n\n @property({ type: Boolean })\n fetching = false;\n\n @property({ type: Boolean, attribute: false })\n hideTopScroll = true;\n\n @property({ type: Boolean, attribute: false })\n hideBottomScroll = true;\n\n @property({ type: String, attribute: 'avatar' })\n defaultAvatar = DEFAULT_AVATAR;\n\n @property({ type: Boolean })\n agent = false;\n\n @property({ type: Boolean, attribute: false })\n endOfHistory = false;\n\n @property({ type: Object, attribute: false })\n oldestEventDate: Date = null;\n\n @property({ type: Boolean, attribute: false })\n showNewMessageNotification = false;\n\n @property({ type: Object })\n showMessageLogsAfter: Date = null;\n\n @property({ type: Boolean })\n hasFooter = false;\n\n private msgMap = new Map<string, ContactEvent>();\n private metadataCache = new Map<string, ContactEvent>();\n\n public firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const scroll = this.shadowRoot.querySelector('.scroll');\n const hasScroll = scroll.scrollHeight > scroll.clientHeight;\n this.hideBottomScroll = true;\n this.hideTopScroll = !hasScroll;\n }\n\n public addMessages(\n messages: ContactEvent[],\n startTime: Date = null,\n append = false\n ) {\n if (!startTime) {\n startTime = new Date();\n }\n\n const elapsed = new Date().getTime() - startTime.getTime();\n window.setTimeout(\n () => {\n this.fetching = false;\n // first add messages to the map\n const newMessages = [];\n for (const m of messages) {\n // filter out metadata events - they aren't rendered but cached for later reference\n if (m.type === 'msg_deleted' || m.type === 'msg_status_changed') {\n const msgUuid = (m as any).msg_uuid;\n if (msgUuid) {\n this.metadataCache.set(msgUuid, m);\n }\n continue;\n }\n\n if (this.addMessage(m)) {\n newMessages.push(m.uuid);\n }\n }\n\n if (newMessages.length === 0) {\n return;\n }\n\n const ele = this.shadowRoot.querySelector('.scroll');\n const prevTop = ele.scrollTop;\n const prevScrollHeight = ele.scrollHeight;\n const scrollableHeight = ele.scrollHeight - ele.clientHeight;\n const isScrolledAway =\n scrollableHeight > 0 && Math.abs(ele.scrollTop) > 50;\n\n const grouped = this.groupMessages(newMessages);\n this.insertGroups(grouped, append);\n\n // show notification if new messages are appended and user is scrolled away from bottom\n if (append && isScrolledAway && newMessages.length > 0) {\n this.showNewMessageNotification = true;\n }\n\n window.setTimeout(() => {\n // when appending (new messages at bottom), adjust scroll to maintain visible content\n // with column-reverse, new content at bottom increases scrollHeight\n if (append && isScrolledAway) {\n const heightDiff = ele.scrollHeight - prevScrollHeight;\n ele.scrollTop = prevTop - heightDiff;\n } else {\n ele.scrollTop = prevTop;\n }\n\n this.fireCustomEvent(CustomEventType.FetchComplete);\n }, 100);\n },\n // if it's the first load don't wait, otherwise wait a minimum amount of time\n this.messageGroups.length === 0\n ? 0\n : Math.max(0, MIN_FETCH_TIME - elapsed)\n );\n }\n\n private addMessage(msg: ContactEvent): boolean {\n const isNew = !this.messageExists(msg);\n this.msgMap.set(msg.uuid, msg);\n return isNew;\n }\n\n public messageExists(msg: ContactEvent): boolean {\n return this.msgMap.has(msg.uuid);\n }\n\n private isSameGroup(\n msg1: ContactEvent,\n msg2: ContactEvent,\n lastTimeElapsedDate?: Date\n ): { same: boolean; reason?: GroupReason } {\n if (!msg1 || !msg2) {\n return { same: true };\n }\n\n // for type equivalence, treat all non-message types as the same\n const isMsg1 = msg1.type === 'msg_created' || msg1.type === 'msg_received';\n const isMsg2 = msg2.type === 'msg_created' || msg2.type === 'msg_received';\n const typeMatch =\n isMsg1 && isMsg2 ? msg1.type === msg2.type : isMsg1 === isMsg2;\n\n // check time first - if BATCH_TIME_WINDOW has passed since last time_elapsed reason\n const timeToCheck = lastTimeElapsedDate || msg1.created_on;\n if (\n Math.abs(msg2.created_on.getTime() - timeToCheck.getTime()) >=\n BATCH_TIME_WINDOW\n ) {\n return { same: false, reason: 'time_elapsed' };\n }\n\n if (!typeMatch) {\n return { same: false, reason: 'new_type' };\n }\n\n // only check author for message types\n if (isMsg1 && isMsg2 && msg1._user?.name !== msg2._user?.name) {\n return { same: false, reason: 'new_author' };\n }\n\n return { same: true };\n }\n\n private insertGroups(newGroups: MessageGroup[], append = false) {\n if (!append) {\n newGroups.reverse();\n }\n\n for (const newGroup of newGroups) {\n // see if our new group belongs to the most recent group\n const group =\n this.messageGroups[append ? 0 : this.messageGroups.length - 1];\n\n if (group) {\n const lastMsgId = group.messages[group.messages.length - 1];\n const lastMsg = this.msgMap.get(lastMsgId);\n const newMsg = this.msgMap.get(newGroup.messages[0]);\n // if our message belongs to the previous group, in we go\n const groupCheck = this.isSameGroup(lastMsg, newMsg);\n if (groupCheck.same) {\n group.messages.push(...newGroup.messages);\n } else {\n // otherwise, just add our entire group as a new one\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n } else {\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n }\n\n this.requestUpdate('messageGroups');\n }\n\n private groupMessages(msgIds: string[]): MessageGroup[] {\n // group our messages by origin and user\n const groups: MessageGroup[] = [];\n let lastGroup: MessageGroup = null;\n let lastMsg: ContactEvent = null;\n let lastTimeElapsedDate: Date = null;\n\n for (const msgId of msgIds) {\n const msg = this.msgMap.get(msgId);\n const groupCheck = this.isSameGroup(msg, lastMsg, lastTimeElapsedDate);\n\n if (!groupCheck.same || !lastGroup) {\n lastGroup = {\n messages: [],\n reason: groupCheck.reason || 'initial'\n };\n groups.push(lastGroup);\n\n // track when we last broke for time_elapsed\n if (groupCheck.reason === 'time_elapsed') {\n lastTimeElapsedDate = msg.created_on;\n }\n }\n\n lastGroup.messages.push(msgId);\n lastMsg = msg;\n }\n return groups;\n }\n\n private handleScroll(event: any) {\n const ele = event.target;\n const scrollableHeight = ele.scrollHeight - ele.clientHeight;\n\n if (scrollableHeight <= 0) {\n return;\n }\n\n // with column-reverse, scrollTop behavior depends on the browser\n // check if scrollTop is negative (some browsers) or positive (others)\n const absScrollTop = Math.abs(ele.scrollTop);\n\n // when scrolling up to older messages, absScrollTop increases\n // trigger when we're close to the maximum scroll (oldest messages)\n const shouldFetch = absScrollTop >= scrollableHeight - SCROLL_FETCH_BUFFER;\n\n this.hideTopScroll = absScrollTop >= scrollableHeight - 1;\n this.hideBottomScroll = absScrollTop <= 1;\n\n // hide notification when scrolled to bottom\n if (absScrollTop <= 10) {\n this.showNewMessageNotification = false;\n }\n\n if (shouldFetch) {\n this.fireCustomEvent(CustomEventType.ScrollThreshold);\n }\n }\n\n private scrollToBottom() {\n const scroll = this.shadowRoot.querySelector('.scroll');\n if (scroll) {\n scroll.scrollTop = 0;\n this.hideBottomScroll = true;\n this.showNewMessageNotification = false;\n }\n }\n\n private handleNewMessageClick() {\n this.scrollToBottom();\n }\n\n private getReasonLabel(reason: GroupReason): string {\n switch (reason) {\n case 'new_author':\n return '👤 Different author';\n case 'new_type':\n return '🔄 Message type changed';\n case 'time_elapsed':\n case 'initial':\n default:\n return '';\n }\n }\n\n private renderMessageGroup(\n group: MessageGroup,\n idx: number,\n lastShownTimestamp: Date | null\n ): { html: TemplateResult; timestamp: Date | null } {\n const today = new Date();\n const msgIds = group.messages;\n\n const mostRecentId = msgIds[msgIds.length - 1];\n const currentMsg = this.msgMap.get(mostRecentId);\n\n const incoming = this.agent\n ? currentMsg.type !== 'msg_received'\n : currentMsg.type === 'msg_received';\n\n const name = currentMsg._user?.name;\n\n const showAvatar =\n ((currentMsg.type === 'msg_received' ||\n currentMsg.type === 'msg_created') &&\n this.agent) ||\n !incoming;\n\n const isSystem = !currentMsg._user?.uuid;\n\n const reasonLabel = this.getReasonLabel(group.reason);\n const showReason = false; // reasonLabel && idx > 0;\n\n // determine if we should show a timestamp\n // use the first message in the group (oldest) for the timestamp\n const firstMsgId = msgIds[0];\n const firstMsg = this.msgMap.get(firstMsgId);\n\n // check if we should show a timestamp based on the last shown timestamp\n let showTimeForReason = false;\n let newLastShownTimestamp = lastShownTimestamp;\n\n if (idx > 0) {\n if (lastShownTimestamp) {\n const timeSinceLastShown = Math.abs(\n firstMsg.created_on.getTime() - lastShownTimestamp.getTime()\n );\n showTimeForReason = timeSinceLastShown >= BATCH_TIME_WINDOW;\n } else {\n // no previous timestamp, check against previous group\n showTimeForReason = group.reason === 'time_elapsed';\n }\n }\n\n let timeForReason = null;\n if (showTimeForReason) {\n newLastShownTimestamp = firstMsg.created_on;\n\n const isDifferentYear =\n today.getFullYear() !== firstMsg.created_on.getFullYear();\n const format = isDifferentYear\n ? VERBOSE_FORMAT_WITH_YEAR\n : today.getDate() !== firstMsg.created_on.getDate()\n ? VERBOSE_FORMAT\n : TIME_FORMAT;\n\n timeForReason = html`<div class=\"time time-elapsed\">\n ${firstMsg.created_on.toLocaleTimeString(undefined, format)}\n </div>`;\n }\n\n const resultHtml = html`\n <div class=\"block ${incoming ? 'incoming' : 'outgoing'}\">\n <div class=\"group-messages\" style=\"flex-grow:1\">\n ${repeat(\n msgIds,\n (msgId) => msgId,\n (msgId, index) => {\n const msg = this.msgMap.get(msgId);\n const msgEvent = msg as MsgEvent;\n const statusClass = (msg as any)._status\n ? (msg as any)._status.status\n : '';\n const hasError =\n msgEvent.msg?.unsendable_reason ||\n (msgEvent._status?.reason &&\n (statusClass === 'failed' || statusClass === 'errored'));\n const unsendableClass = hasError ? 'error' : '';\n const deletedClass = msgEvent._deleted ? 'deleted' : '';\n return html`<div\n class=\"row message ${statusClass} ${unsendableClass} ${deletedClass}\"\n >\n ${this.renderMessage(msg, index == 0 ? name : null)}\n </div>`;\n }\n )}\n </div>\n ${showAvatar\n ? html`<div class=\"avatar\" style=\"align-self:flex-end\">\n <temba-user\n uuid=${currentMsg._user?.uuid}\n name=${name}\n avatar=${currentMsg._user?.avatar}\n ?system=${isSystem}\n >\n </temba-user>\n </div>`\n : null}\n </div>\n ${showReason\n ? html`<div class=\"group-reason\">${reasonLabel}</div>`\n : null}\n ${timeForReason}\n `;\n\n return { html: resultHtml, timestamp: newLastShownTimestamp };\n }\n\n private renderMessage(event: ContactEvent, name = null): TemplateResult {\n if (event._rendered) {\n return html`<div class=\"event\">${event._rendered.html}</div>`;\n }\n\n const message = event as MsgEvent;\n const unsendableReason = message.msg?.unsendable_reason;\n const statusReason = message._status?.reason;\n const errorMessage = unsendableReason\n ? getUnsendableReasonMessage(unsendableReason)\n : statusReason\n ? getStatusReasonMessage(statusReason)\n : null;\n\n const logsURL =\n this.showMessageLogsAfter &&\n message.created_on >= this.showMessageLogsAfter &&\n message.msg.channel\n ? `/channels/channel/logs/${message.msg.channel.uuid}/msg/${event.uuid}/`\n : null;\n\n // handle deleted messages\n const isDeleted = message._deleted;\n const deletedByText = isDeleted\n ? message._deleted.by_contact\n ? 'contact'\n : message._deleted.user?.name || 'user'\n : null;\n\n // check if message has location attachment and text is just coordinates\n const hasLocationAttachment = message.msg.attachments?.some((att) =>\n att.startsWith('geo:')\n );\n const textIsCoordinates =\n hasLocationAttachment &&\n message.msg.text &&\n /^-?\\d+\\.?\\d*\\s*,\\s*-?\\d+\\.?\\d*$/.test(message.msg.text.trim());\n\n return html`\n <div class=\"bubble-wrap\">\n <div class=\"popup\" style=\"white-space: nowrap;\">\n ${errorMessage\n ? html`<div style=\"color: var(--color-error); margin-right: 1em;\">\n ${errorMessage}\n </div>`\n : null}\n <temba-date\n value=\"${message.created_on.toISOString()}\"\n display=\"relative\"\n ></temba-date>\n ${logsURL\n ? html`<a\n style=\"margin-left: 1em; color: var(--color-primary-dark);\"\n href=\"${logsURL}\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n ><temba-icon name=\"log\"></temba-icon\n ></a>`\n : null}\n\n <div class=\"arrow\">▼</div>\n </div>\n ${isDeleted\n ? html`<div class=\"bubble\">\n ${name ? html`<div class=\"name\">${name}</div>` : null}\n <div class=\"message-deleted\">\n Message deleted by ${deletedByText}\n </div>\n </div>`\n : message.msg.text && !textIsCoordinates\n ? html`<div class=\"bubble\">\n ${name ? html`<div class=\"name\">${name}</div>` : null}\n <div class=\"message-text\">${message.msg.text}</div>\n </div>`\n : null}\n\n <div class=\"attachments\">\n ${(message.msg.attachments || []).map(\n (attachment) =>\n html`<temba-thumbnail\n attachment=\"${attachment}\"\n ></temba-thumbnail>`\n )}\n </div>\n </div>\n `;\n }\n\n public reset() {\n this.msgMap.clear();\n this.messageGroups = [];\n this.hideBottomScroll = true;\n this.hideTopScroll = true;\n this.endOfHistory = false;\n this.oldestEventDate = null;\n }\n\n public setEndOfHistory(oldestDate: Date) {\n this.endOfHistory = true;\n this.oldestEventDate = oldestDate;\n }\n\n public render(): TemplateResult {\n return html` <div\n class=\"\n messages \n ${this.hideBottomScroll ? 'scroll-at-bottom' : ''}\n ${this.hideTopScroll ? 'scroll-at-top' : ''}\"\n >\n <div class=\"scroll\" @scroll=${this.handleScroll}>\n ${this.messageGroups\n ? (() => {\n let lastTimestamp: Date | null = null;\n // process from oldest to newest (high index to low index)\n // to establish logical time groupings going forward in time\n const results = [];\n for (let idx = this.messageGroups.length - 1; idx >= 0; idx--) {\n const msgGroup = this.messageGroups[idx];\n const result = this.renderMessageGroup(\n msgGroup,\n idx,\n lastTimestamp\n );\n lastTimestamp = result.timestamp;\n results.unshift(result.html); // add to front since we're going backwards\n }\n return results;\n })()\n : null}\n\n <temba-loading\n class=\"${!this.fetching ? 'hidden' : ''}\"\n ></temba-loading>\n\n ${this.endOfHistory && this.oldestEventDate\n ? html`<div class=\"time first\">\n ${this.oldestEventDate.toLocaleTimeString(\n undefined,\n VERBOSE_FORMAT\n )}\n </div>`\n : null}\n </div>\n ${!this.hasFooter\n ? html`<div\n class=\"new-message-notification ${this.showNewMessageNotification\n ? 'visible'\n : ''}\"\n @click=${this.handleNewMessageClick}\n >\n New Messages\n </div>`\n : null}\n <slot class=\"header\" name=\"header\"></slot>\n <slot class=\"footer\" name=\"footer\"></slot>\n </div>`;\n }\n}\n"]}
1
+ {"version":3,"file":"Chat.js","sourceRoot":"","sources":["../../../src/display/Chat.ts"],"names":[],"mappings":";AAAA,OAAO,EAAkB,IAAI,EAAoB,GAAG,EAAE,MAAM,KAAK,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACzC,MAAM,mBAAmB,GAAG,GAAG,CAAC,CAAC,kBAAkB;AACnD,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,MAAM,0BAA0B,GAAG,CAAC,MAAc,EAAU,EAAE;IAC5D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU;YACb,OAAO,sCAAsC,CAAC;QAChD,KAAK,iBAAiB;YACpB,OAAO,0BAA0B,CAAC;QACpC,KAAK,iBAAiB;YACpB,OAAO,0BAA0B,CAAC;QACpC,KAAK,kBAAkB;YACrB,OAAO,qBAAqB,CAAC;QAC/B,KAAK,eAAe;YAClB,OAAO,wBAAwB,CAAC;QAClC,KAAK,SAAS;YACZ,OAAO,uBAAuB,CAAC;QACjC;YACE,OAAO,wBAAwB,CAAC;IACpC,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,MAAc,EAAU,EAAE;IACxD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,aAAa;YAChB,OAAO,qBAAqB,CAAC;QAC/B,KAAK,SAAS;YACZ,OAAO,4BAA4B,CAAC;QACtC,KAAK,iBAAiB;YACpB,OAAO,qBAAqB,CAAC;QAC/B;YACE,OAAO,wBAAwB,CAAC;IACpC,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAN,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,gCAAiB,CAAA;IACjB,8BAAe,CAAA;IACf,oCAAqB,CAAA;IACrB,4BAAa,CAAA;AACf,CAAC,EALW,WAAW,KAAX,WAAW,QAKtB;AAgED,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAS,CAAC;AAClE,MAAM,cAAc,GAAG;IACrB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;CACX,CAAC;AACT,MAAM,wBAAwB,GAAG;IAC/B,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;CACX,CAAC;AAET,MAAM,OAAO,IAAK,SAAQ,YAAY;IAAtC;;QAqjBE,kBAAa,GAAmB,EAAE,CAAC;QAGnC,aAAQ,GAAG,KAAK,CAAC;QAGjB,kBAAa,GAAG,IAAI,CAAC;QAGrB,qBAAgB,GAAG,IAAI,CAAC;QAGxB,kBAAa,GAAG,cAAc,CAAC;QAG/B,UAAK,GAAG,KAAK,CAAC;QAGd,YAAO,GAAG,KAAK,CAAC;QAGhB,iBAAY,GAAG,KAAK,CAAC;QAGrB,oBAAe,GAAS,IAAI,CAAC;QAG7B,+BAA0B,GAAG,KAAK,CAAC;QAGnC,yBAAoB,GAAS,IAAI,CAAC;QAGlC,cAAS,GAAG,KAAK,CAAC;QAGlB,mBAAc,GAAG,IAAI,CAAC;QAEd,WAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;QACzC,kBAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;IAqhB1D,CAAC;IAhnCC,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+iBT,CAAC;IACJ,CAAC;IA4CM,YAAY,CACjB,OAA0D;QAE1D,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QAC5D,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,CAAC,SAAS,CAAC;IAClC,CAAC;IAEM,WAAW,CAChB,QAAwB,EACxB,YAAkB,IAAI,EACtB,MAAM,GAAG,KAAK;QAEd,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QAC3D,MAAM,CAAC,UAAU,CACf,GAAG,EAAE;YACH,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,gCAAgC;YAChC,MAAM,WAAW,GAAG,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,mFAAmF;gBACnF,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;oBAChE,MAAM,OAAO,GAAI,CAAS,CAAC,QAAQ,CAAC;oBACpC,IAAI,OAAO,EAAE,CAAC;wBACZ,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBACrC,CAAC;oBACD,SAAS;gBACX,CAAC;gBAED,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;oBACvB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO;YACT,CAAC;YAED,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;YACrD,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC;YAC9B,MAAM,gBAAgB,GAAG,GAAG,CAAC,YAAY,CAAC;YAC1C,MAAM,gBAAgB,GAAG,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;YAC7D,MAAM,cAAc,GAClB,gBAAgB,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;YAEvD,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;YAChD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAEnC,uFAAuF;YACvF,IAAI,MAAM,IAAI,cAAc,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvD,IAAI,CAAC,0BAA0B,GAAG,IAAI,CAAC;YACzC,CAAC;YAED,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;gBACrB,qFAAqF;gBACrF,oEAAoE;gBACpE,IAAI,MAAM,IAAI,cAAc,EAAE,CAAC;oBAC7B,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,GAAG,gBAAgB,CAAC;oBACvD,GAAG,CAAC,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;gBACvC,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC;gBAC1B,CAAC;gBAED,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;YACtD,CAAC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QACD,6EAA6E;QAC7E,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;YAC7B,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,CAC1C,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,GAAiB;QAClC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,aAAa,CAAC,GAAiB;QACpC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAEO,WAAW,CACjB,IAAkB,EAClB,IAAkB,EAClB,mBAA0B;;QAE1B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;QAED,gEAAgE;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC;QAC3E,MAAM,SAAS,GACb,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;QAEjE,oFAAoF;QACpF,MAAM,WAAW,GAAG,mBAAmB,IAAI,IAAI,CAAC,UAAU,CAAC;QAC3D,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;YAC3D,iBAAiB,EACjB,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAC7C,CAAC;QAED,sCAAsC;QACtC,IAAI,MAAM,IAAI,MAAM,IAAI,CAAA,MAAA,IAAI,CAAC,KAAK,0CAAE,IAAI,OAAK,MAAA,IAAI,CAAC,KAAK,0CAAE,IAAI,CAAA,EAAE,CAAC;YAC9D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QAC/C,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAEO,YAAY,CAAC,SAAyB,EAAE,MAAM,GAAG,KAAK;QAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS,CAAC,OAAO,EAAE,CAAC;QACtB,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,wDAAwD;YACxD,MAAM,KAAK,GACT,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAEjE,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrD,yDAAyD;gBACzD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBACrD,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;oBACpB,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAC5C,CAAC;qBAAM,CAAC;oBACN,oDAAoD;oBACpD,IAAI,MAAM,EAAE,CAAC;wBACX,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;oBAC5C,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;gBAC5C,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC;IAEO,aAAa,CAAC,MAAgB;QACpC,wCAAwC;QACxC,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,IAAI,SAAS,GAAiB,IAAI,CAAC;QACnC,IAAI,OAAO,GAAiB,IAAI,CAAC;QACjC,IAAI,mBAAmB,GAAS,IAAI,CAAC;QAErC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;YAEvE,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnC,SAAS,GAAG;oBACV,QAAQ,EAAE,EAAE;oBACZ,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,SAAS;iBACvC,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAEvB,4CAA4C;gBAC5C,IAAI,UAAU,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;oBACzC,mBAAmB,GAAG,GAAG,CAAC,UAAU,CAAC;gBACvC,CAAC;YACH,CAAC;YAED,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,OAAO,GAAG,GAAG,CAAC;QAChB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,YAAY,CAAC,KAAU;QAC7B,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;QACzB,MAAM,gBAAgB,GAAG,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;QAE7D,IAAI,gBAAgB,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,iEAAiE;QACjE,sEAAsE;QACtE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE7C,8DAA8D;QAC9D,mEAAmE;QACnE,MAAM,WAAW,GAAG,YAAY,IAAI,gBAAgB,GAAG,mBAAmB,CAAC;QAE3E,IAAI,CAAC,aAAa,GAAG,YAAY,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,gBAAgB,GAAG,YAAY,IAAI,CAAC,CAAC;QAE1C,4CAA4C;QAC5C,IAAI,YAAY,IAAI,EAAE,EAAE,CAAC;YACvB,IAAI,CAAC,0BAA0B,GAAG,KAAK,CAAC;QAC1C,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAEM,cAAc;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;YACrB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,IAAI,CAAC,0BAA0B,GAAG,KAAK,CAAC;QAC1C,CAAC;IACH,CAAC;IAEO,qBAAqB;QAC3B,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEO,cAAc,CAAC,MAAmB;QACxC,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,YAAY;gBACf,OAAO,qBAAqB,CAAC;YAC/B,KAAK,UAAU;gBACb,OAAO,yBAAyB,CAAC;YACnC,KAAK,cAAc,CAAC;YACpB,KAAK,SAAS,CAAC;YACf;gBACE,OAAO,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAEO,kBAAkB,CACxB,KAAmB,EACnB,GAAW,EACX,kBAA+B;;QAE/B,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC;QAE9B,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAEjD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK;YACzB,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,cAAc;YACpC,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,cAAc,CAAC;QAEvC,MAAM,IAAI,GAAG,MAAA,UAAU,CAAC,KAAK,0CAAE,IAAI,CAAC;QAEpC,MAAM,UAAU,GACd,IAAI,CAAC,OAAO;YACZ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,cAAc;gBACnC,UAAU,CAAC,IAAI,KAAK,aAAa,CAAC;gBAClC,IAAI,CAAC,KAAK,CAAC;gBACX,CAAC,QAAQ,CAAC,CAAC;QAEf,MAAM,QAAQ,GAAG,CAAC,CAAA,MAAA,UAAU,CAAC,KAAK,0CAAE,IAAI,CAAA,CAAC;QAEzC,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,0BAA0B;QAEpD,0CAA0C;QAC1C,gEAAgE;QAChE,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAE7C,wEAAwE;QACxE,IAAI,iBAAiB,GAAG,KAAK,CAAC;QAC9B,IAAI,qBAAqB,GAAG,kBAAkB,CAAC;QAE/C,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,IAAI,kBAAkB,EAAE,CAAC;gBACvB,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CACjC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,kBAAkB,CAAC,OAAO,EAAE,CAC7D,CAAC;gBACF,iBAAiB,GAAG,kBAAkB,IAAI,iBAAiB,CAAC;YAC9D,CAAC;iBAAM,CAAC;gBACN,sDAAsD;gBACtD,iBAAiB,GAAG,KAAK,CAAC,MAAM,KAAK,cAAc,CAAC;YACtD,CAAC;QACH,CAAC;QAED,IAAI,aAAa,GAAG,IAAI,CAAC;QACzB,IAAI,iBAAiB,EAAE,CAAC;YACtB,qBAAqB,GAAG,QAAQ,CAAC,UAAU,CAAC;YAE5C,MAAM,eAAe,GACnB,KAAK,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;YAC5D,MAAM,MAAM,GAAG,eAAe;gBAC5B,CAAC,CAAC,wBAAwB;gBAC1B,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE;oBACnD,CAAC,CAAC,cAAc;oBAChB,CAAC,CAAC,WAAW,CAAC;YAEhB,aAAa,GAAG,IAAI,CAAA;UAChB,QAAQ,CAAC,UAAU,CAAC,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC;aACtD,CAAC;QACV,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAA;2BACA,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;;YAEjD,MAAM,CACN,MAAM,EACN,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAChB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;;YACf,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnC,MAAM,QAAQ,GAAG,GAAe,CAAC;YACjC,MAAM,WAAW,GAAI,GAAW,CAAC,OAAO;gBACtC,CAAC,CAAE,GAAW,CAAC,OAAO,CAAC,MAAM;gBAC7B,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,QAAQ,GACZ,CAAA,MAAA,QAAQ,CAAC,GAAG,0CAAE,iBAAiB;gBAC/B,CAAC,CAAA,MAAA,QAAQ,CAAC,OAAO,0CAAE,MAAM;oBACvB,CAAC,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC;YAC7D,MAAM,eAAe,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,MAAM,WAAW,GAAG,KAAK,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,MAAM,UAAU,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,OAAO,IAAI,CAAA;qCACY,WAAW,IAAI,eAAe,IAAI,YAAY,IAAI,WAAW,IAAI,UAAU;;kBAE9F,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;qBAC9C,CAAC;QACV,CAAC,CACF;;UAED,UAAU;YACV,CAAC,CAAC,IAAI,CAAA;;uBAEO,MAAA,UAAU,CAAC,KAAK,0CAAE,IAAI;uBACtB,IAAI;yBACF,MAAA,UAAU,CAAC,KAAK,0CAAE,MAAM;0BACvB,QAAQ;;;mBAGf;YACT,CAAC,CAAC,IAAI;;QAER,UAAU;YACV,CAAC,CAAC,IAAI,CAAA,6BAA6B,WAAW,QAAQ;YACtD,CAAC,CAAC,IAAI;QACN,aAAa;KAChB,CAAC;QAEF,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAAC;IAChE,CAAC;IAEO,aAAa,CAAC,KAAmB,EAAE,IAAI,GAAG,IAAI;;QACpD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO,IAAI,CAAA,sBAAsB,KAAK,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC;QAChE,CAAC;QAED,MAAM,OAAO,GAAG,KAAiB,CAAC;QAElC,qDAAqD;QACrD,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YACjB,OAAO,IAAI,CAAA,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,gBAAgB,GAAG,MAAA,OAAO,CAAC,GAAG,0CAAE,iBAAiB,CAAC;QACxD,MAAM,YAAY,GAAG,MAAA,OAAO,CAAC,OAAO,0CAAE,MAAM,CAAC;QAC7C,MAAM,YAAY,GAAG,gBAAgB;YACnC,CAAC,CAAC,0BAA0B,CAAC,gBAAgB,CAAC;YAC9C,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,sBAAsB,CAAC,YAAY,CAAC;gBACtC,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,OAAO,GACX,IAAI,CAAC,oBAAoB;YACzB,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,oBAAoB;YAC/C,OAAO,CAAC,GAAG,CAAC,OAAO;YACjB,CAAC,CAAC,0BAA0B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,QAAQ,KAAK,CAAC,IAAI,GAAG;YACzE,CAAC,CAAC,IAAI,CAAC;QAEX,0BAA0B;QAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QACnC,MAAM,aAAa,GAAG,SAAS;YAC7B,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAC3B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,CAAA,MAAA,OAAO,CAAC,QAAQ,CAAC,IAAI,0CAAE,IAAI,KAAI,MAAM;YACzC,CAAC,CAAC,IAAI,CAAC;QAET,wEAAwE;QACxE,MAAM,qBAAqB,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,WAAW,0CAAE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAClE,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CACvB,CAAC;QACF,MAAM,iBAAiB,GACrB,qBAAqB;YACrB,OAAO,CAAC,GAAG,CAAC,IAAI;YAChB,iCAAiC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAElE,OAAO,IAAI,CAAA;;UAEL,IAAI,CAAC,cAAc;YACnB,CAAC,CAAC,IAAI,CAAA;gBACA,YAAY;gBACZ,CAAC,CAAC,IAAI,CAAA;;;sBAGA,YAAY;yBACT;gBACT,CAAC,CAAC,IAAI;;yBAEG,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE;;;gBAGzC,OAAO;gBACP,CAAC,CAAC,IAAI,CAAA;;4BAEM,OAAO;;;;wBAIX;gBACR,CAAC,CAAC,IAAI;;;mBAGH;YACT,CAAC,CAAC,IAAI;UACN,SAAS;YACT,CAAC,CAAC,IAAI,CAAA;gBACA,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA,qBAAqB,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI;;qCAE9B,aAAa;;mBAE/B;YACT,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,iBAAiB;gBACxC,CAAC,CAAC,IAAI,CAAA;gBACA,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA,qBAAqB,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI;0CACzB,OAAO,CAAC,GAAG,CAAC,IAAI;mBACvC;gBACT,CAAC,CAAC,IAAI;;;YAGJ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CACnC,CAAC,UAAU,EAAE,EAAE,CACb,IAAI,CAAA;8BACY,UAAU;kCACN,CACvB;;;KAGN,CAAC;IACJ,CAAC;IAEM,KAAK;QACV,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;IAC9B,CAAC;IAEM,eAAe,CAAC,UAAgB;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC;IACpC,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAA;;;UAGL,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE;UAC/C,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;;oCAEf,IAAI,CAAC,YAAY;UAC3C,IAAI,CAAC,aAAa;YAClB,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,IAAI,aAAa,GAAgB,IAAI,CAAC;gBACtC,0DAA0D;gBAC1D,4DAA4D;gBAC5D,MAAM,OAAO,GAAG,EAAE,CAAC;gBACnB,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;oBAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;oBACzC,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CACpC,QAAQ,EACR,GAAG,EACH,aAAa,CACd,CAAC;oBACF,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC;oBACjC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,2CAA2C;gBAC3E,CAAC;gBACD,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,EAAE;YACN,CAAC,CAAC,IAAI;;;mBAGG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;;;UAGvC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,eAAe;YACzC,CAAC,CAAC,IAAI,CAAA;gBACA,IAAI,CAAC,eAAe,CAAC,kBAAkB,CACvC,SAAS,EACT,cAAc,CACf;mBACI;YACT,CAAC,CAAC,IAAI;;QAER,CAAC,IAAI,CAAC,SAAS;YACf,CAAC,CAAC,IAAI,CAAA;8CACgC,IAAI,CAAC,0BAA0B;gBAC/D,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,EAAE;qBACG,IAAI,CAAC,qBAAqB;;;iBAG9B;YACT,CAAC,CAAC,IAAI;;;WAGH,CAAC;IACV,CAAC;CACF;AA5jBC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;2CACS;AAGnC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;sCACX;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;2CACzB;AAGrB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;8CACtB;AAGxB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;2CACjB;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;mCACd;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;qCACZ;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;0CACzB;AAGrB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;6CAChB;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;wDACX;AAGnC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;kDACO;AAGlC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;uCACV;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CACN","sourcesContent":["import { TemplateResult, html, PropertyValueMap, css } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { DEFAULT_AVATAR } from '../webchat/assets';\n\nconst BATCH_TIME_WINDOW = 60 * 60 * 1000;\nconst SCROLL_FETCH_BUFFER = 200; // pixels from top\nconst MIN_FETCH_TIME = 250;\n\nconst getUnsendableReasonMessage = (reason: string): string => {\n switch (reason) {\n case 'no_route':\n return 'No channel available to send message';\n case 'contact_blocked':\n return 'Contact has been blocked';\n case 'contact_stopped':\n return 'Contact has been stopped';\n case 'contact_archived':\n return 'Contact is archived';\n case 'org_suspended':\n return 'Workspace is suspended';\n case 'looping':\n return 'Message loop detected';\n default:\n return 'Unable to send message';\n }\n};\n\nconst getStatusReasonMessage = (reason: string): string => {\n switch (reason) {\n case 'error_limit':\n return 'Error limit reached';\n case 'too_old':\n return 'Message is too old to send';\n case 'channel_removed':\n return 'Channel was removed';\n default:\n return 'Message failed to send';\n }\n};\n\nexport enum MessageType {\n Inline = 'inline',\n Error = 'error',\n Collapse = 'collapse',\n Note = 'note'\n}\n\nexport type GroupReason =\n | 'time_elapsed'\n | 'new_author'\n | 'new_type'\n | 'initial';\n\nexport interface MessageGroup {\n messages: string[];\n reason: GroupReason;\n}\n\nexport interface ObjectReference {\n uuid: string;\n name: string;\n}\n\ninterface User extends ObjectReference {\n avatar?: string;\n email: string;\n}\n\nexport interface Msg {\n text: string;\n channel: ObjectReference;\n quick_replies: string[];\n urn: string;\n direction: string;\n type: string;\n attachments: string[];\n unsendable_reason?:\n | 'no_route'\n | 'contact_blocked'\n | 'contact_stopped'\n | 'contact_archived'\n | 'org_suspended'\n | 'looping';\n}\n\nexport interface ContactEvent {\n uuid?: string;\n type: string;\n created_on: Date;\n _user?: User;\n _rendered?: { html: TemplateResult; type: MessageType };\n}\n\nexport interface MsgEvent extends ContactEvent {\n msg: Msg;\n optin?: ObjectReference;\n _status?: {\n created_on: string;\n status: 'wired' | 'sent' | 'delivered' | 'read' | 'errored' | 'failed';\n reason: 'error_limit' | 'too_old' | 'channel_removed';\n };\n _deleted?: {\n created_on: string;\n by_contact: boolean;\n user?: { name: string; uuid: string };\n };\n _logs_url?: string;\n}\n\nconst TIME_FORMAT = { hour: 'numeric', minute: '2-digit' } as any;\nconst VERBOSE_FORMAT = {\n weekday: undefined,\n year: undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n} as any;\nconst VERBOSE_FORMAT_WITH_YEAR = {\n weekday: undefined,\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit'\n} as any;\n\nexport class Chat extends RapidElement {\n static get styles() {\n return css`\n :host {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n position: relative;\n z-index: 1;\n }\n\n slot[name='header'] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n slot[name='footer'] {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n display: block;\n }\n\n .block {\n margin-bottom: 1em;\n display: flex;\n flex-direction: row;\n }\n\n .block.outgoing {\n flex-direction: row-reverse;\n }\n\n .block.collapse {\n margin: 0;\n align-items: center;\n display: flex;\n flex-direction: column;\n margin-bottom: 0.5em;\n }\n\n .block.collapse .messsage {\n transform: scaleY(0);\n margin: 0;\n padding: 0;\n line-height: 0;\n }\n\n .time {\n text-align: center;\n font-size: 0.8em;\n color: #999;\n margin-bottom: 2em;\n margin-top: 1em;\n border-top: 1px solid #e9e9e9;\n padding: 1em;\n margin-left: 10%;\n margin-right: 10%;\n }\n\n .time.first {\n border-top: none;\n margin-top: 0;\n border-bottom: 1px solid #e9e9e9;\n margin-bottom: 2em;\n }\n\n .first .time {\n margin-top: 0;\n border-top: none;\n padding-top: 0;\n }\n\n .group-reason {\n text-align: center;\n font-size: 0.75em;\n color: #999;\n margin-bottom: 1em;\n margin-top: 0.5em;\n padding: 0.5em 1em;\n font-style: italic;\n }\n\n .row {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n margin-bottom: 8px;\n }\n\n .row.is-event {\n margin-bottom: 2px;\n margin-left: 0px !important;\n margin-right: 4px !important;\n }\n\n .input-panel {\n padding: 1em;\n background: #fff;\n }\n\n temba-user {\n margin-right: 0.6em;\n margin-left: 0.6em;\n width: 2em;\n align-self: flex-end;\n }\n\n .toggle {\n flex-shrink: 0;\n width: 4em;\n height: 4em;\n overflow: hidden;\n border-radius: 100%;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.1);\n cursor: pointer;\n transition: box-shadow var(--toggle-speed, 200ms) ease-out;\n position: absolute;\n bottom: 1em;\n right: 1em;\n }\n\n .toggle:hover {\n box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1em 0.7em,\n rgba(0, 0, 0, 0.4) 0px 1px 2px 0px,\n inset 0 0 0 0.25em rgba(0, 0, 0, 0.2);\n }\n\n .incoming .row {\n flex-direction: row-reverse;\n margin-left: 1em;\n margin-right: 1em;\n }\n\n .bubble {\n padding: 10px 14px;\n background: var(--color-chat-in, #e5e5ea);\n border-radius: 18px;\n border: var(--chat-border-in, none);\n }\n\n .bubble .name {\n font-size: 0.95em;\n font-weight: 400;\n color: rgba(0, 0, 0, 0.4);\n margin-bottom: 0.25em;\n }\n\n .outgoing .latest .bubble {\n border-bottom-left-radius: 4px;\n }\n\n .incoming .bubble-wrap {\n align-items: flex-end;\n }\n\n .incoming .bubble {\n background: var(--color-chat-out, #007aff);\n border: var(--chat-border-out, none);\n color: white;\n }\n\n .incoming .latest .bubble {\n border-bottom-right-radius: 4px;\n }\n\n .incoming .bubble .name {\n color: rgba(255, 255, 255, 0.7);\n }\n\n .note .bubble {\n background: #fffac3;\n color: rgba(0, 0, 0, 0.7);\n }\n\n .note .bubble .name {\n color: rgba(0, 0, 0, 0.5);\n }\n\n .warning .bubble {\n background: #fef3c7;\n color: rgba(125, 87, 18, 0.8);\n border: none;\n }\n\n .warning .bubble .name {\n color: rgba(125, 87, 18, 0.6);\n }\n\n .failed .bubble,\n .error .bubble {\n border: none;\n background: #fee3e3;\n color: #c01829;\n }\n\n .error .bubble .name,\n .failed .bubble .name {\n color: rgba(192, 24, 41, 0.6);\n }\n\n .deleted .bubble {\n background: #fff;\n color: #999;\n border: 1px solid #e0e0e0;\n }\n\n .deleted .bubble .name {\n color: #aaa;\n }\n\n .message-text {\n white-space: pre-wrap;\n margin-bottom: 0;\n line-height: 1.2;\n word-break: break-word;\n font-size: 13px;\n }\n\n .message-deleted {\n font-style: italic;\n margin-bottom: 0;\n line-height: 1.2;\n font-size: 13px;\n }\n\n .quick-replies {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 6px;\n padding: 8px 0;\n margin: 0 auto;\n max-width: 90%;\n }\n\n .quick-reply-btn {\n padding: 4px 8px;\n border-radius: 18px;\n border: 1px solid var(--color-chat-out, #007aff);\n background: white;\n color: var(--color-chat-out, #007aff);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .quick-reply-btn:hover:not(:disabled) {\n background: var(--color-chat-out, #007aff);\n color: white;\n }\n\n .quick-reply-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .chat {\n width: 28rem;\n border-radius: var(--curvature);\n overflow: hidden;\n box-shadow: rgba(0, 0, 0, 0.1) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px, rgba(0, 0, 0, 0.1) 5em 5em 5em 5em;\n position: absolute;\n bottom: 3em;\n right: 1em;\n transition: all var(--toggle-speed, 200ms) ease-out;\n transform: scale(0.9);\n pointer-events: none;\n opacity: 0;\n }\n\n .chat.open {\n bottom: 6em;\n opacity: 1;\n transform: scale(1);\n pointer-events: initial;\n }\n\n .messages {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n }\n\n .scroll {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overflow-scrolling: touch;\n padding: var(--chat-top-padding, 1em) 1em\n var(--chat-bottom-padding, 2.5em) 1em;\n display: flex;\n flex-direction: column-reverse;\n }\n\n :host(.phone-screen) .scroll {\n scrollbar-width: none;\n -ms-overflow-style: none;\n }\n\n :host(.phone-screen) .scroll::-webkit-scrollbar {\n display: none;\n }\n\n .messages:before {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 0,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center top;\n height: 10px;\n display: block;\n position: absolute;\n width: 100%;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .messages:after {\n content: '';\n background: radial-gradient(\n farthest-side at 50% 100%,\n rgba(0, 0, 0, 0.2),\n rgba(0, 0, 0, 0)\n )\n center bottom;\n height: 10px;\n display: block;\n position: absolute;\n bottom: 0;\n margin-top: -10px;\n width: 100%;\n margin-right: 5em;\n transition: opacity var(--toggle-speed, 200ms) ease-out;\n z-index: 1;\n }\n\n .bubble-wrap {\n position: relative;\n max-width: 70%;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n }\n\n .scroll-at-top.messages:before {\n opacity: 0;\n }\n\n .scroll-at-bottom.messages:after {\n opacity: 0;\n }\n\n .input {\n border: none;\n flex-grow: 1;\n color: #333;\n font-size: 1em;\n }\n\n .input:focus {\n outline: none;\n }\n\n input::placeholder {\n opacity: 0.3;\n }\n\n .input.inactive {\n // pointer-events: none;\n // opacity: 0.3;\n }\n\n .active {\n }\n\n .send-icon {\n color: #eee;\n pointer-events: none;\n transform: rotate(-45deg);\n transition: transform 0.2s ease-out;\n }\n\n .pending .send-icon {\n color: var(--color-primary-dark);\n pointer-events: initial;\n transform: rotate(0deg);\n }\n\n .notice {\n padding: 1em;\n background: #f8f8f8;\n color: #666;\n text-align: center;\n cursor: pointer;\n }\n\n .connecting .notice {\n display: flex;\n justify-content: center;\n }\n\n .connecting .notice temba-icon {\n margin-left: 0.5em;\n }\n\n .reconnect {\n color: var(--color-primary-dark);\n text-decoration: underline;\n font-size: 0.9em;\n }\n\n .input:disabled {\n background: transparent !important;\n }\n\n temba-loading {\n justify-content: center;\n margin: 0.5em auto;\n margin-bottom: 2em;\n }\n\n temba-loading.hidden {\n display: none;\n }\n\n .inline {\n }\n\n .event {\n flex-grow: 1;\n align-self: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n font-size: 11px;\n color: #8e8e93;\n }\n\n .event p {\n margin: 0;\n padding: 0;\n }\n\n .collapse {\n }\n\n a {\n color: var(--color-primary-dark);\n }\n\n .attachments {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n align-self: flex-start;\n }\n\n .incoming .attachments {\n align-self: flex-end;\n }\n\n temba-thumbnail {\n margin: 0.4em;\n border-radius: var(--curvature);\n }\n\n .failed temba-thumbnail,\n .error temba-thumbnail {\n --thumb-background: #ffe6e6;\n --thumb-border: var(--color-error);\n border: 1px solid var(--color-error);\n color: #ad4747a8;\n }\n\n .outgoing .popup {\n justify-content: left;\n }\n\n .incoming .popup {\n justify-content: right;\n }\n\n .popup {\n display: flex;\n position: absolute;\n background: #fff;\n margin: 0;\n padding: 0.5em 1em;\n border-radius: var(--curvature);\n box-shadow: rgba(0, 0, 0, 0.05) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.2) 0px 1px 2px 0px;\n border: 1px solid #f3f3f3;\n opacity: 0;\n z-index: 2;\n }\n\n .popup .arrow {\n z-index: 1;\n text-shadow: 0px 3px 3px rgba(0, 0, 0, 0.1);\n position: absolute;\n justify-content: center;\n text-align: center;\n font-size: 1.3em;\n transform: translateY(0.7em) scale(1);\n color: #fff;\n bottom: 0;\n }\n\n .bubble-wrap:hover .popup {\n opacity: 1;\n transition-delay: 1s;\n top: -35px;\n }\n\n .new-message-notification {\n position: absolute;\n bottom: 1em;\n left: 50%;\n transform: translateX(-50%) translateY(100px);\n background: var(--color-primary-dark, #3c92dd);\n color: white;\n padding: 0.75em 1.5em;\n border-radius: var(--curvature);\n box-shadow: rgba(0, 0, 0, 0.2) 0px 3px 7px 0px,\n rgba(0, 0, 0, 0.3) 0px 1px 2px 0px;\n cursor: pointer;\n opacity: 0;\n transition: all 0.3s ease-out;\n z-index: 100;\n font-weight: 500;\n pointer-events: none;\n }\n\n .new-message-notification.visible {\n transform: translateX(-50%) translateY(0);\n opacity: 1;\n pointer-events: auto;\n }\n\n .new-message-notification:hover {\n background: var(--color-primary-darker, #2b7ac4);\n box-shadow: rgba(0, 0, 0, 0.3) 0px 4px 10px 0px,\n rgba(0, 0, 0, 0.4) 0px 2px 4px 0px;\n }\n `;\n }\n\n @property({ type: Array })\n messageGroups: MessageGroup[] = [];\n\n @property({ type: Boolean })\n fetching = false;\n\n @property({ type: Boolean, attribute: false })\n hideTopScroll = true;\n\n @property({ type: Boolean, attribute: false })\n hideBottomScroll = true;\n\n @property({ type: String, attribute: 'avatar' })\n defaultAvatar = DEFAULT_AVATAR;\n\n @property({ type: Boolean })\n agent = false;\n\n @property({ type: Boolean })\n avatars = false;\n\n @property({ type: Boolean, attribute: false })\n endOfHistory = false;\n\n @property({ type: Object, attribute: false })\n oldestEventDate: Date = null;\n\n @property({ type: Boolean, attribute: false })\n showNewMessageNotification = false;\n\n @property({ type: Object })\n showMessageLogsAfter: Date = null;\n\n @property({ type: Boolean })\n hasFooter = false;\n\n @property({ type: Boolean })\n showTimestamps = true;\n\n private msgMap = new Map<string, ContactEvent>();\n private metadataCache = new Map<string, ContactEvent>();\n\n public firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n const scroll = this.shadowRoot.querySelector('.scroll');\n const hasScroll = scroll.scrollHeight > scroll.clientHeight;\n this.hideBottomScroll = true;\n this.hideTopScroll = !hasScroll;\n }\n\n public addMessages(\n messages: ContactEvent[],\n startTime: Date = null,\n append = false\n ) {\n if (!startTime) {\n startTime = new Date();\n }\n\n const elapsed = new Date().getTime() - startTime.getTime();\n window.setTimeout(\n () => {\n this.fetching = false;\n // first add messages to the map\n const newMessages = [];\n for (const m of messages) {\n // filter out metadata events - they aren't rendered but cached for later reference\n if (m.type === 'msg_deleted' || m.type === 'msg_status_changed') {\n const msgUuid = (m as any).msg_uuid;\n if (msgUuid) {\n this.metadataCache.set(msgUuid, m);\n }\n continue;\n }\n\n if (this.addMessage(m)) {\n newMessages.push(m.uuid);\n }\n }\n\n if (newMessages.length === 0) {\n return;\n }\n\n const ele = this.shadowRoot.querySelector('.scroll');\n const prevTop = ele.scrollTop;\n const prevScrollHeight = ele.scrollHeight;\n const scrollableHeight = ele.scrollHeight - ele.clientHeight;\n const isScrolledAway =\n scrollableHeight > 0 && Math.abs(ele.scrollTop) > 50;\n\n const grouped = this.groupMessages(newMessages);\n this.insertGroups(grouped, append);\n\n // show notification if new messages are appended and user is scrolled away from bottom\n if (append && isScrolledAway && newMessages.length > 0) {\n this.showNewMessageNotification = true;\n }\n\n window.setTimeout(() => {\n // when appending (new messages at bottom), adjust scroll to maintain visible content\n // with column-reverse, new content at bottom increases scrollHeight\n if (append && isScrolledAway) {\n const heightDiff = ele.scrollHeight - prevScrollHeight;\n ele.scrollTop = prevTop - heightDiff;\n } else {\n ele.scrollTop = prevTop;\n }\n\n this.fireCustomEvent(CustomEventType.FetchComplete);\n }, 100);\n },\n // if it's the first load don't wait, otherwise wait a minimum amount of time\n this.messageGroups.length === 0\n ? 0\n : Math.max(0, MIN_FETCH_TIME - elapsed)\n );\n }\n\n private addMessage(msg: ContactEvent): boolean {\n const isNew = !this.messageExists(msg);\n this.msgMap.set(msg.uuid, msg);\n return isNew;\n }\n\n public messageExists(msg: ContactEvent): boolean {\n return this.msgMap.has(msg.uuid);\n }\n\n private isSameGroup(\n msg1: ContactEvent,\n msg2: ContactEvent,\n lastTimeElapsedDate?: Date\n ): { same: boolean; reason?: GroupReason } {\n if (!msg1 || !msg2) {\n return { same: true };\n }\n\n // for type equivalence, treat all non-message types as the same\n const isMsg1 = msg1.type === 'msg_created' || msg1.type === 'msg_received';\n const isMsg2 = msg2.type === 'msg_created' || msg2.type === 'msg_received';\n const typeMatch =\n isMsg1 && isMsg2 ? msg1.type === msg2.type : isMsg1 === isMsg2;\n\n // check time first - if BATCH_TIME_WINDOW has passed since last time_elapsed reason\n const timeToCheck = lastTimeElapsedDate || msg1.created_on;\n if (\n Math.abs(msg2.created_on.getTime() - timeToCheck.getTime()) >=\n BATCH_TIME_WINDOW\n ) {\n return { same: false, reason: 'time_elapsed' };\n }\n\n if (!typeMatch) {\n return { same: false, reason: 'new_type' };\n }\n\n // only check author for message types\n if (isMsg1 && isMsg2 && msg1._user?.name !== msg2._user?.name) {\n return { same: false, reason: 'new_author' };\n }\n\n return { same: true };\n }\n\n private insertGroups(newGroups: MessageGroup[], append = false) {\n if (!append) {\n newGroups.reverse();\n }\n\n for (const newGroup of newGroups) {\n // see if our new group belongs to the most recent group\n const group =\n this.messageGroups[append ? 0 : this.messageGroups.length - 1];\n\n if (group) {\n const lastMsgId = group.messages[group.messages.length - 1];\n const lastMsg = this.msgMap.get(lastMsgId);\n const newMsg = this.msgMap.get(newGroup.messages[0]);\n // if our message belongs to the previous group, in we go\n const groupCheck = this.isSameGroup(lastMsg, newMsg);\n if (groupCheck.same) {\n group.messages.push(...newGroup.messages);\n } else {\n // otherwise, just add our entire group as a new one\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n } else {\n if (append) {\n this.messageGroups.splice(0, 0, newGroup);\n } else {\n this.messageGroups.push(newGroup);\n }\n }\n }\n\n this.requestUpdate('messageGroups');\n }\n\n private groupMessages(msgIds: string[]): MessageGroup[] {\n // group our messages by origin and user\n const groups: MessageGroup[] = [];\n let lastGroup: MessageGroup = null;\n let lastMsg: ContactEvent = null;\n let lastTimeElapsedDate: Date = null;\n\n for (const msgId of msgIds) {\n const msg = this.msgMap.get(msgId);\n const groupCheck = this.isSameGroup(msg, lastMsg, lastTimeElapsedDate);\n\n if (!groupCheck.same || !lastGroup) {\n lastGroup = {\n messages: [],\n reason: groupCheck.reason || 'initial'\n };\n groups.push(lastGroup);\n\n // track when we last broke for time_elapsed\n if (groupCheck.reason === 'time_elapsed') {\n lastTimeElapsedDate = msg.created_on;\n }\n }\n\n lastGroup.messages.push(msgId);\n lastMsg = msg;\n }\n return groups;\n }\n\n private handleScroll(event: any) {\n const ele = event.target;\n const scrollableHeight = ele.scrollHeight - ele.clientHeight;\n\n if (scrollableHeight <= 0) {\n return;\n }\n\n // with column-reverse, scrollTop behavior depends on the browser\n // check if scrollTop is negative (some browsers) or positive (others)\n const absScrollTop = Math.abs(ele.scrollTop);\n\n // when scrolling up to older messages, absScrollTop increases\n // trigger when we're close to the maximum scroll (oldest messages)\n const shouldFetch = absScrollTop >= scrollableHeight - SCROLL_FETCH_BUFFER;\n\n this.hideTopScroll = absScrollTop >= scrollableHeight - 1;\n this.hideBottomScroll = absScrollTop <= 1;\n\n // hide notification when scrolled to bottom\n if (absScrollTop <= 10) {\n this.showNewMessageNotification = false;\n }\n\n if (shouldFetch) {\n this.fireCustomEvent(CustomEventType.ScrollThreshold);\n }\n }\n\n public scrollToBottom() {\n const scroll = this.shadowRoot.querySelector('.scroll');\n if (scroll) {\n scroll.scrollTop = 0;\n this.hideBottomScroll = true;\n this.showNewMessageNotification = false;\n }\n }\n\n private handleNewMessageClick() {\n this.scrollToBottom();\n }\n\n private getReasonLabel(reason: GroupReason): string {\n switch (reason) {\n case 'new_author':\n return '👤 Different author';\n case 'new_type':\n return '🔄 Message type changed';\n case 'time_elapsed':\n case 'initial':\n default:\n return '';\n }\n }\n\n private renderMessageGroup(\n group: MessageGroup,\n idx: number,\n lastShownTimestamp: Date | null\n ): { html: TemplateResult; timestamp: Date | null } {\n const today = new Date();\n const msgIds = group.messages;\n\n const mostRecentId = msgIds[msgIds.length - 1];\n const currentMsg = this.msgMap.get(mostRecentId);\n\n const incoming = this.agent\n ? currentMsg.type !== 'msg_received'\n : currentMsg.type === 'msg_received';\n\n const name = currentMsg._user?.name;\n\n const showAvatar =\n this.avatars &&\n (((currentMsg.type === 'msg_received' ||\n currentMsg.type === 'msg_created') &&\n this.agent) ||\n !incoming);\n\n const isSystem = !currentMsg._user?.uuid;\n\n const reasonLabel = this.getReasonLabel(group.reason);\n const showReason = false; // reasonLabel && idx > 0;\n\n // determine if we should show a timestamp\n // use the first message in the group (oldest) for the timestamp\n const firstMsgId = msgIds[0];\n const firstMsg = this.msgMap.get(firstMsgId);\n\n // check if we should show a timestamp based on the last shown timestamp\n let showTimeForReason = false;\n let newLastShownTimestamp = lastShownTimestamp;\n\n if (idx > 0) {\n if (lastShownTimestamp) {\n const timeSinceLastShown = Math.abs(\n firstMsg.created_on.getTime() - lastShownTimestamp.getTime()\n );\n showTimeForReason = timeSinceLastShown >= BATCH_TIME_WINDOW;\n } else {\n // no previous timestamp, check against previous group\n showTimeForReason = group.reason === 'time_elapsed';\n }\n }\n\n let timeForReason = null;\n if (showTimeForReason) {\n newLastShownTimestamp = firstMsg.created_on;\n\n const isDifferentYear =\n today.getFullYear() !== firstMsg.created_on.getFullYear();\n const format = isDifferentYear\n ? VERBOSE_FORMAT_WITH_YEAR\n : today.getDate() !== firstMsg.created_on.getDate()\n ? VERBOSE_FORMAT\n : TIME_FORMAT;\n\n timeForReason = html`<div class=\"time time-elapsed\">\n ${firstMsg.created_on.toLocaleTimeString(undefined, format)}\n </div>`;\n }\n\n const resultHtml = html`\n <div class=\"block ${incoming ? 'incoming' : 'outgoing'}\">\n <div class=\"group-messages\" style=\"flex-grow:1\">\n ${repeat(\n msgIds,\n (msgId) => msgId,\n (msgId, index) => {\n const msg = this.msgMap.get(msgId);\n const msgEvent = msg as MsgEvent;\n const statusClass = (msg as any)._status\n ? (msg as any)._status.status\n : '';\n const hasError =\n msgEvent.msg?.unsendable_reason ||\n (msgEvent._status?.reason &&\n (statusClass === 'failed' || statusClass === 'errored'));\n const unsendableClass = hasError ? 'error' : '';\n const deletedClass = msgEvent._deleted ? 'deleted' : '';\n const latestClass = index === msgIds.length - 1 ? 'latest' : '';\n const eventClass = msg._rendered ? 'is-event' : '';\n return html`<div\n class=\"row message ${statusClass} ${unsendableClass} ${deletedClass} ${latestClass} ${eventClass}\"\n >\n ${this.renderMessage(msg, index == 0 ? name : null)}\n </div>`;\n }\n )}\n </div>\n ${showAvatar\n ? html`<div class=\"avatar\" style=\"align-self:flex-end\">\n <temba-user\n uuid=${currentMsg._user?.uuid}\n name=${name}\n avatar=${currentMsg._user?.avatar}\n ?system=${isSystem}\n >\n </temba-user>\n </div>`\n : null}\n </div>\n ${showReason\n ? html`<div class=\"group-reason\">${reasonLabel}</div>`\n : null}\n ${timeForReason}\n `;\n\n return { html: resultHtml, timestamp: newLastShownTimestamp };\n }\n\n private renderMessage(event: ContactEvent, name = null): TemplateResult {\n if (event._rendered) {\n return html`<div class=\"event\">${event._rendered.html}</div>`;\n }\n\n const message = event as MsgEvent;\n\n // safety check: if msg doesn't exist, return nothing\n if (!message.msg) {\n return html``;\n }\n\n const unsendableReason = message.msg?.unsendable_reason;\n const statusReason = message._status?.reason;\n const errorMessage = unsendableReason\n ? getUnsendableReasonMessage(unsendableReason)\n : statusReason\n ? getStatusReasonMessage(statusReason)\n : null;\n\n const logsURL =\n this.showMessageLogsAfter &&\n message.created_on >= this.showMessageLogsAfter &&\n message.msg.channel\n ? `/channels/channel/logs/${message.msg.channel.uuid}/msg/${event.uuid}/`\n : null;\n\n // handle deleted messages\n const isDeleted = message._deleted;\n const deletedByText = isDeleted\n ? message._deleted.by_contact\n ? 'contact'\n : message._deleted.user?.name || 'user'\n : null;\n\n // check if message has location attachment and text is just coordinates\n const hasLocationAttachment = message.msg.attachments?.some((att) =>\n att.startsWith('geo:')\n );\n const textIsCoordinates =\n hasLocationAttachment &&\n message.msg.text &&\n /^-?\\d+\\.?\\d*\\s*,\\s*-?\\d+\\.?\\d*$/.test(message.msg.text.trim());\n\n return html`\n <div class=\"bubble-wrap\">\n ${this.showTimestamps\n ? html`<div class=\"popup\" style=\"white-space: nowrap;\">\n ${errorMessage\n ? html`<div\n style=\"color: var(--color-error); margin-right: 1em;\"\n >\n ${errorMessage}\n </div>`\n : null}\n <temba-date\n value=\"${message.created_on.toISOString()}\"\n display=\"relative\"\n ></temba-date>\n ${logsURL\n ? html`<a\n style=\"margin-left: 1em; color: var(--color-primary-dark);\"\n href=\"${logsURL}\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n ><temba-icon name=\"log\"></temba-icon\n ></a>`\n : null}\n\n <div class=\"arrow\">▼</div>\n </div>`\n : null}\n ${isDeleted\n ? html`<div class=\"bubble\">\n ${name ? html`<div class=\"name\">${name}</div>` : null}\n <div class=\"message-deleted\">\n Message deleted by ${deletedByText}\n </div>\n </div>`\n : message.msg.text && !textIsCoordinates\n ? html`<div class=\"bubble\">\n ${name ? html`<div class=\"name\">${name}</div>` : null}\n <div class=\"message-text\">${message.msg.text}</div>\n </div>`\n : null}\n\n <div class=\"attachments\">\n ${(message.msg.attachments || []).map(\n (attachment) =>\n html`<temba-thumbnail\n attachment=\"${attachment}\"\n ></temba-thumbnail>`\n )}\n </div>\n </div>\n `;\n }\n\n public reset() {\n this.msgMap.clear();\n this.messageGroups = [];\n this.hideBottomScroll = true;\n this.hideTopScroll = true;\n this.endOfHistory = false;\n this.oldestEventDate = null;\n }\n\n public setEndOfHistory(oldestDate: Date) {\n this.endOfHistory = true;\n this.oldestEventDate = oldestDate;\n }\n\n public render(): TemplateResult {\n return html` <div\n class=\"\n messages \n ${this.hideBottomScroll ? 'scroll-at-bottom' : ''}\n ${this.hideTopScroll ? 'scroll-at-top' : ''}\"\n >\n <div class=\"scroll\" @scroll=${this.handleScroll}>\n ${this.messageGroups\n ? (() => {\n let lastTimestamp: Date | null = null;\n // process from oldest to newest (high index to low index)\n // to establish logical time groupings going forward in time\n const results = [];\n for (let idx = this.messageGroups.length - 1; idx >= 0; idx--) {\n const msgGroup = this.messageGroups[idx];\n const result = this.renderMessageGroup(\n msgGroup,\n idx,\n lastTimestamp\n );\n lastTimestamp = result.timestamp;\n results.unshift(result.html); // add to front since we're going backwards\n }\n return results;\n })()\n : null}\n\n <temba-loading\n class=\"${!this.fetching ? 'hidden' : ''}\"\n ></temba-loading>\n\n ${this.endOfHistory && this.oldestEventDate\n ? html`<div class=\"time first\">\n ${this.oldestEventDate.toLocaleTimeString(\n undefined,\n VERBOSE_FORMAT\n )}\n </div>`\n : null}\n </div>\n ${!this.hasFooter\n ? html`<div\n class=\"new-message-notification ${this.showNewMessageNotification\n ? 'visible'\n : ''}\"\n @click=${this.handleNewMessageClick}\n >\n New Messages\n </div>`\n : null}\n <slot class=\"header\" name=\"header\"></slot>\n <slot class=\"footer\" name=\"footer\"></slot>\n </div>`;\n }\n}\n"]}
@@ -87,11 +87,11 @@ export class FloatingTab extends RapidElement {
87
87
  // auto-calculate position based on index
88
88
  const index = FloatingTab.allTabs.indexOf(this);
89
89
  if (index === -1) {
90
- this.top = 100; // default fallback
90
+ this.top = 150; // default fallback
91
91
  }
92
92
  else {
93
93
  // start at 100px and stack with 10px gap between tabs
94
- this.top = 100 + index * (FloatingTab.TAB_HEIGHT + 0);
94
+ this.top = 150 + index * (FloatingTab.TAB_HEIGHT + 0);
95
95
  }
96
96
  }
97
97
  updated(changes) {
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingTab.js","sourceRoot":"","sources":["../../../src/display/FloatingTab.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { getClasses } from '../utils';\n\nexport class FloatingTab extends RapidElement {\n static get styles() {\n return css`\n .tab.hidden {\n transform: translateX(100%);\n }\n .tab {\n position: fixed;\n right: 0;\n z-index: 4998;\n transition: transform var(--transition-duration, 300ms) ease-in-out;\n display: flex;\n align-items: center;\n padding: 12px;\n border-top-left-radius: 8px;\n border-bottom-left-radius: 8px;\n cursor: pointer;\n box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);\n transition: all calc(var(--transition-duration, 300ms) * 0.7)\n ease-in-out;\n user-select: none;\n }\n\n .tab:hover {\n padding-right: 16px;\n box-shadow: -4px 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .icon-container {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n }\n\n temba-icon {\n --icon-color: white;\n }\n\n .label {\n color: white;\n font-weight: 500;\n font-size: 16px;\n max-width: 0;\n overflow: hidden;\n white-space: nowrap;\n margin-left: 0;\n opacity: 0;\n transition: all var(--transition-duration, 300ms) ease-in-out;\n }\n\n .tab:hover .label {\n max-width: 200px;\n margin-left: 12px;\n opacity: 1;\n }\n `;\n }\n\n static TAB_HEIGHT = 50; // height of tab for auto-stacking\n static allTabs: FloatingTab[] = [];\n\n @property({ type: String })\n icon: string;\n\n @property({ type: String })\n label: string;\n\n @property({ type: String })\n color = '#6B7280';\n\n @property({ type: Number })\n top = -1; // -1 means auto-calculate position\n\n @property({ type: Boolean })\n hidden = false;\n\n connectedCallback() {\n super.connectedCallback();\n FloatingTab.allTabs.push(this);\n this.updatePosition();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n const index = FloatingTab.allTabs.indexOf(this);\n if (index > -1) {\n FloatingTab.allTabs.splice(index, 1);\n }\n // update positions of remaining tabs\n FloatingTab.allTabs.forEach((tab) => tab.updatePosition());\n }\n\n private updatePosition() {\n // auto-calculate position based on index\n const index = FloatingTab.allTabs.indexOf(this);\n if (index === -1) {\n this.top = 100; // default fallback\n } else {\n // start at 100px and stack with 10px gap between tabs\n this.top = 100 + index * (FloatingTab.TAB_HEIGHT + 0);\n }\n }\n\n public updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('hidden')) {\n this.classList.toggle('hidden', this.hidden);\n }\n if (changes.has('top')) {\n this.updatePosition();\n }\n }\n\n private handleClick() {\n // hide all tabs when one is clicked\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n\n this.fireCustomEvent(CustomEventType.ButtonClicked, {\n action: 'toggle'\n });\n }\n\n public static showAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = false;\n });\n }\n\n public static hideAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n }\n\n public render(): TemplateResult {\n const tabStyle = `\n background-color: ${this.color};\n top: ${this.top}px;\n `;\n\n const classes = getClasses({\n tab: true,\n hidden: this.hidden\n });\n\n return html`\n <div class=\"${classes}\" style=\"${tabStyle}\" @click=${this.handleClick}>\n <div class=\"icon-container\">\n ${this.icon\n ? html`<temba-icon size=\"1.5\" name=\"${this.icon}\"></temba-icon>`\n : ''}\n </div>\n <div class=\"label\">${this.label}</div>\n </div>\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"FloatingTab.js","sourceRoot":"","sources":["../../../src/display/FloatingTab.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { getClasses } from '../utils';\n\nexport class FloatingTab extends RapidElement {\n static get styles() {\n return css`\n .tab.hidden {\n transform: translateX(100%);\n }\n .tab {\n position: fixed;\n right: 0;\n z-index: 4998;\n transition: transform var(--transition-duration, 300ms) ease-in-out;\n display: flex;\n align-items: center;\n padding: 12px;\n border-top-left-radius: 8px;\n border-bottom-left-radius: 8px;\n cursor: pointer;\n box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);\n transition: all calc(var(--transition-duration, 300ms) * 0.7)\n ease-in-out;\n user-select: none;\n }\n\n .tab:hover {\n padding-right: 16px;\n box-shadow: -4px 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .icon-container {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n }\n\n temba-icon {\n --icon-color: white;\n }\n\n .label {\n color: white;\n font-weight: 500;\n font-size: 16px;\n max-width: 0;\n overflow: hidden;\n white-space: nowrap;\n margin-left: 0;\n opacity: 0;\n transition: all var(--transition-duration, 300ms) ease-in-out;\n }\n\n .tab:hover .label {\n max-width: 200px;\n margin-left: 12px;\n opacity: 1;\n }\n `;\n }\n\n static TAB_HEIGHT = 50; // height of tab for auto-stacking\n static allTabs: FloatingTab[] = [];\n\n @property({ type: String })\n icon: string;\n\n @property({ type: String })\n label: string;\n\n @property({ type: String })\n color = '#6B7280';\n\n @property({ type: Number })\n top = -1; // -1 means auto-calculate position\n\n @property({ type: Boolean })\n hidden = false;\n\n connectedCallback() {\n super.connectedCallback();\n FloatingTab.allTabs.push(this);\n this.updatePosition();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n const index = FloatingTab.allTabs.indexOf(this);\n if (index > -1) {\n FloatingTab.allTabs.splice(index, 1);\n }\n // update positions of remaining tabs\n FloatingTab.allTabs.forEach((tab) => tab.updatePosition());\n }\n\n private updatePosition() {\n // auto-calculate position based on index\n const index = FloatingTab.allTabs.indexOf(this);\n if (index === -1) {\n this.top = 150; // default fallback\n } else {\n // start at 100px and stack with 10px gap between tabs\n this.top = 150 + index * (FloatingTab.TAB_HEIGHT + 0);\n }\n }\n\n public updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('hidden')) {\n this.classList.toggle('hidden', this.hidden);\n }\n if (changes.has('top')) {\n this.updatePosition();\n }\n }\n\n private handleClick() {\n // hide all tabs when one is clicked\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n\n this.fireCustomEvent(CustomEventType.ButtonClicked, {\n action: 'toggle'\n });\n }\n\n public static showAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = false;\n });\n }\n\n public static hideAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n }\n\n public render(): TemplateResult {\n const tabStyle = `\n background-color: ${this.color};\n top: ${this.top}px;\n `;\n\n const classes = getClasses({\n tab: true,\n hidden: this.hidden\n });\n\n return html`\n <div class=\"${classes}\" style=\"${tabStyle}\" @click=${this.handleClick}>\n <div class=\"icon-container\">\n ${this.icon\n ? html`<temba-icon size=\"1.5\" name=\"${this.icon}\"></temba-icon>`\n : ''}\n </div>\n <div class=\"label\">${this.label}</div>\n </div>\n `;\n }\n}\n"]}