@wordpress/block-library
Version:
Block library for the WordPress editor.
140 lines (130 loc) • 3.69 kB
JavaScript
import { __ } from '@wordpress/i18n';
import { Modal, SearchControl, Spinner } from '@wordpress/components';
import { Stack, Tabs } from '@wordpress/ui';
import { useState, useMemo } from '@wordpress/element';
import { useDebounce } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import IconGrid from './icon-grid';
import { normalizeSearchInput } from '../../../utils/search-patterns';
export default function CustomInserterModal( { onClose, value, onChange } ) {
const [ searchInput, setSearchInput ] = useState( '' );
const [ currentCollection, setCurrentCollection ] = useState( null );
const debouncedSetSearchInput = useDebounce( setSearchInput, 300 );
const collections = useSelect(
( select ) =>
select( coreDataStore ).getEntityRecords(
'root',
'iconCollection'
),
[]
);
// Default to the collection the selected icon belongs to, otherwise the
// first collection.
const selectedCollection = value?.split( '/' )[ 0 ];
const collectionSlug =
currentCollection ??
( collections?.some( ( { slug } ) => slug === selectedCollection )
? selectedCollection
: collections?.[ 0 ]?.slug ) ??
null;
const { icons, hasResolvedIcons } = useSelect(
( select ) => {
if ( collectionSlug === null ) {
return { icons: null, hasResolvedIcons: false };
}
const query =
collectionSlug === '' ? {} : { collection: collectionSlug };
const { getEntityRecords, hasFinishedResolution } =
select( coreDataStore );
return {
icons: getEntityRecords( 'root', 'icon', query ),
hasResolvedIcons: hasFinishedResolution( 'getEntityRecords', [
'root',
'icon',
query,
] ),
};
},
[ collectionSlug ]
);
const filteredIcons = useMemo( () => {
if ( ! icons ) {
return [];
}
if ( searchInput ) {
const input = normalizeSearchInput( searchInput );
return icons.filter( ( icon ) => {
const iconName = normalizeSearchInput( icon.name );
const iconLabel = normalizeSearchInput( icon.label );
return (
iconName.includes( input ) || iconLabel.includes( input )
);
} );
}
return icons;
}, [ searchInput, icons ] );
return (
<Modal
className="wp-block-icon__inserter-modal"
title={ __( 'Icon library' ) }
onRequestClose={ onClose }
isFullScreen
>
<Tabs.Root
className="wp-block-icon__inserter"
orientation="vertical"
value={ collectionSlug }
onValueChange={ setCurrentCollection }
>
<Stack
direction="column"
gap="lg"
className="wp-block-icon__inserter-sidebar"
>
<SearchControl
value={ searchInput }
onChange={ debouncedSetSearchInput }
/>
<Tabs.List>
<Tabs.Tab value="">{ __( 'All' ) }</Tabs.Tab>
{ collections?.map( ( collection ) => (
<Tabs.Tab
key={ collection.slug }
value={ collection.slug }
>
{ collection.label }
</Tabs.Tab>
) ) }
</Tabs.List>
</Stack>
{ [ { slug: '' }, ...( collections ?? [] ) ].map(
( collection ) => (
<Tabs.Panel
tabIndex={ -1 }
key={ collection.slug }
value={ collection.slug }
className="wp-block-icon__inserter-panel"
>
{ ! hasResolvedIcons ? (
<div
className="wp-block-icon__inserter-loading"
role="status"
aria-label={ __( 'Loading…' ) }
>
<Spinner />
</div>
) : (
<IconGrid
icons={ filteredIcons }
onChange={ onChange }
value={ value }
/>
) }
</Tabs.Panel>
)
) }
</Tabs.Root>
</Modal>
);
}