@uzum-tech/ui 1.7.2 → 1.8.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 (93) hide show
  1. package/dist/index.js +1548 -998
  2. package/dist/index.prod.js +3 -3
  3. package/es/chat/index.d.ts +4 -0
  4. package/es/chat/index.js +2 -0
  5. package/es/chat/src/Chat.d.ts +19 -6
  6. package/es/chat/src/Chat.js +53 -14
  7. package/es/chat/src/ChatListItems.d.ts +6027 -0
  8. package/es/chat/src/ChatListItems.js +187 -0
  9. package/es/chat/src/ChatMessages.d.ts +6049 -0
  10. package/es/chat/src/ChatMessages.js +308 -0
  11. package/es/chat/src/ChatParts/ChatAttachment.js +4 -3
  12. package/es/chat/src/ChatParts/MainArea.d.ts +0 -2
  13. package/es/chat/src/ChatParts/MainArea.js +108 -229
  14. package/es/chat/src/ChatParts/Sidebar.js +16 -80
  15. package/es/chat/src/interface.d.ts +6 -1
  16. package/es/chat/src/styles/index.cssr.js +3 -2
  17. package/es/locales/common/arDZ.js +2 -1
  18. package/es/locales/common/deDE.js +2 -1
  19. package/es/locales/common/enGB.js +2 -1
  20. package/es/locales/common/enUS.d.ts +1 -0
  21. package/es/locales/common/enUS.js +2 -1
  22. package/es/locales/common/eo.js +2 -1
  23. package/es/locales/common/esAR.js +2 -1
  24. package/es/locales/common/faIR.js +2 -1
  25. package/es/locales/common/frFR.js +2 -1
  26. package/es/locales/common/idID.js +2 -1
  27. package/es/locales/common/itIT.js +2 -1
  28. package/es/locales/common/jaJP.js +2 -1
  29. package/es/locales/common/koKR.js +2 -1
  30. package/es/locales/common/nbNO.js +2 -1
  31. package/es/locales/common/nlNL.js +2 -1
  32. package/es/locales/common/plPL.js +2 -1
  33. package/es/locales/common/ptBR.js +2 -1
  34. package/es/locales/common/ruRU.js +2 -1
  35. package/es/locales/common/skSK.js +2 -1
  36. package/es/locales/common/svSE.js +2 -1
  37. package/es/locales/common/thTH.js +2 -1
  38. package/es/locales/common/trTR.js +2 -1
  39. package/es/locales/common/ukUA.js +2 -1
  40. package/es/locales/common/viVN.js +2 -1
  41. package/es/locales/common/zhCN.js +2 -1
  42. package/es/locales/common/zhTW.js +2 -1
  43. package/es/version.d.ts +1 -1
  44. package/es/version.js +1 -1
  45. package/lib/chat/index.d.ts +4 -0
  46. package/lib/chat/index.js +5 -1
  47. package/lib/chat/src/Chat.d.ts +19 -6
  48. package/lib/chat/src/Chat.js +52 -13
  49. package/lib/chat/src/ChatListItems.d.ts +6027 -0
  50. package/lib/chat/src/ChatListItems.js +193 -0
  51. package/lib/chat/src/ChatMessages.d.ts +6049 -0
  52. package/lib/chat/src/ChatMessages.js +314 -0
  53. package/lib/chat/src/ChatParts/ChatAttachment.js +4 -3
  54. package/lib/chat/src/ChatParts/MainArea.d.ts +0 -2
  55. package/lib/chat/src/ChatParts/MainArea.js +107 -228
  56. package/lib/chat/src/ChatParts/Sidebar.js +17 -78
  57. package/lib/chat/src/interface.d.ts +6 -1
  58. package/lib/chat/src/styles/index.cssr.js +3 -2
  59. package/lib/locales/common/arDZ.js +2 -1
  60. package/lib/locales/common/deDE.js +2 -1
  61. package/lib/locales/common/enGB.js +2 -1
  62. package/lib/locales/common/enUS.d.ts +1 -0
  63. package/lib/locales/common/enUS.js +2 -1
  64. package/lib/locales/common/eo.js +2 -1
  65. package/lib/locales/common/esAR.js +2 -1
  66. package/lib/locales/common/faIR.js +2 -1
  67. package/lib/locales/common/frFR.js +2 -1
  68. package/lib/locales/common/idID.js +2 -1
  69. package/lib/locales/common/itIT.js +2 -1
  70. package/lib/locales/common/jaJP.js +2 -1
  71. package/lib/locales/common/koKR.js +2 -1
  72. package/lib/locales/common/nbNO.js +2 -1
  73. package/lib/locales/common/nlNL.js +2 -1
  74. package/lib/locales/common/plPL.js +2 -1
  75. package/lib/locales/common/ptBR.js +2 -1
  76. package/lib/locales/common/ruRU.js +2 -1
  77. package/lib/locales/common/skSK.js +2 -1
  78. package/lib/locales/common/svSE.js +2 -1
  79. package/lib/locales/common/thTH.js +2 -1
  80. package/lib/locales/common/trTR.js +2 -1
  81. package/lib/locales/common/ukUA.js +2 -1
  82. package/lib/locales/common/viVN.js +2 -1
  83. package/lib/locales/common/zhCN.js +2 -1
  84. package/lib/locales/common/zhTW.js +2 -1
  85. package/lib/version.d.ts +1 -1
  86. package/lib/version.js +1 -1
  87. package/package.json +1 -1
  88. package/volar.d.ts +2 -0
  89. package/web-types.json +149 -1
  90. package/es/chat/src/ChatGlobalState.d.ts +0 -13
  91. package/es/chat/src/ChatGlobalState.js +0 -32
  92. package/lib/chat/src/ChatGlobalState.d.ts +0 -13
  93. package/lib/chat/src/ChatGlobalState.js +0 -36
@@ -14,8 +14,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const vue_1 = require("vue");
16
16
  const interface_1 = require("../interface");
17
- const ChatGlobalState_1 = require("../ChatGlobalState");
18
- const ChatAttachment_1 = __importDefault(require("./ChatAttachment"));
19
17
  const input_1 = require("../../../input");
20
18
  const button_1 = require("../../../button");
21
19
  const icon_1 = require("../../../icon");
@@ -24,21 +22,14 @@ const upload_1 = require("../../../upload");
24
22
  const flex_1 = require("../../../flex");
25
23
  const _utils_1 = require("../../../_utils");
26
24
  const typography_1 = require("../../../typography");
27
- const skeleton_1 = require("../../../skeleton");
25
+ const ChatMessages_1 = __importDefault(require("../ChatMessages"));
28
26
  const icons_1 = require("../../../_internal/icons");
29
27
  const SCROLL_DELAY = 50;
30
28
  const SENDING_DELAY = 100;
31
- const getChatGlobalState = () => ChatGlobalState_1.ChatGlobalState.getInstance();
32
- const statusIconMapper = {
33
- [interface_1.MessageStatus.READ]: icons_1.CheckmarkDoneSharp,
34
- [interface_1.MessageStatus.PENDING]: icons_1.MdTime,
35
- [interface_1.MessageStatus.RETRY]: icons_1.Refresh,
36
- [interface_1.MessageStatus.UNREAD]: icons_1.CheckmarkDoneSharp
37
- };
38
29
  exports.default = (0, vue_1.defineComponent)({
39
30
  name: 'ChatMainArea',
40
31
  setup(_, { slots }) {
41
- const { mergedClsPrefixRef, selectedChatRef, messagesRef, typingChatIdsRef, messagesLoadingRef, messagesLoadingCountRef, headerButtonPropsRef, headerIconPropsRef, messageUploadPropsRef, footerInputPropsRef, footerButtonPropsRef, footerUploadPropsRef, footerIconPropsRef, inputPlaceholderRef, retryTextRef, typingTextRef, closeButtonTextRef, handleMessageSend, handleMessageRetry, onChatClose, onChatShare, onUserProfile
32
+ const { mergedClsPrefixRef, selectedChatRef, messagesRef, typingChatIdsRef, messagesLoadingRef, messagesLoadingCountRef, headerButtonPropsRef, headerIconPropsRef, messageUploadPropsRef, footerInputPropsRef, footerButtonPropsRef, footerUploadPropsRef, footerIconPropsRef, inputPlaceholderRef, retryTextRef, typingTextRef, closeButtonTextRef, unreadNotificationTextRef, notificationsShownSetRef, unreadCountsBeforeReadRef, markNotificationShown, handleMessageSend, handleMessageRetry, onChatClose, onChatShare, onUserProfile
42
33
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
43
34
  } = (0, vue_1.inject)(interface_1.chatInjectionKey);
44
35
  const messagesBodyRef = (0, vue_1.ref)();
@@ -54,17 +45,18 @@ exports.default = (0, vue_1.defineComponent)({
54
45
  const hasUnreadMessages = (0, vue_1.ref)(false);
55
46
  const unreadCountOnOpen = (0, vue_1.ref)(0);
56
47
  const chatInputs = (0, vue_1.ref)({});
48
+ const lastMessageId = (0, vue_1.ref)(null);
57
49
  (0, vue_1.watch)(selectedChatRef, (newChat, oldChat) => {
58
50
  if (newChat && newChat.id !== (oldChat === null || oldChat === void 0 ? void 0 : oldChat.id)) {
59
51
  inputValue.value = chatInputs.value[newChat.id] || '';
60
- unreadCountOnOpen.value = unreadMessagesCount.value;
61
- const globalState = getChatGlobalState();
62
- globalState.markChatOpened(newChat.id);
63
- if (unreadCountOnOpen.value > 0 &&
64
- !globalState.hasNotificationShown(newChat.id)) {
52
+ const unreadBeforeRead = unreadCountsBeforeReadRef.value[newChat.id] || 0;
53
+ unreadCountOnOpen.value = unreadBeforeRead;
54
+ lastMessageId.value = null;
55
+ if (unreadBeforeRead > 0 &&
56
+ !notificationsShownSetRef.value.has(newChat.id)) {
65
57
  hasUnreadMessages.value = true;
66
58
  showNotificationManually.value = true;
67
- globalState.markNotificationShown(newChat.id);
59
+ markNotificationShown(newChat.id);
68
60
  }
69
61
  else {
70
62
  hasUnreadMessages.value = false;
@@ -73,29 +65,41 @@ exports.default = (0, vue_1.defineComponent)({
73
65
  void (0, vue_1.nextTick)(() => {
74
66
  scrollToBottom();
75
67
  });
68
+ setTimeout(() => {
69
+ scrollToBottom();
70
+ }, SCROLL_DELAY);
76
71
  }
77
72
  }, { immediate: true });
78
- (0, vue_1.watch)(messagesRef, (newMessages, oldMessages) => {
79
- if (newMessages &&
80
- oldMessages &&
81
- newMessages.length > oldMessages.length) {
82
- if (selectedChatRef.value) {
83
- const globalState = getChatGlobalState();
84
- if (globalState.hasNotificationShown(selectedChatRef.value.id)) {
85
- showNotificationManually.value = false;
86
- }
87
- }
73
+ (0, vue_1.watch)(messagesRef, (newMessages) => {
74
+ if (!newMessages || newMessages.length === 0) {
75
+ lastMessageId.value = null;
76
+ return;
77
+ }
78
+ const currentLastMessage = newMessages[newMessages.length - 1];
79
+ const currentLastId = currentLastMessage === null || currentLastMessage === void 0 ? void 0 : currentLastMessage.id;
80
+ if (currentLastId !== lastMessageId.value &&
81
+ lastMessageId.value !== null) {
88
82
  void (0, vue_1.nextTick)(() => {
89
83
  scrollToBottom();
90
84
  });
85
+ setTimeout(() => {
86
+ scrollToBottom();
87
+ }, SCROLL_DELAY);
88
+ if (currentLastMessage &&
89
+ !currentLastMessage.isOwn &&
90
+ currentLastMessage.status === interface_1.MessageStatus.UNREAD) {
91
+ unreadCountOnOpen.value = unreadMessagesCount.value;
92
+ }
91
93
  }
92
- }, { deep: true });
94
+ lastMessageId.value = currentLastId !== null && currentLastId !== void 0 ? currentLastId : null;
95
+ }, { deep: true, flush: 'post' });
93
96
  (0, vue_1.watch)(unreadMessagesCount, (newCount, oldCount) => {
94
- if (selectedChatRef.value) {
95
- if (newCount === 0 && oldCount > 0) {
96
- showNotificationManually.value = false;
97
- hasUnreadMessages.value = false;
98
- }
97
+ if (selectedChatRef.value && newCount === 0 && oldCount > 0) {
98
+ showNotificationManually.value = false;
99
+ hasUnreadMessages.value = false;
100
+ const newSet = new Set(notificationsShownSetRef.value);
101
+ newSet.delete(selectedChatRef.value.id);
102
+ notificationsShownSetRef.value = newSet;
99
103
  }
100
104
  });
101
105
  const showUnreadNotification = (0, vue_1.computed)(() => {
@@ -105,189 +109,63 @@ exports.default = (0, vue_1.defineComponent)({
105
109
  void (0, vue_1.nextTick)(() => {
106
110
  scrollToBottom();
107
111
  });
112
+ setTimeout(() => {
113
+ scrollToBottom();
114
+ }, SCROLL_DELAY);
108
115
  });
109
116
  const scrollToBottom = () => {
110
117
  const el = messagesBodyRef.value;
111
118
  if (!el)
112
119
  return;
113
- if ('scrollTo' in el && typeof el.scrollTo === 'function') {
114
- el.scrollTo({ top: 999999, behavior: 'smooth' });
115
- return;
116
- }
117
120
  if ('$el' in el && el.$el instanceof HTMLElement) {
118
- const scrollContainer = el.$el.querySelector('.u-scrollbar-content') || el.$el;
119
- scrollContainer.scrollTop = scrollContainer.scrollHeight;
121
+ const scrollContainer = el.$el.querySelector('.u-scrollbar-content');
122
+ if (scrollContainer) {
123
+ scrollContainer.scrollTop = scrollContainer.scrollHeight;
124
+ return;
125
+ }
126
+ }
127
+ if ('scrollTo' in el && typeof el.scrollTo === 'function') {
128
+ el.scrollTo({ top: 999999, behavior: 'auto' });
120
129
  return;
121
130
  }
122
131
  if ('scrollTop' in el && 'scrollHeight' in el) {
123
132
  el.scrollTop = el.scrollHeight;
124
133
  }
125
134
  };
126
- const renderUnreadNotification = () => {
127
- if (!showUnreadNotification.value)
128
- return null;
129
- return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__unread-notification` },
130
- (0, vue_1.h)("span", null,
131
- unreadCountOnOpen.value,
132
- " \u043D\u043E\u0432\u044B\u0445 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F")));
133
- };
134
135
  const renderHeader = () => {
135
- var _a;
136
136
  return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__header` },
137
- (0, vue_1.h)(flex_1.UFlex, { justify: "space-between", align: "flex-start" },
138
- (0, vue_1.h)(typography_1.UText, { variant: "heading-s-bold", class: `${mergedClsPrefixRef.value}-chat-main__header-title` }, ((_a = selectedChatRef.value) === null || _a === void 0 ? void 0 : _a.title) || 'Select a chat'),
139
- (0, vue_1.h)(flex_1.UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__header-actions` }, (0, _utils_1.resolveSlot)(slots.headerActions, () => [
140
- (0, vue_1.h)(button_1.UButton, Object.assign({ secondary: true, circle: true, size: "large" }, headerButtonPropsRef.value, { onClick: () => { var _a; return (_a = onChatShare === null || onChatShare === void 0 ? void 0 : onChatShare.value) === null || _a === void 0 ? void 0 : _a.call(onChatShare); } }),
141
- (0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value),
142
- (0, vue_1.h)(icons_1.ArrowHookUpRight, null))),
143
- (0, vue_1.h)(button_1.UButton, Object.assign({ secondary: true, circle: true, size: "large" }, headerButtonPropsRef.value, { onClick: () => { var _a; return (_a = onUserProfile === null || onUserProfile === void 0 ? void 0 : onUserProfile.value) === null || _a === void 0 ? void 0 : _a.call(onUserProfile); } }),
144
- (0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value),
145
- (0, vue_1.h)(icons_1.PersonNote, null))),
146
- (0, vue_1.h)(button_1.UButton, Object.assign({ type: "primary", size: "large", round: true }, headerButtonPropsRef.value, { onClick: () => { var _a; return (_a = onChatClose === null || onChatClose === void 0 ? void 0 : onChatClose.value) === null || _a === void 0 ? void 0 : _a.call(onChatClose); } }), closeButtonTextRef.value)
147
- ])))));
148
- };
149
- const renderDateSeparator = (date) => {
150
- return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__date-separator` },
151
- (0, vue_1.h)("span", null, date)));
152
- };
153
- const renderMessage = (message) => {
154
- const isOwn = message.isOwn;
155
- const attachments = message.attachment
156
- ? Array.isArray(message.attachment)
157
- ? message.attachment
158
- : [message.attachment]
159
- : [];
160
- return ((0, vue_1.h)("div", { key: message.id, class: [
161
- `${mergedClsPrefixRef.value}-chat-main__message`,
162
- isOwn
163
- ? `${mergedClsPrefixRef.value}-chat-main__message--own`
164
- : `${mergedClsPrefixRef.value}-chat-main__message--other`
165
- ] },
166
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-wrapper` },
167
- message.content || attachments.length > 1 ? ((0, vue_1.h)("div", { class: [
168
- `${mergedClsPrefixRef.value}-chat-main__message-bubble`,
169
- isOwn
170
- ? `${mergedClsPrefixRef.value}-chat-main__message-bubble--own`
171
- : `${mergedClsPrefixRef.value}-chat-main__message-bubble--other`
172
- ] },
173
- attachments.length > 0 && ((0, vue_1.h)(ChatAttachment_1.default, { message: message, attachments: attachments, uploadProps: messageUploadPropsRef.value, withPadding: true }, {
174
- default: slots.messageAttachment,
175
- 'upload-file-title': slots.messageAttachmentTitle,
176
- 'upload-file-subtitle': slots.messageAttachmentSubtitle
177
- })),
178
- message.content && ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-text` }, message.content)))) : attachments.length === 1 ? ((0, vue_1.h)(ChatAttachment_1.default, { message: message, attachments: attachments, uploadProps: messageUploadPropsRef.value }, {
179
- default: slots.messageAttachment,
180
- 'upload-file-title': slots.messageAttachmentTitle,
181
- 'upload-file-subtitle': slots.messageAttachmentSubtitle
182
- })) : null,
183
- (0, vue_1.h)("div", { class: [
184
- `${mergedClsPrefixRef.value}-chat-main__message-meta`,
185
- isOwn
186
- ? `${mergedClsPrefixRef.value}-chat-main__message-meta--own`
187
- : `${mergedClsPrefixRef.value}-chat-main__message-meta--other`,
188
- message.status === interface_1.MessageStatus.RETRY &&
189
- `${mergedClsPrefixRef.value}-chat-main__message-meta--retry`
190
- ] }, message.status === interface_1.MessageStatus.RETRY ? ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-retry`, onClick: () => {
191
- handleMessageRetry(message);
192
- }, style: { cursor: 'pointer' } },
193
- (0, vue_1.h)(icon_1.UIcon, { size: 16, component: statusIconMapper[interface_1.MessageStatus.RETRY], class: `${mergedClsPrefixRef.value}-chat-main__message-retry-icon` }),
194
- (0, vue_1.h)("span", { class: `${mergedClsPrefixRef.value}-chat-main__message-retry-text` }, retryTextRef.value))) : ((0, vue_1.h)(vue_1.Fragment, null,
195
- (0, vue_1.h)("span", { class: `${mergedClsPrefixRef.value}-chat-main__message-time` }, message.timestamp),
196
- isOwn && message.status && ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-status` }, slots.messageStatus
197
- ? slots.messageStatus(message)
198
- : statusIconMapper[message.status] && ((0, vue_1.h)(icon_1.UIcon, { size: 16, component: statusIconMapper[message.status], class: [
199
- `${mergedClsPrefixRef.value}-chat-main__message-status-icon`,
200
- `${mergedClsPrefixRef.value}-chat-main__message-status-icon--${String(message.status)}`
201
- ] }))))))))));
202
- };
203
- const renderTypingIndicator = () => {
204
- return ((0, vue_1.h)("div", { class: [
205
- `${mergedClsPrefixRef.value}-chat-main__message`,
206
- `${mergedClsPrefixRef.value}-chat-main__message--other`
207
- ] },
208
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-wrapper` },
209
- (0, vue_1.h)("div", { class: [
210
- `${mergedClsPrefixRef.value}-chat-main__message-bubble`,
211
- `${mergedClsPrefixRef.value}-chat-main__message-bubble--other`,
212
- `${mergedClsPrefixRef.value}-chat-main__message-bubble--typing`
213
- ] }),
214
- (0, vue_1.h)("div", { class: [
215
- `${mergedClsPrefixRef.value}-chat-main__message-meta`,
216
- `${mergedClsPrefixRef.value}-chat-main__message-meta--other`
217
- ] },
218
- (0, vue_1.h)("span", { class: `${mergedClsPrefixRef.value}-chat-main__message-time` }, typingTextRef.value)))));
219
- };
220
- const renderSkeletonMessage = (isOwn, index) => {
221
- return ((0, vue_1.h)("div", { key: `skeleton-${index}`, class: [
222
- `${mergedClsPrefixRef.value}-chat-main__message`,
223
- isOwn
224
- ? `${mergedClsPrefixRef.value}-chat-main__message--own`
225
- : `${mergedClsPrefixRef.value}-chat-main__message--other`
226
- ] },
227
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-wrapper` },
228
- (0, vue_1.h)("div", { class: [
229
- `${mergedClsPrefixRef.value}-chat-main__message-bubble`,
230
- isOwn
231
- ? `${mergedClsPrefixRef.value}-chat-main__message-bubble--own`
232
- : `${mergedClsPrefixRef.value}-chat-main__message-bubble--other`
233
- ] },
234
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-text` },
235
- (0, vue_1.h)("div", { style: { width: '376px', height: '20px' } }))),
236
- (0, vue_1.h)("div", { class: [
237
- `${mergedClsPrefixRef.value}-chat-main__message-meta`,
238
- isOwn
239
- ? `${mergedClsPrefixRef.value}-chat-main__message-meta--own`
240
- : `${mergedClsPrefixRef.value}-chat-main__message-meta--other`
241
- ] },
242
- (0, vue_1.h)(skeleton_1.USkeleton, { style: { width: '36px', height: '20px', borderRadius: '4px' } })))));
137
+ (0, vue_1.h)(flex_1.UFlex, { justify: "space-between", align: "flex-start" }, {
138
+ default: () => ((0, vue_1.h)(vue_1.Fragment, null,
139
+ (0, vue_1.h)(typography_1.UText, { variant: "heading-s-bold", class: `${mergedClsPrefixRef.value}-chat-main__header-title` }, {
140
+ default: () => { var _a; return ((_a = selectedChatRef.value) === null || _a === void 0 ? void 0 : _a.title) || 'Select a chat'; }
141
+ }),
142
+ (0, vue_1.h)(flex_1.UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__header-actions` }, {
143
+ default: () => (0, _utils_1.resolveSlot)(slots.headerActions, () => [
144
+ (0, vue_1.h)(button_1.UButton, Object.assign({ secondary: true, circle: true, size: "large" }, headerButtonPropsRef.value, { onClick: () => { var _a; return (_a = onChatShare === null || onChatShare === void 0 ? void 0 : onChatShare.value) === null || _a === void 0 ? void 0 : _a.call(onChatShare); } }), {
145
+ default: () => ((0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value), {
146
+ default: () => (0, vue_1.h)(icons_1.ArrowHookUpRight, null)
147
+ }))
148
+ }),
149
+ (0, vue_1.h)(button_1.UButton, Object.assign({ secondary: true, circle: true, size: "large" }, headerButtonPropsRef.value, { onClick: () => { var _a; return (_a = onUserProfile === null || onUserProfile === void 0 ? void 0 : onUserProfile.value) === null || _a === void 0 ? void 0 : _a.call(onUserProfile); } }), {
150
+ default: () => ((0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value), {
151
+ default: () => (0, vue_1.h)(icons_1.PersonNote, null)
152
+ }))
153
+ }),
154
+ (0, vue_1.h)(button_1.UButton, Object.assign({ type: "primary", size: "large", round: true }, headerButtonPropsRef.value, { onClick: () => { var _a; return (_a = onChatClose === null || onChatClose === void 0 ? void 0 : onChatClose.value) === null || _a === void 0 ? void 0 : _a.call(onChatClose); } }), {
155
+ default: () => closeButtonTextRef.value
156
+ })
157
+ ])
158
+ })))
159
+ })));
243
160
  };
244
161
  const renderMessages = () => {
245
- var _a, _b;
246
- if (messagesLoadingRef.value) {
247
- return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__messages` }, Array.from({ length: messagesLoadingCountRef.value || 5 }).map((_, index) => {
248
- const isOwn = index % 2 === 0;
249
- return renderSkeletonMessage(isOwn, index);
250
- })));
251
- }
252
- const messagesWithDates = [];
253
- let currentDate = '';
254
- let unreadNotificationInserted = false;
255
- (_a = messagesRef.value) === null || _a === void 0 ? void 0 : _a.forEach((message, index) => {
256
- const messageDate = message.date || '';
257
- if (messageDate !== currentDate) {
258
- messagesWithDates.push({
259
- type: 'date-separator',
260
- date: messageDate,
261
- id: `date-${String(index)}`
262
- });
263
- currentDate = messageDate;
264
- }
265
- if (!unreadNotificationInserted &&
266
- !message.isOwn &&
267
- message.status === interface_1.MessageStatus.UNREAD &&
268
- showUnreadNotification.value) {
269
- messagesWithDates.push({
270
- type: 'unread-notification',
271
- id: 'unread-notification'
272
- });
273
- unreadNotificationInserted = true;
274
- }
275
- messagesWithDates.push(Object.assign({ type: 'message' }, message));
276
- });
277
- return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__messages-container` },
278
- messagesWithDates.map((item) => {
279
- var _a;
280
- if (item.type === 'date-separator') {
281
- return renderDateSeparator((_a = item.date) !== null && _a !== void 0 ? _a : '');
282
- }
283
- if (item.type === 'unread-notification') {
284
- return renderUnreadNotification();
285
- }
286
- return renderMessage(item);
287
- }),
288
- selectedChatRef.value &&
289
- ((_b = typingChatIdsRef.value) === null || _b === void 0 ? void 0 : _b.includes(selectedChatRef.value.id)) &&
290
- renderTypingIndicator()));
162
+ var _a;
163
+ return ((0, vue_1.h)(ChatMessages_1.default, { messages: messagesRef.value, loading: messagesLoadingRef.value, loadingCount: messagesLoadingCountRef.value, typingChatIds: typingChatIdsRef.value, selectedChatId: (_a = selectedChatRef.value) === null || _a === void 0 ? void 0 : _a.id, typingText: typingTextRef.value, retryText: retryTextRef.value, uploadProps: messageUploadPropsRef.value, showUnreadNotification: showUnreadNotification.value, unreadNotificationText: unreadNotificationTextRef.value, unreadNotificationCount: unreadCountOnOpen.value, onMessageRetry: handleMessageRetry }, {
164
+ messageAttachment: slots.messageAttachment,
165
+ messageAttachmentTitle: slots.messageAttachmentTitle,
166
+ messageAttachmentSubtitle: slots.messageAttachmentSubtitle,
167
+ messageStatus: slots.messageStatus
168
+ }));
291
169
  };
292
170
  const isSending = (0, vue_1.ref)(false);
293
171
  const handleSendMessage = () => __awaiter(this, void 0, void 0, function* () {
@@ -321,12 +199,8 @@ exports.default = (0, vue_1.defineComponent)({
321
199
  inputValue.value = '';
322
200
  attachmentFileList.value = [];
323
201
  chatInputs.value[selectedChatRef.value.id] = '';
324
- const globalState = getChatGlobalState();
325
- if (globalState.hasNotificationShown(selectedChatRef.value.id)) {
326
- globalState.markNotificationShown(selectedChatRef.value.id);
327
- showNotificationManually.value = false;
328
- hasUnreadMessages.value = false;
329
- }
202
+ hasUnreadMessages.value = false;
203
+ showNotificationManually.value = false;
330
204
  void (0, vue_1.nextTick)(() => {
331
205
  scrollToBottom();
332
206
  });
@@ -384,32 +258,35 @@ exports.default = (0, vue_1.defineComponent)({
384
258
  };
385
259
  const renderFooter = () => {
386
260
  return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main__footer` },
387
- (0, vue_1.h)(upload_1.UUpload, Object.assign({ abstract: true, multiple: true, defaultUpload: false, fileList: attachmentFileList.value, onUpdateFileList: handleFileListUpdate }, footerUploadPropsRef.value),
388
- (0, vue_1.h)(flex_1.UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__input-container` },
389
- (0, vue_1.h)(upload_1.UUploadTrigger, { abstract: true }, {
390
- default: ({ handleClick }) => ((0, vue_1.h)(button_1.UButton, Object.assign({ secondary: true, size: "large", class: `${mergedClsPrefixRef.value}-chat-main__attach-btn` }, footerButtonPropsRef.value, { onClick: handleClick }),
391
- (0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 24 }, footerIconPropsRef.value),
392
- (0, vue_1.h)(icons_1.AttachIcon, null))))
393
- }),
394
- (0, vue_1.h)(input_1.UInput, Object.assign({ ref: "inputRef", value: inputValue.value, placeholder: inputPlaceholderRef.value, class: `${mergedClsPrefixRef.value}-chat-main__input` }, footerInputPropsRef.value, { onUpdateValue: (value) => {
395
- inputValue.value = value;
396
- if (selectedChatRef.value) {
397
- chatInputs.value[selectedChatRef.value.id] = value;
398
- }
399
- }, onKeydown: (e) => {
400
- if (e.key === 'Enter' && !e.shiftKey) {
401
- e.preventDefault();
402
- e.stopPropagation();
403
- void handleSendMessage();
404
- }
405
- } }))))));
261
+ (0, vue_1.h)(upload_1.UUpload, Object.assign({ abstract: true, multiple: true, defaultUpload: false, fileList: attachmentFileList.value, onUpdateFileList: handleFileListUpdate }, footerUploadPropsRef.value), {
262
+ default: () => ((0, vue_1.h)(flex_1.UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__input-container` }, {
263
+ default: () => ((0, vue_1.h)(vue_1.Fragment, null,
264
+ (0, vue_1.h)(upload_1.UUploadTrigger, { abstract: true }, {
265
+ default: ({ handleClick }) => ((0, vue_1.h)(button_1.UButton, Object.assign({ secondary: true, size: "large", class: `${mergedClsPrefixRef.value}-chat-main__attach-btn` }, footerButtonPropsRef.value, { onClick: handleClick }), {
266
+ default: () => ((0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 24 }, footerIconPropsRef.value), {
267
+ default: () => (0, vue_1.h)(icons_1.AttachIcon, null)
268
+ }))
269
+ }))
270
+ }),
271
+ (0, vue_1.h)(input_1.UInput, Object.assign({ ref: "inputRef", value: inputValue.value, placeholder: inputPlaceholderRef.value, class: `${mergedClsPrefixRef.value}-chat-main__input` }, footerInputPropsRef.value, { onUpdateValue: (value) => {
272
+ inputValue.value = value;
273
+ if (selectedChatRef.value) {
274
+ chatInputs.value[selectedChatRef.value.id] = value;
275
+ }
276
+ }, onKeydown: (e) => {
277
+ if (e.key === 'Enter' && !e.shiftKey) {
278
+ e.preventDefault();
279
+ e.stopPropagation();
280
+ void handleSendMessage();
281
+ }
282
+ } }))))
283
+ }))
284
+ })));
406
285
  };
407
286
  return {
408
287
  renderHeader,
409
288
  renderMessages,
410
289
  renderFooter,
411
- renderUnreadNotification,
412
- showUnreadNotification,
413
290
  messagesBodyRef,
414
291
  inputRef,
415
292
  inputValue,
@@ -422,7 +299,9 @@ exports.default = (0, vue_1.defineComponent)({
422
299
  const { mergedClsPrefixRef } = (0, vue_1.inject)(interface_1.chatInjectionKey);
423
300
  return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-main` },
424
301
  this.renderHeader(),
425
- (0, vue_1.h)(scrollbar_1.UScrollbar, { ref: "messagesBodyRef", class: `${mergedClsPrefixRef.value}-chat-main__body` }, this.renderMessages()),
302
+ (0, vue_1.h)(scrollbar_1.UScrollbar, { ref: "messagesBodyRef", class: `${mergedClsPrefixRef.value}-chat-main__body` }, {
303
+ default: () => this.renderMessages()
304
+ }),
426
305
  this.renderFooter()));
427
306
  }
428
307
  });
@@ -1,100 +1,39 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  const vue_1 = require("vue");
4
7
  const interface_1 = require("../interface");
5
- const ChatGlobalState_1 = require("../ChatGlobalState");
6
8
  const flex_1 = require("../../../flex");
7
- const empty_1 = require("../../../empty");
8
- const avatar_1 = require("../../../avatar");
9
9
  const select_1 = require("../../../select");
10
- const list_1 = require("../../../list");
11
- const badge_1 = require("../../../badge");
12
- const icon_1 = require("../../../icon");
13
- const icons_1 = require("../../../_internal/icons");
14
- const statusIconMapper = {
15
- [interface_1.MessageStatus.READ]: icons_1.CheckmarkDoneSharp,
16
- [interface_1.MessageStatus.PENDING]: icons_1.MdTime,
17
- [interface_1.MessageStatus.RETRY]: icons_1.Refresh,
18
- [interface_1.MessageStatus.UNREAD]: icons_1.CheckmarkDoneSharp
19
- };
10
+ const ChatListItems_1 = __importDefault(require("../ChatListItems"));
20
11
  exports.default = (0, vue_1.defineComponent)({
21
12
  name: 'ChatSidebar',
22
13
  setup(props, { slots }) {
23
14
  return { slots };
24
15
  },
25
16
  render() {
26
- var _a, _b;
27
17
  const { slots } = this;
28
- const { mergedClsPrefixRef, chatItemsRef, chatItemsLoadingRef, chatItemsLoadingCountRef, listEmptyPropsRef, selectedChatIdRef, typingChatIdsRef, typingTextRef, listItemAvatarPropsRef, listItemBadgePropsRef, handleChatSelect
18
+ const { mergedClsPrefixRef, chatItemsRef, chatItemsLoadingRef, chatItemsLoadingCountRef, listEmptyPropsRef, selectedChatIdRef, typingChatIdsRef, typingTextRef, listItemAvatarPropsRef, listItemBadgePropsRef, notificationsShownSetRef, handleChatSelect
29
19
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
30
20
  } = (0, vue_1.inject)(interface_1.chatInjectionKey);
31
21
  const renderListHeader = () => {
32
- var _a, _b;
33
22
  return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header` },
34
- (0, vue_1.h)(flex_1.UFlex, { align: "center", justify: "space-between", style: { width: '100%' } },
35
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-main` }, ((_a = slots.sidebarHeaderMain) === null || _a === void 0 ? void 0 : _a.call(slots)) || (0, vue_1.h)(select_1.USelect, { round: true })),
36
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-actions` }, (_b = slots.sidebarHeaderActions) === null || _b === void 0 ? void 0 : _b.call(slots)))));
37
- };
38
- const renderChatItem = (item) => {
39
- var _a, _b;
40
- const isSelected = selectedChatIdRef.value === item.id;
41
- const isTyping = (_b = (_a = typingChatIdsRef.value) === null || _a === void 0 ? void 0 : _a.includes(item.id)) !== null && _b !== void 0 ? _b : false;
42
- return ((0, vue_1.h)(list_1.UListItem, { key: item.id, showIcon: false, onClick: () => {
43
- handleChatSelect(item.id);
44
- }, class: [
45
- `${mergedClsPrefixRef.value}-chat-sidebar__item`,
46
- isSelected &&
47
- `${mergedClsPrefixRef.value}-chat-sidebar__item--selected`,
48
- isTyping && `${mergedClsPrefixRef.value}-chat-sidebar__item--typing`
49
- ] }, {
50
- prefix: () => {
51
- var _a;
52
- return ((0, vue_1.h)(avatar_1.UAvatar, Object.assign({ size: "medium", src: typeof item.avatar === 'string' ? item.avatar : undefined }, listItemAvatarPropsRef.value), typeof item.avatar === 'function'
53
- ? item.avatar()
54
- : typeof item.title === 'string'
55
- ? (_a = item.title.charAt(0)) === null || _a === void 0 ? void 0 : _a.toUpperCase()
56
- : '?'));
57
- },
58
- header: () => ((0, vue_1.h)("span", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-title` }, typeof item.title === 'function' ? item.title() : item.title)),
59
- description: () => ((0, vue_1.h)("span", { class: [
60
- `${mergedClsPrefixRef.value}-chat-sidebar__item-subtitle`,
61
- isTyping && 'typing'
62
- ], style: {
63
- display: 'block',
64
- overflow: 'hidden',
65
- textOverflow: 'ellipsis',
66
- whiteSpace: 'nowrap',
67
- minWidth: 0,
68
- maxWidth: '100%'
69
- } }, isTyping
70
- ? typingTextRef.value
71
- : typeof item.subtitle === 'string'
72
- ? item.subtitle
73
- : typeof item.subtitle === 'function'
74
- ? item.subtitle()
75
- : item.subtitle)),
76
- suffix: () => {
77
- const getChatGlobalState = () => ChatGlobalState_1.ChatGlobalState.getInstance();
78
- const globalState = getChatGlobalState();
79
- const wasOpened = globalState.isChatOpened(item.id);
80
- const displayUnreadCount = wasOpened ? 0 : item.unreadCount || 0;
81
- const hasUnreadIncoming = displayUnreadCount > 0;
82
- const lastMessageIsOwn = item.lastMessageIsOwn;
83
- return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-indicators` },
84
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-time` }, item.datetime),
85
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-status` },
86
- lastMessageIsOwn &&
87
- (slots.chatItemStatus ? (slots.chatItemStatus(item)) : item.messageStatus &&
88
- statusIconMapper[item.messageStatus] ? ((0, vue_1.h)(icon_1.UIcon, { size: 16, component: statusIconMapper[item.messageStatus], class: [
89
- `${mergedClsPrefixRef.value}-chat-sidebar__item-status-icon`,
90
- `${mergedClsPrefixRef.value}-chat-sidebar__item-status-icon--${item.messageStatus}`
91
- ] })) : null),
92
- !lastMessageIsOwn && hasUnreadIncoming && ((0, vue_1.h)(badge_1.UBadge, Object.assign({ value: displayUnreadCount }, listItemBadgePropsRef.value))))));
93
- }
94
- }));
23
+ (0, vue_1.h)(flex_1.UFlex, { align: "center", justify: "space-between", class: `${mergedClsPrefixRef.value}-chat-sidebar__header-container`, style: { width: '100%' } }, {
24
+ default: () => {
25
+ var _a, _b;
26
+ return ((0, vue_1.h)(vue_1.Fragment, null,
27
+ (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-main` }, ((_a = slots.sidebarHeaderMain) === null || _a === void 0 ? void 0 : _a.call(slots)) || ((0, vue_1.h)(select_1.USelect, { round: true, size: "small" }))),
28
+ (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-actions` }, (_b = slots.sidebarHeaderActions) === null || _b === void 0 ? void 0 : _b.call(slots))));
29
+ }
30
+ })));
95
31
  };
96
32
  return ((0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar` },
97
33
  renderListHeader(),
98
- (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__content` }, chatItemsLoadingRef.value ? ((0, vue_1.h)(list_1.UList, { loading: true }, Array.from({ length: chatItemsLoadingCountRef.value || 10 }).map((_, index) => ((0, vue_1.h)(list_1.UListItem, { key: index, avatar: { icon: icons_1.PersonOutline }, description: { text: 'Loading...' }, header: { text: 'Loading...' } }))))) : ((_a = chatItemsRef.value) === null || _a === void 0 ? void 0 : _a.length) ? ((0, vue_1.h)(list_1.UList, { showIcon: false }, (_b = chatItemsRef.value) === null || _b === void 0 ? void 0 : _b.map((item) => renderChatItem(item)))) : ((0, vue_1.h)(empty_1.UEmpty, Object.assign({}, listEmptyPropsRef.value))))));
34
+ (0, vue_1.h)("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__content` },
35
+ (0, vue_1.h)(ChatListItems_1.default, { chatItems: chatItemsRef.value, selectedChatId: selectedChatIdRef.value, typingChatIds: typingChatIdsRef.value, typingText: typingTextRef.value, loading: chatItemsLoadingRef.value, loadingCount: chatItemsLoadingCountRef.value, emptyProps: listEmptyPropsRef.value, avatarProps: listItemAvatarPropsRef.value, badgeProps: listItemBadgePropsRef.value, notificationsShown: notificationsShownSetRef.value, onChatSelect: handleChatSelect }, {
36
+ chatItemStatus: slots.chatItemStatus
37
+ }))));
99
38
  }
100
39
  });
@@ -109,7 +109,7 @@ export interface ChatAttachment {
109
109
  type: ChatMessageType.FILE;
110
110
  name: string;
111
111
  url: string;
112
- size?: number;
112
+ size?: number | string;
113
113
  thumbnail?: string | (() => VNodeChild);
114
114
  preview?: string | (() => VNodeChild);
115
115
  status?: 'pending' | 'uploading' | 'finished' | 'error';
@@ -146,6 +146,7 @@ export interface ChatProps {
146
146
  retryText?: string;
147
147
  typingText?: string;
148
148
  closeButtonText?: string;
149
+ unreadNotificationText?: string;
149
150
  chatItemsLoading?: boolean;
150
151
  chatItemsLoadingCount?: number;
151
152
  messagesLoading?: boolean;
@@ -269,6 +270,10 @@ export declare const chatInjectionKey: InjectionKey<{
269
270
  retryTextRef: Ref<string>;
270
271
  typingTextRef: Ref<string>;
271
272
  closeButtonTextRef: Ref<string>;
273
+ unreadNotificationTextRef: Ref<string>;
274
+ notificationsShownSetRef: Ref<Set<ChatId>>;
275
+ unreadCountsBeforeReadRef: Ref<Record<ChatId, number>>;
276
+ markNotificationShown: (chatId: ChatId) => void;
272
277
  handleChatSelect: (chatId: ChatId) => void;
273
278
  handleMessageSend: (content: string, attachments?: ChatAttachment[]) => void;
274
279
  handleMessageRetry: (message: ChatMessageData) => void;
@@ -31,8 +31,9 @@ exports.default = (0, cssr_1.cB)('chat', `
31
31
  border-radius: 20px;
32
32
  overflow: hidden;
33
33
  `, [(0, cssr_1.cE)('header', `
34
- padding: 16px 16px 0 16px;
35
34
  flex-shrink: 0;
35
+ `), (0, cssr_1.cE)('header-container', `
36
+ padding: 16px 16px 4px 16px;
36
37
  `), (0, cssr_1.cE)('header-main', `
37
38
  flex: 0 0 48%;
38
39
  min-width: 0;
@@ -48,7 +49,7 @@ exports.default = (0, cssr_1.cB)('chat', `
48
49
  overflow-y: auto;
49
50
  min-height: 0;
50
51
  padding: 16px;
51
- padding-top: 12px;
52
+ padding-top: 8px;
52
53
  `), (0, cssr_1.cE)('item', `
53
54
  padding: 12px 16px;
54
55
  width: 100%;
@@ -130,7 +130,8 @@ const arDZ = {
130
130
  inputPlaceholder: 'Type a message...',
131
131
  typingText: 'Typing...',
132
132
  retryText: 'Resend',
133
- closeButtonText: 'Close chat'
133
+ closeButtonText: 'Close chat',
134
+ unreadNotificationText: 'new messages'
134
135
  }
135
136
  };
136
137
  exports.default = arDZ;
@@ -130,7 +130,8 @@ const deDE = {
130
130
  inputPlaceholder: 'Type a message...',
131
131
  typingText: 'Typing...',
132
132
  retryText: 'Resend',
133
- closeButtonText: 'Close chat'
133
+ closeButtonText: 'Close chat',
134
+ unreadNotificationText: 'new messages'
134
135
  }
135
136
  };
136
137
  exports.default = deDE;