@webitel/ui-chats 0.0.23 → 0.1.0-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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-chats",
3
- "version": "0.0.23",
3
+ "version": "0.1.0-1",
4
4
  "description": "Reusable Webitel Frontend Code for Chats UI",
5
5
  "workspaces": [
6
6
  "../../",
@@ -16,21 +16,28 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "autolinker": "^4.1.5",
19
- "insert-text-at-cursor": "^0.3.0",
20
- "mitt": "^3.0.1",
21
- "vue": "^3.5.24"
19
+ "insert-text-at-cursor": "^0.3.0"
22
20
  },
23
21
  "devDependencies": {
24
22
  "@biomejs/biome": "2.3.8",
25
23
  "@types/node": "^24.10.0",
26
24
  "@vitejs/plugin-vue": "^6.0.1",
27
25
  "@vue/tsconfig": "^0.8.1",
28
- "@webitel/styleguide": "^24.12.95",
29
- "@webitel/ui-sdk": "~25.12",
26
+ "@webitel/styleguide": "^26.2.0-1",
27
+ "@webitel/ui-sdk": "^26.2.0-4",
28
+ "mitt": "^3",
30
29
  "typescript": "~5.9.3",
31
30
  "vite": "npm:rolldown-vite@7.2.2",
31
+ "vue": "^3.5",
32
32
  "vue-tsc": "^3.1.3"
33
33
  },
34
+ "peerDependencies": {
35
+ "@webitel/api-services": "^0.1.0",
36
+ "@webitel/styleguide": "=26.2.0-1",
37
+ "@webitel/ui-sdk": "=26.2.0-4",
38
+ "mitt": "^3",
39
+ "vue": "^3.5"
40
+ },
34
41
  "type": "module",
35
42
  "main": "index.ts",
36
43
  "types": "index.d.ts",
@@ -1,36 +1,39 @@
1
1
  <template>
2
- <div class="chat-date-divider">
2
+ <div class="chat-date-divider typo-subtitle-1">
3
3
  {{ formattedDate }}
4
4
  </div>
5
5
  </template>
6
6
 
7
- <script setup lang="ts">
7
+ <script
8
+ setup
9
+ lang="ts"
10
+ >
8
11
  import { FormatDateMode } from "@webitel/ui-sdk/enums";
9
12
  import { formatDate } from "@webitel/ui-sdk/utils";
10
13
  import { computed } from "vue";
11
14
  import { useI18n } from "vue-i18n";
12
15
 
13
16
  const props = defineProps<{
14
- date: number | string;
17
+ date: number | string;
15
18
  }>();
16
19
 
17
20
  const { t } = useI18n();
18
21
 
19
22
  const formattedDate = computed<Date>(() => {
20
- const chatDate = formatDate(+props.date, FormatDateMode.DATE);
21
- const today = formatDate(Date.now(), FormatDateMode.DATE);
23
+ const chatDate = formatDate(+props.date, FormatDateMode.DATE);
24
+ const today = formatDate(Date.now(), FormatDateMode.DATE);
22
25
 
23
- return chatDate === today ? t("reusable.today") : chatDate;
26
+ return chatDate === today ? t("reusable.today") : chatDate;
24
27
  });
25
28
  </script>
26
29
 
27
- <style lang="scss" scoped>
28
- @use '@webitel/styleguide/typography' as *;
29
-
30
- .chat-date-divider {
31
- @extend %typo-subtitle-1;
32
- width: 100%;
33
- display: flex;
34
- justify-content: center;
35
- }
30
+ <style
31
+ lang="scss"
32
+ scoped
33
+ >
34
+ .chat-date-divider {
35
+ width: 100%;
36
+ display: flex;
37
+ justify-content: center;
38
+ }
36
39
  </style>
@@ -1,9 +1,12 @@
1
1
  <template>
2
- <aside class="dropzone dropzone--animated" v-on="$listeners">
2
+ <aside
3
+ class="dropzone dropzone--animated"
4
+ v-on="$listeners"
5
+ >
3
6
  <div class="dropzone__border-animation"></div>
4
7
  <article class="dropzone__text-wrapper">
5
- <h3 class="dropzone__title">{{ $t('workspaceSec.chat.dropzone.title') }}</h3>
6
- <p class="dropzone__description">{{ $t('workspaceSec.chat.dropzone.description') }}</p>
8
+ <h3 class="dropzone__title typo-heading-2">{{ $t('workspaceSec.chat.dropzone.title') }}</h3>
9
+ <p class="dropzone__description typo-body-2">{{ $t('workspaceSec.chat.dropzone.description') }}</p>
7
10
  </article>
8
11
  </aside>
9
12
  </template>
@@ -11,9 +14,10 @@
11
14
  <script>
12
15
  </script>
13
16
 
14
- <style lang="scss" scoped>
15
- @use '@webitel/styleguide/typography' as *;
16
-
17
+ <style
18
+ lang="scss"
19
+ scoped
20
+ >
17
21
  .dropzone {
18
22
  position: absolute;
19
23
  top: 0;
@@ -36,17 +40,19 @@
36
40
  bottom: 0;
37
41
  left: 0;
38
42
  background: linear-gradient(90deg, var(--primary-color) 50%, transparent 50%),
39
- linear-gradient(90deg, var(--primary-color) 50%, transparent 50%),
40
- linear-gradient(0deg, var(--primary-color) 50%, transparent 50%),
41
- linear-gradient(0deg, var(--primary-color) 50%, transparent 50%);
43
+ linear-gradient(90deg, var(--primary-color) 50%, transparent 50%),
44
+ linear-gradient(0deg, var(--primary-color) 50%, transparent 50%),
45
+ linear-gradient(0deg, var(--primary-color) 50%, transparent 50%);
42
46
  background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
43
47
  background-size: 15px 4px, 15px 4px, 4px 15px, 4px 15px;
44
48
  background-position: 0 0, 100% 100%;
45
49
  animation: border-dance 6s infinite linear;
50
+
46
51
  @keyframes border-dance {
47
52
  0% {
48
53
  background-position: 0 0, 100% 100%, 0 100%, 100% 0;
49
54
  }
55
+
50
56
  100% {
51
57
  background-position: 100% 0, 0 100%, 0 0, 100% 100%;
52
58
  }
@@ -59,12 +65,10 @@
59
65
  }
60
66
 
61
67
  .dropzone__title {
62
- @extend %typo-heading-2;
63
68
  text-align: center;
64
69
  }
65
70
 
66
71
  .dropzone__description {
67
- @extend %typo-body-2;
68
72
  text-align: center;
69
73
  }
70
74
  </style>
@@ -3,7 +3,7 @@
3
3
 
4
4
  <div
5
5
  v-show="props.newMessageCount"
6
- class="scroll-to-bottom-btn__messages-counter"
6
+ class="scroll-to-bottom-btn__messages-counter typo-body-2"
7
7
  >
8
8
  {{ props.newMessageCount }}
9
9
  </div>
@@ -34,8 +34,6 @@ const emit = defineEmits<{
34
34
  </script>
35
35
 
36
36
  <style lang="scss" scoped>
37
- @use '@webitel/styleguide/typography' as *;
38
-
39
37
  .scroll-to-bottom-btn {
40
38
  position: absolute;
41
39
  bottom: 0;
@@ -46,7 +44,6 @@ const emit = defineEmits<{
46
44
  gap: var(--spacing-2xs);
47
45
 
48
46
  &__messages-counter {
49
- @extend %typo-body-2;
50
47
  width: 24px;
51
48
  height: 24px;
52
49
  display: flex;
@@ -1,45 +1,48 @@
1
1
  <template>
2
- <section
3
- class="the-chat-messages-container"
4
- @click="focusOnInput"
2
+ <section
3
+ class="the-chat-messages-container"
4
+ @click="focusOnInput"
5
+ >
6
+ <div
7
+ ref="messages-container"
8
+ class="the-chat-messages-container__wrapper wt-scrollbar"
9
+ @scroll="handleChatScroll"
10
+ @resize="handleChatResize"
5
11
  >
6
- <div
7
- ref="messages-container"
8
- class="the-chat-messages-container__wrapper"
9
- @scroll="handleChatScroll"
10
- @resize="handleChatResize"
12
+ <chat-observer
13
+ v-if="props.next"
14
+ :next="props.next"
15
+ :loading="props.isLoading"
16
+ @[ChatAction.LoadNextMessages]="emit(ChatAction.LoadNextMessages)"
17
+ />
18
+ <chat-message
19
+ v-for="(message, index) of props.messages"
20
+ :key="message.id"
21
+ :message="message"
22
+ :show-avatar="showAvatar(index)"
23
+ :without-avatars="props.withoutAvatars"
24
+ @[MessageAction.ClickOnImage]="clickOnImage(message)"
11
25
  >
12
- <chat-observer
13
- v-if="props.next"
14
- :next="props.next"
15
- :loading="props.isLoading"
16
- @[ChatAction.LoadNextMessages]="emit(ChatAction.LoadNextMessages)"
26
+ <template #before-message>
27
+ <chat-date-divider
28
+ v-if="showChatDate(index)"
29
+ :date="message.createdAt"
17
30
  />
18
- <chat-message
19
- v-for="(message, index) of props.messages"
20
- :key="message.id"
21
- :message="message"
22
- :show-avatar="showAvatar(index)"
23
- :without-avatars="props.withoutAvatars"
24
- @[MessageAction.ClickOnImage]="clickOnImage(message)"
25
- >
26
- <template #before-message>
27
- <chat-date-divider
28
- v-if="showChatDate(index)"
29
- :date="message.createdAt"
30
- />
31
- </template>
32
- </chat-message>
33
- </div>
34
- <scroll-to-bottom-btn
35
- v-if="showScrollToBottomBtn"
36
- :new-message-count="newUnseenMessagesCount"
37
- @scroll="scrollToBottom('smooth')"
38
- />
39
- </section>
31
+ </template>
32
+ </chat-message>
33
+ </div>
34
+ <scroll-to-bottom-btn
35
+ v-if="showScrollToBottomBtn"
36
+ :new-message-count="newUnseenMessagesCount"
37
+ @scroll="scrollToBottom('smooth')"
38
+ />
39
+ </section>
40
40
  </template>
41
41
 
42
- <script setup lang="ts">
42
+ <script
43
+ setup
44
+ lang="ts"
45
+ >
43
46
  import type { Emitter } from "mitt";
44
47
  import { computed, inject, nextTick, onMounted, useTemplateRef } from "vue";
45
48
 
@@ -57,17 +60,17 @@ import ScrollToBottomBtn from "./scroll-to-bottom-btn.vue";
57
60
  const uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>("uiChatsEmitter");
58
61
 
59
62
  const props = withDefaults(
60
- defineProps<{
61
- messages: ChatMessageType[];
62
- next?: boolean;
63
- isLoading?: boolean;
64
- withoutAvatars?: boolean;
65
- }>(),
66
- {
67
- next: false,
68
- isLoading: false,
69
- withoutAvatars: false,
70
- },
63
+ defineProps<{
64
+ messages: ChatMessageType[];
65
+ next?: boolean;
66
+ isLoading?: boolean;
67
+ withoutAvatars?: boolean;
68
+ }>(),
69
+ {
70
+ next: false,
71
+ isLoading: false,
72
+ withoutAvatars: false,
73
+ },
71
74
  );
72
75
 
73
76
  const emit = defineEmits<(e: typeof ChatAction.LoadNextMessages) => void>();
@@ -77,36 +80,37 @@ const messagesContainer = useTemplateRef("messages-container");
77
80
  const { showAvatar, showChatDate } = useChatMessages(props.messages);
78
81
 
79
82
  const {
80
- showScrollToBottomBtn,
81
- newUnseenMessagesCount,
82
- scrollToBottom,
83
- handleChatScroll,
84
- handleChatResize,
83
+ showScrollToBottomBtn,
84
+ newUnseenMessagesCount,
85
+ scrollToBottom,
86
+ handleChatScroll,
87
+ handleChatResize,
85
88
  } = useChatScroll(
86
- messagesContainer,
87
- computed(() => props.messages),
89
+ messagesContainer,
90
+ computed(() => props.messages),
88
91
  );
89
92
 
90
93
  function focusOnInput() {
91
- uiChatsEmitter?.on("focusOnTextField", focus);
94
+ uiChatsEmitter?.on("focusOnTextField", focus);
92
95
  }
93
96
 
94
97
  function clickOnImage(message: ChatMessageType) {
95
- uiChatsEmitter!.emit("clickChatMessageImage", message);
98
+ uiChatsEmitter!.emit("clickChatMessageImage", message);
96
99
  }
97
100
 
98
101
  onMounted(async () => {
99
- /* TODO: add loader on all chat(in the-chat-container?) and remove timeout after that */
100
- await nextTick();
101
- setTimeout(() => {
102
- scrollToBottom();
103
- }, 500);
102
+ /* TODO: add loader on all chat(in the-chat-container?) and remove timeout after that */
103
+ await nextTick();
104
+ setTimeout(() => {
105
+ scrollToBottom();
106
+ }, 500);
104
107
  });
105
108
  </script>
106
109
 
107
- <style scoped lang="scss">
108
- @use '@webitel/styleguide/scroll' as *;
109
-
110
+ <style
111
+ scoped
112
+ lang="scss"
113
+ >
110
114
  .the-chat-messages-container {
111
115
  position: relative;
112
116
  display: flex;
@@ -115,7 +119,6 @@ onMounted(async () => {
115
119
  }
116
120
 
117
121
  .the-chat-messages-container__wrapper {
118
- @extend %wt-scrollbar;
119
122
  display: flex;
120
123
  flex-direction: column;
121
124
  box-sizing: border-box;
@@ -126,5 +129,4 @@ onMounted(async () => {
126
129
  scrollbar-gutter: stable both-edges;
127
130
  gap: var(--spacing-xs);
128
131
  }
129
-
130
132
  </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="chat-message-blocked-error">
2
+ <div class="chat-message-blocked-error typo-body-1">
3
3
  <wt-icon
4
4
  icon="protection-error"
5
5
  color="error"
@@ -20,10 +20,7 @@ const { t } = useI18n();
20
20
  <script setup lang="ts">
21
21
  </script>
22
22
  <style scoped lang="scss">
23
- @use '@webitel/styleguide/typography' as *;
24
-
25
23
  .chat-message-blocked-error {
26
- @extend %typo-body-1;
27
24
  background: var(--p-error-highlight-color);
28
25
  border-radius: var(--spacing-xs);
29
26
  padding: var(--spacing-xs);
@@ -8,10 +8,10 @@
8
8
  <wt-icon class="chat-message-document__icon" icon="attach" />
9
9
  </div>
10
10
  <div class="chat-message-document__info-wrapper">
11
- <a class="chat-message-document__name" :title="props.file.name">
11
+ <a class="chat-message-document__name typo-subtitle-2" :title="props.file.name">
12
12
  {{ props.file.name }}
13
13
  </a>
14
- <div class="chat-message-document__size">
14
+ <div class="chat-message-document__size typo-caption">
15
15
  {{ documentSize }}
16
16
  </div>
17
17
  </div>
@@ -49,8 +49,6 @@ function downloadDocument() {
49
49
  </script>
50
50
 
51
51
  <style lang="scss" scoped>
52
- @use '@webitel/styleguide/typography' as *;
53
-
54
52
  .chat-message-document {
55
53
  display: flex;
56
54
  align-items: flex-start;
@@ -74,14 +72,12 @@ function downloadDocument() {
74
72
  }
75
73
 
76
74
  &__name {
77
- @extend %typo-subtitle-2;
78
75
  cursor: pointer;
79
76
  overflow-wrap: break-word;
80
77
  color: var(--text-main-color);
81
78
  }
82
79
 
83
80
  &__size {
84
- @extend %typo-caption;
85
81
  color: var(--text-main-color);
86
82
  }
87
83
 
@@ -1,7 +1,10 @@
1
1
  <template>
2
- <div class="chat-message-image" @click="emit('open', props.file)">
2
+ <div
3
+ class="chat-message-image"
4
+ @click="emit('open', props.file)"
5
+ >
3
6
  <img
4
- class="chat-message-image__img"
7
+ class="chat-message-image__img typo-body-1"
5
8
  :src="props.file.url"
6
9
  :alt="props.file.name"
7
10
  draggable="false"
@@ -10,30 +13,33 @@
10
13
  </template>
11
14
 
12
15
 
13
- <script setup lang="ts">
16
+ <script
17
+ setup
18
+ lang="ts"
19
+ >
14
20
  import { defineEmits, defineProps } from "vue";
15
21
 
16
22
  import type { ChatMessageFile } from "../../../../types/ChatMessage.types";
17
23
 
18
24
  const props = defineProps<{
19
- file: ChatMessageFile;
25
+ file: ChatMessageFile;
20
26
  }>();
21
27
  const emit = defineEmits<{
22
- open: [
23
- ChatMessageFile,
24
- ];
28
+ open: [
29
+ ChatMessageFile,
30
+ ];
25
31
  }>();
26
32
  </script>
27
33
 
28
34
 
29
- <style lang="scss" scoped>
30
- @use '@webitel/styleguide/typography' as *;
31
-
35
+ <style
36
+ lang="scss"
37
+ scoped
38
+ >
32
39
  .chat-message-image {
33
40
  cursor: pointer;
34
41
 
35
42
  &__img {
36
- @extend %typo-body-1;
37
43
  max-height: var(--chat-file-max-height);
38
44
  max-width: var(--chat-file-max-width);
39
45
  width: 100%;
@@ -1,34 +1,37 @@
1
1
  <template>
2
2
  <p
3
- class="chat-message-text"
3
+ class="chat-message-text typo-body-1"
4
4
  v-html="text"
5
5
  />
6
6
  </template>
7
7
 
8
- <script setup lang="ts">
8
+ <script
9
+ setup
10
+ lang="ts"
11
+ >
9
12
  import Autolinker from "autolinker";
10
13
  import { computed, defineProps } from "vue";
11
14
 
12
15
  const props = defineProps<{
13
- text: string;
16
+ text: string;
14
17
  }>();
15
18
 
16
19
  const text = computed(() => {
17
- // ATTENTION: not all libs are suitable for this case, because we want to preserve "<" signs
18
- // https://my.webitel.com/browse/DEV-2848
19
- return Autolinker.link(props.text, {
20
- newWindow: true,
21
- sanitizeHtml: true, // DONT FORGET TO SANITIZE, OR USE DOM PURIFY
22
- className: "chat-message-new-text__link",
23
- });
20
+ // ATTENTION: not all libs are suitable for this case, because we want to preserve "<" signs
21
+ // https://my.webitel.com/browse/DEV-2848
22
+ return Autolinker.link(props.text, {
23
+ newWindow: true,
24
+ sanitizeHtml: true, // DONT FORGET TO SANITIZE, OR USE DOM PURIFY
25
+ className: "chat-message-new-text__link",
26
+ });
24
27
  });
25
28
  </script>
26
29
 
27
- <style lang="scss" scoped>
28
- @use '@webitel/styleguide/typography' as *;
29
-
30
+ <style
31
+ lang="scss"
32
+ scoped
33
+ >
30
34
  .chat-message-text {
31
- @extend %typo-body-1;
32
35
  overflow-wrap: anywhere;
33
36
  white-space: pre-line; // read \n as "new line"
34
37
  padding: var(--spacing-xs);
@@ -43,5 +46,4 @@ const text = computed(() => {
43
46
  text-decoration: revert;
44
47
  }
45
48
  }
46
-
47
49
  </style>
@@ -1,30 +1,35 @@
1
1
  <template>
2
2
  <aside class="chat-message-time">
3
- <div class="chat-message-time__sent-at">
3
+ <div class="chat-message-time__sent-at typo-caption">
4
4
  {{ time }}
5
5
  </div>
6
6
  </aside>
7
7
  </template>
8
8
 
9
9
 
10
- <script setup lang="ts">
10
+ <script
11
+ setup
12
+ lang="ts"
13
+ >
11
14
  import { prettifyTime } from "@webitel/ui-sdk/scripts";
12
15
  import { computed, defineProps } from "vue";
13
16
 
14
17
  const props = withDefaults(
15
- defineProps<{
16
- date?: string | number; // timestamp
17
- }>(),
18
- {
19
- date: "",
20
- },
18
+ defineProps<{
19
+ date?: string | number; // timestamp
20
+ }>(),
21
+ {
22
+ date: "",
23
+ },
21
24
  );
22
25
 
23
26
  const time = computed(() => prettifyTime(props.date));
24
27
  </script>
25
28
 
26
- <style lang="scss" scoped>
27
- @use '@webitel/styleguide/typography' as *;
29
+ <style
30
+ lang="scss"
31
+ scoped
32
+ >
28
33
  .chat-message-time {
29
34
  display: flex;
30
35
  flex-direction: column;
@@ -32,7 +37,6 @@ const time = computed(() => prettifyTime(props.date));
32
37
  align-items: flex-end;
33
38
 
34
39
  &__sent-at {
35
- @extend %typo-caption;
36
40
  color: var(--text-main-color);
37
41
  white-space: nowrap;
38
42
  }