diff --git a/docs/reference-guides/data/data-core-edit-post.md b/docs/reference-guides/data/data-core-edit-post.md index 1716482d5178c0..40c890748e3199 100644 --- a/docs/reference-guides/data/data-core-edit-post.md +++ b/docs/reference-guides/data/data-core-edit-post.md @@ -476,11 +476,11 @@ _Parameters_ ### switchEditorMode -Triggers an action used to switch editor mode. +Sets the editor mode (for text editing or visual editing). _Parameters_ -- _mode_ `string`: The editor mode. +- _mode_ `'visual'|'text'`: The mode, either 'visual' or 'text'. ### toggleDistractionFree diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index 636ccab4f3c6da..e6423935b6f07f 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -395,7 +395,11 @@ _Returns_ ### switchEditorMode -Undocumented declaration. +Sets the editor mode (for text editing or visual editing). + +_Parameters_ + +- _mode_ `'visual'|'text'`: The mode, either 'visual' or 'text'. ### toggleDistractionFree diff --git a/packages/edit-post/src/components/header/mode-switcher/index.js b/packages/edit-post/src/components/header/mode-switcher/index.js index 1ca01a4b024f81..21ae30a8e8884a 100644 --- a/packages/edit-post/src/components/header/mode-switcher/index.js +++ b/packages/edit-post/src/components/header/mode-switcher/index.js @@ -1,90 +1,40 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; -import { MenuItemsChoice, MenuGroup } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; +import { + privateApis as editorPrivateApis, + store as editorStore, +} from '@wordpress/editor'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; -import { store as editorStore } from '@wordpress/editor'; /** * Internal dependencies */ -import { store as editPostStore } from '../../../store'; +import { unlock } from '../../../lock-unlock'; -/** - * Set of available mode options. - * - * @type {Array} - */ -const MODES = [ - { - value: 'visual', - label: __( 'Visual editor' ), - }, - { - value: 'text', - label: __( 'Code editor' ), - }, -]; +const { ModeSwitcher: EditorModeSwitcher } = unlock( editorPrivateApis ); function ModeSwitcher() { - const { shortcut, isRichEditingEnabled, isCodeEditingEnabled, mode } = - useSelect( - ( select ) => ( { - shortcut: select( - keyboardShortcutsStore - ).getShortcutRepresentation( 'core/edit-post/toggle-mode' ), - isRichEditingEnabled: - select( editorStore ).getEditorSettings() - .richEditingEnabled, - isCodeEditingEnabled: - select( editorStore ).getEditorSettings() - .codeEditingEnabled, - mode: select( editPostStore ).getEditorMode(), - } ), - [] - ); - const { switchEditorMode } = useDispatch( editPostStore ); - - let selectedMode = mode; - if ( ! isRichEditingEnabled && mode === 'visual' ) { - selectedMode = 'text'; - } - if ( ! isCodeEditingEnabled && mode === 'text' ) { - selectedMode = 'visual'; - } - - const choices = MODES.map( ( choice ) => { - if ( ! isCodeEditingEnabled && choice.value === 'text' ) { - choice = { - ...choice, - disabled: true, - }; - } - if ( ! isRichEditingEnabled && choice.value === 'visual' ) { - choice = { - ...choice, - disabled: true, - info: __( - 'You can enable the visual editor in your profile settings.' - ), - }; - } - if ( choice.value !== selectedMode && ! choice.disabled ) { - return { ...choice, shortcut }; - } - return choice; - } ); + const { shortcut, isRichEditingEnabled, isCodeEditingEnabled } = useSelect( + ( select ) => ( { + shortcut: select( + keyboardShortcutsStore + ).getShortcutRepresentation( 'core/edit-post/toggle-mode' ), + isRichEditingEnabled: + select( editorStore ).getEditorSettings().richEditingEnabled, + isCodeEditingEnabled: + select( editorStore ).getEditorSettings().codeEditingEnabled, + } ), + [] + ); return ( - - - + ); } diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js index a1246b4f59928c..0aca86f9ae2f71 100644 --- a/packages/edit-post/src/store/actions.js +++ b/packages/edit-post/src/store/actions.js @@ -5,9 +5,7 @@ import { __ } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; import { store as interfaceStore } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; -import { speak } from '@wordpress/a11y'; import { store as noticesStore } from '@wordpress/notices'; -import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as editorStore } from '@wordpress/editor'; import deprecated from '@wordpress/deprecated'; import { addFilter } from '@wordpress/hooks'; @@ -188,33 +186,14 @@ export const toggleFeature = .toggle( 'core/edit-post', feature ); /** - * Triggers an action used to switch editor mode. + * Sets the editor mode (for text editing or visual editing). * - * @param {string} mode The editor mode. + * @param {'visual'|'text'} mode The mode, either 'visual' or 'text'. */ export const switchEditorMode = ( mode ) => - ( { dispatch, registry } ) => { - registry.dispatch( preferencesStore ).set( 'core', 'editorMode', mode ); - - // Unselect blocks when we switch to the code editor. - if ( mode !== 'visual' ) { - registry.dispatch( blockEditorStore ).clearSelectedBlock(); - } - - if ( - mode === 'text' && - registry.select( preferencesStore ).get( 'core', 'distractionFree' ) - ) { - dispatch.toggleDistractionFree(); - } - - const message = - mode === 'visual' - ? __( 'Visual editor selected' ) - : __( 'Code editor selected' ); - speak( message, 'assertive' ); - }; + ( { registry } ) => + registry.dispatch( editorStore ).setEditorMode( mode ); /** * Triggers an action object used to toggle a plugin name flag. diff --git a/packages/edit-site/src/components/header-edit-mode/mode-switcher/index.js b/packages/edit-site/src/components/header-edit-mode/mode-switcher/index.js index 2c27444f669c03..68614a38e50dba 100644 --- a/packages/edit-site/src/components/header-edit-mode/mode-switcher/index.js +++ b/packages/edit-site/src/components/header-edit-mode/mode-switcher/index.js @@ -1,60 +1,27 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; -import { MenuItemsChoice, MenuGroup } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; /** * Internal dependencies */ -import { store as editSiteStore } from '../../../store'; +import { unlock } from '../../../lock-unlock'; -/** - * Set of available mode options. - * - * @type {Array} - */ -const MODES = [ - { - value: 'visual', - label: __( 'Visual editor' ), - }, - { - value: 'text', - label: __( 'Code editor' ), - }, -]; +const { ModeSwitcher: EditorModeSwitcher } = unlock( editorPrivateApis ); function ModeSwitcher() { - const { shortcut, mode } = useSelect( - ( select ) => ( { - shortcut: select( - keyboardShortcutsStore - ).getShortcutRepresentation( 'core/edit-site/toggle-mode' ), - mode: select( editSiteStore ).getEditorMode(), - } ), + const shortcut = useSelect( + ( select ) => + select( keyboardShortcutsStore ).getShortcutRepresentation( + 'core/edit-site/toggle-mode' + ), [] ); - const { switchEditorMode } = useDispatch( editSiteStore ); - const choices = MODES.map( ( choice ) => { - if ( choice.value !== mode ) { - return { ...choice, shortcut }; - } - return choice; - } ); - - return ( - - - - ); + return ; } export default ModeSwitcher; diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index 728081bf2fc0f4..7cf114664319e0 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -11,7 +11,6 @@ import { store as coreStore } from '@wordpress/core-data'; import { store as interfaceStore } from '@wordpress/interface'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as editorStore } from '@wordpress/editor'; -import { speak } from '@wordpress/a11y'; import { store as preferencesStore } from '@wordpress/preferences'; /** @@ -500,30 +499,15 @@ export const closeGeneralSidebar = .disableComplementaryArea( editSiteStoreName ); }; +/** + * Sets the editor mode (for text editing or visual editing). + * + * @param {'visual'|'text'} mode The mode, either 'visual' or 'text'. + */ export const switchEditorMode = ( mode ) => - ( { dispatch, registry } ) => { - registry - .dispatch( 'core/preferences' ) - .set( 'core', 'editorMode', mode ); - - // Unselect blocks when we switch to a non visual mode. - if ( mode !== 'visual' ) { - registry.dispatch( blockEditorStore ).clearSelectedBlock(); - } - - if ( mode === 'visual' ) { - speak( __( 'Visual editor selected' ), 'assertive' ); - } else if ( mode === 'text' ) { - const isDistractionFree = registry - .select( preferencesStore ) - .get( 'core', 'distractionFree' ); - if ( isDistractionFree ) { - dispatch.toggleDistractionFree(); - } - speak( __( 'Code editor selected' ), 'assertive' ); - } - }; + ( { registry } ) => + registry.dispatch( editorStore ).setEditorMode( mode ); /** * Sets whether or not the editor allows only page content to be edited. diff --git a/packages/editor/src/components/mode-switcher/index.js b/packages/editor/src/components/mode-switcher/index.js new file mode 100644 index 00000000000000..0d0dd9fd1244cb --- /dev/null +++ b/packages/editor/src/components/mode-switcher/index.js @@ -0,0 +1,87 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { MenuItemsChoice, MenuGroup } from '@wordpress/components'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as preferencesStore } from '@wordpress/preferences'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +/** + * Set of available mode options. + * + * @type {Array} + */ +const MODES = [ + { + value: 'visual', + label: __( 'Visual editor' ), + }, + { + value: 'text', + label: __( 'Code editor' ), + }, +]; + +function ModeSwitcher( { + shortcut, + isCodeEditingEnabled = true, + isRichEditingEnabled = true, +} ) { + const { mode } = useSelect( + ( select ) => ( { + mode: + select( preferencesStore ).get( 'core', 'editorMode' ) ?? + 'visual', + } ), + [] + ); + const { setEditorMode } = unlock( useDispatch( editorStore ) ); + + let selectedMode = mode; + if ( ! isRichEditingEnabled && mode === 'visual' ) { + selectedMode = 'text'; + } + if ( ! isCodeEditingEnabled && mode === 'text' ) { + selectedMode = 'visual'; + } + + const choices = MODES.map( ( choice ) => { + if ( ! isCodeEditingEnabled && choice.value === 'text' ) { + choice = { + ...choice, + disabled: true, + }; + } + if ( ! isRichEditingEnabled && choice.value === 'visual' ) { + choice = { + ...choice, + disabled: true, + info: __( + 'You can enable the visual editor in your profile settings.' + ), + }; + } + if ( choice.value !== selectedMode && ! choice.disabled ) { + return { ...choice, shortcut }; + } + return choice; + } ); + + return ( + + + + ); +} + +export default ModeSwitcher; diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index 16c27b1b57c193..061393acab1ebe 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -10,6 +10,7 @@ import useBlockEditorSettings from './components/provider/use-block-editor-setti import DocumentTools from './components/document-tools'; import InserterSidebar from './components/inserter-sidebar'; import ListViewSidebar from './components/list-view-sidebar'; +import ModeSwitcher from './components/mode-switcher'; import PluginPostExcerpt from './components/post-excerpt/plugin'; import PostPanelRow from './components/post-panel-row'; import PostViewLink from './components/post-view-link'; @@ -25,6 +26,7 @@ lock( privateApis, { EntitiesSavedStatesExtensible, InserterSidebar, ListViewSidebar, + ModeSwitcher, PluginPostExcerpt, PostPanelRow, PostViewLink, diff --git a/packages/editor/src/store/private-actions.js b/packages/editor/src/store/private-actions.js index 936d0bd5bf4471..4620d151ed047d 100644 --- a/packages/editor/src/store/private-actions.js +++ b/packages/editor/src/store/private-actions.js @@ -1,6 +1,8 @@ /** * WordPress dependencies */ +import { speak } from '@wordpress/a11y'; +import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; import { __ } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; @@ -109,3 +111,33 @@ export const hideBlockTypes = .dispatch( preferencesStore ) .set( 'core', 'hiddenBlockTypes', [ ...mergedBlockNames ] ); }; + +/** + * Sets the editor mode (for text editing or visual editing). + * + * @param {'visual'|'text'} mode The mode, either 'visual' or 'text'. + */ +export const setEditorMode = + ( mode ) => + ( { dispatch, registry } ) => { + registry + .dispatch( 'core/preferences' ) + .set( 'core', 'editorMode', mode ); + + // Unselect blocks when we switch to a non visual mode. + if ( mode !== 'visual' ) { + registry.dispatch( blockEditorStore ).clearSelectedBlock(); + } + + if ( mode === 'visual' ) { + speak( __( 'Visual editor selected' ), 'assertive' ); + } else if ( mode === 'text' ) { + const isDistractionFree = registry + .select( preferencesStore ) + .get( 'core', 'distractionFree' ); + if ( isDistractionFree ) { + dispatch.toggleDistractionFree(); + } + speak( __( 'Code editor selected' ), 'assertive' ); + } + };