igniteui-webcomponents 6.3.0-alpha.0 → 6.3.0-alpha.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 (269) hide show
  1. package/components/accordion/accordion.js +1 -4
  2. package/components/accordion/accordion.js.map +1 -1
  3. package/components/button/themes/button/button.base.css.js +1 -1
  4. package/components/button/themes/button/button.base.css.js.map +1 -1
  5. package/components/button/themes/button/shared/button.common.css.js +1 -1
  6. package/components/button/themes/button/shared/button.common.css.js.map +1 -1
  7. package/components/button/themes/button/shared/button.fluent.css.js +1 -1
  8. package/components/button/themes/button/shared/button.fluent.css.js.map +1 -1
  9. package/components/button/themes/button/shared/button.indigo.css.js +1 -1
  10. package/components/button/themes/button/shared/button.indigo.css.js.map +1 -1
  11. package/components/button/themes/icon-button/icon-button.base.css.js +1 -1
  12. package/components/button/themes/icon-button/icon-button.base.css.js.map +1 -1
  13. package/components/button/themes/icon-button/shared/icon-button.bootstrap.css.js +1 -1
  14. package/components/button/themes/icon-button/shared/icon-button.bootstrap.css.js.map +1 -1
  15. package/components/button/themes/icon-button/shared/icon-button.fluent.css.js +1 -1
  16. package/components/button/themes/icon-button/shared/icon-button.fluent.css.js.map +1 -1
  17. package/components/button/themes/icon-button/shared/icon-button.indigo.css.js +1 -1
  18. package/components/button/themes/icon-button/shared/icon-button.indigo.css.js.map +1 -1
  19. package/components/button/themes/icon-button/shared/icon-button.material.css.js +1 -1
  20. package/components/button/themes/icon-button/shared/icon-button.material.css.js.map +1 -1
  21. package/components/button-group/themes/shared/button/button.bootstrap.css.js +1 -1
  22. package/components/button-group/themes/shared/button/button.bootstrap.css.js.map +1 -1
  23. package/components/button-group/themes/shared/button/button.common.css.js +1 -1
  24. package/components/button-group/themes/shared/button/button.common.css.js.map +1 -1
  25. package/components/button-group/themes/shared/button/button.indigo.css.js +1 -1
  26. package/components/button-group/themes/shared/button/button.indigo.css.js.map +1 -1
  27. package/components/calendar/days-view/days-view.js +1 -3
  28. package/components/calendar/days-view/days-view.js.map +1 -1
  29. package/components/calendar/months-view/months-view.js +1 -3
  30. package/components/calendar/months-view/months-view.js.map +1 -1
  31. package/components/calendar/themes/year-month-view.base.css.js +1 -1
  32. package/components/calendar/themes/year-month-view.base.css.js.map +1 -1
  33. package/components/calendar/years-view/years-view.js +1 -3
  34. package/components/calendar/years-view/years-view.js.map +1 -1
  35. package/components/carousel/carousel.js +0 -3
  36. package/components/carousel/carousel.js.map +1 -1
  37. package/components/chat/assets/file.png +0 -0
  38. package/components/chat/assets/json.png +0 -0
  39. package/components/chat/assets/link.png +0 -0
  40. package/components/chat/chat-input.d.ts +6 -22
  41. package/components/chat/chat-input.js +34 -163
  42. package/components/chat/chat-input.js.map +1 -1
  43. package/components/chat/chat-message-list.d.ts +5 -46
  44. package/components/chat/chat-message-list.js +16 -105
  45. package/components/chat/chat-message-list.js.map +1 -1
  46. package/components/chat/chat-message.d.ts +8 -18
  47. package/components/chat/chat-message.js +40 -29
  48. package/components/chat/chat-message.js.map +1 -1
  49. package/components/chat/chat-renderer.d.ts +14 -0
  50. package/components/chat/chat-renderer.js +39 -0
  51. package/components/chat/chat-renderer.js.map +1 -0
  52. package/components/chat/chat-state.d.ts +116 -21
  53. package/components/chat/chat-state.js +446 -75
  54. package/components/chat/chat-state.js.map +1 -1
  55. package/components/chat/chat.d.ts +27 -14
  56. package/components/chat/chat.js +145 -63
  57. package/components/chat/chat.js.map +1 -1
  58. package/components/chat/markdown-renderer.d.ts +72 -0
  59. package/components/chat/markdown-renderer.js +71 -0
  60. package/components/chat/markdown-renderer.js.map +1 -0
  61. package/components/chat/message-attachments.d.ts +0 -7
  62. package/components/chat/message-attachments.js +3 -81
  63. package/components/chat/message-attachments.js.map +1 -1
  64. package/components/chat/plain-text-renderer.d.ts +15 -0
  65. package/components/chat/plain-text-renderer.js +7 -0
  66. package/components/chat/plain-text-renderer.js.map +1 -0
  67. package/components/chat/themes/chat.base.css.js +1 -1
  68. package/components/chat/themes/chat.base.css.js.map +1 -1
  69. package/components/chat/themes/dark/chat.bootstrap.css.js +1 -1
  70. package/components/chat/themes/dark/chat.bootstrap.css.js.map +1 -1
  71. package/components/chat/themes/dark/chat.fluent.css.js +1 -1
  72. package/components/chat/themes/dark/chat.fluent.css.js.map +1 -1
  73. package/components/chat/themes/dark/chat.indigo.css.js +1 -1
  74. package/components/chat/themes/dark/chat.indigo.css.js.map +1 -1
  75. package/components/chat/themes/input.base.css.js +1 -1
  76. package/components/chat/themes/input.base.css.js.map +1 -1
  77. package/components/chat/themes/light/chat.bootstrap.css.js +1 -1
  78. package/components/chat/themes/light/chat.bootstrap.css.js.map +1 -1
  79. package/components/chat/themes/light/chat.fluent.css.js +1 -1
  80. package/components/chat/themes/light/chat.fluent.css.js.map +1 -1
  81. package/components/chat/themes/light/chat.indigo.css.js +1 -1
  82. package/components/chat/themes/light/chat.indigo.css.js.map +1 -1
  83. package/components/chat/themes/light/chat.shared.css.js +1 -1
  84. package/components/chat/themes/light/chat.shared.css.js.map +1 -1
  85. package/components/chat/themes/message-attachments.base.css.js +1 -1
  86. package/components/chat/themes/message-attachments.base.css.js.map +1 -1
  87. package/components/chat/themes/message-list.base.css.js +1 -1
  88. package/components/chat/themes/message-list.base.css.js.map +1 -1
  89. package/components/chat/themes/message.base.css.js +1 -1
  90. package/components/chat/themes/message.base.css.js.map +1 -1
  91. package/components/chat/themes/message.d.ts +2 -0
  92. package/components/chat/themes/message.js +28 -0
  93. package/components/chat/themes/message.js.map +1 -0
  94. package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.js +3 -0
  95. package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.js.map +1 -0
  96. package/components/chat/themes/shared/chat-message/chat-message.common.css.d.ts +1 -0
  97. package/components/chat/themes/shared/chat-message/chat-message.common.css.js +3 -0
  98. package/components/chat/themes/shared/chat-message/chat-message.common.css.js.map +1 -0
  99. package/components/chat/themes/shared/chat-message/chat-message.fluent.css.d.ts +1 -0
  100. package/components/chat/themes/shared/chat-message/chat-message.fluent.css.js +3 -0
  101. package/components/chat/themes/shared/chat-message/chat-message.fluent.css.js.map +1 -0
  102. package/components/chat/themes/shared/chat-message/chat-message.indigo.css.d.ts +1 -0
  103. package/components/chat/themes/shared/chat-message/chat-message.indigo.css.js +3 -0
  104. package/components/chat/themes/shared/chat-message/chat-message.indigo.css.js.map +1 -0
  105. package/components/chat/themes/shared/chat.bootstrap.css.d.ts +1 -0
  106. package/components/chat/themes/shared/chat.bootstrap.css.js +3 -0
  107. package/components/chat/themes/shared/chat.bootstrap.css.js.map +1 -0
  108. package/components/chat/themes/shared/chat.indigo.css.d.ts +1 -0
  109. package/components/chat/themes/shared/chat.indigo.css.js +3 -0
  110. package/components/chat/themes/shared/chat.indigo.css.js.map +1 -0
  111. package/components/chat/themes/shared/input/input.common.css.js +1 -1
  112. package/components/chat/themes/shared/input/input.common.css.js.map +1 -1
  113. package/components/chat/themes/shared/input/input.indigo.css.js +1 -1
  114. package/components/chat/themes/shared/input/input.indigo.css.js.map +1 -1
  115. package/components/chat/themes/shared/message-attachments.common.css.js +1 -1
  116. package/components/chat/themes/shared/message-attachments.common.css.js.map +1 -1
  117. package/components/chat/themes/shared/message-list.common.css.js +1 -1
  118. package/components/chat/themes/shared/message-list.common.css.js.map +1 -1
  119. package/components/chat/themes/themes.js +6 -4
  120. package/components/chat/themes/themes.js.map +1 -1
  121. package/components/chat/types.d.ts +72 -18
  122. package/components/chat/types.js +7 -0
  123. package/components/chat/types.js.map +1 -1
  124. package/components/checkbox/themes/shared/switch/switch.bootstrap.css.js +1 -1
  125. package/components/checkbox/themes/shared/switch/switch.bootstrap.css.js.map +1 -1
  126. package/components/checkbox/themes/shared/switch/switch.common.css.js +1 -1
  127. package/components/checkbox/themes/shared/switch/switch.common.css.js.map +1 -1
  128. package/components/checkbox/themes/shared/switch/switch.fluent.css.js +1 -1
  129. package/components/checkbox/themes/shared/switch/switch.fluent.css.js.map +1 -1
  130. package/components/checkbox/themes/shared/switch/switch.indigo.css.js +1 -1
  131. package/components/checkbox/themes/shared/switch/switch.indigo.css.js.map +1 -1
  132. package/components/chip/themes/chip.base.css.js +1 -1
  133. package/components/chip/themes/chip.base.css.js.map +1 -1
  134. package/components/chip/themes/shared/chip.indigo.css.js +1 -1
  135. package/components/chip/themes/shared/chip.indigo.css.js.map +1 -1
  136. package/components/combo/controllers/navigation.js +1 -1
  137. package/components/combo/controllers/navigation.js.map +1 -1
  138. package/components/combo/themes/combo-item.base.css.js +1 -1
  139. package/components/combo/themes/combo-item.base.css.js.map +1 -1
  140. package/components/combo/themes/combo.base.css.js +1 -1
  141. package/components/combo/themes/combo.base.css.js.map +1 -1
  142. package/components/combo/themes/shared/combo.bootstrap.css.js +1 -1
  143. package/components/combo/themes/shared/combo.bootstrap.css.js.map +1 -1
  144. package/components/combo/themes/shared/combo.common.css.js +1 -1
  145. package/components/combo/themes/shared/combo.common.css.js.map +1 -1
  146. package/components/combo/themes/shared/combo.fluent.css.js +1 -1
  147. package/components/combo/themes/shared/combo.fluent.css.js.map +1 -1
  148. package/components/combo/themes/shared/combo.indigo.css.js +1 -1
  149. package/components/combo/themes/shared/combo.indigo.css.js.map +1 -1
  150. package/components/combo/themes/shared/combo.material.css.js +1 -1
  151. package/components/combo/themes/shared/combo.material.css.js.map +1 -1
  152. package/components/common/controllers/key-bindings.js +4 -3
  153. package/components/common/controllers/key-bindings.js.map +1 -1
  154. package/components/common/i18n/chat.resources.d.ts +8 -0
  155. package/components/common/i18n/chat.resources.js +8 -0
  156. package/components/common/i18n/chat.resources.js.map +1 -0
  157. package/components/common/util.d.ts +14 -0
  158. package/components/common/util.js +51 -1
  159. package/components/common/util.js.map +1 -1
  160. package/components/date-picker/date-picker.js +2 -2
  161. package/components/date-picker/date-picker.js.map +1 -1
  162. package/components/date-picker/themes/shared/date-picker.common.css.js +1 -1
  163. package/components/date-picker/themes/shared/date-picker.common.css.js.map +1 -1
  164. package/components/date-range-picker/date-range-picker.js +0 -1
  165. package/components/date-range-picker/date-range-picker.js.map +1 -1
  166. package/components/date-range-picker/themes/shared/date-range-picker.bootstrap.css.js +1 -1
  167. package/components/date-range-picker/themes/shared/date-range-picker.bootstrap.css.js.map +1 -1
  168. package/components/date-range-picker/themes/shared/date-range-picker.common.css.js +1 -1
  169. package/components/date-range-picker/themes/shared/date-range-picker.common.css.js.map +1 -1
  170. package/components/date-time-input/date-time-input.js +1 -1
  171. package/components/date-time-input/date-time-input.js.map +1 -1
  172. package/components/dropdown/themes/dropdown-group.base.css.js +1 -1
  173. package/components/dropdown/themes/dropdown-group.base.css.js.map +1 -1
  174. package/components/dropdown/themes/dropdown-item.base.css.js +1 -1
  175. package/components/dropdown/themes/dropdown-item.base.css.js.map +1 -1
  176. package/components/dropdown/themes/shared/group/dropdown-group.fluent.css.js +1 -1
  177. package/components/dropdown/themes/shared/group/dropdown-group.fluent.css.js.map +1 -1
  178. package/components/dropdown/themes/shared/header/dropdown-header.common.css.js +1 -1
  179. package/components/dropdown/themes/shared/header/dropdown-header.common.css.js.map +1 -1
  180. package/components/dropdown/themes/shared/header/dropdown-header.indigo.css.js +1 -1
  181. package/components/dropdown/themes/shared/header/dropdown-header.indigo.css.js.map +1 -1
  182. package/components/dropdown/themes/shared/item/dropdown-item.indigo.css.js +1 -1
  183. package/components/dropdown/themes/shared/item/dropdown-item.indigo.css.js.map +1 -1
  184. package/components/expansion-panel/expansion-panel.js +0 -1
  185. package/components/expansion-panel/expansion-panel.js.map +1 -1
  186. package/components/expansion-panel/themes/expansion-panel.base.css.js +1 -1
  187. package/components/expansion-panel/themes/expansion-panel.base.css.js.map +1 -1
  188. package/components/expansion-panel/themes/shared/expansion-panel.indigo.css.js +1 -1
  189. package/components/expansion-panel/themes/shared/expansion-panel.indigo.css.js.map +1 -1
  190. package/components/file-input/themes/shared/file-input.bootstrap.css.js +1 -1
  191. package/components/file-input/themes/shared/file-input.bootstrap.css.js.map +1 -1
  192. package/components/input/themes/shared/input.bootstrap.css.js +1 -1
  193. package/components/input/themes/shared/input.bootstrap.css.js.map +1 -1
  194. package/components/input/themes/shared/input.common.css.js +1 -1
  195. package/components/input/themes/shared/input.common.css.js.map +1 -1
  196. package/components/input/themes/shared/input.fluent.css.js +1 -1
  197. package/components/input/themes/shared/input.fluent.css.js.map +1 -1
  198. package/components/input/themes/shared/input.indigo.css.js +1 -1
  199. package/components/input/themes/shared/input.indigo.css.js.map +1 -1
  200. package/components/input/themes/shared/input.material.css.js +1 -1
  201. package/components/input/themes/shared/input.material.css.js.map +1 -1
  202. package/components/list/themes/header.base.css.js +1 -1
  203. package/components/list/themes/header.base.css.js.map +1 -1
  204. package/components/list/themes/item.base.css.js +1 -1
  205. package/components/list/themes/item.base.css.js.map +1 -1
  206. package/components/list/themes/shared/header/list-header.indigo.css.js +1 -1
  207. package/components/list/themes/shared/header/list-header.indigo.css.js.map +1 -1
  208. package/components/list/themes/shared/item/list-item.indigo.css.js +1 -1
  209. package/components/list/themes/shared/item/list-item.indigo.css.js.map +1 -1
  210. package/components/rating/rating.js +0 -1
  211. package/components/rating/rating.js.map +1 -1
  212. package/components/select/themes/dark/select.bootstrap.css.js +1 -1
  213. package/components/select/themes/dark/select.bootstrap.css.js.map +1 -1
  214. package/components/select/themes/light/select.bootstrap.css.js +1 -1
  215. package/components/select/themes/light/select.bootstrap.css.js.map +1 -1
  216. package/components/select/themes/shared/select.bootstrap.css.js +1 -1
  217. package/components/select/themes/shared/select.bootstrap.css.js.map +1 -1
  218. package/components/select/themes/shared/select.common.css.js +1 -1
  219. package/components/select/themes/shared/select.common.css.js.map +1 -1
  220. package/components/select/themes/shared/select.material.css.js +1 -1
  221. package/components/select/themes/shared/select.material.css.js.map +1 -1
  222. package/components/slider/slider-base.js +0 -1
  223. package/components/slider/slider-base.js.map +1 -1
  224. package/components/tabs/tabs.js +0 -1
  225. package/components/tabs/tabs.js.map +1 -1
  226. package/components/textarea/themes/shared/textarea.bootstrap.css.js +1 -1
  227. package/components/textarea/themes/shared/textarea.bootstrap.css.js.map +1 -1
  228. package/components/textarea/themes/shared/textarea.common.css.js +1 -1
  229. package/components/textarea/themes/shared/textarea.common.css.js.map +1 -1
  230. package/components/textarea/themes/shared/textarea.fluent.css.js +1 -1
  231. package/components/textarea/themes/shared/textarea.fluent.css.js.map +1 -1
  232. package/components/textarea/themes/shared/textarea.indigo.css.js +1 -1
  233. package/components/textarea/themes/shared/textarea.indigo.css.js.map +1 -1
  234. package/components/textarea/themes/shared/textarea.material.css.js +1 -1
  235. package/components/textarea/themes/shared/textarea.material.css.js.map +1 -1
  236. package/components/textarea/themes/textarea.base.css.js +1 -1
  237. package/components/textarea/themes/textarea.base.css.js.map +1 -1
  238. package/components/tree/themes/item.base.css.js +1 -1
  239. package/components/tree/themes/item.base.css.js.map +1 -1
  240. package/components/tree/themes/shared/item.indigo.css.js +1 -1
  241. package/components/tree/themes/shared/item.indigo.css.js.map +1 -1
  242. package/components/tree/tree.js +3 -1
  243. package/components/tree/tree.js.map +1 -1
  244. package/components/tree/tree.navigation.js +3 -3
  245. package/components/tree/tree.navigation.js.map +1 -1
  246. package/components/tree/tree.selection.js +6 -2
  247. package/components/tree/tree.selection.js.map +1 -1
  248. package/custom-elements.json +5131 -4707
  249. package/igniteui-webcomponents.css-data.json +1 -1
  250. package/igniteui-webcomponents.html-data.json +1 -1
  251. package/index.d.ts +3 -0
  252. package/index.js +3 -0
  253. package/index.js.map +1 -1
  254. package/package.json +1 -1
  255. package/themes/dark/bootstrap.css +1 -1
  256. package/themes/dark/fluent.css +1 -1
  257. package/themes/dark/indigo.css +1 -1
  258. package/themes/dark/material.css +1 -1
  259. package/themes/light/bootstrap.css +1 -1
  260. package/themes/light/fluent.css +1 -1
  261. package/themes/light/indigo.css +1 -1
  262. package/themes/light/material.css +1 -1
  263. package/web-types.json +2 -2
  264. package/components/chat/markdown-util.d.ts +0 -2
  265. package/components/chat/markdown-util.js +0 -22
  266. package/components/chat/markdown-util.js.map +0 -1
  267. package/components/chat/themes/shared/chat-message.common.css.js +0 -3
  268. package/components/chat/themes/shared/chat-message.common.css.js.map +0 -1
  269. /package/components/chat/themes/shared/{chat-message.common.css.d.ts → chat-message/chat-message.bootstrap.css.d.ts} +0 -0
@@ -1,15 +1,56 @@
1
+ import { html, nothing } from 'lit';
2
+ import { ifDefined } from 'lit/directives/if-defined.js';
3
+ import { createRef, ref } from 'lit/directives/ref.js';
4
+ import { enterKey } from '../common/controllers/key-bindings.js';
5
+ import { IgcChatResourceStringEN } from '../common/i18n/chat.resources.js';
6
+ import { partMap } from '../common/part-map.js';
7
+ import { registerIconFromText } from '../icon/icon.registry.js';
8
+ import { DefaultChatRenderer } from './chat-renderer.js';
9
+ import { PlainTextRenderer } from './plain-text-renderer.js';
10
+ import { copyIcon, regenerateIcon, thumbDownIcon, thumbUpIcon, } from './types.js';
1
11
  export class ChatState {
2
- get sortedMessagesIds() {
3
- return this._sortedMessages.map((m) => m.id);
12
+ get _sharedTooltip() {
13
+ return this._sharedTooltipRef?.value;
14
+ }
15
+ getIconName(fileType) {
16
+ if (fileType?.startsWith('image')) {
17
+ return 'file-image';
18
+ }
19
+ return 'file-document';
20
+ }
21
+ renderDefaultAttachmentHeaderText(attachment, message) {
22
+ return html `
23
+ ${html `${message.sender !== this.currentUserId
24
+ ? html `${attachment.type === 'image' ||
25
+ attachment.file?.type.startsWith('image/')
26
+ ? html `<igc-icon
27
+ name="image"
28
+ collection="material"
29
+ part="attachment-icon"
30
+ ></igc-icon>`
31
+ : html `<igc-icon
32
+ name="file"
33
+ collection="material"
34
+ part="attachment-icon"
35
+ ></igc-icon>`}`
36
+ : nothing} <span part="file-name">${attachment.name}</span>`}
37
+ `;
38
+ }
39
+ handleHeaderClick(attachment) {
40
+ this.emitEvent('igcAttachmentClick', { detail: attachment });
41
+ }
42
+ showTooltip(ev, text) {
43
+ if (!this._sharedTooltip)
44
+ return;
45
+ this._sharedTooltip.message = text;
46
+ this._sharedTooltip.hideDelay = 300;
47
+ this._sharedTooltip.show(ev.composedPath()[0]);
4
48
  }
5
49
  get messages() {
6
50
  return this._messages;
7
51
  }
8
52
  set messages(value) {
9
53
  this._messages = value;
10
- this._sortedMessages = value.slice().sort((a, b) => {
11
- return a.timestamp.getTime() - b.timestamp.getTime();
12
- });
13
54
  this._host.requestUpdate();
14
55
  }
15
56
  get options() {
@@ -18,6 +59,9 @@ export class ChatState {
18
59
  set options(value) {
19
60
  this._options = value;
20
61
  this._host.requestUpdate();
62
+ if (this._host.updateContextValue) {
63
+ this._host.updateContextValue();
64
+ }
21
65
  }
22
66
  get currentUserId() {
23
67
  return this._options?.currentUserId ?? 'user';
@@ -25,18 +69,27 @@ export class ChatState {
25
69
  get suggestionsPosition() {
26
70
  return this._options?.suggestionsPosition ?? this._suggestionsPosition;
27
71
  }
72
+ get stopTypingDelay() {
73
+ return this._options?.stopTypingDelay ?? this._stopTypingDelay;
74
+ }
28
75
  get textArea() {
29
76
  return this._textArea;
30
77
  }
31
78
  set textArea(value) {
32
79
  this._textArea = value;
33
80
  }
81
+ get textAreaRef() {
82
+ return this._textAreaRef;
83
+ }
34
84
  get inputAttachments() {
35
85
  return this._inputAttachments;
36
86
  }
37
87
  set inputAttachments(value) {
38
88
  this._inputAttachments = value;
39
89
  this._host.requestUpdate();
90
+ if (this._host.updateContextValue) {
91
+ this._host.updateContextValue();
92
+ }
40
93
  }
41
94
  get inputValue() {
42
95
  return this._inputValue;
@@ -44,43 +97,397 @@ export class ChatState {
44
97
  set inputValue(value) {
45
98
  this._inputValue = value;
46
99
  this._host.requestUpdate();
100
+ if (this._host.updateContextValue) {
101
+ this._host.updateContextValue();
102
+ }
103
+ }
104
+ get defaultTemplates() {
105
+ return this._defaultTemplates;
106
+ }
107
+ set defaultTemplates(templates) {
108
+ this._defaultTemplates = { ...templates };
109
+ }
110
+ get mergedTemplates() {
111
+ return { ...this._defaultTemplates, ...this.options?.templates };
112
+ }
113
+ get chatRenderer() {
114
+ if (!this._chatRenderer ||
115
+ this._chatRenderer !== this.options?.messageRenderer) {
116
+ this._chatRenderer = new DefaultChatRenderer(this.options?.messageRenderer ?? new PlainTextRenderer(), this.mergedTemplates);
117
+ this.options?.messageRenderer?.init?.();
118
+ }
119
+ return this._chatRenderer;
47
120
  }
48
121
  constructor(chat) {
49
122
  this._textArea = null;
50
123
  this._messages = [];
51
- this._sortedMessages = [];
52
124
  this._inputAttachments = [];
53
125
  this._inputValue = '';
54
126
  this._acceptedTypesCache = null;
55
127
  this._suggestionsPosition = 'below-messages';
56
- this._host = chat;
57
- }
58
- emitEvent(name, args) {
59
- return this._host.emitEvent(name, args);
60
- }
61
- handleInputChange(value) {
62
- this.inputValue = value;
63
- this.emitEvent('igcInputChange', { detail: { value: this.inputValue } });
64
- }
65
- addMessage(message) {
66
- const newMessage = {
67
- id: message.id ?? Date.now().toString(),
68
- text: message.text,
69
- sender: message.sender ?? this.currentUserId,
70
- timestamp: message.timestamp ?? new Date(),
71
- attachments: message.attachments || [],
128
+ this._stopTypingDelay = 3000;
129
+ this._isTyping = false;
130
+ this._lastTyped = Date.now();
131
+ this._fileIcon = new URL('./assets/file.png', import.meta.url).href;
132
+ this._jsonIcon = new URL('./assets/json.png', import.meta.url).href;
133
+ this._linkIcon = new URL('./assets/link.png', import.meta.url).href;
134
+ this._textAreaRef = createRef();
135
+ this._attachmentsButtonInputRef = createRef();
136
+ this._sharedTooltipRef = createRef();
137
+ this.resourceStrings = IgcChatResourceStringEN;
138
+ this._defaultTemplates = {
139
+ attachmentTemplate: (att, m) => this.renderDefaultAttachmentTemplate(att, m),
140
+ attachmentsTemplate: (m, _ctx) => this.renderDefaultAttachmentsTemplate(m),
141
+ attachmentHeaderTemplate: (att, msg) => this.renderDefaultAttachmentHeader(att, msg),
142
+ attachmentContentTemplate: (att) => this.renderDefaultAttachmentContent(att),
143
+ messageAuthorTemplate: () => { },
144
+ messageTemplate: (m, ctx) => this.renderDefaultMessageTemplate(m, ctx),
145
+ messageActionsTemplate: (message) => this.renderDefaultMessageActionsTemplate(message),
146
+ suggestionPrefixTemplate: () => { },
147
+ typingIndicatorTemplate: () => this.renderDefaultTypingIndicator(),
148
+ textInputTemplate: () => this.renderDefaultTextArea(),
149
+ textAreaActionsTemplate: () => this.renderDefaultActionsArea(),
150
+ textAreaAttachmentsTemplate: (attachments) => this.renderDefaultAttachmentsArea(attachments),
72
151
  };
73
- const allowed = this.emitEvent('igcMessageCreated', {
74
- detail: newMessage,
75
- cancelable: true,
76
- });
77
- if (allowed) {
78
- if (!this.messages.some((msg) => msg.id === newMessage.id)) {
79
- this.messages = [...this.messages, newMessage];
152
+ this.renderDefaultAttachmentsArea = (attachments) => {
153
+ return html `${attachments?.map((attachment, index) => html `
154
+ <div part="attachment-wrapper" role="listitem">
155
+ <igc-chip removable @igcRemove=${() => this.removeAttachment(index)}>
156
+ <igc-icon
157
+ slot="prefix"
158
+ name=${this.getIconName(attachment.file?.type ?? attachment.type)}
159
+ collection="material"
160
+ ></igc-icon>
161
+ <span part="attachment-name">${attachment.name}</span>
162
+ </igc-chip>
163
+ </div>
164
+ `)} `;
165
+ };
166
+ this.renderDefaultTextArea = () => {
167
+ return html ` <igc-textarea
168
+ part="text-input"
169
+ ${ref(this._textAreaRef)}
170
+ .placeholder=${this.options?.inputPlaceholder}
171
+ resize="auto"
172
+ rows="1"
173
+ .value=${this.inputValue}
174
+ @igcInput=${this.handleInput}
175
+ @focus=${this.handleFocus}
176
+ @blur=${this.handleBlur}
177
+ ></igc-textarea>`;
178
+ };
179
+ this.renderDefaultFileUploadButton = () => {
180
+ if (this.options?.disableInputAttachments)
181
+ return html ``;
182
+ return html `
183
+ <label for="input_attachments" part="upload-button">
184
+ <igc-icon-button
185
+ variant="flat"
186
+ name="attachment"
187
+ collection="material"
188
+ @click=${() => this._attachmentsButtonInputRef?.value?.click()}
189
+ ></igc-icon-button>
190
+ <input
191
+ type="file"
192
+ id="input_attachments"
193
+ name="input_attachments"
194
+ ${ref(this._attachmentsButtonInputRef)}
195
+ multiple
196
+ accept=${ifDefined(this.options?.acceptedFiles === '' ? undefined : this.options?.acceptedFiles)}
197
+ @change=${this.handleFileUpload}>
198
+ </input>
199
+ </label>
200
+ `;
201
+ };
202
+ this.renderDefaultSendButton = () => {
203
+ return html ` <igc-icon-button
204
+ aria-label="Send message"
205
+ name="send-message"
206
+ collection="material"
207
+ variant="contained"
208
+ part="send-button"
209
+ ?disabled=${!this.inputValue.trim() && this.inputAttachments.length === 0}
210
+ @click=${this.sendMessage}
211
+ ></igc-icon-button>`;
212
+ };
213
+ this.renderDefaultActionsArea = () => {
214
+ return html ` ${this.renderDefaultFileUploadButton()}
215
+ ${this.renderDefaultSendButton()}`;
216
+ };
217
+ this.renderDefaultTypingIndicator = () => {
218
+ return html `<div part="typing-indicator">
219
+ <div part="typing-dot"></div>
220
+ <div part="typing-dot"></div>
221
+ <div part="typing-dot"></div>
222
+ </div>`;
223
+ };
224
+ this.renderDefaultMessageTemplate = (m, ctx) => {
225
+ const templates = { ...this._defaultTemplates, ...ctx.templates };
226
+ return html `
227
+ ${templates.messageAuthorTemplate(m) ?? nothing}
228
+ ${ctx?.textContent ?? m.text}
229
+ ${m.attachments?.length
230
+ ? html `<igc-message-attachments .message=${m}>
231
+ </igc-message-attachments>`
232
+ : nothing}
233
+ ${templates.messageActionsTemplate(m) ?? nothing}
234
+ `;
235
+ };
236
+ this.renderDefaultAttachmentHeader = (attachment, message) => {
237
+ return this.renderDefaultAttachmentHeaderText(attachment, message);
238
+ };
239
+ this.renderDefaultAttachmentContent = (attachment) => {
240
+ const ext = this.getFileExtension(attachment.name);
241
+ const isImage = this.isImageAttachment(attachment);
242
+ const url = isImage
243
+ ? this.getURL(attachment)
244
+ : (this._fileIconMap[ext] ?? this._fileIconMap['default']);
245
+ const partName = isImage ? 'image-attachment' : 'file-attachment';
246
+ return html `<img part="${partName}" src=${url} alt=${attachment.name} />`;
247
+ };
248
+ this.renderDefaultMessageActionsTemplate = (message) => {
249
+ const isLastMessage = message === this.messages.at(-1);
250
+ return message?.sender !== this.currentUserId &&
251
+ message?.text.trim() &&
252
+ (!isLastMessage || !this._isTyping)
253
+ ? html `<div>
254
+ <igc-icon-button
255
+ id="copy-response-button"
256
+ @pointerenter=${(ev) => this.showTooltip(ev, this.resourceStrings.reactionCopyResponse)}
257
+ name="copy-response"
258
+ collection="material"
259
+ variant="flat"
260
+ @click=${(e) => this.handleMessageActionClick(e, message)}
261
+ ></igc-icon-button>
262
+ <igc-icon-button
263
+ id="good-response-button"
264
+ @pointerenter=${(ev) => this.showTooltip(ev, this.resourceStrings.reactionGoodResponse)}
265
+ name="good-response"
266
+ collection="material"
267
+ variant="flat"
268
+ @click=${(e) => this.handleMessageActionClick(e, message)}
269
+ ></igc-icon-button>
270
+ <igc-icon-button
271
+ id="bad-response-button"
272
+ @pointerenter=${(ev) => this.showTooltip(ev, this.resourceStrings.reactionBadResponse)}
273
+ name="bad-response"
274
+ variant="flat"
275
+ collection="material"
276
+ @click=${(e) => this.handleMessageActionClick(e, message)}
277
+ ></igc-icon-button>
278
+ <igc-icon-button
279
+ id="redo-button"
280
+ @pointerenter=${(ev) => this.showTooltip(ev, this.resourceStrings.reactionRedo)}
281
+ name="redo"
282
+ variant="flat"
283
+ collection="material"
284
+ @click=${(e) => this.handleMessageActionClick(e, message)}
285
+ ></igc-icon-button>
286
+ <igc-tooltip
287
+ id="sharedTooltip"
288
+ ${ref(this._sharedTooltipRef)}
289
+ ></igc-tooltip>
290
+ </div>`
291
+ : nothing;
292
+ };
293
+ this.handleMessageActionClick = (event, message) => {
294
+ const reaction = event.target.getAttribute('name');
295
+ this.emitEvent('igcMessageReact', {
296
+ detail: { message, reaction },
297
+ });
298
+ };
299
+ this.renderDefaultAttachmentTemplate = (att, msg) => {
300
+ const isCurrentUser = msg.sender === this.currentUserId;
301
+ const attachmentParts = {
302
+ attachment: true,
303
+ sent: isCurrentUser,
304
+ };
305
+ const contentParts = {
306
+ 'attachment-content': true,
307
+ sent: isCurrentUser,
308
+ };
309
+ const headerParts = {
310
+ 'attachment-header': true,
311
+ sent: isCurrentUser,
312
+ };
313
+ const content = html `<div part=${partMap(contentParts)}>
314
+ ${this.mergedTemplates.attachmentContentTemplate(att)}
315
+ </div>`;
316
+ const header = html ` <div
317
+ part=${partMap(headerParts)}
318
+ role="button"
319
+ @click=${() => this.handleHeaderClick(att)}
320
+ >
321
+ <div part="details">
322
+ ${this.mergedTemplates.attachmentHeaderTemplate(att, msg)}
323
+ </div>
324
+ </div>`;
325
+ return html `<div part=${partMap(attachmentParts)}>
326
+ ${isCurrentUser ? content : nothing} ${header}
327
+ ${!isCurrentUser ? content : nothing}
328
+ </div> `;
329
+ };
330
+ this.renderDefaultAttachmentsTemplate = (m) => {
331
+ return html `
332
+ ${(m.attachments ?? []).map((att) => this.mergedTemplates.attachmentTemplate(att, m)) || nothing}
333
+ `;
334
+ };
335
+ this.handleInput = ({ detail }) => {
336
+ if (detail === this.inputValue)
337
+ return;
338
+ this.inputValue = detail;
339
+ this.emitEvent('igcInputChange', { detail: { value: this.inputValue } });
340
+ };
341
+ this.emitEvent = (name, args) => {
342
+ return this._host.emitEvent(name, args);
343
+ };
344
+ this.addMessage = (message) => {
345
+ const newMessage = {
346
+ id: message.id ?? Date.now().toString(),
347
+ text: message.text,
348
+ sender: message.sender ?? this.currentUserId,
349
+ timestamp: message.timestamp ?? new Date(),
350
+ attachments: message.attachments || [],
351
+ };
352
+ const allowed = this.emitEvent('igcMessageCreated', {
353
+ detail: newMessage,
354
+ cancelable: true,
355
+ });
356
+ if (allowed) {
357
+ if (!this.messages.some((msg) => msg.id === newMessage.id)) {
358
+ this.messages = [...this.messages, newMessage];
359
+ }
360
+ this.inputValue = '';
361
+ this.inputAttachments = [];
362
+ }
363
+ };
364
+ this.getURL = (attachment) => {
365
+ if (attachment.url) {
366
+ return attachment.url;
80
367
  }
368
+ if (attachment.file) {
369
+ return URL.createObjectURL(attachment.file);
370
+ }
371
+ return '';
372
+ };
373
+ this._fileIconMap = {
374
+ pdf: this._fileIcon,
375
+ doc: this._fileIcon,
376
+ docx: this._fileIcon,
377
+ xls: this._fileIcon,
378
+ xlsx: this._fileIcon,
379
+ txt: this._fileIcon,
380
+ json: this._jsonIcon,
381
+ link: this._linkIcon,
382
+ default: this._fileIcon,
383
+ };
384
+ this.handleKeyDown = (e) => {
385
+ if (e.key.toLowerCase() === enterKey.toLowerCase() && !e.shiftKey) {
386
+ e.preventDefault();
387
+ this.sendMessage();
388
+ }
389
+ else {
390
+ this._lastTyped = Date.now();
391
+ if (!this._isTyping) {
392
+ this.emitEvent('igcTypingChange', {
393
+ detail: { isTyping: true },
394
+ });
395
+ this._isTyping = true;
396
+ }
397
+ const stopTypingDelay = this.stopTypingDelay;
398
+ setTimeout(() => {
399
+ if (this._isTyping &&
400
+ stopTypingDelay &&
401
+ this._lastTyped + stopTypingDelay < Date.now()) {
402
+ this.emitEvent('igcTypingChange', {
403
+ detail: { isTyping: false },
404
+ });
405
+ this._isTyping = false;
406
+ }
407
+ }, stopTypingDelay);
408
+ }
409
+ };
410
+ this.handleFocus = () => {
411
+ this.emitEvent('igcInputFocus');
412
+ };
413
+ this.handleBlur = () => {
414
+ this.emitEvent('igcInputBlur');
415
+ };
416
+ this.sendMessage = () => {
417
+ if (!this.inputValue.trim() && this.inputAttachments.length === 0)
418
+ return;
419
+ this.addMessage({
420
+ text: this.inputValue,
421
+ attachments: this.inputAttachments,
422
+ });
81
423
  this.inputValue = '';
82
- this.inputAttachments = [];
83
- }
424
+ if (this._textArea) {
425
+ this._textArea.style.height = 'auto';
426
+ }
427
+ this._host.updateComplete.then(() => {
428
+ this._textArea?.focus();
429
+ });
430
+ };
431
+ this.handleFileUpload = (e) => {
432
+ const input = e.target;
433
+ if (!input.files || input.files.length === 0)
434
+ return;
435
+ const files = Array.from(input.files);
436
+ this.attachFiles(files);
437
+ this._host.requestUpdate();
438
+ };
439
+ this.removeAttachment = (index) => {
440
+ const allowed = this.emitEvent('igcAttachmentChange', {
441
+ detail: this.inputAttachments.filter((_, i) => i !== index),
442
+ cancelable: true,
443
+ });
444
+ if (allowed) {
445
+ this.inputAttachments = this.inputAttachments.filter((_, i) => i !== index);
446
+ }
447
+ };
448
+ this.handleSuggestionClick = (suggestion) => {
449
+ this.addMessage({ text: suggestion });
450
+ if (this.textArea) {
451
+ this.textArea.focus();
452
+ }
453
+ };
454
+ this.updateAcceptedTypesCache = () => {
455
+ if (!this.options?.acceptedFiles) {
456
+ this._acceptedTypesCache = null;
457
+ return;
458
+ }
459
+ const types = this.options?.acceptedFiles
460
+ .split(',')
461
+ .map((type) => type.trim().toLowerCase());
462
+ this._acceptedTypesCache = {
463
+ extensions: new Set(types.filter((t) => t.startsWith('.'))),
464
+ mimeTypes: new Set(types.filter((t) => !t.startsWith('.') && !t.endsWith('/*'))),
465
+ wildcardTypes: new Set(types.filter((t) => t.endsWith('/*')).map((t) => t.slice(0, -2))),
466
+ };
467
+ };
468
+ this.isFileTypeAccepted = (file, type = '') => {
469
+ if (!this._acceptedTypesCache)
470
+ return true;
471
+ if (file === null && type === '')
472
+ return false;
473
+ const fileType = file != null ? file.type.toLowerCase() : type.toLowerCase();
474
+ const fileExtension = file != null
475
+ ? `.${file.name.split('.').pop()?.toLowerCase()}`
476
+ : `.${type.split('/').pop()?.toLowerCase()}`;
477
+ if (this._acceptedTypesCache.extensions.has(fileExtension)) {
478
+ return true;
479
+ }
480
+ if (this._acceptedTypesCache.mimeTypes.has(fileType)) {
481
+ return true;
482
+ }
483
+ const [fileBaseType] = fileType.split('/');
484
+ return this._acceptedTypesCache.wildcardTypes.has(fileBaseType);
485
+ };
486
+ this._host = chat;
487
+ registerIconFromText('copy-response', copyIcon, 'material');
488
+ registerIconFromText('good-response', thumbUpIcon, 'material');
489
+ registerIconFromText('bad-response', thumbDownIcon, 'material');
490
+ registerIconFromText('redo', regenerateIcon, 'material');
84
491
  }
85
492
  attachFiles(files) {
86
493
  const newAttachments = [];
@@ -106,56 +513,20 @@ export class ChatState {
106
513
  this.inputAttachments = [...this.inputAttachments, ...newAttachments];
107
514
  }
108
515
  }
109
- removeAttachment(index) {
110
- const allowed = this.emitEvent('igcAttachmentChange', {
111
- detail: this.inputAttachments.filter((_, i) => i !== index),
112
- cancelable: true,
113
- });
114
- if (allowed) {
115
- this.inputAttachments = this.inputAttachments.filter((_, i) => i !== index);
116
- }
516
+ isImageAttachment(attachment) {
517
+ return (attachment.type === 'image' ||
518
+ !!attachment.file?.type.startsWith('image/'));
117
519
  }
118
- handleSuggestionClick(suggestion) {
119
- this.addMessage({ text: suggestion });
120
- if (this.textArea) {
121
- this.textArea.focus();
520
+ getFileExtension(fileName) {
521
+ const parts = fileName.split('.');
522
+ if (parts.length > 1) {
523
+ return parts.pop().toLowerCase();
122
524
  }
525
+ return '';
123
526
  }
124
527
  updateOptions(options) {
125
528
  this.options = { ...this.options, ...options };
126
529
  }
127
- updateAcceptedTypesCache() {
128
- if (!this.options?.acceptedFiles) {
129
- this._acceptedTypesCache = null;
130
- return;
131
- }
132
- const types = this.options?.acceptedFiles
133
- .split(',')
134
- .map((type) => type.trim().toLowerCase());
135
- this._acceptedTypesCache = {
136
- extensions: new Set(types.filter((t) => t.startsWith('.'))),
137
- mimeTypes: new Set(types.filter((t) => !t.startsWith('.') && !t.endsWith('/*'))),
138
- wildcardTypes: new Set(types.filter((t) => t.endsWith('/*')).map((t) => t.slice(0, -2))),
139
- };
140
- }
141
- isFileTypeAccepted(file, type = '') {
142
- if (!this._acceptedTypesCache)
143
- return true;
144
- if (file === null && type === '')
145
- return false;
146
- const fileType = file != null ? file.type.toLowerCase() : type.toLowerCase();
147
- const fileExtension = file != null
148
- ? `.${file.name.split('.').pop()?.toLowerCase()}`
149
- : `.${type.split('/').pop()?.toLowerCase()}`;
150
- if (this._acceptedTypesCache.extensions.has(fileExtension)) {
151
- return true;
152
- }
153
- if (this._acceptedTypesCache.mimeTypes.has(fileType)) {
154
- return true;
155
- }
156
- const [fileBaseType] = fileType.split('/');
157
- return this._acceptedTypesCache.wildcardTypes.has(fileBaseType);
158
- }
159
530
  hasSlotContent(name) {
160
531
  return (this._host.renderRoot.querySelector(`slot[name=${name}]`)
161
532
  ?.childNodes.length !== 0);