@elliemae/ds-chat-container 3.70.0-next.42 → 3.70.0-next.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/parts/chat-container-messages-list/useActionRef.js +6 -5
- package/dist/cjs/parts/chat-container-messages-list/useActionRef.js.map +2 -2
- package/dist/cjs/parts/chat-container-messages-list/useChatContainerMessageList.js +4 -3
- package/dist/cjs/parts/chat-container-messages-list/useChatContainerMessageList.js.map +2 -2
- package/dist/cjs/parts/chat-container-messages-list/useFocusAndScrollHelpers.js +41 -20
- package/dist/cjs/parts/chat-container-messages-list/useFocusAndScrollHelpers.js.map +2 -2
- package/dist/cjs/parts/chat-container-messages-list/useKeyboard.js +13 -4
- package/dist/cjs/parts/chat-container-messages-list/useKeyboard.js.map +2 -2
- package/dist/esm/parts/chat-container-messages-list/useActionRef.js +6 -5
- package/dist/esm/parts/chat-container-messages-list/useActionRef.js.map +2 -2
- package/dist/esm/parts/chat-container-messages-list/useChatContainerMessageList.js +4 -3
- package/dist/esm/parts/chat-container-messages-list/useChatContainerMessageList.js.map +2 -2
- package/dist/esm/parts/chat-container-messages-list/useFocusAndScrollHelpers.js +42 -21
- package/dist/esm/parts/chat-container-messages-list/useFocusAndScrollHelpers.js.map +2 -2
- package/dist/esm/parts/chat-container-messages-list/useKeyboard.js +13 -4
- package/dist/esm/parts/chat-container-messages-list/useKeyboard.js.map +2 -2
- package/dist/types/parts/chat-container-messages-list/useActionRef.d.ts +3 -2
- package/dist/types/parts/chat-container-messages-list/useFocusAndScrollHelpers.d.ts +2 -0
- package/dist/types/parts/chat-container-messages-list/useKeyboard.d.ts +2 -2
- package/package.json +17 -16
|
@@ -37,7 +37,8 @@ const useActionRef = ({
|
|
|
37
37
|
actionRef,
|
|
38
38
|
useVirtualHelpers: { scrollToIndex: vScroll },
|
|
39
39
|
virtualListRef,
|
|
40
|
-
|
|
40
|
+
updateCache,
|
|
41
|
+
getMessagesInView,
|
|
41
42
|
onlyFocus,
|
|
42
43
|
scrollAndFocus
|
|
43
44
|
}) => {
|
|
@@ -48,7 +49,7 @@ const useActionRef = ({
|
|
|
48
49
|
vScroll(index, opts);
|
|
49
50
|
requestAnimationFrame(() => {
|
|
50
51
|
vScroll(index, opts);
|
|
51
|
-
|
|
52
|
+
updateCache();
|
|
52
53
|
});
|
|
53
54
|
}, 0);
|
|
54
55
|
};
|
|
@@ -59,12 +60,12 @@ const useActionRef = ({
|
|
|
59
60
|
virtualListRef.current?.focus();
|
|
60
61
|
};
|
|
61
62
|
actionRef.current.scrollToIndex = scrollToIndex;
|
|
62
|
-
actionRef.current.getMessagesInView =
|
|
63
|
-
|
|
63
|
+
actionRef.current.getMessagesInView = getMessagesInView;
|
|
64
|
+
updateCache();
|
|
64
65
|
actionRef.current.focusToIndex = focusToIndex;
|
|
65
66
|
actionRef.current.focusToIndexWithoutScroll = onlyFocus;
|
|
66
67
|
actionRef.current.focusToList = focusToList;
|
|
67
68
|
}
|
|
68
|
-
}, [actionRef,
|
|
69
|
+
}, [actionRef, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, vScroll, virtualListRef]);
|
|
69
70
|
};
|
|
70
71
|
//# 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 { useVirtual } from 'react-virtual';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseActionRefArgs = {\n actionRef: DSChatT.ActionRef;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;
|
|
4
|
+
"sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport React from 'react';\nimport type { useVirtual } from 'react-virtual';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseActionRefArgs = {\n actionRef: DSChatT.ActionRef;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\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};\n\nexport const useActionRef = ({\n actionRef,\n useVirtualHelpers: { scrollToIndex: vScroll },\n virtualListRef,\n updateCache,\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 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 updateCache(); // populate cache immediately on mount \u2014 leading throttle fires synchronously\n actionRef.current.focusToIndex = focusToIndex;\n actionRef.current.focusToIndexWithoutScroll = onlyFocus;\n actionRef.current.focusToList = focusToList;\n }\n }, [actionRef, updateCache, 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;AAcX,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA,mBAAmB,EAAE,eAAe,QAAQ;AAAA,EAC5C;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,kBAAY;AACZ,gBAAU,QAAQ,eAAe;AACjC,gBAAU,QAAQ,4BAA4B;AAC9C,gBAAU,QAAQ,cAAc;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,WAAW,aAAa,mBAAmB,WAAW,gBAAgB,SAAS,cAAc,CAAC;AACpG;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -71,7 +71,7 @@ const useChatContainerMessageList = (props) => {
|
|
|
71
71
|
// https://github.com/tannerlinsley/react-virtual/issues/23
|
|
72
72
|
estimateSize: import_react.default.useCallback(() => 80, [])
|
|
73
73
|
});
|
|
74
|
-
const { onScrollStop, onlyFocus, scrollAndFocus, checkPendingOnScroll } = (0, import_useFocusAndScrollHelpers.useFocusAndScrollHelpers)({
|
|
74
|
+
const { onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll } = (0, import_useFocusAndScrollHelpers.useFocusAndScrollHelpers)({
|
|
75
75
|
propsWithDefault,
|
|
76
76
|
useVirtualHelpers,
|
|
77
77
|
pendingOnScroll,
|
|
@@ -81,7 +81,8 @@ const useChatContainerMessageList = (props) => {
|
|
|
81
81
|
actionRef,
|
|
82
82
|
useVirtualHelpers,
|
|
83
83
|
virtualListRef,
|
|
84
|
-
|
|
84
|
+
updateCache,
|
|
85
|
+
getMessagesInView,
|
|
85
86
|
onlyFocus,
|
|
86
87
|
scrollAndFocus
|
|
87
88
|
});
|
|
@@ -98,7 +99,7 @@ const useChatContainerMessageList = (props) => {
|
|
|
98
99
|
loadMoreRef,
|
|
99
100
|
scrollAndFocus,
|
|
100
101
|
onlyFocus,
|
|
101
|
-
|
|
102
|
+
getMessagesInView
|
|
102
103
|
});
|
|
103
104
|
return import_react.default.useMemo(
|
|
104
105
|
() => ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/parts/chat-container-messages-list/useChatContainerMessageList.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 {\n useMemoMergePropsWithDefault,\n useGetGlobalAttributes,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useVirtual } from 'react-virtual';\nimport { useActionRef } from './useActionRef.js';\nimport { useGlobalEventListener } from './useGlobalEventListener.js';\nimport { useKeyboard } from './useKeyboard.js';\nimport { useFocusAndScrollHelpers } from './useFocusAndScrollHelpers.js';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\nimport { ChatContainerMessagesListPropTypes, defaultPropsMessagesList } from '../../react-desc-prop-types.js';\nimport { DSChatContainerMessagesList } from '../../DSChatContainerDefinitions.js';\n\nconst getPadding = ({ hasMoreItems, bannerPosition, isLoading }: DSChatT.GetPaddingT) => {\n const padding = {\n paddingStart: 0,\n paddingEnd: -5,\n };\n if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'top')) padding.paddingStart = 42;\n else if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'bottom')) padding.paddingEnd = 42;\n return padding;\n};\n\ntype UseChatContainerMessageList = (props: DSChatT.MessagesListProps) => {\n propsWithDefault: DSChatT.MessagesListProps;\n globalAttributes: ReturnType<typeof useGetGlobalAttributes>;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n} & ReturnType<typeof useKeyboard>;\n\nexport const useChatContainerMessageList: UseChatContainerMessageList = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<DSChatT.MessagesListProps>(props, defaultPropsMessagesList);\n useValidateTypescriptPropTypes<DSChatT.MessagesListProps>(\n propsWithDefault,\n ChatContainerMessagesListPropTypes,\n DSChatContainerMessagesList,\n );\n const globalAttributes = useGetGlobalAttributes(propsWithDefault);\n const loadMoreRef = React.useRef<HTMLButtonElement>();\n const virtualListRef = React.useRef<HTMLDivElement>();\n\n const pendingOnScroll = React.useRef(false);\n const { bannerPosition, messages, actionRef, hasMoreItems, isLoading } = propsWithDefault;\n const useVirtualHelpers = useVirtual({\n size: messages?.length,\n parentRef: virtualListRef,\n overscan: 15,\n ...getPadding({ hasMoreItems, bannerPosition, isLoading }),\n // estimateSize should not be really required given what was stated on\n // https://github.com/tannerlinsley/react-virtual/issues/23\n estimateSize: React.useCallback(() => 80, []),\n });\n\n const { onScrollStop, onlyFocus, scrollAndFocus, checkPendingOnScroll }
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;AAClB,8BAIO;AACP,2BAA2B;AAC3B,0BAA6B;AAC7B,oCAAuC;AACvC,yBAA4B;AAC5B,sCAAyC;AAEzC,mCAA6E;AAC7E,wCAA4C;AAE5C,MAAM,aAAa,CAAC,EAAE,cAAc,gBAAgB,UAAU,MAA2B;AACvF,QAAM,UAAU;AAAA,IACd,cAAc;AAAA,IACd,YAAY;AAAA,EACd;AACA,MAAI,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,KAAK,EAAG,SAAQ,eAAe;AAAA,WAC5F,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,QAAQ,EAAG,SAAQ,aAAa;AAC3G,SAAO;AACT;AAUO,MAAM,8BAA2D,CAAC,UAAU;AACjF,QAAM,uBAAmB,sDAAwD,OAAO,qDAAwB;AAChH;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,uBAAmB,gDAAuB,gBAAgB;AAChE,QAAM,cAAc,aAAAA,QAAM,OAA0B;AACpD,QAAM,iBAAiB,aAAAA,QAAM,OAAuB;AAEpD,QAAM,kBAAkB,aAAAA,QAAM,OAAO,KAAK;AAC1C,QAAM,EAAE,gBAAgB,UAAU,WAAW,cAAc,UAAU,IAAI;AACzE,QAAM,wBAAoB,iCAAW;AAAA,IACnC,MAAM,UAAU;AAAA,IAChB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,GAAG,WAAW,EAAE,cAAc,gBAAgB,UAAU,CAAC;AAAA;AAAA;AAAA,IAGzD,cAAc,aAAAA,QAAM,YAAY,MAAM,IAAI,CAAC,CAAC;AAAA,EAC9C,CAAC;AAED,QAAM,EAAE,cAAc,WAAW,gBAAgB,qBAAqB,
|
|
4
|
+
"sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport React from 'react';\nimport {\n useMemoMergePropsWithDefault,\n useGetGlobalAttributes,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useVirtual } from 'react-virtual';\nimport { useActionRef } from './useActionRef.js';\nimport { useGlobalEventListener } from './useGlobalEventListener.js';\nimport { useKeyboard } from './useKeyboard.js';\nimport { useFocusAndScrollHelpers } from './useFocusAndScrollHelpers.js';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\nimport { ChatContainerMessagesListPropTypes, defaultPropsMessagesList } from '../../react-desc-prop-types.js';\nimport { DSChatContainerMessagesList } from '../../DSChatContainerDefinitions.js';\n\nconst getPadding = ({ hasMoreItems, bannerPosition, isLoading }: DSChatT.GetPaddingT) => {\n const padding = {\n paddingStart: 0,\n paddingEnd: -5,\n };\n if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'top')) padding.paddingStart = 42;\n else if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'bottom')) padding.paddingEnd = 42;\n return padding;\n};\n\ntype UseChatContainerMessageList = (props: DSChatT.MessagesListProps) => {\n propsWithDefault: DSChatT.MessagesListProps;\n globalAttributes: ReturnType<typeof useGetGlobalAttributes>;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n} & ReturnType<typeof useKeyboard>;\n\nexport const useChatContainerMessageList: UseChatContainerMessageList = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<DSChatT.MessagesListProps>(props, defaultPropsMessagesList);\n useValidateTypescriptPropTypes<DSChatT.MessagesListProps>(\n propsWithDefault,\n ChatContainerMessagesListPropTypes,\n DSChatContainerMessagesList,\n );\n const globalAttributes = useGetGlobalAttributes(propsWithDefault);\n const loadMoreRef = React.useRef<HTMLButtonElement>();\n const virtualListRef = React.useRef<HTMLDivElement>();\n\n const pendingOnScroll = React.useRef(false);\n const { bannerPosition, messages, actionRef, hasMoreItems, isLoading } = propsWithDefault;\n const useVirtualHelpers = useVirtual({\n size: messages?.length,\n parentRef: virtualListRef,\n overscan: 15,\n ...getPadding({ hasMoreItems, bannerPosition, isLoading }),\n // estimateSize should not be really required given what was stated on\n // https://github.com/tannerlinsley/react-virtual/issues/23\n estimateSize: React.useCallback(() => 80, []),\n });\n\n const { onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll } =\n useFocusAndScrollHelpers({\n propsWithDefault,\n useVirtualHelpers,\n pendingOnScroll,\n virtualListRef,\n });\n\n useActionRef({\n actionRef,\n useVirtualHelpers,\n virtualListRef,\n updateCache,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n });\n\n useGlobalEventListener({\n propsWithDefault,\n virtualListRef,\n onScrollStop,\n checkPendingOnScroll,\n });\n\n const keyboardMethods = useKeyboard({\n propsWithDefault,\n actionRef,\n virtualListRef,\n loadMoreRef,\n scrollAndFocus,\n onlyFocus,\n getMessagesInView,\n });\n\n return React.useMemo(\n () => ({\n propsWithDefault,\n globalAttributes,\n useVirtualHelpers,\n loadMoreRef,\n virtualListRef,\n ...keyboardMethods,\n }),\n [globalAttributes, keyboardMethods, propsWithDefault, useVirtualHelpers, loadMoreRef, virtualListRef],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;AAClB,8BAIO;AACP,2BAA2B;AAC3B,0BAA6B;AAC7B,oCAAuC;AACvC,yBAA4B;AAC5B,sCAAyC;AAEzC,mCAA6E;AAC7E,wCAA4C;AAE5C,MAAM,aAAa,CAAC,EAAE,cAAc,gBAAgB,UAAU,MAA2B;AACvF,QAAM,UAAU;AAAA,IACd,cAAc;AAAA,IACd,YAAY;AAAA,EACd;AACA,MAAI,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,KAAK,EAAG,SAAQ,eAAe;AAAA,WAC5F,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,QAAQ,EAAG,SAAQ,aAAa;AAC3G,SAAO;AACT;AAUO,MAAM,8BAA2D,CAAC,UAAU;AACjF,QAAM,uBAAmB,sDAAwD,OAAO,qDAAwB;AAChH;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,uBAAmB,gDAAuB,gBAAgB;AAChE,QAAM,cAAc,aAAAA,QAAM,OAA0B;AACpD,QAAM,iBAAiB,aAAAA,QAAM,OAAuB;AAEpD,QAAM,kBAAkB,aAAAA,QAAM,OAAO,KAAK;AAC1C,QAAM,EAAE,gBAAgB,UAAU,WAAW,cAAc,UAAU,IAAI;AACzE,QAAM,wBAAoB,iCAAW;AAAA,IACnC,MAAM,UAAU;AAAA,IAChB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,GAAG,WAAW,EAAE,cAAc,gBAAgB,UAAU,CAAC;AAAA;AAAA;AAAA,IAGzD,cAAc,aAAAA,QAAM,YAAY,MAAM,IAAI,CAAC,CAAC;AAAA,EAC9C,CAAC;AAED,QAAM,EAAE,cAAc,aAAa,mBAAmB,WAAW,gBAAgB,qBAAqB,QACpG,0DAAyB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAEH,wCAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,4DAAuB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,sBAAkB,gCAAY;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,IACA,CAAC,kBAAkB,iBAAiB,kBAAkB,mBAAmB,aAAa,cAAc;AAAA,EACtG;AACF;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -40,26 +40,42 @@ const useFocusAndScrollHelpers = ({
|
|
|
40
40
|
pendingOnScroll,
|
|
41
41
|
virtualListRef
|
|
42
42
|
}) => {
|
|
43
|
+
const computeVisibleItems = import_react.default.useCallback(() => {
|
|
44
|
+
if (document.visibilityState === "hidden") {
|
|
45
|
+
pendingOnScroll.current = true;
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
if (!virtualListRef.current) return [];
|
|
49
|
+
pendingOnScroll.current = false;
|
|
50
|
+
const { bottom, top } = virtualListRef.current.getBoundingClientRect();
|
|
51
|
+
const list = virtualListRef.current.querySelectorAll('[data-element="chat-element-list-item"]');
|
|
52
|
+
const indexList = [];
|
|
53
|
+
list.forEach((item) => {
|
|
54
|
+
const { top: itemTop } = item.getBoundingClientRect();
|
|
55
|
+
const itemPadding = 10;
|
|
56
|
+
if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index || "");
|
|
57
|
+
});
|
|
58
|
+
return indexList;
|
|
59
|
+
}, [pendingOnScroll, virtualListRef]);
|
|
60
|
+
const visibleItemsCache = import_react.default.useRef([]);
|
|
61
|
+
const updateCache = import_react.default.useMemo(
|
|
62
|
+
() => (0, import_lodash_es.throttle)(
|
|
63
|
+
() => {
|
|
64
|
+
visibleItemsCache.current = computeVisibleItems();
|
|
65
|
+
},
|
|
66
|
+
500,
|
|
67
|
+
{ leading: true }
|
|
68
|
+
),
|
|
69
|
+
[computeVisibleItems]
|
|
70
|
+
);
|
|
71
|
+
const getMessagesInView = import_react.default.useCallback(() => [...visibleItemsCache.current], []);
|
|
43
72
|
const onScrollStop = import_react.default.useMemo(
|
|
44
73
|
() => (0, import_lodash_es.debounce)(() => {
|
|
45
|
-
|
|
46
|
-
pendingOnScroll.current = true;
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
if (!virtualListRef.current) return [];
|
|
50
|
-
pendingOnScroll.current = false;
|
|
51
|
-
const { bottom, top } = virtualListRef.current?.getBoundingClientRect() || {};
|
|
52
|
-
const list = virtualListRef.current.querySelectorAll('[data-element="chat-element-list-item"]');
|
|
53
|
-
const indexList = [];
|
|
54
|
-
list.forEach((item) => {
|
|
55
|
-
const { top: itemTop } = item.getBoundingClientRect();
|
|
56
|
-
const itemPadding = 10;
|
|
57
|
-
if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index || "");
|
|
58
|
-
});
|
|
74
|
+
const indexList = computeVisibleItems();
|
|
59
75
|
if (onScrollEnds) onScrollEnds(indexList);
|
|
60
76
|
return indexList;
|
|
61
77
|
}, 500),
|
|
62
|
-
[
|
|
78
|
+
[computeVisibleItems, onScrollEnds]
|
|
63
79
|
);
|
|
64
80
|
const onlyFocus = import_react.default.useCallback(
|
|
65
81
|
(index) => {
|
|
@@ -76,21 +92,26 @@ const useFocusAndScrollHelpers = ({
|
|
|
76
92
|
setTimeout(() => {
|
|
77
93
|
onlyFocus(index.toString());
|
|
78
94
|
}, 300);
|
|
79
|
-
|
|
95
|
+
updateCache();
|
|
80
96
|
},
|
|
81
|
-
[
|
|
97
|
+
[updateCache, onlyFocus, vScroll]
|
|
82
98
|
);
|
|
83
99
|
const checkPendingOnScroll = import_react.default.useCallback(() => {
|
|
84
|
-
if (pendingOnScroll.current === true)
|
|
85
|
-
|
|
100
|
+
if (pendingOnScroll.current === true) {
|
|
101
|
+
updateCache();
|
|
102
|
+
onScrollStop();
|
|
103
|
+
}
|
|
104
|
+
}, [updateCache, onScrollStop, pendingOnScroll]);
|
|
86
105
|
return import_react.default.useMemo(
|
|
87
106
|
() => ({
|
|
88
107
|
onScrollStop,
|
|
108
|
+
updateCache,
|
|
109
|
+
getMessagesInView,
|
|
89
110
|
onlyFocus,
|
|
90
111
|
scrollAndFocus,
|
|
91
112
|
checkPendingOnScroll
|
|
92
113
|
}),
|
|
93
|
-
[onScrollStop, onlyFocus, scrollAndFocus, checkPendingOnScroll]
|
|
114
|
+
[onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll]
|
|
94
115
|
);
|
|
95
116
|
};
|
|
96
117
|
//# sourceMappingURL=useFocusAndScrollHelpers.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/parts/chat-container-messages-list/useFocusAndScrollHelpers.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 { useVirtual } from 'react-virtual';\nimport { debounce } from 'lodash-es';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseFocusAndScrollHelpersArgs = {\n propsWithDefault: DSChatT.MessagesListProps;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n pendingOnScroll: React.MutableRefObject<boolean>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n};\n\nexport const useFocusAndScrollHelpers = ({\n propsWithDefault: { onScrollEnds },\n useVirtualHelpers: { scrollToIndex: vScroll },\n pendingOnScroll,\n virtualListRef,\n}: UseFocusAndScrollHelpersArgs) => {\n const
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;AAElB,
|
|
4
|
+
"sourcesContent": ["/* eslint-disable complexity */\n/* eslint-disable jsx-a11y/no-noninteractive-tabindex */\n/* eslint-disable max-lines */\nimport React from 'react';\nimport type { useVirtual } from 'react-virtual';\nimport { debounce, throttle } from 'lodash-es';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseFocusAndScrollHelpersArgs = {\n propsWithDefault: DSChatT.MessagesListProps;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n pendingOnScroll: React.MutableRefObject<boolean>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n};\n\nexport const useFocusAndScrollHelpers = ({\n propsWithDefault: { onScrollEnds },\n useVirtualHelpers: { scrollToIndex: vScroll },\n pendingOnScroll,\n virtualListRef,\n}: UseFocusAndScrollHelpersArgs) => {\n // Pure DOM read \u2014 no side effects beyond pendingOnScroll flag and getBoundingClientRect queries.\n const computeVisibleItems = React.useCallback((): string[] => {\n if (document.visibilityState === 'hidden') {\n pendingOnScroll.current = true;\n return [];\n }\n if (!virtualListRef.current) return [];\n pendingOnScroll.current = false;\n const { bottom, top } = virtualListRef.current.getBoundingClientRect();\n const list = virtualListRef.current.querySelectorAll<HTMLElement>('[data-element=\"chat-element-list-item\"]');\n const indexList: string[] = [];\n list.forEach((item: HTMLElement) => {\n const { top: itemTop } = item.getBoundingClientRect();\n const itemPadding = 10;\n if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index || '');\n });\n return indexList;\n }, [pendingOnScroll, virtualListRef]);\n\n // Throttled with leading: populates the cache immediately on first call and keeps it\n // fresh. No side effects beyond DOM reads \u2014 onScrollEnds is not involved.\n const visibleItemsCache = React.useRef<string[]>([]);\n const updateCache = React.useMemo(\n () =>\n throttle(\n () => {\n visibleItemsCache.current = computeVisibleItems();\n },\n 500,\n { leading: true },\n ),\n [computeVisibleItems],\n );\n\n // Synchronous getter \u2014 returns a copy so callers using .pop()/.shift() don't mutate the cache.\n const getMessagesInView = React.useCallback((): string[] => [...visibleItemsCache.current], []);\n\n // Debounced trailing: notifies onScrollEnds consumers after scrolling settles.\n // Semantics and timing unchanged \u2014 this path is isolated from the cache.\n const onScrollStop = React.useMemo(\n () =>\n debounce((): string[] => {\n const indexList = computeVisibleItems();\n if (onScrollEnds) onScrollEnds(indexList);\n return indexList;\n }, 500),\n [computeVisibleItems, onScrollEnds],\n ) as () => string[];\n\n const onlyFocus = React.useCallback(\n (index: string) => {\n (virtualListRef.current?.querySelector(`[data-index=\"${index}\"]`) as HTMLDivElement)?.focus();\n },\n [virtualListRef],\n );\n\n const scrollAndFocus = React.useCallback(\n (index: number) => {\n vScroll(index, { align: 'center' });\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, { align: 'center' });\n });\n\n setTimeout(() => {\n onlyFocus(index.toString());\n }, 300);\n\n updateCache();\n },\n [updateCache, onlyFocus, vScroll],\n );\n\n const checkPendingOnScroll = React.useCallback(() => {\n if (pendingOnScroll.current === true) {\n updateCache();\n onScrollStop();\n }\n }, [updateCache, onScrollStop, pendingOnScroll]);\n\n return React.useMemo(\n () => ({\n onScrollStop,\n updateCache,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n checkPendingOnScroll,\n }),\n [onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;AAElB,uBAAmC;AAU5B,MAAM,2BAA2B,CAAC;AAAA,EACvC,kBAAkB,EAAE,aAAa;AAAA,EACjC,mBAAmB,EAAE,eAAe,QAAQ;AAAA,EAC5C;AAAA,EACA;AACF,MAAoC;AAElC,QAAM,sBAAsB,aAAAA,QAAM,YAAY,MAAgB;AAC5D,QAAI,SAAS,oBAAoB,UAAU;AACzC,sBAAgB,UAAU;AAC1B,aAAO,CAAC;AAAA,IACV;AACA,QAAI,CAAC,eAAe,QAAS,QAAO,CAAC;AACrC,oBAAgB,UAAU;AAC1B,UAAM,EAAE,QAAQ,IAAI,IAAI,eAAe,QAAQ,sBAAsB;AACrE,UAAM,OAAO,eAAe,QAAQ,iBAA8B,yCAAyC;AAC3G,UAAM,YAAsB,CAAC;AAC7B,SAAK,QAAQ,CAAC,SAAsB;AAClC,YAAM,EAAE,KAAK,QAAQ,IAAI,KAAK,sBAAsB;AACpD,YAAM,cAAc;AACpB,UAAI,UAAU,cAAc,UAAU,UAAU,cAAc,IAAK,WAAU,KAAK,KAAK,QAAQ,SAAS,EAAE;AAAA,IAC5G,CAAC;AACD,WAAO;AAAA,EACT,GAAG,CAAC,iBAAiB,cAAc,CAAC;AAIpC,QAAM,oBAAoB,aAAAA,QAAM,OAAiB,CAAC,CAAC;AACnD,QAAM,cAAc,aAAAA,QAAM;AAAA,IACxB,UACE;AAAA,MACE,MAAM;AACJ,0BAAkB,UAAU,oBAAoB;AAAA,MAClD;AAAA,MACA;AAAA,MACA,EAAE,SAAS,KAAK;AAAA,IAClB;AAAA,IACF,CAAC,mBAAmB;AAAA,EACtB;AAGA,QAAM,oBAAoB,aAAAA,QAAM,YAAY,MAAgB,CAAC,GAAG,kBAAkB,OAAO,GAAG,CAAC,CAAC;AAI9F,QAAM,eAAe,aAAAA,QAAM;AAAA,IACzB,UACE,2BAAS,MAAgB;AACvB,YAAM,YAAY,oBAAoB;AACtC,UAAI,aAAc,cAAa,SAAS;AACxC,aAAO;AAAA,IACT,GAAG,GAAG;AAAA,IACR,CAAC,qBAAqB,YAAY;AAAA,EACpC;AAEA,QAAM,YAAY,aAAAA,QAAM;AAAA,IACtB,CAAC,UAAkB;AACjB,MAAC,eAAe,SAAS,cAAc,gBAAgB,KAAK,IAAI,GAAsB,MAAM;AAAA,IAC9F;AAAA,IACA,CAAC,cAAc;AAAA,EACjB;AAEA,QAAM,iBAAiB,aAAAA,QAAM;AAAA,IAC3B,CAAC,UAAkB;AACjB,cAAQ,OAAO,EAAE,OAAO,SAAS,CAAC;AAYlC,4BAAsB,MAAM;AAC1B,gBAAQ,OAAO,EAAE,OAAO,SAAS,CAAC;AAAA,MACpC,CAAC;AAED,iBAAW,MAAM;AACf,kBAAU,MAAM,SAAS,CAAC;AAAA,MAC5B,GAAG,GAAG;AAEN,kBAAY;AAAA,IACd;AAAA,IACA,CAAC,aAAa,WAAW,OAAO;AAAA,EAClC;AAEA,QAAM,uBAAuB,aAAAA,QAAM,YAAY,MAAM;AACnD,QAAI,gBAAgB,YAAY,MAAM;AACpC,kBAAY;AACZ,mBAAa;AAAA,IACf;AAAA,EACF,GAAG,CAAC,aAAa,cAAc,eAAe,CAAC;AAE/C,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,cAAc,aAAa,mBAAmB,WAAW,gBAAgB,oBAAoB;AAAA,EAChG;AACF;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -41,7 +41,7 @@ const useKeyboard = ({
|
|
|
41
41
|
loadMoreRef,
|
|
42
42
|
scrollAndFocus,
|
|
43
43
|
onlyFocus,
|
|
44
|
-
|
|
44
|
+
getMessagesInView
|
|
45
45
|
}) => {
|
|
46
46
|
const handleKey = import_react.default.useCallback(
|
|
47
47
|
(e) => {
|
|
@@ -102,7 +102,7 @@ const useKeyboard = ({
|
|
|
102
102
|
case "ArrowUp":
|
|
103
103
|
e.preventDefault();
|
|
104
104
|
if (document.activeElement !== loadMoreRef.current) {
|
|
105
|
-
const id =
|
|
105
|
+
const id = getMessagesInView()?.shift();
|
|
106
106
|
if (id) onlyFocus(id);
|
|
107
107
|
}
|
|
108
108
|
break;
|
|
@@ -111,7 +111,7 @@ const useKeyboard = ({
|
|
|
111
111
|
if (document.activeElement === loadMoreRef.current) {
|
|
112
112
|
virtualListRef.current?.querySelector(`[data-index="0"]`)?.focus();
|
|
113
113
|
} else {
|
|
114
|
-
const id =
|
|
114
|
+
const id = getMessagesInView()?.pop();
|
|
115
115
|
if (id) onlyFocus(id);
|
|
116
116
|
}
|
|
117
117
|
break;
|
|
@@ -144,7 +144,16 @@ const useKeyboard = ({
|
|
|
144
144
|
break;
|
|
145
145
|
}
|
|
146
146
|
},
|
|
147
|
-
[
|
|
147
|
+
[
|
|
148
|
+
actionRef,
|
|
149
|
+
hasMoreItems,
|
|
150
|
+
loadMoreRef,
|
|
151
|
+
messages.length,
|
|
152
|
+
getMessagesInView,
|
|
153
|
+
onlyFocus,
|
|
154
|
+
scrollAndFocus,
|
|
155
|
+
virtualListRef
|
|
156
|
+
]
|
|
148
157
|
);
|
|
149
158
|
return import_react.default.useMemo(() => ({ handleKey, handleListKey }), [handleKey, handleListKey]);
|
|
150
159
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/parts/chat-container-messages-list/useKeyboard.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 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
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,mBAAkB;
|
|
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 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", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -4,7 +4,8 @@ const useActionRef = ({
|
|
|
4
4
|
actionRef,
|
|
5
5
|
useVirtualHelpers: { scrollToIndex: vScroll },
|
|
6
6
|
virtualListRef,
|
|
7
|
-
|
|
7
|
+
updateCache,
|
|
8
|
+
getMessagesInView,
|
|
8
9
|
onlyFocus,
|
|
9
10
|
scrollAndFocus
|
|
10
11
|
}) => {
|
|
@@ -15,7 +16,7 @@ const useActionRef = ({
|
|
|
15
16
|
vScroll(index, opts);
|
|
16
17
|
requestAnimationFrame(() => {
|
|
17
18
|
vScroll(index, opts);
|
|
18
|
-
|
|
19
|
+
updateCache();
|
|
19
20
|
});
|
|
20
21
|
}, 0);
|
|
21
22
|
};
|
|
@@ -26,13 +27,13 @@ const useActionRef = ({
|
|
|
26
27
|
virtualListRef.current?.focus();
|
|
27
28
|
};
|
|
28
29
|
actionRef.current.scrollToIndex = scrollToIndex;
|
|
29
|
-
actionRef.current.getMessagesInView =
|
|
30
|
-
|
|
30
|
+
actionRef.current.getMessagesInView = getMessagesInView;
|
|
31
|
+
updateCache();
|
|
31
32
|
actionRef.current.focusToIndex = focusToIndex;
|
|
32
33
|
actionRef.current.focusToIndexWithoutScroll = onlyFocus;
|
|
33
34
|
actionRef.current.focusToList = focusToList;
|
|
34
35
|
}
|
|
35
|
-
}, [actionRef,
|
|
36
|
+
}, [actionRef, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, vScroll, virtualListRef]);
|
|
36
37
|
};
|
|
37
38
|
export {
|
|
38
39
|
useActionRef
|
|
@@ -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/useActionRef.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 { useVirtual } from 'react-virtual';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseActionRefArgs = {\n actionRef: DSChatT.ActionRef;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;
|
|
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 { useVirtual } from 'react-virtual';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseActionRefArgs = {\n actionRef: DSChatT.ActionRef;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\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};\n\nexport const useActionRef = ({\n actionRef,\n useVirtualHelpers: { scrollToIndex: vScroll },\n virtualListRef,\n updateCache,\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 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 updateCache(); // populate cache immediately on mount \u2014 leading throttle fires synchronously\n actionRef.current.focusToIndex = focusToIndex;\n actionRef.current.focusToIndexWithoutScroll = onlyFocus;\n actionRef.current.focusToList = focusToList;\n }\n }, [actionRef, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, vScroll, virtualListRef]);\n};\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;AAcX,MAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA,mBAAmB,EAAE,eAAe,QAAQ;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwB;AACtB,EAAAA,OAAM,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,kBAAY;AACZ,gBAAU,QAAQ,eAAe;AACjC,gBAAU,QAAQ,4BAA4B;AAC9C,gBAAU,QAAQ,cAAc;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,WAAW,aAAa,mBAAmB,WAAW,gBAAgB,SAAS,cAAc,CAAC;AACpG;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -42,7 +42,7 @@ const useChatContainerMessageList = (props) => {
|
|
|
42
42
|
// https://github.com/tannerlinsley/react-virtual/issues/23
|
|
43
43
|
estimateSize: React2.useCallback(() => 80, [])
|
|
44
44
|
});
|
|
45
|
-
const { onScrollStop, onlyFocus, scrollAndFocus, checkPendingOnScroll } = useFocusAndScrollHelpers({
|
|
45
|
+
const { onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll } = useFocusAndScrollHelpers({
|
|
46
46
|
propsWithDefault,
|
|
47
47
|
useVirtualHelpers,
|
|
48
48
|
pendingOnScroll,
|
|
@@ -52,7 +52,8 @@ const useChatContainerMessageList = (props) => {
|
|
|
52
52
|
actionRef,
|
|
53
53
|
useVirtualHelpers,
|
|
54
54
|
virtualListRef,
|
|
55
|
-
|
|
55
|
+
updateCache,
|
|
56
|
+
getMessagesInView,
|
|
56
57
|
onlyFocus,
|
|
57
58
|
scrollAndFocus
|
|
58
59
|
});
|
|
@@ -69,7 +70,7 @@ const useChatContainerMessageList = (props) => {
|
|
|
69
70
|
loadMoreRef,
|
|
70
71
|
scrollAndFocus,
|
|
71
72
|
onlyFocus,
|
|
72
|
-
|
|
73
|
+
getMessagesInView
|
|
73
74
|
});
|
|
74
75
|
return React2.useMemo(
|
|
75
76
|
() => ({
|
|
@@ -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/useChatContainerMessageList.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 {\n useMemoMergePropsWithDefault,\n useGetGlobalAttributes,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useVirtual } from 'react-virtual';\nimport { useActionRef } from './useActionRef.js';\nimport { useGlobalEventListener } from './useGlobalEventListener.js';\nimport { useKeyboard } from './useKeyboard.js';\nimport { useFocusAndScrollHelpers } from './useFocusAndScrollHelpers.js';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\nimport { ChatContainerMessagesListPropTypes, defaultPropsMessagesList } from '../../react-desc-prop-types.js';\nimport { DSChatContainerMessagesList } from '../../DSChatContainerDefinitions.js';\n\nconst getPadding = ({ hasMoreItems, bannerPosition, isLoading }: DSChatT.GetPaddingT) => {\n const padding = {\n paddingStart: 0,\n paddingEnd: -5,\n };\n if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'top')) padding.paddingStart = 42;\n else if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'bottom')) padding.paddingEnd = 42;\n return padding;\n};\n\ntype UseChatContainerMessageList = (props: DSChatT.MessagesListProps) => {\n propsWithDefault: DSChatT.MessagesListProps;\n globalAttributes: ReturnType<typeof useGetGlobalAttributes>;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n} & ReturnType<typeof useKeyboard>;\n\nexport const useChatContainerMessageList: UseChatContainerMessageList = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<DSChatT.MessagesListProps>(props, defaultPropsMessagesList);\n useValidateTypescriptPropTypes<DSChatT.MessagesListProps>(\n propsWithDefault,\n ChatContainerMessagesListPropTypes,\n DSChatContainerMessagesList,\n );\n const globalAttributes = useGetGlobalAttributes(propsWithDefault);\n const loadMoreRef = React.useRef<HTMLButtonElement>();\n const virtualListRef = React.useRef<HTMLDivElement>();\n\n const pendingOnScroll = React.useRef(false);\n const { bannerPosition, messages, actionRef, hasMoreItems, isLoading } = propsWithDefault;\n const useVirtualHelpers = useVirtual({\n size: messages?.length,\n parentRef: virtualListRef,\n overscan: 15,\n ...getPadding({ hasMoreItems, bannerPosition, isLoading }),\n // estimateSize should not be really required given what was stated on\n // https://github.com/tannerlinsley/react-virtual/issues/23\n estimateSize: React.useCallback(() => 80, []),\n });\n\n const { onScrollStop, onlyFocus, scrollAndFocus, checkPendingOnScroll }
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AACvC,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AAEzC,SAAS,oCAAoC,gCAAgC;AAC7E,SAAS,mCAAmC;AAE5C,MAAM,aAAa,CAAC,EAAE,cAAc,gBAAgB,UAAU,MAA2B;AACvF,QAAM,UAAU;AAAA,IACd,cAAc;AAAA,IACd,YAAY;AAAA,EACd;AACA,MAAI,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,KAAK,EAAG,SAAQ,eAAe;AAAA,WAC5F,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,QAAQ,EAAG,SAAQ,aAAa;AAC3G,SAAO;AACT;AAUO,MAAM,8BAA2D,CAAC,UAAU;AACjF,QAAM,mBAAmB,6BAAwD,OAAO,wBAAwB;AAChH;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,mBAAmB,uBAAuB,gBAAgB;AAChE,QAAM,cAAcA,OAAM,OAA0B;AACpD,QAAM,iBAAiBA,OAAM,OAAuB;AAEpD,QAAM,kBAAkBA,OAAM,OAAO,KAAK;AAC1C,QAAM,EAAE,gBAAgB,UAAU,WAAW,cAAc,UAAU,IAAI;AACzE,QAAM,oBAAoB,WAAW;AAAA,IACnC,MAAM,UAAU;AAAA,IAChB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,GAAG,WAAW,EAAE,cAAc,gBAAgB,UAAU,CAAC;AAAA;AAAA;AAAA,IAGzD,cAAcA,OAAM,YAAY,MAAM,IAAI,CAAC,CAAC;AAAA,EAC9C,CAAC;AAED,QAAM,EAAE,cAAc,WAAW,gBAAgB,qBAAqB,
|
|
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 {\n useMemoMergePropsWithDefault,\n useGetGlobalAttributes,\n useValidateTypescriptPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { useVirtual } from 'react-virtual';\nimport { useActionRef } from './useActionRef.js';\nimport { useGlobalEventListener } from './useGlobalEventListener.js';\nimport { useKeyboard } from './useKeyboard.js';\nimport { useFocusAndScrollHelpers } from './useFocusAndScrollHelpers.js';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\nimport { ChatContainerMessagesListPropTypes, defaultPropsMessagesList } from '../../react-desc-prop-types.js';\nimport { DSChatContainerMessagesList } from '../../DSChatContainerDefinitions.js';\n\nconst getPadding = ({ hasMoreItems, bannerPosition, isLoading }: DSChatT.GetPaddingT) => {\n const padding = {\n paddingStart: 0,\n paddingEnd: -5,\n };\n if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'top')) padding.paddingStart = 42;\n else if ([hasMoreItems, bannerPosition, isLoading].some((item) => item === 'bottom')) padding.paddingEnd = 42;\n return padding;\n};\n\ntype UseChatContainerMessageList = (props: DSChatT.MessagesListProps) => {\n propsWithDefault: DSChatT.MessagesListProps;\n globalAttributes: ReturnType<typeof useGetGlobalAttributes>;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n} & ReturnType<typeof useKeyboard>;\n\nexport const useChatContainerMessageList: UseChatContainerMessageList = (props) => {\n const propsWithDefault = useMemoMergePropsWithDefault<DSChatT.MessagesListProps>(props, defaultPropsMessagesList);\n useValidateTypescriptPropTypes<DSChatT.MessagesListProps>(\n propsWithDefault,\n ChatContainerMessagesListPropTypes,\n DSChatContainerMessagesList,\n );\n const globalAttributes = useGetGlobalAttributes(propsWithDefault);\n const loadMoreRef = React.useRef<HTMLButtonElement>();\n const virtualListRef = React.useRef<HTMLDivElement>();\n\n const pendingOnScroll = React.useRef(false);\n const { bannerPosition, messages, actionRef, hasMoreItems, isLoading } = propsWithDefault;\n const useVirtualHelpers = useVirtual({\n size: messages?.length,\n parentRef: virtualListRef,\n overscan: 15,\n ...getPadding({ hasMoreItems, bannerPosition, isLoading }),\n // estimateSize should not be really required given what was stated on\n // https://github.com/tannerlinsley/react-virtual/issues/23\n estimateSize: React.useCallback(() => 80, []),\n });\n\n const { onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll } =\n useFocusAndScrollHelpers({\n propsWithDefault,\n useVirtualHelpers,\n pendingOnScroll,\n virtualListRef,\n });\n\n useActionRef({\n actionRef,\n useVirtualHelpers,\n virtualListRef,\n updateCache,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n });\n\n useGlobalEventListener({\n propsWithDefault,\n virtualListRef,\n onScrollStop,\n checkPendingOnScroll,\n });\n\n const keyboardMethods = useKeyboard({\n propsWithDefault,\n actionRef,\n virtualListRef,\n loadMoreRef,\n scrollAndFocus,\n onlyFocus,\n getMessagesInView,\n });\n\n return React.useMemo(\n () => ({\n propsWithDefault,\n globalAttributes,\n useVirtualHelpers,\n loadMoreRef,\n virtualListRef,\n ...keyboardMethods,\n }),\n [globalAttributes, keyboardMethods, propsWithDefault, useVirtualHelpers, loadMoreRef, virtualListRef],\n );\n};\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AACvC,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AAEzC,SAAS,oCAAoC,gCAAgC;AAC7E,SAAS,mCAAmC;AAE5C,MAAM,aAAa,CAAC,EAAE,cAAc,gBAAgB,UAAU,MAA2B;AACvF,QAAM,UAAU;AAAA,IACd,cAAc;AAAA,IACd,YAAY;AAAA,EACd;AACA,MAAI,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,KAAK,EAAG,SAAQ,eAAe;AAAA,WAC5F,CAAC,cAAc,gBAAgB,SAAS,EAAE,KAAK,CAAC,SAAS,SAAS,QAAQ,EAAG,SAAQ,aAAa;AAC3G,SAAO;AACT;AAUO,MAAM,8BAA2D,CAAC,UAAU;AACjF,QAAM,mBAAmB,6BAAwD,OAAO,wBAAwB;AAChH;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,mBAAmB,uBAAuB,gBAAgB;AAChE,QAAM,cAAcA,OAAM,OAA0B;AACpD,QAAM,iBAAiBA,OAAM,OAAuB;AAEpD,QAAM,kBAAkBA,OAAM,OAAO,KAAK;AAC1C,QAAM,EAAE,gBAAgB,UAAU,WAAW,cAAc,UAAU,IAAI;AACzE,QAAM,oBAAoB,WAAW;AAAA,IACnC,MAAM,UAAU;AAAA,IAChB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,GAAG,WAAW,EAAE,cAAc,gBAAgB,UAAU,CAAC;AAAA;AAAA;AAAA,IAGzD,cAAcA,OAAM,YAAY,MAAM,IAAI,CAAC,CAAC;AAAA,EAC9C,CAAC;AAED,QAAM,EAAE,cAAc,aAAa,mBAAmB,WAAW,gBAAgB,qBAAqB,IACpG,yBAAyB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAEH,eAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,yBAAuB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,kBAAkB,YAAY;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAOA,OAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,IACA,CAAC,kBAAkB,iBAAiB,kBAAkB,mBAAmB,aAAa,cAAc;AAAA,EACtG;AACF;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -1,32 +1,48 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import React2 from "react";
|
|
3
|
-
import { debounce } from "lodash-es";
|
|
3
|
+
import { debounce, throttle } from "lodash-es";
|
|
4
4
|
const useFocusAndScrollHelpers = ({
|
|
5
5
|
propsWithDefault: { onScrollEnds },
|
|
6
6
|
useVirtualHelpers: { scrollToIndex: vScroll },
|
|
7
7
|
pendingOnScroll,
|
|
8
8
|
virtualListRef
|
|
9
9
|
}) => {
|
|
10
|
+
const computeVisibleItems = React2.useCallback(() => {
|
|
11
|
+
if (document.visibilityState === "hidden") {
|
|
12
|
+
pendingOnScroll.current = true;
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
if (!virtualListRef.current) return [];
|
|
16
|
+
pendingOnScroll.current = false;
|
|
17
|
+
const { bottom, top } = virtualListRef.current.getBoundingClientRect();
|
|
18
|
+
const list = virtualListRef.current.querySelectorAll('[data-element="chat-element-list-item"]');
|
|
19
|
+
const indexList = [];
|
|
20
|
+
list.forEach((item) => {
|
|
21
|
+
const { top: itemTop } = item.getBoundingClientRect();
|
|
22
|
+
const itemPadding = 10;
|
|
23
|
+
if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index || "");
|
|
24
|
+
});
|
|
25
|
+
return indexList;
|
|
26
|
+
}, [pendingOnScroll, virtualListRef]);
|
|
27
|
+
const visibleItemsCache = React2.useRef([]);
|
|
28
|
+
const updateCache = React2.useMemo(
|
|
29
|
+
() => throttle(
|
|
30
|
+
() => {
|
|
31
|
+
visibleItemsCache.current = computeVisibleItems();
|
|
32
|
+
},
|
|
33
|
+
500,
|
|
34
|
+
{ leading: true }
|
|
35
|
+
),
|
|
36
|
+
[computeVisibleItems]
|
|
37
|
+
);
|
|
38
|
+
const getMessagesInView = React2.useCallback(() => [...visibleItemsCache.current], []);
|
|
10
39
|
const onScrollStop = React2.useMemo(
|
|
11
40
|
() => debounce(() => {
|
|
12
|
-
|
|
13
|
-
pendingOnScroll.current = true;
|
|
14
|
-
return [];
|
|
15
|
-
}
|
|
16
|
-
if (!virtualListRef.current) return [];
|
|
17
|
-
pendingOnScroll.current = false;
|
|
18
|
-
const { bottom, top } = virtualListRef.current?.getBoundingClientRect() || {};
|
|
19
|
-
const list = virtualListRef.current.querySelectorAll('[data-element="chat-element-list-item"]');
|
|
20
|
-
const indexList = [];
|
|
21
|
-
list.forEach((item) => {
|
|
22
|
-
const { top: itemTop } = item.getBoundingClientRect();
|
|
23
|
-
const itemPadding = 10;
|
|
24
|
-
if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index || "");
|
|
25
|
-
});
|
|
41
|
+
const indexList = computeVisibleItems();
|
|
26
42
|
if (onScrollEnds) onScrollEnds(indexList);
|
|
27
43
|
return indexList;
|
|
28
44
|
}, 500),
|
|
29
|
-
[
|
|
45
|
+
[computeVisibleItems, onScrollEnds]
|
|
30
46
|
);
|
|
31
47
|
const onlyFocus = React2.useCallback(
|
|
32
48
|
(index) => {
|
|
@@ -43,21 +59,26 @@ const useFocusAndScrollHelpers = ({
|
|
|
43
59
|
setTimeout(() => {
|
|
44
60
|
onlyFocus(index.toString());
|
|
45
61
|
}, 300);
|
|
46
|
-
|
|
62
|
+
updateCache();
|
|
47
63
|
},
|
|
48
|
-
[
|
|
64
|
+
[updateCache, onlyFocus, vScroll]
|
|
49
65
|
);
|
|
50
66
|
const checkPendingOnScroll = React2.useCallback(() => {
|
|
51
|
-
if (pendingOnScroll.current === true)
|
|
52
|
-
|
|
67
|
+
if (pendingOnScroll.current === true) {
|
|
68
|
+
updateCache();
|
|
69
|
+
onScrollStop();
|
|
70
|
+
}
|
|
71
|
+
}, [updateCache, onScrollStop, pendingOnScroll]);
|
|
53
72
|
return React2.useMemo(
|
|
54
73
|
() => ({
|
|
55
74
|
onScrollStop,
|
|
75
|
+
updateCache,
|
|
76
|
+
getMessagesInView,
|
|
56
77
|
onlyFocus,
|
|
57
78
|
scrollAndFocus,
|
|
58
79
|
checkPendingOnScroll
|
|
59
80
|
}),
|
|
60
|
-
[onScrollStop, onlyFocus, scrollAndFocus, checkPendingOnScroll]
|
|
81
|
+
[onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll]
|
|
61
82
|
);
|
|
62
83
|
};
|
|
63
84
|
export {
|
|
@@ -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/useFocusAndScrollHelpers.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 { useVirtual } from 'react-virtual';\nimport { debounce } from 'lodash-es';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseFocusAndScrollHelpersArgs = {\n propsWithDefault: DSChatT.MessagesListProps;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n pendingOnScroll: React.MutableRefObject<boolean>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n};\n\nexport const useFocusAndScrollHelpers = ({\n propsWithDefault: { onScrollEnds },\n useVirtualHelpers: { scrollToIndex: vScroll },\n pendingOnScroll,\n virtualListRef,\n}: UseFocusAndScrollHelpersArgs) => {\n const
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;AAElB,SAAS,gBAAgB;
|
|
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 { useVirtual } from 'react-virtual';\nimport { debounce, throttle } from 'lodash-es';\nimport type { DSChatT } from '../../react-desc-prop-types.js';\n\ntype UseFocusAndScrollHelpersArgs = {\n propsWithDefault: DSChatT.MessagesListProps;\n useVirtualHelpers: ReturnType<typeof useVirtual>;\n pendingOnScroll: React.MutableRefObject<boolean>;\n virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;\n};\n\nexport const useFocusAndScrollHelpers = ({\n propsWithDefault: { onScrollEnds },\n useVirtualHelpers: { scrollToIndex: vScroll },\n pendingOnScroll,\n virtualListRef,\n}: UseFocusAndScrollHelpersArgs) => {\n // Pure DOM read \u2014 no side effects beyond pendingOnScroll flag and getBoundingClientRect queries.\n const computeVisibleItems = React.useCallback((): string[] => {\n if (document.visibilityState === 'hidden') {\n pendingOnScroll.current = true;\n return [];\n }\n if (!virtualListRef.current) return [];\n pendingOnScroll.current = false;\n const { bottom, top } = virtualListRef.current.getBoundingClientRect();\n const list = virtualListRef.current.querySelectorAll<HTMLElement>('[data-element=\"chat-element-list-item\"]');\n const indexList: string[] = [];\n list.forEach((item: HTMLElement) => {\n const { top: itemTop } = item.getBoundingClientRect();\n const itemPadding = 10;\n if (itemTop + itemPadding < bottom && itemTop + itemPadding > top) indexList.push(item.dataset.index || '');\n });\n return indexList;\n }, [pendingOnScroll, virtualListRef]);\n\n // Throttled with leading: populates the cache immediately on first call and keeps it\n // fresh. No side effects beyond DOM reads \u2014 onScrollEnds is not involved.\n const visibleItemsCache = React.useRef<string[]>([]);\n const updateCache = React.useMemo(\n () =>\n throttle(\n () => {\n visibleItemsCache.current = computeVisibleItems();\n },\n 500,\n { leading: true },\n ),\n [computeVisibleItems],\n );\n\n // Synchronous getter \u2014 returns a copy so callers using .pop()/.shift() don't mutate the cache.\n const getMessagesInView = React.useCallback((): string[] => [...visibleItemsCache.current], []);\n\n // Debounced trailing: notifies onScrollEnds consumers after scrolling settles.\n // Semantics and timing unchanged \u2014 this path is isolated from the cache.\n const onScrollStop = React.useMemo(\n () =>\n debounce((): string[] => {\n const indexList = computeVisibleItems();\n if (onScrollEnds) onScrollEnds(indexList);\n return indexList;\n }, 500),\n [computeVisibleItems, onScrollEnds],\n ) as () => string[];\n\n const onlyFocus = React.useCallback(\n (index: string) => {\n (virtualListRef.current?.querySelector(`[data-index=\"${index}\"]`) as HTMLDivElement)?.focus();\n },\n [virtualListRef],\n );\n\n const scrollAndFocus = React.useCallback(\n (index: number) => {\n vScroll(index, { align: 'center' });\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, { align: 'center' });\n });\n\n setTimeout(() => {\n onlyFocus(index.toString());\n }, 300);\n\n updateCache();\n },\n [updateCache, onlyFocus, vScroll],\n );\n\n const checkPendingOnScroll = React.useCallback(() => {\n if (pendingOnScroll.current === true) {\n updateCache();\n onScrollStop();\n }\n }, [updateCache, onScrollStop, pendingOnScroll]);\n\n return React.useMemo(\n () => ({\n onScrollStop,\n updateCache,\n getMessagesInView,\n onlyFocus,\n scrollAndFocus,\n checkPendingOnScroll,\n }),\n [onScrollStop, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, checkPendingOnScroll],\n );\n};\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;AAElB,SAAS,UAAU,gBAAgB;AAU5B,MAAM,2BAA2B,CAAC;AAAA,EACvC,kBAAkB,EAAE,aAAa;AAAA,EACjC,mBAAmB,EAAE,eAAe,QAAQ;AAAA,EAC5C;AAAA,EACA;AACF,MAAoC;AAElC,QAAM,sBAAsBA,OAAM,YAAY,MAAgB;AAC5D,QAAI,SAAS,oBAAoB,UAAU;AACzC,sBAAgB,UAAU;AAC1B,aAAO,CAAC;AAAA,IACV;AACA,QAAI,CAAC,eAAe,QAAS,QAAO,CAAC;AACrC,oBAAgB,UAAU;AAC1B,UAAM,EAAE,QAAQ,IAAI,IAAI,eAAe,QAAQ,sBAAsB;AACrE,UAAM,OAAO,eAAe,QAAQ,iBAA8B,yCAAyC;AAC3G,UAAM,YAAsB,CAAC;AAC7B,SAAK,QAAQ,CAAC,SAAsB;AAClC,YAAM,EAAE,KAAK,QAAQ,IAAI,KAAK,sBAAsB;AACpD,YAAM,cAAc;AACpB,UAAI,UAAU,cAAc,UAAU,UAAU,cAAc,IAAK,WAAU,KAAK,KAAK,QAAQ,SAAS,EAAE;AAAA,IAC5G,CAAC;AACD,WAAO;AAAA,EACT,GAAG,CAAC,iBAAiB,cAAc,CAAC;AAIpC,QAAM,oBAAoBA,OAAM,OAAiB,CAAC,CAAC;AACnD,QAAM,cAAcA,OAAM;AAAA,IACxB,MACE;AAAA,MACE,MAAM;AACJ,0BAAkB,UAAU,oBAAoB;AAAA,MAClD;AAAA,MACA;AAAA,MACA,EAAE,SAAS,KAAK;AAAA,IAClB;AAAA,IACF,CAAC,mBAAmB;AAAA,EACtB;AAGA,QAAM,oBAAoBA,OAAM,YAAY,MAAgB,CAAC,GAAG,kBAAkB,OAAO,GAAG,CAAC,CAAC;AAI9F,QAAM,eAAeA,OAAM;AAAA,IACzB,MACE,SAAS,MAAgB;AACvB,YAAM,YAAY,oBAAoB;AACtC,UAAI,aAAc,cAAa,SAAS;AACxC,aAAO;AAAA,IACT,GAAG,GAAG;AAAA,IACR,CAAC,qBAAqB,YAAY;AAAA,EACpC;AAEA,QAAM,YAAYA,OAAM;AAAA,IACtB,CAAC,UAAkB;AACjB,MAAC,eAAe,SAAS,cAAc,gBAAgB,KAAK,IAAI,GAAsB,MAAM;AAAA,IAC9F;AAAA,IACA,CAAC,cAAc;AAAA,EACjB;AAEA,QAAM,iBAAiBA,OAAM;AAAA,IAC3B,CAAC,UAAkB;AACjB,cAAQ,OAAO,EAAE,OAAO,SAAS,CAAC;AAYlC,4BAAsB,MAAM;AAC1B,gBAAQ,OAAO,EAAE,OAAO,SAAS,CAAC;AAAA,MACpC,CAAC;AAED,iBAAW,MAAM;AACf,kBAAU,MAAM,SAAS,CAAC;AAAA,MAC5B,GAAG,GAAG;AAEN,kBAAY;AAAA,IACd;AAAA,IACA,CAAC,aAAa,WAAW,OAAO;AAAA,EAClC;AAEA,QAAM,uBAAuBA,OAAM,YAAY,MAAM;AACnD,QAAI,gBAAgB,YAAY,MAAM;AACpC,kBAAY;AACZ,mBAAa;AAAA,IACf;AAAA,EACF,GAAG,CAAC,aAAa,cAAc,eAAe,CAAC;AAE/C,SAAOA,OAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,cAAc,aAAa,mBAAmB,WAAW,gBAAgB,oBAAoB;AAAA,EAChG;AACF;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -8,7 +8,7 @@ const useKeyboard = ({
|
|
|
8
8
|
loadMoreRef,
|
|
9
9
|
scrollAndFocus,
|
|
10
10
|
onlyFocus,
|
|
11
|
-
|
|
11
|
+
getMessagesInView
|
|
12
12
|
}) => {
|
|
13
13
|
const handleKey = React2.useCallback(
|
|
14
14
|
(e) => {
|
|
@@ -69,7 +69,7 @@ const useKeyboard = ({
|
|
|
69
69
|
case "ArrowUp":
|
|
70
70
|
e.preventDefault();
|
|
71
71
|
if (document.activeElement !== loadMoreRef.current) {
|
|
72
|
-
const id =
|
|
72
|
+
const id = getMessagesInView()?.shift();
|
|
73
73
|
if (id) onlyFocus(id);
|
|
74
74
|
}
|
|
75
75
|
break;
|
|
@@ -78,7 +78,7 @@ const useKeyboard = ({
|
|
|
78
78
|
if (document.activeElement === loadMoreRef.current) {
|
|
79
79
|
virtualListRef.current?.querySelector(`[data-index="0"]`)?.focus();
|
|
80
80
|
} else {
|
|
81
|
-
const id =
|
|
81
|
+
const id = getMessagesInView()?.pop();
|
|
82
82
|
if (id) onlyFocus(id);
|
|
83
83
|
}
|
|
84
84
|
break;
|
|
@@ -111,7 +111,16 @@ const useKeyboard = ({
|
|
|
111
111
|
break;
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
|
-
[
|
|
114
|
+
[
|
|
115
|
+
actionRef,
|
|
116
|
+
hasMoreItems,
|
|
117
|
+
loadMoreRef,
|
|
118
|
+
messages.length,
|
|
119
|
+
getMessagesInView,
|
|
120
|
+
onlyFocus,
|
|
121
|
+
scrollAndFocus,
|
|
122
|
+
virtualListRef
|
|
123
|
+
]
|
|
115
124
|
);
|
|
116
125
|
return React2.useMemo(() => ({ handleKey, handleListKey }), [handleKey, handleListKey]);
|
|
117
126
|
};
|
|
@@ -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
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACGvB,OAAOA,YAAW;
|
|
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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",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -5,9 +5,10 @@ type UseActionRefArgs = {
|
|
|
5
5
|
actionRef: DSChatT.ActionRef;
|
|
6
6
|
useVirtualHelpers: ReturnType<typeof useVirtual>;
|
|
7
7
|
virtualListRef: React.MutableRefObject<HTMLDivElement | undefined>;
|
|
8
|
-
|
|
8
|
+
updateCache: () => void;
|
|
9
|
+
getMessagesInView: () => string[];
|
|
9
10
|
onlyFocus: (index: string) => void;
|
|
10
11
|
scrollAndFocus: (index: number, opts?: DSChatT.ScrollToIndexOptions) => void;
|
|
11
12
|
};
|
|
12
|
-
export declare const useActionRef: ({ actionRef, useVirtualHelpers: { scrollToIndex: vScroll }, virtualListRef,
|
|
13
|
+
export declare const useActionRef: ({ actionRef, useVirtualHelpers: { scrollToIndex: vScroll }, virtualListRef, updateCache, getMessagesInView, onlyFocus, scrollAndFocus, }: UseActionRefArgs) => void;
|
|
13
14
|
export {};
|
|
@@ -9,6 +9,8 @@ type UseFocusAndScrollHelpersArgs = {
|
|
|
9
9
|
};
|
|
10
10
|
export declare const useFocusAndScrollHelpers: ({ propsWithDefault: { onScrollEnds }, useVirtualHelpers: { scrollToIndex: vScroll }, pendingOnScroll, virtualListRef, }: UseFocusAndScrollHelpersArgs) => {
|
|
11
11
|
onScrollStop: () => string[];
|
|
12
|
+
updateCache: import("lodash").DebouncedFuncLeading<() => void>;
|
|
13
|
+
getMessagesInView: () => string[];
|
|
12
14
|
onlyFocus: (index: string) => void;
|
|
13
15
|
scrollAndFocus: (index: number) => void;
|
|
14
16
|
checkPendingOnScroll: () => void;
|
|
@@ -7,9 +7,9 @@ type UseKeyboardArgs = {
|
|
|
7
7
|
loadMoreRef: React.MutableRefObject<HTMLButtonElement | undefined>;
|
|
8
8
|
scrollAndFocus: (index: number, opts?: DSChatT.ScrollToIndexOptions) => void;
|
|
9
9
|
onlyFocus: (index: string) => void;
|
|
10
|
-
|
|
10
|
+
getMessagesInView: () => string[];
|
|
11
11
|
};
|
|
12
|
-
export declare const useKeyboard: ({ propsWithDefault: { hasMoreItems, messages, bannerPosition, bannerRef }, actionRef, virtualListRef, loadMoreRef, scrollAndFocus, onlyFocus,
|
|
12
|
+
export declare const useKeyboard: ({ propsWithDefault: { hasMoreItems, messages, bannerPosition, bannerRef }, actionRef, virtualListRef, loadMoreRef, scrollAndFocus, onlyFocus, getMessagesInView, }: UseKeyboardArgs) => {
|
|
13
13
|
handleKey: (e: React.KeyboardEvent<HTMLElement>) => void;
|
|
14
14
|
handleListKey: (e: React.KeyboardEvent) => void;
|
|
15
15
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-chat-container",
|
|
3
|
-
"version": "3.70.0-next.
|
|
3
|
+
"version": "3.70.0-next.43",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - Chat Container",
|
|
6
6
|
"files": [
|
|
@@ -37,25 +37,26 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"react-virtual": "~2.10.4",
|
|
40
|
-
"@elliemae/ds-banner": "3.70.0-next.
|
|
41
|
-
"@elliemae/ds-
|
|
42
|
-
"@elliemae/ds-
|
|
43
|
-
"@elliemae/ds-chat-
|
|
44
|
-
"@elliemae/ds-chat-
|
|
45
|
-
"@elliemae/ds-
|
|
46
|
-
"@elliemae/ds-
|
|
47
|
-
"@elliemae/ds-
|
|
48
|
-
"@elliemae/ds-
|
|
49
|
-
"@elliemae/ds-
|
|
50
|
-
"@elliemae/ds-system": "3.70.0-next.
|
|
51
|
-
"@elliemae/ds-
|
|
40
|
+
"@elliemae/ds-banner": "3.70.0-next.43",
|
|
41
|
+
"@elliemae/ds-button-v2": "3.70.0-next.43",
|
|
42
|
+
"@elliemae/ds-chat-bubble": "3.70.0-next.43",
|
|
43
|
+
"@elliemae/ds-chat-container-header": "3.70.0-next.43",
|
|
44
|
+
"@elliemae/ds-chat-message-delimeter": "3.70.0-next.43",
|
|
45
|
+
"@elliemae/ds-chat-system-message": "3.70.0-next.43",
|
|
46
|
+
"@elliemae/ds-grid": "3.70.0-next.43",
|
|
47
|
+
"@elliemae/ds-indeterminate-progress-indicator": "3.70.0-next.43",
|
|
48
|
+
"@elliemae/ds-icons": "3.70.0-next.43",
|
|
49
|
+
"@elliemae/ds-props-helpers": "3.70.0-next.43",
|
|
50
|
+
"@elliemae/ds-system": "3.70.0-next.43",
|
|
51
|
+
"@elliemae/ds-typescript-helpers": "3.70.0-next.43"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"@playwright/experimental-ct-react": "^1.60.0",
|
|
54
55
|
"@types/react": "^18.0.0",
|
|
55
56
|
"jest": "^30.0.0",
|
|
56
57
|
"styled-components": "~5.3.9",
|
|
57
|
-
"@elliemae/ds-monorepo-devops": "3.70.0-next.
|
|
58
|
-
"@elliemae/ds-test-utils": "3.70.0-next.
|
|
58
|
+
"@elliemae/ds-monorepo-devops": "3.70.0-next.43",
|
|
59
|
+
"@elliemae/ds-test-utils": "3.70.0-next.43"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
61
62
|
"lodash-es": "^4.18.1",
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
"styled-components": "~5.3.9"
|
|
65
66
|
},
|
|
66
67
|
"scripts": {
|
|
67
|
-
"test": "ds-monorepo-devops test --passWithNoTests --coverage=\"false\"",
|
|
68
|
+
"test": "playwright test -c ./playwright.config.mjs && ds-monorepo-devops test --passWithNoTests --coverage=\"false\"",
|
|
68
69
|
"lint": "node ../../../scripts/lint.mjs --fix",
|
|
69
70
|
"lint:strict": "node ../../../scripts/lint-strict.mjs",
|
|
70
71
|
"dts": "node ../../../scripts/dts.mjs",
|