From 31e093d2ff9736269f4916a666755adc3c1106c2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 5 Aug 2025 10:43:51 +0100 Subject: [PATCH 01/15] Restrict formatting controls in write mode (contentOnly) - Add useBlockEditingMode() hook to detect write mode - In contentOnly mode, only show bold and italic controls - Remove link and unknown formats from write mode toolbar - Hide 'More' dropdown with additional formatting options in write mode - Keep write mode simple and focused on essential content editing --- .../rich-text/format-toolbar/index.js | 91 +++++++++++-------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/format-toolbar/index.js b/packages/block-editor/src/components/rich-text/format-toolbar/index.js index 811164b0751c5f..51b3bb0c45d1f9 100644 --- a/packages/block-editor/src/components/rich-text/format-toolbar/index.js +++ b/packages/block-editor/src/components/rich-text/format-toolbar/index.js @@ -14,59 +14,74 @@ import { chevronDown } from '@wordpress/icons'; * Internal dependencies */ import { orderBy } from '../../../utils/sorting'; +import { useBlockEditingMode } from '../../block-editing-mode'; const POPOVER_PROPS = { placement: 'bottom-start', }; const FormatToolbar = () => { + const blockEditingMode = useBlockEditingMode(); + const isContentOnlyMode = blockEditingMode === 'contentOnly'; + + // In contentOnly mode, only show essential formatting controls + const primaryFormats = isContentOnlyMode + ? [ 'bold', 'italic', 'link' ] + : [ 'bold', 'italic', 'link', 'unknown' ]; + return ( <> - { [ 'bold', 'italic', 'link', 'unknown' ].map( ( format ) => ( + { primaryFormats.map( ( format ) => ( ) ) } - - { ( fills ) => { - if ( ! fills.length ) { - return null; - } + { ! isContentOnlyMode && ( + + { ( fills ) => { + if ( ! fills.length ) { + return null; + } - const allProps = fills.map( ( [ { props } ] ) => props ); - const hasActive = allProps.some( - ( { isActive } ) => isActive - ); + const allProps = fills.map( + ( [ { props } ] ) => props + ); + const hasActive = allProps.some( + ( { isActive } ) => isActive + ); - return ( - - { ( toggleProps ) => ( - props ), - 'title' - ) } - popoverProps={ POPOVER_PROPS } - /> - ) } - - ); - } } - + return ( + + { ( toggleProps ) => ( + props + ), + 'title' + ) } + popoverProps={ POPOVER_PROPS } + /> + ) } + + ); + } } + + ) } ); }; From 6bebca26e99d3684b43c06be876cbca5fe9b77a4 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 5 Aug 2025 16:03:09 +0100 Subject: [PATCH 02/15] Update format toolbar to use correct Write Mode pattern --- .../components/rich-text/format-toolbar/index.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/format-toolbar/index.js b/packages/block-editor/src/components/rich-text/format-toolbar/index.js index 51b3bb0c45d1f9..25fa02b4394f93 100644 --- a/packages/block-editor/src/components/rich-text/format-toolbar/index.js +++ b/packages/block-editor/src/components/rich-text/format-toolbar/index.js @@ -15,6 +15,8 @@ import { chevronDown } from '@wordpress/icons'; */ import { orderBy } from '../../../utils/sorting'; import { useBlockEditingMode } from '../../block-editing-mode'; +import { useSelect } from '@wordpress/data'; +import { store as blockEditorStore } from '../../../store'; const POPOVER_PROPS = { placement: 'bottom-start', @@ -22,10 +24,15 @@ const POPOVER_PROPS = { const FormatToolbar = () => { const blockEditingMode = useBlockEditingMode(); + const isNavigationMode = useSelect( + ( select ) => select( blockEditorStore ).isNavigationMode(), + [] + ); const isContentOnlyMode = blockEditingMode === 'contentOnly'; + const isWriteMode = isNavigationMode && isContentOnlyMode; - // In contentOnly mode, only show essential formatting controls - const primaryFormats = isContentOnlyMode + // In write mode, only show essential formatting controls + const primaryFormats = isWriteMode ? [ 'bold', 'italic', 'link' ] : [ 'bold', 'italic', 'link', 'unknown' ]; @@ -37,7 +44,7 @@ const FormatToolbar = () => { key={ format } /> ) ) } - { ! isContentOnlyMode && ( + { ! isWriteMode && ( { ( fills ) => { if ( ! fills.length ) { From a32322bdb73cd8c84ddf147bb0de76a6fe6bdec7 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 17:02:19 +0100 Subject: [PATCH 03/15] Add write mode format filtering with essential flag - Add withWriteModeFilter HOC to filter format edit components in write mode - Add essential property to format registrations (default: false) - Mark core formats (bold, italic, link, strikethrough) as essential - Apply HOC in FormatEdit component to filter non-essential formats - Maintain backward compatibility for existing formats - Enable third-party plugins to opt formats into write mode via essential flag This allows write mode to show only essential formatting controls while maintaining full functionality in default mode. --- .../src/components/rich-text/format-edit.js | 27 +++++-- .../rich-text/format-toolbar/index.js | 80 +++++++++---------- .../rich-text/with-write-mode-filter.js | 38 +++++++++ packages/format-library/src/bold/index.js | 1 + packages/format-library/src/code/index.js | 1 + packages/format-library/src/italic/index.js | 1 + packages/format-library/src/link/index.js | 1 + .../format-library/src/strikethrough/index.js | 1 + .../format-library/src/underline/index.js | 1 + 9 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 packages/block-editor/src/components/rich-text/with-write-mode-filter.js diff --git a/packages/block-editor/src/components/rich-text/format-edit.js b/packages/block-editor/src/components/rich-text/format-edit.js index a70b9f8f778815..2b7613a622e596 100644 --- a/packages/block-editor/src/components/rich-text/format-edit.js +++ b/packages/block-editor/src/components/rich-text/format-edit.js @@ -8,8 +8,8 @@ import { useContext, useMemo } from '@wordpress/element'; * Internal dependencies */ import BlockContext from '../block-context'; - -const DEFAULT_BLOCK_CONTEXT = {}; +import { blockEditingModeKey } from '../block-edit/context'; +import withWriteModeFilter from './with-write-mode-filter'; export const usesContextKey = Symbol( 'usesContext' ); @@ -24,19 +24,32 @@ function Edit( { onChange, onFocus, value, forwardedRef, settings } ) { // Assign context values using the block type's declared context needs. const context = useMemo( () => { - return usesContext - ? Object.fromEntries( + // Always include blockEditingMode in context for write mode filtering + const baseContext = { + blockEditingMode: blockContext[ blockEditingModeKey ], + }; + + if ( usesContext ) { + return { + ...baseContext, + ...Object.fromEntries( Object.entries( blockContext ).filter( ( [ key ] ) => usesContext.includes( key ) ) - ) - : DEFAULT_BLOCK_CONTEXT; + ), + }; + } + + return baseContext; }, [ usesContext, blockContext ] ); if ( ! EditFunction ) { return null; } + // Apply the write mode filter HOC + const FilteredEditFunction = withWriteModeFilter( EditFunction, settings ); + const activeFormat = getActiveFormat( value, name ); const isActive = activeFormat !== undefined; const activeObject = getActiveObject( value ); @@ -44,7 +57,7 @@ function Edit( { onChange, onFocus, value, forwardedRef, settings } ) { activeObject !== undefined && activeObject.type === name; return ( - { key={ format } /> ) ) } - { ! isWriteMode && ( - - { ( fills ) => { - if ( ! fills.length ) { - return null; - } + + { ( fills ) => { + if ( ! fills.length ) { + return null; + } - const allProps = fills.map( - ( [ { props } ] ) => props - ); - const hasActive = allProps.some( - ( { isActive } ) => isActive - ); + const allProps = fills.map( ( [ { props } ] ) => props ); + const hasActive = allProps.some( + ( { isActive } ) => isActive + ); - return ( - - { ( toggleProps ) => ( - props - ), - 'title' - ) } - popoverProps={ POPOVER_PROPS } - /> - ) } - - ); - } } - - ) } + return ( + + { ( toggleProps ) => ( + props ), + 'title' + ) } + popoverProps={ POPOVER_PROPS } + /> + ) } + + ); + } } + ); }; diff --git a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js new file mode 100644 index 00000000000000..02299ca5830f67 --- /dev/null +++ b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js @@ -0,0 +1,38 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; +import { useBlockEditingMode } from '../block-editing-mode'; + +/** + * Higher-Order Component that filters format edit components based on write mode. + * + * @param {Function} WrappedComponent The format edit component to wrap + * @param {Object} formatSettings The format settings including essential flag + * @return {Function} The wrapped component + */ +const withWriteModeFilter = ( WrappedComponent, formatSettings ) => { + return ( props ) => { + const blockEditingMode = useBlockEditingMode(); + const isNavigationMode = useSelect( + ( select ) => select( blockEditorStore ).isNavigationMode(), + [] + ); + const isContentOnlyMode = blockEditingMode === 'contentOnly'; + const isWriteMode = isNavigationMode && isContentOnlyMode; + + // In write mode, only show essential formats + if ( isWriteMode && ! formatSettings?.essential ) { + return null; + } + + return ; + }; +}; + +export default withWriteModeFilter; diff --git a/packages/format-library/src/bold/index.js b/packages/format-library/src/bold/index.js index 98f5b4e3a9542b..5a282765862d9b 100644 --- a/packages/format-library/src/bold/index.js +++ b/packages/format-library/src/bold/index.js @@ -18,6 +18,7 @@ export const bold = { title, tagName: 'strong', className: null, + essential: true, edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/code/index.js b/packages/format-library/src/code/index.js index 27a99ebc989e21..40dd144500b309 100644 --- a/packages/format-library/src/code/index.js +++ b/packages/format-library/src/code/index.js @@ -17,6 +17,7 @@ export const code = { title, tagName: 'code', className: null, + essential: false, __unstableInputRule( value ) { const BACKTICK = '`'; const { start, text } = value; diff --git a/packages/format-library/src/italic/index.js b/packages/format-library/src/italic/index.js index 7287cff6546d29..95e0b4187ce563 100644 --- a/packages/format-library/src/italic/index.js +++ b/packages/format-library/src/italic/index.js @@ -18,6 +18,7 @@ export const italic = { title, tagName: 'em', className: null, + essential: true, edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/link/index.js b/packages/format-library/src/link/index.js index 508ed4655a6695..bbc7e5b658dd25 100644 --- a/packages/format-library/src/link/index.js +++ b/packages/format-library/src/link/index.js @@ -228,6 +228,7 @@ export const link = { target: 'target', rel: 'rel', }, + essential: true, __unstablePasteRule( value, { html, plainText } ) { const pastedText = ( html || plainText ) .replace( /<[^>]+>/g, '' ) diff --git a/packages/format-library/src/strikethrough/index.js b/packages/format-library/src/strikethrough/index.js index 56dc81c9c66afb..f81fa985ff5c08 100644 --- a/packages/format-library/src/strikethrough/index.js +++ b/packages/format-library/src/strikethrough/index.js @@ -17,6 +17,7 @@ export const strikethrough = { title, tagName: 's', className: null, + essential: true, edit( { isActive, value, onChange, onFocus } ) { function onClick() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/underline/index.js b/packages/format-library/src/underline/index.js index 90d7c5852214e3..ac09b7af04b565 100644 --- a/packages/format-library/src/underline/index.js +++ b/packages/format-library/src/underline/index.js @@ -19,6 +19,7 @@ export const underline = { attributes: { style: 'style', }, + essential: false, edit( { value, onChange } ) { const onToggle = () => { onChange( From 4faecc82e1bd87aa5486a04ce84a748c06ae3b6e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 17:06:07 +0100 Subject: [PATCH 04/15] Mark strikethrough as non-essential again --- packages/format-library/src/strikethrough/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/format-library/src/strikethrough/index.js b/packages/format-library/src/strikethrough/index.js index f81fa985ff5c08..65eac07cc94c38 100644 --- a/packages/format-library/src/strikethrough/index.js +++ b/packages/format-library/src/strikethrough/index.js @@ -17,7 +17,7 @@ export const strikethrough = { title, tagName: 's', className: null, - essential: true, + essential: false, edit( { isActive, value, onChange, onFocus } ) { function onClick() { onChange( toggleFormat( value, { type: name, title } ) ); From af68b521eb26feaa5805379ef4edc6d4488d10bf Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 17:49:09 +0100 Subject: [PATCH 05/15] Restore changes to format edit --- .../src/components/rich-text/format-edit.js | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/format-edit.js b/packages/block-editor/src/components/rich-text/format-edit.js index 2b7613a622e596..20d13c1d3f189e 100644 --- a/packages/block-editor/src/components/rich-text/format-edit.js +++ b/packages/block-editor/src/components/rich-text/format-edit.js @@ -8,9 +8,10 @@ import { useContext, useMemo } from '@wordpress/element'; * Internal dependencies */ import BlockContext from '../block-context'; -import { blockEditingModeKey } from '../block-edit/context'; import withWriteModeFilter from './with-write-mode-filter'; +const DEFAULT_BLOCK_CONTEXT = {}; + export const usesContextKey = Symbol( 'usesContext' ); function Edit( { onChange, onFocus, value, forwardedRef, settings } ) { @@ -24,23 +25,13 @@ function Edit( { onChange, onFocus, value, forwardedRef, settings } ) { // Assign context values using the block type's declared context needs. const context = useMemo( () => { - // Always include blockEditingMode in context for write mode filtering - const baseContext = { - blockEditingMode: blockContext[ blockEditingModeKey ], - }; - - if ( usesContext ) { - return { - ...baseContext, - ...Object.fromEntries( + return usesContext + ? Object.fromEntries( Object.entries( blockContext ).filter( ( [ key ] ) => usesContext.includes( key ) ) - ), - }; - } - - return baseContext; + ) + : DEFAULT_BLOCK_CONTEXT; }, [ usesContext, blockContext ] ); if ( ! EditFunction ) { From bb7b3215aa6668f70b51498e96842155750cf1cd Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 17:51:31 +0100 Subject: [PATCH 06/15] Tidy changes to toolbar --- .../components/rich-text/format-toolbar/index.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/format-toolbar/index.js b/packages/block-editor/src/components/rich-text/format-toolbar/index.js index aa0a499b194f05..5db4729921891e 100644 --- a/packages/block-editor/src/components/rich-text/format-toolbar/index.js +++ b/packages/block-editor/src/components/rich-text/format-toolbar/index.js @@ -14,27 +14,14 @@ import { chevronDown } from '@wordpress/icons'; * Internal dependencies */ import { orderBy } from '../../../utils/sorting'; -import { useBlockEditingMode } from '../../block-editing-mode'; -import { useSelect } from '@wordpress/data'; -import { store as blockEditorStore } from '../../../store'; const POPOVER_PROPS = { placement: 'bottom-start', }; const FormatToolbar = () => { - const blockEditingMode = useBlockEditingMode(); - const isNavigationMode = useSelect( - ( select ) => select( blockEditorStore ).isNavigationMode(), - [] - ); - const isContentOnlyMode = blockEditingMode === 'contentOnly'; - const isWriteMode = isNavigationMode && isContentOnlyMode; - // In write mode, only show essential formatting controls - const primaryFormats = isWriteMode - ? [ 'bold', 'italic', 'link' ] - : [ 'bold', 'italic', 'link', 'unknown' ]; + const primaryFormats = [ 'bold', 'italic', 'link', 'unknown' ]; return ( <> From f4ba923a5931075be2eb62a7b4caa1c3bfb221ae Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 17:52:29 +0100 Subject: [PATCH 07/15] Restore toolbar to original --- .../src/components/rich-text/format-toolbar/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/format-toolbar/index.js b/packages/block-editor/src/components/rich-text/format-toolbar/index.js index 5db4729921891e..811164b0751c5f 100644 --- a/packages/block-editor/src/components/rich-text/format-toolbar/index.js +++ b/packages/block-editor/src/components/rich-text/format-toolbar/index.js @@ -20,12 +20,9 @@ const POPOVER_PROPS = { }; const FormatToolbar = () => { - // In write mode, only show essential formatting controls - const primaryFormats = [ 'bold', 'italic', 'link', 'unknown' ]; - return ( <> - { primaryFormats.map( ( format ) => ( + { [ 'bold', 'italic', 'link', 'unknown' ].map( ( format ) => ( Date: Wed, 6 Aug 2025 18:01:09 +0100 Subject: [PATCH 08/15] Add perf opt --- .../rich-text/with-write-mode-filter.js | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js index 02299ca5830f67..87c8437893fb04 100644 --- a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js +++ b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; +import { memo, useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -17,22 +18,39 @@ import { useBlockEditingMode } from '../block-editing-mode'; * @return {Function} The wrapped component */ const withWriteModeFilter = ( WrappedComponent, formatSettings ) => { - return ( props ) => { + // Early return if format is essential - no filtering needed + if ( formatSettings?.essential ) { + return WrappedComponent; + } + + // Memoize the wrapped component to prevent unnecessary re-renders + const FilteredComponent = memo( ( props ) => { const blockEditingMode = useBlockEditingMode(); const isNavigationMode = useSelect( ( select ) => select( blockEditorStore ).isNavigationMode(), [] ); - const isContentOnlyMode = blockEditingMode === 'contentOnly'; - const isWriteMode = isNavigationMode && isContentOnlyMode; + + // Memoize the write mode calculation + const isWriteMode = useMemo( () => { + const isContentOnlyMode = blockEditingMode === 'contentOnly'; + return isNavigationMode && isContentOnlyMode; + }, [ isNavigationMode, blockEditingMode ] ); // In write mode, only show essential formats - if ( isWriteMode && ! formatSettings?.essential ) { + if ( isWriteMode ) { return null; } return ; - }; + } ); + + // Set display name for debugging + FilteredComponent.displayName = `withWriteModeFilter(${ + WrappedComponent.displayName || WrappedComponent.name || 'Component' + })`; + + return FilteredComponent; }; export default withWriteModeFilter; From 4659d6099b291cf81c0336d41af8143f42071b97 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 18:03:03 +0100 Subject: [PATCH 09/15] Optimize withWriteModeFilter HOC performance - Add early return for Write Mode experiment flag check - Avoid applying HOC when experiment is not enabled - Maintain existing optimizations for essential formats - Improve performance by reducing unnecessary wrapper components --- .../src/components/rich-text/with-write-mode-filter.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js index 87c8437893fb04..74540469239dd2 100644 --- a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js +++ b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js @@ -23,6 +23,11 @@ const withWriteModeFilter = ( WrappedComponent, formatSettings ) => { return WrappedComponent; } + // Early return if Write Mode experiment is not enabled + if ( ! window?.__experimentalEditorWriteMode ) { + return WrappedComponent; + } + // Memoize the wrapped component to prevent unnecessary re-renders const FilteredComponent = memo( ( props ) => { const blockEditingMode = useBlockEditingMode(); From d3cd4ec9c9dc38dc1874ed79660eab90746fa601 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 18:17:51 +0100 Subject: [PATCH 10/15] Use unstable --- .../src/components/rich-text/with-write-mode-filter.js | 6 +++--- packages/format-library/src/bold/index.js | 2 +- packages/format-library/src/code/index.js | 2 +- packages/format-library/src/image/index.js | 1 + packages/format-library/src/italic/index.js | 2 +- packages/format-library/src/language/index.js | 1 + packages/format-library/src/link/index.js | 2 +- packages/format-library/src/non-breaking-space/index.js | 1 + packages/format-library/src/strikethrough/index.js | 2 +- packages/format-library/src/subscript/index.js | 1 + packages/format-library/src/superscript/index.js | 1 + packages/format-library/src/text-color/index.js | 1 + packages/format-library/src/underline/index.js | 2 +- packages/format-library/src/unknown/index.js | 1 + 14 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js index 74540469239dd2..c2d9e06ea80cff 100644 --- a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js +++ b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js @@ -14,12 +14,12 @@ import { useBlockEditingMode } from '../block-editing-mode'; * Higher-Order Component that filters format edit components based on write mode. * * @param {Function} WrappedComponent The format edit component to wrap - * @param {Object} formatSettings The format settings including essential flag + * @param {Object} formatSettings The format settings including __unstableEssential flag * @return {Function} The wrapped component */ const withWriteModeFilter = ( WrappedComponent, formatSettings ) => { - // Early return if format is essential - no filtering needed - if ( formatSettings?.essential ) { + // Early return if format is __unstableEssential - no filtering needed + if ( formatSettings?.__unstableEssential ) { return WrappedComponent; } diff --git a/packages/format-library/src/bold/index.js b/packages/format-library/src/bold/index.js index 5a282765862d9b..89c17438dbbc37 100644 --- a/packages/format-library/src/bold/index.js +++ b/packages/format-library/src/bold/index.js @@ -18,7 +18,7 @@ export const bold = { title, tagName: 'strong', className: null, - essential: true, + __unstableEssential: true, edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/code/index.js b/packages/format-library/src/code/index.js index 40dd144500b309..2181761946da73 100644 --- a/packages/format-library/src/code/index.js +++ b/packages/format-library/src/code/index.js @@ -17,7 +17,7 @@ export const code = { title, tagName: 'code', className: null, - essential: false, + __unstableInputRule( value ) { const BACKTICK = '`'; const { start, text } = value; diff --git a/packages/format-library/src/image/index.js b/packages/format-library/src/image/index.js index 6e226b764d4c64..0691040b0913d4 100644 --- a/packages/format-library/src/image/index.js +++ b/packages/format-library/src/image/index.js @@ -56,6 +56,7 @@ export const image = { url: 'src', alt: 'alt', }, + edit: Edit, }; diff --git a/packages/format-library/src/italic/index.js b/packages/format-library/src/italic/index.js index 95e0b4187ce563..23ea7863037fd3 100644 --- a/packages/format-library/src/italic/index.js +++ b/packages/format-library/src/italic/index.js @@ -18,7 +18,7 @@ export const italic = { title, tagName: 'em', className: null, - essential: true, + __unstableEssential: true, edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/language/index.js b/packages/format-library/src/language/index.js index 6cfb8c4ad44927..54a4a6b7875070 100644 --- a/packages/format-library/src/language/index.js +++ b/packages/format-library/src/language/index.js @@ -26,6 +26,7 @@ export const language = { name, tagName: 'bdo', className: null, + edit: Edit, title, }; diff --git a/packages/format-library/src/link/index.js b/packages/format-library/src/link/index.js index bbc7e5b658dd25..5899ce1574201a 100644 --- a/packages/format-library/src/link/index.js +++ b/packages/format-library/src/link/index.js @@ -228,7 +228,7 @@ export const link = { target: 'target', rel: 'rel', }, - essential: true, + __unstableEssential: true, __unstablePasteRule( value, { html, plainText } ) { const pastedText = ( html || plainText ) .replace( /<[^>]+>/g, '' ) diff --git a/packages/format-library/src/non-breaking-space/index.js b/packages/format-library/src/non-breaking-space/index.js index 829b0960f28a92..dac8c9a1e67aea 100644 --- a/packages/format-library/src/non-breaking-space/index.js +++ b/packages/format-library/src/non-breaking-space/index.js @@ -13,6 +13,7 @@ export const nonBreakingSpace = { title, tagName: 'nbsp', className: null, + edit( { value, onChange } ) { function addNonBreakingSpace() { onChange( insert( value, '\u00a0' ) ); diff --git a/packages/format-library/src/strikethrough/index.js b/packages/format-library/src/strikethrough/index.js index 65eac07cc94c38..4cfe1c6ef5ce56 100644 --- a/packages/format-library/src/strikethrough/index.js +++ b/packages/format-library/src/strikethrough/index.js @@ -17,7 +17,7 @@ export const strikethrough = { title, tagName: 's', className: null, - essential: false, + edit( { isActive, value, onChange, onFocus } ) { function onClick() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/subscript/index.js b/packages/format-library/src/subscript/index.js index 50bda8b43cd247..a605d48f559667 100644 --- a/packages/format-library/src/subscript/index.js +++ b/packages/format-library/src/subscript/index.js @@ -14,6 +14,7 @@ export const subscript = { title, tagName: 'sub', className: null, + edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/superscript/index.js b/packages/format-library/src/superscript/index.js index aaf21b80d44ef6..430656cd02c51e 100644 --- a/packages/format-library/src/superscript/index.js +++ b/packages/format-library/src/superscript/index.js @@ -14,6 +14,7 @@ export const superscript = { title, tagName: 'sup', className: null, + edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/text-color/index.js b/packages/format-library/src/text-color/index.js index 04fd8ee6ce55aa..fa51c29d310f43 100644 --- a/packages/format-library/src/text-color/index.js +++ b/packages/format-library/src/text-color/index.js @@ -128,5 +128,6 @@ export const textColor = { style: 'style', class: 'class', }, + edit: TextColorEdit, }; diff --git a/packages/format-library/src/underline/index.js b/packages/format-library/src/underline/index.js index ac09b7af04b565..b5122c64b8a0c8 100644 --- a/packages/format-library/src/underline/index.js +++ b/packages/format-library/src/underline/index.js @@ -19,7 +19,7 @@ export const underline = { attributes: { style: 'style', }, - essential: false, + edit( { value, onChange } ) { const onToggle = () => { onChange( diff --git a/packages/format-library/src/unknown/index.js b/packages/format-library/src/unknown/index.js index b2da23388c79b7..0e2b0800290c85 100644 --- a/packages/format-library/src/unknown/index.js +++ b/packages/format-library/src/unknown/index.js @@ -25,6 +25,7 @@ export const unknown = { title, tagName: '*', className: null, + edit( { isActive, value, onChange, onFocus } ) { if ( ! isActive && ! selectionContainsUnknownFormats( value ) ) { return null; From 533103a16a0f92663da19b3e66f49f962fe39d00 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 6 Aug 2025 18:20:56 +0100 Subject: [PATCH 11/15] Revert unneeded changes to formats --- packages/format-library/src/code/index.js | 1 - packages/format-library/src/image/index.js | 1 - packages/format-library/src/language/index.js | 1 - packages/format-library/src/non-breaking-space/index.js | 1 - packages/format-library/src/strikethrough/index.js | 1 - packages/format-library/src/subscript/index.js | 1 - packages/format-library/src/superscript/index.js | 1 - packages/format-library/src/text-color/index.js | 1 - packages/format-library/src/underline/index.js | 1 - packages/format-library/src/unknown/index.js | 1 - 10 files changed, 10 deletions(-) diff --git a/packages/format-library/src/code/index.js b/packages/format-library/src/code/index.js index 2181761946da73..27a99ebc989e21 100644 --- a/packages/format-library/src/code/index.js +++ b/packages/format-library/src/code/index.js @@ -17,7 +17,6 @@ export const code = { title, tagName: 'code', className: null, - __unstableInputRule( value ) { const BACKTICK = '`'; const { start, text } = value; diff --git a/packages/format-library/src/image/index.js b/packages/format-library/src/image/index.js index 0691040b0913d4..6e226b764d4c64 100644 --- a/packages/format-library/src/image/index.js +++ b/packages/format-library/src/image/index.js @@ -56,7 +56,6 @@ export const image = { url: 'src', alt: 'alt', }, - edit: Edit, }; diff --git a/packages/format-library/src/language/index.js b/packages/format-library/src/language/index.js index 54a4a6b7875070..6cfb8c4ad44927 100644 --- a/packages/format-library/src/language/index.js +++ b/packages/format-library/src/language/index.js @@ -26,7 +26,6 @@ export const language = { name, tagName: 'bdo', className: null, - edit: Edit, title, }; diff --git a/packages/format-library/src/non-breaking-space/index.js b/packages/format-library/src/non-breaking-space/index.js index dac8c9a1e67aea..829b0960f28a92 100644 --- a/packages/format-library/src/non-breaking-space/index.js +++ b/packages/format-library/src/non-breaking-space/index.js @@ -13,7 +13,6 @@ export const nonBreakingSpace = { title, tagName: 'nbsp', className: null, - edit( { value, onChange } ) { function addNonBreakingSpace() { onChange( insert( value, '\u00a0' ) ); diff --git a/packages/format-library/src/strikethrough/index.js b/packages/format-library/src/strikethrough/index.js index 4cfe1c6ef5ce56..56dc81c9c66afb 100644 --- a/packages/format-library/src/strikethrough/index.js +++ b/packages/format-library/src/strikethrough/index.js @@ -17,7 +17,6 @@ export const strikethrough = { title, tagName: 's', className: null, - edit( { isActive, value, onChange, onFocus } ) { function onClick() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/subscript/index.js b/packages/format-library/src/subscript/index.js index a605d48f559667..50bda8b43cd247 100644 --- a/packages/format-library/src/subscript/index.js +++ b/packages/format-library/src/subscript/index.js @@ -14,7 +14,6 @@ export const subscript = { title, tagName: 'sub', className: null, - edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/superscript/index.js b/packages/format-library/src/superscript/index.js index 430656cd02c51e..aaf21b80d44ef6 100644 --- a/packages/format-library/src/superscript/index.js +++ b/packages/format-library/src/superscript/index.js @@ -14,7 +14,6 @@ export const superscript = { title, tagName: 'sup', className: null, - edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/text-color/index.js b/packages/format-library/src/text-color/index.js index fa51c29d310f43..04fd8ee6ce55aa 100644 --- a/packages/format-library/src/text-color/index.js +++ b/packages/format-library/src/text-color/index.js @@ -128,6 +128,5 @@ export const textColor = { style: 'style', class: 'class', }, - edit: TextColorEdit, }; diff --git a/packages/format-library/src/underline/index.js b/packages/format-library/src/underline/index.js index b5122c64b8a0c8..90d7c5852214e3 100644 --- a/packages/format-library/src/underline/index.js +++ b/packages/format-library/src/underline/index.js @@ -19,7 +19,6 @@ export const underline = { attributes: { style: 'style', }, - edit( { value, onChange } ) { const onToggle = () => { onChange( diff --git a/packages/format-library/src/unknown/index.js b/packages/format-library/src/unknown/index.js index 0e2b0800290c85..b2da23388c79b7 100644 --- a/packages/format-library/src/unknown/index.js +++ b/packages/format-library/src/unknown/index.js @@ -25,7 +25,6 @@ export const unknown = { title, tagName: '*', className: null, - edit( { isActive, value, onChange, onFocus } ) { if ( ! isActive && ! selectionContainsUnknownFormats( value ) ) { return null; From 6fc6b0a9153825091b3b519ccd0580ff191e1ec7 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 7 Aug 2025 11:02:58 +0100 Subject: [PATCH 12/15] Refactor Write Mode format filtering to use useFormatTypes hook - Remove withWriteModeFilter HOC approach in favor of centralized filtering - Add Write Mode detection to RichText component with experiment flag check - Enhance useFormatTypes hook with disableNoneEssentialFormatting parameter - Centralize all format filtering logic in one place for better performance - Eliminate individual store subscriptions per format component - Maintain same functionality with improved architecture and performance --- .../src/components/rich-text/format-edit.js | 6 +- .../src/components/rich-text/index.js | 32 +++++++--- .../components/rich-text/use-format-types.js | 51 ++++++++++------ .../rich-text/with-write-mode-filter.js | 61 ------------------- 4 files changed, 55 insertions(+), 95 deletions(-) delete mode 100644 packages/block-editor/src/components/rich-text/with-write-mode-filter.js diff --git a/packages/block-editor/src/components/rich-text/format-edit.js b/packages/block-editor/src/components/rich-text/format-edit.js index 20d13c1d3f189e..a70b9f8f778815 100644 --- a/packages/block-editor/src/components/rich-text/format-edit.js +++ b/packages/block-editor/src/components/rich-text/format-edit.js @@ -8,7 +8,6 @@ import { useContext, useMemo } from '@wordpress/element'; * Internal dependencies */ import BlockContext from '../block-context'; -import withWriteModeFilter from './with-write-mode-filter'; const DEFAULT_BLOCK_CONTEXT = {}; @@ -38,9 +37,6 @@ function Edit( { onChange, onFocus, value, forwardedRef, settings } ) { return null; } - // Apply the write mode filter HOC - const FilteredEditFunction = withWriteModeFilter( EditFunction, settings ); - const activeFormat = getActiveFormat( value, name ); const isActive = activeFormat !== undefined; const activeObject = getActiveObject( value ); @@ -48,7 +44,7 @@ function Edit( { onChange, onFocus, value, forwardedRef, settings } ) { activeObject !== undefined && activeObject.type === name; return ( - { @@ -323,8 +334,9 @@ export function RichTextWrapper( } = useFormatTypes( { clientId, identifier, - withoutInteractiveFormatting, allowedFormats: adjustedAllowedFormats, + withoutInteractiveFormatting, + disableNoneEssentialFormatting: isWriteMode, } ); function addEditorOnlyFormats( value ) { diff --git a/packages/block-editor/src/components/rich-text/use-format-types.js b/packages/block-editor/src/components/rich-text/use-format-types.js index 0bbebbf262367d..fcb58a852cc89b 100644 --- a/packages/block-editor/src/components/rich-text/use-format-types.js +++ b/packages/block-editor/src/components/rich-text/use-format-types.js @@ -56,35 +56,48 @@ function getPrefixedSelectKeys( selected, prefix ) { * This hook provides RichText with the `formatTypes` and its derived props from * experimental format type settings. * - * @param {Object} $0 Options - * @param {string} $0.clientId Block client ID. - * @param {string} $0.identifier Block attribute. - * @param {boolean} $0.withoutInteractiveFormatting Whether to clean the interactive formatting or not. - * @param {Array} $0.allowedFormats Allowed formats + * @param {Object} options Options + * @param {string} options.clientId Block client ID. + * @param {string} options.identifier Block attribute. + * @param {Array} options.allowedFormats Allowed formats + * @param {boolean} options.withoutInteractiveFormatting Whether to clean the interactive formatting or not. + * @param {boolean} options.disableNoneEssentialFormatting Whether to disable none-essential formatting or not. */ export function useFormatTypes( { clientId, identifier, - withoutInteractiveFormatting, allowedFormats, + withoutInteractiveFormatting, + disableNoneEssentialFormatting = false, } ) { const allFormatTypes = useSelect( formatTypesSelector, [] ); const formatTypes = useMemo( () => { - return allFormatTypes.filter( ( { name, interactive, tagName } ) => { - if ( allowedFormats && ! allowedFormats.includes( name ) ) { - return false; - } + return allFormatTypes.filter( + ( { name, interactive, tagName, __unstableEssential } ) => { + if ( allowedFormats && ! allowedFormats.includes( name ) ) { + return false; + } - if ( - withoutInteractiveFormatting && - ( interactive || interactiveContentTags.has( tagName ) ) - ) { - return false; - } + if ( disableNoneEssentialFormatting && ! __unstableEssential ) { + return false; + } + + if ( + withoutInteractiveFormatting && + ( interactive || interactiveContentTags.has( tagName ) ) + ) { + return false; + } - return true; - } ); - }, [ allFormatTypes, allowedFormats, withoutInteractiveFormatting ] ); + return true; + } + ); + }, [ + allFormatTypes, + allowedFormats, + disableNoneEssentialFormatting, + withoutInteractiveFormatting, + ] ); const keyedSelected = useSelect( ( select ) => formatTypes.reduce( ( accumulator, type ) => { diff --git a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js b/packages/block-editor/src/components/rich-text/with-write-mode-filter.js deleted file mode 100644 index c2d9e06ea80cff..00000000000000 --- a/packages/block-editor/src/components/rich-text/with-write-mode-filter.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; -import { memo, useMemo } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import { store as blockEditorStore } from '../../store'; -import { useBlockEditingMode } from '../block-editing-mode'; - -/** - * Higher-Order Component that filters format edit components based on write mode. - * - * @param {Function} WrappedComponent The format edit component to wrap - * @param {Object} formatSettings The format settings including __unstableEssential flag - * @return {Function} The wrapped component - */ -const withWriteModeFilter = ( WrappedComponent, formatSettings ) => { - // Early return if format is __unstableEssential - no filtering needed - if ( formatSettings?.__unstableEssential ) { - return WrappedComponent; - } - - // Early return if Write Mode experiment is not enabled - if ( ! window?.__experimentalEditorWriteMode ) { - return WrappedComponent; - } - - // Memoize the wrapped component to prevent unnecessary re-renders - const FilteredComponent = memo( ( props ) => { - const blockEditingMode = useBlockEditingMode(); - const isNavigationMode = useSelect( - ( select ) => select( blockEditorStore ).isNavigationMode(), - [] - ); - - // Memoize the write mode calculation - const isWriteMode = useMemo( () => { - const isContentOnlyMode = blockEditingMode === 'contentOnly'; - return isNavigationMode && isContentOnlyMode; - }, [ isNavigationMode, blockEditingMode ] ); - - // In write mode, only show essential formats - if ( isWriteMode ) { - return null; - } - - return ; - } ); - - // Set display name for debugging - FilteredComponent.displayName = `withWriteModeFilter(${ - WrappedComponent.displayName || WrappedComponent.name || 'Component' - })`; - - return FilteredComponent; -}; - -export default withWriteModeFilter; From 8d4a120bd59c3ae83b9a4bc7e42ab3c5e3a05ca9 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 7 Aug 2025 11:12:10 +0100 Subject: [PATCH 13/15] Remove redundant experiment flag check in Write Mode detection - isNavigationMode() already checks window.__experimentalEditorWriteMode internally - Removes duplicate experiment flag check for cleaner, more efficient code - Maintains same functionality while following existing codebase patterns --- packages/block-editor/src/components/rich-text/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index d5394382084fc2..bd831558f71b38 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -159,7 +159,6 @@ export function RichTextWrapper( selectionEnd: isSelected ? selectionEnd.offset : undefined, isSelected, isWriteMode: - window?.__experimentalEditorWriteMode && isNavigationMode() && getBlockEditingMode( clientId ) === 'contentOnly', }; From 669b5f82c66fc889481b804c617f18b35377b0de Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 7 Aug 2025 11:24:56 +0100 Subject: [PATCH 14/15] Replace __unstableEssential with private Symbol essentialFormatKey - Add essentialFormatKey to private-keys.js for internal Core usage - Expose essentialFormatKey in private-apis.js for Core packages - Update use-format-types.js to use private Symbol instead of __unstableEssential - Update format library packages (bold, italic, link) to use private Symbol - Follow correct import pattern: unlock from lock-unlock.js + privateApis from block-editor - Remove unstable API prefix as per Core guidelines --- .../src/components/rich-text/use-format-types.js | 14 ++++++++++++-- packages/block-editor/src/private-apis.js | 2 ++ packages/block-editor/src/store/private-keys.js | 1 + packages/format-library/src/bold/index.js | 10 +++++++++- packages/format-library/src/italic/index.js | 10 +++++++++- packages/format-library/src/link/index.js | 6 +++++- 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/use-format-types.js b/packages/block-editor/src/components/rich-text/use-format-types.js index fcb58a852cc89b..f6d55ea1cb9644 100644 --- a/packages/block-editor/src/components/rich-text/use-format-types.js +++ b/packages/block-editor/src/components/rich-text/use-format-types.js @@ -5,6 +5,11 @@ import { useMemo } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; import { store as richTextStore } from '@wordpress/rich-text'; +/** + * Internal dependencies + */ +import { essentialFormatKey } from '../../store/private-keys'; + function formatTypesSelector( select ) { return select( richTextStore ).getFormatTypes(); } @@ -73,12 +78,17 @@ export function useFormatTypes( { const allFormatTypes = useSelect( formatTypesSelector, [] ); const formatTypes = useMemo( () => { return allFormatTypes.filter( - ( { name, interactive, tagName, __unstableEssential } ) => { + ( { + name, + interactive, + tagName, + [ essentialFormatKey ]: isEssential, + } ) => { if ( allowedFormats && ! allowedFormats.includes( name ) ) { return false; } - if ( disableNoneEssentialFormatting && ! __unstableEssential ) { + if ( disableNoneEssentialFormatting && ! isEssential ) { return false; } diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index 0ecacd124e97ae..f6d5e8f5fe1cb2 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -40,6 +40,7 @@ import { globalStylesLinksDataKey, sectionRootClientIdKey, mediaEditKey, + essentialFormatKey, } from './store/private-keys'; import { requiresWrapperOnCopy } from './components/writing-flow/utils'; import { PrivateRichText } from './components/rich-text/'; @@ -101,4 +102,5 @@ lock( privateApis, { CommentIconSlotFill, CommentIconToolbarSlotFill, mediaEditKey, + essentialFormatKey, } ); diff --git a/packages/block-editor/src/store/private-keys.js b/packages/block-editor/src/store/private-keys.js index 15da423296c3ff..8fde1a53aaa523 100644 --- a/packages/block-editor/src/store/private-keys.js +++ b/packages/block-editor/src/store/private-keys.js @@ -4,3 +4,4 @@ export const selectBlockPatternsKey = Symbol( 'selectBlockPatternsKey' ); export const reusableBlocksSelectKey = Symbol( 'reusableBlocksSelect' ); export const sectionRootClientIdKey = Symbol( 'sectionRootClientIdKey' ); export const mediaEditKey = Symbol( 'mediaEditKey' ); +export const essentialFormatKey = Symbol( 'essentialFormat' ); diff --git a/packages/format-library/src/bold/index.js b/packages/format-library/src/bold/index.js index 89c17438dbbc37..78dc26ac43dc50 100644 --- a/packages/format-library/src/bold/index.js +++ b/packages/format-library/src/bold/index.js @@ -7,9 +7,17 @@ import { RichTextToolbarButton, RichTextShortcut, __unstableRichTextInputEvent, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { formatBold } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; + +const { essentialFormatKey } = unlock( blockEditorPrivateApis ); + const name = 'core/bold'; const title = __( 'Bold' ); @@ -18,7 +26,7 @@ export const bold = { title, tagName: 'strong', className: null, - __unstableEssential: true, + [ essentialFormatKey ]: true, edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/italic/index.js b/packages/format-library/src/italic/index.js index 23ea7863037fd3..15355e31841004 100644 --- a/packages/format-library/src/italic/index.js +++ b/packages/format-library/src/italic/index.js @@ -7,9 +7,17 @@ import { RichTextToolbarButton, RichTextShortcut, __unstableRichTextInputEvent, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { formatItalic } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; + +const { essentialFormatKey } = unlock( blockEditorPrivateApis ); + const name = 'core/italic'; const title = __( 'Italic' ); @@ -18,7 +26,7 @@ export const italic = { title, tagName: 'em', className: null, - __unstableEssential: true, + [ essentialFormatKey ]: true, edit( { isActive, value, onChange, onFocus } ) { function onToggle() { onChange( toggleFormat( value, { type: name, title } ) ); diff --git a/packages/format-library/src/link/index.js b/packages/format-library/src/link/index.js index 5899ce1574201a..a8f9bc58bc3f0b 100644 --- a/packages/format-library/src/link/index.js +++ b/packages/format-library/src/link/index.js @@ -16,6 +16,7 @@ import { isURL, isEmail, isPhoneNumber } from '@wordpress/url'; import { RichTextToolbarButton, RichTextShortcut, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { decodeEntities } from '@wordpress/html-entities'; import { link as linkIcon } from '@wordpress/icons'; @@ -26,6 +27,9 @@ import { speak } from '@wordpress/a11y'; */ import InlineLinkUI from './inline'; import { isValidHref } from './utils'; +import { unlock } from '../lock-unlock'; + +const { essentialFormatKey } = unlock( blockEditorPrivateApis ); const name = 'core/link'; const title = __( 'Link' ); @@ -228,7 +232,7 @@ export const link = { target: 'target', rel: 'rel', }, - __unstableEssential: true, + [ essentialFormatKey ]: true, __unstablePasteRule( value, { html, plainText } ) { const pastedText = ( html || plainText ) .replace( /<[^>]+>/g, '' ) From a2787ca2784c219aa099fca1047db57775590d0e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 7 Aug 2025 11:33:53 +0100 Subject: [PATCH 15/15] Improve variable naming: rename isWriteMode to isContentOnlyWriteMode - More accurately reflects that we're checking both Write Mode and content-only editing - Makes the dual condition check explicit: Write Mode + content-only block editing - Improves code readability and maintainability - Clarifies the relationship between Write Mode and content editing mode --- .../block-editor/src/components/rich-text/index.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index bd831558f71b38..310b2a0ce63264 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -158,21 +158,19 @@ export function RichTextWrapper( selectionStart: isSelected ? selectionStart.offset : undefined, selectionEnd: isSelected ? selectionEnd.offset : undefined, isSelected, - isWriteMode: + isContentOnlyWriteMode: isNavigationMode() && getBlockEditingMode( clientId ) === 'contentOnly', }; }; - const { selectionStart, selectionEnd, isSelected, isWriteMode } = useSelect( - selector, - [ + const { selectionStart, selectionEnd, isSelected, isContentOnlyWriteMode } = + useSelect( selector, [ clientId, identifier, instanceId, originalIsSelected, isBlockSelected, - ] - ); + ] ); const { disableBoundBlock, bindingsPlaceholder, bindingsLabel } = useSelect( ( select ) => { @@ -335,7 +333,7 @@ export function RichTextWrapper( identifier, allowedFormats: adjustedAllowedFormats, withoutInteractiveFormatting, - disableNoneEssentialFormatting: isWriteMode, + disableNoneEssentialFormatting: isContentOnlyWriteMode, } ); function addEditorOnlyFormats( value ) {