UNPKG

@wordpress/editor

Version:
335 lines (320 loc) 14.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.EditorProvider = EditorProvider; exports.default = exports.ExperimentalEditorProvider = void 0; var _element = require("@wordpress/element"); var _data = require("@wordpress/data"); var _i18n = require("@wordpress/i18n"); var _coreData = require("@wordpress/core-data"); var _blockEditor = require("@wordpress/block-editor"); var _notices = require("@wordpress/notices"); var _patterns = require("@wordpress/patterns"); var _blocks = require("@wordpress/blocks"); var _withRegistryProvider = _interopRequireDefault(require("./with-registry-provider")); var _store = require("../../store"); var _useBlockEditorSettings = _interopRequireDefault(require("./use-block-editor-settings")); var _lockUnlock = require("../../lock-unlock"); var _disableNonPageContentBlocks = _interopRequireDefault(require("./disable-non-page-content-blocks")); var _navigationBlockEditingMode = _interopRequireDefault(require("./navigation-block-editing-mode")); var _useHideBlocksFromInserter = require("./use-hide-blocks-from-inserter"); var _commands = _interopRequireDefault(require("../commands")); var _blockRemovalWarnings = _interopRequireDefault(require("../block-removal-warnings")); var _startPageOptions = _interopRequireDefault(require("../start-page-options")); var _keyboardShortcutHelpModal = _interopRequireDefault(require("../keyboard-shortcut-help-modal")); var _contentOnlySettingsMenu = _interopRequireDefault(require("../block-settings-menu/content-only-settings-menu")); var _startTemplateOptions = _interopRequireDefault(require("../start-template-options")); var _globalKeyboardShortcuts = _interopRequireDefault(require("../global-keyboard-shortcuts")); var _patternRenameModal = _interopRequireDefault(require("../pattern-rename-modal")); var _patternDuplicateModal = _interopRequireDefault(require("../pattern-duplicate-modal")); var _templatePartMenuItems = _interopRequireDefault(require("../template-part-menu-items")); var _jsxRuntime = require("react/jsx-runtime"); /** * WordPress dependencies */ /** * Internal dependencies */ const { ExperimentalBlockEditorProvider } = (0, _lockUnlock.unlock)(_blockEditor.privateApis); const { PatternsMenuItems } = (0, _lockUnlock.unlock)(_patterns.privateApis); const noop = () => {}; /** * These are global entities that are only there to split blocks into logical units * They don't provide a "context" for the current post/page being rendered. * So we should not use their ids as post context. This is important to allow post blocks * (post content, post title) to be used within them without issues. */ const NON_CONTEXTUAL_POST_TYPES = ['wp_block', 'wp_navigation', 'wp_template_part']; /** * Depending on the post, template and template mode, * returns the appropriate blocks and change handlers for the block editor provider. * * @param {Array} post Block list. * @param {boolean} template Whether the page content has focus (and the surrounding template is inert). If `true` return page content blocks. Default `false`. * @param {string} mode Rendering mode. * * @example * ```jsx * const [ blocks, onInput, onChange ] = useBlockEditorProps( post, template, mode ); * ``` * * @return {Array} Block editor props. */ function useBlockEditorProps(post, template, mode) { const rootLevelPost = mode === 'post-only' || !template ? 'post' : 'template'; const [postBlocks, onInput, onChange] = (0, _coreData.useEntityBlockEditor)('postType', post.type, { id: post.id }); const [templateBlocks, onInputTemplate, onChangeTemplate] = (0, _coreData.useEntityBlockEditor)('postType', template?.type, { id: template?.id }); const maybeNavigationBlocks = (0, _element.useMemo)(() => { if (post.type === 'wp_navigation') { return [(0, _blocks.createBlock)('core/navigation', { ref: post.id, // As the parent editor is locked with `templateLock`, the template locking // must be explicitly "unset" on the block itself to allow the user to modify // the block's content. templateLock: false })]; } }, [post.type, post.id]); // It is important that we don't create a new instance of blocks on every change // We should only create a new instance if the blocks them selves change, not a dependency of them. const blocks = (0, _element.useMemo)(() => { if (maybeNavigationBlocks) { return maybeNavigationBlocks; } if (rootLevelPost === 'template') { return templateBlocks; } return postBlocks; }, [maybeNavigationBlocks, rootLevelPost, templateBlocks, postBlocks]); // Handle fallback to postBlocks outside of the above useMemo, to ensure // that constructed block templates that call `createBlock` are not generated // too frequently. This ensures that clientIds are stable. const disableRootLevelChanges = !!template && mode === 'template-locked' || post.type === 'wp_navigation'; if (disableRootLevelChanges) { return [blocks, noop, noop]; } return [blocks, rootLevelPost === 'post' ? onInput : onInputTemplate, rootLevelPost === 'post' ? onChange : onChangeTemplate]; } /** * This component provides the editor context and manages the state of the block editor. * * @param {Object} props The component props. * @param {Object} props.post The post object. * @param {Object} props.settings The editor settings. * @param {boolean} props.recovery Indicates if the editor is in recovery mode. * @param {Array} props.initialEdits The initial edits for the editor. * @param {Object} props.children The child components. * @param {Object} [props.BlockEditorProviderComponent] The block editor provider component to use. Defaults to ExperimentalBlockEditorProvider. * @param {Object} [props.__unstableTemplate] The template object. * * @example * ```jsx * <ExperimentalEditorProvider * post={ post } * settings={ settings } * recovery={ recovery } * initialEdits={ initialEdits } * __unstableTemplate={ template } * > * { children } * </ExperimentalEditorProvider> * * @return {Object} The rendered ExperimentalEditorProvider component. */ const ExperimentalEditorProvider = exports.ExperimentalEditorProvider = (0, _withRegistryProvider.default)(({ post, settings, recovery, initialEdits, children, BlockEditorProviderComponent = ExperimentalBlockEditorProvider, __unstableTemplate: template }) => { const { editorSettings, selection, isReady, mode, postTypes } = (0, _data.useSelect)(select => { const { getEditorSettings, getEditorSelection, getRenderingMode, __unstableIsEditorReady } = select(_store.store); const { getPostTypes } = select(_coreData.store); return { editorSettings: getEditorSettings(), isReady: __unstableIsEditorReady(), mode: getRenderingMode(), selection: getEditorSelection(), postTypes: getPostTypes({ per_page: -1 }) }; }, []); const shouldRenderTemplate = !!template && mode !== 'post-only'; const rootLevelPost = shouldRenderTemplate ? template : post; const defaultBlockContext = (0, _element.useMemo)(() => { const postContext = {}; // If it is a template, try to inherit the post type from the slug. if (post.type === 'wp_template') { if (!post.is_custom) { const [kind] = post.slug.split('-'); switch (kind) { case 'page': postContext.postType = 'page'; break; case 'single': // Infer the post type from the slug. const postTypesSlugs = postTypes?.map(entity => entity.slug) || []; const match = post.slug.match(`^single-(${postTypesSlugs.join('|')})(?:-.+)?$`); if (match) { postContext.postType = match[1]; } break; } } } else if (!NON_CONTEXTUAL_POST_TYPES.includes(rootLevelPost.type) || shouldRenderTemplate) { postContext.postId = post.id; postContext.postType = post.type; } return { ...postContext, templateSlug: rootLevelPost.type === 'wp_template' ? rootLevelPost.slug : undefined }; }, [shouldRenderTemplate, post.id, post.type, rootLevelPost.type, rootLevelPost.slug, postTypes]); const { id, type } = rootLevelPost; const blockEditorSettings = (0, _useBlockEditorSettings.default)(editorSettings, type, id, mode); const [blocks, onInput, onChange] = useBlockEditorProps(post, template, mode); const { updatePostLock, setupEditor, updateEditorSettings, setCurrentTemplateId, setEditedPost, setRenderingMode } = (0, _lockUnlock.unlock)((0, _data.useDispatch)(_store.store)); const { createWarningNotice } = (0, _data.useDispatch)(_notices.store); // Ideally this should be synced on each change and not just something you do once. (0, _element.useLayoutEffect)(() => { // Assume that we don't need to initialize in the case of an error recovery. if (recovery) { return; } updatePostLock(settings.postLock); setupEditor(post, initialEdits, settings.template); if (settings.autosave) { createWarningNotice((0, _i18n.__)('There is an autosave of this post that is more recent than the version below.'), { id: 'autosave-exists', actions: [{ label: (0, _i18n.__)('View the autosave'), url: settings.autosave.editLink }] }); } }, []); // Synchronizes the active post with the state (0, _element.useEffect)(() => { setEditedPost(post.type, post.id); }, [post.type, post.id, setEditedPost]); // Synchronize the editor settings as they change. (0, _element.useEffect)(() => { updateEditorSettings(settings); }, [settings, updateEditorSettings]); // Synchronizes the active template with the state. (0, _element.useEffect)(() => { setCurrentTemplateId(template?.id); }, [template?.id, setCurrentTemplateId]); // Sets the right rendering mode when loading the editor. (0, _element.useEffect)(() => { var _settings$defaultRend; setRenderingMode((_settings$defaultRend = settings.defaultRenderingMode) !== null && _settings$defaultRend !== void 0 ? _settings$defaultRend : 'post-only'); }, [settings.defaultRenderingMode, setRenderingMode]); (0, _useHideBlocksFromInserter.useHideBlocksFromInserter)(post.type, mode); // Register the editor commands. (0, _commands.default)(); if (!isReady) { return null; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_coreData.EntityProvider, { kind: "root", type: "site", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_coreData.EntityProvider, { kind: "postType", type: post.type, id: post.id, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockContextProvider, { value: defaultBlockContext, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(BlockEditorProviderComponent, { value: blocks, onChange: onChange, onInput: onInput, selection: selection, settings: blockEditorSettings, useSubRegistry: false, children: [children, !settings.__unstableIsPreviewMode && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(PatternsMenuItems, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_templatePartMenuItems.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_contentOnlySettingsMenu.default, {}), mode === 'template-locked' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_disableNonPageContentBlocks.default, {}), type === 'wp_navigation' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_navigationBlockEditingMode.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_globalKeyboardShortcuts.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_keyboardShortcutHelpModal.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockRemovalWarnings.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_startPageOptions.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_startTemplateOptions.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_patternRenameModal.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_patternDuplicateModal.default, {})] })] }) }) }) }); }); /** * This component establishes a new post editing context, and serves as the entry point for a new post editor (or post with template editor). * * It supports a large number of post types, including post, page, templates, * custom post types, patterns, template parts. * * All modification and changes are performed to the `@wordpress/core-data` store. * * @param {Object} props The component props. * @param {Object} [props.post] The post object to edit. This is required. * @param {Object} [props.__unstableTemplate] The template object wrapper the edited post. * This is optional and can only be used when the post type supports templates (like posts and pages). * @param {Object} [props.settings] The settings object to use for the editor. * This is optional and can be used to override the default settings. * @param {Element} [props.children] Children elements for which the BlockEditorProvider context should apply. * This is optional. * * @example * ```jsx * <EditorProvider * post={ post } * settings={ settings } * __unstableTemplate={ template } * > * { children } * </EditorProvider> * ``` * * @return {JSX.Element} The rendered EditorProvider component. */ function EditorProvider(props) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(ExperimentalEditorProvider, { ...props, BlockEditorProviderComponent: _blockEditor.BlockEditorProvider, children: props.children }); } var _default = exports.default = EditorProvider; //# sourceMappingURL=index.js.map