@wordpress/block-editor
Version:
183 lines (163 loc) • 7 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* WordPress dependencies
*/
import { useMemo, useState, useCallback, useRef, useEffect } from '@wordpress/element';
import { _x, __ } from '@wordpress/i18n';
import { useAsyncList, useViewportMatch } from '@wordpress/compose';
import { __experimentalItemGroup as ItemGroup, __experimentalItem as Item, __experimentalHStack as HStack, FlexBlock, Button } from '@wordpress/components';
import { Icon, chevronRight } from '@wordpress/icons';
import { focus } from '@wordpress/dom';
/**
* Internal dependencies
*/
import usePatternsState from './hooks/use-patterns-state';
import BlockPatternList from '../block-patterns-list';
import PatternsExplorerModal from './block-patterns-explorer/explorer';
import MobileTabNavigation from './mobile-tab-navigation';
const noop = () => {}; // Preferred order of pattern categories. Any other categories should
// be at the bottom without any re-ordering.
const patternCategoriesOrder = ['featured', 'posts', 'text', 'gallery', 'call-to-action', 'banner', 'header', 'footer'];
function usePatternsCategories(rootClientId) {
const [allPatterns, allCategories] = usePatternsState(undefined, rootClientId);
const hasRegisteredCategory = useCallback(pattern => {
if (!pattern.categories || !pattern.categories.length) {
return false;
}
return pattern.categories.some(cat => allCategories.some(category => category.name === cat));
}, [allCategories]); // Remove any empty categories.
const populatedCategories = useMemo(() => {
const categories = allCategories.filter(category => allPatterns.some(pattern => pattern.categories?.includes(category.name))).sort(({
name: aName
}, {
name: bName
}) => {
// Sort categories according to `patternCategoriesOrder`.
let aIndex = patternCategoriesOrder.indexOf(aName);
let bIndex = patternCategoriesOrder.indexOf(bName); // All other categories should come after that.
if (aIndex < 0) aIndex = patternCategoriesOrder.length;
if (bIndex < 0) bIndex = patternCategoriesOrder.length;
return aIndex - bIndex;
});
if (allPatterns.some(pattern => !hasRegisteredCategory(pattern)) && !categories.find(category => category.name === 'uncategorized')) {
categories.push({
name: 'uncategorized',
label: _x('Uncategorized')
});
}
return categories;
}, [allPatterns, allCategories]);
return populatedCategories;
}
export function BlockPatternsCategoryDialog({
rootClientId,
onInsert,
onHover,
category,
showTitlesAsTooltip
}) {
const container = useRef();
useEffect(() => {
const timeout = setTimeout(() => {
const [firstTabbable] = focus.tabbable.find(container.current);
firstTabbable?.focus();
});
return () => clearTimeout(timeout);
}, [category]);
return createElement("div", {
ref: container,
className: "block-editor-inserter__patterns-category-dialog"
}, createElement(BlockPatternsCategoryPanel, {
rootClientId: rootClientId,
onInsert: onInsert,
onHover: onHover,
category: category,
showTitlesAsTooltip: showTitlesAsTooltip
}));
}
export function BlockPatternsCategoryPanel({
rootClientId,
onInsert,
onHover = noop,
category,
showTitlesAsTooltip
}) {
const [allPatterns,, onClick] = usePatternsState(onInsert, rootClientId);
const availableCategories = usePatternsCategories(rootClientId);
const currentCategoryPatterns = useMemo(() => allPatterns.filter(pattern => {
var _pattern$categories$f;
if (category.name !== 'uncategorized') {
return pattern.categories?.includes(category.name);
} // The uncategorized category should show all the patterns without any category
// or with no available category.
const availablePatternCategories = (_pattern$categories$f = pattern.categories?.filter(cat => availableCategories.find(availableCategory => availableCategory.name === cat))) !== null && _pattern$categories$f !== void 0 ? _pattern$categories$f : [];
return availablePatternCategories.length === 0;
}), [allPatterns, category]);
const currentShownPatterns = useAsyncList(currentCategoryPatterns); // Hide block pattern preview on unmount.
useEffect(() => () => onHover(null), []);
if (!currentCategoryPatterns.length) {
return null;
}
return createElement("div", {
className: "block-editor-inserter__patterns-category-panel"
}, createElement("div", {
className: "block-editor-inserter__patterns-category-panel-title"
}, category.label), createElement("p", null, category.description), createElement(BlockPatternList, {
shownPatterns: currentShownPatterns,
blockPatterns: currentCategoryPatterns,
onClickPattern: onClick,
onHover: onHover,
label: category.label,
orientation: "vertical",
category: category.label,
isDraggable: true,
showTitlesAsTooltip: showTitlesAsTooltip
}));
}
function BlockPatternsTabs({
onSelectCategory,
selectedCategory,
onInsert,
rootClientId
}) {
const [showPatternsExplorer, setShowPatternsExplorer] = useState(false);
const categories = usePatternsCategories(rootClientId);
const initialCategory = selectedCategory || categories[0];
const isMobile = useViewportMatch('medium', '<');
return createElement(Fragment, null, !isMobile && createElement("div", {
className: "block-editor-inserter__block-patterns-tabs-container"
}, createElement("nav", {
"aria-label": __('Block pattern categories')
}, createElement(ItemGroup, {
role: "list",
className: "block-editor-inserter__block-patterns-tabs"
}, categories.map(category => createElement(Item, {
role: "listitem",
key: category.name,
onClick: () => onSelectCategory(category),
className: category === selectedCategory ? 'block-editor-inserter__patterns-category block-editor-inserter__patterns-selected-category' : 'block-editor-inserter__patterns-category',
"aria-label": category.label,
"aria-current": category === selectedCategory ? 'true' : undefined
}, createElement(HStack, null, createElement(FlexBlock, null, category.label), createElement(Icon, {
icon: chevronRight
})))), createElement("div", {
role: "listitem"
}, createElement(Button, {
className: "block-editor-inserter__patterns-explore-button",
onClick: () => setShowPatternsExplorer(true),
variant: "secondary"
}, __('Explore all patterns')))))), isMobile && createElement(MobileTabNavigation, {
categories: categories
}, category => createElement(BlockPatternsCategoryPanel, {
onInsert: onInsert,
rootClientId: rootClientId,
category: category,
showTitlesAsTooltip: false
})), showPatternsExplorer && createElement(PatternsExplorerModal, {
initialCategory: initialCategory,
patternCategories: categories,
onModalClose: () => setShowPatternsExplorer(false)
}));
}
export default BlockPatternsTabs;
//# sourceMappingURL=block-patterns-tab.js.map