@wordpress/block-library
Version:
Block library for the WordPress editor.
140 lines (130 loc) • 5.84 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* External dependencies
*/
import { isEmpty } from 'lodash';
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { BlockSettingsMenuControls, BlockTitle, useBlockProps, Warning, store as blockEditorStore, __experimentalRecursionProvider as RecursionProvider, __experimentalUseHasRecursion as useHasRecursion } from '@wordpress/block-editor';
import { Spinner, Modal, MenuItem } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
import { useState, createInterpolateElement } from '@wordpress/element';
/**
* Internal dependencies
*/
import TemplatePartPlaceholder from './placeholder';
import TemplatePartSelectionModal from './selection-modal';
import { TemplatePartAdvancedControls } from './advanced-controls';
import TemplatePartInnerBlocks from './inner-blocks';
import { createTemplatePartId } from './utils/create-template-part-id';
import { useAlternativeBlockPatterns, useAlternativeTemplateParts, useTemplatePartArea } from './utils/hooks';
export default function TemplatePartEdit(_ref) {
let {
attributes,
setAttributes,
clientId,
isSelected
} = _ref;
const {
slug,
theme,
tagName,
layout = {}
} = attributes;
const templatePartId = createTemplatePartId(theme, slug);
const hasAlreadyRendered = useHasRecursion(templatePartId);
const [isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen] = useState(false); // Set the postId block attribute if it did not exist,
// but wait until the inner blocks have loaded to allow
// new edits to trigger this.
const {
isResolved,
innerBlocks,
isMissing,
area
} = useSelect(select => {
const {
getEditedEntityRecord,
hasFinishedResolution
} = select(coreStore);
const {
getBlocks
} = select(blockEditorStore);
const getEntityArgs = ['postType', 'wp_template_part', templatePartId];
const entityRecord = templatePartId ? getEditedEntityRecord(...getEntityArgs) : null;
const _area = (entityRecord === null || entityRecord === void 0 ? void 0 : entityRecord.area) || attributes.area;
const hasResolvedEntity = templatePartId ? hasFinishedResolution('getEditedEntityRecord', getEntityArgs) : false;
return {
innerBlocks: getBlocks(clientId),
isResolved: hasResolvedEntity,
isMissing: hasResolvedEntity && isEmpty(entityRecord),
area: _area
};
}, [templatePartId, clientId]);
const {
templateParts
} = useAlternativeTemplateParts(area, templatePartId);
const blockPatterns = useAlternativeBlockPatterns(area, clientId);
const hasReplacements = !!templateParts.length || !!blockPatterns.length;
const areaObject = useTemplatePartArea(area);
const blockProps = useBlockProps();
const isPlaceholder = !slug;
const isEntityAvailable = !isPlaceholder && !isMissing && isResolved;
const TagName = tagName || areaObject.tagName; // The `isSelected` check ensures the `BlockSettingsMenuControls` fill
// doesn't render multiple times. The block controls has similar internal check.
const canReplace = isSelected && isEntityAvailable && hasReplacements && (area === 'header' || area === 'footer'); // We don't want to render a missing state if we have any inner blocks.
// A new template part is automatically created if we have any inner blocks but no entity.
if (innerBlocks.length === 0 && (slug && !theme || slug && isMissing)) {
return createElement(TagName, blockProps, createElement(Warning, null, sprintf(
/* translators: %s: Template part slug */
__('Template part has been deleted or is unavailable: %s'), slug)));
}
if (isEntityAvailable && hasAlreadyRendered) {
return createElement(TagName, blockProps, createElement(Warning, null, __('Block cannot be rendered inside itself.')));
}
return createElement(Fragment, null, createElement(RecursionProvider, {
uniqueId: templatePartId
}, createElement(TemplatePartAdvancedControls, {
tagName: tagName,
setAttributes: setAttributes,
isEntityAvailable: isEntityAvailable,
templatePartId: templatePartId,
defaultWrapper: areaObject.tagName
}), isPlaceholder && createElement(TagName, blockProps, createElement(TemplatePartPlaceholder, {
area: attributes.area,
templatePartId: templatePartId,
clientId: clientId,
setAttributes: setAttributes,
onOpenSelectionModal: () => setIsTemplatePartSelectionOpen(true)
})), canReplace && createElement(BlockSettingsMenuControls, null, () => createElement(MenuItem, {
onClick: () => {
setIsTemplatePartSelectionOpen(true);
}
}, createInterpolateElement(__('Replace <BlockTitle />'), {
BlockTitle: createElement(BlockTitle, {
clientId: clientId,
maximumLength: 25
})
}))), isEntityAvailable && createElement(TemplatePartInnerBlocks, {
tagName: TagName,
blockProps: blockProps,
postId: templatePartId,
hasInnerBlocks: innerBlocks.length > 0,
layout: layout
}), !isPlaceholder && !isResolved && createElement(TagName, blockProps, createElement(Spinner, null))), isTemplatePartSelectionOpen && createElement(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()),
closeLabel: __('Cancel'),
onRequestClose: () => setIsTemplatePartSelectionOpen(false)
}, createElement(TemplatePartSelectionModal, {
templatePartId: templatePartId,
clientId: clientId,
area: area,
setAttributes: setAttributes,
onClose: () => setIsTemplatePartSelectionOpen(false)
})));
}
//# sourceMappingURL=index.js.map