Skip to content

Commit

Permalink
feat(Select): add onLoadMore prop (#901)
Browse files Browse the repository at this point in the history
Co-authored-by: Yevhenii Chernovol <echernovol@yandex-team.ru>
  • Loading branch information
imechoim and imechoim authored Aug 16, 2023
1 parent a254e1b commit e191c0b
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/components/Select/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
| onFocus | `function` | `-` | Handler that is called when the element receives focus. |
| onBlur | `function` | `-` | Handler that is called when the element loses focus. |
| loading | `boolean` | `-` | Add the loading item to the end of the options list. Works like persistant loading indicator while the options list is empty. |
| onLoadMore | `function` | `-` | Fires when loading indicator gets visible. |

---

Expand Down
1 change: 1 addition & 0 deletions src/components/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ export const Select = React.forwardRef<HTMLButtonElement, SelectProps>(function
getOptionHeight={getOptionHeight}
getOptionGroupHeight={getOptionGroupHeight}
loading={props.loading}
onLoadMore={props.onLoadMore}
/>
) : (
<EmptyOptions filter={filter} renderEmptyOptions={renderEmptyOptions} />
Expand Down
8 changes: 7 additions & 1 deletion src/components/Select/components/SelectList/SelectList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type SelectListProps = {
multiple?: boolean;
virtualized?: boolean;
loading?: boolean;
onLoadMore?: () => void;
};

const loadingOption = {value: '__SELECT_LIST_ITEM_LOADING__', disabled: true};
Expand All @@ -43,6 +44,7 @@ export const SelectList = React.forwardRef<List<FlattenOption>, SelectListProps>
virtualized,
mobile,
loading,
onLoadMore,
} = props;
const items = React.useMemo(
() => (loading ? [...flattenOptions, loadingOption] : flattenOptions),
Expand Down Expand Up @@ -85,7 +87,11 @@ export const SelectList = React.forwardRef<List<FlattenOption>, SelectListProps>
return <GroupLabel option={option} renderOptionGroup={wrappedRenderOptionGroup} />;
}
if (option.value === loadingOption.value) {
return <SelectLoadingIndicator />;
return (
<SelectLoadingIndicator
onIntersect={itemIndex === 0 ? undefined : onLoadMore}
/>
);
}

const wrappedRenderOption = renderOption
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React from 'react';

import {Loader} from '../../../Loader/Loader';
import {useIntersection} from '../../../utils/useIntersection';
import {selectListBlock} from '../../constants';

export const SelectLoadingIndicator = () => {
export const SelectLoadingIndicator = (props: {onIntersect?: () => void}) => {
const ref = React.useRef<HTMLDivElement | null>(null);

useIntersection({element: ref.current, onIntersect: props?.onIntersect});

return (
<div className={selectListBlock('loading-indicator')}>
<div ref={ref} className={selectListBlock('loading-indicator')}>
<Loader />
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/components/Select/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export type SelectProps<T = any> = QAProps &
onFocus?: (e: React.FocusEvent) => void;
onBlur?: (e: React.FocusEvent) => void;
loading?: boolean;
onLoadMore?: () => void;
children?:
| React.ReactElement<SelectOption<T>, typeof Option>
| React.ReactElement<SelectOption<T>, typeof Option>[]
Expand Down
23 changes: 23 additions & 0 deletions src/components/utils/useIntersection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';

export type UseIntersection = {
element: Element | null;
options?: IntersectionObserverInit;
onIntersect?: () => void;
};

export const useIntersection = ({element, options, onIntersect}: UseIntersection) => {
React.useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
onIntersect?.();
}
}, options);

if (element) {
observer.observe(element);
}

return () => (element === null ? undefined : observer.unobserve(element));
}, [element, options, onIntersect]);
};

0 comments on commit e191c0b

Please sign in to comment.