📅 You're Invited: Meet the Socket team at RSAC (April 28 – May 1).RSVP

react-select-async-paginate

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-select-async-paginate - npm Package Compare versions

Comparing version

to
0.7.10

// src/index.ts
import Select from "react-select";
// src/components/useComponents.ts
import { useMemo as useMemo2 } from "react";
import { components as defaultComponents } from "react-select";
// src/components/wrapMenuList.tsx
import composeRefs from "@seznam/compose-react-refs";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { jsx } from "react/jsx-runtime";
var CHECK_TIMEOUT = 300;
function wrapMenuList(MenuList2) {
function WrappedMenuList(props) {
const { selectProps, innerRef } = props;
const { handleScrolledToBottom, shouldLoadMore } = selectProps;
const checkTimeoutRef = useRef(null);
const menuListRef = useRef(null);
const shouldHandle = useCallback(() => {
const el = menuListRef.current;
if (!el) {
return false;
}
const { scrollTop, scrollHeight, clientHeight } = el;
return shouldLoadMore(scrollHeight, clientHeight, scrollTop);
}, [shouldLoadMore]);
const checkAndHandle = useCallback(() => {
if (shouldHandle()) {
if (handleScrolledToBottom) {
handleScrolledToBottom();
}
}
}, [shouldHandle, handleScrolledToBottom]);
const setCheckAndHandleTimeout = useMemo(() => {
const res = () => {
checkAndHandle();
checkTimeoutRef.current = setTimeout(
res,
CHECK_TIMEOUT
);
};
return res;
}, [checkAndHandle]);
useEffect(() => {
setCheckAndHandleTimeout();
return () => {
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current);
}
};
}, []);
return /* @__PURE__ */ jsx(
MenuList2,
{
...props,
innerRef: composeRefs(innerRef, menuListRef)
}
);
}
return WrappedMenuList;
}
// src/components/useComponents.ts
var MenuList = wrapMenuList(
// biome-ignore lint/suspicious/noExplicitAny: fix types
defaultComponents.MenuList
);
var useComponents = (components) => useMemo2(
() => ({
MenuList,
...components
}),
[components]
);
// src/useAsyncPaginate.ts
import { useCallback as useCallback2, useState as useState2 } from "react";
import { useCallback as useCallback3, useState as useState2 } from "react";
// src/useAsyncPaginateBase.ts
import { useLazyRef } from "@vtaits/use-lazy-ref";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState } from "react";
import useIsMountedRef from "use-is-mounted-ref";

@@ -84,3 +156,3 @@ import useLatest from "use-latest";

// src/requestOptions.ts
var requestOptions = async (caller, paramsRef, optionsCacheRef, debounceTimeout, setOptionsCache, reduceOptions, isMountedRef) => {
var requestOptions = async (caller, paramsRef, optionsCacheRef, debounceTimeout, setOptionsCache, reduceOptions, isMountedRef, clearCacheOnSearchChange) => {
const currentInputValue = paramsRef.current.inputValue;

@@ -93,9 +165,19 @@ const isCacheEmpty = !optionsCacheRef.current[currentInputValue];

setOptionsCache(
(prevOptionsCache) => ({
...prevOptionsCache,
[currentInputValue]: {
...currentOptions,
isLoading: true
(prevOptionsCache) => {
if (clearCacheOnSearchChange && caller === "input-change") {
return {
[currentInputValue]: {
...currentOptions,
isLoading: true
}
};
}
})
return {
...prevOptionsCache,
[currentInputValue]: {
...currentOptions,
isLoading: true
}
};
}
);

@@ -168,2 +250,4 @@ if (debounceTimeout > 0 && caller === "input-change") {

const {
clearCacheOnSearchChange = false,
clearCacheOnMenuClose = false,
defaultOptions,

@@ -183,4 +267,4 @@ loadOptionsOnMenuOpen = true,

const loadOptionsOnMenuOpenRef = useLatest(loadOptionsOnMenuOpen);
const isInitRef = useRef(true);
const paramsRef = useRef(params);
const isInitRef = useRef2(true);
const paramsRef = useRef2(params);
paramsRef.current = params;

@@ -203,7 +287,8 @@ const [_stateId, setStateId] = useState(0);

reduceOptionsRef.current,
isMountedRef
isMountedRef,
clearCacheOnSearchChange
);
}
);
const handleScrolledToBottom = useCallback(() => {
const handleScrolledToBottom = useCallback2(() => {
const currentInputValue = paramsRef.current.inputValue;

@@ -215,3 +300,3 @@ const currentOptions2 = optionsCacheRef.current[currentInputValue];

}, [callRequestOptionsRef, optionsCacheRef]);
useEffect(() => {
useEffect2(() => {
if (isInitRef.current) {

@@ -227,3 +312,3 @@ isInitRef.current = false;

}, deps);
useEffect(() => {
useEffect2(() => {
if (menuIsOpenRef.current && !optionsCacheRef.current[inputValue]) {

@@ -233,6 +318,14 @@ callRequestOptionsRef.current("input-change");

}, [callRequestOptionsRef, inputValue, menuIsOpenRef, optionsCacheRef]);
useEffect(() => {
if (menuIsOpen && !optionsCacheRef.current[""] && loadOptionsOnMenuOpenRef.current) {
callRequestOptionsRef.current("menu-toggle");
useEffect2(() => {
if (menuIsOpen) {
if (!optionsCacheRef.current[""] && loadOptionsOnMenuOpenRef.current) {
callRequestOptionsRef.current("menu-toggle");
return;
}
return;
}
if (clearCacheOnMenuClose) {
optionsCacheRef.current = {};
setStateId(increaseStateId);
}
}, [

@@ -242,6 +335,7 @@ callRequestOptionsRef,

menuIsOpen,
optionsCacheRef
optionsCacheRef,
clearCacheOnMenuClose
]);
const currentOptions = optionsCacheRef.current[inputValue] || getInitialCache(params);
const options = useMemo(() => {
const options = useMemo3(() => {
if (!mapOptionsForMenu) {

@@ -279,3 +373,3 @@ return currentOptions.options;

const menuIsOpen = typeof menuIsOpenParam === "boolean" ? menuIsOpenParam : menuIsOpenState;
const onInputChange = useCallback2(
const onInputChange = useCallback3(
(nextInputValue, actionMeta) => {

@@ -289,3 +383,3 @@ if (onInputChangeParam) {

);
const onMenuClose = useCallback2(() => {
const onMenuClose = useCallback3(() => {
if (onMenuCloseParam) {

@@ -296,3 +390,3 @@ onMenuCloseParam();

}, [onMenuCloseParam]);
const onMenuOpen = useCallback2(() => {
const onMenuOpen = useCallback3(() => {
if (onMenuOpenParam) {

@@ -321,71 +415,2 @@ onMenuOpenParam();

// src/useComponents.ts
import { useMemo as useMemo3 } from "react";
import { components as defaultComponents } from "react-select";
// src/wrapMenuList.tsx
import composeRefs from "@seznam/compose-react-refs";
import { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
import { jsx } from "react/jsx-runtime";
var CHECK_TIMEOUT = 300;
function wrapMenuList(MenuList2) {
function WrappedMenuList(props) {
const { selectProps, innerRef } = props;
const { handleScrolledToBottom, shouldLoadMore } = selectProps;
const checkTimeoutRef = useRef2(null);
const menuListRef = useRef2(null);
const shouldHandle = useCallback3(() => {
const el = menuListRef.current;
if (!el) {
return false;
}
const { scrollTop, scrollHeight, clientHeight } = el;
return shouldLoadMore(scrollHeight, clientHeight, scrollTop);
}, [shouldLoadMore]);
const checkAndHandle = useCallback3(() => {
if (shouldHandle()) {
if (handleScrolledToBottom) {
handleScrolledToBottom();
}
}
}, [shouldHandle, handleScrolledToBottom]);
const setCheckAndHandleTimeout = useMemo2(() => {
const res = () => {
checkAndHandle();
checkTimeoutRef.current = setTimeout(res, CHECK_TIMEOUT);
};
return res;
}, [checkAndHandle]);
useEffect2(() => {
setCheckAndHandleTimeout();
return () => {
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current);
}
};
}, []);
return /* @__PURE__ */ jsx(
MenuList2,
{
...props,
innerRef: composeRefs(innerRef, menuListRef)
}
);
}
return WrappedMenuList;
}
// src/useComponents.ts
var MenuList = wrapMenuList(
// biome-ignore lint/suspicious/noExplicitAny: fix types
defaultComponents.MenuList
);
var useComponents = (components) => useMemo3(
() => ({
MenuList,
...components
}),
[components]
);
// src/withAsyncPaginate.tsx

@@ -402,2 +427,4 @@ import { jsx as jsx2 } from "react/jsx-runtime";

cacheUniqs = defaultCacheUniqs,
menuPlacement,
menuShouldScrollIntoView,
...rest

@@ -415,2 +442,4 @@ } = props;

...asyncPaginateProps,
menuPlacement,
menuShouldScrollIntoView: menuPlacement === "auto" ? isLoading ? false : menuShouldScrollIntoView : menuShouldScrollIntoView,
isLoading,

@@ -417,0 +446,0 @@ components: processedComponents,

import { Ref, ReactElement, ComponentType } from 'react';
import { GroupBase, OptionsOrGroups, InputActionMeta, SelectInstance, Props, MenuListProps, SelectComponentsConfig } from 'react-select';
import { GroupBase, Props, OptionsOrGroups, InputActionMeta, SelectInstance, MenuListProps, SelectComponentsConfig } from 'react-select';
import { FilterOptionOption } from 'react-select/dist/declarations/src/filters';

@@ -42,2 +42,10 @@

type UseAsyncPaginateParams<OptionType, Group extends GroupBase<OptionType>, Additional> = {
/**
* Clear all cached options on search change
*/
clearCacheOnSearchChange?: boolean;
/**
* Clear all cached options on menu close
*/
clearCacheOnMenuClose?: boolean;
loadOptions: LoadOptions<OptionType, Group, Additional>;

@@ -44,0 +52,0 @@ options?: OptionsOrGroups<OptionType, Group>;

@@ -46,8 +46,80 @@ "use strict";

// src/useAsyncPaginate.ts
// src/components/useComponents.ts
var import_react2 = require("react");
var import_react_select = require("react-select");
// src/components/wrapMenuList.tsx
var import_compose_react_refs = __toESM(require("@seznam/compose-react-refs"));
var import_react = require("react");
var import_jsx_runtime = require("react/jsx-runtime");
var CHECK_TIMEOUT = 300;
function wrapMenuList(MenuList2) {
function WrappedMenuList(props) {
const { selectProps, innerRef } = props;
const { handleScrolledToBottom, shouldLoadMore } = selectProps;
const checkTimeoutRef = (0, import_react.useRef)(null);
const menuListRef = (0, import_react.useRef)(null);
const shouldHandle = (0, import_react.useCallback)(() => {
const el = menuListRef.current;
if (!el) {
return false;
}
const { scrollTop, scrollHeight, clientHeight } = el;
return shouldLoadMore(scrollHeight, clientHeight, scrollTop);
}, [shouldLoadMore]);
const checkAndHandle = (0, import_react.useCallback)(() => {
if (shouldHandle()) {
if (handleScrolledToBottom) {
handleScrolledToBottom();
}
}
}, [shouldHandle, handleScrolledToBottom]);
const setCheckAndHandleTimeout = (0, import_react.useMemo)(() => {
const res = () => {
checkAndHandle();
checkTimeoutRef.current = setTimeout(
res,
CHECK_TIMEOUT
);
};
return res;
}, [checkAndHandle]);
(0, import_react.useEffect)(() => {
setCheckAndHandleTimeout();
return () => {
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current);
}
};
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuList2,
{
...props,
innerRef: (0, import_compose_react_refs.default)(innerRef, menuListRef)
}
);
}
return WrappedMenuList;
}
// src/components/useComponents.ts
var MenuList = wrapMenuList(
// biome-ignore lint/suspicious/noExplicitAny: fix types
import_react_select.components.MenuList
);
var useComponents = (components) => (0, import_react2.useMemo)(
() => ({
MenuList,
...components
}),
[components]
);
// src/useAsyncPaginate.ts
var import_react4 = require("react");
// src/useAsyncPaginateBase.ts
var import_use_lazy_ref = require("@vtaits/use-lazy-ref");
var import_react = require("react");
var import_react3 = require("react");
var import_use_is_mounted_ref = __toESM(require("use-is-mounted-ref"));

@@ -127,3 +199,3 @@ var import_use_latest = __toESM(require("use-latest"));

// src/requestOptions.ts
var requestOptions = async (caller, paramsRef, optionsCacheRef, debounceTimeout, setOptionsCache, reduceOptions, isMountedRef) => {
var requestOptions = async (caller, paramsRef, optionsCacheRef, debounceTimeout, setOptionsCache, reduceOptions, isMountedRef, clearCacheOnSearchChange) => {
const currentInputValue = paramsRef.current.inputValue;

@@ -136,9 +208,19 @@ const isCacheEmpty = !optionsCacheRef.current[currentInputValue];

setOptionsCache(
(prevOptionsCache) => ({
...prevOptionsCache,
[currentInputValue]: {
...currentOptions,
isLoading: true
(prevOptionsCache) => {
if (clearCacheOnSearchChange && caller === "input-change") {
return {
[currentInputValue]: {
...currentOptions,
isLoading: true
}
};
}
})
return {
...prevOptionsCache,
[currentInputValue]: {
...currentOptions,
isLoading: true
}
};
}
);

@@ -211,2 +293,4 @@ if (debounceTimeout > 0 && caller === "input-change") {

const {
clearCacheOnSearchChange = false,
clearCacheOnMenuClose = false,
defaultOptions,

@@ -226,6 +310,6 @@ loadOptionsOnMenuOpen = true,

const loadOptionsOnMenuOpenRef = (0, import_use_latest.default)(loadOptionsOnMenuOpen);
const isInitRef = (0, import_react.useRef)(true);
const paramsRef = (0, import_react.useRef)(params);
const isInitRef = (0, import_react3.useRef)(true);
const paramsRef = (0, import_react3.useRef)(params);
paramsRef.current = params;
const [_stateId, setStateId] = (0, import_react.useState)(0);
const [_stateId, setStateId] = (0, import_react3.useState)(0);
const optionsCacheRef = (0, import_use_lazy_ref.useLazyRef)(() => getInitialOptionsCache(params));

@@ -246,7 +330,8 @@ const callRequestOptionsRef = (0, import_use_latest.default)(

reduceOptionsRef.current,
isMountedRef
isMountedRef,
clearCacheOnSearchChange
);
}
);
const handleScrolledToBottom = (0, import_react.useCallback)(() => {
const handleScrolledToBottom = (0, import_react3.useCallback)(() => {
const currentInputValue = paramsRef.current.inputValue;

@@ -258,3 +343,3 @@ const currentOptions2 = optionsCacheRef.current[currentInputValue];

}, [callRequestOptionsRef, optionsCacheRef]);
(0, import_react.useEffect)(() => {
(0, import_react3.useEffect)(() => {
if (isInitRef.current) {

@@ -270,3 +355,3 @@ isInitRef.current = false;

}, deps);
(0, import_react.useEffect)(() => {
(0, import_react3.useEffect)(() => {
if (menuIsOpenRef.current && !optionsCacheRef.current[inputValue]) {

@@ -276,6 +361,14 @@ callRequestOptionsRef.current("input-change");

}, [callRequestOptionsRef, inputValue, menuIsOpenRef, optionsCacheRef]);
(0, import_react.useEffect)(() => {
if (menuIsOpen && !optionsCacheRef.current[""] && loadOptionsOnMenuOpenRef.current) {
callRequestOptionsRef.current("menu-toggle");
(0, import_react3.useEffect)(() => {
if (menuIsOpen) {
if (!optionsCacheRef.current[""] && loadOptionsOnMenuOpenRef.current) {
callRequestOptionsRef.current("menu-toggle");
return;
}
return;
}
if (clearCacheOnMenuClose) {
optionsCacheRef.current = {};
setStateId(increaseStateId);
}
}, [

@@ -285,6 +378,7 @@ callRequestOptionsRef,

menuIsOpen,
optionsCacheRef
optionsCacheRef,
clearCacheOnMenuClose
]);
const currentOptions = optionsCacheRef.current[inputValue] || getInitialCache(params);
const options = (0, import_react.useMemo)(() => {
const options = (0, import_react3.useMemo)(() => {
if (!mapOptionsForMenu) {

@@ -316,9 +410,9 @@ return currentOptions.options;

} = params;
const [inputValueState, setInputValue] = (0, import_react2.useState)(
const [inputValueState, setInputValue] = (0, import_react4.useState)(
defaultInputValueParam || ""
);
const [menuIsOpenState, setMenuIsOpen] = (0, import_react2.useState)(!!defaultMenuIsOpenParam);
const [menuIsOpenState, setMenuIsOpen] = (0, import_react4.useState)(!!defaultMenuIsOpenParam);
const inputValue = typeof inputValueParam === "string" ? inputValueParam : inputValueState;
const menuIsOpen = typeof menuIsOpenParam === "boolean" ? menuIsOpenParam : menuIsOpenState;
const onInputChange = (0, import_react2.useCallback)(
const onInputChange = (0, import_react4.useCallback)(
(nextInputValue, actionMeta) => {

@@ -332,3 +426,3 @@ if (onInputChangeParam) {

);
const onMenuClose = (0, import_react2.useCallback)(() => {
const onMenuClose = (0, import_react4.useCallback)(() => {
if (onMenuCloseParam) {

@@ -339,3 +433,3 @@ onMenuCloseParam();

}, [onMenuCloseParam]);
const onMenuOpen = (0, import_react2.useCallback)(() => {
const onMenuOpen = (0, import_react4.useCallback)(() => {
if (onMenuOpenParam) {

@@ -364,71 +458,2 @@ onMenuOpenParam();

// src/useComponents.ts
var import_react4 = require("react");
var import_react_select = require("react-select");
// src/wrapMenuList.tsx
var import_compose_react_refs = __toESM(require("@seznam/compose-react-refs"));
var import_react3 = require("react");
var import_jsx_runtime = require("react/jsx-runtime");
var CHECK_TIMEOUT = 300;
function wrapMenuList(MenuList2) {
function WrappedMenuList(props) {
const { selectProps, innerRef } = props;
const { handleScrolledToBottom, shouldLoadMore } = selectProps;
const checkTimeoutRef = (0, import_react3.useRef)(null);
const menuListRef = (0, import_react3.useRef)(null);
const shouldHandle = (0, import_react3.useCallback)(() => {
const el = menuListRef.current;
if (!el) {
return false;
}
const { scrollTop, scrollHeight, clientHeight } = el;
return shouldLoadMore(scrollHeight, clientHeight, scrollTop);
}, [shouldLoadMore]);
const checkAndHandle = (0, import_react3.useCallback)(() => {
if (shouldHandle()) {
if (handleScrolledToBottom) {
handleScrolledToBottom();
}
}
}, [shouldHandle, handleScrolledToBottom]);
const setCheckAndHandleTimeout = (0, import_react3.useMemo)(() => {
const res = () => {
checkAndHandle();
checkTimeoutRef.current = setTimeout(res, CHECK_TIMEOUT);
};
return res;
}, [checkAndHandle]);
(0, import_react3.useEffect)(() => {
setCheckAndHandleTimeout();
return () => {
if (checkTimeoutRef.current) {
clearTimeout(checkTimeoutRef.current);
}
};
}, []);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
MenuList2,
{
...props,
innerRef: (0, import_compose_react_refs.default)(innerRef, menuListRef)
}
);
}
return WrappedMenuList;
}
// src/useComponents.ts
var MenuList = wrapMenuList(
// biome-ignore lint/suspicious/noExplicitAny: fix types
import_react_select.components.MenuList
);
var useComponents = (components) => (0, import_react4.useMemo)(
() => ({
MenuList,
...components
}),
[components]
);
// src/withAsyncPaginate.tsx

@@ -445,2 +470,4 @@ var import_jsx_runtime2 = require("react/jsx-runtime");

cacheUniqs = defaultCacheUniqs,
menuPlacement,
menuShouldScrollIntoView,
...rest

@@ -458,2 +485,4 @@ } = props;

...asyncPaginateProps,
menuPlacement,
menuShouldScrollIntoView: menuPlacement === "auto" ? isLoading ? false : menuShouldScrollIntoView : menuShouldScrollIntoView,
isLoading,

@@ -460,0 +489,0 @@ components: processedComponents,

{
"name": "react-select-async-paginate",
"version": "0.7.9",
"version": "0.7.10",
"description": "Wrapper above react-select that supports pagination on menu scroll",

@@ -30,6 +30,6 @@ "files": [

"build": "tsup src/index.ts --sourcemap --format esm,cjs --dts --legacy-output",
"lint": "biome check src",
"lint:fix": "biome check src --write --unsafe",
"format": "biome format src --write",
"prepare": "yarn build",
"lint": "biome check src __stories__",
"lint:fix": "biome check src __stories__ --write --unsafe",
"format": "biome format src __stories__ --write",
"prepare": "bun run build",
"test:ts": "tsc --noEmit",

@@ -46,3 +46,3 @@ "test:unit": "vitest run --coverage.enabled --coverage.all --coverage.include=src",

"@seznam/compose-react-refs": "^1.0.6",
"@vtaits/use-lazy-ref": "^0.1.3",
"@vtaits/use-lazy-ref": "^0.1.4",
"krustykrab": "^1.1.0",

@@ -55,13 +55,13 @@ "sleep-promise": "^9.1.0",

"@biomejs/biome": "^1.9.4",
"@storybook/react": "^8.4.7",
"@storybook/test": "^8.4.7",
"@types/node": "^22.10.2",
"@types/react": "^19.0.2",
"@vitest/coverage-v8": "^2.1.8",
"react": "^19.0.0",
"react-select": "^5.9.0",
"tsup": "^8.3.5",
"typescript": "5.6.2",
"vitest": "^2.1.8"
"@storybook/react": "^8.6.12",
"@storybook/test": "^8.6.12",
"@types/node": "^22.14.1",
"@types/react": "^19.1.2",
"@vitest/coverage-v8": "^3.1.1",
"react": "^19.1.0",
"react-select": "^5.10.1",
"tsup": "^8.4.0",
"typescript": "5.8.3",
"vitest": "^3.1.1"
}
}

@@ -48,2 +48,8 @@ [![NPM](https://img.shields.io/npm/v/react-select-async-paginate.svg)](https://www.npmjs.com/package/react-select-async-paginate)

or
```
bun add react-select react-select-async-paginate
```
## Usage

@@ -114,2 +120,10 @@

### clearCacheOnSearchChange
Not required. Boolean. Clear all cached options on search change
### clearCacheOnMenuClose
Not required. Boolean. Clear all cached options on menu close
### cacheUniqs

@@ -116,0 +130,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet