@gechiui/block-editor
Version:
195 lines (177 loc) • 5.06 kB
JavaScript
/**
* External dependencies
*/
import { orderBy, isEmpty } from 'lodash';
/**
* GeChiUI dependencies
*/
import { useMemo, useEffect } from '@gechiui/element';
import { __, _n, sprintf } from '@gechiui/i18n';
import { VisuallyHidden } from '@gechiui/components';
import { useDebounce, useAsyncList } from '@gechiui/compose';
import { speak } from '@gechiui/a11y';
/**
* Internal dependencies
*/
import BlockTypesList from '../block-types-list';
import BlockPatternsList from '../block-patterns-list';
import __unstableInserterMenuExtension from '../inserter-menu-extension';
import InserterPanel from './panel';
import InserterNoResults from './no-results';
import useInsertionPoint from './hooks/use-insertion-point';
import usePatternsState from './hooks/use-patterns-state';
import useBlockTypesState from './hooks/use-block-types-state';
import { searchBlockItems, searchItems } from './search-items';
import InserterListbox from '../inserter-listbox';
const INITIAL_INSERTER_RESULTS = 9;
/**
* Shared reference to an empty array for cases where it is important to avoid
* returning a new array reference on every invocation and rerendering the component.
*
* @type {Array}
*/
const EMPTY_ARRAY = [];
function InserterSearchResults( {
filterValue,
onSelect,
onHover,
rootClientId,
clientId,
isAppender,
__experimentalInsertionIndex,
maxBlockPatterns,
maxBlockTypes,
showBlockDirectory = false,
isDraggable = true,
shouldFocusBlock = true,
} ) {
const debouncedSpeak = useDebounce( speak, 500 );
const [ destinationRootClientId, onInsertBlocks ] = useInsertionPoint( {
onSelect,
rootClientId,
clientId,
isAppender,
insertionIndex: __experimentalInsertionIndex,
shouldFocusBlock,
} );
const [
blockTypes,
blockTypeCategories,
blockTypeCollections,
onSelectBlockType,
] = useBlockTypesState( destinationRootClientId, onInsertBlocks );
const [ patterns, , onSelectBlockPattern ] = usePatternsState(
onInsertBlocks,
destinationRootClientId
);
const filteredBlockTypes = useMemo( () => {
const results = searchBlockItems(
orderBy( blockTypes, [ 'frecency' ], [ 'desc' ] ),
blockTypeCategories,
blockTypeCollections,
filterValue
);
return maxBlockTypes !== undefined
? results.slice( 0, maxBlockTypes )
: results;
}, [
filterValue,
blockTypes,
blockTypeCategories,
blockTypeCollections,
maxBlockTypes,
] );
const filteredBlockPatterns = useMemo( () => {
const results = searchItems( patterns, filterValue );
return maxBlockPatterns !== undefined
? results.slice( 0, maxBlockPatterns )
: results;
}, [ filterValue, patterns, maxBlockPatterns ] );
// Announce search results on change
useEffect( () => {
if ( ! filterValue ) {
return;
}
const count = filteredBlockTypes.length + filteredBlockPatterns.length;
const resultsFoundMessage = sprintf(
/* translators: %d: number of results. */
_n( '%d result found.', '%d results found.', count ),
count
);
debouncedSpeak( resultsFoundMessage );
}, [ filterValue, debouncedSpeak ] );
const currentShownBlockTypes = useAsyncList( filteredBlockTypes, {
step: INITIAL_INSERTER_RESULTS,
} );
const currentShownPatterns = useAsyncList(
currentShownBlockTypes.length === filteredBlockTypes.length
? filteredBlockPatterns
: EMPTY_ARRAY
);
const hasItems =
! isEmpty( filteredBlockTypes ) || ! isEmpty( filteredBlockPatterns );
return (
<InserterListbox>
{ ! showBlockDirectory && ! hasItems && <InserterNoResults /> }
{ !! filteredBlockTypes.length && (
<InserterPanel
title={
<VisuallyHidden>{ __( '区块' ) }</VisuallyHidden>
}
>
<BlockTypesList
items={ currentShownBlockTypes }
onSelect={ onSelectBlockType }
onHover={ onHover }
label={ __( '区块' ) }
isDraggable={ isDraggable }
/>
</InserterPanel>
) }
{ !! filteredBlockTypes.length &&
!! filteredBlockPatterns.length && (
<div className="block-editor-inserter__quick-inserter-separator" />
) }
{ !! filteredBlockPatterns.length && (
<InserterPanel
title={
<VisuallyHidden>
{ __( '区块样板' ) }
</VisuallyHidden>
}
>
<div className="block-editor-inserter__quick-inserter-patterns">
<BlockPatternsList
shownPatterns={ currentShownPatterns }
blockPatterns={ filteredBlockPatterns }
onClickPattern={ onSelectBlockPattern }
isDraggable={ isDraggable }
/>
</div>
</InserterPanel>
) }
{ showBlockDirectory && (
<__unstableInserterMenuExtension.Slot
fillProps={ {
onSelect: onSelectBlockType,
onHover,
filterValue,
hasItems,
rootClientId: destinationRootClientId,
} }
>
{ ( fills ) => {
if ( fills.length ) {
return fills;
}
if ( ! hasItems ) {
return <InserterNoResults />;
}
return null;
} }
</__unstableInserterMenuExtension.Slot>
) }
</InserterListbox>
);
}
export default InserterSearchResults;