@wordpress/block-editor
Version:
346 lines (345 loc) • 10.6 kB
JavaScript
// packages/block-editor/src/components/inserter/menu.js
import clsx from "clsx";
import {
forwardRef,
useState,
useCallback,
useMemo,
useRef,
useLayoutEffect
} from "@wordpress/element";
import { VisuallyHidden, SearchControl, Popover } from "@wordpress/components";
import { __ } from "@wordpress/i18n";
import { useDebouncedInput, useViewportMatch } from "@wordpress/compose";
import { useSelect } from "@wordpress/data";
import Tips from "./tips";
import InserterPreviewPanel from "./preview-panel";
import BlockTypesTab from "./block-types-tab";
import BlockPatternsTab from "./block-patterns-tab";
import { PatternCategoryPreviews } from "./block-patterns-tab/pattern-category-previews";
import { MediaTab, MediaCategoryPanel } from "./media-tab";
import InserterSearchResults from "./search-results";
import useInsertionPoint from "./hooks/use-insertion-point";
import { store as blockEditorStore } from "../../store";
import TabbedSidebar from "../tabbed-sidebar";
import { useZoomOut } from "../../hooks/use-zoom-out";
import { unlock } from "../../lock-unlock";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var NOOP = () => {
};
function InserterMenu({
rootClientId,
clientId,
isAppender,
__experimentalInsertionIndex,
onSelect,
showInserterHelpPanel,
showMostUsedBlocks,
__experimentalFilterValue = "",
shouldFocusBlock = true,
onPatternCategorySelection,
onClose,
__experimentalInitialTab,
__experimentalInitialCategory
}, ref) {
const { isZoomOutMode, hasSectionRootClientId } = useSelect((select) => {
const { isZoomOut, getSectionRootClientId } = unlock(
select(blockEditorStore)
);
return {
isZoomOutMode: isZoomOut(),
hasSectionRootClientId: !!getSectionRootClientId()
};
}, []);
const [filterValue, setFilterValue, delayedFilterValue] = useDebouncedInput(__experimentalFilterValue);
const [hoveredItem, setHoveredItem] = useState(null);
const [selectedPatternCategory, setSelectedPatternCategory] = useState(
__experimentalInitialCategory
);
const [patternFilter, setPatternFilter] = useState("all");
const [selectedMediaCategory, setSelectedMediaCategory] = useState(null);
const isLargeViewport = useViewportMatch("large");
function getInitialTab() {
if (__experimentalInitialTab) {
return __experimentalInitialTab;
}
if (isZoomOutMode) {
return "patterns";
}
return "blocks";
}
const [selectedTab, setSelectedTab] = useState(getInitialTab());
const shouldUseZoomOut = hasSectionRootClientId && (selectedTab === "patterns" || selectedTab === "media");
useZoomOut(shouldUseZoomOut && isLargeViewport);
const [destinationRootClientId, onInsertBlocks, onToggleInsertionPoint] = useInsertionPoint({
rootClientId,
clientId,
isAppender,
insertionIndex: __experimentalInsertionIndex,
shouldFocusBlock
});
const blockTypesTabRef = useRef();
const onInsert = useCallback(
(blocks, meta, shouldForceFocusBlock, _rootClientId) => {
onInsertBlocks(
blocks,
meta,
shouldForceFocusBlock,
_rootClientId
);
onSelect(blocks);
window.requestAnimationFrame(() => {
if (!shouldFocusBlock && !blockTypesTabRef.current?.contains(
ref.current.ownerDocument.activeElement
)) {
blockTypesTabRef.current?.querySelector("button").focus();
}
});
},
[onInsertBlocks, onSelect, shouldFocusBlock]
);
const onInsertPattern = useCallback(
(blocks, patternName, ...args) => {
onToggleInsertionPoint(false);
onInsertBlocks(blocks, { patternName }, ...args);
onSelect();
},
[onInsertBlocks, onSelect]
);
const onHover = useCallback(
(item) => {
onToggleInsertionPoint(item);
setHoveredItem(item);
},
[onToggleInsertionPoint, setHoveredItem]
);
const onClickPatternCategory = useCallback(
(patternCategory, filter) => {
setSelectedPatternCategory(patternCategory);
setPatternFilter(filter);
onPatternCategorySelection?.();
},
[setSelectedPatternCategory, onPatternCategorySelection]
);
const showPatternPanel = selectedTab === "patterns" && !delayedFilterValue && !!selectedPatternCategory;
const showMediaPanel = selectedTab === "media" && !!selectedMediaCategory;
const inserterSearch = useMemo(() => {
if (selectedTab === "media") {
return null;
}
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
SearchControl,
{
__nextHasNoMarginBottom: true,
className: "block-editor-inserter__search",
onChange: (value) => {
if (hoveredItem) {
setHoveredItem(null);
}
setFilterValue(value);
},
value: filterValue,
label: __("Search"),
placeholder: __("Search")
}
),
!!delayedFilterValue && /* @__PURE__ */ jsx(
InserterSearchResults,
{
filterValue: delayedFilterValue,
onSelect,
onHover,
rootClientId,
clientId,
isAppender,
__experimentalInsertionIndex,
showBlockDirectory: true,
shouldFocusBlock,
prioritizePatterns: selectedTab === "patterns"
}
)
] });
}, [
selectedTab,
hoveredItem,
setHoveredItem,
setFilterValue,
filterValue,
delayedFilterValue,
onSelect,
onHover,
shouldFocusBlock,
clientId,
rootClientId,
__experimentalInsertionIndex,
isAppender
]);
const blocksTab = useMemo(() => {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx("div", { className: "block-editor-inserter__block-list", children: /* @__PURE__ */ jsx(
BlockTypesTab,
{
ref: blockTypesTabRef,
rootClientId: destinationRootClientId,
onInsert,
onHover,
showMostUsedBlocks
}
) }),
showInserterHelpPanel && /* @__PURE__ */ jsxs("div", { className: "block-editor-inserter__tips", children: [
/* @__PURE__ */ jsx(VisuallyHidden, { as: "h2", children: __("A tip for using the block editor") }),
/* @__PURE__ */ jsx(Tips, {})
] })
] });
}, [
destinationRootClientId,
onInsert,
onHover,
showMostUsedBlocks,
showInserterHelpPanel
]);
const patternsTab = useMemo(() => {
return /* @__PURE__ */ jsx(
BlockPatternsTab,
{
rootClientId: destinationRootClientId,
onInsert: onInsertPattern,
onSelectCategory: onClickPatternCategory,
selectedCategory: selectedPatternCategory,
children: showPatternPanel && /* @__PURE__ */ jsx(
PatternCategoryPreviews,
{
rootClientId: destinationRootClientId,
onInsert: onInsertPattern,
category: selectedPatternCategory,
patternFilter,
showTitlesAsTooltip: true
}
)
}
);
}, [
destinationRootClientId,
onInsertPattern,
onClickPatternCategory,
patternFilter,
selectedPatternCategory,
showPatternPanel
]);
const mediaTab = useMemo(() => {
return /* @__PURE__ */ jsx(
MediaTab,
{
rootClientId: destinationRootClientId,
selectedCategory: selectedMediaCategory,
onSelectCategory: setSelectedMediaCategory,
onInsert,
children: showMediaPanel && /* @__PURE__ */ jsx(
MediaCategoryPanel,
{
rootClientId: destinationRootClientId,
onInsert,
category: selectedMediaCategory
}
)
}
);
}, [
destinationRootClientId,
onInsert,
selectedMediaCategory,
setSelectedMediaCategory,
showMediaPanel
]);
const handleSetSelectedTab = (value) => {
if (value !== "patterns") {
setSelectedPatternCategory(null);
}
setSelectedTab(value);
};
const tabsRef = useRef();
useLayoutEffect(() => {
if (tabsRef.current) {
window.requestAnimationFrame(() => {
tabsRef.current.querySelector('[role="tab"][aria-selected="true"]')?.focus();
});
}
}, []);
return /* @__PURE__ */ jsxs(
"div",
{
className: clsx("block-editor-inserter__menu", {
"show-panel": showPatternPanel || showMediaPanel,
"is-zoom-out": isZoomOutMode
}),
ref,
children: [
/* @__PURE__ */ jsx("div", { className: "block-editor-inserter__main-area", children: /* @__PURE__ */ jsx(
TabbedSidebar,
{
ref: tabsRef,
onSelect: handleSetSelectedTab,
onClose,
selectedTab,
closeButtonLabel: __("Close Block Inserter"),
tabs: [
{
name: "blocks",
title: __("Blocks"),
panel: /* @__PURE__ */ jsxs(Fragment, { children: [
inserterSearch,
selectedTab === "blocks" && !delayedFilterValue && blocksTab
] })
},
{
name: "patterns",
title: __("Patterns"),
panel: /* @__PURE__ */ jsxs(Fragment, { children: [
inserterSearch,
selectedTab === "patterns" && !delayedFilterValue && patternsTab
] })
},
{
name: "media",
title: __("Media"),
panel: /* @__PURE__ */ jsxs(Fragment, { children: [
inserterSearch,
mediaTab
] })
}
]
}
) }),
showInserterHelpPanel && hoveredItem && /* @__PURE__ */ jsx(
Popover,
{
className: "block-editor-inserter__preview-container__popover",
placement: "right-start",
offset: 16,
focusOnMount: false,
animate: false,
children: /* @__PURE__ */ jsx(InserterPreviewPanel, { item: hoveredItem })
}
)
]
}
);
}
var PrivateInserterMenu = forwardRef(InserterMenu);
function PublicInserterMenu(props, ref) {
return /* @__PURE__ */ jsx(
PrivateInserterMenu,
{
...props,
onPatternCategorySelection: NOOP,
ref
}
);
}
var menu_default = forwardRef(PublicInserterMenu);
export {
PrivateInserterMenu,
menu_default as default
};
//# sourceMappingURL=menu.js.map