UNPKG

@wordpress/block-library

Version:
285 lines (284 loc) 9.32 kB
// packages/block-library/src/template-part/edit/index.js import { serialize } from "@wordpress/blocks"; import { useSelect, useDispatch } from "@wordpress/data"; import { BlockSettingsMenuControls, useBlockProps, Warning, store as blockEditorStore, RecursionProvider, useHasRecursion, InspectorControls, __experimentalBlockPatternsList as BlockPatternsList, BlockControls } from "@wordpress/block-editor"; import { PanelBody, Spinner, Modal, MenuItem, ToolbarButton } from "@wordpress/components"; import { __, sprintf } from "@wordpress/i18n"; import { store as coreStore } from "@wordpress/core-data"; import { useState } from "@wordpress/element"; import { store as noticesStore } from "@wordpress/notices"; import TemplatePartPlaceholder from "./placeholder.mjs"; import TemplatePartSelectionModal from "./selection-modal.mjs"; import { TemplatePartAdvancedControls } from "./advanced-controls.mjs"; import TemplatePartInnerBlocks from "./inner-blocks.mjs"; import { createTemplatePartId } from "./utils/create-template-part-id.mjs"; import { useAlternativeBlockPatterns, useAlternativeTemplateParts, useTemplatePartArea } from "./utils/hooks.mjs"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var SUPPORTED_AREAS = ["header", "footer"]; function getSupportedAreas() { const isOverlayExperimentEnabled = typeof window !== "undefined" && window.__experimentalNavigationOverlays === true; return isOverlayExperimentEnabled ? [...SUPPORTED_AREAS, "navigation-overlay"] : SUPPORTED_AREAS; } function ReplaceButton({ isEntityAvailable, area, templatePartId, isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen }) { const { templateParts } = useAlternativeTemplateParts( area, templatePartId ); const hasReplacements = !!templateParts.length; const supportedAreas = getSupportedAreas(); const canReplace = isEntityAvailable && hasReplacements && supportedAreas.includes(area); if (!canReplace) { return null; } return /* @__PURE__ */ jsx( MenuItem, { onClick: () => { setIsTemplatePartSelectionOpen(true); }, "aria-expanded": isTemplatePartSelectionOpen, "aria-haspopup": "dialog", children: __("Replace") } ); } function TemplatesList({ area, clientId, isEntityAvailable, onSelect }) { const blockPatterns = useAlternativeBlockPatterns(area, clientId); const supportedAreas = getSupportedAreas(); const canReplace = isEntityAvailable && !!blockPatterns.length && supportedAreas.includes(area); if (!canReplace) { return null; } return /* @__PURE__ */ jsx(PanelBody, { title: __("Design"), children: /* @__PURE__ */ jsx( BlockPatternsList, { label: __("Templates"), blockPatterns, onClickPattern: onSelect, showTitlesAsTooltip: true } ) }); } function TemplatePartEdit({ attributes, setAttributes, clientId }) { const { createSuccessNotice } = useDispatch(noticesStore); const { editEntityRecord } = useDispatch(coreStore); const currentTheme = useSelect( (select) => select(coreStore).getCurrentTheme()?.stylesheet, [] ); const { slug, theme = currentTheme, tagName, layout = {} } = attributes; const templatePartId = createTemplatePartId(theme, slug); const hasAlreadyRendered = useHasRecursion(templatePartId); const [isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen] = useState(false); const { isResolved, hasInnerBlocks, isMissing, area, onNavigateToEntityRecord, title, canUserEdit } = useSelect( (select) => { const { getEditedEntityRecord, hasFinishedResolution } = select(coreStore); const { getBlockCount, getSettings } = select(blockEditorStore); const getEntityArgs = [ "postType", "wp_template_part", templatePartId ]; const entityRecord = templatePartId ? getEditedEntityRecord(...getEntityArgs) : null; const _area = entityRecord?.area || attributes.area; const hasResolvedEntity = templatePartId ? hasFinishedResolution( "getEditedEntityRecord", getEntityArgs ) : false; const _canUserEdit = hasResolvedEntity ? select(coreStore).canUser("update", { kind: "postType", name: "wp_template_part", id: templatePartId }) : false; return { hasInnerBlocks: getBlockCount(clientId) > 0, isResolved: hasResolvedEntity, isMissing: hasResolvedEntity && (!entityRecord || Object.keys(entityRecord).length === 0), area: _area, onNavigateToEntityRecord: getSettings().onNavigateToEntityRecord, title: entityRecord?.title, canUserEdit: !!_canUserEdit }; }, [templatePartId, attributes.area, clientId] ); const areaObject = useTemplatePartArea(area); const blockProps = useBlockProps(); const isPlaceholder = !slug; const isEntityAvailable = !isPlaceholder && !isMissing && isResolved; const TagName = tagName || areaObject.tagName; const onPatternSelect = async (pattern) => { await editEntityRecord( "postType", "wp_template_part", templatePartId, { blocks: pattern.blocks, content: serialize(pattern.blocks) } ); createSuccessNotice( sprintf( /* translators: %s: template part title. */ __('Template Part "%s" updated.'), title || slug ), { type: "snackbar" } ); }; if (!hasInnerBlocks && (slug && !theme || slug && isMissing)) { return /* @__PURE__ */ jsx(TagName, { ...blockProps, children: /* @__PURE__ */ jsx(Warning, { children: sprintf( /* translators: %s: Template part slug. */ __( "Template part has been deleted or is unavailable: %s" ), slug ) }) }); } if (isEntityAvailable && hasAlreadyRendered) { return /* @__PURE__ */ jsx(TagName, { ...blockProps, children: /* @__PURE__ */ jsx(Warning, { children: __("Block cannot be rendered inside itself.") }) }); } return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs(RecursionProvider, { uniqueId: templatePartId, children: [ isEntityAvailable && onNavigateToEntityRecord && canUserEdit && /* @__PURE__ */ jsx(BlockControls, { group: "other", children: /* @__PURE__ */ jsx( ToolbarButton, { onClick: () => { onNavigateToEntityRecord({ postId: templatePartId, postType: "wp_template_part" }); }, children: __("Edit section") } ) }), canUserEdit && /* @__PURE__ */ jsx(InspectorControls, { group: "advanced", children: /* @__PURE__ */ jsx( TemplatePartAdvancedControls, { tagName, setAttributes, isEntityAvailable, templatePartId, defaultWrapper: areaObject.tagName, hasInnerBlocks, clientId } ) }), isPlaceholder && /* @__PURE__ */ jsx(TagName, { ...blockProps, children: /* @__PURE__ */ jsx( TemplatePartPlaceholder, { area: attributes.area, templatePartId, clientId, setAttributes, onOpenSelectionModal: () => setIsTemplatePartSelectionOpen(true) } ) }), /* @__PURE__ */ jsx(BlockSettingsMenuControls, { children: ({ selectedClientIds }) => { if (!(selectedClientIds.length === 1 && clientId === selectedClientIds[0])) { return null; } return /* @__PURE__ */ jsx( ReplaceButton, { ...{ isEntityAvailable, area, clientId, templatePartId, isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen } } ); } }), /* @__PURE__ */ jsx(InspectorControls, { group: "settings", children: /* @__PURE__ */ jsx( TemplatesList, { area, clientId, isEntityAvailable, onSelect: (pattern) => onPatternSelect(pattern) } ) }), isEntityAvailable && /* @__PURE__ */ jsx( TemplatePartInnerBlocks, { tagName: TagName, blockProps, postId: templatePartId, hasInnerBlocks, layout } ), !isPlaceholder && !isResolved && /* @__PURE__ */ jsx(TagName, { ...blockProps, children: /* @__PURE__ */ jsx(Spinner, {}) }) ] }), isTemplatePartSelectionOpen && /* @__PURE__ */ jsx( Modal, { overlayClassName: "block-editor-template-part__selection-modal", title: sprintf( // Translators: %s as template part area title ("Header", "Footer", etc.). __("Choose a %s"), areaObject.label.toLowerCase() ), onRequestClose: () => setIsTemplatePartSelectionOpen(false), isFullScreen: true, children: /* @__PURE__ */ jsx( TemplatePartSelectionModal, { templatePartId, clientId, area, setAttributes, onClose: () => setIsTemplatePartSelectionOpen(false) } ) } ) ] }); } export { TemplatePartEdit as default }; //# sourceMappingURL=index.mjs.map