diff --git a/.changeset/gentle-eyes-sell.md b/.changeset/gentle-eyes-sell.md new file mode 100644 index 0000000000..fd8bbaa760 --- /dev/null +++ b/.changeset/gentle-eyes-sell.md @@ -0,0 +1,6 @@ +--- +'react-select': patch +'storybook': patch +--- + +Introduces a new optional prop allowEmptySearch to the Async Select component. diff --git a/packages/react-select/src/useAsync.ts b/packages/react-select/src/useAsync.ts index 334f66d7f2..19d20a8543 100644 --- a/packages/react-select/src/useAsync.ts +++ b/packages/react-select/src/useAsync.ts @@ -33,6 +33,12 @@ export interface AsyncAdditionalProps> { * Async select is not currently waiting for loadOptions to resolve */ isLoading?: boolean; + /** + * When set to `true`, the `loadOptions` function will be called even when the input is empty (`''`). + * This allows consumers to handle empty input searches (e.g., return a default set of results). + * If `false` (default), the input will reset without triggering `loadOptions('')`. + */ + allowEmptySearch?: boolean; } export type AsyncProps< @@ -55,6 +61,7 @@ export default function useAsync< isLoading: propsIsLoading = false, onInputChange: propsOnInputChange, filterOption = null, + allowEmptySearch, ...restSelectProps }: AsyncProps & AdditionalProps): StateManagerProps< Option, @@ -143,7 +150,7 @@ export default function useAsync< actionMeta, propsOnInputChange ); - if (!inputValue) { + if (!inputValue && !allowEmptySearch) { lastRequest.current = undefined; setStateInputValue(''); setLoadedInputValue(''); @@ -183,6 +190,7 @@ export default function useAsync< loadedInputValue, optionsCache, propsOnInputChange, + allowEmptySearch, ] ); diff --git a/storybook/stories/AsyncPromisesWithAllowEmptySearch.stories.tsx b/storybook/stories/AsyncPromisesWithAllowEmptySearch.stories.tsx new file mode 100644 index 0000000000..570e06891e --- /dev/null +++ b/storybook/stories/AsyncPromisesWithAllowEmptySearch.stories.tsx @@ -0,0 +1,44 @@ +import type { ComponentMeta } from '@storybook/react'; +import * as React from 'react'; +import AsyncSelect from 'react-select/async'; + +import { Field } from '../components'; +import { ColourOption, colourOptions } from '../data'; + +export default { + title: 'Select/AsyncPromises', + component: AsyncSelect, + argTypes: {}, +} as ComponentMeta; + +export function AsyncPromises() { + return ( + + + + ); +} + +// ============================================================================= +// Utils +// ============================================================================= + +function filterColors(inputValue: string) { + return colourOptions.filter((i) => + i.label.toLowerCase().includes(inputValue.toLowerCase()) + ); +} + +function promiseOptions(inputValue: string) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(filterColors(inputValue)); + }, 1000); + }); +}