@webitel/ui-chats 0.0.3 → 0.0.5

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 (58) hide show
  1. package/package.json +61 -61
  2. package/src/locale/en/en.ts +8 -8
  3. package/src/ui/chat-footer/components/chat-footer-wrapper.vue +2 -4
  4. package/src/ui/chat-footer/modules/user-input/components/actions/attach-files-action.vue +11 -13
  5. package/src/ui/chat-footer/modules/user-input/components/actions/emoji-picker-action.vue +6 -8
  6. package/src/ui/chat-footer/modules/user-input/components/actions/send-message-action.vue +6 -8
  7. package/src/ui/chat-footer/modules/user-input/components/chat-input-actions-bar.vue +37 -39
  8. package/src/ui/chat-footer/modules/user-input/components/chat-text-field.vue +24 -19
  9. package/src/ui/chat-footer/modules/user-input/types/ChatAction.types.ts +5 -5
  10. package/src/ui/index.ts +3 -3
  11. package/src/ui/messaging/components/chat-date-divider.vue +34 -0
  12. package/src/ui/messaging/components/scroll-to-bottom-btn.vue +60 -0
  13. package/src/ui/messaging/components/the-chat-messages-container.vue +89 -0
  14. package/src/ui/messaging/composebles/useChatScroll.ts +107 -0
  15. package/src/ui/messaging/modules/message/components/chat-message.vue +51 -57
  16. package/src/ui/messaging/modules/message/components/details/chat-message-avatar.vue +21 -22
  17. package/src/ui/messaging/modules/message/components/details/chat-message-blocked-error.vue +1 -1
  18. package/src/ui/messaging/modules/message/components/details/chat-message-document.vue +22 -19
  19. package/src/ui/messaging/modules/message/components/details/chat-message-image.vue +8 -8
  20. package/src/ui/messaging/modules/message/components/details/chat-message-player.vue +14 -12
  21. package/src/ui/messaging/modules/message/components/details/chat-message-text.vue +12 -12
  22. package/src/ui/messaging/modules/message/components/details/chat-message-time.vue +11 -9
  23. package/src/ui/messaging/modules/message/composables/useChatMessage.ts +43 -0
  24. package/src/ui/messaging/modules/message/composables/useChatMessageFile.ts +26 -26
  25. package/src/ui/messaging/types/ChatMessage.types.ts +32 -32
  26. package/src/ui/the-chat-container.vue +118 -0
  27. package/src/ui/utils/ResultCallbacks.types.ts +1 -1
  28. package/src/ui/utils/emitter.ts +7 -5
  29. package/types/locale/en/en.d.ts +1 -1
  30. package/types/ui/chat-container.vue.d.ts +47 -22
  31. package/types/ui/chat-footer/modules/user-input/components/chat-input-actions-bar.vue.d.ts +1 -2
  32. package/types/ui/chat-footer/modules/user-input/components/chat-text-field.vue.d.ts +2 -2
  33. package/types/ui/chat-input/components/actions/attach-files-action.vue.d.ts +27 -5
  34. package/types/ui/chat-input/components/actions/emoji-picker-action.vue.d.ts +22 -1
  35. package/types/ui/chat-input/components/actions/send-message-action.vue.d.ts +27 -5
  36. package/types/ui/chat-input/components/chat-input-actions-bar.vue.d.ts +34 -12
  37. package/types/ui/chat-input/components/chat-input-actions-wrapper.vue.d.ts +26 -5
  38. package/types/ui/chat-input/components/chat-input.vue.d.ts +32 -10
  39. package/types/ui/chat-input/components/chat-text-field.vue.d.ts +28 -6
  40. package/types/ui/chat-input/enums/ChatAction.enum.d.ts +3 -3
  41. package/types/ui/index.d.ts +3 -3
  42. package/types/ui/messaging/components/chat-date-divider.vue.d.ts +6 -0
  43. package/types/ui/messaging/components/chat-messages-container.vue.d.ts +24 -3
  44. package/types/ui/messaging/components/scroll-to-bottom-btn.vue.d.ts +12 -0
  45. package/types/ui/messaging/components/the-chat-messages-container.vue.d.ts +10 -0
  46. package/types/ui/messaging/composebles/useChatScroll.d.ts +9 -0
  47. package/types/ui/messaging/modules/message/components/chat-message.vue.d.ts +4 -4
  48. package/types/ui/messaging/modules/message/components/details/chat-message-avatar.vue.d.ts +1 -1
  49. package/types/ui/messaging/modules/message/components/details/chat-message-document.vue.d.ts +1 -1
  50. package/types/ui/messaging/modules/message/components/details/chat-message-image.vue.d.ts +1 -1
  51. package/types/ui/messaging/modules/message/components/details/chat-message-player.vue.d.ts +3 -3
  52. package/types/ui/messaging/modules/message/composables/useChatMessage.d.ts +12 -0
  53. package/types/ui/messaging/modules/message/composables/useChatMessageFile.d.ts +2 -2
  54. package/types/ui/messaging/types/ChatMessage.types.d.ts +1 -1
  55. package/types/ui/the-chat-container.vue.d.ts +33 -0
  56. package/types/ui/utils/ResultCallbacks.types.d.ts +1 -1
  57. package/src/ui/chat-container.vue +0 -102
  58. package/src/ui/messaging/components/chat-messages-container.vue +0 -19
package/package.json CHANGED
@@ -1,63 +1,63 @@
1
1
  {
2
- "name": "@webitel/ui-chats",
3
- "version": "0.0.3",
4
- "description": "Reusable Webitel Frontend Code for Chats UI",
5
- "workspaces": [
6
- "../../",
7
- "../api-services"
8
- ],
9
- "scripts": {
10
- "dev": "vite",
11
- "make-all": "npm version patch --git-tag-version false && (npm run lint:oxlint || true) && (npm run build:types || true) && npm run utils:publish",
12
- "build": "(npm run build:types || true)",
13
- "build:types": "vue-tsc -p ./tsconfig.build.json",
14
- "lint:oxlint": "npx oxlint . --fix --type-aware",
15
- "utils:publish": "npm publish --access public"
16
- },
17
- "dependencies": {
18
- "autolinker": "^4.1.5",
19
- "insert-text-at-cursor": "^0.3.0",
20
- "mitt": "^3.0.1",
21
- "vue": "^3.5.24"
22
- },
23
- "devDependencies": {
24
- "@types/node": "^24.10.0",
25
- "@vitejs/plugin-vue": "^6.0.1",
26
- "@vue/tsconfig": "^0.8.1",
27
- "@webitel/styleguide": "^24.12.61",
28
- "@webitel/ui-sdk": "~25.12",
29
- "oxlint-tsgolint": "^0.5.1",
30
- "typescript": "~5.9.3",
31
- "vite": "npm:rolldown-vite@7.2.2",
32
- "vue-tsc": "^3.1.3"
33
- },
34
- "type": "module",
35
- "main": "index.ts",
36
- "types": "index.d.ts",
37
- "files": [
38
- "src/*",
39
- "types/*",
40
- "Readme.md",
41
- "CHANGELOG.md"
42
- ],
43
- "exports": {
44
- "./ui": {
45
- "types": "./types/ui/index.d.ts",
46
- "import": "./src/ui/index.ts"
47
- }
48
- },
49
- "author": "webitel",
50
- "license": "ISC",
51
- "keywords": [
52
- "webitel",
53
- "webitel-ui"
54
- ],
55
- "repository": {
56
- "type": "git",
57
- "url": "github.com/webitel/webitel-ui-sdk"
58
- },
59
- "engines": {
60
- "npm": ">=10",
61
- "node": ">=v22"
62
- }
2
+ "name": "@webitel/ui-chats",
3
+ "version": "0.0.5",
4
+ "description": "Reusable Webitel Frontend Code for Chats UI",
5
+ "workspaces": [
6
+ "../../",
7
+ "../api-services"
8
+ ],
9
+ "scripts": {
10
+ "dev": "vite",
11
+ "make-all": "npm version patch --git-tag-version false && (npm run lint:biome || true) && (npm run build:types || true) && npm run utils:publish",
12
+ "build": "(npm run build:types || true)",
13
+ "build:types": "vue-tsc -p ./tsconfig.build.json",
14
+ "lint:biome": "biome check --write --unsafe",
15
+ "utils:publish": "npm publish --access public"
16
+ },
17
+ "dependencies": {
18
+ "autolinker": "^4.1.5",
19
+ "insert-text-at-cursor": "^0.3.0",
20
+ "mitt": "^3.0.1",
21
+ "vue": "^3.5.24"
22
+ },
23
+ "devDependencies": {
24
+ "@biomejs/biome": "2.3.8",
25
+ "@types/node": "^24.10.0",
26
+ "@vitejs/plugin-vue": "^6.0.1",
27
+ "@vue/tsconfig": "^0.8.1",
28
+ "@webitel/styleguide": "^24.12.61",
29
+ "@webitel/ui-sdk": "~25.12",
30
+ "typescript": "~5.9.3",
31
+ "vite": "npm:rolldown-vite@7.2.2",
32
+ "vue-tsc": "^3.1.3"
33
+ },
34
+ "type": "module",
35
+ "main": "index.ts",
36
+ "types": "index.d.ts",
37
+ "files": [
38
+ "src/*",
39
+ "types/*",
40
+ "Readme.md",
41
+ "CHANGELOG.md"
42
+ ],
43
+ "exports": {
44
+ "./ui": {
45
+ "types": "./types/ui/index.d.ts",
46
+ "import": "./src/ui/index.ts"
47
+ }
48
+ },
49
+ "author": "webitel",
50
+ "license": "ISC",
51
+ "keywords": [
52
+ "webitel",
53
+ "webitel-ui"
54
+ ],
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "github.com/webitel/webitel-ui-sdk"
58
+ },
59
+ "engines": {
60
+ "npm": ">=10",
61
+ "node": ">=v22"
62
+ }
63
63
  }
@@ -1,9 +1,9 @@
1
1
  export default {
2
- '@webitel/ui-chats': {
3
- ui: {
4
- messaging: {
5
- chatsFileBlocked: 'TODO',
6
- },
7
- },
8
- },
9
- };
2
+ "@webitel/ui-chats": {
3
+ ui: {
4
+ messaging: {
5
+ chatsFileBlocked: "TODO",
6
+ },
7
+ },
8
+ },
9
+ };
@@ -5,11 +5,9 @@
5
5
  </template>
6
6
 
7
7
  <script setup lang="ts">
8
-
9
- const slots = defineSlots<{
10
- default: () => any;
8
+ const _slots = defineSlots<{
9
+ default: () => any;
11
10
  }>();
12
-
13
11
  </script>
14
12
 
15
13
  <style scoped>
@@ -17,23 +17,21 @@
17
17
  </template>
18
18
 
19
19
  <script setup lang="ts">
20
- import { inject, useTemplateRef } from 'vue';
21
- import { WtRoundedAction } from '@webitel/ui-sdk/components';
22
- import { ComponentSize } from '@webitel/ui-sdk/enums';
23
- import { ChatAction } from '../../types/ChatAction.types';
20
+ import type { ComponentSize } from "@webitel/ui-sdk/enums";
21
+ import { inject, useTemplateRef } from "vue";
22
+ import { ChatAction } from "../../types/ChatAction.types";
24
23
 
25
- const size = inject<ComponentSize>('size');
24
+ const _size = inject<ComponentSize>("size");
26
25
 
27
- const emit = defineEmits<{
28
- (e: typeof ChatAction.AttachFiles, files: File[]): void;
29
- }>();
26
+ const emit =
27
+ defineEmits<(e: typeof ChatAction.AttachFiles, files: File[]) => void>();
30
28
 
31
- const attachFilesInputRef = useTemplateRef('attachFilesInput');
29
+ const _attachFilesInputRef = useTemplateRef("attachFilesInput");
32
30
 
33
- const handleAttachmentInputChange = (event: Event) => {
34
- const files = (event.target as HTMLInputElement).files;
35
- if (!files) return;
36
- emit(ChatAction.AttachFiles, Array.from(files) as File[]);
31
+ const _handleAttachmentInputChange = (event: Event) => {
32
+ const files = (event.target as HTMLInputElement).files;
33
+ if (!files) return;
34
+ emit(ChatAction.AttachFiles, Array.from(files) as File[]);
37
35
  };
38
36
  </script>
39
37
 
@@ -6,14 +6,12 @@
6
6
  </template>
7
7
 
8
8
  <script setup lang="ts">
9
- import { inject } from 'vue';
10
- import { WtChatEmoji } from '@webitel/ui-sdk/components';
11
- import { ComponentSize } from '@webitel/ui-sdk/enums';
12
- import type { Emitter } from 'mitt';
9
+ import type { ComponentSize } from "@webitel/ui-sdk/enums";
10
+ import type { Emitter } from "mitt";
11
+ import { inject } from "vue";
13
12
 
14
- import type{ UiChatsEmitterEvents } from '../../../../../utils/emitter';
15
-
16
- const size = inject<ComponentSize>('size');
17
- const uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>('uiChatsEmitter');
13
+ import type { UiChatsEmitterEvents } from "../../../../../utils/emitter";
18
14
 
15
+ const _size = inject<ComponentSize>("size");
16
+ const _uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>("uiChatsEmitter");
19
17
  </script>
@@ -10,14 +10,12 @@
10
10
  </template>
11
11
 
12
12
  <script setup lang="ts">
13
- import { inject } from 'vue';
14
- import { ComponentSize } from '@webitel/ui-sdk/enums';
15
- import { ChatAction } from '../../types/ChatAction.types';
13
+ import type { ComponentSize } from "@webitel/ui-sdk/enums";
14
+ import { inject } from "vue";
16
15
 
17
- const size = inject<ComponentSize>('size');
16
+ import type { ChatAction } from "../../types/ChatAction.types";
18
17
 
19
- const emit = defineEmits<{
20
- (e: typeof ChatAction.SendMessage): void;
21
- }>();
18
+ const _size = inject<ComponentSize>("size");
22
19
 
23
- </script>
20
+ const _emit = defineEmits<(e: typeof ChatAction.SendMessage) => void>();
21
+ </script>
@@ -9,60 +9,58 @@
9
9
  <component
10
10
  :is="actionComponent"
11
11
  :size="size"
12
- @sendMessage="emit(ChatAction.SendMessage)"
13
- @attachFiles="emit(ChatAction.AttachFiles, $event)"
12
+ @send-message="emit(ChatAction.SendMessage)"
13
+ @attach-files="emit(ChatAction.AttachFiles, $event)"
14
14
  />
15
15
  </slot>
16
16
  </section>
17
17
  </template>
18
18
 
19
19
  <script setup lang="ts">
20
- import { computed, inject } from 'vue';
21
- import { ComponentSize } from '@webitel/ui-sdk/enums';
20
+ import type { ComponentSize } from "@webitel/ui-sdk/enums";
21
+ import { computed, inject } from "vue";
22
22
 
23
- import { ChatAction } from '../types/ChatAction.types';
24
- import SendMessageAction from './actions/send-message-action.vue';
25
- import AttachFilesAction from './actions/attach-files-action.vue';
26
- import EmojiPickerAction from './actions/emoji-picker-action.vue';
27
- import { SharedActionSlots } from '../types/ChatAction.types';
23
+ import { ChatAction, type SharedActionSlots } from "../types/ChatAction.types";
24
+ import AttachFilesAction from "./actions/attach-files-action.vue";
25
+ import EmojiPickerAction from "./actions/emoji-picker-action.vue";
26
+ import SendMessageAction from "./actions/send-message-action.vue";
28
27
 
29
- const size = inject<ComponentSize>('size');
28
+ const _size = inject<ComponentSize>("size");
30
29
 
31
30
  const props = defineProps<{
32
- actions: ChatAction[];
31
+ actions: ChatAction[];
33
32
  }>();
34
33
 
35
- const emit = defineEmits<{
36
- (e: typeof ChatAction.SendMessage): void;
37
- (e: typeof ChatAction.AttachFiles, files: File[]): void;
34
+ const _emit = defineEmits<{
35
+ (e: typeof ChatAction.SendMessage): void;
36
+ (e: typeof ChatAction.AttachFiles, files: File[]): void;
38
37
  }>();
39
38
 
40
- const slots = defineSlots<SharedActionSlots>();
39
+ const _slots = defineSlots<SharedActionSlots>();
41
40
 
42
- const ShownActionComponentsList = computed(() => {
43
- /**
44
- * note! actions order is declared here and cannot be changed from outside
45
- */
46
- return [
47
- {
48
- action: ChatAction.AttachFiles,
49
- component: AttachFilesAction,
50
- },
51
- {
52
- action: ChatAction.EmojiPicker,
53
- component: EmojiPickerAction,
54
- },
55
- {
56
- action: ChatAction.QuickReplies,
57
- component: null, // has no component inside lib, should be provided by pkg-client application
58
- },
59
- {
60
- action: ChatAction.SendMessage,
61
- component: SendMessageAction,
62
- },
63
- ].filter(({ action }) => props.actions.includes(action));
41
+ const _ShownActionComponentsList = computed(() => {
42
+ /**
43
+ * note! actions order is declared here and cannot be changed from outside
44
+ */
45
+ return [
46
+ {
47
+ action: ChatAction.AttachFiles,
48
+ component: AttachFilesAction,
49
+ },
50
+ {
51
+ action: ChatAction.EmojiPicker,
52
+ component: EmojiPickerAction,
53
+ },
54
+ {
55
+ action: ChatAction.QuickReplies,
56
+ component: null, // has no component inside lib, should be provided by pkg-client application
57
+ },
58
+ {
59
+ action: ChatAction.SendMessage,
60
+ component: SendMessageAction,
61
+ },
62
+ ].filter(({ action }) => props.actions.includes(action));
64
63
  });
65
-
66
64
  </script>
67
65
 
68
66
  <style scoped>
@@ -74,4 +72,4 @@ const ShownActionComponentsList = computed(() => {
74
72
  flex: 1;
75
73
  }
76
74
  }
77
- </style>
75
+ </style>
@@ -1,39 +1,44 @@
1
1
  <template>
2
2
  <wt-textarea
3
- v-model="textModel"
4
3
  ref="chatTextFieldInput"
4
+ v-model="textModel"
5
5
  :size="size"
6
6
  autoresize
7
7
  />
8
8
  </template>
9
9
 
10
10
  <script setup lang="ts">
11
- import { computed, inject, useTemplateRef, MaybeRef } from 'vue';
12
- import { WtTextarea } from '@webitel/ui-sdk/components';
13
- import { ComponentSize } from '@webitel/ui-sdk/enums';
14
- import insertTextAtCursor from 'insert-text-at-cursor';
15
- import type { Emitter } from 'mitt';
11
+ import type { WtTextarea } from "@webitel/ui-sdk/components";
12
+ import type { ComponentSize } from "@webitel/ui-sdk/enums";
13
+ import insertTextAtCursor from "insert-text-at-cursor";
14
+ import type { Emitter } from "mitt";
15
+ import { computed, inject, type MaybeRef, useTemplateRef } from "vue";
16
16
 
17
- import type { UiChatsEmitterEvents } from '../../../../utils/emitter';
17
+ import type { UiChatsEmitterEvents } from "../../../../utils/emitter";
18
18
 
19
- const textModel = defineModel<MaybeRef<string>>('text', { required: true });
19
+ const _textModel = defineModel<MaybeRef<string>>("text", {
20
+ required: true,
21
+ });
20
22
 
21
- const size = inject<ComponentSize>('size');
22
- const uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>('uiChatsEmitter');
23
+ const _size = inject<ComponentSize>("size");
24
+ const uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>("uiChatsEmitter");
23
25
 
24
- uiChatsEmitter!.on('insertAtCursor', ({ text }) => insertAtCursor(text));
25
- uiChatsEmitter!.on('focusOnTextField', focus);
26
+ uiChatsEmitter?.on("insertAtCursor", ({ text }) => insertAtCursor(text));
27
+ uiChatsEmitter?.on("focusOnTextField", focus);
26
28
 
27
- const chatTextFieldInputRef = useTemplateRef<typeof WtTextarea>('chatTextFieldInput');
29
+ const chatTextFieldInputRef =
30
+ useTemplateRef<typeof WtTextarea>("chatTextFieldInput");
28
31
 
29
- const textareaEl = computed(() => chatTextFieldInputRef.value?.$el.querySelector('textarea'));
32
+ const textareaEl = computed(() =>
33
+ chatTextFieldInputRef.value?.$el.querySelector("textarea"),
34
+ );
30
35
 
31
36
  function focus() {
32
- textareaEl.value!.focus();
33
- };
37
+ textareaEl.value?.focus();
38
+ }
34
39
 
35
40
  function insertAtCursor(text: string) {
36
- focus();
37
- insertTextAtCursor(textareaEl.value!, text);
41
+ focus();
42
+ insertTextAtCursor(textareaEl.value!, text);
38
43
  }
39
- </script>
44
+ </script>
@@ -1,12 +1,12 @@
1
1
  export const ChatAction = {
2
- SendMessage: 'sendMessage',
3
- AttachFiles: 'attachFiles',
4
- EmojiPicker: 'emojiPicker',
5
- QuickReplies: 'quickReplies',
2
+ SendMessage: "sendMessage",
3
+ AttachFiles: "attachFiles",
4
+ EmojiPicker: "emojiPicker",
5
+ QuickReplies: "quickReplies",
6
6
  } as const;
7
7
 
8
8
  export type ChatAction = (typeof ChatAction)[keyof typeof ChatAction];
9
9
 
10
10
  export type SharedActionSlots = {
11
- [key in `action:${ChatAction}`]?: () => any;
11
+ [key in `action:${ChatAction}`]?: () => any;
12
12
  };
package/src/ui/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { default as ChatContainerComponent } from './chat-container.vue';
2
- export { ChatAction } from './chat-footer/modules/user-input/types/ChatAction.types';
3
- export { type ChatMessageType } from './messaging/types/ChatMessage.types';
1
+ export { ChatAction } from "./chat-footer/modules/user-input/types/ChatAction.types";
2
+ export type { ChatMessageType } from "./messaging/types/ChatMessage.types";
3
+ export { default as ChatContainerComponent } from "./the-chat-container.vue";
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <div class="chat-date-divider">
3
+ {{ formattedDate }}
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { FormatDateMode } from "@webitel/ui-sdk/enums";
9
+ import { formatDate } from "@webitel/ui-sdk/utils";
10
+ import { computed } from "vue";
11
+ import { useI18n } from "vue-i18n";
12
+
13
+ const props = defineProps<{
14
+ date: number | string;
15
+ }>();
16
+
17
+ const { t } = useI18n();
18
+
19
+ const _formattedDate = computed<Date>(() => {
20
+ const chatDate = formatDate(+props.date, FormatDateMode.DATE);
21
+ const today = formatDate(Date.now(), FormatDateMode.DATE);
22
+
23
+ return chatDate === today ? t("reusable.today") : chatDate;
24
+ });
25
+ </script>
26
+
27
+ <style lang="scss" scoped>
28
+ .chat-date-divider {
29
+ @extend %typo-subtitle-1;
30
+ width: 100%;
31
+ display: flex;
32
+ justify-content: center;
33
+ }
34
+ </style>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div class="scroll-to-bottom-btn">
3
+
4
+ <div
5
+ v-show="props.newMessageCount"
6
+ class="scroll-to-bottom-btn__messages-counter"
7
+ >
8
+ {{ props.newMessageCount }}
9
+ </div>
10
+ <wt-rounded-action
11
+ icon="arrow-down"
12
+ rounded
13
+ @click="emit('scroll')"
14
+ />
15
+
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { defineEmits } from "vue";
21
+
22
+ const _props = withDefaults(
23
+ defineProps<{
24
+ newMessageCount?: number;
25
+ }>(),
26
+ {
27
+ newMessageCount: 0,
28
+ },
29
+ );
30
+
31
+ const _emit = defineEmits<{
32
+ scroll: [];
33
+ }>();
34
+ </script>
35
+
36
+ <style lang="scss" scoped>
37
+
38
+ .scroll-to-bottom-btn {
39
+ position: absolute;
40
+ bottom: 0;
41
+ right: calc(var(--scrollbar-width) + var(--spacing-2xs));
42
+ display: flex;
43
+ flex-direction: column;
44
+ align-items: center;
45
+ gap: var(--spacing-2xs);
46
+
47
+ &__messages-counter {
48
+ @extend %typo-body-2;
49
+ width: 24px;
50
+ height: 24px;
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ background: var(--success-color);
55
+ border-radius: 50%;
56
+ color: var(--text-on-brand-color);
57
+ }
58
+ }
59
+
60
+ </style>
@@ -0,0 +1,89 @@
1
+ <template>
2
+ <section class="the-chat-messages-container" @click="focusOnInput">
3
+ <div
4
+ ref="messages-container"
5
+ class="the-chat-messages-container__wrapper"
6
+ @scroll="handleChatScroll"
7
+ @resize="handleChatResize"
8
+ >
9
+ <chat-message-component
10
+ v-for="(message, index) of props.messages"
11
+ :key="message.id"
12
+ :message="message"
13
+ :show-avatar="!props.hideAvatars && showAvatar(index)"
14
+ >
15
+ <template #before-message>
16
+ <chat-date
17
+ v-if="showChatDate(index)"
18
+ :date="message.createdAt"
19
+ />
20
+ </template>
21
+ </chat-message-component>
22
+ </div>
23
+ <scroll-to-bottom-btn
24
+ v-if="showScrollToBottomBtn"
25
+ :new-message-count="newUnseenMessages"
26
+ @scroll="scrollToBottom('smooth')"
27
+ />
28
+ </section>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import type { Emitter } from "mitt";
33
+ import { inject, useTemplateRef } from "vue";
34
+
35
+ import type { UiChatsEmitterEvents } from "../../utils/emitter";
36
+ import { useChatScroll } from "../composebles/useChatScroll";
37
+ import { useChatMessages } from "../modules/message/composables/useChatMessage";
38
+ import type { ChatMessageType } from "../types/ChatMessage.types";
39
+
40
+ const uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>("uiChatsEmitter");
41
+
42
+ const props = withDefaults(
43
+ defineProps<{
44
+ messages: ChatMessageType[];
45
+ hideAvatars?: boolean;
46
+ }>(),
47
+ {
48
+ hideAvatars: false,
49
+ },
50
+ );
51
+
52
+ const messagesContainer = useTemplateRef("messages-container");
53
+
54
+ const { showAvatar, showChatDate } = useChatMessages(props.messages);
55
+
56
+ const {
57
+ showScrollToBottomBtn,
58
+ newUnseenMessages,
59
+ scrollToBottom,
60
+ handleChatScroll,
61
+ handleChatResize,
62
+ } = useChatScroll(messagesContainer, props.messages);
63
+
64
+ function _focusOnInput() {
65
+ uiChatsEmitter?.on("focusOnTextField", focus);
66
+ }
67
+ </script>
68
+
69
+ <style scoped lang="scss">
70
+ .the-chat-messages-container {
71
+ position: relative;
72
+ display: flex;
73
+ overflow: hidden;
74
+ height: inherit;
75
+ }
76
+
77
+ .the-chat-messages-container__wrapper {
78
+ @extend %wt-scrollbar;
79
+ display: flex;
80
+ flex-direction: column;
81
+ box-sizing: border-box;
82
+ overflow-x: hidden;
83
+ overflow-y: auto;
84
+ width: 100%;
85
+ padding-right: var(--scrollbar-width); // scrollbar offset
86
+ scrollbar-gutter: stable both-edges;
87
+ gap: var(--spacing-xs);
88
+ }
89
+ </style>