@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
@@ -9,8 +9,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { h, defineComponent, inject, computed, ref, watch, nextTick, onMounted, Fragment } from 'vue';
11
11
  import { MessageStatus, ChatMessageType, chatInjectionKey } from '../interface';
12
- import { ChatGlobalState } from '../ChatGlobalState';
13
- import ChatAttachmentComponent from './ChatAttachment';
14
12
  import { UInput } from '../../../input';
15
13
  import { UButton } from '../../../button';
16
14
  import { UIcon } from '../../../icon';
@@ -19,21 +17,14 @@ import { UUpload, UUploadTrigger } from '../../../upload';
19
17
  import { UFlex } from '../../../flex';
20
18
  import { resolveSlot } from '../../../_utils';
21
19
  import { UText } from '../../../typography';
22
- import { USkeleton } from '../../../skeleton';
23
- import { CheckmarkDoneSharp, Refresh, MdTime, ArrowHookUpRight, PersonNote, AttachIcon } from '../../../_internal/icons';
20
+ import UChatMessages from '../ChatMessages';
21
+ import { ArrowHookUpRight, PersonNote, AttachIcon } from '../../../_internal/icons';
24
22
  const SCROLL_DELAY = 50;
25
23
  const SENDING_DELAY = 100;
26
- const getChatGlobalState = () => ChatGlobalState.getInstance();
27
- const statusIconMapper = {
28
- [MessageStatus.READ]: CheckmarkDoneSharp,
29
- [MessageStatus.PENDING]: MdTime,
30
- [MessageStatus.RETRY]: Refresh,
31
- [MessageStatus.UNREAD]: CheckmarkDoneSharp
32
- };
33
24
  export default defineComponent({
34
25
  name: 'ChatMainArea',
35
26
  setup(_, { slots }) {
36
- const { mergedClsPrefixRef, selectedChatRef, messagesRef, typingChatIdsRef, messagesLoadingRef, messagesLoadingCountRef, headerButtonPropsRef, headerIconPropsRef, messageUploadPropsRef, footerInputPropsRef, footerButtonPropsRef, footerUploadPropsRef, footerIconPropsRef, inputPlaceholderRef, retryTextRef, typingTextRef, closeButtonTextRef, handleMessageSend, handleMessageRetry, onChatClose, onChatShare, onUserProfile
27
+ 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
37
28
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
38
29
  } = inject(chatInjectionKey);
39
30
  const messagesBodyRef = ref();
@@ -49,17 +40,18 @@ export default defineComponent({
49
40
  const hasUnreadMessages = ref(false);
50
41
  const unreadCountOnOpen = ref(0);
51
42
  const chatInputs = ref({});
43
+ const lastMessageId = ref(null);
52
44
  watch(selectedChatRef, (newChat, oldChat) => {
53
45
  if (newChat && newChat.id !== (oldChat === null || oldChat === void 0 ? void 0 : oldChat.id)) {
54
46
  inputValue.value = chatInputs.value[newChat.id] || '';
55
- unreadCountOnOpen.value = unreadMessagesCount.value;
56
- const globalState = getChatGlobalState();
57
- globalState.markChatOpened(newChat.id);
58
- if (unreadCountOnOpen.value > 0 &&
59
- !globalState.hasNotificationShown(newChat.id)) {
47
+ const unreadBeforeRead = unreadCountsBeforeReadRef.value[newChat.id] || 0;
48
+ unreadCountOnOpen.value = unreadBeforeRead;
49
+ lastMessageId.value = null;
50
+ if (unreadBeforeRead > 0 &&
51
+ !notificationsShownSetRef.value.has(newChat.id)) {
60
52
  hasUnreadMessages.value = true;
61
53
  showNotificationManually.value = true;
62
- globalState.markNotificationShown(newChat.id);
54
+ markNotificationShown(newChat.id);
63
55
  }
64
56
  else {
65
57
  hasUnreadMessages.value = false;
@@ -68,29 +60,41 @@ export default defineComponent({
68
60
  void nextTick(() => {
69
61
  scrollToBottom();
70
62
  });
63
+ setTimeout(() => {
64
+ scrollToBottom();
65
+ }, SCROLL_DELAY);
71
66
  }
72
67
  }, { immediate: true });
73
- watch(messagesRef, (newMessages, oldMessages) => {
74
- if (newMessages &&
75
- oldMessages &&
76
- newMessages.length > oldMessages.length) {
77
- if (selectedChatRef.value) {
78
- const globalState = getChatGlobalState();
79
- if (globalState.hasNotificationShown(selectedChatRef.value.id)) {
80
- showNotificationManually.value = false;
81
- }
82
- }
68
+ watch(messagesRef, (newMessages) => {
69
+ if (!newMessages || newMessages.length === 0) {
70
+ lastMessageId.value = null;
71
+ return;
72
+ }
73
+ const currentLastMessage = newMessages[newMessages.length - 1];
74
+ const currentLastId = currentLastMessage === null || currentLastMessage === void 0 ? void 0 : currentLastMessage.id;
75
+ if (currentLastId !== lastMessageId.value &&
76
+ lastMessageId.value !== null) {
83
77
  void nextTick(() => {
84
78
  scrollToBottom();
85
79
  });
80
+ setTimeout(() => {
81
+ scrollToBottom();
82
+ }, SCROLL_DELAY);
83
+ if (currentLastMessage &&
84
+ !currentLastMessage.isOwn &&
85
+ currentLastMessage.status === MessageStatus.UNREAD) {
86
+ unreadCountOnOpen.value = unreadMessagesCount.value;
87
+ }
86
88
  }
87
- }, { deep: true });
89
+ lastMessageId.value = currentLastId !== null && currentLastId !== void 0 ? currentLastId : null;
90
+ }, { deep: true, flush: 'post' });
88
91
  watch(unreadMessagesCount, (newCount, oldCount) => {
89
- if (selectedChatRef.value) {
90
- if (newCount === 0 && oldCount > 0) {
91
- showNotificationManually.value = false;
92
- hasUnreadMessages.value = false;
93
- }
92
+ if (selectedChatRef.value && newCount === 0 && oldCount > 0) {
93
+ showNotificationManually.value = false;
94
+ hasUnreadMessages.value = false;
95
+ const newSet = new Set(notificationsShownSetRef.value);
96
+ newSet.delete(selectedChatRef.value.id);
97
+ notificationsShownSetRef.value = newSet;
94
98
  }
95
99
  });
96
100
  const showUnreadNotification = computed(() => {
@@ -100,189 +104,63 @@ export default defineComponent({
100
104
  void nextTick(() => {
101
105
  scrollToBottom();
102
106
  });
107
+ setTimeout(() => {
108
+ scrollToBottom();
109
+ }, SCROLL_DELAY);
103
110
  });
104
111
  const scrollToBottom = () => {
105
112
  const el = messagesBodyRef.value;
106
113
  if (!el)
107
114
  return;
108
- if ('scrollTo' in el && typeof el.scrollTo === 'function') {
109
- el.scrollTo({ top: 999999, behavior: 'smooth' });
110
- return;
111
- }
112
115
  if ('$el' in el && el.$el instanceof HTMLElement) {
113
- const scrollContainer = el.$el.querySelector('.u-scrollbar-content') || el.$el;
114
- scrollContainer.scrollTop = scrollContainer.scrollHeight;
116
+ const scrollContainer = el.$el.querySelector('.u-scrollbar-content');
117
+ if (scrollContainer) {
118
+ scrollContainer.scrollTop = scrollContainer.scrollHeight;
119
+ return;
120
+ }
121
+ }
122
+ if ('scrollTo' in el && typeof el.scrollTo === 'function') {
123
+ el.scrollTo({ top: 999999, behavior: 'auto' });
115
124
  return;
116
125
  }
117
126
  if ('scrollTop' in el && 'scrollHeight' in el) {
118
127
  el.scrollTop = el.scrollHeight;
119
128
  }
120
129
  };
121
- const renderUnreadNotification = () => {
122
- if (!showUnreadNotification.value)
123
- return null;
124
- return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__unread-notification` },
125
- h("span", null,
126
- unreadCountOnOpen.value,
127
- " \u043D\u043E\u0432\u044B\u0445 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F")));
128
- };
129
130
  const renderHeader = () => {
130
- var _a;
131
131
  return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__header` },
132
- h(UFlex, { justify: "space-between", align: "flex-start" },
133
- h(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'),
134
- h(UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__header-actions` }, resolveSlot(slots.headerActions, () => [
135
- h(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); } }),
136
- h(UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value),
137
- h(ArrowHookUpRight, null))),
138
- h(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); } }),
139
- h(UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value),
140
- h(PersonNote, null))),
141
- h(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)
142
- ])))));
143
- };
144
- const renderDateSeparator = (date) => {
145
- return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__date-separator` },
146
- h("span", null, date)));
147
- };
148
- const renderMessage = (message) => {
149
- const isOwn = message.isOwn;
150
- const attachments = message.attachment
151
- ? Array.isArray(message.attachment)
152
- ? message.attachment
153
- : [message.attachment]
154
- : [];
155
- return (h("div", { key: message.id, class: [
156
- `${mergedClsPrefixRef.value}-chat-main__message`,
157
- isOwn
158
- ? `${mergedClsPrefixRef.value}-chat-main__message--own`
159
- : `${mergedClsPrefixRef.value}-chat-main__message--other`
160
- ] },
161
- h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-wrapper` },
162
- message.content || attachments.length > 1 ? (h("div", { class: [
163
- `${mergedClsPrefixRef.value}-chat-main__message-bubble`,
164
- isOwn
165
- ? `${mergedClsPrefixRef.value}-chat-main__message-bubble--own`
166
- : `${mergedClsPrefixRef.value}-chat-main__message-bubble--other`
167
- ] },
168
- attachments.length > 0 && (h(ChatAttachmentComponent, { message: message, attachments: attachments, uploadProps: messageUploadPropsRef.value, withPadding: true }, {
169
- default: slots.messageAttachment,
170
- 'upload-file-title': slots.messageAttachmentTitle,
171
- 'upload-file-subtitle': slots.messageAttachmentSubtitle
172
- })),
173
- message.content && (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-text` }, message.content)))) : attachments.length === 1 ? (h(ChatAttachmentComponent, { message: message, attachments: attachments, uploadProps: messageUploadPropsRef.value }, {
174
- default: slots.messageAttachment,
175
- 'upload-file-title': slots.messageAttachmentTitle,
176
- 'upload-file-subtitle': slots.messageAttachmentSubtitle
177
- })) : null,
178
- h("div", { class: [
179
- `${mergedClsPrefixRef.value}-chat-main__message-meta`,
180
- isOwn
181
- ? `${mergedClsPrefixRef.value}-chat-main__message-meta--own`
182
- : `${mergedClsPrefixRef.value}-chat-main__message-meta--other`,
183
- message.status === MessageStatus.RETRY &&
184
- `${mergedClsPrefixRef.value}-chat-main__message-meta--retry`
185
- ] }, message.status === MessageStatus.RETRY ? (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-retry`, onClick: () => {
186
- handleMessageRetry(message);
187
- }, style: { cursor: 'pointer' } },
188
- h(UIcon, { size: 16, component: statusIconMapper[MessageStatus.RETRY], class: `${mergedClsPrefixRef.value}-chat-main__message-retry-icon` }),
189
- h("span", { class: `${mergedClsPrefixRef.value}-chat-main__message-retry-text` }, retryTextRef.value))) : (h(Fragment, null,
190
- h("span", { class: `${mergedClsPrefixRef.value}-chat-main__message-time` }, message.timestamp),
191
- isOwn && message.status && (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-status` }, slots.messageStatus
192
- ? slots.messageStatus(message)
193
- : statusIconMapper[message.status] && (h(UIcon, { size: 16, component: statusIconMapper[message.status], class: [
194
- `${mergedClsPrefixRef.value}-chat-main__message-status-icon`,
195
- `${mergedClsPrefixRef.value}-chat-main__message-status-icon--${String(message.status)}`
196
- ] }))))))))));
197
- };
198
- const renderTypingIndicator = () => {
199
- return (h("div", { class: [
200
- `${mergedClsPrefixRef.value}-chat-main__message`,
201
- `${mergedClsPrefixRef.value}-chat-main__message--other`
202
- ] },
203
- h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-wrapper` },
204
- h("div", { class: [
205
- `${mergedClsPrefixRef.value}-chat-main__message-bubble`,
206
- `${mergedClsPrefixRef.value}-chat-main__message-bubble--other`,
207
- `${mergedClsPrefixRef.value}-chat-main__message-bubble--typing`
208
- ] }),
209
- h("div", { class: [
210
- `${mergedClsPrefixRef.value}-chat-main__message-meta`,
211
- `${mergedClsPrefixRef.value}-chat-main__message-meta--other`
212
- ] },
213
- h("span", { class: `${mergedClsPrefixRef.value}-chat-main__message-time` }, typingTextRef.value)))));
214
- };
215
- const renderSkeletonMessage = (isOwn, index) => {
216
- return (h("div", { key: `skeleton-${index}`, class: [
217
- `${mergedClsPrefixRef.value}-chat-main__message`,
218
- isOwn
219
- ? `${mergedClsPrefixRef.value}-chat-main__message--own`
220
- : `${mergedClsPrefixRef.value}-chat-main__message--other`
221
- ] },
222
- h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-wrapper` },
223
- h("div", { class: [
224
- `${mergedClsPrefixRef.value}-chat-main__message-bubble`,
225
- isOwn
226
- ? `${mergedClsPrefixRef.value}-chat-main__message-bubble--own`
227
- : `${mergedClsPrefixRef.value}-chat-main__message-bubble--other`
228
- ] },
229
- h("div", { class: `${mergedClsPrefixRef.value}-chat-main__message-text` },
230
- h("div", { style: { width: '376px', height: '20px' } }))),
231
- h("div", { class: [
232
- `${mergedClsPrefixRef.value}-chat-main__message-meta`,
233
- isOwn
234
- ? `${mergedClsPrefixRef.value}-chat-main__message-meta--own`
235
- : `${mergedClsPrefixRef.value}-chat-main__message-meta--other`
236
- ] },
237
- h(USkeleton, { style: { width: '36px', height: '20px', borderRadius: '4px' } })))));
132
+ h(UFlex, { justify: "space-between", align: "flex-start" }, {
133
+ default: () => (h(Fragment, null,
134
+ h(UText, { variant: "heading-s-bold", class: `${mergedClsPrefixRef.value}-chat-main__header-title`, theme: mergedThemeRef.value.peers.Typography, themeOverrides: mergedThemeRef.value.peerOverrides.Typography }, {
135
+ default: () => { var _a; return ((_a = selectedChatRef.value) === null || _a === void 0 ? void 0 : _a.title) || 'Select a chat'; }
136
+ }),
137
+ h(UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__header-actions` }, {
138
+ default: () => resolveSlot(slots.headerActions, () => [
139
+ h(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); } }), {
140
+ default: () => (h(UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value, { theme: mergedThemeRef.value.peers.Icon, themeOverrides: mergedThemeRef.value.peerOverrides.Icon }), {
141
+ default: () => h(ArrowHookUpRight, null)
142
+ }))
143
+ }),
144
+ h(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); } }), {
145
+ default: () => (h(UIcon, Object.assign({ size: 20 }, headerIconPropsRef.value, { theme: mergedThemeRef.value.peers.Icon, themeOverrides: mergedThemeRef.value.peerOverrides.Icon }), {
146
+ default: () => h(PersonNote, null)
147
+ }))
148
+ }),
149
+ h(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); } }), {
150
+ default: () => closeButtonTextRef.value
151
+ })
152
+ ])
153
+ })))
154
+ })));
238
155
  };
239
156
  const renderMessages = () => {
240
- var _a, _b;
241
- if (messagesLoadingRef.value) {
242
- return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__messages` }, Array.from({ length: messagesLoadingCountRef.value || 5 }).map((_, index) => {
243
- const isOwn = index % 2 === 0;
244
- return renderSkeletonMessage(isOwn, index);
245
- })));
246
- }
247
- const messagesWithDates = [];
248
- let currentDate = '';
249
- let unreadNotificationInserted = false;
250
- (_a = messagesRef.value) === null || _a === void 0 ? void 0 : _a.forEach((message, index) => {
251
- const messageDate = message.date || '';
252
- if (messageDate !== currentDate) {
253
- messagesWithDates.push({
254
- type: 'date-separator',
255
- date: messageDate,
256
- id: `date-${String(index)}`
257
- });
258
- currentDate = messageDate;
259
- }
260
- if (!unreadNotificationInserted &&
261
- !message.isOwn &&
262
- message.status === MessageStatus.UNREAD &&
263
- showUnreadNotification.value) {
264
- messagesWithDates.push({
265
- type: 'unread-notification',
266
- id: 'unread-notification'
267
- });
268
- unreadNotificationInserted = true;
269
- }
270
- messagesWithDates.push(Object.assign({ type: 'message' }, message));
271
- });
272
- return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__messages-container` },
273
- messagesWithDates.map((item) => {
274
- var _a;
275
- if (item.type === 'date-separator') {
276
- return renderDateSeparator((_a = item.date) !== null && _a !== void 0 ? _a : '');
277
- }
278
- if (item.type === 'unread-notification') {
279
- return renderUnreadNotification();
280
- }
281
- return renderMessage(item);
282
- }),
283
- selectedChatRef.value &&
284
- ((_b = typingChatIdsRef.value) === null || _b === void 0 ? void 0 : _b.includes(selectedChatRef.value.id)) &&
285
- renderTypingIndicator()));
157
+ var _a;
158
+ return (h(UChatMessages, { 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 }, {
159
+ messageAttachment: slots.messageAttachment,
160
+ messageAttachmentTitle: slots.messageAttachmentTitle,
161
+ messageAttachmentSubtitle: slots.messageAttachmentSubtitle,
162
+ messageStatus: slots.messageStatus
163
+ }));
286
164
  };
287
165
  const isSending = ref(false);
288
166
  const handleSendMessage = () => __awaiter(this, void 0, void 0, function* () {
@@ -316,12 +194,8 @@ export default defineComponent({
316
194
  inputValue.value = '';
317
195
  attachmentFileList.value = [];
318
196
  chatInputs.value[selectedChatRef.value.id] = '';
319
- const globalState = getChatGlobalState();
320
- if (globalState.hasNotificationShown(selectedChatRef.value.id)) {
321
- globalState.markNotificationShown(selectedChatRef.value.id);
322
- showNotificationManually.value = false;
323
- hasUnreadMessages.value = false;
324
- }
197
+ hasUnreadMessages.value = false;
198
+ showNotificationManually.value = false;
325
199
  void nextTick(() => {
326
200
  scrollToBottom();
327
201
  });
@@ -379,32 +253,35 @@ export default defineComponent({
379
253
  };
380
254
  const renderFooter = () => {
381
255
  return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main__footer` },
382
- h(UUpload, Object.assign({ abstract: true, multiple: true, defaultUpload: false, fileList: attachmentFileList.value, onUpdateFileList: handleFileListUpdate }, footerUploadPropsRef.value),
383
- h(UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__input-container` },
384
- h(UUploadTrigger, { abstract: true }, {
385
- default: ({ handleClick }) => (h(UButton, Object.assign({ secondary: true, size: "large", class: `${mergedClsPrefixRef.value}-chat-main__attach-btn` }, footerButtonPropsRef.value, { onClick: handleClick }),
386
- h(UIcon, Object.assign({ size: 24 }, footerIconPropsRef.value),
387
- h(AttachIcon, null))))
388
- }),
389
- h(UInput, Object.assign({ ref: "inputRef", value: inputValue.value, placeholder: inputPlaceholderRef.value, class: `${mergedClsPrefixRef.value}-chat-main__input` }, footerInputPropsRef.value, { onUpdateValue: (value) => {
390
- inputValue.value = value;
391
- if (selectedChatRef.value) {
392
- chatInputs.value[selectedChatRef.value.id] = value;
393
- }
394
- }, onKeydown: (e) => {
395
- if (e.key === 'Enter' && !e.shiftKey) {
396
- e.preventDefault();
397
- e.stopPropagation();
398
- void handleSendMessage();
399
- }
400
- } }))))));
256
+ h(UUpload, Object.assign({ abstract: true, multiple: true, defaultUpload: false, fileList: attachmentFileList.value, onUpdateFileList: handleFileListUpdate }, footerUploadPropsRef.value), {
257
+ default: () => (h(UFlex, { align: "center", size: "small", class: `${mergedClsPrefixRef.value}-chat-main__input-container` }, {
258
+ default: () => (h(Fragment, null,
259
+ h(UUploadTrigger, { abstract: true }, {
260
+ default: ({ handleClick }) => (h(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 }), {
261
+ default: () => (h(UIcon, Object.assign({ size: 24 }, footerIconPropsRef.value, { theme: mergedThemeRef.value.peers.Icon, themeOverrides: mergedThemeRef.value.peerOverrides.Icon }), {
262
+ default: () => h(AttachIcon, null)
263
+ }))
264
+ }))
265
+ }),
266
+ h(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) => {
267
+ inputValue.value = value;
268
+ if (selectedChatRef.value) {
269
+ chatInputs.value[selectedChatRef.value.id] = value;
270
+ }
271
+ }, onKeydown: (e) => {
272
+ if (e.key === 'Enter' && !e.shiftKey) {
273
+ e.preventDefault();
274
+ e.stopPropagation();
275
+ void handleSendMessage();
276
+ }
277
+ } }))))
278
+ }))
279
+ })));
401
280
  };
402
281
  return {
403
282
  renderHeader,
404
283
  renderMessages,
405
284
  renderFooter,
406
- renderUnreadNotification,
407
- showUnreadNotification,
408
285
  messagesBodyRef,
409
286
  inputRef,
410
287
  inputValue,
@@ -417,7 +294,9 @@ export default defineComponent({
417
294
  const { mergedClsPrefixRef } = inject(chatInjectionKey);
418
295
  return (h("div", { class: `${mergedClsPrefixRef.value}-chat-main` },
419
296
  this.renderHeader(),
420
- h(UScrollbar, { ref: "messagesBodyRef", class: `${mergedClsPrefixRef.value}-chat-main__body` }, this.renderMessages()),
297
+ h(UScrollbar, { ref: "messagesBodyRef", class: `${mergedClsPrefixRef.value}-chat-main__body` }, {
298
+ default: () => this.renderMessages()
299
+ }),
421
300
  this.renderFooter()));
422
301
  }
423
302
  });
@@ -1,98 +1,34 @@
1
- import { h, defineComponent, inject } from 'vue';
2
- import { chatInjectionKey, MessageStatus } from '../interface';
3
- import { ChatGlobalState } from '../ChatGlobalState';
1
+ import { h, defineComponent, inject, Fragment } from 'vue';
2
+ import { chatInjectionKey } from '../interface';
4
3
  import { UFlex } from '../../../flex';
5
- import { UEmpty } from '../../../empty';
6
- import { UAvatar } from '../../../avatar';
7
4
  import { USelect } from '../../../select';
8
- import { UListItem, UList } from '../../../list';
9
- import { UBadge } from '../../../badge';
10
- import { UIcon } from '../../../icon';
11
- import { CheckmarkDoneSharp, MdTime, PersonOutline, Refresh } from '../../../_internal/icons';
12
- const statusIconMapper = {
13
- [MessageStatus.READ]: CheckmarkDoneSharp,
14
- [MessageStatus.PENDING]: MdTime,
15
- [MessageStatus.RETRY]: Refresh,
16
- [MessageStatus.UNREAD]: CheckmarkDoneSharp
17
- };
5
+ import UChatListItems from '../ChatListItems';
18
6
  export default defineComponent({
19
7
  name: 'ChatSidebar',
20
8
  setup(props, { slots }) {
21
9
  return { slots };
22
10
  },
23
11
  render() {
24
- var _a, _b;
25
12
  const { slots } = this;
26
- const { mergedClsPrefixRef, chatItemsRef, chatItemsLoadingRef, chatItemsLoadingCountRef, listEmptyPropsRef, selectedChatIdRef, typingChatIdsRef, typingTextRef, listItemAvatarPropsRef, listItemBadgePropsRef, handleChatSelect
13
+ const { mergedClsPrefixRef, mergedThemeRef, chatItemsRef, chatItemsLoadingRef, chatItemsLoadingCountRef, listEmptyPropsRef, selectedChatIdRef, typingChatIdsRef, typingTextRef, listItemAvatarPropsRef, listItemBadgePropsRef, notificationsShownSetRef, handleChatSelect
27
14
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
28
15
  } = inject(chatInjectionKey);
29
16
  const renderListHeader = () => {
30
- var _a, _b;
31
17
  return (h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header` },
32
- h(UFlex, { align: "center", justify: "space-between", style: { width: '100%' } },
33
- h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-main` }, ((_a = slots.sidebarHeaderMain) === null || _a === void 0 ? void 0 : _a.call(slots)) || h(USelect, { round: true })),
34
- h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-actions` }, (_b = slots.sidebarHeaderActions) === null || _b === void 0 ? void 0 : _b.call(slots)))));
35
- };
36
- const renderChatItem = (item) => {
37
- var _a, _b;
38
- const isSelected = selectedChatIdRef.value === item.id;
39
- const isTyping = (_b = (_a = typingChatIdsRef.value) === null || _a === void 0 ? void 0 : _a.includes(item.id)) !== null && _b !== void 0 ? _b : false;
40
- return (h(UListItem, { key: item.id, showIcon: false, onClick: () => {
41
- handleChatSelect(item.id);
42
- }, class: [
43
- `${mergedClsPrefixRef.value}-chat-sidebar__item`,
44
- isSelected &&
45
- `${mergedClsPrefixRef.value}-chat-sidebar__item--selected`,
46
- isTyping && `${mergedClsPrefixRef.value}-chat-sidebar__item--typing`
47
- ] }, {
48
- prefix: () => {
49
- var _a;
50
- return (h(UAvatar, Object.assign({ size: "medium", src: typeof item.avatar === 'string' ? item.avatar : undefined }, listItemAvatarPropsRef.value), typeof item.avatar === 'function'
51
- ? item.avatar()
52
- : typeof item.title === 'string'
53
- ? (_a = item.title.charAt(0)) === null || _a === void 0 ? void 0 : _a.toUpperCase()
54
- : '?'));
55
- },
56
- header: () => (h("span", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-title` }, typeof item.title === 'function' ? item.title() : item.title)),
57
- description: () => (h("span", { class: [
58
- `${mergedClsPrefixRef.value}-chat-sidebar__item-subtitle`,
59
- isTyping && 'typing'
60
- ], style: {
61
- display: 'block',
62
- overflow: 'hidden',
63
- textOverflow: 'ellipsis',
64
- whiteSpace: 'nowrap',
65
- minWidth: 0,
66
- maxWidth: '100%'
67
- } }, isTyping
68
- ? typingTextRef.value
69
- : typeof item.subtitle === 'string'
70
- ? item.subtitle
71
- : typeof item.subtitle === 'function'
72
- ? item.subtitle()
73
- : item.subtitle)),
74
- suffix: () => {
75
- const getChatGlobalState = () => ChatGlobalState.getInstance();
76
- const globalState = getChatGlobalState();
77
- const wasOpened = globalState.isChatOpened(item.id);
78
- const displayUnreadCount = wasOpened ? 0 : item.unreadCount || 0;
79
- const hasUnreadIncoming = displayUnreadCount > 0;
80
- const lastMessageIsOwn = item.lastMessageIsOwn;
81
- return (h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-indicators` },
82
- h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-time` }, item.datetime),
83
- h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__item-status` },
84
- lastMessageIsOwn &&
85
- (slots.chatItemStatus ? (slots.chatItemStatus(item)) : item.messageStatus &&
86
- statusIconMapper[item.messageStatus] ? (h(UIcon, { size: 16, component: statusIconMapper[item.messageStatus], class: [
87
- `${mergedClsPrefixRef.value}-chat-sidebar__item-status-icon`,
88
- `${mergedClsPrefixRef.value}-chat-sidebar__item-status-icon--${item.messageStatus}`
89
- ] })) : null),
90
- !lastMessageIsOwn && hasUnreadIncoming && (h(UBadge, Object.assign({ value: displayUnreadCount }, listItemBadgePropsRef.value))))));
91
- }
92
- }));
18
+ h(UFlex, { align: "center", justify: "space-between", class: `${mergedClsPrefixRef.value}-chat-sidebar__header-container`, style: { width: '100%' } }, {
19
+ default: () => {
20
+ var _a, _b;
21
+ return (h(Fragment, null,
22
+ h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-main` }, ((_a = slots.sidebarHeaderMain) === null || _a === void 0 ? void 0 : _a.call(slots)) || (h(USelect, { round: true, size: "tiny", theme: mergedThemeRef.value.peers.Select, themeOverrides: mergedThemeRef.value.peerOverrides.Select }))),
23
+ h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__header-actions` }, (_b = slots.sidebarHeaderActions) === null || _b === void 0 ? void 0 : _b.call(slots))));
24
+ }
25
+ })));
93
26
  };
94
27
  return (h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar` },
95
28
  renderListHeader(),
96
- h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__content` }, chatItemsLoadingRef.value ? (h(UList, { loading: true }, Array.from({ length: chatItemsLoadingCountRef.value || 10 }).map((_, index) => (h(UListItem, { key: index, avatar: { icon: PersonOutline }, description: { text: 'Loading...' }, header: { text: 'Loading...' } }))))) : ((_a = chatItemsRef.value) === null || _a === void 0 ? void 0 : _a.length) ? (h(UList, { showIcon: false }, (_b = chatItemsRef.value) === null || _b === void 0 ? void 0 : _b.map((item) => renderChatItem(item)))) : (h(UEmpty, Object.assign({}, listEmptyPropsRef.value))))));
29
+ h("div", { class: `${mergedClsPrefixRef.value}-chat-sidebar__content` },
30
+ h(UChatListItems, { 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 }, {
31
+ chatItemStatus: slots.chatItemStatus
32
+ }))));
97
33
  }
98
34
  });
@@ -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;