@elliemae/ds-chat-container 3.80.0-next.30 → 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
@@ -1,5 +1,6 @@
1
1
  import * as React from "react";
2
2
  import React2 from "react";
3
+ import { getMessageFocusId } from "./useMessageFocusTracker.js";
3
4
  const getIsNumber = (val) => Number.isInteger(val);
4
5
  const useKeyboard = ({
5
6
  propsWithDefault: { hasMoreItems, messages, bannerPosition, bannerRef },
@@ -8,7 +9,8 @@ const useKeyboard = ({
8
9
  loadMoreRef,
9
10
  scrollAndFocus,
10
11
  onlyFocus,
11
- getMessagesInView
12
+ getMessagesInView,
13
+ trackFocusMessage
12
14
  }) => {
13
15
  const handleKey = React2.useCallback(
14
16
  (e) => {
@@ -20,7 +22,7 @@ const useKeyboard = ({
20
22
  case "ArrowUp":
21
23
  e.preventDefault();
22
24
  if (index && index > 0) {
23
- (virtualListRef.current?.querySelector(`[data-index="${index - 1}"]`)).focus();
25
+ trackFocusMessage(getMessageFocusId(messages[index - 1], index - 1));
24
26
  } else if (hasMoreItems === "top") {
25
27
  loadMoreRef.current?.focus();
26
28
  }
@@ -28,7 +30,7 @@ const useKeyboard = ({
28
30
  case "ArrowDown":
29
31
  e.preventDefault();
30
32
  if (messages?.length && isIndexNumber && index < messages.length - 1) {
31
- (virtualListRef.current?.querySelector(`[data-index="${index + 1}"]`)).focus();
33
+ trackFocusMessage(getMessageFocusId(messages[index + 1], index + 1));
32
34
  }
33
35
  break;
34
36
  case "Home":
@@ -60,7 +62,7 @@ const useKeyboard = ({
60
62
  break;
61
63
  }
62
64
  },
63
- [hasMoreItems, messages.length, scrollAndFocus, virtualListRef, loadMoreRef, bannerPosition, bannerRef]
65
+ [hasMoreItems, messages, scrollAndFocus, virtualListRef, loadMoreRef, bannerPosition, bannerRef, trackFocusMessage]
64
66
  );
65
67
  const handleListKey = React2.useCallback(
66
68
  (e) => {
@@ -76,7 +78,7 @@ const useKeyboard = ({
76
78
  case "ArrowDown":
77
79
  e.preventDefault();
78
80
  if (document.activeElement === loadMoreRef.current) {
79
- virtualListRef.current?.querySelector(`[data-index="0"]`)?.focus();
81
+ onlyFocus("0");
80
82
  } else {
81
83
  const id = getMessagesInView()?.pop();
82
84
  if (id) onlyFocus(id);
@@ -111,16 +113,7 @@ const useKeyboard = ({
111
113
  break;
112
114
  }
113
115
  },
114
- [
115
- actionRef,
116
- hasMoreItems,
117
- loadMoreRef,
118
- messages.length,
119
- getMessagesInView,
120
- onlyFocus,
121
- scrollAndFocus,
122
- virtualListRef
123
- ]
116
+ [actionRef, hasMoreItems, loadMoreRef, messages, getMessagesInView, onlyFocus, scrollAndFocus, virtualListRef]
124
117
  );
125
118
  return React2.useMemo(() => ({ handleKey, handleListKey }), [handleKey, handleListKey]);
126
119
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/chat-container-messages-list/useKeyboard.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* 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 UseKeyboardArgs = {\n propsWithDefault: DSChatT.MessagesListProps;\n actionRef: DSChatT.ActionRef;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;\n scrollAndFocus: (index: number, opts?: DSChatT.ScrollToIndexOptions) => void;\n onlyFocus: (index: string) => void;\n getMessagesInView: () => string[];\n};\n\nconst getIsNumber = (val: unknown): val is number => Number.isInteger(val);\n\nexport const useKeyboard = ({\n propsWithDefault: { hasMoreItems, messages, bannerPosition, bannerRef },\n actionRef,\n virtualListRef,\n loadMoreRef,\n scrollAndFocus,\n onlyFocus,\n getMessagesInView,\n}: UseKeyboardArgs) => {\n const handleKey = React.useCallback(\n (e: React.KeyboardEvent<HTMLElement>) => {\n const { key, currentTarget } = e;\n const index = currentTarget.dataset?.index ? Number(currentTarget.dataset.index) : undefined;\n const isIndexNumber = getIsNumber(index);\n e.stopPropagation();\n switch (key) {\n case 'ArrowUp':\n e.preventDefault();\n if (index && index > 0) {\n (virtualListRef.current?.querySelector(`[data-index=\"${index - 1}\"]`) as HTMLDivElement).focus();\n } else if (hasMoreItems === 'top') {\n loadMoreRef.current?.focus();\n }\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (messages?.length && isIndexNumber && index < messages.length - 1) {\n (virtualListRef.current?.querySelector(`[data-index=\"${index + 1}\"]`) as HTMLDivElement).focus();\n }\n break;\n case 'Home':\n e.preventDefault();\n scrollAndFocus(0);\n break;\n case 'End':\n e.preventDefault();\n if (messages?.length) scrollAndFocus(messages.length - 1);\n break;\n case 'Tab':\n if (hasMoreItems === 'bottom' && !e.shiftKey) {\n e.preventDefault();\n loadMoreRef.current?.focus();\n } else if (hasMoreItems === 'top' && e.shiftKey) {\n e.preventDefault();\n loadMoreRef.current?.focus();\n } else if (!e.shiftKey) {\n if (bannerPosition) {\n e.preventDefault();\n bannerRef?.current?.focusOnWrapper();\n }\n } else {\n e.preventDefault();\n virtualListRef.current?.focus();\n }\n break;\n default:\n break;\n }\n },\n [hasMoreItems, messages.length, scrollAndFocus, virtualListRef, loadMoreRef, bannerPosition, bannerRef],\n );\n const handleListKey = React.useCallback(\n (e: React.KeyboardEvent) => {\n const { key } = e;\n switch (key) {\n case 'ArrowUp':\n e.preventDefault();\n if (document.activeElement !== loadMoreRef.current) {\n const id = getMessagesInView()?.shift();\n if (id) onlyFocus(id);\n }\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (document.activeElement === loadMoreRef.current) {\n (virtualListRef.current?.querySelector(`[data-index=\"0\"]`) as HTMLDivElement)?.focus();\n } else {\n const id = getMessagesInView()?.pop();\n if (id) onlyFocus(id);\n }\n break;\n case 'Home':\n e.preventDefault();\n scrollAndFocus(0);\n break;\n case 'End':\n e.preventDefault();\n if (messages?.length) scrollAndFocus(messages.length - 1);\n break;\n case 'Tab':\n if (document.activeElement !== loadMoreRef.current) {\n if (hasMoreItems === 'bottom' && !e.shiftKey) {\n e.preventDefault();\n loadMoreRef.current?.focus();\n } else if (!e.shiftKey) {\n e.preventDefault();\n actionRef.current?.focusToComposer?.();\n }\n } else if (!e.shiftKey) {\n e.preventDefault();\n actionRef.current?.focusToComposer?.();\n } else {\n e.preventDefault();\n virtualListRef.current?.focus();\n }\n break;\n default:\n break;\n }\n },\n [\n actionRef,\n hasMoreItems,\n loadMoreRef,\n messages.length,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n virtualListRef,\n ],\n );\n\n return React.useMemo(() => ({ handleKey, handleListKey }), [handleKey, handleListKey]);\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* 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';\nimport { getMessageFocusId } from './useMessageFocusTracker.js';\nimport type { MessageId } from './useMessageFocusTracker.js';\n\ntype UseKeyboardArgs = {\n propsWithDefault: DSChatT.MessagesListProps;\n actionRef: DSChatT.ActionRef;\n virtualListRef: React.MutableRefObject<HTMLDivElement | null>;\n loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;\n scrollAndFocus: (index: number, opts?: DSChatT.ScrollActionOptions) => void;\n onlyFocus: (index: string) => void;\n getMessagesInView: () => string[];\n trackFocusMessage: (messageId: MessageId, options?: { preventScroll?: boolean }) => void;\n};\n\nconst getIsNumber = (val: unknown): val is number => Number.isInteger(val);\n\nexport const useKeyboard = ({\n propsWithDefault: { hasMoreItems, messages, bannerPosition, bannerRef },\n actionRef,\n virtualListRef,\n loadMoreRef,\n scrollAndFocus,\n onlyFocus,\n getMessagesInView,\n trackFocusMessage,\n}: UseKeyboardArgs) => {\n const handleKey = React.useCallback(\n (e: React.KeyboardEvent<HTMLElement>) => {\n const { key, currentTarget } = e;\n const index = currentTarget.dataset?.index ? Number(currentTarget.dataset.index) : undefined;\n const isIndexNumber = getIsNumber(index);\n e.stopPropagation();\n switch (key) {\n case 'ArrowUp':\n e.preventDefault();\n if (index && index > 0) {\n trackFocusMessage(getMessageFocusId(messages[index - 1], index - 1));\n } else if (hasMoreItems === 'top') {\n loadMoreRef.current?.focus();\n }\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (messages?.length && isIndexNumber && index < messages.length - 1) {\n trackFocusMessage(getMessageFocusId(messages[index + 1], index + 1));\n }\n break;\n case 'Home':\n e.preventDefault();\n scrollAndFocus(0);\n break;\n case 'End':\n e.preventDefault();\n if (messages?.length) scrollAndFocus(messages.length - 1);\n break;\n case 'Tab':\n if (hasMoreItems === 'bottom' && !e.shiftKey) {\n e.preventDefault();\n loadMoreRef.current?.focus();\n } else if (hasMoreItems === 'top' && e.shiftKey) {\n e.preventDefault();\n loadMoreRef.current?.focus();\n } else if (!e.shiftKey) {\n if (bannerPosition) {\n e.preventDefault();\n bannerRef?.current?.focusOnWrapper();\n }\n } else {\n e.preventDefault();\n virtualListRef.current?.focus();\n }\n break;\n default:\n break;\n }\n },\n [hasMoreItems, messages, scrollAndFocus, virtualListRef, loadMoreRef, bannerPosition, bannerRef, trackFocusMessage],\n );\n const handleListKey = React.useCallback(\n (e: React.KeyboardEvent) => {\n const { key } = e;\n switch (key) {\n case 'ArrowUp':\n e.preventDefault();\n if (document.activeElement !== loadMoreRef.current) {\n const id = getMessagesInView()?.shift();\n if (id) onlyFocus(id);\n }\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (document.activeElement === loadMoreRef.current) {\n onlyFocus('0');\n } else {\n const id = getMessagesInView()?.pop();\n if (id) onlyFocus(id);\n }\n break;\n case 'Home':\n e.preventDefault();\n scrollAndFocus(0);\n break;\n case 'End':\n e.preventDefault();\n if (messages?.length) scrollAndFocus(messages.length - 1);\n break;\n case 'Tab':\n if (document.activeElement !== loadMoreRef.current) {\n if (hasMoreItems === 'bottom' && !e.shiftKey) {\n e.preventDefault();\n loadMoreRef.current?.focus();\n } else if (!e.shiftKey) {\n e.preventDefault();\n actionRef.current?.focusToComposer?.();\n }\n } else if (!e.shiftKey) {\n e.preventDefault();\n actionRef.current?.focusToComposer?.();\n } else {\n e.preventDefault();\n virtualListRef.current?.focus();\n }\n break;\n default:\n break;\n }\n },\n [actionRef, hasMoreItems, loadMoreRef, messages, getMessagesInView, onlyFocus, scrollAndFocus, virtualListRef],\n );\n\n return React.useMemo(() => ({ handleKey, handleListKey }), [handleKey, handleListKey]);\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["React"]
7
7
  }
@@ -0,0 +1,102 @@
1
+ import * as React from "react";
2
+ import React2 from "react";
3
+ const getMessageFocusId = (message, index) => message.dsId === void 0 || message.dsId === null ? `index:${index}` : `id:${typeof message.dsId}:${message.dsId}`;
4
+ const getMessagePositionId = (index) => `position:${index}`;
5
+ const useMessageFocusTracker = (virtualListRef) => {
6
+ const [focusRequest, setFocusRequest] = React2.useState(null);
7
+ const lastRequestId = React2.useRef(0);
8
+ const fulfilledRequestId = React2.useRef(0);
9
+ const requestOrigin = React2.useRef(null);
10
+ const trackFocusMessage = React2.useCallback(
11
+ (messageId, { preventScroll = false } = {}) => {
12
+ lastRequestId.current += 1;
13
+ requestOrigin.current = document.activeElement;
14
+ setFocusRequest({ messageId, requestId: lastRequestId.current, preventScroll });
15
+ },
16
+ []
17
+ );
18
+ const trackFocusResetter = React2.useCallback(() => {
19
+ fulfilledRequestId.current = lastRequestId.current;
20
+ setFocusRequest(null);
21
+ }, []);
22
+ const trackFocusedMessage = React2.useCallback((messageId) => {
23
+ fulfilledRequestId.current = lastRequestId.current;
24
+ setFocusRequest(
25
+ (previous) => previous?.messageId === messageId ? previous : { messageId, requestId: lastRequestId.current, preventScroll: false }
26
+ );
27
+ }, []);
28
+ const mayTakeFocus = React2.useCallback(
29
+ (requestId, target) => {
30
+ const active = document.activeElement;
31
+ const isPending = requestId > fulfilledRequestId.current;
32
+ if (!active || active === document.body) return isPending ? "request" : "restore";
33
+ if (isPending && active === requestOrigin.current) return "request";
34
+ if (!target?.contains(active)) trackFocusResetter();
35
+ return null;
36
+ },
37
+ [trackFocusResetter]
38
+ );
39
+ const markFulfilled = React2.useCallback((requestId) => {
40
+ fulfilledRequestId.current = Math.max(fulfilledRequestId.current, requestId);
41
+ }, []);
42
+ const listenersCleanup = React2.useRef(null);
43
+ const listRootRef = React2.useCallback(
44
+ (node) => {
45
+ listenersCleanup.current?.();
46
+ listenersCleanup.current = null;
47
+ if (!node) return;
48
+ const onDocumentFocusIn = (e) => {
49
+ const target = e.composedPath()[0] ?? e.target;
50
+ if (!virtualListRef.current?.contains(target)) trackFocusResetter();
51
+ };
52
+ const endPendingRequest = () => {
53
+ if (lastRequestId.current > fulfilledRequestId.current) trackFocusResetter();
54
+ };
55
+ const userScrollEvents = ["wheel", "touchstart", "pointerdown"];
56
+ document.addEventListener("focusin", onDocumentFocusIn);
57
+ userScrollEvents.forEach((type) => node.addEventListener(type, endPendingRequest, { passive: true }));
58
+ listenersCleanup.current = () => {
59
+ document.removeEventListener("focusin", onDocumentFocusIn);
60
+ userScrollEvents.forEach((type) => node.removeEventListener(type, endPendingRequest));
61
+ };
62
+ },
63
+ [virtualListRef, trackFocusResetter]
64
+ );
65
+ const handleFocusOut = React2.useCallback(
66
+ (e) => {
67
+ const related = e.relatedTarget;
68
+ if (related && e.currentTarget.contains(related)) return;
69
+ if (!related && !document.hasFocus()) return;
70
+ trackFocusResetter();
71
+ },
72
+ [trackFocusResetter]
73
+ );
74
+ return React2.useMemo(
75
+ () => ({
76
+ focusRequest,
77
+ trackFocusMessage,
78
+ trackFocusResetter,
79
+ trackFocusedMessage,
80
+ mayTakeFocus,
81
+ markFulfilled,
82
+ handleFocusOut,
83
+ listRootRef
84
+ }),
85
+ [
86
+ focusRequest,
87
+ trackFocusMessage,
88
+ trackFocusResetter,
89
+ trackFocusedMessage,
90
+ mayTakeFocus,
91
+ markFulfilled,
92
+ handleFocusOut,
93
+ listRootRef
94
+ ]
95
+ );
96
+ };
97
+ export {
98
+ getMessageFocusId,
99
+ getMessagePositionId,
100
+ useMessageFocusTracker
101
+ };
102
+ //# sourceMappingURL=useMessageFocusTracker.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/chat-container-messages-list/useMessageFocusTracker.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React from 'react';\n\n/** Focus identity of a message, from `getMessageFocusId`. */\nexport type MessageId = string;\n\n/**\n * Identity the focus intent is kept by: the message's `dsId`, which survives index shifts. `dsId` is required by\n * the types but not at runtime, so a message without one falls back to its index (the focus then follows the\n * position, as it did before the focus tracker) instead of matching every other id-less message. The two forms\n * carry different prefixes so a `dsId` can never equal an index fallback, and the type of the `dsId` is kept so\n * `3` and `'3'` stay different messages, as with a direct comparison.\n */\nexport const getMessageFocusId = (message: { dsId?: string | number | null }, index: number): MessageId =>\n message.dsId === undefined || message.dsId === null ? `index:${index}` : `id:${typeof message.dsId}:${message.dsId}`;\n\n/**\n * Target by position, for a request made before the message exists in the rendered list (for example\n * `focusToIndex` called right after the consumer adds a message): the item at that index focuses itself when it\n * mounts, and its real focus then moves the intent to its identity.\n */\nexport const getMessagePositionId = (index: number): MessageId => `position:${index}`;\n\nexport type MessageFocusRequest = {\n /** Identity of the message to focus, from `getMessageFocusId`. */\n messageId: MessageId;\n /** Incremented by every explicit request, so asking again for the current target focuses it again. */\n requestId: number;\n /** `true` when the caller scrolls to the message itself, so focusing must not scroll as well. */\n preventScroll: boolean;\n};\n\ntype TrackFocusOptions = { preventScroll?: boolean };\n\n/**\n * Message focus through the focus-tracker pattern: handlers declare which message should have the focus, and\n * only that message's `ItemRenderer` focuses itself from its ref callback, once React has committed it. Nothing\n * here moves the focus directly.\n *\n * Removing a focused message never clears the intent: React does not dispatch `onBlur` for a focused node it\n * removes itself (measured for a prepend and for a message scrolled out of the virtual window). The intent is\n * cleared by real focus moves: leaving the list (`handleFocusOut`), a `focusin` on a non-message element of the\n * list, any `focusin` outside the list while an intent exists (also when the focus was on the page, where no\n * event crosses the list), and a remount that finds the focus elsewhere (`mayTakeFocus`).\n */\nexport const useMessageFocusTracker = (virtualListRef: React.MutableRefObject<HTMLDivElement | null>) => {\n const [focusRequest, setFocusRequest] = React.useState<MessageFocusRequest | null>(null);\n const lastRequestId = React.useRef(0);\n const fulfilledRequestId = React.useRef(0);\n /** The element that had the focus when the last explicit request was made. */\n const requestOrigin = React.useRef<Element | null>(null);\n\n const trackFocusMessage = React.useCallback(\n (messageId: MessageId, { preventScroll = false }: TrackFocusOptions = {}) => {\n lastRequestId.current += 1;\n requestOrigin.current = document.activeElement;\n setFocusRequest({ messageId, requestId: lastRequestId.current, preventScroll });\n },\n [],\n );\n\n const trackFocusResetter = React.useCallback(() => {\n fulfilledRequestId.current = lastRequestId.current;\n setFocusRequest(null);\n }, []);\n\n /**\n * Keeps the intent equal to the message that actually has the focus (the item itself or a descendant, such as a\n * link in its body), without re-focusing it. The real focus closes any pending request: this invariant keeps the\n * new intent passive, so the guard in `mayTakeFocus` neither takes the focus from the user nor drops the intent.\n */\n const trackFocusedMessage = React.useCallback((messageId: MessageId) => {\n fulfilledRequestId.current = lastRequestId.current;\n setFocusRequest((previous) =>\n previous?.messageId === messageId\n ? previous\n : { messageId, requestId: lastRequestId.current, preventScroll: false },\n );\n }, []);\n\n /**\n * Whether the target (the message's own item wrapper) may take the focus now, and how:\n * - `'request'`: an explicit request not yet fulfilled, from `body` or from the element focused when it was made;\n * it focuses with the request's own `preventScroll`.\n * - `'restore'`: a target that only remounts (scrolled back into view, or shifted by older messages), from\n * `body`; it focuses without scrolling, so restoring the focus never moves the list (the scroll offset is\n * the consumer's to change).\n * - `null`: not now. If the focus is already inside the target (for example on a link in its body), nothing\n * changes; if it is anywhere else, the user moved away and the intent is cleared, pending or passive.\n */\n const mayTakeFocus = React.useCallback(\n (requestId: number, target: Element | null): 'request' | 'restore' | null => {\n const active = document.activeElement;\n const isPending = requestId > fulfilledRequestId.current;\n if (!active || active === document.body) return isPending ? 'request' : 'restore';\n if (isPending && active === requestOrigin.current) return 'request';\n if (!target?.contains(active)) trackFocusResetter();\n return null;\n },\n [trackFocusResetter],\n );\n\n const markFulfilled = React.useCallback((requestId: number) => {\n fulfilledRequestId.current = Math.max(fulfilledRequestId.current, requestId);\n }, []);\n\n const listenersCleanup = React.useRef<(() => void) | null>(null);\n /**\n * Ref callback for the list wrapper. It subscribes, in the commit phase like the focus itself, to what no React\n * handler on the list sees:\n * - a `focusin` anywhere outside the list clears the intent, even when the focus was on the page and no event\n * crossed the list (for example a message scrolled away, then the composer focused and blurred);\n * - the user scrolling the list by hand (wheel, touch, scrollbar) cancels a pending request, so a target that\n * mounts much later never takes the focus, from the element the request was made from or from `body`.\n */\n const listRootRef = React.useCallback(\n (node: HTMLElement | null) => {\n listenersCleanup.current?.();\n listenersCleanup.current = null;\n if (!node) return;\n const onDocumentFocusIn = (e: FocusEvent) => {\n /** `composedPath` sees the real target when the chat is rendered inside a shadow root. */\n const target = (e.composedPath()[0] ?? e.target) as Node;\n if (!virtualListRef.current?.contains(target)) trackFocusResetter();\n };\n /** Clears a pending request (not a passive intent): marking it fulfilled would still let it restore from `body`. */\n const endPendingRequest = () => {\n if (lastRequestId.current > fulfilledRequestId.current) trackFocusResetter();\n };\n const userScrollEvents = ['wheel', 'touchstart', 'pointerdown'] as const;\n document.addEventListener('focusin', onDocumentFocusIn);\n userScrollEvents.forEach((type) => node.addEventListener(type, endPendingRequest, { passive: true }));\n listenersCleanup.current = () => {\n document.removeEventListener('focusin', onDocumentFocusIn);\n userScrollEvents.forEach((type) => node.removeEventListener(type, endPendingRequest));\n };\n },\n [virtualListRef, trackFocusResetter],\n );\n\n /** `focusout` on the list wrapper: clears the intent when the focus leaves the message list or goes to the page. */\n const handleFocusOut = React.useCallback(\n (e: React.FocusEvent<HTMLElement>) => {\n const related = e.relatedTarget as Node | null;\n if (related && e.currentTarget.contains(related)) return;\n /** Switching to another window blurs the message without the user moving the focus in the page. */\n if (!related && !document.hasFocus()) return;\n trackFocusResetter();\n },\n [trackFocusResetter],\n );\n\n return React.useMemo(\n () => ({\n focusRequest,\n trackFocusMessage,\n trackFocusResetter,\n trackFocusedMessage,\n mayTakeFocus,\n markFulfilled,\n handleFocusOut,\n listRootRef,\n }),\n [\n focusRequest,\n trackFocusMessage,\n trackFocusResetter,\n trackFocusedMessage,\n mayTakeFocus,\n markFulfilled,\n handleFocusOut,\n listRootRef,\n ],\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["React"]
7
+ }
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
- import { PropTypes, globalAttributesPropTypes } from "@elliemae/ds-props-helpers";
2
+ import { PropTypes, getPropsPerSlotPropTypes, globalAttributesPropTypes } from "@elliemae/ds-props-helpers";
3
3
  import { BANNER_TYPES } from "@elliemae/ds-banner";
4
+ import { DSChatContainerSlotName, DSChatContainerSlots } from "./DSChatContainerDefinitions.js";
4
5
  function noop(..._args) {
5
6
  }
6
7
  const defaultPropsComposer = {
@@ -23,7 +24,7 @@ const defaultPropsComposer = {
23
24
  const ChatComposerPropTypes = {
24
25
  placeholder: PropTypes.string.description("Input Placeholder").defaultValue(defaultPropsComposer.placeholder),
25
26
  inputValue: PropTypes.string.description("Input value").defaultValue(defaultPropsComposer.inputValue),
26
- ariaMaxLengthMessage: PropTypes.string.description("Aria message for Max length message when exceeded").defaultValue(defaultPropsComposer.maxLengthMessage),
27
+ ariaMaxLengthMessage: PropTypes.string.description("Aria message for Max length message when exceeded").defaultValue(defaultPropsComposer.ariaMaxLengthMessage),
27
28
  maxLengthMessage: PropTypes.string.description("Max length message").defaultValue(defaultPropsComposer.maxLengthMessage),
28
29
  onChange: PropTypes.func.description("Called when the user types").defaultValue(defaultPropsComposer.onChange),
29
30
  onResize: PropTypes.func.description("Called the input changes his height").defaultValue(defaultPropsComposer.onResize),
@@ -31,19 +32,22 @@ const ChatComposerPropTypes = {
31
32
  onFocus: PropTypes.func.description("Input focus").defaultValue(defaultPropsComposer.onFocus),
32
33
  onBlur: PropTypes.func.description("Input blur").defaultValue(defaultPropsComposer.onBlur),
33
34
  onKeyDown: PropTypes.func.description("Input on key down").defaultValue(defaultPropsComposer.onKeyDown),
34
- maxHeight: PropTypes.number.description("Max height of the composer. Use 0 for no limit").defaultValue(defaultPropsComposer.onBlur),
35
+ maxHeight: PropTypes.number.description("Max height of the composer. Use 0 for no limit").defaultValue(defaultPropsComposer.maxHeight),
35
36
  inputMaxLength: PropTypes.number.description("Max length of the composer. `undefined` for no limit").defaultValue(defaultPropsComposer.inputMaxLength),
36
37
  buttonDisabled: PropTypes.bool.description("Control the disabled for the send button").defaultValue(defaultPropsComposer.buttonDisabled),
37
- dataTestid: PropTypes.string.description("Data testid").defaultValue(defaultPropsComposer.placeholder),
38
+ dataTestid: PropTypes.string.description("Data testid").defaultValue(defaultPropsComposer.dataTestid),
38
39
  actionRef: PropTypes.object.description(
39
40
  `Reference:
40
41
  {
41
- scrollToIndex?: (n: number, opts: { align: 'end' | 'center' | 'start' }) => void,
42
- getMessagesInView?: () => number[],
43
- focusToIndex?: (n: number) => void,
42
+ scrollToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,
43
+ focusToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,
44
+ getMessagesInView?: () => string[],
45
+ focusToIndexWithoutScroll?: (n: string) => void,
44
46
  focusToList?: () => void,
45
47
  focusToComposer?: () => void,
46
48
  focusToSend?: () => void,
49
+ focusOnBanner?: () => void,
50
+ focusOnBannerLink?: () => void,
47
51
  }
48
52
 
49
53
  `
@@ -62,18 +66,21 @@ const defaultPropsMessagesList = {
62
66
  bannerRef: void 0
63
67
  };
64
68
  const ChatContainerMessagesListPropTypes = {
69
+ ...getPropsPerSlotPropTypes(DSChatContainerSlotName, DSChatContainerSlots),
65
70
  ...globalAttributesPropTypes,
66
71
  messages: PropTypes.arrayOf(PropTypes.object).description("The array of out-of-the-box items you want to render inside the ChatMessageList").defaultValue(defaultPropsMessagesList.messages),
67
72
  actionRef: PropTypes.object.description(
68
73
  `Reference:
69
74
  {
70
- scrollToIndex?: (n: number, opts: { align: 'end' | 'center' | 'start' }) => void,
71
- getMessagesInView: () => number[],
72
- focusToIndex: (n: number) => void,
73
- focusToIndexWithoutScroll: (n: number) => void,
74
- focusToList: () => void,
75
- focusToComposer: () => void,
76
- focusToSend: () => void,
75
+ scrollToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,
76
+ focusToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,
77
+ getMessagesInView?: () => string[],
78
+ focusToIndexWithoutScroll?: (n: string) => void,
79
+ focusToList?: () => void,
80
+ focusToComposer?: () => void,
81
+ focusToSend?: () => void,
82
+ focusOnBanner?: () => void,
83
+ focusOnBannerLink?: () => void,
77
84
  }
78
85
 
79
86
  `
@@ -85,7 +92,9 @@ const ChatContainerMessagesListPropTypes = {
85
92
  hasMoreItems: PropTypes.oneOf(["top", "bottom", void 0]).description(
86
93
  "Show Load More button at the `top` or `bottom` of the container"
87
94
  ),
88
- getMoreMessages: PropTypes.func.description("Called when the user clicks on load more").defaultValue(defaultPropsMessagesList.getMoreMessages),
95
+ getMoreMessages: PropTypes.func.description(
96
+ "Called when the user clicks on load more. When older messages are added at the start of `messages`, the list keeps its scroll offset, so the messages in view shift; call `actionRef.current.scrollToIndex` after updating `messages` to bring the user back to where they were"
97
+ ).defaultValue(defaultPropsMessagesList.getMoreMessages),
89
98
  sendingMessages: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)]).description("Array of ids of sending messages").defaultValue(defaultPropsMessagesList.sendingMessages),
90
99
  sendingText: PropTypes.string.description("Label description for messages in sending status").defaultValue(defaultPropsMessagesList.sendingText)
91
100
  };
@@ -111,7 +120,9 @@ const defaultProps = {
111
120
  };
112
121
  const ChatContainerPropTypes = {
113
122
  ...globalAttributesPropTypes,
114
- messagesListProps: PropTypes.object.description('ChatMessageList props "messages" / "onScrollEnds"').defaultValue(defaultProps.messagesListProps),
123
+ messagesListProps: PropTypes.object.description(
124
+ 'ChatMessageList props "messages" / "onScrollEnds", plus the "dsChatcontainerMessagesListScrollArea" slot prop (object or function) for the scroll area'
125
+ ).defaultValue(defaultProps.messagesListProps),
115
126
  composerProps: PropTypes.object.description("Composer configuration").defaultValue(defaultProps.composerProps),
116
127
  autoScroll: PropTypes.bool.description("Auto scroll to bottom on resize").defaultValue(defaultProps.autoScroll),
117
128
  device: PropTypes.string.description("Option to render mobile or desktop style composer").defaultValue(defaultProps.device),
@@ -121,9 +132,11 @@ const ChatContainerPropTypes = {
121
132
  hasMoreItems: PropTypes.oneOf(["top", "bottom", void 0]).description(
122
133
  "Show Load More button at the `top` or `bottom` of the container"
123
134
  ),
124
- getMoreMessages: PropTypes.func.description("Called when the user clicks on load more").defaultValue(defaultProps.getMoreMessages),
135
+ getMoreMessages: PropTypes.func.description(
136
+ "Called when the user clicks on load more. When older messages are added at the start of `messages`, the list keeps its scroll offset, so the messages in view shift; call `actionRef.current.scrollToIndex` after updating `messages` to bring the user back to where they were"
137
+ ).defaultValue(defaultProps.getMoreMessages),
125
138
  bannerPosition: PropTypes.oneOf(["top", "bottom", void 0]).description(
126
- "Show Loading messages indicator at the `top` or `bottom` of the container"
139
+ "Show the unread messages banner (configured with `bannerProps`) at the `top` or `bottom` of the container"
127
140
  ),
128
141
  bannerProps: PropTypes.object.description(
129
142
  `Banner configuration:
@@ -139,12 +152,15 @@ const ChatContainerPropTypes = {
139
152
  actionRef: PropTypes.object.description(
140
153
  `Reference:
141
154
  {
142
- scrollToIndex: (n: number) => void,
143
- getMessagesInView: () => number[],
144
- focusToIndex: (n: number) => void,
145
- focusToList: () => void,
146
- focusToComposer: () => void,
147
- focusToSend: () => void,
155
+ scrollToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,
156
+ focusToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,
157
+ getMessagesInView?: () => string[],
158
+ focusToIndexWithoutScroll?: (n: string) => void,
159
+ focusToList?: () => void,
160
+ focusToComposer?: () => void,
161
+ focusToSend?: () => void,
162
+ focusOnBanner?: () => void,
163
+ focusOnBannerLink?: () => void,
148
164
  }
149
165
 
150
166
  `
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/react-desc-prop-types.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-lines */\nimport type { Virtualizer } from '@tanstack/react-virtual';\nimport { PropTypes, globalAttributesPropTypes } from '@elliemae/ds-props-helpers';\nimport { BANNER_TYPES } from '@elliemae/ds-banner';\nimport { type DSChatBubbleT } from '@elliemae/ds-chat-bubble';\nimport { type DSButtonT } from '@elliemae/ds-button-v2';\n\n// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\nfunction noop<T extends unknown[]>(..._args: T): void {}\nexport declare namespace DSChatT {\n interface ChatBannerProps {\n label: string;\n viewLabel: string;\n type?: 'info' | 'success' | 'danger' | 'warning';\n onView: () => void;\n onClose: () => void;\n }\n /**\n * Single source of truth for the virtualizer's element generics \u2014 reused across every file that\n * types `useVirtualHelpers`, so they can't drift out of sync with each other (which previously\n * produced a real dts build failure: `Virtualizer<HTMLDivElement, Element>` vs `Virtualizer<Element, Element>`).\n */\n export type ChatVirtualizer = Virtualizer<HTMLDivElement, HTMLDivElement>;\n export type ScrollToIndexOptions = Parameters<ChatVirtualizer['scrollToIndex']>[1];\n export type ActionRef = React.MutableRefObject<{\n scrollToIndex?: (index: number, opts?: ScrollToIndexOptions) => void;\n focusToIndex?: (index: number, opts?: ScrollToIndexOptions) => void;\n getMessagesInView?: () => string[];\n focusToIndexWithoutScroll?: (index: string) => void;\n focusToList?: () => void;\n focusToComposer?: () => void;\n focusToSend?: () => void;\n focusOnBanner?: () => void;\n focusOnBannerLink?: () => void;\n }>;\n\n export interface ComposerProps extends Record<string, unknown> {\n placeholder?: string;\n inputValue?: string;\n ariaMaxLengthMessage?: string;\n maxLengthMessage?: string;\n onChange: (value: string) => void;\n onResize?: (value: number) => void;\n onSend: (e: Parameters<Required<DSButtonT.Props>['onClick']>[0]) => void;\n onFocus?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;\n onBlur?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n maxHeight?: number;\n inputMaxLength?: number;\n buttonDisabled: boolean;\n dataTestid?: string;\n actionRef?: ActionRef;\n }\n\n export interface MessagesListProps extends Record<string, unknown> {\n messages: DSChatBubbleT.Props[];\n actionRef: ActionRef;\n onScrollEnds?: (indexList: string[]) => void;\n isLoading?: 'top' | 'bottom';\n hasMoreItems?: 'top' | 'bottom';\n getMoreMessages: () => void;\n sendingMessages?: Array<string | number>;\n sendingText: string;\n bannerPosition?: 'top' | 'bottom';\n bannerRef?: React.MutableRefObject<{\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n focusOnWrapper: (...args: any[]) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n focusOnLink: (...args: any[]) => void;\n }>;\n }\n\n export interface ContainerProps extends Record<string, unknown> {\n messagesListProps: Pick<MessagesListProps, 'messages' | 'onScrollEnds'>;\n composerProps: ComposerProps;\n actionRef?: ActionRef;\n autoScroll: boolean;\n device: 'desktop' | 'mobile';\n isLoading?: 'top' | 'bottom';\n hasMoreItems?: 'top' | 'bottom';\n getMoreMessages: () => void;\n bannerPosition?: 'top' | 'bottom';\n bannerProps?: ChatBannerProps;\n sendingMessages?: string[] | number[];\n sendingText: string;\n }\n\n export interface GetPaddingT {\n hasMoreItems: string | undefined;\n bannerPosition: string | undefined;\n isLoading: string | undefined;\n }\n}\n\nexport interface TextAreaProps {\n height: string | number;\n style: React.CSSProperties;\n}\n\nexport const defaultPropsComposer: DSChatT.ComposerProps = {\n placeholder: 'Type your message',\n inputValue: '',\n ariaMaxLengthMessage: '',\n onChange: noop,\n onResize: noop,\n onSend: noop,\n onFocus: noop,\n onBlur: noop,\n onKeyDown: noop,\n maxHeight: 0,\n inputMaxLength: undefined,\n maxLengthMessage: undefined,\n buttonDisabled: false,\n dataTestid: 'ds-chat-composer',\n actionRef: undefined,\n};\n\nexport const ChatComposerPropTypes = {\n placeholder: PropTypes.string.description('Input Placeholder').defaultValue(defaultPropsComposer.placeholder),\n inputValue: PropTypes.string.description('Input value').defaultValue(defaultPropsComposer.inputValue),\n ariaMaxLengthMessage: PropTypes.string\n .description('Aria message for Max length message when exceeded')\n .defaultValue(defaultPropsComposer.maxLengthMessage),\n maxLengthMessage: PropTypes.string\n .description('Max length message')\n .defaultValue(defaultPropsComposer.maxLengthMessage),\n onChange: PropTypes.func.description('Called when the user types').defaultValue(defaultPropsComposer.onChange),\n onResize: PropTypes.func\n .description('Called the input changes his height')\n .defaultValue(defaultPropsComposer.onResize),\n onSend: PropTypes.func.description('Called when the click send').defaultValue(defaultPropsComposer.onSend),\n onFocus: PropTypes.func.description('Input focus').defaultValue(defaultPropsComposer.onFocus),\n onBlur: PropTypes.func.description('Input blur').defaultValue(defaultPropsComposer.onBlur),\n onKeyDown: PropTypes.func.description('Input on key down').defaultValue(defaultPropsComposer.onKeyDown),\n maxHeight: PropTypes.number\n .description('Max height of the composer. Use 0 for no limit')\n .defaultValue(defaultPropsComposer.onBlur),\n inputMaxLength: PropTypes.number\n .description('Max length of the composer. `undefined` for no limit')\n .defaultValue(defaultPropsComposer.inputMaxLength),\n buttonDisabled: PropTypes.bool\n .description('Control the disabled for the send button')\n .defaultValue(defaultPropsComposer.buttonDisabled),\n dataTestid: PropTypes.string.description('Data testid').defaultValue(defaultPropsComposer.placeholder),\n actionRef: PropTypes.object\n .description(\n `Reference: \n { \n scrollToIndex?: (n: number, opts: { align: 'end' | 'center' | 'start' }) => void,\n getMessagesInView?: () => number[],\n focusToIndex?: (n: number) => void,\n focusToList?: () => void,\n focusToComposer?: () => void,\n focusToSend?: () => void,\n }\n \n `,\n )\n .defaultValue(defaultPropsComposer.actionRef),\n};\n\nexport const defaultPropsMessagesList: DSChatT.MessagesListProps = {\n messages: [],\n actionRef: { current: {} },\n // we don't want this to exist \"by default\" since this loads document.addEventListener\n // the code is already checking for this callback existence everytime it's invoked anyway\n // onScrollEnds: () => [],\n getMoreMessages: noop,\n sendingMessages: undefined,\n sendingText: 'Sending',\n bannerPosition: undefined,\n bannerRef: undefined,\n};\n\nexport const ChatContainerMessagesListPropTypes = {\n ...globalAttributesPropTypes,\n\n messages: PropTypes.arrayOf(PropTypes.object)\n .description('The array of out-of-the-box items you want to render inside the ChatMessageList')\n .defaultValue(defaultPropsMessagesList.messages),\n actionRef: PropTypes.object\n .description(\n `Reference: \n { \n scrollToIndex?: (n: number, opts: { align: 'end' | 'center' | 'start' }) => void,\n getMessagesInView: () => number[],\n focusToIndex: (n: number) => void,\n focusToIndexWithoutScroll: (n: number) => void,\n focusToList: () => void,\n focusToComposer: () => void,\n focusToSend: () => void,\n }\n \n `,\n )\n .defaultValue(defaultPropsMessagesList.actionRef),\n onScrollEnds: PropTypes.func.description(`Called when the scroll stops.`),\n isLoading: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Keeps the load more space while the loading is in progress',\n ),\n hasMoreItems: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Load More button at the `top` or `bottom` of the container',\n ),\n getMoreMessages: PropTypes.func\n .description('Called when the user clicks on load more')\n .defaultValue(defaultPropsMessagesList.getMoreMessages),\n sendingMessages: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)])\n .description('Array of ids of sending messages')\n .defaultValue(defaultPropsMessagesList.sendingMessages),\n sendingText: PropTypes.string\n .description('Label description for messages in sending status')\n .defaultValue(defaultPropsMessagesList.sendingText),\n};\n\nexport const defaultProps: DSChatT.ContainerProps = {\n messagesListProps: defaultPropsMessagesList,\n composerProps: defaultPropsComposer,\n actionRef: undefined,\n autoScroll: false,\n device: 'desktop',\n isLoading: undefined,\n hasMoreItems: undefined,\n getMoreMessages: noop,\n bannerPosition: undefined,\n bannerProps: {\n type: BANNER_TYPES.INFO,\n label: 'Unread Messages',\n viewLabel: 'View',\n onView: noop,\n onClose: noop,\n },\n sendingMessages: undefined,\n sendingText: 'Sending',\n};\n\nexport const ChatContainerPropTypes = {\n ...globalAttributesPropTypes,\n messagesListProps: PropTypes.object\n .description('ChatMessageList props \"messages\" / \"onScrollEnds\"')\n .defaultValue(defaultProps.messagesListProps),\n composerProps: PropTypes.object.description('Composer configuration').defaultValue(defaultProps.composerProps),\n autoScroll: PropTypes.bool.description('Auto scroll to bottom on resize').defaultValue(defaultProps.autoScroll),\n device: PropTypes.string\n .description('Option to render mobile or desktop style composer')\n .defaultValue(defaultProps.device),\n isLoading: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Loading messages indicator at the `top` or `bottom` of the container',\n ),\n hasMoreItems: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Load More button at the `top` or `bottom` of the container',\n ),\n getMoreMessages: PropTypes.func\n .description('Called when the user clicks on load more')\n .defaultValue(defaultProps.getMoreMessages),\n bannerPosition: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Loading messages indicator at the `top` or `bottom` of the container',\n ),\n bannerProps: PropTypes.object\n .description(\n `Banner configuration:\n label: string;\n viewLabel: string;\n type: BANNER_TYPES;\n onView: () => void;\n onClose: () => void;\n `,\n )\n .defaultValue(defaultProps.bannerProps),\n sendingMessages: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)])\n .description('Array of ids of sending messages')\n .defaultValue(defaultProps.sendingMessages),\n sendingText: PropTypes.string\n .description('Label description for messages in sending status')\n .defaultValue(defaultProps.sendingText),\n actionRef: PropTypes.object\n .description(\n `Reference: \n { \n scrollToIndex: (n: number) => void,\n getMessagesInView: () => number[],\n focusToIndex: (n: number) => void,\n focusToList: () => void,\n focusToComposer: () => void,\n focusToSend: () => void,\n }\n \n `,\n )\n .defaultValue(defaultProps.actionRef),\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-lines */\nimport type { DSFastListT } from '@elliemae/ds-fast-list';\nimport { PropTypes, getPropsPerSlotPropTypes, globalAttributesPropTypes } from '@elliemae/ds-props-helpers';\nimport type { TypescriptHelpersT } from '@elliemae/ds-typescript-helpers';\nimport { BANNER_TYPES } from '@elliemae/ds-banner';\nimport { type DSChatBubbleT } from '@elliemae/ds-chat-bubble';\nimport { type DSButtonT } from '@elliemae/ds-button-v2';\nimport { DSChatContainerSlotName, DSChatContainerSlots } from './DSChatContainerDefinitions.js';\n\n// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars\nfunction noop<T extends unknown[]>(..._args: T): void {}\nexport declare namespace DSChatT {\n interface ChatBannerProps {\n label: string;\n viewLabel: string;\n type?: 'info' | 'success' | 'danger' | 'warning';\n onView: () => void;\n onClose: () => void;\n }\n /**\n * Kept with its published shape \u2014 react-virtual v2's optional `scrollToIndex` options: `{ align }` with `align`\n * required, or `undefined` \u2014 so code written against it keeps compiling.\n */\n export type ScrollToIndexOptions = DSFastListT.ScrollToOptions | undefined;\n /** What `scrollToIndex` and `focusToIndex` accept: `align` is optional and `behavior` can request a smooth scroll. */\n export type ScrollActionOptions = DSFastListT.ScrollActionOptions;\n export type ActionRef = React.MutableRefObject<{\n /** Method syntax on purpose: an `actionRef` typed with the published `ScrollToIndexOptions` stays assignable. */\n scrollToIndex?(index: number, opts?: ScrollActionOptions): void;\n focusToIndex?(index: number, opts?: ScrollActionOptions): void;\n getMessagesInView?: () => string[];\n focusToIndexWithoutScroll?: (index: string) => void;\n focusToList?: () => void;\n focusToComposer?: () => void;\n focusToSend?: () => void;\n focusOnBanner?: () => void;\n focusOnBannerLink?: () => void;\n }>;\n\n export interface ComposerProps extends Record<string, unknown> {\n placeholder?: string;\n inputValue?: string;\n ariaMaxLengthMessage?: string;\n maxLengthMessage?: string;\n onChange: (value: string) => void;\n onResize?: (value: number) => void;\n onSend: (e: Parameters<Required<DSButtonT.Props>['onClick']>[0]) => void;\n onFocus?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;\n onBlur?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n maxHeight?: number;\n inputMaxLength?: number;\n buttonDisabled: boolean;\n dataTestid?: string;\n actionRef?: ActionRef;\n }\n\n export type MessagesListSlotProps = TypescriptHelpersT.PropsForGlobalOnSlots<\n typeof DSChatContainerSlotName,\n typeof DSChatContainerSlots\n >;\n\n export interface MessagesListProps extends Record<string, unknown>, MessagesListSlotProps {\n messages: DSChatBubbleT.Props[];\n actionRef: ActionRef;\n onScrollEnds?: (indexList: string[]) => void;\n isLoading?: 'top' | 'bottom';\n hasMoreItems?: 'top' | 'bottom';\n getMoreMessages: () => void;\n sendingMessages?: Array<string | number>;\n sendingText: string;\n bannerPosition?: 'top' | 'bottom';\n bannerRef?: React.MutableRefObject<{\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n focusOnWrapper: (...args: any[]) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n focusOnLink: (...args: any[]) => void;\n }>;\n }\n\n export interface ContainerProps extends Record<string, unknown> {\n messagesListProps: Pick<MessagesListProps, 'messages' | 'onScrollEnds'> & MessagesListSlotProps;\n composerProps: ComposerProps;\n actionRef?: ActionRef;\n autoScroll: boolean;\n device: 'desktop' | 'mobile';\n isLoading?: 'top' | 'bottom';\n hasMoreItems?: 'top' | 'bottom';\n getMoreMessages: () => void;\n bannerPosition?: 'top' | 'bottom';\n bannerProps?: ChatBannerProps;\n sendingMessages?: string[] | number[];\n sendingText: string;\n }\n\n export interface GetPaddingT {\n hasMoreItems: string | undefined;\n bannerPosition: string | undefined;\n isLoading: string | undefined;\n }\n}\n\nexport interface TextAreaProps {\n height: string | number;\n style: React.CSSProperties;\n}\n\nexport const defaultPropsComposer: DSChatT.ComposerProps = {\n placeholder: 'Type your message',\n inputValue: '',\n ariaMaxLengthMessage: '',\n onChange: noop,\n onResize: noop,\n onSend: noop,\n onFocus: noop,\n onBlur: noop,\n onKeyDown: noop,\n maxHeight: 0,\n inputMaxLength: undefined,\n maxLengthMessage: undefined,\n buttonDisabled: false,\n dataTestid: 'ds-chat-composer',\n actionRef: undefined,\n};\n\nexport const ChatComposerPropTypes = {\n placeholder: PropTypes.string.description('Input Placeholder').defaultValue(defaultPropsComposer.placeholder),\n inputValue: PropTypes.string.description('Input value').defaultValue(defaultPropsComposer.inputValue),\n ariaMaxLengthMessage: PropTypes.string\n .description('Aria message for Max length message when exceeded')\n .defaultValue(defaultPropsComposer.ariaMaxLengthMessage),\n maxLengthMessage: PropTypes.string\n .description('Max length message')\n .defaultValue(defaultPropsComposer.maxLengthMessage),\n onChange: PropTypes.func.description('Called when the user types').defaultValue(defaultPropsComposer.onChange),\n onResize: PropTypes.func\n .description('Called the input changes his height')\n .defaultValue(defaultPropsComposer.onResize),\n onSend: PropTypes.func.description('Called when the click send').defaultValue(defaultPropsComposer.onSend),\n onFocus: PropTypes.func.description('Input focus').defaultValue(defaultPropsComposer.onFocus),\n onBlur: PropTypes.func.description('Input blur').defaultValue(defaultPropsComposer.onBlur),\n onKeyDown: PropTypes.func.description('Input on key down').defaultValue(defaultPropsComposer.onKeyDown),\n maxHeight: PropTypes.number\n .description('Max height of the composer. Use 0 for no limit')\n .defaultValue(defaultPropsComposer.maxHeight),\n inputMaxLength: PropTypes.number\n .description('Max length of the composer. `undefined` for no limit')\n .defaultValue(defaultPropsComposer.inputMaxLength),\n buttonDisabled: PropTypes.bool\n .description('Control the disabled for the send button')\n .defaultValue(defaultPropsComposer.buttonDisabled),\n dataTestid: PropTypes.string.description('Data testid').defaultValue(defaultPropsComposer.dataTestid),\n actionRef: PropTypes.object\n .description(\n `Reference: \n { \n scrollToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,\n focusToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,\n getMessagesInView?: () => string[],\n focusToIndexWithoutScroll?: (n: string) => void,\n focusToList?: () => void,\n focusToComposer?: () => void,\n focusToSend?: () => void,\n focusOnBanner?: () => void,\n focusOnBannerLink?: () => void,\n }\n \n `,\n )\n .defaultValue(defaultPropsComposer.actionRef),\n};\n\nexport const defaultPropsMessagesList: DSChatT.MessagesListProps = {\n messages: [],\n actionRef: { current: {} },\n // we don't want this to exist \"by default\" since this loads document.addEventListener\n // the code is already checking for this callback existence everytime it's invoked anyway\n // onScrollEnds: () => [],\n getMoreMessages: noop,\n sendingMessages: undefined,\n sendingText: 'Sending',\n bannerPosition: undefined,\n bannerRef: undefined,\n};\n\nexport const ChatContainerMessagesListPropTypes = {\n ...getPropsPerSlotPropTypes(DSChatContainerSlotName, DSChatContainerSlots),\n ...globalAttributesPropTypes,\n\n messages: PropTypes.arrayOf(PropTypes.object)\n .description('The array of out-of-the-box items you want to render inside the ChatMessageList')\n .defaultValue(defaultPropsMessagesList.messages),\n actionRef: PropTypes.object\n .description(\n `Reference: \n { \n scrollToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,\n focusToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,\n getMessagesInView?: () => string[],\n focusToIndexWithoutScroll?: (n: string) => void,\n focusToList?: () => void,\n focusToComposer?: () => void,\n focusToSend?: () => void,\n focusOnBanner?: () => void,\n focusOnBannerLink?: () => void,\n }\n \n `,\n )\n .defaultValue(defaultPropsMessagesList.actionRef),\n onScrollEnds: PropTypes.func.description(`Called when the scroll stops.`),\n isLoading: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Keeps the load more space while the loading is in progress',\n ),\n hasMoreItems: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Load More button at the `top` or `bottom` of the container',\n ),\n getMoreMessages: PropTypes.func\n .description(\n 'Called when the user clicks on load more. When older messages are added at the start of `messages`, the list keeps its scroll offset, so the messages in view shift; call `actionRef.current.scrollToIndex` after updating `messages` to bring the user back to where they were',\n )\n .defaultValue(defaultPropsMessagesList.getMoreMessages),\n sendingMessages: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)])\n .description('Array of ids of sending messages')\n .defaultValue(defaultPropsMessagesList.sendingMessages),\n sendingText: PropTypes.string\n .description('Label description for messages in sending status')\n .defaultValue(defaultPropsMessagesList.sendingText),\n};\n\nexport const defaultProps: DSChatT.ContainerProps = {\n messagesListProps: defaultPropsMessagesList,\n composerProps: defaultPropsComposer,\n actionRef: undefined,\n autoScroll: false,\n device: 'desktop',\n isLoading: undefined,\n hasMoreItems: undefined,\n getMoreMessages: noop,\n bannerPosition: undefined,\n bannerProps: {\n type: BANNER_TYPES.INFO,\n label: 'Unread Messages',\n viewLabel: 'View',\n onView: noop,\n onClose: noop,\n },\n sendingMessages: undefined,\n sendingText: 'Sending',\n};\n\nexport const ChatContainerPropTypes = {\n ...globalAttributesPropTypes,\n messagesListProps: PropTypes.object\n .description(\n 'ChatMessageList props \"messages\" / \"onScrollEnds\", plus the \"dsChatcontainerMessagesListScrollArea\" slot prop (object or function) for the scroll area',\n )\n .defaultValue(defaultProps.messagesListProps),\n composerProps: PropTypes.object.description('Composer configuration').defaultValue(defaultProps.composerProps),\n autoScroll: PropTypes.bool.description('Auto scroll to bottom on resize').defaultValue(defaultProps.autoScroll),\n device: PropTypes.string\n .description('Option to render mobile or desktop style composer')\n .defaultValue(defaultProps.device),\n isLoading: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Loading messages indicator at the `top` or `bottom` of the container',\n ),\n hasMoreItems: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show Load More button at the `top` or `bottom` of the container',\n ),\n getMoreMessages: PropTypes.func\n .description(\n 'Called when the user clicks on load more. When older messages are added at the start of `messages`, the list keeps its scroll offset, so the messages in view shift; call `actionRef.current.scrollToIndex` after updating `messages` to bring the user back to where they were',\n )\n .defaultValue(defaultProps.getMoreMessages),\n bannerPosition: PropTypes.oneOf(['top', 'bottom', undefined]).description(\n 'Show the unread messages banner (configured with `bannerProps`) at the `top` or `bottom` of the container',\n ),\n bannerProps: PropTypes.object\n .description(\n `Banner configuration:\n label: string;\n viewLabel: string;\n type: BANNER_TYPES;\n onView: () => void;\n onClose: () => void;\n `,\n )\n .defaultValue(defaultProps.bannerProps),\n sendingMessages: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)])\n .description('Array of ids of sending messages')\n .defaultValue(defaultProps.sendingMessages),\n sendingText: PropTypes.string\n .description('Label description for messages in sending status')\n .defaultValue(defaultProps.sendingText),\n actionRef: PropTypes.object\n .description(\n `Reference: \n { \n scrollToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,\n focusToIndex?: (n: number, opts?: { align?: 'start' | 'center' | 'end' | 'auto', behavior?: 'auto' | 'smooth' }) => void,\n getMessagesInView?: () => string[],\n focusToIndexWithoutScroll?: (n: string) => void,\n focusToList?: () => void,\n focusToComposer?: () => void,\n focusToSend?: () => void,\n focusOnBanner?: () => void,\n focusOnBannerLink?: () => void,\n }\n \n `,\n )\n .defaultValue(defaultProps.actionRef),\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -53,6 +53,19 @@ const testDefinitionAsConst = {
53
53
  },
54
54
  sendingText: "Sending..."
55
55
  };
56
+ const actionRef = { current: {} };
57
+ const scrollOptionsAlign = { align: "end" };
58
+ const scrollOptionsBehavior = { behavior: "smooth" };
59
+ const scrollOptionsBoth = { align: "start", behavior: "auto" };
60
+ const publishedScrollOptions = { align: "center" };
61
+ const publishedAlign = publishedScrollOptions.align;
62
+ const publishedNoScrollOptions = void 0;
63
+ const handleScrollToIndexWithPublishedOptions = () => actionRef.current.scrollToIndex?.(1, publishedScrollOptions);
64
+ const handleScrollToIndex = () => actionRef.current.scrollToIndex?.(1);
65
+ const handleScrollToIndexWithAlign = () => actionRef.current.scrollToIndex?.(1, { align: "end" });
66
+ const handleScrollToIndexWithBehavior = () => actionRef.current.scrollToIndex?.(1, { behavior: "smooth" });
67
+ const handleFocusToIndexWithBoth = () => actionRef.current.focusToIndex?.(1, { align: "start", behavior: "auto" });
68
+ const handleGetMessagesInView = () => actionRef.current.getMessagesInView?.() ?? [];
56
69
  const ExampleUsageComponent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
57
70
  /* @__PURE__ */ jsx(ChatContainer, { ...testExplicitDefinition }),
58
71
  /* @__PURE__ */ jsx(ChatContainer, { ...testInferedTypeCompatibility }),
@@ -76,6 +89,24 @@ const ExampleUsageComponent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
76
89
  },
77
90
  sendingText: "Sending..."
78
91
  }
92
+ ),
93
+ /* @__PURE__ */ jsx(ChatContainer, { ...testExplicitDefinition, actionRef }),
94
+ /* @__PURE__ */ jsx(
95
+ ChatContainer,
96
+ {
97
+ ...testExplicitDefinition,
98
+ messagesListProps: { messages, dsChatcontainerMessagesListScrollArea: { "aria-describedby": "description" } }
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsx(
102
+ ChatContainer,
103
+ {
104
+ ...testExplicitDefinition,
105
+ messagesListProps: {
106
+ messages,
107
+ dsChatcontainerMessagesListScrollArea: () => ({ "aria-describedby": "description" })
108
+ }
109
+ }
79
110
  )
80
111
  ] });
81
112
  //# sourceMappingURL=typescript-chat-container-valid.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/typescript-testing/typescript-chat-container-valid.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */\nimport type { DSChatBubbleT } from '@elliemae/ds-chat-bubble';\nimport { ChatContainer } from '../index.js';\nimport type { DSChatT } from '../index.js';\n\n// test we expose the namespace and the namespace follows our deliverable conventions\ntype ComponentPropsForApp = DSChatT.ContainerProps;\n\nconst messages: DSChatBubbleT.Props[] = [];\n\n// using the explicit type definition, if there is an error, it will be marked on the key that is wrong\nconst testExplicitDefinition: ComponentPropsForApp = {\n messagesListProps: {\n messages,\n },\n composerProps: {\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n },\n autoScroll: false,\n device: 'desktop',\n getMoreMessages: () => {},\n sendingText: 'Sending...',\n};\n\n// using the \"as\" syntax, if there is an error, it will be marking the whole object as wrong because it is not compatible with the type\nconst testInferedTypeCompatibility = {\n messagesListProps: {\n messages,\n },\n composerProps: {\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n },\n autoScroll: false,\n device: 'desktop',\n getMoreMessages: () => {},\n sendingText: 'Sending...',\n} as ComponentPropsForApp;\n\nconst testDefinitionAsConst = {\n messagesListProps: {\n messages,\n },\n composerProps: {\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n },\n autoScroll: false,\n device: 'desktop',\n getMoreMessages: () => {},\n sendingText: 'Sending...',\n} as const;\n\nconst ExampleUsageComponent = () => (\n <>\n {/* works with explicitly casted props, all syntaxes */}\n <ChatContainer {...testExplicitDefinition} />\n <ChatContainer {...testInferedTypeCompatibility} />\n <ChatContainer {...testDefinitionAsConst} />\n {/* works with inline values */}\n <ChatContainer\n messagesListProps={{\n messages,\n }}\n composerProps={{\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n }}\n autoScroll={false}\n device=\"desktop\"\n getMoreMessages={() => {}}\n sendingText=\"Sending...\"\n />\n </>\n);\n"],
5
- "mappings": "AAAA,YAAY,WAAW;AC0DrB,mBAEE,KAFF;AAxDF,SAAS,qBAAqB;AAM9B,MAAM,WAAkC,CAAC;AAGzC,MAAM,yBAA+C;AAAA,EACnD,mBAAmB;AAAA,IACjB;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,UAAU,MAAM;AAAA,IAAC;AAAA,IACjB,QAAQ,MAAM;AAAA,IAAC;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,iBAAiB,MAAM;AAAA,EAAC;AAAA,EACxB,aAAa;AACf;AAGA,MAAM,+BAA+B;AAAA,EACnC,mBAAmB;AAAA,IACjB;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,UAAU,MAAM;AAAA,IAAC;AAAA,IACjB,QAAQ,MAAM;AAAA,IAAC;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,iBAAiB,MAAM;AAAA,EAAC;AAAA,EACxB,aAAa;AACf;AAEA,MAAM,wBAAwB;AAAA,EAC5B,mBAAmB;AAAA,IACjB;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,UAAU,MAAM;AAAA,IAAC;AAAA,IACjB,QAAQ,MAAM;AAAA,IAAC;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,iBAAiB,MAAM;AAAA,EAAC;AAAA,EACxB,aAAa;AACf;AAEA,MAAM,wBAAwB,MAC5B,iCAEE;AAAA,sBAAC,iBAAe,GAAG,wBAAwB;AAAA,EAC3C,oBAAC,iBAAe,GAAG,8BAA8B;AAAA,EACjD,oBAAC,iBAAe,GAAG,uBAAuB;AAAA,EAE1C;AAAA,IAAC;AAAA;AAAA,MACC,mBAAmB;AAAA,QACjB;AAAA,MACF;AAAA,MACA,eAAe;AAAA,QACb,UAAU,MAAM;AAAA,QAAC;AAAA,QACjB,QAAQ,MAAM;AAAA,QAAC;AAAA,QACf,gBAAgB;AAAA,MAClB;AAAA,MACA,YAAY;AAAA,MACZ,QAAO;AAAA,MACP,iBAAiB,MAAM;AAAA,MAAC;AAAA,MACxB,aAAY;AAAA;AAAA,EACd;AAAA,GACF;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */\nimport type { DSChatBubbleT } from '@elliemae/ds-chat-bubble';\nimport { ChatContainer } from '../index.js';\nimport type { DSChatT } from '../index.js';\n\n// test we expose the namespace and the namespace follows our deliverable conventions\ntype ComponentPropsForApp = DSChatT.ContainerProps;\n\nconst messages: DSChatBubbleT.Props[] = [];\n\n// using the explicit type definition, if there is an error, it will be marked on the key that is wrong\nconst testExplicitDefinition: ComponentPropsForApp = {\n messagesListProps: {\n messages,\n },\n composerProps: {\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n },\n autoScroll: false,\n device: 'desktop',\n getMoreMessages: () => {},\n sendingText: 'Sending...',\n};\n\n// using the \"as\" syntax, if there is an error, it will be marking the whole object as wrong because it is not compatible with the type\nconst testInferedTypeCompatibility = {\n messagesListProps: {\n messages,\n },\n composerProps: {\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n },\n autoScroll: false,\n device: 'desktop',\n getMoreMessages: () => {},\n sendingText: 'Sending...',\n} as ComponentPropsForApp;\n\nconst testDefinitionAsConst = {\n messagesListProps: {\n messages,\n },\n composerProps: {\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n },\n autoScroll: false,\n device: 'desktop',\n getMoreMessages: () => {},\n sendingText: 'Sending...',\n} as const;\n\n// the public actionRef, including the scroll options (both `align` and `behavior` are optional)\nconst actionRef: DSChatT.ActionRef = { current: {} };\nconst scrollOptionsAlign: DSChatT.ScrollActionOptions = { align: 'end' };\nconst scrollOptionsBehavior: DSChatT.ScrollActionOptions = { behavior: 'smooth' };\nconst scrollOptionsBoth: DSChatT.ScrollActionOptions = { align: 'start', behavior: 'auto' };\n// ScrollToIndexOptions keeps its published shape: `{ align }` with `align` required, or `undefined`\nconst publishedScrollOptions: NonNullable<DSChatT.ScrollToIndexOptions> = { align: 'center' };\nconst publishedAlign: 'start' | 'center' | 'end' | 'auto' = publishedScrollOptions.align;\nconst publishedNoScrollOptions: DSChatT.ScrollToIndexOptions = undefined;\nconst handleScrollToIndexWithPublishedOptions = () => actionRef.current.scrollToIndex?.(1, publishedScrollOptions);\nconst handleScrollToIndex = () => actionRef.current.scrollToIndex?.(1);\nconst handleScrollToIndexWithAlign = () => actionRef.current.scrollToIndex?.(1, { align: 'end' });\nconst handleScrollToIndexWithBehavior = () => actionRef.current.scrollToIndex?.(1, { behavior: 'smooth' });\nconst handleFocusToIndexWithBoth = () => actionRef.current.focusToIndex?.(1, { align: 'start', behavior: 'auto' });\nconst handleGetMessagesInView: () => string[] = () => actionRef.current.getMessagesInView?.() ?? [];\n\nconst ExampleUsageComponent = () => (\n <>\n {/* works with explicitly casted props, all syntaxes */}\n <ChatContainer {...testExplicitDefinition} />\n <ChatContainer {...testInferedTypeCompatibility} />\n <ChatContainer {...testDefinitionAsConst} />\n {/* works with inline values */}\n <ChatContainer\n messagesListProps={{\n messages,\n }}\n composerProps={{\n onChange: () => {},\n onSend: () => {},\n buttonDisabled: false,\n }}\n autoScroll={false}\n device=\"desktop\"\n getMoreMessages={() => {}}\n sendingText=\"Sending...\"\n />\n <ChatContainer {...testExplicitDefinition} actionRef={actionRef} />\n {/* the message list scroll area slot, in object and function form, through messagesListProps */}\n <ChatContainer\n {...testExplicitDefinition}\n messagesListProps={{ messages, dsChatcontainerMessagesListScrollArea: { 'aria-describedby': 'description' } }}\n />\n <ChatContainer\n {...testExplicitDefinition}\n messagesListProps={{\n messages,\n dsChatcontainerMessagesListScrollArea: () => ({ 'aria-describedby': 'description' }),\n }}\n />\n </>\n);\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,11 @@
1
1
  export declare const DSChatContainerName = "DSChatcontainername";
2
2
  export declare const DSChatContainerComposerName = "DSChatcontainercomposer";
3
3
  export declare const DSChatContainerMessagesList = "DSChatcontainermessageslist";
4
+ /**
5
+ * Slot system: the main component and its parts share one slot owner name, each part with its own slot
6
+ * names (the convention of the `ds-chat-container-compliance` change, which moves these into `src/constants/`).
7
+ */
8
+ export declare const DSChatContainerSlotName = "DSChatcontainer";
9
+ export declare const DSChatContainerSlots: {
10
+ readonly MESSAGES_LIST_SCROLL_AREA: "messages-list-scroll-area";
11
+ };
@@ -1,12 +1,25 @@
1
1
  import type { DSChatBubbleT } from '@elliemae/ds-chat-bubble';
2
2
  export declare const StyledWrapper: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
3
3
  export declare const StyledWrapperListItem: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, Partial<DSChatBubbleT.Props> & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
4
- export declare const StyledChatContainerContentList: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
4
+ /**
5
+ * The scroll container is DSFastList's own container, so its horizontal padding and overflow rules are
6
+ * applied through the class that `styled(DSFastList)` forwards to it. `&&` doubles the class so these
7
+ * rules win over the container's own `overflow: auto` regardless of style injection order.
8
+ *
9
+ * No padding-top here on purpose: the scroll container is also the virtualizer's scroll element, and
10
+ * the virtualizer compares the raw `scrollTop` with its own content-relative item positions with no
11
+ * awareness of CSS padding, so a CSS top-padding would desync `getVisibleItems()` near the top boundary
12
+ * by roughly the padding's own size. The equivalent top space is passed as the virtualizer's
13
+ * `paddingStart` instead (see useChatContainerMessageList.ts).
14
+ */
15
+ export declare const StyledFastList: import("styled-components").StyledComponent<{
16
+ <T extends object>(props: import("@elliemae/ds-fast-list").DSFastListT.Props<T>): React.JSX.Element;
17
+ displayName: string;
18
+ }, import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<{
19
+ <T extends object>(props: import("@elliemae/ds-fast-list").DSFastListT.Props<T>): React.JSX.Element;
20
+ displayName: string;
21
+ }>, never>;
5
22
  export declare const StyledNewMessagesHiddenContainer: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
6
- export declare const StyledChatContainerContentListScroll: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, {
7
- height: string;
8
- } & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
9
23
  export declare const StyledLoadMoreContainer: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, {
10
24
  hasMoreItems?: "top" | "bottom";
11
25
  } & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
12
- export declare const ListItem: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
@@ -2,13 +2,11 @@ import React from 'react';
2
2
  import type { DSChatT } from '../../react-desc-prop-types.js';
3
3
  type UseActionRefArgs = {
4
4
  actionRef: DSChatT.ActionRef;
5
- useVirtualHelpers: DSChatT.ChatVirtualizer;
6
- virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;
7
- updateCache: () => void;
5
+ vScroll: (index: number, opts?: DSChatT.ScrollActionOptions) => void;
6
+ virtualListRef: React.MutableRefObject<HTMLDivElement | null>;
8
7
  getMessagesInView: () => string[];
9
8
  onlyFocus: (index: string) => void;
10
- scrollAndFocus: (index: number, opts?: DSChatT.ScrollToIndexOptions) => void;
11
- hasVirtualItems: boolean;
9
+ scrollAndFocus: (index: number, opts?: DSChatT.ScrollActionOptions) => void;
12
10
  };
13
- export declare const useActionRef: ({ actionRef, useVirtualHelpers: { scrollToIndex: vScroll }, virtualListRef, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, hasVirtualItems, }: UseActionRefArgs) => void;
11
+ export declare const useActionRef: ({ actionRef, vScroll, virtualListRef, getMessagesInView, onlyFocus, scrollAndFocus, }: UseActionRefArgs) => void;
14
12
  export {};