UNPKG

@wordpress/block-library

Version:
208 lines (204 loc) 6.57 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; import { useRef, useMemo } from '@wordpress/element'; import { useEntityRecord, store as coreStore, useEntityBlockEditor } from '@wordpress/core-data'; import { Placeholder, Spinner, ToolbarButton, ToolbarGroup } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useInnerBlocksProps, RecursionProvider, useHasRecursion, useBlockProps, Warning, privateApis as blockEditorPrivateApis, store as blockEditorStore, BlockControls, InnerBlocks } from '@wordpress/block-editor'; import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; import { getBlockBindingsSource } from '@wordpress/blocks'; /** * Internal dependencies */ import { unlock } from '../lock-unlock'; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; const { useLayoutClasses } = unlock(blockEditorPrivateApis); const { hasOverridableBlocks } = unlock(patternsPrivateApis); const fullAlignments = ['full', 'wide', 'left', 'right']; const useInferredLayout = (blocks, parentLayout) => { const initialInferredAlignmentRef = useRef(); return useMemo(() => { // Exit early if the pattern's blocks haven't loaded yet. if (!blocks?.length) { return {}; } let alignment = initialInferredAlignmentRef.current; // Only track the initial alignment so that temporarily removed // alignments can be reapplied. if (alignment === undefined) { const isConstrained = parentLayout?.type === 'constrained'; const hasFullAlignment = blocks.some(block => fullAlignments.includes(block.attributes.align)); alignment = isConstrained && hasFullAlignment ? 'full' : null; initialInferredAlignmentRef.current = alignment; } const layout = alignment ? parentLayout : undefined; return { alignment, layout }; }, [blocks, parentLayout]); }; function RecursionWarning() { const blockProps = useBlockProps(); return /*#__PURE__*/_jsx("div", { ...blockProps, children: /*#__PURE__*/_jsx(Warning, { children: __('Block cannot be rendered inside itself.') }) }); } const NOOP = () => {}; // Wrap the main Edit function for the pattern block with a recursion wrapper // that allows short-circuiting rendering as early as possible, before any // of the other effects in the block edit have run. export default function ReusableBlockEditRecursionWrapper(props) { const { ref } = props.attributes; const hasAlreadyRendered = useHasRecursion(ref); if (hasAlreadyRendered) { return /*#__PURE__*/_jsx(RecursionWarning, {}); } return /*#__PURE__*/_jsx(RecursionProvider, { uniqueId: ref, children: /*#__PURE__*/_jsx(ReusableBlockEdit, { ...props }) }); } function ReusableBlockControl({ recordId, canOverrideBlocks, hasContent, handleEditOriginal, resetContent }) { const canUserEdit = useSelect(select => !!select(coreStore).canUser('update', { kind: 'postType', name: 'wp_block', id: recordId }), [recordId]); return /*#__PURE__*/_jsxs(_Fragment, { children: [canUserEdit && !!handleEditOriginal && /*#__PURE__*/_jsx(BlockControls, { children: /*#__PURE__*/_jsx(ToolbarGroup, { children: /*#__PURE__*/_jsx(ToolbarButton, { onClick: handleEditOriginal, children: __('Edit original') }) }) }), canOverrideBlocks && /*#__PURE__*/_jsx(BlockControls, { children: /*#__PURE__*/_jsx(ToolbarGroup, { children: /*#__PURE__*/_jsx(ToolbarButton, { onClick: resetContent, disabled: !hasContent, children: __('Reset') }) }) })] }); } function ReusableBlockEdit({ name, attributes: { ref, content }, __unstableParentLayout: parentLayout, setAttributes }) { const { record, hasResolved } = useEntityRecord('postType', 'wp_block', ref); const [blocks] = useEntityBlockEditor('postType', 'wp_block', { id: ref }); const isMissing = hasResolved && !record; const { __unstableMarkLastChangeAsPersistent } = useDispatch(blockEditorStore); const { onNavigateToEntityRecord, hasPatternOverridesSource } = useSelect(select => { const { getSettings } = select(blockEditorStore); // For editing link to the site editor if the theme and user permissions support it. return { onNavigateToEntityRecord: getSettings().onNavigateToEntityRecord, hasPatternOverridesSource: !!getBlockBindingsSource('core/pattern-overrides') }; }, []); const canOverrideBlocks = useMemo(() => hasPatternOverridesSource && hasOverridableBlocks(blocks), [hasPatternOverridesSource, blocks]); const { alignment, layout } = useInferredLayout(blocks, parentLayout); const layoutClasses = useLayoutClasses({ layout }, name); const blockProps = useBlockProps({ className: clsx('block-library-block__reusable-block-container', layout && layoutClasses, { [`align${alignment}`]: alignment }) }); const innerBlocksProps = useInnerBlocksProps(blockProps, { layout, value: blocks, onInput: NOOP, onChange: NOOP, renderAppender: blocks?.length ? undefined : InnerBlocks.ButtonBlockAppender }); const handleEditOriginal = () => { onNavigateToEntityRecord({ postId: ref, postType: 'wp_block' }); }; const resetContent = () => { if (content) { // Make sure any previous changes are persisted before resetting. __unstableMarkLastChangeAsPersistent(); setAttributes({ content: undefined }); } }; let children = null; if (isMissing) { children = /*#__PURE__*/_jsx(Warning, { children: __('Block has been deleted or is unavailable.') }); } if (!hasResolved) { children = /*#__PURE__*/_jsx(Placeholder, { children: /*#__PURE__*/_jsx(Spinner, {}) }); } return /*#__PURE__*/_jsxs(_Fragment, { children: [hasResolved && !isMissing && /*#__PURE__*/_jsx(ReusableBlockControl, { recordId: ref, canOverrideBlocks: canOverrideBlocks, hasContent: !!content, handleEditOriginal: onNavigateToEntityRecord ? handleEditOriginal : undefined, resetContent: resetContent }), children === null ? /*#__PURE__*/_jsx("div", { ...innerBlocksProps }) : /*#__PURE__*/_jsx("div", { ...blockProps, children: children })] }); } //# sourceMappingURL=edit.js.map