diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 47ab161e05723..c9e744157c65b 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -27,7 +27,6 @@ "@wordpress/i18n": "file:../i18n", "@wordpress/rich-text": "file:../rich-text", "lodash": "^4.17.11", - "memize": "^1.0.5", "rememo": "^3.0.0", "uuid": "^3.3.2" }, diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index a0a1408359681..3cd7a4ac8dd0e 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -88,8 +88,18 @@ const globalStyle = document.createElement( 'style' ); document.head.appendChild( globalStyle ); -function pickPropsByPrefix( props, prefix ) { - return pickBy( props, ( value, key ) => key.startsWith( prefix ) ); +function createPrepareEditableTree( props ) { + const fns = Object.keys( props ).reduce( ( accumulator, key ) => { + if ( key.startsWith( 'format_prepare_functions' ) ) { + accumulator.push( props[ key ] ); + } + + return accumulator; + }, [] ); + + return ( value ) => fns.reduce( ( accumlator, fn ) => { + return fn( accumlator, value.text ); + }, value.formats ); } export class RichText extends Component { @@ -200,7 +210,7 @@ export class RichText extends Component { range, multilineTag: this.multilineTag, multilineWrapperTags: this.multilineWrapperTags, - prepareEditableTree: Object.values( pickPropsByPrefix( this.props, 'format_prepare_functions' ) ), + prepareEditableTree: createPrepareEditableTree( this.props ), __unstableIsEditableTree: true, } ); } @@ -211,7 +221,7 @@ export class RichText extends Component { current: this.editableRef, multilineTag: this.multilineTag, multilineWrapperTags: this.multilineWrapperTags, - prepareEditableTree: Object.values( pickPropsByPrefix( this.props, 'format_prepare_functions' ) ), + prepareEditableTree: createPrepareEditableTree( this.props ), __unstableDomOnly: domOnly, } ); } @@ -517,19 +527,6 @@ export class RichText extends Component { } } - /** - * Calls all registered onChangeEditableValue handlers. - * - * @param {Array} formats The formats of the latest rich-text value. - * @param {string} text The text of the latest rich-text value. - */ - onChangeEditableValue( { formats, text } ) { - Object.values( pickPropsByPrefix( this.props, 'format_on_change_functions_' ) ) - .forEach( ( eventHandler ) => { - eventHandler( formats, text ); - } ); - } - /** * Sync the value to global state. The node tree and selection will also be * updated if differences are found. @@ -543,10 +540,15 @@ export class RichText extends Component { this.applyRecord( record ); const { start, end, formatPlaceholder, selectedFormat } = record; + const changeHandlers = pickBy( this.props, ( v, key ) => + key.startsWith( 'format_on_change_functions_' ) + ); - this.formatPlaceholder = formatPlaceholder; - this.onChangeEditableValue( record ); + Object.values( changeHandlers ).forEach( ( changeHandler ) => { + changeHandler( record.formats, record.text ); + } ); + this.formatPlaceholder = formatPlaceholder; this.savedContent = this.valueToFormat( record ); this.props.onChange( this.savedContent ); this.setState( { start, end, selectedFormat } ); @@ -949,12 +951,12 @@ export class RichText extends Component { } const prefix = 'format_prepare_props_'; + const predicate = ( v, key ) => key.startsWith( prefix ); + const prepareProps = pickBy( this.props, predicate ); + const prevPrepareProps = pickBy( prevProps, predicate ); - // If any format props update, reapply value. - if ( ! isShallowEqual( - pickPropsByPrefix( this.props, prefix ), - pickPropsByPrefix( prevProps, prefix ) - ) ) { + // If any format prepare props update, reapply value. + if ( ! isShallowEqual( prepareProps, prevPrepareProps ) ) { const record = this.formatToValue( value ); // Maintain the previous selection if the instance is currently @@ -1005,7 +1007,7 @@ export class RichText extends Component { return unstableToDom( { value, multilineTag: this.multilineTag, - prepareEditableTree: Object.values( pickPropsByPrefix( this.props, 'format_prepare_functions' ) ), + prepareEditableTree: createPrepareEditableTree( this.props ), } ).body.innerHTML; } diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 096b3faa12499..b2a0f0165b40d 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -25,6 +25,7 @@ "@wordpress/compose": "file:../compose", "@wordpress/data": "file:../data", "@wordpress/escape-html": "file:../escape-html", + "@wordpress/hooks": "file:../hooks", "lodash": "^4.17.11", "rememo": "^3.0.0" }, diff --git a/packages/rich-text/src/register-format-type.js b/packages/rich-text/src/register-format-type.js index 98047d7ce8c51..eb6d48c9e5636 100644 --- a/packages/rich-text/src/register-format-type.js +++ b/packages/rich-text/src/register-format-type.js @@ -10,16 +10,6 @@ import { select, dispatch, withSelect, withDispatch } from '@wordpress/data'; import { addFilter } from '@wordpress/hooks'; import { compose } from '@wordpress/compose'; -function getPropsByPrefix( props, prefix ) { - return Object.keys( props ).reduce( ( accumulator, key ) => { - if ( key.startsWith( prefix ) ) { - accumulator[ key.slice( prefix.length ) ] = props[ key ]; - } - - return accumulator; - }, {} ); -} - /** * Registers a new format provided a unique name and an object defining its * behavior. @@ -140,10 +130,17 @@ export function registerFormatType( name, settings ) { const Component = ( props ) => { const newProps = { ...props }; - const propsByPrefix = { - ...getPropsByPrefix( props, selectPrefix ), - ...getPropsByPrefix( props, dispatchPrefix ), - }; + const propsByPrefix = Object.keys( props ).reduce( ( accumulator, key ) => { + if ( key.startsWith( selectPrefix ) ) { + accumulator[ key.slice( selectPrefix.length ) ] = props[ key ]; + } + + if ( key.startsWith( dispatchPrefix ) ) { + accumulator[ key.slice( dispatchPrefix.length ) ] = props[ key ]; + } + + return accumulator; + }, {} ); const args = { richTextIdentifier: props.identifier, blockClientId: props.clientId, diff --git a/packages/rich-text/src/to-dom.js b/packages/rich-text/src/to-dom.js index 9ebe8365a25ba..33cc08b27e47d 100644 --- a/packages/rich-text/src/to-dom.js +++ b/packages/rich-text/src/to-dom.js @@ -113,12 +113,6 @@ function remove( node ) { return node.parentNode.removeChild( node ); } -function prepareFormats( prepareEditableTree = [], value ) { - return prepareEditableTree.reduce( ( accumlator, fn ) => { - return fn( accumlator, value.text ); - }, value.formats ); -} - export function toDom( { value, multilineTag, @@ -128,11 +122,15 @@ export function toDom( { let startPath = []; let endPath = []; - const tree = toTree( { - value: { + if ( prepareEditableTree ) { + value = { ...value, - formats: prepareFormats( prepareEditableTree, value ), - }, + formats: prepareEditableTree( value ), + }; + } + + const tree = toTree( { + value, multilineTag, createEmpty, append, diff --git a/packages/rich-text/src/unregister-format-type.js b/packages/rich-text/src/unregister-format-type.js index 6f6741183ee16..a70c1d1d417f2 100644 --- a/packages/rich-text/src/unregister-format-type.js +++ b/packages/rich-text/src/unregister-format-type.js @@ -22,10 +22,7 @@ export function unregisterFormatType( name ) { return; } - if ( - oldFormat.__experimentalCreatePrepareEditableTree && - oldFormat.__experimentalGetPropsForEditableTreePreparation - ) { + if ( oldFormat.__experimentalCreatePrepareEditableTree ) { removeFilter( 'experimentalRichText', name ); }