@uzum-tech/ui 1.7.2 → 1.8.1

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 (97) hide show
  1. package/dist/index.js +1673 -996
  2. package/dist/index.prod.js +3 -3
  3. package/es/chat/index.d.ts +6 -1
  4. package/es/chat/index.js +3 -0
  5. package/es/chat/src/Chat.d.ts +19 -6
  6. package/es/chat/src/Chat.js +54 -14
  7. package/es/chat/src/ChatListItems.d.ts +7782 -0
  8. package/es/chat/src/ChatListItems.js +188 -0
  9. package/es/chat/src/ChatMessages.d.ts +7805 -0
  10. package/es/chat/src/ChatMessages.js +325 -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 +10 -1
  16. package/es/chat/src/styles/index.cssr.js +16 -16
  17. package/es/chat/styles/light.d.ts +1 -1
  18. package/es/chat/styles/light.js +15 -3
  19. package/es/locales/common/arDZ.js +2 -1
  20. package/es/locales/common/deDE.js +2 -1
  21. package/es/locales/common/enGB.js +2 -1
  22. package/es/locales/common/enUS.d.ts +1 -0
  23. package/es/locales/common/enUS.js +2 -1
  24. package/es/locales/common/eo.js +2 -1
  25. package/es/locales/common/esAR.js +2 -1
  26. package/es/locales/common/faIR.js +2 -1
  27. package/es/locales/common/frFR.js +2 -1
  28. package/es/locales/common/idID.js +2 -1
  29. package/es/locales/common/itIT.js +2 -1
  30. package/es/locales/common/jaJP.js +2 -1
  31. package/es/locales/common/koKR.js +2 -1
  32. package/es/locales/common/nbNO.js +2 -1
  33. package/es/locales/common/nlNL.js +2 -1
  34. package/es/locales/common/plPL.js +2 -1
  35. package/es/locales/common/ptBR.js +2 -1
  36. package/es/locales/common/ruRU.js +2 -1
  37. package/es/locales/common/skSK.js +2 -1
  38. package/es/locales/common/svSE.js +2 -1
  39. package/es/locales/common/thTH.js +2 -1
  40. package/es/locales/common/trTR.js +2 -1
  41. package/es/locales/common/ukUA.js +2 -1
  42. package/es/locales/common/viVN.js +2 -1
  43. package/es/locales/common/zhCN.js +2 -1
  44. package/es/locales/common/zhTW.js +2 -1
  45. package/es/version.d.ts +1 -1
  46. package/es/version.js +1 -1
  47. package/lib/chat/index.d.ts +6 -1
  48. package/lib/chat/index.js +9 -1
  49. package/lib/chat/src/Chat.d.ts +19 -6
  50. package/lib/chat/src/Chat.js +53 -13
  51. package/lib/chat/src/ChatListItems.d.ts +7782 -0
  52. package/lib/chat/src/ChatListItems.js +194 -0
  53. package/lib/chat/src/ChatMessages.d.ts +7805 -0
  54. package/lib/chat/src/ChatMessages.js +331 -0
  55. package/lib/chat/src/ChatParts/ChatAttachment.js +4 -3
  56. package/lib/chat/src/ChatParts/MainArea.d.ts +0 -2
  57. package/lib/chat/src/ChatParts/MainArea.js +107 -228
  58. package/lib/chat/src/ChatParts/Sidebar.js +17 -78
  59. package/lib/chat/src/interface.d.ts +10 -1
  60. package/lib/chat/src/styles/index.cssr.js +16 -16
  61. package/lib/chat/styles/light.d.ts +1 -1
  62. package/lib/chat/styles/light.js +15 -3
  63. package/lib/locales/common/arDZ.js +2 -1
  64. package/lib/locales/common/deDE.js +2 -1
  65. package/lib/locales/common/enGB.js +2 -1
  66. package/lib/locales/common/enUS.d.ts +1 -0
  67. package/lib/locales/common/enUS.js +2 -1
  68. package/lib/locales/common/eo.js +2 -1
  69. package/lib/locales/common/esAR.js +2 -1
  70. package/lib/locales/common/faIR.js +2 -1
  71. package/lib/locales/common/frFR.js +2 -1
  72. package/lib/locales/common/idID.js +2 -1
  73. package/lib/locales/common/itIT.js +2 -1
  74. package/lib/locales/common/jaJP.js +2 -1
  75. package/lib/locales/common/koKR.js +2 -1
  76. package/lib/locales/common/nbNO.js +2 -1
  77. package/lib/locales/common/nlNL.js +2 -1
  78. package/lib/locales/common/plPL.js +2 -1
  79. package/lib/locales/common/ptBR.js +2 -1
  80. package/lib/locales/common/ruRU.js +2 -1
  81. package/lib/locales/common/skSK.js +2 -1
  82. package/lib/locales/common/svSE.js +2 -1
  83. package/lib/locales/common/thTH.js +2 -1
  84. package/lib/locales/common/trTR.js +2 -1
  85. package/lib/locales/common/ukUA.js +2 -1
  86. package/lib/locales/common/viVN.js +2 -1
  87. package/lib/locales/common/zhCN.js +2 -1
  88. package/lib/locales/common/zhTW.js +2 -1
  89. package/lib/version.d.ts +1 -1
  90. package/lib/version.js +1 -1
  91. package/package.json +1 -1
  92. package/volar.d.ts +2 -0
  93. package/web-types.json +149 -1
  94. package/es/chat/src/ChatGlobalState.d.ts +0 -13
  95. package/es/chat/src/ChatGlobalState.js +0 -32
  96. package/lib/chat/src/ChatGlobalState.d.ts +0 -13
  97. 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, mergedThemeRef, 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`, theme: mergedThemeRef.value.peers.Typography, themeOverrides: mergedThemeRef.value.peerOverrides.Typography }, {
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, { theme: mergedThemeRef.value.peers.Button, themeOverrides: mergedThemeRef.value.peerOverrides.Button, 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, { theme: mergedThemeRef.value.peers.Icon, themeOverrides: mergedThemeRef.value.peerOverrides.Icon }), {
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, { theme: mergedThemeRef.value.peers.Button, themeOverrides: mergedThemeRef.value.peerOverrides.Button, 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, { theme: mergedThemeRef.value.peers.Icon, themeOverrides: mergedThemeRef.value.peerOverrides.Icon }), {
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, { theme: mergedThemeRef.value.peers.Button, themeOverrides: mergedThemeRef.value.peerOverrides.Button, 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, { theme: mergedThemeRef.value.peers.Button, themeOverrides: mergedThemeRef.value.peerOverrides.Button, onClick: handleClick }), {
266
+ default: () => ((0, vue_1.h)(icon_1.UIcon, Object.assign({ size: 24 }, footerIconPropsRef.value, { theme: mergedThemeRef.value.peers.Icon, themeOverrides: mergedThemeRef.value.peerOverrides.Icon }), {
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, { theme: mergedThemeRef.value.peers.Input, themeOverrides: mergedThemeRef.value.peerOverrides.Input, 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, mergedThemeRef, 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: "tiny", theme: mergedThemeRef.value.peers.Select, themeOverrides: mergedThemeRef.value.peerOverrides.Select }))),
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
  });
@@ -6,6 +6,8 @@ import type { IconProps } from '../../icon';
6
6
  import type { BadgeProps } from '../../badge';
7
7
  import { EmptyProps } from '../../empty';
8
8
  import { InputProps } from '../../input';
9
+ import type { ChatTheme } from '../styles';
10
+ import type { MergedTheme } from '../../_mixins';
9
11
  export declare enum MessageStatus {
10
12
  READ = "read",
11
13
  UNREAD = "unread",
@@ -69,6 +71,7 @@ export interface ChatMessageData {
69
71
  uploadProps?: Partial<UploadProps>;
70
72
  senderAvatar?: string | (() => VNodeChild);
71
73
  senderName?: string | (() => VNodeChild);
74
+ markType?: ChatMarkType;
72
75
  }
73
76
  export interface ChatMessageProps {
74
77
  id: ChatId;
@@ -109,7 +112,7 @@ export interface ChatAttachment {
109
112
  type: ChatMessageType.FILE;
110
113
  name: string;
111
114
  url: string;
112
- size?: number;
115
+ size?: number | string;
113
116
  thumbnail?: string | (() => VNodeChild);
114
117
  preview?: string | (() => VNodeChild);
115
118
  status?: 'pending' | 'uploading' | 'finished' | 'error';
@@ -146,6 +149,7 @@ export interface ChatProps {
146
149
  retryText?: string;
147
150
  typingText?: string;
148
151
  closeButtonText?: string;
152
+ unreadNotificationText?: string;
149
153
  chatItemsLoading?: boolean;
150
154
  chatItemsLoadingCount?: number;
151
155
  messagesLoading?: boolean;
@@ -240,6 +244,7 @@ export interface ChatListInst {
240
244
  }
241
245
  export declare const chatInjectionKey: InjectionKey<{
242
246
  mergedClsPrefixRef: Ref<string>;
247
+ mergedThemeRef: Ref<MergedTheme<ChatTheme>>;
243
248
  chatItemsRef: Ref<ChatListItemData[] | undefined>;
244
249
  selectedChatIdRef: Ref<ChatId | undefined>;
245
250
  selectedChatRef: Ref<ChatListItemData | undefined>;
@@ -269,6 +274,10 @@ export declare const chatInjectionKey: InjectionKey<{
269
274
  retryTextRef: Ref<string>;
270
275
  typingTextRef: Ref<string>;
271
276
  closeButtonTextRef: Ref<string>;
277
+ unreadNotificationTextRef: Ref<string>;
278
+ notificationsShownSetRef: Ref<Set<ChatId>>;
279
+ unreadCountsBeforeReadRef: Ref<Record<ChatId, number>>;
280
+ markNotificationShown: (chatId: ChatId) => void;
272
281
  handleChatSelect: (chatId: ChatId) => void;
273
282
  handleMessageSend: (content: string, attachments?: ChatAttachment[]) => void;
274
283
  handleMessageRetry: (message: ChatMessageData) => void;