UNPKG

@gechiui/block-editor

Version:
133 lines (119 loc) 4.61 kB
import { createElement } from "@gechiui/element"; /** * External dependencies */ import { map, flow, groupBy, orderBy } from 'lodash'; /** * GeChiUI dependencies */ import { __, _x } from '@gechiui/i18n'; import { useMemo, useEffect } from '@gechiui/element'; import { useAsyncList } from '@gechiui/compose'; /** * Internal dependencies */ import BlockTypesList from '../block-types-list'; import InserterPanel from './panel'; import useBlockTypesState from './hooks/use-block-types-state'; import InserterListbox from '../inserter-listbox'; const getBlockNamespace = item => item.name.split('/')[0]; const MAX_SUGGESTED_ITEMS = 6; /** * 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 = []; export function BlockTypesTab(_ref) { let { rootClientId, onInsert, onHover, showMostUsedBlocks } = _ref; const [items, categories, collections, onSelectItem] = useBlockTypesState(rootClientId, onInsert); const suggestedItems = useMemo(() => { return orderBy(items, ['frecency'], ['desc']).slice(0, MAX_SUGGESTED_ITEMS); }, [items]); const uncategorizedItems = useMemo(() => { return items.filter(item => !item.category); }, [items]); const itemsPerCategory = useMemo(() => { return flow(itemList => itemList.filter(item => item.category && item.category !== 'reusable'), itemList => groupBy(itemList, 'category'))(items); }, [items]); const itemsPerCollection = useMemo(() => { // Create a new Object to avoid mutating collection. const result = { ...collections }; Object.keys(collections).forEach(namespace => { result[namespace] = items.filter(item => getBlockNamespace(item) === namespace); if (result[namespace].length === 0) { delete result[namespace]; } }); return result; }, [items, collections]); // Hide block preview on unmount. useEffect(() => () => onHover(null), []); /** * The inserter contains a big number of blocks and opening it is a costful operation. * The rendering is the most costful part of it, in order to improve the responsiveness * of the "opening" action, these lazy lists allow us to render the inserter category per category, * once all the categories are rendered, we start rendering the collections and the uncategorized block types. */ const currentlyRenderedCategories = useAsyncList(categories); const didRenderAllCategories = categories.length === currentlyRenderedCategories.length; // Async List requires an array const collectionEntries = useMemo(() => { return Object.entries(collections); }, [collections]); const currentlyRenderedCollections = useAsyncList(didRenderAllCategories ? collectionEntries : EMPTY_ARRAY); return createElement(InserterListbox, null, createElement("div", null, showMostUsedBlocks && !!suggestedItems.length && createElement(InserterPanel, { title: _x('Most used', 'blocks') }, createElement(BlockTypesList, { items: suggestedItems, onSelect: onSelectItem, onHover: onHover, label: _x('Most used', 'blocks') })), map(currentlyRenderedCategories, category => { const categoryItems = itemsPerCategory[category.slug]; if (!categoryItems || !categoryItems.length) { return null; } return createElement(InserterPanel, { key: category.slug, title: category.title, icon: category.icon }, createElement(BlockTypesList, { items: categoryItems, onSelect: onSelectItem, onHover: onHover, label: category.title })); }), didRenderAllCategories && uncategorizedItems.length > 0 && createElement(InserterPanel, { className: "block-editor-inserter__uncategorized-blocks-panel", title: __('未分类') }, createElement(BlockTypesList, { items: uncategorizedItems, onSelect: onSelectItem, onHover: onHover, label: __('未分类') })), map(currentlyRenderedCollections, _ref2 => { let [namespace, collection] = _ref2; const collectionItems = itemsPerCollection[namespace]; if (!collectionItems || !collectionItems.length) { return null; } return createElement(InserterPanel, { key: namespace, title: collection.title, icon: collection.icon }, createElement(BlockTypesList, { items: collectionItems, onSelect: onSelectItem, onHover: onHover, label: collection.title })); }))); } export default BlockTypesTab; //# sourceMappingURL=block-types-tab.js.map