diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index ef5147c35858f..55cd4506a082c 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -50,6 +50,7 @@ import CanvasLoader from '../canvas-loader'; import { unlock } from '../../lock-unlock'; import useEditedEntityRecord from '../use-edited-entity-record'; import PatternModal from '../pattern-modal'; +import PageModal from '../page-modal'; import { POST_TYPE_LABELS, TEMPLATE_POST_TYPE } from '../../utils/constants'; import SiteEditorCanvas from '../block-editor/site-editor-canvas'; import TemplatePartConverter from '../template-part-converter'; @@ -229,6 +230,7 @@ export default function Editor( { isLoading, onClick } ) { ) } + ) } { editorMode === 'text' && isEditMode && ( diff --git a/packages/edit-site/src/components/page-modal/index.js b/packages/edit-site/src/components/page-modal/index.js new file mode 100644 index 0000000000000..0bb77a11ec5f7 --- /dev/null +++ b/packages/edit-site/src/components/page-modal/index.js @@ -0,0 +1,17 @@ +/** + * Internal dependencies + */ +import PageRenameModal from './rename'; + +export const PAGE_MODALS = { + rename: 'edit-site/page-rename', +}; + +export default function PageModal() { + return ( + <> + { /* Possibly more Page related commands needing modals to come, hence this wrapper */ } + + + ); +} diff --git a/packages/edit-site/src/components/page-modal/rename.js b/packages/edit-site/src/components/page-modal/rename.js new file mode 100644 index 0000000000000..f33bebb369337 --- /dev/null +++ b/packages/edit-site/src/components/page-modal/rename.js @@ -0,0 +1,56 @@ +/** + * WordPress dependencies + */ +import { Modal } from '@wordpress/components'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; +import { __ } from '@wordpress/i18n'; +import { store as interfaceStore } from '@wordpress/interface'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { PAGE_MODALS } from './'; +import useEditedEntityRecord from '../use-edited-entity-record'; + +const { RenamePostModalContent } = unlock( editorPrivateApis ); + +export default function PageRenameModal() { + const { postId, postType } = useSelect( ( select ) => { + const { getCurrentPostType, getCurrentPostId } = select( editorStore ); + + return { + postId: getCurrentPostId(), + postType: getCurrentPostType(), + }; + }, [] ); + + const { record: page } = useEditedEntityRecord( postType, postId ); + const { closeModal } = useDispatch( interfaceStore ); + const isActive = useSelect( ( select ) => + select( interfaceStore ).isModalActive( PAGE_MODALS.rename ) + ); + + if ( ! isActive ) { + return null; + } + + return ( + + + + ); +} diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index c6b6d95e57a51..840d79083d264 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -21,6 +21,7 @@ import { privateApis as editorPrivateApis } from '@wordpress/editor'; * Internal dependencies */ import Page from '../page'; +import PageCommandsModal from '../page-modal'; import { default as Link, useLink } from '../routes/link'; import { DEFAULT_VIEWS, @@ -411,6 +412,7 @@ export default function PagePages() { onChangeView={ onChangeView } onSelectionChange={ onSelectionChange } /> + { view?.type !== LAYOUT_LIST && } ); } diff --git a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js index a6ab867d043ec..f4b829f34d7d0 100644 --- a/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js +++ b/packages/edit-site/src/hooks/commands/use-edit-mode-commands.js @@ -32,6 +32,7 @@ import isTemplateRevertable from '../../utils/is-template-revertable'; import { KEYBOARD_SHORTCUT_HELP_MODAL_NAME } from '../../components/keyboard-shortcut-help-modal'; import { PREFERENCES_MODAL_NAME } from '../../components/preferences-modal'; import { PATTERN_MODALS } from '../../components/pattern-modal'; +import { PAGE_MODALS } from '../../components/page-modal'; import { unlock } from '../../lock-unlock'; import { TEMPLATE_POST_TYPE } from '../../utils/constants'; import { useLink } from '../../components/routes/link'; @@ -99,6 +100,45 @@ function usePageContentFocusCommands() { return { isLoading: false, commands }; } +function useManipulateEditedDocumentCommands() { + const { isPage, postId, postType } = useSelect( ( select ) => { + const { isPage: _isPage } = unlock( select( editSiteStore ) ); + const { getCurrentPostType, getCurrentPostId } = select( editorStore ); + + return { + isPage: _isPage(), + postId: getCurrentPostId(), + postType: getCurrentPostType(), + }; + }, [] ); + + const { isLoaded, record } = useEditedEntityRecord( postType, postId ); + const { openModal } = useDispatch( interfaceStore ); + + if ( ! isLoaded ) { + return { isLoading: true, commands: [] }; + } + + const commands = []; + + if ( isPage && !! record ) { + commands.push( { + name: 'core/rename-page', + label: __( 'Rename page' ), + icon: edit, + callback: ( { close } ) => { + openModal( PAGE_MODALS.rename ); + close(); + }, + } ); + } + + return { + isLoading: ! isLoaded, + commands, + }; +} + function useManipulateDocumentCommands() { const { isLoaded, record: template } = useEditedEntityRecord(); const { removeTemplate, revertTemplate } = useDispatch( editSiteStore ); @@ -294,6 +334,12 @@ export function useEditModeCommands() { hook: useManipulateDocumentCommands, } ); + useCommandLoader( { + name: 'core/edit-site/manipulate-edited-document', + hook: useManipulateEditedDocumentCommands, + context: 'site-editor-edit', + } ); + useCommandLoader( { name: 'core/edit-site/patterns', hook: usePatternCommands, diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 7d38fc93e222d..6e38b28ff6051 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -8,16 +8,19 @@ import { decodeEntities } from '@wordpress/html-entities'; import { store as coreStore } from '@wordpress/core-data'; import { __, _n, sprintf } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; -import { useMemo, useState } from '@wordpress/element'; - +import { useMemo } from '@wordpress/element'; import { Button, - TextControl, __experimentalText as Text, __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; +/** + * Internal dependencies + */ +import RenamePostModalContent from './rename-post-modal-content'; + function getItemTitle( item ) { if ( typeof item.title === 'string' ) { return decodeEntities( item.title ); @@ -420,75 +423,7 @@ export const renamePostAction = { isEligible( post ) { return post.status !== 'trash'; }, - RenderModal: ( { items, closeModal } ) => { - const [ item ] = items; - const originalTitle = decodeEntities( - typeof item.title === 'string' ? item.title : item.title.rendered - ); - const [ title, setTitle ] = useState( () => originalTitle ); - const { editEntityRecord, saveEditedEntityRecord } = - useDispatch( coreStore ); - const { createSuccessNotice, createErrorNotice } = - useDispatch( noticesStore ); - - async function onRename( event ) { - event.preventDefault(); - try { - await editEntityRecord( 'postType', item.type, item.id, { - title, - } ); - // Update state before saving rerenders the list. - setTitle( '' ); - closeModal(); - // Persist edited entity. - await saveEditedEntityRecord( 'postType', item.type, item.id, { - throwOnError: true, - } ); - createSuccessNotice( __( 'Name updated' ), { - type: 'snackbar', - } ); - } catch ( error ) { - const errorMessage = - error.message && error.code !== 'unknown_error' - ? error.message - : __( 'An error occurred while updating the name' ); - createErrorNotice( errorMessage, { type: 'snackbar' } ); - } - } - - return ( -
- - - - - - - -
- ); - }, + RenderModal: RenamePostModalContent, }; export function usePostActions( onActionPerformed, actionIds = null ) { diff --git a/packages/editor/src/components/post-actions/rename-post-modal-content.js b/packages/editor/src/components/post-actions/rename-post-modal-content.js new file mode 100644 index 0000000000000..ff77425b22cf6 --- /dev/null +++ b/packages/editor/src/components/post-actions/rename-post-modal-content.js @@ -0,0 +1,86 @@ +/** + * WordPress dependencies + */ +import { + Button, + TextControl, + __experimentalHStack as HStack, + __experimentalVStack as VStack, +} from '@wordpress/components'; +import { store as coreStore } from '@wordpress/core-data'; +import { useDispatch } from '@wordpress/data'; +import { useState } from '@wordpress/element'; +import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; +import { store as noticesStore } from '@wordpress/notices'; + +export default function RenamePostModalContent( { items, closeModal } ) { + const [ item ] = items; + const originalTitle = decodeEntities( + typeof item.title === 'string' ? item.title : item.title.rendered + ); + const [ title, setTitle ] = useState( () => originalTitle ); + const { editEntityRecord, saveEditedEntityRecord } = + useDispatch( coreStore ); + const { createSuccessNotice, createErrorNotice } = + useDispatch( noticesStore ); + + async function onRename( event ) { + event.preventDefault(); + try { + await editEntityRecord( 'postType', item.type, item.id, { + title, + } ); + // Update state before saving rerenders the list. + setTitle( '' ); + closeModal(); + // Persist edited entity. + await saveEditedEntityRecord( 'postType', item.type, item.id, { + throwOnError: true, + } ); + createSuccessNotice( __( 'Name updated' ), { + id: 'page-update', + type: 'snackbar', + } ); + } catch ( error ) { + const errorMessage = + error.message && error.code !== 'unknown_error' + ? error.message + : __( 'An error occurred while updating the name' ); + createErrorNotice( errorMessage, { type: 'snackbar' } ); + } + } + + return ( +
+ + + + + + + +
+ ); +} diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index ea42d6ad5fde5..47719f881e27a 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -18,6 +18,7 @@ import PreviewDropdown from './components/preview-dropdown'; import PreferencesModal from './components/preferences-modal'; import { usePostActions } from './components/post-actions/actions'; import PostCardPanel from './components/post-card-panel'; +import RenamePostModalContent from './components/post-actions/rename-post-modal-content'; export const privateApis = {}; lock( privateApis, { @@ -36,6 +37,7 @@ lock( privateApis, { PreferencesModal, usePostActions, PostCardPanel, + RenamePostModalContent, // This is a temporary private API while we're updating the site editor to use EditorProvider. useBlockEditorSettings,