diff --git a/src/components/Select/index.test.tsx b/src/components/Select/index.test.tsx index d806702b..c7a1b71a 100644 --- a/src/components/Select/index.test.tsx +++ b/src/components/Select/index.test.tsx @@ -137,6 +137,25 @@ describe("Select Single test suite:", () => { expect(onChangeCallback).toHaveBeenCalledWith(["Sculpture"]); }); + it("onScroll", () => { + const onScrollEndCallback = jest.fn(); + const outerWrapperDataCy = getComposedDataCy(DATA_CY_DEFAULT, SUBPARTS_MAP.outerWrapper); + const { wrapper } = getSelectTestable({ + dataCy: outerWrapperDataCy, + domNode: "div", + mountOnly: true, + props: { onScrollEnd: onScrollEndCallback }, + }); + + const input = wrapper.find(`input[data-cy='${DATA_CY_DEFAULT}']`); + input.simulate("mousedown"); + + const listbox = wrapper.find("ul.MuiAutocomplete-listbox"); + listbox.simulate("scroll", { clientHeight: 100, scrollHeight: 100, scrollTop: 0 }); + + expect(onScrollEndCallback).toHaveBeenCalledTimes(1); + }); + it("options - default", () => { const outerWrapperDataCy = getComposedDataCy(DATA_CY_DEFAULT, SUBPARTS_MAP.outerWrapper); const { wrapper } = getSelectTestable({ diff --git a/src/components/Select/index.tsx b/src/components/Select/index.tsx index 861f080e..4a69f102 100644 --- a/src/components/Select/index.tsx +++ b/src/components/Select/index.tsx @@ -1,4 +1,4 @@ -import React, { CSSProperties, Fragment, useCallback, useMemo } from "react"; +import React, { CSSProperties, Fragment, SyntheticEvent, useCallback, useMemo } from "react"; import { ListSubheader as MUIListSubheader, Popper as MUIPopper, @@ -57,6 +57,7 @@ const Select = ({ loading = false, multiple = false, onChange: externalOnChange, + onScrollEnd, options: externalOptions, placeholder, popperWidth, @@ -93,6 +94,21 @@ const Select = ({ [externalOnChange] ); + const onScroll = useCallback( + ({ currentTarget: listboxNode }: SyntheticEvent) => { + if (!listboxNode || !onScrollEnd) { + return; + } + + const { clientHeight, scrollHeight, scrollTop } = listboxNode; + const scrollEnded = clientHeight + scrollTop === scrollHeight; + if (scrollEnded) { + onScrollEnd(); + } + }, + [onScrollEnd] + ); + const options = useMemo(() => { let options = [...externalOptions]; if (!autoSort && !groupBy) { @@ -145,7 +161,13 @@ const Select = ({ getOptionLabel={getOptionLabel} getOptionSelected={isOptionSelected} groupBy={groupBy} - ListboxProps={{ style: { padding: 0, width: "100%" } }} + ListboxProps={{ + onScroll, + style: { + padding: 0, + width: "100%", + }, + }} loading={loading} multiple={multiple} onChange={onChange} diff --git a/src/types/Select.ts b/src/types/Select.ts index 42923e9e..71f7d690 100644 --- a/src/types/Select.ts +++ b/src/types/Select.ts @@ -11,6 +11,7 @@ interface IBaseSelect extends ILocalizable, ILoadable, IInput { getOptionLabel?: (option: T) => string; getOptionSelected?: (option: T, value: T) => boolean; groupBy?: (option: T) => string; + onScrollEnd?: () => void; options: T[]; popperWidth?: number; }