From fb4cdf618b0c131f1ace28478a9029004a1b4d54 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Fri, 10 Nov 2023 20:54:05 +0200 Subject: [PATCH] Rich text: remove preserveWhiteSpace serialisation differences (#55999) --- .../src/components/editable-text/index.js | 9 +- .../src/components/rich-text/README.md | 3 +- .../src/components/rich-text/index.js | 1 - .../components/rich-text/use-paste-handler.js | 7 +- packages/block-editor/src/store/actions.js | 83 +++---------------- packages/block-editor/src/store/selectors.js | 21 +---- packages/block-editor/src/store/utils.js | 12 --- packages/block-library/src/code/transforms.js | 22 +++-- packages/block-library/src/html/transforms.js | 7 +- .../__snapshots__/transforms.native.js.snap | 6 ++ .../src/paragraph/test/transforms.native.js | 1 + .../src/preformatted/transforms.js | 5 +- packages/blocks/README.md | 1 - .../src/api/raw-handling/paste-handler.js | 31 +++---- .../api/raw-handling/test/paste-handler.js | 2 - .../editor/src/components/post-title/index.js | 1 - packages/rich-text/README.md | 2 - packages/rich-text/src/component/index.js | 12 +-- .../src/component/use-copy-handler.js | 7 +- packages/rich-text/src/create.js | 41 ++++----- .../src/test/__snapshots__/to-dom.js.snap | 6 -- packages/rich-text/src/test/helpers/index.js | 19 ----- packages/rich-text/src/to-html-string.js | 9 +- packages/rich-text/src/to-tree.js | 3 +- ...ode-should-paste-plain-text-1-chromium.txt | 3 +- ...preserve-character-newlines-2-chromium.txt | 4 +- ...ve-white-space-when-merging-1-chromium.txt | 5 +- .../blocks/verse-code-preformatted.spec.js | 2 +- ...s-block-selection-is-copied-2-chromium.txt | 4 +- 29 files changed, 87 insertions(+), 242 deletions(-) delete mode 100644 packages/block-editor/src/store/utils.js diff --git a/packages/block-editor/src/components/editable-text/index.js b/packages/block-editor/src/components/editable-text/index.js index 21366087257ef..62bb166efa8e6 100644 --- a/packages/block-editor/src/components/editable-text/index.js +++ b/packages/block-editor/src/components/editable-text/index.js @@ -9,14 +9,7 @@ import { forwardRef } from '@wordpress/element'; import RichText from '../rich-text'; const EditableText = forwardRef( ( props, ref ) => { - return ( - - ); + return ; } ); EditableText.Content = ( { value = '', tagName: Tag = 'div', ...props } ) => { diff --git a/packages/block-editor/src/components/rich-text/README.md b/packages/block-editor/src/components/rich-text/README.md index fba07d7c5d852..d17f987a34cf0 100644 --- a/packages/block-editor/src/components/rich-text/README.md +++ b/packages/block-editor/src/components/rich-text/README.md @@ -71,7 +71,8 @@ _Optional._ A list of autocompleters to use instead of the default. ### `preserveWhiteSpace: Boolean` -_Optional._ Whether or not to preserve white space characters in the `value`. Normally tab, newline and space characters are collapsed to a single space. If turned on, soft line breaks will be saved as newline characters, not as line break elements. +_Optional._ Whether or not to preserve white space characters in the `value`. Normally tab, newline and space characters are collapsed to a single space or +trimmed. ## RichText.Content diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 3fc6ec4414222..1a6793ca9efe7 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -348,7 +348,6 @@ export function RichTextWrapper( onReplace, onSplit, __unstableEmbedURLOnPaste, - preserveWhiteSpace, pastePlainText, } ), useDelete( { diff --git a/packages/block-editor/src/components/rich-text/use-paste-handler.js b/packages/block-editor/src/components/rich-text/use-paste-handler.js index 3d24906abddd9..1302e2d0dce46 100644 --- a/packages/block-editor/src/components/rich-text/use-paste-handler.js +++ b/packages/block-editor/src/components/rich-text/use-paste-handler.js @@ -35,7 +35,6 @@ export function usePasteHandler( props ) { onReplace, onSplit, __unstableEmbedURLOnPaste, - preserveWhiteSpace, pastePlainText, } = propsRef.current; @@ -63,10 +62,7 @@ export function usePasteHandler( props ) { // without filtering the data. The filters are only meant for externally // pasted content and remove inline styles. if ( isInternal ) { - const pastedValue = create( { - html, - preserveWhiteSpace, - } ); + const pastedValue = create( { html } ); addActiveFormats( pastedValue, value.activeFormats ); onChange( insert( value, pastedValue ) ); return; @@ -136,7 +132,6 @@ export function usePasteHandler( props ) { plainText, mode, tagName, - preserveWhiteSpace, } ); if ( typeof content === 'string' ) { diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index 4f6ce7b5b044c..b21436161cb8c 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -23,7 +23,6 @@ import deprecated from '@wordpress/deprecated'; /** * Internal dependencies */ -import { mapRichTextSettings } from './utils'; import { retrieveSelectedAttribute, START_OF_SELECTED_AREA, @@ -759,43 +758,23 @@ export const __unstableDeleteSelection = const selectionB = selectionEnd; const blockA = select.getBlock( selectionA.clientId ); - const blockAType = getBlockType( blockA.name ); - const blockB = select.getBlock( selectionB.clientId ); - const blockBType = getBlockType( blockB.name ); const htmlA = blockA.attributes[ selectionA.attributeKey ]; const htmlB = blockB.attributes[ selectionB.attributeKey ]; - const attributeDefinitionA = - blockAType.attributes[ selectionA.attributeKey ]; - const attributeDefinitionB = - blockBType.attributes[ selectionB.attributeKey ]; - - let valueA = create( { - html: htmlA, - ...mapRichTextSettings( attributeDefinitionA ), - } ); - let valueB = create( { - html: htmlB, - ...mapRichTextSettings( attributeDefinitionB ), - } ); + let valueA = create( { html: htmlA } ); + let valueB = create( { html: htmlB } ); valueA = remove( valueA, selectionA.offset, valueA.text.length ); valueB = insert( valueB, START_OF_SELECTED_AREA, 0, selectionB.offset ); // Clone the blocks so we don't manipulate the original. const cloneA = cloneBlock( blockA, { - [ selectionA.attributeKey ]: toHTMLString( { - value: valueA, - ...mapRichTextSettings( attributeDefinitionA ), - } ), + [ selectionA.attributeKey ]: toHTMLString( { value: valueA } ), } ); const cloneB = cloneBlock( blockB, { - [ selectionB.attributeKey ]: toHTMLString( { - value: valueB, - ...mapRichTextSettings( attributeDefinitionB ), - } ), + [ selectionB.attributeKey ]: toHTMLString( { value: valueB } ), } ); const followingBlock = isForward ? cloneA : cloneB; @@ -831,20 +810,10 @@ export const __unstableDeleteSelection = const newAttributeKey = retrieveSelectedAttribute( updatedAttributes ); const convertedHtml = updatedAttributes[ newAttributeKey ]; - const convertedValue = create( { - html: convertedHtml, - ...mapRichTextSettings( - targetBlockType.attributes[ newAttributeKey ] - ), - } ); + const convertedValue = create( { html: convertedHtml } ); const newOffset = convertedValue.text.indexOf( START_OF_SELECTED_AREA ); const newValue = remove( convertedValue, newOffset, newOffset + 1 ); - const newHtml = toHTMLString( { - value: newValue, - ...mapRichTextSettings( - targetBlockType.attributes[ newAttributeKey ] - ), - } ); + const newHtml = toHTMLString( { value: newValue } ); updatedAttributes[ newAttributeKey ] = newHtml; @@ -931,27 +900,13 @@ export const __unstableSplitSelection = const selectionB = selectionEnd; const blockA = select.getBlock( selectionA.clientId ); - const blockAType = getBlockType( blockA.name ); - const blockB = select.getBlock( selectionB.clientId ); - const blockBType = getBlockType( blockB.name ); const htmlA = blockA.attributes[ selectionA.attributeKey ]; const htmlB = blockB.attributes[ selectionB.attributeKey ]; - const attributeDefinitionA = - blockAType.attributes[ selectionA.attributeKey ]; - const attributeDefinitionB = - blockBType.attributes[ selectionB.attributeKey ]; - - let valueA = create( { - html: htmlA, - ...mapRichTextSettings( attributeDefinitionA ), - } ); - let valueB = create( { - html: htmlB, - ...mapRichTextSettings( attributeDefinitionB ), - } ); + let valueA = create( { html: htmlA } ); + let valueB = create( { html: htmlB } ); valueA = remove( valueA, selectionA.offset, valueA.text.length ); valueB = remove( valueB, 0, selectionB.offset ); @@ -964,7 +919,6 @@ export const __unstableSplitSelection = ...blockA.attributes, [ selectionA.attributeKey ]: toHTMLString( { value: valueA, - ...mapRichTextSettings( attributeDefinitionA ), } ), }, }, @@ -975,7 +929,6 @@ export const __unstableSplitSelection = ...blockB.attributes, [ selectionB.attributeKey ]: toHTMLString( { value: valueB, - ...mapRichTextSettings( attributeDefinitionB ), } ), }, }, @@ -1143,10 +1096,7 @@ export const mergeBlocks = const selectedBlock = clientId === clientIdA ? cloneA : cloneB; const html = selectedBlock.attributes[ attributeKey ]; const value = insert( - create( { - html, - ...mapRichTextSettings( attributeDefinition ), - } ), + create( { html } ), START_OF_SELECTED_AREA, offset, offset @@ -1154,7 +1104,6 @@ export const mergeBlocks = selectedBlock.attributes[ attributeKey ] = toHTMLString( { value, - ...mapRichTextSettings( attributeDefinition ), } ); } @@ -1180,22 +1129,12 @@ export const mergeBlocks = const newAttributeKey = retrieveSelectedAttribute( updatedAttributes ); const convertedHtml = updatedAttributes[ newAttributeKey ]; - const convertedValue = create( { - html: convertedHtml, - ...mapRichTextSettings( - blockAType.attributes[ newAttributeKey ] - ), - } ); + const convertedValue = create( { html: convertedHtml } ); const newOffset = convertedValue.text.indexOf( START_OF_SELECTED_AREA ); const newValue = remove( convertedValue, newOffset, newOffset + 1 ); - const newHtml = toHTMLString( { - value: newValue, - ...mapRichTextSettings( - blockAType.attributes[ newAttributeKey ] - ), - } ); + const newHtml = toHTMLString( { value: newValue } ); updatedAttributes[ newAttributeKey ] = newHtml; diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index e9d17d86a2672..548ad71664b5e 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -26,7 +26,6 @@ import { createRegistrySelector } from '@wordpress/data'; /** * Internal dependencies */ -import { mapRichTextSettings } from './utils'; import { orderBy } from '../utils/sorting'; /** @@ -1114,27 +1113,13 @@ export const __unstableGetSelectedBlocksWithPartialSelection = ( state ) => { : [ selectionAnchor, selectionFocus ]; const blockA = getBlock( state, selectionStart.clientId ); - const blockAType = getBlockType( blockA.name ); - const blockB = getBlock( state, selectionEnd.clientId ); - const blockBType = getBlockType( blockB.name ); const htmlA = blockA.attributes[ selectionStart.attributeKey ]; const htmlB = blockB.attributes[ selectionEnd.attributeKey ]; - const attributeDefinitionA = - blockAType.attributes[ selectionStart.attributeKey ]; - const attributeDefinitionB = - blockBType.attributes[ selectionEnd.attributeKey ]; - - let valueA = create( { - html: htmlA, - ...mapRichTextSettings( attributeDefinitionA ), - } ); - let valueB = create( { - html: htmlB, - ...mapRichTextSettings( attributeDefinitionB ), - } ); + let valueA = create( { html: htmlA } ); + let valueB = create( { html: htmlB } ); valueA = remove( valueA, 0, selectionStart.offset ); valueB = remove( valueB, selectionEnd.offset, valueB.text.length ); @@ -1146,7 +1131,6 @@ export const __unstableGetSelectedBlocksWithPartialSelection = ( state ) => { ...blockA.attributes, [ selectionStart.attributeKey ]: toHTMLString( { value: valueA, - ...mapRichTextSettings( attributeDefinitionA ), } ), }, }, @@ -1156,7 +1140,6 @@ export const __unstableGetSelectedBlocksWithPartialSelection = ( state ) => { ...blockB.attributes, [ selectionEnd.attributeKey ]: toHTMLString( { value: valueB, - ...mapRichTextSettings( attributeDefinitionB ), } ), }, }, diff --git a/packages/block-editor/src/store/utils.js b/packages/block-editor/src/store/utils.js deleted file mode 100644 index 4a19d76d1a472..0000000000000 --- a/packages/block-editor/src/store/utils.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Helper function that maps attribute definition properties to the - * ones used by RichText utils like `create, toHTMLString, etc..`. - * - * @param {Object} attributeDefinition A block's attribute definition object. - * @return {Object} The mapped object. - */ -export function mapRichTextSettings( attributeDefinition ) { - const { __unstablePreserveWhiteSpace: preserveWhiteSpace } = - attributeDefinition; - return { preserveWhiteSpace }; -} diff --git a/packages/block-library/src/code/transforms.js b/packages/block-library/src/code/transforms.js index fcfb41fb0262c..af6d4686af812 100644 --- a/packages/block-library/src/code/transforms.js +++ b/packages/block-library/src/code/transforms.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { createBlock } from '@wordpress/blocks'; +import { create, toHTMLString } from '@wordpress/rich-text'; const transforms = { from: [ @@ -12,10 +13,18 @@ const transforms = { }, { type: 'block', - blocks: [ 'core/html', 'core/paragraph' ], - transform: ( { content } ) => { + blocks: [ 'core/paragraph' ], + transform: ( { content } ) => + createBlock( 'core/code', { content } ), + }, + { + type: 'block', + blocks: [ 'core/html' ], + transform: ( { content: text } ) => { return createBlock( 'core/code', { - content, + // The HTML is plain text (with plain line breaks), so + // convert it to rich text. + content: toHTMLString( { value: create( { text } ) } ), } ); }, }, @@ -42,11 +51,8 @@ const transforms = { { type: 'block', blocks: [ 'core/paragraph' ], - transform: ( { content } ) => { - return createBlock( 'core/paragraph', { - content: content.replace( /\n/g, '
' ), - } ); - }, + transform: ( { content } ) => + createBlock( 'core/paragraph', { content } ), }, ], }; diff --git a/packages/block-library/src/html/transforms.js b/packages/block-library/src/html/transforms.js index 6265acefc8f80..af1a16288fe9f 100644 --- a/packages/block-library/src/html/transforms.js +++ b/packages/block-library/src/html/transforms.js @@ -2,15 +2,18 @@ * WordPress dependencies */ import { createBlock } from '@wordpress/blocks'; +import { create } from '@wordpress/rich-text'; const transforms = { from: [ { type: 'block', blocks: [ 'core/code' ], - transform: ( { content } ) => { + transform: ( { content: html } ) => { return createBlock( 'core/html', { - content, + // The code block may output HTML formatting, so convert it + // to plain text. + content: create( { html } ).text, } ); }, }, diff --git a/packages/block-library/src/paragraph/test/__snapshots__/transforms.native.js.snap b/packages/block-library/src/paragraph/test/__snapshots__/transforms.native.js.snap index 22e05ce5435c9..b0855c02bd0e9 100644 --- a/packages/block-library/src/paragraph/test/__snapshots__/transforms.native.js.snap +++ b/packages/block-library/src/paragraph/test/__snapshots__/transforms.native.js.snap @@ -1,5 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Paragraph block transforms to Code block 1`] = ` +" +
Example text
+" +`; + exports[`Paragraph block transforms to Columns block 1`] = ` "
diff --git a/packages/block-library/src/paragraph/test/transforms.native.js b/packages/block-library/src/paragraph/test/transforms.native.js index 0f34038ca298c..bb2d14a996625 100644 --- a/packages/block-library/src/paragraph/test/transforms.native.js +++ b/packages/block-library/src/paragraph/test/transforms.native.js @@ -23,6 +23,7 @@ const blockTransforms = [ 'Preformatted', 'Pullquote', 'Verse', + 'Code', ...transformsWithInnerBlocks, ]; diff --git a/packages/block-library/src/preformatted/transforms.js b/packages/block-library/src/preformatted/transforms.js index 068a08b8bcfc7..ef5f332447409 100644 --- a/packages/block-library/src/preformatted/transforms.js +++ b/packages/block-library/src/preformatted/transforms.js @@ -34,10 +34,7 @@ const transforms = { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => - createBlock( 'core/paragraph', { - ...attributes, - content: attributes.content.replace( /\n/g, '
' ), - } ), + createBlock( 'core/paragraph', attributes ), }, { type: 'block', diff --git a/packages/blocks/README.md b/packages/blocks/README.md index cbde04f72fd95..8e6fdc9d900db 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -457,7 +457,6 @@ _Parameters_ - _options.plainText_ `[string]`: Plain text version. - _options.mode_ `[string]`: Handle content as blocks or inline content. _ 'AUTO': Decide based on the content passed. _ 'INLINE': Always handle as inline content, and return string. \* 'BLOCKS': Always handle as blocks, and return array of blocks. - _options.tagName_ `[Array]`: The tag into which content will be inserted. -- _options.preserveWhiteSpace_ `[boolean]`: Whether or not to preserve consequent white space. _Returns_ diff --git a/packages/blocks/src/api/raw-handling/paste-handler.js b/packages/blocks/src/api/raw-handling/paste-handler.js index 9fa87462d8a1b..2f68a826931ab 100644 --- a/packages/blocks/src/api/raw-handling/paste-handler.js +++ b/packages/blocks/src/api/raw-handling/paste-handler.js @@ -41,12 +41,11 @@ const { console } = window; /** * Filters HTML to only contain phrasing content. * - * @param {string} HTML The HTML to filter. - * @param {boolean} preserveWhiteSpace Whether or not to preserve consequent white space. + * @param {string} HTML The HTML to filter. * * @return {string} HTML only containing phrasing content. */ -function filterInlineHTML( HTML, preserveWhiteSpace ) { +function filterInlineHTML( HTML ) { HTML = deepFilterHTML( HTML, [ headRemover, googleDocsUIDRemover, @@ -58,9 +57,7 @@ function filterInlineHTML( HTML, preserveWhiteSpace ) { inline: true, } ); - if ( ! preserveWhiteSpace ) { - HTML = deepFilterHTML( HTML, [ htmlFormattingRemover, brRemover ] ); - } + HTML = deepFilterHTML( HTML, [ htmlFormattingRemover, brRemover ] ); // Allows us to ask for this information when we get a report. console.log( 'Processed inline HTML:\n\n', HTML ); @@ -71,15 +68,14 @@ function filterInlineHTML( HTML, preserveWhiteSpace ) { /** * Converts an HTML string to known blocks. Strips everything else. * - * @param {Object} options - * @param {string} [options.HTML] The HTML to convert. - * @param {string} [options.plainText] Plain text version. - * @param {string} [options.mode] Handle content as blocks or inline content. - * * 'AUTO': Decide based on the content passed. - * * 'INLINE': Always handle as inline content, and return string. - * * 'BLOCKS': Always handle as blocks, and return array of blocks. - * @param {Array} [options.tagName] The tag into which content will be inserted. - * @param {boolean} [options.preserveWhiteSpace] Whether or not to preserve consequent white space. + * @param {Object} options + * @param {string} [options.HTML] The HTML to convert. + * @param {string} [options.plainText] Plain text version. + * @param {string} [options.mode] Handle content as blocks or inline content. + * * 'AUTO': Decide based on the content passed. + * * 'INLINE': Always handle as inline content, and return string. + * * 'BLOCKS': Always handle as blocks, and return array of blocks. + * @param {Array} [options.tagName] The tag into which content will be inserted. * * @return {Array|string} A list of blocks or a string, depending on `handlerMode`. */ @@ -88,7 +84,6 @@ export function pasteHandler( { plainText = '', mode = 'AUTO', tagName, - preserveWhiteSpace, } ) { // First of all, strip any meta tags. HTML = HTML.replace( /]+>/g, '' ); @@ -167,7 +162,7 @@ export function pasteHandler( { } if ( mode === 'INLINE' ) { - return filterInlineHTML( HTML, preserveWhiteSpace ); + return filterInlineHTML( HTML ); } if ( @@ -175,7 +170,7 @@ export function pasteHandler( { ! hasShortcodes && isInlineContent( HTML, tagName ) ) { - return filterInlineHTML( HTML, preserveWhiteSpace ); + return filterInlineHTML( HTML ); } const phrasingContentSchema = getPhrasingContentSchema( 'paste' ); diff --git a/packages/blocks/src/api/raw-handling/test/paste-handler.js b/packages/blocks/src/api/raw-handling/test/paste-handler.js index e8e1e34c7d57a..6938ad0d9c408 100644 --- a/packages/blocks/src/api/raw-handling/test/paste-handler.js +++ b/packages/blocks/src/api/raw-handling/test/paste-handler.js @@ -69,7 +69,6 @@ describe( 'pasteHandler', () => { const [ result ] = pasteHandler( { HTML: tableWithHeaderFooterAndBodyUsingColspan, tagName: 'p', - preserveWhiteSpace: false, } ); expect( console ).toHaveLogged(); @@ -110,7 +109,6 @@ describe( 'pasteHandler', () => { const [ result ] = pasteHandler( { HTML: tableWithHeaderFooterAndBodyUsingRowspan, tagName: 'p', - preserveWhiteSpace: false, } ); expect( console ).toHaveLogged(); diff --git a/packages/editor/src/components/post-title/index.js b/packages/editor/src/components/post-title/index.js index d7094b080de9d..09f5f30c2a660 100644 --- a/packages/editor/src/components/post-title/index.js +++ b/packages/editor/src/components/post-title/index.js @@ -222,7 +222,6 @@ function PostTitle( _, forwardedRef ) { } ); }, __unstableDisableFormats: true, - preserveWhiteSpace: true, } ); /* eslint-disable jsx-a11y/heading-has-content, jsx-a11y/no-noninteractive-element-to-interactive-role */ diff --git a/packages/rich-text/README.md b/packages/rich-text/README.md index 84f33bc3afaf1..90726ff238c1b 100644 --- a/packages/rich-text/README.md +++ b/packages/rich-text/README.md @@ -174,7 +174,6 @@ _Parameters_ - _$1.text_ `[string]`: Text to create value from. - _$1.html_ `[string]`: HTML to create value from. - _$1.range_ `[Range]`: Range to create value from. -- _$1.preserveWhiteSpace_ `[boolean]`: Whether or not to collapse white space characters. - _$1.\_\_unstableIsEditableTree_ `[boolean]`: _Returns_ @@ -420,7 +419,6 @@ _Parameters_ - _$1_ `Object`: Named argements. - _$1.value_ `RichTextValue`: Rich text value. -- _$1.preserveWhiteSpace_ `[boolean]`: Whether or not to use newline characters for line breaks. _Returns_ diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index 4aaa0b88ebc14..17cf17e2e3154 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -8,7 +8,7 @@ import { useRegistry } from '@wordpress/data'; /** * Internal dependencies */ -import { create } from '../create'; +import { collapseWhiteSpace, create } from '../create'; import { apply } from '../to-dom'; import { toHTMLString } from '../to-html-string'; import { useDefaultStyle } from './use-default-style'; @@ -25,8 +25,8 @@ export function useRichText( { selectionStart, selectionEnd, placeholder, - preserveWhiteSpace, onSelectionChange, + preserveWhiteSpace, onChange, __unstableDisableFormats: disableFormats, __unstableIsSelected: isSelected, @@ -51,7 +51,6 @@ export function useRichText( { element: ref.current, range, __unstableIsEditableTree: true, - preserveWhiteSpace, } ); } @@ -72,8 +71,7 @@ export function useRichText( { function setRecordFromProps() { _value.current = value; record.current = create( { - html: value, - preserveWhiteSpace, + html: preserveWhiteSpace ? value : collapseWhiteSpace( value ), } ); if ( disableFormats ) { record.current.formats = Array( value.length ); @@ -139,7 +137,6 @@ export function useRichText( { formats: __unstableBeforeSerialize( newRecord ), } : newRecord, - preserveWhiteSpace, } ); } @@ -168,7 +165,6 @@ export function useRichText( { formats: __unstableBeforeSerialize( newRecord ), } : newRecord, - preserveWhiteSpace, } ); const { formats, text } = newRecord; @@ -215,7 +211,7 @@ export function useRichText( { ref, useDefaultStyle(), useBoundaryStyle( { record } ), - useCopyHandler( { record, preserveWhiteSpace } ), + useCopyHandler( { record } ), useSelectObject(), useFormatBoundaries( { record, applyRecord } ), useDelete( { diff --git a/packages/rich-text/src/component/use-copy-handler.js b/packages/rich-text/src/component/use-copy-handler.js index 3be5935443215..f0ba652528e87 100644 --- a/packages/rich-text/src/component/use-copy-handler.js +++ b/packages/rich-text/src/component/use-copy-handler.js @@ -17,7 +17,7 @@ export function useCopyHandler( props ) { propsRef.current = props; return useRefEffect( ( element ) => { function onCopy( event ) { - const { record, preserveWhiteSpace } = propsRef.current; + const { record } = propsRef.current; const { ownerDocument } = element; if ( isCollapsed( record.current ) || @@ -28,10 +28,7 @@ export function useCopyHandler( props ) { const selectedRecord = slice( record.current ); const plainText = getTextContent( selectedRecord ); - const html = toHTMLString( { - value: selectedRecord, - preserveWhiteSpace, - } ); + const html = toHTMLString( { value: selectedRecord } ); event.clipboardData.setData( 'text/plain', plainText ); event.clipboardData.setData( 'text/html', html ); event.clipboardData.setData( 'rich-text', 'true' ); diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index 793bdca77f71d..63aac8c076b8b 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -135,8 +135,6 @@ function toFormat( { tagName, attributes } ) { * @param {string} [$1.text] Text to create value from. * @param {string} [$1.html] HTML to create value from. * @param {Range} [$1.range] Range to create value from. - * @param {boolean} [$1.preserveWhiteSpace] Whether or not to collapse - * white space characters. * @param {boolean} [$1.__unstableIsEditableTree] * * @return {RichTextValue} A rich text value. @@ -147,7 +145,6 @@ export function create( { html, range, __unstableIsEditableTree: isEditableTree, - preserveWhiteSpace, } = {} ) { if ( typeof text === 'string' && text.length > 0 ) { return { @@ -171,7 +168,6 @@ export function create( { element, range, isEditableTree, - preserveWhiteSpace, } ); } @@ -272,9 +268,17 @@ function filterRange( node, range, filter ) { * Collapse any whitespace used for HTML formatting to one space character, * because it will also be displayed as such by the browser. * + * We need to strip it from the content because we use white-space: pre-wrap for + * displaying editable rich text. Without using white-space: pre-wrap, the + * browser will litter the content with non breaking spaces, among other issues. + * See packages/rich-text/src/component/use-default-style.js. + * + * @see + * https://developer.mozilla.org/en-US/docs/Web/CSS/white-space-collapse#collapsing_of_white_space + * * @param {string} string */ -function collapseWhiteSpace( string ) { +export function collapseWhiteSpace( string ) { return string.replace( /[\n\r\t]+/g, ' ' ); } @@ -294,21 +298,14 @@ export function removeReservedCharacters( string ) { /** * Creates a Rich Text value from a DOM element and range. * - * @param {Object} $1 Named argements. - * @param {Element} [$1.element] Element to create value from. - * @param {Range} [$1.range] Range to create value from. - * @param {boolean} [$1.preserveWhiteSpace] Whether or not to collapse white - * space characters. + * @param {Object} $1 Named argements. + * @param {Element} [$1.element] Element to create value from. + * @param {Range} [$1.range] Range to create value from. * @param {boolean} [$1.isEditableTree] * * @return {RichTextValue} A rich text value. */ -function createFromElement( { - element, - range, - isEditableTree, - preserveWhiteSpace, -} ) { +function createFromElement( { element, range, isEditableTree } ) { const accumulator = createEmptyValue(); if ( ! element ) { @@ -328,15 +325,8 @@ function createFromElement( { const tagName = node.nodeName.toLowerCase(); if ( node.nodeType === node.TEXT_NODE ) { - let filter = removeReservedCharacters; - - if ( ! preserveWhiteSpace ) { - filter = ( string ) => - removeReservedCharacters( collapseWhiteSpace( string ) ); - } - - const text = filter( node.nodeValue ); - range = filterRange( node, range, filter ); + const text = removeReservedCharacters( node.nodeValue ); + range = filterRange( node, range, removeReservedCharacters ); accumulateSelection( accumulator, node, range, { text } ); // Create a sparse array of the same length as `text`, in which // formats can be added. @@ -417,7 +407,6 @@ function createFromElement( { element: node, range, isEditableTree, - preserveWhiteSpace, } ); accumulateSelection( accumulator, node, range, value ); diff --git a/packages/rich-text/src/test/__snapshots__/to-dom.js.snap b/packages/rich-text/src/test/__snapshots__/to-dom.js.snap index 5e2fbcac00de6..0daf48aa9a1c3 100644 --- a/packages/rich-text/src/test/__snapshots__/to-dom.js.snap +++ b/packages/rich-text/src/test/__snapshots__/to-dom.js.snap @@ -301,9 +301,3 @@ exports[`recordToDom should remove padding 1`] = `  `; - -exports[`recordToDom should replace characters to format HTML with space 1`] = ` - - - -`; diff --git a/packages/rich-text/src/test/helpers/index.js b/packages/rich-text/src/test/helpers/index.js index cff9daa3e24ec..f246ab956db3a 100644 --- a/packages/rich-text/src/test/helpers/index.js +++ b/packages/rich-text/src/test/helpers/index.js @@ -72,25 +72,6 @@ export const spec = [ text: 'hi', }, }, - { - description: 'should replace characters to format HTML with space', - html: '\n\n\r\n\t', - createRange: ( element ) => ( { - startOffset: 0, - startContainer: element, - endOffset: 1, - endContainer: element, - } ), - startPath: [ 0, 0 ], - endPath: [ 0, 1 ], - record: { - start: 0, - end: 1, - formats: [ , ], - replacements: [ , ], - text: ' ', - }, - }, { description: 'should preserve non breaking space', html: 'test\u00a0 test', diff --git a/packages/rich-text/src/to-html-string.js b/packages/rich-text/src/to-html-string.js index 66ae1d82b3845..3e25cbd5bcce1 100644 --- a/packages/rich-text/src/to-html-string.js +++ b/packages/rich-text/src/to-html-string.js @@ -19,17 +19,14 @@ import { toTree } from './to-tree'; /** * Create an HTML string from a Rich Text value. * - * @param {Object} $1 Named argements. - * @param {RichTextValue} $1.value Rich text value. - * @param {boolean} [$1.preserveWhiteSpace] Whether or not to use newline - * characters for line breaks. + * @param {Object} $1 Named argements. + * @param {RichTextValue} $1.value Rich text value. * * @return {string} HTML string. */ -export function toHTMLString( { value, preserveWhiteSpace } ) { +export function toHTMLString( { value } ) { const tree = toTree( { value, - preserveWhiteSpace, createEmpty, append, getLastChild, diff --git a/packages/rich-text/src/to-tree.js b/packages/rich-text/src/to-tree.js index c380570db561d..d2d347bc9ee04 100644 --- a/packages/rich-text/src/to-tree.js +++ b/packages/rich-text/src/to-tree.js @@ -129,7 +129,6 @@ function isEqualUntil( a, b, index ) { export function toTree( { value, - preserveWhiteSpace, createEmpty, append, getLastChild, @@ -268,7 +267,7 @@ export function toTree( { } // Ensure pointer is text node. pointer = append( getParent( pointer ), '' ); - } else if ( ! preserveWhiteSpace && character === '\n' ) { + } else if ( character === '\n' ) { pointer = append( getParent( pointer ), { type: 'br', attributes: isEditableTree diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Code-should-paste-plain-text-1-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Code-should-paste-plain-text-1-chromium.txt index 47b54e7c96405..7c76778feef43 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Code-should-paste-plain-text-1-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Code-should-paste-plain-text-1-chromium.txt @@ -1,4 +1,3 @@ -
<img />
-	<br>
+
<img />
<br>
\ No newline at end of file diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-character-newlines-2-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-character-newlines-2-chromium.txt index d1e3a3869958b..46e5991e53213 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-character-newlines-2-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-character-newlines-2-chromium.txt @@ -1,5 +1,3 @@ -
0
-1
-2
+
0
1
2
\ No newline at end of file diff --git a/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-white-space-when-merging-1-chromium.txt b/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-white-space-when-merging-1-chromium.txt index 3d3ef935d9f44..be7745e6bc120 100644 --- a/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-white-space-when-merging-1-chromium.txt +++ b/test/e2e/specs/editor/blocks/__snapshots__/Preformatted-should-preserve-white-space-when-merging-1-chromium.txt @@ -1,6 +1,3 @@ -
1
-2
-
-3
+
1
2

3
\ No newline at end of file diff --git a/test/e2e/specs/editor/blocks/verse-code-preformatted.spec.js b/test/e2e/specs/editor/blocks/verse-code-preformatted.spec.js index c3642bfbca312..fdb76a8277a46 100644 --- a/test/e2e/specs/editor/blocks/verse-code-preformatted.spec.js +++ b/test/e2e/specs/editor/blocks/verse-code-preformatted.spec.js @@ -43,7 +43,7 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); { name: blockName, attributes: { - content: 'a\n\nb', + content: 'a

b', }, }, ] ); diff --git a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-plain-text-in-plain-text-context-when-cross-block-selection-is-copied-2-chromium.txt b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-plain-text-in-plain-text-context-when-cross-block-selection-is-copied-2-chromium.txt index 2f13cd0939822..356ee09a32df6 100644 --- a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-plain-text-in-plain-text-context-when-cross-block-selection-is-copied-2-chromium.txt +++ b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-plain-text-in-plain-text-context-when-cross-block-selection-is-copied-2-chromium.txt @@ -7,7 +7,5 @@ -
ading
-
-Paragra
+
ading

Paragra
\ No newline at end of file