diff --git a/packages/components/src/combobox-control/index.tsx b/packages/components/src/combobox-control/index.tsx
index 28510c8653d02e..fe0b6aaad30b58 100644
--- a/packages/components/src/combobox-control/index.tsx
+++ b/packages/components/src/combobox-control/index.tsx
@@ -35,6 +35,7 @@ import type { TokenInputProps } from '../form-token-field/types';
import { useDeprecated36pxDefaultSizeProp } from '../utils/use-deprecated-props';
import { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';
import { maybeWarnDeprecated36pxSize } from '../utils/deprecated-36px-size';
+import Spinner from '../spinner';
const noop = () => {};
@@ -126,6 +127,7 @@ function ComboboxControl( props: ComboboxControlProps ) {
help,
allowReset = true,
className,
+ isLoading = false,
messages = {
selected: __( 'Item selected.' ),
},
@@ -362,6 +364,7 @@ function ComboboxControl( props: ComboboxControlProps ) {
onChange={ onInputChange }
/>
+ { isLoading && }
{ allowReset && (
) }
diff --git a/packages/components/src/combobox-control/types.ts b/packages/components/src/combobox-control/types.ts
index 470b38c35e2c8a..d01aa213554c86 100644
--- a/packages/components/src/combobox-control/types.ts
+++ b/packages/components/src/combobox-control/types.ts
@@ -86,4 +86,9 @@ export type ComboboxControlProps = Pick<
* If passed, the combobox input will show a placeholder string if no values are present.
*/
placeholder?: string;
+
+ /**
+ * When loading, combobox will show a spinner
+ */
+ isLoading?: boolean;
};
diff --git a/packages/components/src/form-token-field/index.tsx b/packages/components/src/form-token-field/index.tsx
index 987c75d769b727..95af52fa21ffd5 100644
--- a/packages/components/src/form-token-field/index.tsx
+++ b/packages/components/src/form-token-field/index.tsx
@@ -77,6 +77,7 @@ export function FormTokenField( props: FormTokenFieldProps ) {
__experimentalAutoSelectFirstMatch = false,
__nextHasNoMarginBottom = false,
tokenizeOnBlur = false,
+ isLoading = false,
} = useDeprecated36pxDefaultSizeProp< FormTokenFieldProps >( props );
if ( ! __nextHasNoMarginBottom ) {
@@ -743,6 +744,7 @@ export function FormTokenField( props: FormTokenFieldProps ) {
onHover={ onSuggestionHovered }
onSelect={ onSuggestionSelected }
__experimentalRenderItem={ __experimentalRenderItem }
+ isLoading={ isLoading }
/>
) }
diff --git a/packages/components/src/form-token-field/suggestions-list.tsx b/packages/components/src/form-token-field/suggestions-list.tsx
index 1339e0cc189e38..bd073026666d30 100644
--- a/packages/components/src/form-token-field/suggestions-list.tsx
+++ b/packages/components/src/form-token-field/suggestions-list.tsx
@@ -31,6 +31,7 @@ export function SuggestionsList<
suggestions = [],
displayTransform,
instanceId,
+ isLoading,
__experimentalRenderItem,
}: SuggestionsListProps< T > ) {
const listRef = useRefEffect< HTMLUListElement >(
@@ -157,7 +158,7 @@ export function SuggestionsList<
);
/* eslint-enable jsx-a11y/click-events-have-key-events */
} ) }
- { suggestions.length === 0 && (
+ { suggestions.length === 0 && ! isLoading && (
{ __( 'No items found' ) }
diff --git a/packages/components/src/form-token-field/types.ts b/packages/components/src/form-token-field/types.ts
index 051f00a6cdeb06..989a5611149a0e 100644
--- a/packages/components/src/form-token-field/types.ts
+++ b/packages/components/src/form-token-field/types.ts
@@ -190,6 +190,11 @@ export interface FormTokenFieldProps
* @default false
*/
tokenizeOnBlur?: boolean;
+
+ /**
+ * Is the component loading data?
+ */
+ isLoading?: boolean;
}
/**
@@ -207,6 +212,7 @@ export interface SuggestionsListProps<
displayTransform: ( value: T ) => string;
instanceId: string | number;
__experimentalRenderItem?: ( args: { item: T } ) => ReactNode;
+ isLoading?: boolean;
}
export interface TokenProps extends TokenItem {
diff --git a/packages/editor/src/components/post-author/combobox.js b/packages/editor/src/components/post-author/combobox.js
index 867eca7947976a..f95dd0db2dcbf6 100644
--- a/packages/editor/src/components/post-author/combobox.js
+++ b/packages/editor/src/components/post-author/combobox.js
@@ -17,7 +17,8 @@ export default function PostAuthorCombobox() {
const [ fieldValue, setFieldValue ] = useState();
const { editPost } = useDispatch( editorStore );
- const { authorId, authorOptions } = useAuthorsQuery( fieldValue );
+ const { authorId, authorOptions, isLoading } =
+ useAuthorsQuery( fieldValue );
/**
* Handle author selection.
@@ -44,13 +45,14 @@ export default function PostAuthorCombobox() {
);
}
diff --git a/packages/editor/src/components/post-author/hook.js b/packages/editor/src/components/post-author/hook.js
index f251eba79e1806..28c4c126547b82 100644
--- a/packages/editor/src/components/post-author/hook.js
+++ b/packages/editor/src/components/post-author/hook.js
@@ -14,9 +14,9 @@ import { store as editorStore } from '../../store';
import { AUTHORS_QUERY, BASE_QUERY } from './constants';
export function useAuthorsQuery( search ) {
- const { authorId, authors, postAuthor } = useSelect(
+ const { authorId, authors, postAuthor, isLoading } = useSelect(
( select ) => {
- const { getUser, getUsers } = select( coreStore );
+ const { getUser, getUsers, isResolving } = select( coreStore );
const { getEditedPostAttribute } = select( editorStore );
const _authorId = getEditedPostAttribute( 'author' );
const query = { ...AUTHORS_QUERY };
@@ -30,6 +30,7 @@ export function useAuthorsQuery( search ) {
authorId: _authorId,
authors: getUsers( query ),
postAuthor: getUser( _authorId, BASE_QUERY ),
+ isLoading: isResolving( 'getUsers', [ query ] ),
};
},
[ search ]
@@ -68,5 +69,5 @@ export function useAuthorsQuery( search ) {
return [ ...currentAuthor, ...fetchedAuthors ];
}, [ authors, postAuthor ] );
- return { authorId, authorOptions, postAuthor };
+ return { authorId, authorOptions, postAuthor, isLoading };
}