UNPKG

@gechiui/block-editor

Version:
195 lines (177 loc) 5.06 kB
/** * 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;