UNPKG

@wordpress/editor

Version:
289 lines (276 loc) 8.48 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { InterfaceSkeleton, ComplementaryArea } from '@wordpress/interface'; import { useSelect, useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { store as preferencesStore } from '@wordpress/preferences'; import { BlockBreadcrumb, BlockToolbar } from '@wordpress/block-editor'; import { useViewportMatch } from '@wordpress/compose'; import { useState, useCallback } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; import { InlineNotices } from '@wordpress/notices'; /** * Internal dependencies */ import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; import TemplateValidationNotice from '../template-validation-notice'; import Header from '../header'; import InserterSidebar from '../inserter-sidebar'; import ListViewSidebar from '../list-view-sidebar'; import { RevisionsHeader, RevisionsCanvas } from '../post-revisions-preview'; import { CollaboratorsOverlay } from '../collaborators-overlay'; import { useCollaboratorNotifications } from '../collaborators-presence/use-collaborator-notifications'; import SavePublishPanels from '../save-publish-panels'; import TextEditor from '../text-editor'; import VisualEditor from '../visual-editor'; import StylesCanvas from '../styles-canvas'; import { MediaPreview } from '../media'; const interfaceLabels = { /* translators: accessibility text for the editor top bar landmark region. */ header: __( 'Editor top bar' ), /* translators: accessibility text for the editor content landmark region. */ body: __( 'Editor content' ), /* translators: accessibility text for the editor settings landmark region. */ sidebar: __( 'Editor settings' ), /* translators: accessibility text for the editor publish landmark region. */ actions: __( 'Editor publish' ), /* translators: accessibility text for the editor footer landmark region. */ footer: __( 'Editor footer' ), }; const Notices = () => ( <InlineNotices pinnedNoticesClassName="editor-notices__pinned" dismissibleNoticesClassName="editor-notices__dismissible" > <TemplateValidationNotice /> </InlineNotices> ); export default function EditorInterface( { className, children, forceIsDirty, contentRef, disableIframe, autoFocus, customSaveButton, customSavePanel, forceDisableBlockTools, iframeProps, } ) { const { mode, postId, postType, isAttachment, isInserterOpened, isListViewOpened, isDistractionFree, isPreviewMode, showBlockBreadcrumbs, postTypeLabel, stylesPath, showStylebook, isRevisionsMode, showDiff, } = useSelect( ( select ) => { const { get } = select( preferencesStore ); const { getEditorSettings, getPostTypeLabel, getCurrentPostType, getCurrentPostId, } = select( editorStore ); const { getStylesPath, getShowStylebook, isRevisionsMode: _isRevisionsMode, isShowingRevisionDiff, } = unlock( select( editorStore ) ); const editorSettings = getEditorSettings(); let _mode = select( editorStore ).getEditorMode(); if ( ! editorSettings.richEditingEnabled && _mode === 'visual' ) { _mode = 'text'; } if ( ! editorSettings.codeEditingEnabled && _mode === 'text' ) { _mode = 'visual'; } return { mode: _mode, postId: getCurrentPostId(), postType: getCurrentPostType(), isInserterOpened: select( editorStore ).isInserterOpened(), isListViewOpened: select( editorStore ).isListViewOpened(), isDistractionFree: get( 'core', 'distractionFree' ), isPreviewMode: editorSettings.isPreviewMode, showBlockBreadcrumbs: get( 'core', 'showBlockBreadcrumbs' ), postTypeLabel: getPostTypeLabel(), stylesPath: getStylesPath(), showStylebook: getShowStylebook(), isAttachment: getCurrentPostType() === 'attachment' && window?.__experimentalMediaEditor, isRevisionsMode: _isRevisionsMode(), showDiff: isShowingRevisionDiff(), }; }, [] ); const { setShowRevisionDiff } = unlock( useDispatch( editorStore ) ); // Runs unconditionally so join/leave/save notifications are dispatched // regardless of viewport width or whether the header centre area is visible. useCollaboratorNotifications( postId, postType ); const isLargeViewport = useViewportMatch( 'medium' ); const secondarySidebarLabel = isListViewOpened ? __( 'Document Overview' ) : __( 'Block Library' ); const shouldShowMediaEditor = !! isAttachment; const shouldShowStylesCanvas = ! isAttachment && ( showStylebook || stylesPath?.startsWith( '/revisions' ) ); const shouldShowBlockEditor = ! shouldShowMediaEditor && ! shouldShowStylesCanvas; // Local state for save panel. // Note 'truthy' callback implies an open panel. const [ entitiesSavedStatesCallback, setEntitiesSavedStatesCallback ] = useState( false ); const closeEntitiesSavedStates = useCallback( ( arg ) => { if ( typeof entitiesSavedStatesCallback === 'function' ) { entitiesSavedStatesCallback( arg ); } setEntitiesSavedStatesCallback( false ); }, [ entitiesSavedStatesCallback ] ); // When in revisions mode, render the revisions interface. if ( isRevisionsMode ) { return ( <InterfaceSkeleton className={ clsx( 'editor-editor-interface', className ) } labels={ interfaceLabels } header={ <RevisionsHeader showDiff={ showDiff } onToggleDiff={ () => setShowRevisionDiff( ! showDiff ) } /> } content={ <RevisionsCanvas /> } sidebar={ <ComplementaryArea.Slot scope="core" /> } /> ); } return ( <InterfaceSkeleton isDistractionFree={ isDistractionFree } className={ clsx( 'editor-editor-interface', className, { 'is-entity-save-view-open': !! entitiesSavedStatesCallback, 'is-distraction-free': isDistractionFree && ! isPreviewMode, } ) } labels={ { ...interfaceLabels, secondarySidebar: secondarySidebarLabel, } } header={ ! isPreviewMode && ( <Header forceIsDirty={ forceIsDirty } setEntitiesSavedStatesCallback={ setEntitiesSavedStatesCallback } customSaveButton={ customSaveButton } forceDisableBlockTools={ forceDisableBlockTools } /> ) } editorNotices={ <Notices /> } secondarySidebar={ ! isAttachment && ! isPreviewMode && mode === 'visual' && ( ( isInserterOpened && <InserterSidebar /> ) || ( isListViewOpened && <ListViewSidebar /> ) ) } sidebar={ ! isPreviewMode && ! isDistractionFree && <ComplementaryArea.Slot scope="core" /> } content={ <> { ! isDistractionFree && ! isPreviewMode && <Notices /> } { shouldShowMediaEditor && ( <MediaPreview { ...iframeProps } /> ) } { shouldShowStylesCanvas && <StylesCanvas /> } { shouldShowBlockEditor && ( <> { ! isPreviewMode && mode === 'text' && ( <TextEditor // We should auto-focus the canvas (title) on load. // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus={ autoFocus } /> ) } { ! isPreviewMode && ! isLargeViewport && mode === 'visual' && ( <BlockToolbar hideDragHandle /> ) } { ( isPreviewMode || mode === 'visual' ) && ( <VisualEditor contentRef={ contentRef } disableIframe={ disableIframe } // We should auto-focus the canvas (title) on load. // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus={ autoFocus } iframeProps={ iframeProps } /> ) } { children } <CollaboratorsOverlay postId={ postId } postType={ postType } /> </> ) } </> } footer={ ! isPreviewMode && ! isDistractionFree && isLargeViewport && showBlockBreadcrumbs && mode === 'visual' && ( <BlockBreadcrumb rootLabelText={ postTypeLabel ? decodeEntities( postTypeLabel ) : undefined } /> ) } actions={ ! isPreviewMode ? customSavePanel || ( <SavePublishPanels closeEntitiesSavedStates={ closeEntitiesSavedStates } isEntitiesSavedStatesOpen={ entitiesSavedStatesCallback } setEntitiesSavedStatesCallback={ setEntitiesSavedStatesCallback } forceIsDirtyPublishPanel={ forceIsDirty } /> ) : undefined } /> ); }