@webitel/ui-chats 0.0.25 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-chats",
3
- "version": "0.0.25",
3
+ "version": "0.1.0",
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 {
45
48
  computed,
@@ -64,17 +67,17 @@ import ScrollToBottomBtn from "./scroll-to-bottom-btn.vue";
64
67
  const uiChatsEmitter = inject<Emitter<UiChatsEmitterEvents>>("uiChatsEmitter");
65
68
 
66
69
  const props = withDefaults(
67
- defineProps<{
68
- messages: ChatMessageType[];
69
- next?: boolean;
70
- isLoading?: boolean;
71
- withoutAvatars?: boolean;
72
- }>(),
73
- {
74
- next: false,
75
- isLoading: false,
76
- withoutAvatars: false,
77
- },
70
+ defineProps<{
71
+ messages: ChatMessageType[];
72
+ next?: boolean;
73
+ isLoading?: boolean;
74
+ withoutAvatars?: boolean;
75
+ }>(),
76
+ {
77
+ next: false,
78
+ isLoading: false,
79
+ withoutAvatars: false,
80
+ },
78
81
  );
79
82
 
80
83
  const emit = defineEmits<(e: typeof ChatAction.LoadNextMessages) => void>();
@@ -86,36 +89,37 @@ const { showAvatar, showChatDate } = useChatMessages(
86
89
  ); // props values reactivity https://stackoverflow.com/questions/72408463/use-props-in-composables-vue3 @author ye.pohranichna
87
90
 
88
91
  const {
89
- showScrollToBottomBtn,
90
- newUnseenMessagesCount,
91
- scrollToBottom,
92
- handleChatScroll,
93
- handleChatResize,
92
+ showScrollToBottomBtn,
93
+ newUnseenMessagesCount,
94
+ scrollToBottom,
95
+ handleChatScroll,
96
+ handleChatResize,
94
97
  } = useChatScroll(
95
98
  messagesContainer,
96
99
  computed(() => props.messages), // props values reactivity https://stackoverflow.com/questions/72408463/use-props-in-composables-vue3 @author ye.pohranichna
97
100
  );
98
101
 
99
102
  function focusOnInput() {
100
- uiChatsEmitter?.on("focusOnTextField", focus);
103
+ uiChatsEmitter?.on("focusOnTextField", focus);
101
104
  }
102
105
 
103
106
  function clickOnImage(message: ChatMessageType) {
104
- uiChatsEmitter!.emit("clickChatMessageImage", message);
107
+ uiChatsEmitter!.emit("clickChatMessageImage", message);
105
108
  }
106
109
 
107
110
  onMounted(async () => {
108
- /* TODO: add loader on all chat(in the-chat-container?) and remove timeout after that */
109
- await nextTick();
110
- setTimeout(() => {
111
- scrollToBottom();
112
- }, 500);
111
+ /* TODO: add loader on all chat(in the-chat-container?) and remove timeout after that */
112
+ await nextTick();
113
+ setTimeout(() => {
114
+ scrollToBottom();
115
+ }, 500);
113
116
  });
114
117
  </script>
115
118
 
116
- <style scoped lang="scss">
117
- @use '@webitel/styleguide/scroll' as *;
118
-
119
+ <style
120
+ scoped
121
+ lang="scss"
122
+ >
119
123
  .the-chat-messages-container {
120
124
  position: relative;
121
125
  display: flex;
@@ -124,7 +128,6 @@ onMounted(async () => {
124
128
  }
125
129
 
126
130
  .the-chat-messages-container__wrapper {
127
- @extend %wt-scrollbar;
128
131
  display: flex;
129
132
  flex-direction: column;
130
133
  box-sizing: border-box;
@@ -135,5 +138,4 @@ onMounted(async () => {
135
138
  scrollbar-gutter: stable both-edges;
136
139
  gap: var(--spacing-xs);
137
140
  }
138
-
139
141
  </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
  }