@elliemae/ds-chat-container 3.80.0-next.31 → 3.80.0-next.35

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 (52) hide show
  1. package/dist/cjs/DSChatContainerDefinitions.js +7 -1
  2. package/dist/cjs/DSChatContainerDefinitions.js.map +2 -2
  3. package/dist/cjs/parts/chat-container-messages-list/ChatContainerMessagesList.js +134 -71
  4. package/dist/cjs/parts/chat-container-messages-list/ChatContainerMessagesList.js.map +2 -2
  5. package/dist/cjs/parts/chat-container-messages-list/styled.js +33 -43
  6. package/dist/cjs/parts/chat-container-messages-list/styled.js.map +2 -2
  7. package/dist/cjs/parts/chat-container-messages-list/useActionRef.js +3 -9
  8. package/dist/cjs/parts/chat-container-messages-list/useActionRef.js.map +2 -2
  9. package/dist/cjs/parts/chat-container-messages-list/useChatContainerMessageList.js +30 -22
  10. package/dist/cjs/parts/chat-container-messages-list/useChatContainerMessageList.js.map +2 -2
  11. package/dist/cjs/parts/chat-container-messages-list/useFocusAndScrollHelpers.js +38 -38
  12. package/dist/cjs/parts/chat-container-messages-list/useFocusAndScrollHelpers.js.map +2 -2
  13. package/dist/cjs/parts/chat-container-messages-list/useGlobalEventListener.js.map +1 -1
  14. package/dist/cjs/parts/chat-container-messages-list/useKeyboard.js +8 -15
  15. package/dist/cjs/parts/chat-container-messages-list/useKeyboard.js.map +2 -2
  16. package/dist/cjs/parts/chat-container-messages-list/useMessageFocusTracker.js +132 -0
  17. package/dist/cjs/parts/chat-container-messages-list/useMessageFocusTracker.js.map +7 -0
  18. package/dist/cjs/react-desc-prop-types.js +39 -23
  19. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  20. package/dist/cjs/typescript-testing/typescript-chat-container-valid.js +31 -0
  21. package/dist/cjs/typescript-testing/typescript-chat-container-valid.js.map +2 -2
  22. package/dist/esm/DSChatContainerDefinitions.js +7 -1
  23. package/dist/esm/DSChatContainerDefinitions.js.map +2 -2
  24. package/dist/esm/parts/chat-container-messages-list/ChatContainerMessagesList.js +135 -74
  25. package/dist/esm/parts/chat-container-messages-list/ChatContainerMessagesList.js.map +2 -2
  26. package/dist/esm/parts/chat-container-messages-list/styled.js +33 -43
  27. package/dist/esm/parts/chat-container-messages-list/styled.js.map +2 -2
  28. package/dist/esm/parts/chat-container-messages-list/useActionRef.js +3 -9
  29. package/dist/esm/parts/chat-container-messages-list/useActionRef.js.map +2 -2
  30. package/dist/esm/parts/chat-container-messages-list/useChatContainerMessageList.js +30 -22
  31. package/dist/esm/parts/chat-container-messages-list/useChatContainerMessageList.js.map +2 -2
  32. package/dist/esm/parts/chat-container-messages-list/useFocusAndScrollHelpers.js +39 -39
  33. package/dist/esm/parts/chat-container-messages-list/useFocusAndScrollHelpers.js.map +2 -2
  34. package/dist/esm/parts/chat-container-messages-list/useGlobalEventListener.js.map +1 -1
  35. package/dist/esm/parts/chat-container-messages-list/useKeyboard.js +8 -15
  36. package/dist/esm/parts/chat-container-messages-list/useKeyboard.js.map +2 -2
  37. package/dist/esm/parts/chat-container-messages-list/useMessageFocusTracker.js +102 -0
  38. package/dist/esm/parts/chat-container-messages-list/useMessageFocusTracker.js.map +7 -0
  39. package/dist/esm/react-desc-prop-types.js +40 -24
  40. package/dist/esm/react-desc-prop-types.js.map +2 -2
  41. package/dist/esm/typescript-testing/typescript-chat-container-valid.js +31 -0
  42. package/dist/esm/typescript-testing/typescript-chat-container-valid.js.map +2 -2
  43. package/dist/types/DSChatContainerDefinitions.d.ts +8 -0
  44. package/dist/types/parts/chat-container-messages-list/styled.d.ts +18 -5
  45. package/dist/types/parts/chat-container-messages-list/useActionRef.d.ts +4 -6
  46. package/dist/types/parts/chat-container-messages-list/useChatContainerMessageList.d.ts +7 -2
  47. package/dist/types/parts/chat-container-messages-list/useFocusAndScrollHelpers.d.ts +9 -5
  48. package/dist/types/parts/chat-container-messages-list/useGlobalEventListener.d.ts +1 -1
  49. package/dist/types/parts/chat-container-messages-list/useKeyboard.d.ts +7 -3
  50. package/dist/types/parts/chat-container-messages-list/useMessageFocusTracker.d.ts +52 -0
  51. package/dist/types/react-desc-prop-types.d.ts +798 -793
  52. package/package.json +16 -16
@@ -30,11 +30,17 @@ var DSChatContainerDefinitions_exports = {};
30
30
  __export(DSChatContainerDefinitions_exports, {
31
31
  DSChatContainerComposerName: () => DSChatContainerComposerName,
32
32
  DSChatContainerMessagesList: () => DSChatContainerMessagesList,
33
- DSChatContainerName: () => DSChatContainerName
33
+ DSChatContainerName: () => DSChatContainerName,
34
+ DSChatContainerSlotName: () => DSChatContainerSlotName,
35
+ DSChatContainerSlots: () => DSChatContainerSlots
34
36
  });
35
37
  module.exports = __toCommonJS(DSChatContainerDefinitions_exports);
36
38
  var React = __toESM(require("react"));
37
39
  const DSChatContainerName = "DSChatcontainername";
38
40
  const DSChatContainerComposerName = "DSChatcontainercomposer";
39
41
  const DSChatContainerMessagesList = "DSChatcontainermessageslist";
42
+ const DSChatContainerSlotName = "DSChatcontainer";
43
+ const DSChatContainerSlots = {
44
+ MESSAGES_LIST_SCROLL_AREA: "messages-list-scroll-area"
45
+ };
40
46
  //# sourceMappingURL=DSChatContainerDefinitions.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/DSChatContainerDefinitions.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["export const DSChatContainerName = 'DSChatcontainername';\nexport const DSChatContainerComposerName = 'DSChatcontainercomposer';\nexport const DSChatContainerMessagesList = 'DSChatcontainermessageslist';\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAhB,MAAM,sBAAsB;AAC5B,MAAM,8BAA8B;AACpC,MAAM,8BAA8B;",
4
+ "sourcesContent": ["export const DSChatContainerName = 'DSChatcontainername';\nexport const DSChatContainerComposerName = 'DSChatcontainercomposer';\nexport const DSChatContainerMessagesList = 'DSChatcontainermessageslist';\n\n/**\n * Slot system: the main component and its parts share one slot owner name, each part with its own slot\n * names (the convention of the `ds-chat-container-compliance` change, which moves these into `src/constants/`).\n */\nexport const DSChatContainerSlotName = 'DSChatcontainer';\nexport const DSChatContainerSlots = {\n MESSAGES_LIST_SCROLL_AREA: 'messages-list-scroll-area',\n} as const;\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAhB,MAAM,sBAAsB;AAC5B,MAAM,8BAA8B;AACpC,MAAM,8BAA8B;AAMpC,MAAM,0BAA0B;AAChC,MAAM,uBAAuB;AAAA,EAClC,2BAA2B;AAC7B;",
6
6
  "names": []
7
7
  }
@@ -44,91 +44,154 @@ var import_styled = require("./styled.js");
44
44
  var import_react_desc_prop_types = require("../../react-desc-prop-types.js");
45
45
  var import_useGetNewMessages = require("./useGetNewMessages.js");
46
46
  var import_useChatContainerMessageList = require("./useChatContainerMessageList.js");
47
+ var import_useMessageFocusTracker = require("./useMessageFocusTracker.js");
47
48
  var import_ChatContainerDataTestids = require("../../ChatContainerDataTestids.js");
49
+ const ESTIMATED_MESSAGE_HEIGHT = 80;
50
+ const estimateSize = () => ESTIMATED_MESSAGE_HEIGHT;
51
+ const WRAPPER_LIST_PROPS = { role: "none" };
52
+ const ItemRenderer = ({ index, extraItemProps }) => {
53
+ const { messages, sendingMessages, sendingText, focusRequest, focusCallbacks } = extraItemProps ?? {};
54
+ const row = messages?.[index];
55
+ const isFocusTarget = Boolean(
56
+ row && focusRequest && (focusRequest.messageId === (0, import_useMessageFocusTracker.getMessageFocusId)(row, index) || focusRequest.messageId === (0, import_useMessageFocusTracker.getMessagePositionId)(index))
57
+ );
58
+ const requestId = isFocusTarget && focusRequest ? focusRequest.requestId : 0;
59
+ const preventScroll = isFocusTarget && focusRequest ? focusRequest.preventScroll : false;
60
+ const focusRef = import_react.default.useCallback(
61
+ (node) => {
62
+ if (!node || !isFocusTarget || !focusCallbacks) return;
63
+ const item = node.closest("[data-index]");
64
+ const takeFocus = focusCallbacks.mayTakeFocus(requestId, item);
65
+ if (!takeFocus) return;
66
+ item?.focus({ preventScroll: takeFocus === "restore" || preventScroll });
67
+ focusCallbacks.markFulfilled(requestId);
68
+ },
69
+ [isFocusTarget, requestId, preventScroll, focusCallbacks]
70
+ );
71
+ if (!row) return null;
72
+ const isSending = sendingMessages && sendingMessages.find((m) => m === row.dsId);
73
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styled.StyledWrapperListItem, { type: row.type, innerRef: focusRef, children: [
74
+ row.type === import_ds_chat_bubble.BUBBLE_TYPES.SENDER || row.type === import_ds_chat_bubble.BUBBLE_TYPES.RECIPIENT ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chat_bubble.ChatBubble, { ...row, helpMessage: isSending ? sendingText : row.helpMessage }) : null,
75
+ row.type === import_ds_chat_bubble.BUBBLE_TYPES.DELIMITER ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chat_message_delimeter.MessageDelimiter, { ...row }) : null,
76
+ row.type === import_ds_chat_bubble.BUBBLE_TYPES.SYSTEM ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chat_system_message.SystemMessage, { ...row }) : null
77
+ ] });
78
+ };
48
79
  const ChatContainerMessagesList = (props) => {
49
80
  const {
50
81
  propsWithDefault,
51
82
  globalAttributes,
52
- useVirtualHelpers,
83
+ fastListActionRef,
84
+ paddingStart,
85
+ paddingEnd,
53
86
  handleKey,
54
87
  handleListKey,
55
88
  loadMoreRef,
56
- virtualListRef
89
+ virtualListRef,
90
+ focusTracker
57
91
  } = (0, import_useChatContainerMessageList.useChatContainerMessageList)(props);
58
92
  const { sendingText, sendingMessages, messages, getMoreMessages, hasMoreItems, isLoading } = propsWithDefault;
59
- const totalSize = useVirtualHelpers.getTotalSize();
60
- const virtualItems = useVirtualHelpers.getVirtualItems();
61
- const { measureElement } = useVirtualHelpers;
62
93
  const newMessages = (0, import_useGetNewMessages.useGetNewMessages)(messages);
63
- const render = import_react.default.useMemo(
64
- () => virtualItems.map((virtualItem) => {
65
- const { index, start } = virtualItem;
66
- const row = messages[index];
67
- const isSending = sendingMessages && sendingMessages.find((m) => m === row.dsId);
68
- const style = {
69
- position: "absolute",
70
- top: 0,
71
- left: 0,
72
- transform: `translateY(${start}px)`,
73
- width: "100%"
74
- };
75
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
76
- import_styled.ListItem,
77
- {
78
- "data-element": "chat-element-list-item",
79
- "data-index": index,
80
- style,
81
- innerRef: measureElement,
82
- tabIndex: -1,
83
- onKeyDown: handleKey,
84
- role: "listitem",
85
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styled.StyledWrapperListItem, { type: row.type, children: [
86
- row.type === import_ds_chat_bubble.BUBBLE_TYPES.SENDER || row.type === import_ds_chat_bubble.BUBBLE_TYPES.RECIPIENT ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chat_bubble.ChatBubble, { ...row, helpMessage: isSending ? sendingText : row.helpMessage }) : null,
87
- row.type === import_ds_chat_bubble.BUBBLE_TYPES.DELIMITER ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chat_message_delimeter.MessageDelimiter, { ...row }) : null,
88
- row.type === import_ds_chat_bubble.BUBBLE_TYPES.SYSTEM ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chat_system_message.SystemMessage, { ...row }) : null
89
- ] })
90
- },
91
- `ds-chat-bubble-${index}-${row.dsId}-${row.type}`
92
- );
93
- }),
94
- [virtualItems, messages, sendingMessages, handleKey, sendingText, measureElement]
94
+ const getOwnerProps = import_react.default.useCallback(() => propsWithDefault, [propsWithDefault]);
95
+ const getId = import_react.default.useCallback(
96
+ (index) => `${index}-${messages[index].dsId}-${messages[index].type}`,
97
+ [messages]
98
+ );
99
+ const {
100
+ focusRequest,
101
+ mayTakeFocus,
102
+ markFulfilled,
103
+ trackFocusedMessage,
104
+ trackFocusResetter,
105
+ handleFocusOut,
106
+ listRootRef
107
+ } = focusTracker;
108
+ const focusCallbacks = import_react.default.useMemo(() => ({ mayTakeFocus, markFulfilled }), [mayTakeFocus, markFulfilled]);
109
+ const extraItemProps = import_react.default.useMemo(
110
+ () => ({ messages, sendingMessages, sendingText, focusRequest, focusCallbacks }),
111
+ [messages, sendingMessages, sendingText, focusRequest, focusCallbacks]
95
112
  );
96
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styled.StyledWrapper, { ...globalAttributes, children: [
97
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
- import_styled.StyledChatContainerContentList,
113
+ const { onFocus: onFocusFromConsumer, onBlur: onBlurFromConsumer } = globalAttributes;
114
+ const handleFocusIn = import_react.default.useCallback(
115
+ (e) => {
116
+ const item = e.target.closest('[data-element="chat-element-list-item"]');
117
+ const index = item?.dataset.index;
118
+ const position = Number(index);
119
+ const row = index !== void 0 ? messages[position] : void 0;
120
+ if (row) trackFocusedMessage((0, import_useMessageFocusTracker.getMessageFocusId)(row, position));
121
+ else trackFocusResetter();
122
+ onFocusFromConsumer?.(e);
123
+ },
124
+ [messages, trackFocusedMessage, trackFocusResetter, onFocusFromConsumer]
125
+ );
126
+ const handleFocusOutWithConsumer = import_react.default.useCallback(
127
+ (e) => {
128
+ handleFocusOut(e);
129
+ onBlurFromConsumer?.(e);
130
+ },
131
+ [handleFocusOut, onBlurFromConsumer]
132
+ );
133
+ const itemProps = import_react.default.useMemo(
134
+ () => ({ "data-element": "chat-element-list-item", tabIndex: -1, onKeyDown: handleKey }),
135
+ [handleKey]
136
+ );
137
+ const extraContent = import_react.default.useMemo(
138
+ () => !isLoading && hasMoreItems ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styled.StyledLoadMoreContainer, { hasMoreItems, role: "listitem", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
139
+ import_ds_button_v2.DSButtonV2,
99
140
  {
100
- "data-testid": import_ChatContainerDataTestids.ChatContainerDataTestIds.THREAD_CONTAINER,
101
- tabIndex: 0,
102
- innerRef: virtualListRef,
103
- role: "list",
104
- onKeyDown: handleListKey,
105
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styled.StyledChatContainerContentListScroll, { height: `${totalSize}px`, children: [
106
- !isLoading && hasMoreItems ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styled.StyledLoadMoreContainer, { hasMoreItems, role: "listitem", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
107
- import_ds_button_v2.DSButtonV2,
108
- {
109
- buttonType: "outline",
110
- onClick: getMoreMessages,
111
- "data-testid": import_ChatContainerDataTestids.ChatContainerDataTestIds.LOAD_MORE_BUTTON,
112
- innerRef: loadMoreRef,
113
- children: "Load More"
114
- }
115
- ) }) : null,
116
- render
117
- ] })
141
+ buttonType: "outline",
142
+ onClick: getMoreMessages,
143
+ "data-testid": import_ChatContainerDataTestids.ChatContainerDataTestIds.LOAD_MORE_BUTTON,
144
+ innerRef: loadMoreRef,
145
+ children: "Load More"
118
146
  }
119
- ),
120
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styled.StyledNewMessagesHiddenContainer, { "aria-live": "polite", "aria-hidden": "false", children: newMessages.map((newMessage) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
121
- newMessage.title,
122
- " ",
123
- newMessage.time,
124
- " ",
125
- newMessage.body,
126
- " ",
127
- newMessage.errorMessage,
128
- " ",
129
- newMessage.helpMessage
130
- ] }, newMessage.dsId)) })
131
- ] });
147
+ ) }) : null,
148
+ [isLoading, hasMoreItems, getMoreMessages, loadMoreRef]
149
+ );
150
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
151
+ import_styled.StyledWrapper,
152
+ {
153
+ ...globalAttributes,
154
+ innerRef: listRootRef,
155
+ onFocus: handleFocusIn,
156
+ onBlur: handleFocusOutWithConsumer,
157
+ children: [
158
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
159
+ import_styled.StyledFastList,
160
+ {
161
+ getOwnerProps,
162
+ "data-testid": import_ChatContainerDataTestids.ChatContainerDataTestIds.THREAD_CONTAINER,
163
+ role: "list",
164
+ tabIndex: 0,
165
+ onKeyDown: handleListKey,
166
+ innerRef: virtualListRef,
167
+ actionRef: fastListActionRef,
168
+ remountOnCountChange: false,
169
+ count: messages.length,
170
+ getId,
171
+ estimateSize,
172
+ paddingStart,
173
+ paddingEnd,
174
+ ItemRenderer,
175
+ extraItemProps,
176
+ extraContent,
177
+ dsFastlistWrapperList: WRAPPER_LIST_PROPS,
178
+ dsFastlistItem: itemProps
179
+ }
180
+ ),
181
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styled.StyledNewMessagesHiddenContainer, { "aria-live": "polite", "aria-hidden": "false", children: newMessages.map((newMessage) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
182
+ newMessage.title,
183
+ " ",
184
+ newMessage.time,
185
+ " ",
186
+ newMessage.body,
187
+ " ",
188
+ newMessage.errorMessage,
189
+ " ",
190
+ newMessage.helpMessage
191
+ ] }, newMessage.dsId)) })
192
+ ]
193
+ }
194
+ );
132
195
  };
133
196
  ChatContainerMessagesList.displayName = "ChatContainerMessagesList";
134
197
  const ChatContainerMessagesListWithSchema = (0, import_ds_props_helpers.describe)(ChatContainerMessagesList);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/parts/chat-container-messages-list/ChatContainerMessagesList.tsx", "../../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport type { CSSProperties, WeakValidationMap } from 'react';\nimport React from 'react';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { DSButtonV2, type DSButtonV2T } from '@elliemae/ds-button-v2';\nimport { ChatBubble, BUBBLE_TYPES } from '@elliemae/ds-chat-bubble';\nimport type { DSChatMessageDelimeterT } from '@elliemae/ds-chat-message-delimeter';\nimport { MessageDelimiter } from '@elliemae/ds-chat-message-delimeter';\nimport type { DSChatSystemMessageT } from '@elliemae/ds-chat-system-message';\nimport { SystemMessage } from '@elliemae/ds-chat-system-message';\nimport {\n StyledWrapperListItem,\n StyledChatContainerContentList,\n StyledChatContainerContentListScroll,\n StyledWrapper,\n StyledLoadMoreContainer,\n ListItem,\n StyledNewMessagesHiddenContainer,\n} from './styled.js';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\nimport { ChatContainerMessagesListPropTypes } from '../../react-desc-prop-types.js';\nimport { useGetNewMessages } from './useGetNewMessages.js';\nimport { useChatContainerMessageList } from './useChatContainerMessageList.js';\nimport { ChatContainerDataTestIds } from '../../ChatContainerDataTestids.js';\n\ntype ButtonV2InnerRefT = DSButtonV2T.Props['innerRef'];\n\nconst ChatContainerMessagesList: React.ComponentType<DSChatT.MessagesListProps> = (props) => {\n const {\n propsWithDefault,\n globalAttributes,\n useVirtualHelpers,\n handleKey,\n handleListKey,\n loadMoreRef,\n virtualListRef,\n } = useChatContainerMessageList(props);\n\n const { sendingText, sendingMessages, messages, getMoreMessages, hasMoreItems, isLoading } = propsWithDefault;\n const totalSize = useVirtualHelpers.getTotalSize();\n const virtualItems = useVirtualHelpers.getVirtualItems();\n const { measureElement } = useVirtualHelpers;\n\n const newMessages = useGetNewMessages(messages);\n\n const render = React.useMemo(\n () =>\n virtualItems.map((virtualItem) => {\n const { index, start } = virtualItem;\n const row = messages[index];\n const isSending = sendingMessages && sendingMessages.find((m) => m === row.dsId);\n const style: CSSProperties = {\n position: 'absolute',\n top: 0,\n left: 0,\n transform: `translateY(${start}px)`,\n width: '100%',\n };\n\n return (\n <ListItem\n data-element=\"chat-element-list-item\"\n data-index={index}\n key={`ds-chat-bubble-${index}-${row.dsId}-${row.type}`}\n style={style}\n innerRef={measureElement}\n tabIndex={-1}\n onKeyDown={handleKey}\n role=\"listitem\"\n >\n <StyledWrapperListItem type={row.type}>\n {row.type === BUBBLE_TYPES.SENDER || row.type === BUBBLE_TYPES.RECIPIENT ? (\n <ChatBubble {...row} helpMessage={isSending ? sendingText : row.helpMessage} />\n ) : null}\n {row.type === BUBBLE_TYPES.DELIMITER ? (\n <MessageDelimiter {...(row as unknown as DSChatMessageDelimeterT.Props)} />\n ) : null}\n {row.type === BUBBLE_TYPES.SYSTEM ? <SystemMessage {...(row as DSChatSystemMessageT.Props)} /> : null}\n </StyledWrapperListItem>\n </ListItem>\n );\n }),\n [virtualItems, messages, sendingMessages, handleKey, sendingText, measureElement],\n );\n\n return (\n <StyledWrapper {...globalAttributes}>\n <StyledChatContainerContentList\n data-testid={ChatContainerDataTestIds.THREAD_CONTAINER}\n tabIndex={0}\n innerRef={virtualListRef as React.RefObject<HTMLDivElement>}\n role=\"list\"\n onKeyDown={handleListKey}\n >\n <StyledChatContainerContentListScroll height={`${totalSize}px`}>\n {!isLoading && hasMoreItems ? (\n <StyledLoadMoreContainer hasMoreItems={hasMoreItems} role=\"listitem\">\n <DSButtonV2\n buttonType=\"outline\"\n onClick={getMoreMessages}\n data-testid={ChatContainerDataTestIds.LOAD_MORE_BUTTON}\n innerRef={loadMoreRef as ButtonV2InnerRefT}\n >\n Load More\n </DSButtonV2>\n </StyledLoadMoreContainer>\n ) : null}\n {render}\n </StyledChatContainerContentListScroll>\n </StyledChatContainerContentList>\n {/* We repeat the render with the new available messages */}\n <StyledNewMessagesHiddenContainer aria-live=\"polite\" aria-hidden=\"false\">\n {newMessages.map((newMessage) => (\n <p key={newMessage.dsId}>\n {newMessage.title} {newMessage.time} {newMessage.body} {newMessage.errorMessage} {newMessage.helpMessage}\n </p>\n ))}\n </StyledNewMessagesHiddenContainer>\n </StyledWrapper>\n );\n};\n\nChatContainerMessagesList.displayName = 'ChatContainerMessagesList';\nconst ChatContainerMessagesListWithSchema = describe(ChatContainerMessagesList);\nChatContainerMessagesListWithSchema.propTypes = ChatContainerMessagesListPropTypes as WeakValidationMap<unknown>;\n\nexport { ChatContainerMessagesList, ChatContainerMessagesListWithSchema };\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport type { WeakValidationMap } from 'react';\nimport React from 'react';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { DSButtonV2, type DSButtonV2T } from '@elliemae/ds-button-v2';\nimport { ChatBubble, BUBBLE_TYPES } from '@elliemae/ds-chat-bubble';\nimport type { DSChatMessageDelimeterT } from '@elliemae/ds-chat-message-delimeter';\nimport { MessageDelimiter } from '@elliemae/ds-chat-message-delimeter';\nimport type { DSChatSystemMessageT } from '@elliemae/ds-chat-system-message';\nimport { SystemMessage } from '@elliemae/ds-chat-system-message';\nimport {\n StyledWrapperListItem,\n StyledFastList,\n StyledWrapper,\n StyledLoadMoreContainer,\n StyledNewMessagesHiddenContainer,\n} from './styled.js';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\nimport { ChatContainerMessagesListPropTypes } from '../../react-desc-prop-types.js';\nimport { useGetNewMessages } from './useGetNewMessages.js';\nimport { useChatContainerMessageList } from './useChatContainerMessageList.js';\nimport { getMessageFocusId, getMessagePositionId } from './useMessageFocusTracker.js';\nimport type { MessageFocusRequest, useMessageFocusTracker } from './useMessageFocusTracker.js';\nimport { ChatContainerDataTestIds } from '../../ChatContainerDataTestids.js';\n\ntype ButtonV2InnerRefT = DSButtonV2T.Props['innerRef'];\n\ntype FocusTracker = ReturnType<typeof useMessageFocusTracker>;\ntype ItemFocusCallbacks = Pick<FocusTracker, 'mayTakeFocus' | 'markFulfilled'>;\n\ntype ItemExtraProps = {\n messages: DSChatT.MessagesListProps['messages'];\n sendingMessages: DSChatT.MessagesListProps['sendingMessages'];\n sendingText: DSChatT.MessagesListProps['sendingText'];\n focusRequest: MessageFocusRequest | null;\n focusCallbacks: ItemFocusCallbacks;\n};\n\nconst ESTIMATED_MESSAGE_HEIGHT = 80;\nconst estimateSize = () => ESTIMATED_MESSAGE_HEIGHT;\n// the wrapper `ds-fast-list` renders is neutral: the scroll container owns the `list` role\nconst WRAPPER_LIST_PROPS = { role: 'none' };\n\n/**\n * Module-level on purpose: `DSFastList` renders it as a component, so its identity must be stable or\n * every item would remount on each render of the list.\n */\nconst ItemRenderer: React.ComponentType<{ index: number; extraItemProps?: object }> = ({ index, extraItemProps }) => {\n // `styled(DSFastList)` drops DSFastList's generic, so `extraItemProps` arrives typed as `object`\n const { messages, sendingMessages, sendingText, focusRequest, focusCallbacks } = (extraItemProps ??\n {}) as Partial<ItemExtraProps>;\n const row = messages?.[index];\n const isFocusTarget = Boolean(\n row &&\n focusRequest &&\n (focusRequest.messageId === getMessageFocusId(row, index) ||\n focusRequest.messageId === getMessagePositionId(index)),\n );\n const requestId = isFocusTarget && focusRequest ? focusRequest.requestId : 0;\n const preventScroll = isFocusTarget && focusRequest ? focusRequest.preventScroll : false;\n /**\n * The only place a message is focused. It runs once React has committed the message, so a target that is\n * not mounted yet (far away, or remounted after older messages were loaded) is focused when it mounts. The\n * focusable element is the item wrapper `ds-fast-list` renders around this component, the one carrying\n * `data-index` and QA's `data-element`, so it is reached with `closest` from this message's own node.\n */\n const focusRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n if (!node || !isFocusTarget || !focusCallbacks) return;\n const item = node.closest<HTMLElement>('[data-index]');\n const takeFocus = focusCallbacks.mayTakeFocus(requestId, item);\n if (!takeFocus) return;\n item?.focus({ preventScroll: takeFocus === 'restore' || preventScroll });\n focusCallbacks.markFulfilled(requestId);\n },\n [isFocusTarget, requestId, preventScroll, focusCallbacks],\n );\n if (!row) return null;\n const isSending = sendingMessages && sendingMessages.find((m) => m === row.dsId);\n return (\n <StyledWrapperListItem type={row.type} innerRef={focusRef}>\n {row.type === BUBBLE_TYPES.SENDER || row.type === BUBBLE_TYPES.RECIPIENT ? (\n <ChatBubble {...row} helpMessage={isSending ? sendingText : row.helpMessage} />\n ) : null}\n {row.type === BUBBLE_TYPES.DELIMITER ? (\n <MessageDelimiter {...(row as unknown as DSChatMessageDelimeterT.Props)} />\n ) : null}\n {row.type === BUBBLE_TYPES.SYSTEM ? <SystemMessage {...(row as DSChatSystemMessageT.Props)} /> : null}\n </StyledWrapperListItem>\n );\n};\n\nconst ChatContainerMessagesList: React.ComponentType<DSChatT.MessagesListProps> = (props) => {\n const {\n propsWithDefault,\n globalAttributes,\n fastListActionRef,\n paddingStart,\n paddingEnd,\n handleKey,\n handleListKey,\n loadMoreRef,\n virtualListRef,\n focusTracker,\n } = useChatContainerMessageList(props);\n\n const { sendingText, sendingMessages, messages, getMoreMessages, hasMoreItems, isLoading } = propsWithDefault;\n\n const newMessages = useGetNewMessages(messages);\n\n const getOwnerProps = React.useCallback(() => propsWithDefault, [propsWithDefault]);\n /**\n * The key must carry the index. `ds-fast-list` reuses an item's DOM node for as long as its key is the same,\n * but the virtualizer measures each node by its `data-index` and does not measure a node again when only its\n * index changes. With a key made only of `dsId`, loading older messages (which shifts every index) keeps the\n * nodes and leaves their measurements pointing at another position: items overlap or leave gaps, and the list\n * flickers while scrolling. An index-bearing key recreates the shifted items so they are measured at their\n * new index, as the list did before it was moved onto `ds-fast-list`.\n */\n const getId = React.useCallback(\n (index: number) => `${index}-${messages[index].dsId}-${messages[index].type}`,\n [messages],\n );\n const {\n focusRequest,\n mayTakeFocus,\n markFulfilled,\n trackFocusedMessage,\n trackFocusResetter,\n handleFocusOut,\n listRootRef,\n } = focusTracker;\n const focusCallbacks = React.useMemo(() => ({ mayTakeFocus, markFulfilled }), [mayTakeFocus, markFulfilled]);\n const extraItemProps = React.useMemo(\n () => ({ messages, sendingMessages, sendingText, focusRequest, focusCallbacks }),\n [messages, sendingMessages, sendingText, focusRequest, focusCallbacks],\n );\n const { onFocus: onFocusFromConsumer, onBlur: onBlurFromConsumer } = globalAttributes as {\n onFocus?: React.FocusEventHandler<HTMLElement>;\n onBlur?: React.FocusEventHandler<HTMLElement>;\n };\n /**\n * Keeps the focus intent equal to the message that actually got the focus (keyboard, mouse or API), also when\n * the focus is on a descendant of the message, and clears it when the focus moves to anything else in the list.\n */\n const handleFocusIn = React.useCallback(\n (e: React.FocusEvent<HTMLElement>) => {\n const item = (e.target as HTMLElement).closest<HTMLElement>('[data-element=\"chat-element-list-item\"]');\n const index = item?.dataset.index;\n const position = Number(index);\n const row = index !== undefined ? messages[position] : undefined;\n if (row) trackFocusedMessage(getMessageFocusId(row, position));\n else trackFocusResetter();\n onFocusFromConsumer?.(e);\n },\n [messages, trackFocusedMessage, trackFocusResetter, onFocusFromConsumer],\n );\n const handleFocusOutWithConsumer = React.useCallback(\n (e: React.FocusEvent<HTMLElement>) => {\n handleFocusOut(e);\n onBlurFromConsumer?.(e);\n },\n [handleFocusOut, onBlurFromConsumer],\n );\n const itemProps = React.useMemo(\n () => ({ 'data-element': 'chat-element-list-item', tabIndex: -1, onKeyDown: handleKey }),\n [handleKey],\n );\n const extraContent = React.useMemo(\n () =>\n !isLoading && hasMoreItems ? (\n <StyledLoadMoreContainer hasMoreItems={hasMoreItems} role=\"listitem\">\n <DSButtonV2\n buttonType=\"outline\"\n onClick={getMoreMessages}\n data-testid={ChatContainerDataTestIds.LOAD_MORE_BUTTON}\n innerRef={loadMoreRef as ButtonV2InnerRefT}\n >\n Load More\n </DSButtonV2>\n </StyledLoadMoreContainer>\n ) : null,\n [isLoading, hasMoreItems, getMoreMessages, loadMoreRef],\n );\n\n return (\n <StyledWrapper\n {...globalAttributes}\n innerRef={listRootRef}\n onFocus={handleFocusIn}\n onBlur={handleFocusOutWithConsumer}\n >\n <StyledFastList\n getOwnerProps={getOwnerProps}\n data-testid={ChatContainerDataTestIds.THREAD_CONTAINER}\n role=\"list\"\n tabIndex={0}\n onKeyDown={handleListKey}\n innerRef={virtualListRef}\n actionRef={fastListActionRef}\n remountOnCountChange={false}\n count={messages.length}\n getId={getId}\n estimateSize={estimateSize}\n paddingStart={paddingStart}\n paddingEnd={paddingEnd}\n ItemRenderer={ItemRenderer}\n extraItemProps={extraItemProps}\n extraContent={extraContent}\n dsFastlistWrapperList={WRAPPER_LIST_PROPS}\n dsFastlistItem={itemProps}\n />\n {/* We repeat the render with the new available messages */}\n <StyledNewMessagesHiddenContainer aria-live=\"polite\" aria-hidden=\"false\">\n {newMessages.map((newMessage) => (\n <p key={newMessage.dsId}>\n {newMessage.title} {newMessage.time} {newMessage.body} {newMessage.errorMessage} {newMessage.helpMessage}\n </p>\n ))}\n </StyledNewMessagesHiddenContainer>\n </StyledWrapper>\n );\n};\n\nChatContainerMessagesList.displayName = 'ChatContainerMessagesList';\nconst ChatContainerMessagesListWithSchema = describe(ChatContainerMessagesList);\nChatContainerMessagesListWithSchema.propTypes = ChatContainerMessagesListPropTypes as WeakValidationMap<unknown>;\n\nexport { ChatContainerMessagesList, ChatContainerMessagesListWithSchema };\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": "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",
6
6
  "names": ["React"]
7
7
  }
@@ -28,9 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var styled_exports = {};
30
30
  __export(styled_exports, {
31
- ListItem: () => ListItem,
32
- StyledChatContainerContentList: () => StyledChatContainerContentList,
33
- StyledChatContainerContentListScroll: () => StyledChatContainerContentListScroll,
31
+ StyledFastList: () => StyledFastList,
34
32
  StyledLoadMoreContainer: () => StyledLoadMoreContainer,
35
33
  StyledNewMessagesHiddenContainer: () => StyledNewMessagesHiddenContainer,
36
34
  StyledWrapper: () => StyledWrapper,
@@ -39,7 +37,9 @@ __export(styled_exports, {
39
37
  module.exports = __toCommonJS(styled_exports);
40
38
  var React = __toESM(require("react"));
41
39
  var import_ds_system = require("@elliemae/ds-system");
40
+ var import_ds_fast_list = require("@elliemae/ds-fast-list");
42
41
  var import_ds_chat_bubble = require("@elliemae/ds-chat-bubble");
42
+ var import_DSChatContainerDefinitions = require("../../DSChatContainerDefinitions.js");
43
43
  const StyledWrapper = import_ds_system.styled.div`
44
44
  width: 100%;
45
45
  height: 100%;
@@ -54,21 +54,36 @@ const StyledWrapperListItem = import_ds_system.styled.div`
54
54
  ${(props) => props.type === import_ds_chat_bubble.BUBBLE_TYPES.SYSTEM && `padding: ${props.theme.space.xxs} 0px
55
55
  `};
56
56
  `;
57
- const StyledChatContainerContentList = import_ds_system.styled.div`
58
- width: 100%;
59
- height: 100%;
60
- /**
61
- * No padding-top here on purpose: this element is also react-virtual's getScrollElement, and
62
- * virtual-core compares raw el.scrollTop against its own content-relative item positions with no
63
- * padding awareness — a CSS top-padding on the scroll element itself desyncs those two frames,
64
- * making calculateRange() (and therefore getMessagesInView()) misjudge the visible range near the
65
- * top boundary by roughly the padding's own size. The equivalent top space is provided instead via
66
- * the virtualizer's own paddingStart option (useChatContainerMessageList.ts), which is baked into
67
- * its measurements and stays in the same frame as scrollTop.
68
- */
69
- padding: 0 ${(props) => props.theme.space.xs} 0 ${(props) => props.theme.space.xs};
70
- overflow-y: auto;
71
- overflow-x: hidden;
57
+ const StyledFastList = (0, import_ds_system.styled)(import_ds_fast_list.DSFastList, {
58
+ name: import_DSChatContainerDefinitions.DSChatContainerSlotName,
59
+ slot: import_DSChatContainerDefinitions.DSChatContainerSlots.MESSAGES_LIST_SCROLL_AREA
60
+ })`
61
+ && {
62
+ padding: 0 ${(props) => props.theme.space.xs} 0 ${(props) => props.theme.space.xs};
63
+ overflow-y: auto;
64
+ overflow-x: hidden;
65
+ }
66
+
67
+ [data-element='chat-element-list-item'] {
68
+ &:focus,
69
+ &:focus-visible {
70
+ outline: none;
71
+ &:after {
72
+ content: '';
73
+ display: block;
74
+ position: absolute;
75
+ top: 0;
76
+ left: -${(props) => props.theme.space.xxs};
77
+ pointer-events: none;
78
+ border-radius: 2px;
79
+ background-color: #ebedf0;
80
+ width: calc(100% + 24px);
81
+ border: 2px solid #1e79c2;
82
+ height: 100%;
83
+ z-index: -1;
84
+ }
85
+ }
86
+ }
72
87
  `;
73
88
  const StyledNewMessagesHiddenContainer = import_ds_system.styled.div`
74
89
  position: absolute;
@@ -82,11 +97,6 @@ const StyledNewMessagesHiddenContainer = import_ds_system.styled.div`
82
97
  clip-path: inset(100%);
83
98
  white-space: nowrap;
84
99
  `;
85
- const StyledChatContainerContentListScroll = import_ds_system.styled.div`
86
- width: 100%;
87
- height: ${(props) => props.height};
88
- position: relative;
89
- `;
90
100
  const StyledLoadMoreContainer = import_ds_system.styled.div`
91
101
  position: absolute;
92
102
  width: calc(100% + ${(props) => props.theme.space.xxs});
@@ -99,24 +109,4 @@ const StyledLoadMoreContainer = import_ds_system.styled.div`
99
109
  ${(props) => props.hasMoreItems === "top" ? "top: 0;" : ""}
100
110
  ${(props) => props.hasMoreItems === "bottom" ? "bottom: 0;" : ""}
101
111
  `;
102
- const ListItem = import_ds_system.styled.div`
103
- &:focus,
104
- &:focus-visible {
105
- outline: none;
106
- &:after {
107
- content: '';
108
- display: block;
109
- position: absolute;
110
- top: 0;
111
- left: -${(props) => props.theme.space.xxs};
112
- pointer-events: none;
113
- border-radius: 2px;
114
- background-color: #ebedf0;
115
- width: calc(100% + 24px);
116
- border: 2px solid #1e79c2;
117
- height: 100%;
118
- z-index: -1;
119
- }
120
- }
121
- `;
122
112
  //# sourceMappingURL=styled.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/parts/chat-container-messages-list/styled.ts", "../../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["import { styled } from '@elliemae/ds-system';\nimport type { DSChatBubbleT } from '@elliemae/ds-chat-bubble';\nimport { BUBBLE_TYPES } from '@elliemae/ds-chat-bubble';\n\nexport const StyledWrapper = styled.div`\n width: 100%;\n height: 100%;\n`;\n\n// list\nexport const StyledWrapperListItem = styled.div<Partial<DSChatBubbleT.Props>>`\n min-width: 100%;\n ${(props) =>\n props.type === BUBBLE_TYPES.SENDER &&\n `padding: ${props.theme.space.xxs} ${props.theme.space.xxs} ${props.theme.space.xxs} 13%\n `};\n ${(props) =>\n props.type === BUBBLE_TYPES.RECIPIENT &&\n `padding: ${props.theme.space.xxs} 13% ${props.theme.space.xxs}\n ${props.theme.space.xxs}\n `};\n ${(props) =>\n props.type === BUBBLE_TYPES.SYSTEM &&\n `padding: ${props.theme.space.xxs} 0px\n `};\n`;\n\nexport const StyledChatContainerContentList = styled.div`\n width: 100%;\n height: 100%;\n /**\n * No padding-top here on purpose: this element is also react-virtual's getScrollElement, and\n * virtual-core compares raw el.scrollTop against its own content-relative item positions with no\n * padding awareness \u2014 a CSS top-padding on the scroll element itself desyncs those two frames,\n * making calculateRange() (and therefore getMessagesInView()) misjudge the visible range near the\n * top boundary by roughly the padding's own size. The equivalent top space is provided instead via\n * the virtualizer's own paddingStart option (useChatContainerMessageList.ts), which is baked into\n * its measurements and stays in the same frame as scrollTop.\n */\n padding: 0 ${(props) => props.theme.space.xs} 0 ${(props) => props.theme.space.xs};\n overflow-y: auto;\n overflow-x: hidden;\n`;\n\nexport const StyledNewMessagesHiddenContainer = styled.div`\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n border: 0;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(100%);\n white-space: nowrap;\n`;\n\nexport const StyledChatContainerContentListScroll = styled.div<{ height: string }>`\n width: 100%;\n height: ${(props) => props.height};\n position: relative;\n`;\n\nexport const StyledLoadMoreContainer = styled.div<{ hasMoreItems?: 'top' | 'bottom' }>`\n position: absolute;\n width: calc(100% + ${(props) => props.theme.space.xxs});\n padding: ${(props) => props.theme.space.xxs};\n left: -${(props) => props.theme.space.xxs};\n right: -${(props) => props.theme.space.xxs};\n display: grid;\n justify-content: center;\n align-items: center;\n ${(props) => (props.hasMoreItems === 'top' ? 'top: 0;' : '')}\n ${(props) => (props.hasMoreItems === 'bottom' ? 'bottom: 0;' : '')}\n`;\nexport const ListItem = styled.div`\n &:focus,\n &:focus-visible {\n outline: none;\n &:after {\n content: '';\n display: block;\n position: absolute;\n top: 0;\n left: -${(props) => props.theme.space.xxs};\n pointer-events: none;\n border-radius: 2px;\n background-color: #ebedf0;\n width: calc(100% + 24px);\n border: 2px solid #1e79c2;\n height: 100%;\n z-index: -1;\n }\n }\n`;\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,uBAAuB;AAEvB,4BAA6B;AAEtB,MAAM,gBAAgB,wBAAO;AAAA;AAAA;AAAA;AAM7B,MAAM,wBAAwB,wBAAO;AAAA;AAAA,IAExC,CAAC,UACD,MAAM,SAAS,mCAAa,UAC5B,YAAY,MAAM,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,MAAM,GAAG;AAAA,GACpF;AAAA,IACC,CAAC,UACD,MAAM,SAAS,mCAAa,aAC5B,YAAY,MAAM,MAAM,MAAM,GAAG,QAAQ,MAAM,MAAM,MAAM,GAAG;AAAA,MAC5D,MAAM,MAAM,MAAM,GAAG;AAAA,GACxB;AAAA,IACC,CAAC,UACD,MAAM,SAAS,mCAAa,UAC5B,YAAY,MAAM,MAAM,MAAM,GAAG;AAAA,GAClC;AAAA;AAGI,MAAM,iCAAiC,wBAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAYtC,CAAC,UAAU,MAAM,MAAM,MAAM,EAAE,MAAM,CAAC,UAAU,MAAM,MAAM,MAAM,EAAE;AAAA;AAAA;AAAA;AAK5E,MAAM,mCAAmC,wBAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAahD,MAAM,uCAAuC,wBAAO;AAAA;AAAA,YAE/C,CAAC,UAAU,MAAM,MAAM;AAAA;AAAA;AAI5B,MAAM,0BAA0B,wBAAO;AAAA;AAAA,uBAEvB,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA,aAC1C,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA,WAClC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA,YAC/B,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA,IAIxC,CAAC,UAAW,MAAM,iBAAiB,QAAQ,YAAY,EAAG;AAAA,IAC1D,CAAC,UAAW,MAAM,iBAAiB,WAAW,eAAe,EAAG;AAAA;AAE7D,MAAM,WAAW,wBAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAShB,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import { styled } from '@elliemae/ds-system';\nimport { DSFastList } from '@elliemae/ds-fast-list';\nimport type { DSChatBubbleT } from '@elliemae/ds-chat-bubble';\nimport { BUBBLE_TYPES } from '@elliemae/ds-chat-bubble';\nimport { DSChatContainerSlotName, DSChatContainerSlots } from '../../DSChatContainerDefinitions.js';\n\nexport const StyledWrapper = styled.div`\n width: 100%;\n height: 100%;\n`;\n\n// list\nexport const StyledWrapperListItem = styled.div<Partial<DSChatBubbleT.Props>>`\n min-width: 100%;\n ${(props) =>\n props.type === BUBBLE_TYPES.SENDER &&\n `padding: ${props.theme.space.xxs} ${props.theme.space.xxs} ${props.theme.space.xxs} 13%\n `};\n ${(props) =>\n props.type === BUBBLE_TYPES.RECIPIENT &&\n `padding: ${props.theme.space.xxs} 13% ${props.theme.space.xxs}\n ${props.theme.space.xxs}\n `};\n ${(props) =>\n props.type === BUBBLE_TYPES.SYSTEM &&\n `padding: ${props.theme.space.xxs} 0px\n `};\n`;\n\n/**\n * The scroll container is DSFastList's own container, so its horizontal padding and overflow rules are\n * applied through the class that `styled(DSFastList)` forwards to it. `&&` doubles the class so these\n * rules win over the container's own `overflow: auto` regardless of style injection order.\n *\n * No padding-top here on purpose: the scroll container is also the virtualizer's scroll element, and\n * the virtualizer compares the raw `scrollTop` with its own content-relative item positions with no\n * awareness of CSS padding, so a CSS top-padding would desync `getVisibleItems()` near the top boundary\n * by roughly the padding's own size. The equivalent top space is passed as the virtualizer's\n * `paddingStart` instead (see useChatContainerMessageList.ts).\n */\nexport const StyledFastList = styled(DSFastList, {\n name: DSChatContainerSlotName,\n slot: DSChatContainerSlots.MESSAGES_LIST_SCROLL_AREA,\n})`\n && {\n padding: 0 ${(props) => props.theme.space.xs} 0 ${(props) => props.theme.space.xs};\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n [data-element='chat-element-list-item'] {\n &:focus,\n &:focus-visible {\n outline: none;\n &:after {\n content: '';\n display: block;\n position: absolute;\n top: 0;\n left: -${(props) => props.theme.space.xxs};\n pointer-events: none;\n border-radius: 2px;\n background-color: #ebedf0;\n width: calc(100% + 24px);\n border: 2px solid #1e79c2;\n height: 100%;\n z-index: -1;\n }\n }\n }\n`;\n\nexport const StyledNewMessagesHiddenContainer = styled.div`\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n border: 0;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(100%);\n white-space: nowrap;\n`;\n\nexport const StyledLoadMoreContainer = styled.div<{ hasMoreItems?: 'top' | 'bottom' }>`\n position: absolute;\n width: calc(100% + ${(props) => props.theme.space.xxs});\n padding: ${(props) => props.theme.space.xxs};\n left: -${(props) => props.theme.space.xxs};\n right: -${(props) => props.theme.space.xxs};\n display: grid;\n justify-content: center;\n align-items: center;\n ${(props) => (props.hasMoreItems === 'top' ? 'top: 0;' : '')}\n ${(props) => (props.hasMoreItems === 'bottom' ? 'bottom: 0;' : '')}\n`;\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,uBAAuB;AACvB,0BAA2B;AAE3B,4BAA6B;AAC7B,wCAA8D;AAEvD,MAAM,gBAAgB,wBAAO;AAAA;AAAA;AAAA;AAM7B,MAAM,wBAAwB,wBAAO;AAAA;AAAA,IAExC,CAAC,UACD,MAAM,SAAS,mCAAa,UAC5B,YAAY,MAAM,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,MAAM,GAAG;AAAA,GACpF;AAAA,IACC,CAAC,UACD,MAAM,SAAS,mCAAa,aAC5B,YAAY,MAAM,MAAM,MAAM,GAAG,QAAQ,MAAM,MAAM,MAAM,GAAG;AAAA,MAC5D,MAAM,MAAM,MAAM,GAAG;AAAA,GACxB;AAAA,IACC,CAAC,UACD,MAAM,SAAS,mCAAa,UAC5B,YAAY,MAAM,MAAM,MAAM,GAAG;AAAA,GAClC;AAAA;AAcI,MAAM,qBAAiB,yBAAO,gCAAY;AAAA,EAC/C,MAAM;AAAA,EACN,MAAM,uDAAqB;AAC7B,CAAC;AAAA;AAAA,iBAEgB,CAAC,UAAU,MAAM,MAAM,MAAM,EAAE,MAAM,CAAC,UAAU,MAAM,MAAM,MAAM,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAcpE,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAa1C,MAAM,mCAAmC,wBAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAahD,MAAM,0BAA0B,wBAAO;AAAA;AAAA,uBAEvB,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA,aAC1C,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA,WAClC,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA,YAC/B,CAAC,UAAU,MAAM,MAAM,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA,IAIxC,CAAC,UAAW,MAAM,iBAAiB,QAAQ,YAAY,EAAG;AAAA,IAC1D,CAAC,UAAW,MAAM,iBAAiB,WAAW,eAAe,EAAG;AAAA;",
6
6
  "names": []
7
7
  }
@@ -35,13 +35,11 @@ var React = __toESM(require("react"));
35
35
  var import_react = __toESM(require("react"));
36
36
  const useActionRef = ({
37
37
  actionRef,
38
- useVirtualHelpers: { scrollToIndex: vScroll },
38
+ vScroll,
39
39
  virtualListRef,
40
- updateCache,
41
40
  getMessagesInView,
42
41
  onlyFocus,
43
- scrollAndFocus,
44
- hasVirtualItems
42
+ scrollAndFocus
45
43
  }) => {
46
44
  import_react.default.useEffect(() => {
47
45
  if (actionRef && actionRef.current) {
@@ -50,7 +48,6 @@ const useActionRef = ({
50
48
  vScroll(index, opts);
51
49
  requestAnimationFrame(() => {
52
50
  vScroll(index, opts);
53
- updateCache();
54
51
  });
55
52
  }, 0);
56
53
  };
@@ -66,9 +63,6 @@ const useActionRef = ({
66
63
  actionRef.current.focusToIndexWithoutScroll = onlyFocus;
67
64
  actionRef.current.focusToList = focusToList;
68
65
  }
69
- }, [actionRef, getMessagesInView, onlyFocus, scrollAndFocus, updateCache, vScroll, virtualListRef]);
70
- import_react.default.useEffect(() => {
71
- if (hasVirtualItems) updateCache();
72
- }, [hasVirtualItems, updateCache]);
66
+ }, [actionRef, getMessagesInView, onlyFocus, scrollAndFocus, vScroll, virtualListRef]);
73
67
  };
74
68
  //# sourceMappingURL=useActionRef.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/parts/chat-container-messages-list/useActionRef.ts", "../../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport React from 'react';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseActionRefArgs = {\n actionRef: DSChatT.ActionRef;\n useVirtualHelpers: DSChatT.ChatVirtualizer;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n updateCache: () => void;\n getMessagesInView: () => string[];\n onlyFocus: (index: string) => void;\n scrollAndFocus: (index: number, opts?: DSChatT.ScrollToIndexOptions) => void;\n hasVirtualItems: boolean;\n};\n\nexport const useActionRef = ({\n actionRef,\n useVirtualHelpers: { scrollToIndex: vScroll },\n virtualListRef,\n updateCache,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n hasVirtualItems,\n}: UseActionRefArgs) => {\n React.useEffect(() => {\n if (actionRef && actionRef.current) {\n const scrollToIndex: DSChatT.ActionRef['current']['scrollToIndex'] = (index, opts = { align: 'center' }) => {\n setTimeout(() => {\n vScroll(index, opts);\n /* [PUI-15629](https://jira.elliemae.io/browse/PUI-15629)\n * requestAnimationFrame is needed because the first scroll might not calculate positions\n * correctly if the DOM hasn't been fully updated yet. By waiting for the next animation\n * frame, we ensure that:\n * 1. The DOM has been updated with new positions after the first scroll\n * 2. Element height and position measurements are accurate\n * 3. The second scroll can center the element with correct measurements\n *\n * TODO: It might be worth consider upgrading to react-virtual v3(@tanstack/react-virtual), which handles DOM measurements and scroll\n * synchronization better. This RAF workaround might not be necessary with v3.\n */\n requestAnimationFrame(() => {\n vScroll(index, opts);\n updateCache();\n });\n }, 0);\n };\n const focusToIndex: DSChatT.ActionRef['current']['focusToIndex'] = (index, opts = { align: 'center' }) => {\n scrollAndFocus(index, opts);\n };\n const focusToList = () => {\n virtualListRef.current?.focus();\n };\n\n actionRef.current.scrollToIndex = scrollToIndex;\n actionRef.current.getMessagesInView = getMessagesInView;\n actionRef.current.focusToIndex = focusToIndex;\n actionRef.current.focusToIndexWithoutScroll = onlyFocus;\n actionRef.current.focusToList = focusToList;\n }\n }, [actionRef, getMessagesInView, onlyFocus, scrollAndFocus, updateCache, vScroll, virtualListRef]);\n\n /**\n * Populates the visible-items cache once the virtualizer has actually rendered rows. Unlike v2 \u2014\n * whose calculateRange never gated on the scroll container's measured size, so it always rendered\n * overscan+1 rows synchronously on the first commit \u2014 v3 gates rendering on a real, measured\n * container size, so `getVirtualItems()` is empty for the first render(s) until that measurement\n * resolves (confirmed empirically: 2 empty renders observed before the first non-empty one).\n * Calling updateCache() unconditionally on mount (the v2-era approach) raced this and cached an\n * empty list, which Shift+Tab-from-composer then read once and never revisited.\n *\n * Residual, narrower risk: interacting with the thread in the brief window before `hasVirtualItems`\n * flips true (the first render, before real layout exists) still finds an empty cache \u2014 this is a\n * known, accepted limitation of `onlyFocus`'s querySelector-based focus lookup, not something this\n * migration introduces new architecture to close. See KNOWN_INTENTIONAL_DEVIATIONS.md.\n */\n React.useEffect(() => {\n if (hasVirtualItems) updateCache();\n }, [hasVirtualItems, updateCache]);\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;AAcX,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA,mBAAmB,EAAE,eAAe,QAAQ;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwB;AACtB,eAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,aAAa,UAAU,SAAS;AAClC,YAAM,gBAA+D,CAAC,OAAO,OAAO,EAAE,OAAO,SAAS,MAAM;AAC1G,mBAAW,MAAM;AACf,kBAAQ,OAAO,IAAI;AAYnB,gCAAsB,MAAM;AAC1B,oBAAQ,OAAO,IAAI;AACnB,wBAAY;AAAA,UACd,CAAC;AAAA,QACH,GAAG,CAAC;AAAA,MACN;AACA,YAAM,eAA6D,CAAC,OAAO,OAAO,EAAE,OAAO,SAAS,MAAM;AACxG,uBAAe,OAAO,IAAI;AAAA,MAC5B;AACA,YAAM,cAAc,MAAM;AACxB,uBAAe,SAAS,MAAM;AAAA,MAChC;AAEA,gBAAU,QAAQ,gBAAgB;AAClC,gBAAU,QAAQ,oBAAoB;AACtC,gBAAU,QAAQ,eAAe;AACjC,gBAAU,QAAQ,4BAA4B;AAC9C,gBAAU,QAAQ,cAAc;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,WAAW,mBAAmB,WAAW,gBAAgB,aAAa,SAAS,cAAc,CAAC;AAgBlG,eAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,gBAAiB,aAAY;AAAA,EACnC,GAAG,CAAC,iBAAiB,WAAW,CAAC;AACnC;",
4
+ "sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport React from 'react';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseActionRefArgs = {\n actionRef: DSChatT.ActionRef;\n vScroll: (index: number, opts?: DSChatT.ScrollActionOptions) => void;\n virtualListRef: React.MutableRefObject<HTMLDivElement | null>;\n getMessagesInView: () => string[];\n onlyFocus: (index: string) => void;\n scrollAndFocus: (index: number, opts?: DSChatT.ScrollActionOptions) => void;\n};\n\nexport const useActionRef = ({\n actionRef,\n vScroll,\n virtualListRef,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n}: UseActionRefArgs) => {\n React.useEffect(() => {\n if (actionRef && actionRef.current) {\n const scrollToIndex: DSChatT.ActionRef['current']['scrollToIndex'] = (index, opts = { align: 'center' }) => {\n setTimeout(() => {\n vScroll(index, opts);\n /* [PUI-15629](https://jira.elliemae.io/browse/PUI-15629)\n * requestAnimationFrame is needed because the first scroll might not calculate positions\n * correctly if the DOM hasn't been fully updated yet. By waiting for the next animation\n * frame, we ensure that:\n * 1. The DOM has been updated with new positions after the first scroll\n * 2. Element height and position measurements are accurate\n * 3. The second scroll can align the element with correct measurements\n */\n requestAnimationFrame(() => {\n vScroll(index, opts);\n });\n }, 0);\n };\n const focusToIndex: DSChatT.ActionRef['current']['focusToIndex'] = (index, opts = { align: 'center' }) => {\n scrollAndFocus(index, opts);\n };\n const focusToList = () => {\n virtualListRef.current?.focus();\n };\n\n actionRef.current.scrollToIndex = scrollToIndex;\n actionRef.current.getMessagesInView = getMessagesInView;\n actionRef.current.focusToIndex = focusToIndex;\n actionRef.current.focusToIndexWithoutScroll = onlyFocus;\n actionRef.current.focusToList = focusToList;\n }\n }, [actionRef, getMessagesInView, onlyFocus, scrollAndFocus, vScroll, virtualListRef]);\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;AAYX,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwB;AACtB,eAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,aAAa,UAAU,SAAS;AAClC,YAAM,gBAA+D,CAAC,OAAO,OAAO,EAAE,OAAO,SAAS,MAAM;AAC1G,mBAAW,MAAM;AACf,kBAAQ,OAAO,IAAI;AASnB,gCAAsB,MAAM;AAC1B,oBAAQ,OAAO,IAAI;AAAA,UACrB,CAAC;AAAA,QACH,GAAG,CAAC;AAAA,MACN;AACA,YAAM,eAA6D,CAAC,OAAO,OAAO,EAAE,OAAO,SAAS,MAAM;AACxG,uBAAe,OAAO,IAAI;AAAA,MAC5B;AACA,YAAM,cAAc,MAAM;AACxB,uBAAe,SAAS,MAAM;AAAA,MAChC;AAEA,gBAAU,QAAQ,gBAAgB;AAClC,gBAAU,QAAQ,oBAAoB;AACtC,gBAAU,QAAQ,eAAe;AACjC,gBAAU,QAAQ,4BAA4B;AAC9C,gBAAU,QAAQ,cAAc;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,WAAW,mBAAmB,WAAW,gBAAgB,SAAS,cAAc,CAAC;AACvF;",
6
6
  "names": ["React"]
7
7
  }
@@ -35,11 +35,11 @@ var React = __toESM(require("react"));
35
35
  var import_react = __toESM(require("react"));
36
36
  var import_styled_components = require("styled-components");
37
37
  var import_ds_props_helpers = require("@elliemae/ds-props-helpers");
38
- var import_react_virtual = require("@tanstack/react-virtual");
39
38
  var import_useActionRef = require("./useActionRef.js");
40
39
  var import_useGlobalEventListener = require("./useGlobalEventListener.js");
41
40
  var import_useKeyboard = require("./useKeyboard.js");
42
41
  var import_useFocusAndScrollHelpers = require("./useFocusAndScrollHelpers.js");
42
+ var import_useMessageFocusTracker = require("./useMessageFocusTracker.js");
43
43
  var import_react_desc_prop_types = require("../../react-desc-prop-types.js");
44
44
  var import_DSChatContainerDefinitions = require("../../DSChatContainerDefinitions.js");
45
45
  const getPadding = ({ hasMoreItems, bannerPosition, isLoading }) => {
@@ -60,36 +60,30 @@ const useChatContainerMessageList = (props) => {
60
60
  );
61
61
  const globalAttributes = (0, import_ds_props_helpers.useGetGlobalAttributes)(propsWithDefault);
62
62
  const loadMoreRef = import_react.default.useRef();
63
- const virtualListRef = import_react.default.useRef();
63
+ const virtualListRef = import_react.default.useRef(null);
64
+ const fastListActionRef = import_react.default.useRef({});
64
65
  const pendingOnScroll = import_react.default.useRef(false);
65
- const { bannerPosition, messages, actionRef, hasMoreItems, isLoading } = propsWithDefault;
66
+ const { bannerPosition, actionRef, hasMoreItems, isLoading } = propsWithDefault;
66
67
  const theme = (0, import_styled_components.useTheme)();
67
68
  const containerPaddingStart = parseInt(theme.space.xs, 10);
68
69
  const padding = getPadding({ hasMoreItems, bannerPosition, isLoading });
69
- const useVirtualHelpers = (0, import_react_virtual.useVirtualizer)({
70
- count: messages?.length ?? 0,
71
- getScrollElement: () => virtualListRef.current ?? null,
72
- overscan: 15,
73
- paddingStart: padding.paddingStart + containerPaddingStart,
74
- paddingEnd: padding.paddingEnd,
75
- // Unlike v2, v3 has no internal default for estimateSize — it's required, not optional.
76
- estimateSize: import_react.default.useCallback(() => 80, [])
77
- });
78
- const { onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll } = (0, import_useFocusAndScrollHelpers.useFocusAndScrollHelpers)({
70
+ const paddingStart = padding.paddingStart + containerPaddingStart;
71
+ const { paddingEnd } = padding;
72
+ const focusTracker = (0, import_useMessageFocusTracker.useMessageFocusTracker)(virtualListRef);
73
+ const { trackFocusMessage } = focusTracker;
74
+ const { vScroll, onScrollStop, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll } = (0, import_useFocusAndScrollHelpers.useFocusAndScrollHelpers)({
79
75
  propsWithDefault,
80
- useVirtualHelpers,
76
+ fastListActionRef,
81
77
  pendingOnScroll,
82
- virtualListRef
78
+ trackFocusMessage
83
79
  });
84
80
  (0, import_useActionRef.useActionRef)({
85
81
  actionRef,
86
- useVirtualHelpers,
82
+ vScroll,
87
83
  virtualListRef,
88
- updateCache,
89
84
  getMessagesInView,
90
85
  onlyFocus,
91
- scrollAndFocus,
92
- hasVirtualItems: useVirtualHelpers.getVirtualItems().length > 0
86
+ scrollAndFocus
93
87
  });
94
88
  (0, import_useGlobalEventListener.useGlobalEventListener)({
95
89
  propsWithDefault,
@@ -104,18 +98,32 @@ const useChatContainerMessageList = (props) => {
104
98
  loadMoreRef,
105
99
  scrollAndFocus,
106
100
  onlyFocus,
107
- getMessagesInView
101
+ getMessagesInView,
102
+ trackFocusMessage
108
103
  });
109
104
  return import_react.default.useMemo(
110
105
  () => ({
111
106
  propsWithDefault,
112
107
  globalAttributes,
113
- useVirtualHelpers,
108
+ fastListActionRef,
109
+ paddingStart,
110
+ paddingEnd,
114
111
  loadMoreRef,
115
112
  virtualListRef,
113
+ focusTracker,
116
114
  ...keyboardMethods
117
115
  }),
118
- [globalAttributes, keyboardMethods, propsWithDefault, useVirtualHelpers, loadMoreRef, virtualListRef]
116
+ [
117
+ globalAttributes,
118
+ keyboardMethods,
119
+ propsWithDefault,
120
+ fastListActionRef,
121
+ paddingStart,
122
+ paddingEnd,
123
+ loadMoreRef,
124
+ virtualListRef,
125
+ focusTracker
126
+ ]
119
127
  );
120
128
  };
121
129
  //# sourceMappingURL=useChatContainerMessageList.js.map