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.
- package/components/accordion/accordion.js +1 -4
- package/components/accordion/accordion.js.map +1 -1
- package/components/button/themes/button/button.base.css.js +1 -1
- package/components/button/themes/button/button.base.css.js.map +1 -1
- package/components/button/themes/button/shared/button.common.css.js +1 -1
- package/components/button/themes/button/shared/button.common.css.js.map +1 -1
- package/components/button/themes/button/shared/button.fluent.css.js +1 -1
- package/components/button/themes/button/shared/button.fluent.css.js.map +1 -1
- package/components/button/themes/button/shared/button.indigo.css.js +1 -1
- package/components/button/themes/button/shared/button.indigo.css.js.map +1 -1
- package/components/button/themes/icon-button/icon-button.base.css.js +1 -1
- package/components/button/themes/icon-button/icon-button.base.css.js.map +1 -1
- package/components/button/themes/icon-button/shared/icon-button.bootstrap.css.js +1 -1
- package/components/button/themes/icon-button/shared/icon-button.bootstrap.css.js.map +1 -1
- package/components/button/themes/icon-button/shared/icon-button.fluent.css.js +1 -1
- package/components/button/themes/icon-button/shared/icon-button.fluent.css.js.map +1 -1
- package/components/button/themes/icon-button/shared/icon-button.indigo.css.js +1 -1
- package/components/button/themes/icon-button/shared/icon-button.indigo.css.js.map +1 -1
- package/components/button/themes/icon-button/shared/icon-button.material.css.js +1 -1
- package/components/button/themes/icon-button/shared/icon-button.material.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.bootstrap.css.js +1 -1
- package/components/button-group/themes/shared/button/button.bootstrap.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.common.css.js +1 -1
- package/components/button-group/themes/shared/button/button.common.css.js.map +1 -1
- package/components/button-group/themes/shared/button/button.indigo.css.js +1 -1
- package/components/button-group/themes/shared/button/button.indigo.css.js.map +1 -1
- package/components/calendar/days-view/days-view.js +1 -3
- package/components/calendar/days-view/days-view.js.map +1 -1
- package/components/calendar/months-view/months-view.js +1 -3
- package/components/calendar/months-view/months-view.js.map +1 -1
- package/components/calendar/themes/year-month-view.base.css.js +1 -1
- package/components/calendar/themes/year-month-view.base.css.js.map +1 -1
- package/components/calendar/years-view/years-view.js +1 -3
- package/components/calendar/years-view/years-view.js.map +1 -1
- package/components/carousel/carousel.js +0 -3
- package/components/carousel/carousel.js.map +1 -1
- package/components/chat/assets/file.png +0 -0
- package/components/chat/assets/json.png +0 -0
- package/components/chat/assets/link.png +0 -0
- package/components/chat/chat-input.d.ts +6 -22
- package/components/chat/chat-input.js +34 -163
- package/components/chat/chat-input.js.map +1 -1
- package/components/chat/chat-message-list.d.ts +5 -46
- package/components/chat/chat-message-list.js +16 -105
- package/components/chat/chat-message-list.js.map +1 -1
- package/components/chat/chat-message.d.ts +8 -18
- package/components/chat/chat-message.js +40 -29
- package/components/chat/chat-message.js.map +1 -1
- package/components/chat/chat-renderer.d.ts +14 -0
- package/components/chat/chat-renderer.js +39 -0
- package/components/chat/chat-renderer.js.map +1 -0
- package/components/chat/chat-state.d.ts +116 -21
- package/components/chat/chat-state.js +446 -75
- package/components/chat/chat-state.js.map +1 -1
- package/components/chat/chat.d.ts +27 -14
- package/components/chat/chat.js +145 -63
- package/components/chat/chat.js.map +1 -1
- package/components/chat/markdown-renderer.d.ts +72 -0
- package/components/chat/markdown-renderer.js +71 -0
- package/components/chat/markdown-renderer.js.map +1 -0
- package/components/chat/message-attachments.d.ts +0 -7
- package/components/chat/message-attachments.js +3 -81
- package/components/chat/message-attachments.js.map +1 -1
- package/components/chat/plain-text-renderer.d.ts +15 -0
- package/components/chat/plain-text-renderer.js +7 -0
- package/components/chat/plain-text-renderer.js.map +1 -0
- package/components/chat/themes/chat.base.css.js +1 -1
- package/components/chat/themes/chat.base.css.js.map +1 -1
- package/components/chat/themes/dark/chat.bootstrap.css.js +1 -1
- package/components/chat/themes/dark/chat.bootstrap.css.js.map +1 -1
- package/components/chat/themes/dark/chat.fluent.css.js +1 -1
- package/components/chat/themes/dark/chat.fluent.css.js.map +1 -1
- package/components/chat/themes/dark/chat.indigo.css.js +1 -1
- package/components/chat/themes/dark/chat.indigo.css.js.map +1 -1
- package/components/chat/themes/input.base.css.js +1 -1
- package/components/chat/themes/input.base.css.js.map +1 -1
- package/components/chat/themes/light/chat.bootstrap.css.js +1 -1
- package/components/chat/themes/light/chat.bootstrap.css.js.map +1 -1
- package/components/chat/themes/light/chat.fluent.css.js +1 -1
- package/components/chat/themes/light/chat.fluent.css.js.map +1 -1
- package/components/chat/themes/light/chat.indigo.css.js +1 -1
- package/components/chat/themes/light/chat.indigo.css.js.map +1 -1
- package/components/chat/themes/light/chat.shared.css.js +1 -1
- package/components/chat/themes/light/chat.shared.css.js.map +1 -1
- package/components/chat/themes/message-attachments.base.css.js +1 -1
- package/components/chat/themes/message-attachments.base.css.js.map +1 -1
- package/components/chat/themes/message-list.base.css.js +1 -1
- package/components/chat/themes/message-list.base.css.js.map +1 -1
- package/components/chat/themes/message.base.css.js +1 -1
- package/components/chat/themes/message.base.css.js.map +1 -1
- package/components/chat/themes/message.d.ts +2 -0
- package/components/chat/themes/message.js +28 -0
- package/components/chat/themes/message.js.map +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.js +3 -0
- package/components/chat/themes/shared/chat-message/chat-message.bootstrap.css.js.map +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.common.css.d.ts +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.common.css.js +3 -0
- package/components/chat/themes/shared/chat-message/chat-message.common.css.js.map +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.fluent.css.d.ts +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.fluent.css.js +3 -0
- package/components/chat/themes/shared/chat-message/chat-message.fluent.css.js.map +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.indigo.css.d.ts +1 -0
- package/components/chat/themes/shared/chat-message/chat-message.indigo.css.js +3 -0
- package/components/chat/themes/shared/chat-message/chat-message.indigo.css.js.map +1 -0
- package/components/chat/themes/shared/chat.bootstrap.css.d.ts +1 -0
- package/components/chat/themes/shared/chat.bootstrap.css.js +3 -0
- package/components/chat/themes/shared/chat.bootstrap.css.js.map +1 -0
- package/components/chat/themes/shared/chat.indigo.css.d.ts +1 -0
- package/components/chat/themes/shared/chat.indigo.css.js +3 -0
- package/components/chat/themes/shared/chat.indigo.css.js.map +1 -0
- package/components/chat/themes/shared/input/input.common.css.js +1 -1
- package/components/chat/themes/shared/input/input.common.css.js.map +1 -1
- package/components/chat/themes/shared/input/input.indigo.css.js +1 -1
- package/components/chat/themes/shared/input/input.indigo.css.js.map +1 -1
- package/components/chat/themes/shared/message-attachments.common.css.js +1 -1
- package/components/chat/themes/shared/message-attachments.common.css.js.map +1 -1
- package/components/chat/themes/shared/message-list.common.css.js +1 -1
- package/components/chat/themes/shared/message-list.common.css.js.map +1 -1
- package/components/chat/themes/themes.js +6 -4
- package/components/chat/themes/themes.js.map +1 -1
- package/components/chat/types.d.ts +72 -18
- package/components/chat/types.js +7 -0
- package/components/chat/types.js.map +1 -1
- package/components/checkbox/themes/shared/switch/switch.bootstrap.css.js +1 -1
- package/components/checkbox/themes/shared/switch/switch.bootstrap.css.js.map +1 -1
- package/components/checkbox/themes/shared/switch/switch.common.css.js +1 -1
- package/components/checkbox/themes/shared/switch/switch.common.css.js.map +1 -1
- package/components/checkbox/themes/shared/switch/switch.fluent.css.js +1 -1
- package/components/checkbox/themes/shared/switch/switch.fluent.css.js.map +1 -1
- package/components/checkbox/themes/shared/switch/switch.indigo.css.js +1 -1
- package/components/checkbox/themes/shared/switch/switch.indigo.css.js.map +1 -1
- package/components/chip/themes/chip.base.css.js +1 -1
- package/components/chip/themes/chip.base.css.js.map +1 -1
- package/components/chip/themes/shared/chip.indigo.css.js +1 -1
- package/components/chip/themes/shared/chip.indigo.css.js.map +1 -1
- package/components/combo/controllers/navigation.js +1 -1
- package/components/combo/controllers/navigation.js.map +1 -1
- package/components/combo/themes/combo-item.base.css.js +1 -1
- package/components/combo/themes/combo-item.base.css.js.map +1 -1
- package/components/combo/themes/combo.base.css.js +1 -1
- package/components/combo/themes/combo.base.css.js.map +1 -1
- package/components/combo/themes/shared/combo.bootstrap.css.js +1 -1
- package/components/combo/themes/shared/combo.bootstrap.css.js.map +1 -1
- package/components/combo/themes/shared/combo.common.css.js +1 -1
- package/components/combo/themes/shared/combo.common.css.js.map +1 -1
- package/components/combo/themes/shared/combo.fluent.css.js +1 -1
- package/components/combo/themes/shared/combo.fluent.css.js.map +1 -1
- package/components/combo/themes/shared/combo.indigo.css.js +1 -1
- package/components/combo/themes/shared/combo.indigo.css.js.map +1 -1
- package/components/combo/themes/shared/combo.material.css.js +1 -1
- package/components/combo/themes/shared/combo.material.css.js.map +1 -1
- package/components/common/controllers/key-bindings.js +4 -3
- package/components/common/controllers/key-bindings.js.map +1 -1
- package/components/common/i18n/chat.resources.d.ts +8 -0
- package/components/common/i18n/chat.resources.js +8 -0
- package/components/common/i18n/chat.resources.js.map +1 -0
- package/components/common/util.d.ts +14 -0
- package/components/common/util.js +51 -1
- package/components/common/util.js.map +1 -1
- package/components/date-picker/date-picker.js +2 -2
- package/components/date-picker/date-picker.js.map +1 -1
- package/components/date-picker/themes/shared/date-picker.common.css.js +1 -1
- package/components/date-picker/themes/shared/date-picker.common.css.js.map +1 -1
- package/components/date-range-picker/date-range-picker.js +0 -1
- package/components/date-range-picker/date-range-picker.js.map +1 -1
- package/components/date-range-picker/themes/shared/date-range-picker.bootstrap.css.js +1 -1
- package/components/date-range-picker/themes/shared/date-range-picker.bootstrap.css.js.map +1 -1
- package/components/date-range-picker/themes/shared/date-range-picker.common.css.js +1 -1
- package/components/date-range-picker/themes/shared/date-range-picker.common.css.js.map +1 -1
- package/components/date-time-input/date-time-input.js +1 -1
- package/components/date-time-input/date-time-input.js.map +1 -1
- package/components/dropdown/themes/dropdown-group.base.css.js +1 -1
- package/components/dropdown/themes/dropdown-group.base.css.js.map +1 -1
- package/components/dropdown/themes/dropdown-item.base.css.js +1 -1
- package/components/dropdown/themes/dropdown-item.base.css.js.map +1 -1
- package/components/dropdown/themes/shared/group/dropdown-group.fluent.css.js +1 -1
- package/components/dropdown/themes/shared/group/dropdown-group.fluent.css.js.map +1 -1
- package/components/dropdown/themes/shared/header/dropdown-header.common.css.js +1 -1
- package/components/dropdown/themes/shared/header/dropdown-header.common.css.js.map +1 -1
- package/components/dropdown/themes/shared/header/dropdown-header.indigo.css.js +1 -1
- package/components/dropdown/themes/shared/header/dropdown-header.indigo.css.js.map +1 -1
- package/components/dropdown/themes/shared/item/dropdown-item.indigo.css.js +1 -1
- package/components/dropdown/themes/shared/item/dropdown-item.indigo.css.js.map +1 -1
- package/components/expansion-panel/expansion-panel.js +0 -1
- package/components/expansion-panel/expansion-panel.js.map +1 -1
- package/components/expansion-panel/themes/expansion-panel.base.css.js +1 -1
- package/components/expansion-panel/themes/expansion-panel.base.css.js.map +1 -1
- package/components/expansion-panel/themes/shared/expansion-panel.indigo.css.js +1 -1
- package/components/expansion-panel/themes/shared/expansion-panel.indigo.css.js.map +1 -1
- package/components/file-input/themes/shared/file-input.bootstrap.css.js +1 -1
- package/components/file-input/themes/shared/file-input.bootstrap.css.js.map +1 -1
- package/components/input/themes/shared/input.bootstrap.css.js +1 -1
- package/components/input/themes/shared/input.bootstrap.css.js.map +1 -1
- package/components/input/themes/shared/input.common.css.js +1 -1
- package/components/input/themes/shared/input.common.css.js.map +1 -1
- package/components/input/themes/shared/input.fluent.css.js +1 -1
- package/components/input/themes/shared/input.fluent.css.js.map +1 -1
- package/components/input/themes/shared/input.indigo.css.js +1 -1
- package/components/input/themes/shared/input.indigo.css.js.map +1 -1
- package/components/input/themes/shared/input.material.css.js +1 -1
- package/components/input/themes/shared/input.material.css.js.map +1 -1
- package/components/list/themes/header.base.css.js +1 -1
- package/components/list/themes/header.base.css.js.map +1 -1
- package/components/list/themes/item.base.css.js +1 -1
- package/components/list/themes/item.base.css.js.map +1 -1
- package/components/list/themes/shared/header/list-header.indigo.css.js +1 -1
- package/components/list/themes/shared/header/list-header.indigo.css.js.map +1 -1
- package/components/list/themes/shared/item/list-item.indigo.css.js +1 -1
- package/components/list/themes/shared/item/list-item.indigo.css.js.map +1 -1
- package/components/rating/rating.js +0 -1
- package/components/rating/rating.js.map +1 -1
- package/components/select/themes/dark/select.bootstrap.css.js +1 -1
- package/components/select/themes/dark/select.bootstrap.css.js.map +1 -1
- package/components/select/themes/light/select.bootstrap.css.js +1 -1
- package/components/select/themes/light/select.bootstrap.css.js.map +1 -1
- package/components/select/themes/shared/select.bootstrap.css.js +1 -1
- package/components/select/themes/shared/select.bootstrap.css.js.map +1 -1
- package/components/select/themes/shared/select.common.css.js +1 -1
- package/components/select/themes/shared/select.common.css.js.map +1 -1
- package/components/select/themes/shared/select.material.css.js +1 -1
- package/components/select/themes/shared/select.material.css.js.map +1 -1
- package/components/slider/slider-base.js +0 -1
- package/components/slider/slider-base.js.map +1 -1
- package/components/tabs/tabs.js +0 -1
- package/components/tabs/tabs.js.map +1 -1
- package/components/textarea/themes/shared/textarea.bootstrap.css.js +1 -1
- package/components/textarea/themes/shared/textarea.bootstrap.css.js.map +1 -1
- package/components/textarea/themes/shared/textarea.common.css.js +1 -1
- package/components/textarea/themes/shared/textarea.common.css.js.map +1 -1
- package/components/textarea/themes/shared/textarea.fluent.css.js +1 -1
- package/components/textarea/themes/shared/textarea.fluent.css.js.map +1 -1
- package/components/textarea/themes/shared/textarea.indigo.css.js +1 -1
- package/components/textarea/themes/shared/textarea.indigo.css.js.map +1 -1
- package/components/textarea/themes/shared/textarea.material.css.js +1 -1
- package/components/textarea/themes/shared/textarea.material.css.js.map +1 -1
- package/components/textarea/themes/textarea.base.css.js +1 -1
- package/components/textarea/themes/textarea.base.css.js.map +1 -1
- package/components/tree/themes/item.base.css.js +1 -1
- package/components/tree/themes/item.base.css.js.map +1 -1
- package/components/tree/themes/shared/item.indigo.css.js +1 -1
- package/components/tree/themes/shared/item.indigo.css.js.map +1 -1
- package/components/tree/tree.js +3 -1
- package/components/tree/tree.js.map +1 -1
- package/components/tree/tree.navigation.js +3 -3
- package/components/tree/tree.navigation.js.map +1 -1
- package/components/tree/tree.selection.js +6 -2
- package/components/tree/tree.selection.js.map +1 -1
- package/custom-elements.json +5131 -4707
- package/igniteui-webcomponents.css-data.json +1 -1
- package/igniteui-webcomponents.html-data.json +1 -1
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/themes/dark/bootstrap.css +1 -1
- package/themes/dark/fluent.css +1 -1
- package/themes/dark/indigo.css +1 -1
- package/themes/dark/material.css +1 -1
- package/themes/light/bootstrap.css +1 -1
- package/themes/light/fluent.css +1 -1
- package/themes/light/indigo.css +1 -1
- package/themes/light/material.css +1 -1
- package/web-types.json +2 -2
- package/components/chat/markdown-util.d.ts +0 -2
- package/components/chat/markdown-util.js +0 -22
- package/components/chat/markdown-util.js.map +0 -1
- package/components/chat/themes/shared/chat-message.common.css.js +0 -3
- package/components/chat/themes/shared/chat-message.common.css.js.map +0 -1
- /package/components/chat/themes/shared/{chat-message.common.css.d.ts → chat-message/chat-message.bootstrap.css.d.ts} +0 -0
|
@@ -6,10 +6,9 @@ import { LitElement } from 'lit';
|
|
|
6
6
|
*
|
|
7
7
|
* This component:
|
|
8
8
|
* - Renders messages using the `<igc-chat-message>` component.
|
|
9
|
-
* - Supports keyboard navigation between messages (Home, End, ArrowUp, ArrowDown).
|
|
10
9
|
* - Manages focus highlighting on active messages.
|
|
11
10
|
* - Automatically scrolls to the bottom when new messages arrive, unless auto-scroll is disabled.
|
|
12
|
-
* - Displays a typing indicator if the chat state option `
|
|
11
|
+
* - Displays a typing indicator if the chat state option `isTyping` is true.
|
|
13
12
|
*
|
|
14
13
|
* Accessibility:
|
|
15
14
|
* - Uses ARIA roles and properties for grouping and active descendant management.
|
|
@@ -21,37 +20,16 @@ export default class IgcChatMessageListComponent extends LitElement {
|
|
|
21
20
|
static readonly tagName = "igc-chat-message-list";
|
|
22
21
|
/** Styles applied to the component */
|
|
23
22
|
static styles: import("lit").CSSResult[];
|
|
24
|
-
/**
|
|
25
|
-
* Consumed chat state context providing messages, options, and user data.
|
|
26
|
-
* @private
|
|
27
|
-
*/
|
|
28
|
-
private _chatState?;
|
|
29
|
-
/**
|
|
30
|
-
* Currently active message id used for focus and keyboard navigation.
|
|
31
|
-
* @private
|
|
32
|
-
*/
|
|
33
|
-
private _activeMessageId;
|
|
34
23
|
/**
|
|
35
24
|
* Registers this component and its dependencies.
|
|
36
25
|
* Used internally for component setup.
|
|
37
26
|
*/
|
|
38
27
|
static register(): void;
|
|
39
|
-
constructor();
|
|
40
|
-
/**
|
|
41
|
-
* Formats a date to a human-readable label.
|
|
42
|
-
* Returns 'Today', 'Yesterday', or localized date string.
|
|
43
|
-
* @param date - Date object to format
|
|
44
|
-
* @returns formatted string
|
|
45
|
-
* @private
|
|
46
|
-
*/
|
|
47
|
-
private formatDate;
|
|
48
28
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @param messages - Array of messages to group
|
|
51
|
-
* @returns Array of groups with date label and messages
|
|
29
|
+
* Consumed chat state context providing messages, options, and user data.
|
|
52
30
|
* @private
|
|
53
31
|
*/
|
|
54
|
-
private
|
|
32
|
+
private _chatState?;
|
|
55
33
|
/**
|
|
56
34
|
* Scrolls the container to the bottom, typically called after new messages are rendered.
|
|
57
35
|
* @private
|
|
@@ -62,26 +40,7 @@ export default class IgcChatMessageListComponent extends LitElement {
|
|
|
62
40
|
* @param messageId - The id of the message to scroll to
|
|
63
41
|
* @private
|
|
64
42
|
*/
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Handles focus entering the message list container.
|
|
68
|
-
* Sets the active message to the last message for keyboard navigation.
|
|
69
|
-
* @private
|
|
70
|
-
*/
|
|
71
|
-
private handleFocusIn;
|
|
72
|
-
/**
|
|
73
|
-
* Handles focus leaving the message list container.
|
|
74
|
-
* Clears the active message.
|
|
75
|
-
* @private
|
|
76
|
-
*/
|
|
77
|
-
private handleFocusOut;
|
|
78
|
-
/**
|
|
79
|
-
* Handles keyboard navigation within the message list.
|
|
80
|
-
* Supports Home, End, ArrowUp, ArrowDown keys to move active message focus.
|
|
81
|
-
* @param e KeyboardEvent from user input
|
|
82
|
-
* @private
|
|
83
|
-
*/
|
|
84
|
-
private navigateToMessage;
|
|
43
|
+
scrollToMessage(messageId: string): void;
|
|
85
44
|
/**
|
|
86
45
|
* Lifecycle: called when the component updates.
|
|
87
46
|
* Scrolls to bottom unless auto-scroll is disabled.
|
|
@@ -93,7 +52,7 @@ export default class IgcChatMessageListComponent extends LitElement {
|
|
|
93
52
|
*/
|
|
94
53
|
protected firstUpdated(): void;
|
|
95
54
|
/**
|
|
96
|
-
* Renders the typing indicator template
|
|
55
|
+
* Renders the typing indicator template.
|
|
97
56
|
* @protected
|
|
98
57
|
*/
|
|
99
58
|
protected renderLoadingTemplate(): Generator<import("lit-html").TemplateResult<1>, void, unknown>;
|
|
@@ -6,10 +6,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { consume } from '@lit/context';
|
|
8
8
|
import { html, LitElement, nothing } from 'lit';
|
|
9
|
-
import { state } from 'lit/decorators.js';
|
|
10
9
|
import { repeat } from 'lit/directives/repeat.js';
|
|
11
10
|
import { chatContext } from '../common/context.js';
|
|
12
|
-
import { addKeybindings, arrowDown, arrowUp, endKey, homeKey, } from '../common/controllers/key-bindings.js';
|
|
13
11
|
import { registerComponent } from '../common/definitions/register.js';
|
|
14
12
|
import IgcChatMessageComponent from './chat-message.js';
|
|
15
13
|
import { styles } from './themes/message-list.base.css.js';
|
|
@@ -18,45 +16,6 @@ class IgcChatMessageListComponent extends LitElement {
|
|
|
18
16
|
static register() {
|
|
19
17
|
registerComponent(IgcChatMessageListComponent, IgcChatMessageComponent);
|
|
20
18
|
}
|
|
21
|
-
constructor() {
|
|
22
|
-
super();
|
|
23
|
-
this._activeMessageId = '';
|
|
24
|
-
addKeybindings(this)
|
|
25
|
-
.set(homeKey, this.navigateToMessage)
|
|
26
|
-
.set(endKey, this.navigateToMessage)
|
|
27
|
-
.set(arrowUp, this.navigateToMessage)
|
|
28
|
-
.set(arrowDown, this.navigateToMessage);
|
|
29
|
-
}
|
|
30
|
-
formatDate(date) {
|
|
31
|
-
const today = new Date();
|
|
32
|
-
const yesterday = new Date(today);
|
|
33
|
-
yesterday.setDate(yesterday.getDate() - 1);
|
|
34
|
-
if (date.toDateString() === today.toDateString()) {
|
|
35
|
-
return 'Today';
|
|
36
|
-
}
|
|
37
|
-
if (date.toDateString() === yesterday.toDateString()) {
|
|
38
|
-
return 'Yesterday';
|
|
39
|
-
}
|
|
40
|
-
return date.toLocaleDateString('en-US', {
|
|
41
|
-
weekday: 'long',
|
|
42
|
-
month: 'short',
|
|
43
|
-
day: 'numeric',
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
groupMessagesByDate(messages) {
|
|
47
|
-
const grouped = {};
|
|
48
|
-
messages.forEach((message) => {
|
|
49
|
-
const dateStr = this.formatDate(message.timestamp);
|
|
50
|
-
if (!grouped[dateStr]) {
|
|
51
|
-
grouped[dateStr] = [];
|
|
52
|
-
}
|
|
53
|
-
grouped[dateStr].push(message);
|
|
54
|
-
});
|
|
55
|
-
return Object.keys(grouped).map((date) => ({
|
|
56
|
-
date,
|
|
57
|
-
messages: grouped[date],
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
19
|
scrollToBottom() {
|
|
61
20
|
requestAnimationFrame(() => {
|
|
62
21
|
const container = this.shadowRoot?.host;
|
|
@@ -69,47 +28,6 @@ class IgcChatMessageListComponent extends LitElement {
|
|
|
69
28
|
const messageElement = this.shadowRoot?.querySelector(`#message-${messageId}`);
|
|
70
29
|
messageElement?.scrollIntoView();
|
|
71
30
|
}
|
|
72
|
-
handleFocusIn() {
|
|
73
|
-
if (!this._chatState?.messages || this._chatState.messages.length === 0) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const lastMessage = this._chatState.sortedMessagesIds?.pop() ?? '';
|
|
77
|
-
this._activeMessageId = lastMessage !== '' ? `message-${lastMessage}` : '';
|
|
78
|
-
}
|
|
79
|
-
handleFocusOut() {
|
|
80
|
-
this._activeMessageId = '';
|
|
81
|
-
}
|
|
82
|
-
navigateToMessage(e) {
|
|
83
|
-
if (!this._chatState?.messages || this._chatState.messages.length === 0) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const currentIndex = this._chatState?.sortedMessagesIds.findIndex((id) => `message-${id}` === this._activeMessageId);
|
|
87
|
-
let activeMessageId = '';
|
|
88
|
-
const key = e.key.toLowerCase();
|
|
89
|
-
switch (key) {
|
|
90
|
-
case 'home':
|
|
91
|
-
activeMessageId = this._chatState.sortedMessagesIds[0];
|
|
92
|
-
break;
|
|
93
|
-
case 'end':
|
|
94
|
-
activeMessageId =
|
|
95
|
-
this._chatState.sortedMessagesIds[this._chatState.sortedMessagesIds.length - 1];
|
|
96
|
-
break;
|
|
97
|
-
case 'arrowup':
|
|
98
|
-
if (currentIndex > 0) {
|
|
99
|
-
activeMessageId = this._chatState.sortedMessagesIds[currentIndex - 1];
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
case 'arrowdown':
|
|
103
|
-
if (currentIndex < this._chatState?.messages.length - 1) {
|
|
104
|
-
activeMessageId = this._chatState.sortedMessagesIds[currentIndex + 1];
|
|
105
|
-
}
|
|
106
|
-
break;
|
|
107
|
-
default:
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
this._activeMessageId = `message-${activeMessageId}`;
|
|
111
|
-
this.scrollToMessage(activeMessageId);
|
|
112
|
-
}
|
|
113
31
|
updated() {
|
|
114
32
|
if (!this._chatState?.options?.disableAutoScroll) {
|
|
115
33
|
this.scrollToBottom();
|
|
@@ -121,44 +39,40 @@ class IgcChatMessageListComponent extends LitElement {
|
|
|
121
39
|
}
|
|
122
40
|
}
|
|
123
41
|
*renderLoadingTemplate() {
|
|
124
|
-
yield html `${this._chatState?.options?.templates?.
|
|
125
|
-
? this._chatState.options.templates.
|
|
42
|
+
yield html `${this._chatState?.options?.templates?.typingIndicatorTemplate
|
|
43
|
+
? this._chatState.options.templates.typingIndicatorTemplate
|
|
126
44
|
: html `<div part="typing-indicator">
|
|
127
45
|
<div part="typing-dot"></div>
|
|
128
46
|
<div part="typing-dot"></div>
|
|
129
47
|
<div part="typing-dot"></div>
|
|
48
|
+
<div part="typing-dot"></div>
|
|
130
49
|
</div>`}`;
|
|
131
50
|
}
|
|
132
51
|
render() {
|
|
133
|
-
const
|
|
52
|
+
const messages = this._chatState?.messages ?? [];
|
|
134
53
|
return html `
|
|
135
54
|
<div
|
|
136
55
|
part="message-container"
|
|
137
|
-
aria-activedescendant=${this._activeMessageId}
|
|
138
56
|
role="group"
|
|
139
57
|
aria-label="Message list"
|
|
140
58
|
tabindex="0"
|
|
141
|
-
@focusin=${this.handleFocusIn}
|
|
142
|
-
@focusout=${this.handleFocusOut}
|
|
143
59
|
></div>
|
|
144
60
|
<div part="message-list">
|
|
145
|
-
|
|
146
|
-
${repeat(group.messages, (message) => message.id, (message) => {
|
|
61
|
+
${repeat(messages, (message) => message.id, (message) => {
|
|
147
62
|
const messageId = `message-${message.id}`;
|
|
148
63
|
return html `
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
64
|
+
<igc-chat-message
|
|
65
|
+
id=${messageId}
|
|
66
|
+
role="option"
|
|
67
|
+
part="message-item"
|
|
68
|
+
.message=${message}
|
|
69
|
+
exportparts="message-container, message-text, message-attachments, message-actions,
|
|
70
|
+
attachments-container, attachment, attachment-header, attachment-content, attachment-icon, file-name, actions: attachment-actions"
|
|
71
|
+
>
|
|
72
|
+
</igc-chat-message>
|
|
73
|
+
`;
|
|
159
74
|
})}
|
|
160
|
-
|
|
161
|
-
${this._chatState?.options?.isComposing
|
|
75
|
+
${this._chatState?.options?.isTyping
|
|
162
76
|
? this.renderLoadingTemplate()
|
|
163
77
|
: nothing}
|
|
164
78
|
</div>
|
|
@@ -172,7 +86,4 @@ export default IgcChatMessageListComponent;
|
|
|
172
86
|
__decorate([
|
|
173
87
|
consume({ context: chatContext, subscribe: true })
|
|
174
88
|
], IgcChatMessageListComponent.prototype, "_chatState", void 0);
|
|
175
|
-
__decorate([
|
|
176
|
-
state()
|
|
177
|
-
], IgcChatMessageListComponent.prototype, "_activeMessageId", void 0);
|
|
178
89
|
//# sourceMappingURL=chat-message-list.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-message-list.js","sourceRoot":"","sources":["../../../src/components/chat/chat-message-list.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, nothing } from 'lit';\nimport { state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { chatContext } from '../common/context.js';\nimport {\n addKeybindings,\n arrowDown,\n arrowUp,\n endKey,\n homeKey,\n} from '../common/controllers/key-bindings.js';\nimport { registerComponent } from '../common/definitions/register.js';\nimport IgcChatMessageComponent from './chat-message.js';\nimport type { ChatState } from './chat-state.js';\nimport { styles } from './themes/message-list.base.css.js';\nimport { styles as shared } from './themes/shared/message-list.common.css.js';\nimport type { IgcMessage } from './types.js';\n\n/**\n * A chat message list component that displays a list of chat messages grouped by date.\n *\n * @element igc-chat-message-list\n *\n * This component:\n * - Renders messages using the `<igc-chat-message>` component.\n * - Supports keyboard navigation between messages (Home, End, ArrowUp, ArrowDown).\n * - Manages focus highlighting on active messages.\n * - Automatically scrolls to the bottom when new messages arrive, unless auto-scroll is disabled.\n * - Displays a typing indicator if the chat state option `isComposing` is true.\n *\n * Accessibility:\n * - Uses ARIA roles and properties for grouping and active descendant management.\n * - Message items have role=\"option\" for assistive technologies.\n *\n */\nexport default class IgcChatMessageListComponent extends LitElement {\n /** Tag name of the custom element. */\n public static readonly tagName = 'igc-chat-message-list';\n\n /** Styles applied to the component */\n public static override styles = [styles, shared];\n\n /**\n * Consumed chat state context providing messages, options, and user data.\n * @private\n */\n @consume({ context: chatContext, subscribe: true })\n private _chatState?: ChatState;\n\n /**\n * Currently active message id used for focus and keyboard navigation.\n * @private\n */\n @state()\n private _activeMessageId = '';\n\n /**\n * Registers this component and its dependencies.\n * Used internally for component setup.\n */\n /* blazorSuppress */\n public static register() {\n registerComponent(IgcChatMessageListComponent, IgcChatMessageComponent);\n }\n\n constructor() {\n super();\n addKeybindings(this)\n .set(homeKey, this.navigateToMessage)\n .set(endKey, this.navigateToMessage)\n .set(arrowUp, this.navigateToMessage)\n .set(arrowDown, this.navigateToMessage);\n }\n\n /**\n * Formats a date to a human-readable label.\n * Returns 'Today', 'Yesterday', or localized date string.\n * @param date - Date object to format\n * @returns formatted string\n * @private\n */\n private formatDate(date: Date): string {\n const today = new Date();\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n\n if (date.toDateString() === today.toDateString()) {\n return 'Today';\n }\n\n if (date.toDateString() === yesterday.toDateString()) {\n return 'Yesterday';\n }\n\n return date.toLocaleDateString('en-US', {\n weekday: 'long',\n month: 'short',\n day: 'numeric',\n });\n }\n\n /**\n * Groups messages by their date labels.\n * @param messages - Array of messages to group\n * @returns Array of groups with date label and messages\n * @private\n */\n private groupMessagesByDate(\n messages: IgcMessage[]\n ): { date: string; messages: IgcMessage[] }[] {\n const grouped: { [key: string]: IgcMessage[] } = {};\n\n messages.forEach((message) => {\n const dateStr = this.formatDate(message.timestamp);\n if (!grouped[dateStr]) {\n grouped[dateStr] = [];\n }\n grouped[dateStr].push(message);\n });\n\n return Object.keys(grouped).map((date) => ({\n date,\n messages: grouped[date],\n }));\n }\n\n /**\n * Scrolls the container to the bottom, typically called after new messages are rendered.\n * @private\n */\n private scrollToBottom() {\n requestAnimationFrame(() => {\n const container = this.shadowRoot?.host as HTMLElement;\n if (container) {\n container.scrollTop = container.scrollHeight;\n }\n });\n }\n\n /**\n * Scrolls the view to a specific message by id.\n * @param messageId - The id of the message to scroll to\n * @private\n */\n private scrollToMessage(messageId: string) {\n const messageElement = this.shadowRoot?.querySelector(\n `#message-${messageId}`\n );\n messageElement?.scrollIntoView();\n }\n\n /**\n * Handles focus entering the message list container.\n * Sets the active message to the last message for keyboard navigation.\n * @private\n */\n private handleFocusIn() {\n if (!this._chatState?.messages || this._chatState.messages.length === 0) {\n return;\n }\n const lastMessage = this._chatState.sortedMessagesIds?.pop() ?? '';\n this._activeMessageId = lastMessage !== '' ? `message-${lastMessage}` : '';\n }\n\n /**\n * Handles focus leaving the message list container.\n * Clears the active message.\n * @private\n */\n private handleFocusOut() {\n this._activeMessageId = '';\n }\n\n /**\n * Handles keyboard navigation within the message list.\n * Supports Home, End, ArrowUp, ArrowDown keys to move active message focus.\n * @param e KeyboardEvent from user input\n * @private\n */\n private navigateToMessage(e: KeyboardEvent) {\n if (!this._chatState?.messages || this._chatState.messages.length === 0) {\n return;\n }\n\n const currentIndex = this._chatState?.sortedMessagesIds.findIndex(\n (id) => `message-${id}` === this._activeMessageId\n );\n let activeMessageId = '';\n const key = e.key.toLowerCase();\n\n switch (key) {\n case 'home':\n activeMessageId = this._chatState.sortedMessagesIds[0];\n break;\n case 'end':\n activeMessageId =\n this._chatState.sortedMessagesIds[\n this._chatState.sortedMessagesIds.length - 1\n ];\n break;\n case 'arrowup':\n if (currentIndex > 0) {\n activeMessageId = this._chatState.sortedMessagesIds[currentIndex - 1];\n }\n break;\n case 'arrowdown':\n if (currentIndex < this._chatState?.messages.length - 1) {\n activeMessageId = this._chatState.sortedMessagesIds[currentIndex + 1];\n }\n break;\n default:\n return; // Ignore other keys\n }\n\n this._activeMessageId = `message-${activeMessageId}`;\n this.scrollToMessage(activeMessageId);\n }\n\n /**\n * Lifecycle: called when the component updates.\n * Scrolls to bottom unless auto-scroll is disabled.\n */\n protected override updated() {\n if (!this._chatState?.options?.disableAutoScroll) {\n this.scrollToBottom();\n }\n }\n\n /**\n * Lifecycle: called after first render.\n * Scrolls to bottom unless auto-scroll is disabled.\n */\n protected override firstUpdated() {\n if (!this._chatState?.options?.disableAutoScroll) {\n this.scrollToBottom();\n }\n }\n\n /**\n * Renders the typing indicator template if composing.\n * @protected\n */\n protected *renderLoadingTemplate() {\n yield html`${this._chatState?.options?.templates?.composingIndicatorTemplate\n ? this._chatState.options.templates.composingIndicatorTemplate\n : html`<div part=\"typing-indicator\">\n <div part=\"typing-dot\"></div>\n <div part=\"typing-dot\"></div>\n <div part=\"typing-dot\"></div>\n </div>`}`;\n }\n\n /**\n * Main render method.\n * Groups messages by date and renders each message.\n * Shows the typing indicator if applicable.\n */\n protected override render() {\n const groupedMessages = this.groupMessagesByDate(\n this._chatState?.messages ?? []\n );\n\n return html`\n <div\n part=\"message-container\"\n aria-activedescendant=${this._activeMessageId}\n role=\"group\"\n aria-label=\"Message list\"\n tabindex=\"0\"\n @focusin=${this.handleFocusIn}\n @focusout=${this.handleFocusOut}\n ></div>\n <div part=\"message-list\">\n ${repeat(\n groupedMessages,\n (group) => group.date,\n (group) => html`\n ${repeat(\n group.messages,\n (message) => message.id,\n (message) => {\n const messageId = `message-${message.id}`;\n return html`\n <igc-chat-message\n id=${messageId}\n role=\"option\"\n part=\"message-item ${this._activeMessageId === messageId\n ? 'active'\n : ''}\"\n .message=${message}\n >\n </igc-chat-message>\n `;\n }\n )}\n `\n )}\n ${\n this._chatState?.options?.isComposing\n ? this.renderLoadingTemplate()\n : nothing\n }\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-chat-message-list': IgcChatMessageListComponent;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-message-list.js","sourceRoot":"","sources":["../../../src/components/chat/chat-message-list.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,uBAAuB,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAC3D,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,4CAA4C,CAAC;AAkB9E,MAAqB,2BAA4B,SAAQ,UAAU;IAY1D,MAAM,CAAC,QAAQ;QACpB,iBAAiB,CAAC,2BAA2B,EAAE,uBAAuB,CAAC,CAAC;IAC1E,CAAC;IAaO,cAAc;QACpB,qBAAqB,CAAC,GAAG,EAAE;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,IAAmB,CAAC;YACvD,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC,YAAY,CAAC;YAC/C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAOM,eAAe,CAAC,SAAiB;QACtC,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CACnD,YAAY,SAAS,EAAE,CACxB,CAAC;QACF,cAAc,EAAE,cAAc,EAAE,CAAC;IACnC,CAAC;IAMkB,OAAO;QACxB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;YACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAMkB,YAAY;QAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;YACjD,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAMS,CAAC,qBAAqB;QAC9B,MAAM,IAAI,CAAA,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,uBAAuB;YACvE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,uBAAuB;YAC3D,CAAC,CAAC,IAAI,CAAA;;;;;eAKG,EAAE,CAAC;IAChB,CAAC;IAOkB,MAAM;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,IAAI,EAAE,CAAC;QAEjD,OAAO,IAAI,CAAA;;;;;;;;aAQF,MAAM,CACN,QAAQ,EACR,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,EACvB,CAAC,OAAO,EAAE,EAAE;YACV,MAAM,SAAS,GAAG,WAAW,OAAO,CAAC,EAAE,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAA;;wBAEF,SAAS;;;8BAGH,OAAO;;;;;gBAKrB,CAAC;QACJ,CAAC,CACF;YAEA,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ;YAChC,CAAC,CAAC,IAAI,CAAC,qBAAqB,EAAE;YAC9B,CAAC,CAAC,OACN;;;KAGL,CAAC;IACJ,CAAC;;AA3HsB,mCAAO,GAAG,uBAAuB,CAAC;AAGlC,kCAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;eAL9B,2BAA2B;AAqBtC;IADP,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;+DACpB","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, nothing } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { chatContext } from '../common/context.js';\nimport { registerComponent } from '../common/definitions/register.js';\nimport IgcChatMessageComponent from './chat-message.js';\nimport type { ChatState } from './chat-state.js';\nimport { styles } from './themes/message-list.base.css.js';\nimport { styles as shared } from './themes/shared/message-list.common.css.js';\n\n/**\n * A chat message list component that displays a list of chat messages grouped by date.\n *\n * @element igc-chat-message-list\n *\n * This component:\n * - Renders messages using the `<igc-chat-message>` component.\n * - Manages focus highlighting on active messages.\n * - Automatically scrolls to the bottom when new messages arrive, unless auto-scroll is disabled.\n * - Displays a typing indicator if the chat state option `isTyping` is true.\n *\n * Accessibility:\n * - Uses ARIA roles and properties for grouping and active descendant management.\n * - Message items have role=\"option\" for assistive technologies.\n *\n */\nexport default class IgcChatMessageListComponent extends LitElement {\n /** Tag name of the custom element. */\n public static readonly tagName = 'igc-chat-message-list';\n\n /** Styles applied to the component */\n public static override styles = [styles, shared];\n\n /**\n * Registers this component and its dependencies.\n * Used internally for component setup.\n */\n /* blazorSuppress */\n public static register() {\n registerComponent(IgcChatMessageListComponent, IgcChatMessageComponent);\n }\n\n /**\n * Consumed chat state context providing messages, options, and user data.\n * @private\n */\n @consume({ context: chatContext, subscribe: true })\n private _chatState?: ChatState;\n\n /**\n * Scrolls the container to the bottom, typically called after new messages are rendered.\n * @private\n */\n private scrollToBottom() {\n requestAnimationFrame(() => {\n const container = this.shadowRoot?.host as HTMLElement;\n if (container) {\n container.scrollTop = container.scrollHeight;\n }\n });\n }\n\n /**\n * Scrolls the view to a specific message by id.\n * @param messageId - The id of the message to scroll to\n * @private\n */\n public scrollToMessage(messageId: string) {\n const messageElement = this.shadowRoot?.querySelector(\n `#message-${messageId}`\n );\n messageElement?.scrollIntoView();\n }\n\n /**\n * Lifecycle: called when the component updates.\n * Scrolls to bottom unless auto-scroll is disabled.\n */\n protected override updated() {\n if (!this._chatState?.options?.disableAutoScroll) {\n this.scrollToBottom();\n }\n }\n\n /**\n * Lifecycle: called after first render.\n * Scrolls to bottom unless auto-scroll is disabled.\n */\n protected override firstUpdated() {\n if (!this._chatState?.options?.disableAutoScroll) {\n this.scrollToBottom();\n }\n }\n\n /**\n * Renders the typing indicator template.\n * @protected\n */\n protected *renderLoadingTemplate() {\n yield html`${this._chatState?.options?.templates?.typingIndicatorTemplate\n ? this._chatState.options.templates.typingIndicatorTemplate\n : html`<div part=\"typing-indicator\">\n <div part=\"typing-dot\"></div>\n <div part=\"typing-dot\"></div>\n <div part=\"typing-dot\"></div>\n <div part=\"typing-dot\"></div>\n </div>`}`;\n }\n\n /**\n * Main render method.\n * Groups messages by date and renders each message.\n * Shows the typing indicator if applicable.\n */\n protected override render() {\n const messages = this._chatState?.messages ?? [];\n\n return html`\n <div\n part=\"message-container\"\n role=\"group\"\n aria-label=\"Message list\"\n tabindex=\"0\"\n ></div>\n <div part=\"message-list\">\n ${repeat(\n messages,\n (message) => message.id,\n (message) => {\n const messageId = `message-${message.id}`;\n return html`\n <igc-chat-message\n id=${messageId}\n role=\"option\"\n part=\"message-item\"\n .message=${message}\n exportparts=\"message-container, message-text, message-attachments, message-actions,\n attachments-container, attachment, attachment-header, attachment-content, attachment-icon, file-name, actions: attachment-actions\"\n >\n </igc-chat-message>\n `;\n }\n )}\n ${\n this._chatState?.options?.isTyping\n ? this.renderLoadingTemplate()\n : nothing\n }\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-chat-message-list': IgcChatMessageListComponent;\n }\n}\n"]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, nothing } from 'lit';
|
|
2
2
|
import type { IgcMessage } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* A chat message component for displaying individual messages in `<igc-chat>`.
|
|
5
5
|
*
|
|
6
6
|
* @element igc-chat-message
|
|
7
7
|
*
|
|
8
|
+
* @fires igcMessageReact - Fired when a message is reacted to.
|
|
9
|
+
*
|
|
8
10
|
* This component renders a single chat message including:
|
|
9
11
|
* - Message text (sanitized)
|
|
10
12
|
* - Attachments (if any)
|
|
@@ -17,38 +19,26 @@ import type { IgcMessage } from './types.js';
|
|
|
17
19
|
* and can be rendered with a markdown renderer if provided.
|
|
18
20
|
*/
|
|
19
21
|
export default class IgcChatMessageComponent extends LitElement {
|
|
20
|
-
/** Tag name of the custom element. */
|
|
21
22
|
static readonly tagName = "igc-chat-message";
|
|
22
|
-
/** Styles applied to the component. */
|
|
23
23
|
static styles: import("lit").CSSResult[];
|
|
24
|
+
static register(): void;
|
|
24
25
|
/**
|
|
25
26
|
* Injected chat state context. Provides message data, user info, and options.
|
|
26
|
-
* @private
|
|
27
27
|
*/
|
|
28
28
|
private _chatState?;
|
|
29
|
-
/**
|
|
30
|
-
* Registers this component and its dependencies.
|
|
31
|
-
* This is used internally to set up the component definitions.
|
|
32
|
-
*/
|
|
33
|
-
static register(): void;
|
|
34
29
|
/**
|
|
35
30
|
* The chat message to render.
|
|
36
31
|
*/
|
|
37
|
-
message
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* @param text The raw message text
|
|
41
|
-
* @returns Sanitized text safe for HTML rendering
|
|
42
|
-
* @private
|
|
43
|
-
*/
|
|
44
|
-
private sanitizeMessageText;
|
|
32
|
+
message?: IgcMessage;
|
|
33
|
+
constructor();
|
|
34
|
+
protected firstUpdated(): void;
|
|
45
35
|
/**
|
|
46
36
|
* Renders the chat message template.
|
|
47
37
|
* - Applies 'sent' CSS class if the message sender matches current user.
|
|
48
38
|
* - Uses markdown rendering if configured.
|
|
49
39
|
* - Renders attachments and custom templates if provided.
|
|
50
40
|
*/
|
|
51
|
-
protected render(): import("lit-html").TemplateResult<1
|
|
41
|
+
protected render(): import("lit-html").TemplateResult<1> | typeof nothing;
|
|
52
42
|
}
|
|
53
43
|
declare global {
|
|
54
44
|
interface HTMLElementTagNameMap {
|
|
@@ -5,46 +5,42 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { consume } from '@lit/context';
|
|
8
|
-
import
|
|
9
|
-
import { html, LitElement, nothing } from 'lit';
|
|
8
|
+
import { adoptStyles, html, LitElement, nothing } from 'lit';
|
|
10
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { until } from 'lit/directives/until.js';
|
|
11
|
+
import { addThemingController } from '../../theming/theming-controller.js';
|
|
11
12
|
import IgcAvatarComponent from '../avatar/avatar.js';
|
|
12
13
|
import { chatContext } from '../common/context.js';
|
|
13
14
|
import { registerComponent } from '../common/definitions/register.js';
|
|
14
|
-
import {
|
|
15
|
+
import { partMap } from '../common/part-map.js';
|
|
16
|
+
import IgcTooltipComponent from '../tooltip/tooltip.js';
|
|
15
17
|
import IgcMessageAttachmentsComponent from './message-attachments.js';
|
|
16
18
|
import { styles } from './themes/message.base.css.js';
|
|
17
|
-
import {
|
|
19
|
+
import { all } from './themes/message.js';
|
|
20
|
+
import { styles as shared } from './themes/shared/chat-message/chat-message.common.css.js';
|
|
18
21
|
class IgcChatMessageComponent extends LitElement {
|
|
19
22
|
static register() {
|
|
20
|
-
registerComponent(IgcChatMessageComponent, IgcMessageAttachmentsComponent, IgcAvatarComponent);
|
|
23
|
+
registerComponent(IgcChatMessageComponent, IgcMessageAttachmentsComponent, IgcAvatarComponent, IgcTooltipComponent);
|
|
21
24
|
}
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
addThemingController(this, all);
|
|
28
|
+
}
|
|
29
|
+
firstUpdated() {
|
|
30
|
+
adoptPageStyles(this);
|
|
24
31
|
}
|
|
25
32
|
render() {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
${this.message?.attachments && this.message?.attachments.length > 0
|
|
38
|
-
? html `<igc-message-attachments .message=${this.message}>
|
|
39
|
-
</igc-message-attachments>`
|
|
40
|
-
: nothing}
|
|
41
|
-
${this._chatState?.options?.templates?.messageActionsTemplate &&
|
|
42
|
-
this.message
|
|
43
|
-
? this._chatState.options.templates.messageActionsTemplate(this.message)
|
|
44
|
-
: nothing}
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
`;
|
|
33
|
+
const parts = {
|
|
34
|
+
'message-container': true,
|
|
35
|
+
sent: this._chatState?.currentUserId === this.message?.sender,
|
|
36
|
+
};
|
|
37
|
+
return this.message && this._chatState?.chatRenderer
|
|
38
|
+
? html `
|
|
39
|
+
<div part=${partMap(parts)}>
|
|
40
|
+
${until(this._chatState.chatRenderer.render(this.message))}
|
|
41
|
+
</div>
|
|
42
|
+
`
|
|
43
|
+
: nothing;
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
46
|
IgcChatMessageComponent.tagName = 'igc-chat-message';
|
|
@@ -56,4 +52,19 @@ __decorate([
|
|
|
56
52
|
__decorate([
|
|
57
53
|
property({ attribute: false })
|
|
58
54
|
], IgcChatMessageComponent.prototype, "message", void 0);
|
|
55
|
+
function adoptPageStyles(message) {
|
|
56
|
+
const sheets = [];
|
|
57
|
+
for (const sheet of document.styleSheets) {
|
|
58
|
+
try {
|
|
59
|
+
const constructed = new CSSStyleSheet();
|
|
60
|
+
for (const rule of sheet.cssRules) {
|
|
61
|
+
constructed.insertRule(rule.cssText);
|
|
62
|
+
}
|
|
63
|
+
sheets.push(constructed);
|
|
64
|
+
}
|
|
65
|
+
catch { }
|
|
66
|
+
}
|
|
67
|
+
const ctor = message.constructor;
|
|
68
|
+
adoptStyles(message.shadowRoot, [...ctor.elementStyles, ...sheets]);
|
|
69
|
+
}
|
|
59
70
|
//# sourceMappingURL=chat-message.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-message.js","sourceRoot":"","sources":["../../../src/components/chat/chat-message.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,
|
|
1
|
+
{"version":3,"file":"chat-message.js","sourceRoot":"","sources":["../../../src/components/chat/chat-message.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,kBAAkB,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AAExD,OAAO,8BAA8B,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AACtD,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,yDAAyD,CAAC;AAqB3F,MAAqB,uBAAwB,SAAQ,UAAU;IAKtD,MAAM,CAAC,QAAQ;QACpB,iBAAiB,CACf,uBAAuB,EACvB,8BAA8B,EAC9B,kBAAkB,EAClB,mBAAmB,CACpB,CAAC;IACJ,CAAC;IAcD;QACE,KAAK,EAAE,CAAC;QACR,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IAEkB,YAAY;QAC7B,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAQkB,MAAM;QACvB,MAAM,KAAK,GAAG;YACZ,mBAAmB,EAAE,IAAI;YACzB,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAC,OAAO,EAAE,MAAM;SAC9D,CAAC;QAEF,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,EAAE,YAAY;YAClD,CAAC,CAAC,IAAI,CAAA;sBACU,OAAO,CAAC,KAAK,CAAC;cACtB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;;SAE7D;YACH,CAAC,CAAC,OAAO,CAAC;IACd,CAAC;;AArDsB,+BAAO,GAAG,kBAAkB,CAAC;AAC7B,8BAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;eAF9B,uBAAuB;AAkBlC;IADP,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;2DACpB;AAMxB;IADN,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;wDACH;AAwC9B,SAAS,eAAe,CAAC,OAAgC;IACvD,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,aAAa,EAAE,CAAC;YACxC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAClC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,WAAgC,CAAC;IACtD,WAAW,CAAC,OAAO,CAAC,UAAW,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;AACvE,CAAC","sourcesContent":["import { consume } from '@lit/context';\nimport { adoptStyles, html, LitElement, nothing } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { until } from 'lit/directives/until.js';\nimport { addThemingController } from '../../theming/theming-controller.js';\nimport IgcAvatarComponent from '../avatar/avatar.js';\nimport { chatContext } from '../common/context.js';\nimport { registerComponent } from '../common/definitions/register.js';\nimport { partMap } from '../common/part-map.js';\nimport IgcTooltipComponent from '../tooltip/tooltip.js';\nimport type { ChatState } from './chat-state.js';\nimport IgcMessageAttachmentsComponent from './message-attachments.js';\nimport { styles } from './themes/message.base.css.js';\nimport { all } from './themes/message.js';\nimport { styles as shared } from './themes/shared/chat-message/chat-message.common.css.js';\nimport type { IgcMessage } from './types.js';\n\n/**\n * A chat message component for displaying individual messages in `<igc-chat>`.\n *\n * @element igc-chat-message\n *\n * @fires igcMessageReact - Fired when a message is reacted to.\n *\n * This component renders a single chat message including:\n * - Message text (sanitized)\n * - Attachments (if any)\n * - Custom templates for message content and actions (if provided via chat options)\n *\n * It distinguishes sent messages from received messages by comparing\n * the message sender with the current user ID from chat state.\n *\n * The message text is sanitized with DOMPurify before rendering,\n * and can be rendered with a markdown renderer if provided.\n */\nexport default class IgcChatMessageComponent extends LitElement {\n public static readonly tagName = 'igc-chat-message';\n public static override styles = [styles, shared];\n\n /* blazorSuppress */\n public static register(): void {\n registerComponent(\n IgcChatMessageComponent,\n IgcMessageAttachmentsComponent,\n IgcAvatarComponent,\n IgcTooltipComponent\n );\n }\n\n /**\n * Injected chat state context. Provides message data, user info, and options.\n */\n @consume({ context: chatContext, subscribe: true })\n private _chatState?: ChatState;\n\n /**\n * The chat message to render.\n */\n @property({ attribute: false })\n public message?: IgcMessage;\n\n constructor() {\n super();\n addThemingController(this, all);\n }\n\n protected override firstUpdated(): void {\n adoptPageStyles(this);\n }\n\n /**\n * Renders the chat message template.\n * - Applies 'sent' CSS class if the message sender matches current user.\n * - Uses markdown rendering if configured.\n * - Renders attachments and custom templates if provided.\n */\n protected override render() {\n const parts = {\n 'message-container': true,\n sent: this._chatState?.currentUserId === this.message?.sender,\n };\n\n return this.message && this._chatState?.chatRenderer\n ? html`\n <div part=${partMap(parts)}>\n ${until(this._chatState.chatRenderer.render(this.message))}\n </div>\n `\n : nothing;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'igc-chat-message': IgcChatMessageComponent;\n }\n}\n\n// REVIEW: Maybe put that behind a configuration flag as this is nasty.\nfunction adoptPageStyles(message: IgcChatMessageComponent): void {\n const sheets: CSSStyleSheet[] = [];\n\n for (const sheet of document.styleSheets) {\n try {\n const constructed = new CSSStyleSheet();\n for (const rule of sheet.cssRules) {\n constructed.insertRule(rule.cssText);\n }\n sheets.push(constructed);\n } catch {}\n }\n\n const ctor = message.constructor as typeof LitElement;\n adoptStyles(message.shadowRoot!, [...ctor.elementStyles, ...sheets]);\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChatMessageRenderer, IgcChatTemplates, IgcMessage } from './types.js';
|
|
2
|
+
export declare class DefaultChatRenderer implements ChatMessageRenderer {
|
|
3
|
+
private baseTextRenderer;
|
|
4
|
+
private defaultTemplates;
|
|
5
|
+
private cache;
|
|
6
|
+
templates: Required<IgcChatTemplates>;
|
|
7
|
+
constructor(baseTextRenderer: ChatMessageRenderer, // e.g. PlainTextRenderer, MarkdownMessageRenderer
|
|
8
|
+
defaultTemplates: Required<IgcChatTemplates>, userTemplates?: Partial<IgcChatTemplates>);
|
|
9
|
+
protected renderText(message: IgcMessage): Promise<unknown>;
|
|
10
|
+
render(message: IgcMessage, ctx?: {
|
|
11
|
+
templates?: Partial<IgcChatTemplates>;
|
|
12
|
+
}): Promise<unknown>;
|
|
13
|
+
clearCache(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class DefaultChatRenderer {
|
|
2
|
+
constructor(baseTextRenderer, defaultTemplates, userTemplates) {
|
|
3
|
+
this.baseTextRenderer = baseTextRenderer;
|
|
4
|
+
this.defaultTemplates = defaultTemplates;
|
|
5
|
+
this.cache = new Map();
|
|
6
|
+
this.templates = {
|
|
7
|
+
...this.defaultTemplates,
|
|
8
|
+
...(userTemplates ?? {}),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
async renderText(message) {
|
|
12
|
+
const rendered = await this.baseTextRenderer.render(message);
|
|
13
|
+
return rendered;
|
|
14
|
+
}
|
|
15
|
+
async render(message, ctx) {
|
|
16
|
+
const templates = { ...ctx?.templates, ...this.templates };
|
|
17
|
+
if (!message.id) {
|
|
18
|
+
const textContent = await this.baseTextRenderer.render(message);
|
|
19
|
+
return templates.messageTemplate(message, { textContent, templates });
|
|
20
|
+
}
|
|
21
|
+
if (this.cache.has(message.id)) {
|
|
22
|
+
const cached = this.cache.get(message.id);
|
|
23
|
+
if (cached && cached.text === message.text) {
|
|
24
|
+
return cached.rendered;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const textContent = await this.baseTextRenderer.render(message);
|
|
28
|
+
const rendered = templates.messageTemplate(message, {
|
|
29
|
+
textContent,
|
|
30
|
+
templates,
|
|
31
|
+
});
|
|
32
|
+
this.cache.set(message.id, { text: message.text, rendered });
|
|
33
|
+
return rendered;
|
|
34
|
+
}
|
|
35
|
+
clearCache() {
|
|
36
|
+
this.cache.clear();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=chat-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-renderer.js","sourceRoot":"","sources":["../../../src/components/chat/chat-renderer.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,mBAAmB;IAI9B,YACU,gBAAqC,EACrC,gBAA4C,EACpD,aAAyC;QAFjC,qBAAgB,GAAhB,gBAAgB,CAAqB;QACrC,qBAAgB,GAAhB,gBAAgB,CAA4B;QAL9C,UAAK,GAAG,IAAI,GAAG,EAA+C,CAAC;QAQrE,IAAI,CAAC,SAAS,GAAG;YACf,GAAG,IAAI,CAAC,gBAAgB;YACxB,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;SACzB,CAAC;IACJ,CAAC;IAES,KAAK,CAAC,UAAU,CAAC,OAAmB;QAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEM,KAAK,CAAC,MAAM,CACjB,OAAmB,EACnB,GAA+C;QAE/C,MAAM,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC3D,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAEhB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAChE,OAAO,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC1C,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC;gBAC3C,OAAO,MAAM,CAAC,QAAQ,CAAC;YACzB,CAAC;QACH,CAAC;QAGD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE;YAClD,WAAW;YACX,SAAS;SACV,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAE7D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEM,UAAU;QACf,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF","sourcesContent":["import type {\n ChatMessageRenderer,\n IgcChatTemplates,\n IgcMessage,\n} from './types.js';\n\nexport class DefaultChatRenderer implements ChatMessageRenderer {\n private cache = new Map<string, { text: string; rendered: unknown }>();\n public templates: Required<IgcChatTemplates>;\n\n constructor(\n private baseTextRenderer: ChatMessageRenderer, // e.g. PlainTextRenderer, MarkdownMessageRenderer\n private defaultTemplates: Required<IgcChatTemplates>,\n userTemplates?: Partial<IgcChatTemplates>\n ) {\n this.templates = {\n ...this.defaultTemplates,\n ...(userTemplates ?? {}),\n };\n }\n\n protected async renderText(message: IgcMessage) {\n const rendered = await this.baseTextRenderer.render(message);\n return rendered;\n }\n\n public async render(\n message: IgcMessage,\n ctx?: { templates?: Partial<IgcChatTemplates> }\n ): Promise<unknown> {\n const templates = { ...ctx?.templates, ...this.templates };\n if (!message.id) {\n // No caching for messages without an ID\n const textContent = await this.baseTextRenderer.render(message);\n return templates.messageTemplate(message, { textContent, templates });\n }\n\n if (this.cache.has(message.id)) {\n const cached = this.cache.get(message.id);\n if (cached && cached.text === message.text) {\n return cached.rendered;\n }\n }\n\n // Cache miss or message text changed\n const textContent = await this.baseTextRenderer.render(message);\n const rendered = templates.messageTemplate(message, {\n textContent,\n templates,\n });\n this.cache.set(message.id, { text: message.text, rendered });\n\n return rendered;\n }\n\n public clearCache() {\n this.cache.clear();\n }\n}\n"]}
|