From 18ec1dd892591edfb8a720ac5508b72460baa844 Mon Sep 17 00:00:00 2001 From: Ella Date: Thu, 9 Nov 2023 15:30:52 +0200 Subject: [PATCH 1/7] Rich text: auto preserve whitespace --- .../src/components/editable-text/index.js | 9 +- .../src/components/rich-text/README.md | 4 - .../src/components/rich-text/index.js | 3 - .../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/block.json | 3 +- packages/block-library/src/code/edit.js | 1 - .../block-library/src/preformatted/block.json | 1 - .../block-library/src/preformatted/edit.js | 1 - packages/block-library/src/verse/block.json | 1 - packages/block-library/src/verse/edit.js | 1 - 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 | 11 +-- .../src/component/use-copy-handler.js | 7 +- packages/rich-text/src/create.js | 41 ++------- packages/rich-text/src/to-html-string.js | 9 +- packages/rich-text/src/to-tree.js | 3 +- 23 files changed, 43 insertions(+), 212 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..e11b83ec4de22 100644 --- a/packages/block-editor/src/components/rich-text/README.md +++ b/packages/block-editor/src/components/rich-text/README.md @@ -69,10 +69,6 @@ _Optional._ Whether to show the input is selected or not in order to show the fo _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. - ## RichText.Content `RichText.Content` should be used in the `save` function of your block to correctly save rich text 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..46f31cd6e0a1d 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -103,7 +103,6 @@ export function RichTextWrapper( __unstableOnSplitAtEnd: onSplitAtEnd, __unstableOnSplitAtDoubleLineEnd: onSplitAtDoubleLineEnd, identifier, - preserveWhiteSpace, __unstablePastePlainText: pastePlainText, __unstableEmbedURLOnPaste, __unstableDisableFormats: disableFormats, @@ -262,7 +261,6 @@ export function RichTextWrapper( placeholder, __unstableIsSelected: isSelected, __unstableDisableFormats: disableFormats, - preserveWhiteSpace, __unstableDependencies: [ ...dependencies, tagName ], __unstableAfterParse: addEditorOnlyFormats, __unstableBeforeSerialize: removeEditorOnlyFormats, @@ -348,7 +346,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/block.json b/packages/block-library/src/code/block.json index 80df74b5062b5..4d19423f1b629 100644 --- a/packages/block-library/src/code/block.json +++ b/packages/block-library/src/code/block.json @@ -10,8 +10,7 @@ "content": { "type": "string", "source": "html", - "selector": "code", - "__unstablePreserveWhiteSpace": true + "selector": "code" } }, "supports": { diff --git a/packages/block-library/src/code/edit.js b/packages/block-library/src/code/edit.js index a3dbedeaf2335..b39cf7c709def 100644 --- a/packages/block-library/src/code/edit.js +++ b/packages/block-library/src/code/edit.js @@ -24,7 +24,6 @@ export default function CodeEdit( { onMerge={ mergeBlocks } placeholder={ __( 'Write code…' ) } aria-label={ __( 'Code' ) } - preserveWhiteSpace __unstablePastePlainText __unstableOnSplitAtDoubleLineEnd={ () => insertBlocksAfter( createBlock( getDefaultBlockName() ) ) diff --git a/packages/block-library/src/preformatted/block.json b/packages/block-library/src/preformatted/block.json index ec6ea839385eb..49416bf4f5817 100644 --- a/packages/block-library/src/preformatted/block.json +++ b/packages/block-library/src/preformatted/block.json @@ -12,7 +12,6 @@ "source": "html", "selector": "pre", "default": "", - "__unstablePreserveWhiteSpace": true, "__experimentalRole": "content" } }, diff --git a/packages/block-library/src/preformatted/edit.js b/packages/block-library/src/preformatted/edit.js index 072475ff072c9..ce8a26e4784fd 100644 --- a/packages/block-library/src/preformatted/edit.js +++ b/packages/block-library/src/preformatted/edit.js @@ -20,7 +20,6 @@ export default function PreformattedEdit( { { setAttributes( { diff --git a/packages/block-library/src/verse/block.json b/packages/block-library/src/verse/block.json index d0fffc8ae5076..11e35c2ad3ebf 100644 --- a/packages/block-library/src/verse/block.json +++ b/packages/block-library/src/verse/block.json @@ -13,7 +13,6 @@ "source": "html", "selector": "pre", "default": "", - "__unstablePreserveWhiteSpace": true, "__experimentalRole": "content" }, "textAlign": { diff --git a/packages/block-library/src/verse/edit.js b/packages/block-library/src/verse/edit.js index a76ecc1ff6ab4..de1fa9a8d4605 100644 --- a/packages/block-library/src/verse/edit.js +++ b/packages/block-library/src/verse/edit.js @@ -44,7 +44,6 @@ export default function VerseEdit( { { setAttributes( { 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..9f7277cc1af50 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -25,7 +25,6 @@ export function useRichText( { selectionStart, selectionEnd, placeholder, - preserveWhiteSpace, onSelectionChange, onChange, __unstableDisableFormats: disableFormats, @@ -51,7 +50,6 @@ export function useRichText( { element: ref.current, range, __unstableIsEditableTree: true, - preserveWhiteSpace, } ); } @@ -71,10 +69,7 @@ export function useRichText( { function setRecordFromProps() { _value.current = value; - record.current = create( { - html: value, - preserveWhiteSpace, - } ); + record.current = create( { html: value } ); if ( disableFormats ) { record.current.formats = Array( value.length ); record.current.replacements = Array( value.length ); @@ -139,7 +134,6 @@ export function useRichText( { formats: __unstableBeforeSerialize( newRecord ), } : newRecord, - preserveWhiteSpace, } ); } @@ -168,7 +162,6 @@ export function useRichText( { formats: __unstableBeforeSerialize( newRecord ), } : newRecord, - preserveWhiteSpace, } ); const { formats, text } = newRecord; @@ -215,7 +208,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..b17c8356cd3bc 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, } ); } @@ -268,16 +264,6 @@ function filterRange( node, range, filter ) { return { startContainer, startOffset, endContainer, endOffset }; } -/** - * Collapse any whitespace used for HTML formatting to one space character, - * because it will also be displayed as such by the browser. - * - * @param {string} string - */ -function collapseWhiteSpace( string ) { - return string.replace( /[\n\r\t]+/g, ' ' ); -} - /** * Removes reserved characters used by rich-text (zero width non breaking spaces added by `toTree` and object replacement characters). * @@ -294,21 +280,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 +307,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 +389,6 @@ function createFromElement( { element: node, range, isEditableTree, - preserveWhiteSpace, } ); accumulateSelection( accumulator, node, range, value ); 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 From c576e362cef1345610617ec0fcb30569676952e2 Mon Sep 17 00:00:00 2001 From: Ella Date: Thu, 9 Nov 2023 16:46:16 +0200 Subject: [PATCH 2/7] Fix transforms --- packages/block-library/src/code/transforms.js | 22 ++++++++++++------- packages/block-library/src/html/transforms.js | 7 ++++-- .../src/preformatted/transforms.js | 5 +---- .../src/test/__snapshots__/to-dom.js.snap | 6 ----- packages/rich-text/src/test/helpers/index.js | 19 ---------------- ...ode-should-paste-plain-text-1-chromium.txt | 2 +- ...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 +--- 10 files changed, 25 insertions(+), 51 deletions(-) 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/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/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/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..9560b3bd8e9ad 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,4 @@
<img />
-	<br>
+
<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 From 0e50b6f06a41b15476f3a802b79e36ea12b741db Mon Sep 17 00:00:00 2001 From: Ella Date: Thu, 9 Nov 2023 17:14:38 +0200 Subject: [PATCH 3/7] Polish tests --- packages/block-library/src/paragraph/test/transforms.native.js | 1 + .../__snapshots__/Code-should-paste-plain-text-1-chromium.txt | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 9560b3bd8e9ad..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 From e11bc4c3dd3c9f7f4ef3974b96f296007c1b5008 Mon Sep 17 00:00:00 2001 From: Ella Date: Thu, 9 Nov 2023 18:25:35 +0200 Subject: [PATCH 4/7] Add missing snap --- .../paragraph/test/__snapshots__/transforms.native.js.snap | 6 ++++++ 1 file changed, 6 insertions(+) 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`] = ` "
From 0c2649337b7dfa94630b0370768e9150922590f7 Mon Sep 17 00:00:00 2001 From: Ella Date: Fri, 10 Nov 2023 15:53:36 +0200 Subject: [PATCH 5/7] Restore stripping white space when parsing HTML --- .../src/components/rich-text/README.md | 6 +++++ .../src/components/rich-text/index.js | 2 ++ packages/block-library/src/code/block.json | 3 ++- packages/block-library/src/code/edit.js | 1 + .../block-library/src/preformatted/block.json | 1 + .../block-library/src/preformatted/edit.js | 1 + packages/block-library/src/verse/block.json | 1 + packages/block-library/src/verse/edit.js | 1 + packages/rich-text/README.md | 1 + packages/rich-text/src/component/index.js | 3 ++- packages/rich-text/src/create.js | 22 +++++++++++++++++++ 11 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/README.md b/packages/block-editor/src/components/rich-text/README.md index e11b83ec4de22..85112af75165a 100644 --- a/packages/block-editor/src/components/rich-text/README.md +++ b/packages/block-editor/src/components/rich-text/README.md @@ -69,6 +69,12 @@ _Optional._ Whether to show the input is selected or not in order to show the fo _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 or +trimmed. + ## RichText.Content `RichText.Content` should be used in the `save` function of your block to correctly save rich text content. diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 46f31cd6e0a1d..1a6793ca9efe7 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -103,6 +103,7 @@ export function RichTextWrapper( __unstableOnSplitAtEnd: onSplitAtEnd, __unstableOnSplitAtDoubleLineEnd: onSplitAtDoubleLineEnd, identifier, + preserveWhiteSpace, __unstablePastePlainText: pastePlainText, __unstableEmbedURLOnPaste, __unstableDisableFormats: disableFormats, @@ -261,6 +262,7 @@ export function RichTextWrapper( placeholder, __unstableIsSelected: isSelected, __unstableDisableFormats: disableFormats, + preserveWhiteSpace, __unstableDependencies: [ ...dependencies, tagName ], __unstableAfterParse: addEditorOnlyFormats, __unstableBeforeSerialize: removeEditorOnlyFormats, diff --git a/packages/block-library/src/code/block.json b/packages/block-library/src/code/block.json index 4d19423f1b629..80df74b5062b5 100644 --- a/packages/block-library/src/code/block.json +++ b/packages/block-library/src/code/block.json @@ -10,7 +10,8 @@ "content": { "type": "string", "source": "html", - "selector": "code" + "selector": "code", + "__unstablePreserveWhiteSpace": true } }, "supports": { diff --git a/packages/block-library/src/code/edit.js b/packages/block-library/src/code/edit.js index b39cf7c709def..a3dbedeaf2335 100644 --- a/packages/block-library/src/code/edit.js +++ b/packages/block-library/src/code/edit.js @@ -24,6 +24,7 @@ export default function CodeEdit( { onMerge={ mergeBlocks } placeholder={ __( 'Write code…' ) } aria-label={ __( 'Code' ) } + preserveWhiteSpace __unstablePastePlainText __unstableOnSplitAtDoubleLineEnd={ () => insertBlocksAfter( createBlock( getDefaultBlockName() ) ) diff --git a/packages/block-library/src/preformatted/block.json b/packages/block-library/src/preformatted/block.json index 49416bf4f5817..ec6ea839385eb 100644 --- a/packages/block-library/src/preformatted/block.json +++ b/packages/block-library/src/preformatted/block.json @@ -12,6 +12,7 @@ "source": "html", "selector": "pre", "default": "", + "__unstablePreserveWhiteSpace": true, "__experimentalRole": "content" } }, diff --git a/packages/block-library/src/preformatted/edit.js b/packages/block-library/src/preformatted/edit.js index ce8a26e4784fd..072475ff072c9 100644 --- a/packages/block-library/src/preformatted/edit.js +++ b/packages/block-library/src/preformatted/edit.js @@ -20,6 +20,7 @@ export default function PreformattedEdit( { { setAttributes( { diff --git a/packages/block-library/src/verse/block.json b/packages/block-library/src/verse/block.json index 11e35c2ad3ebf..d0fffc8ae5076 100644 --- a/packages/block-library/src/verse/block.json +++ b/packages/block-library/src/verse/block.json @@ -13,6 +13,7 @@ "source": "html", "selector": "pre", "default": "", + "__unstablePreserveWhiteSpace": true, "__experimentalRole": "content" }, "textAlign": { diff --git a/packages/block-library/src/verse/edit.js b/packages/block-library/src/verse/edit.js index de1fa9a8d4605..a76ecc1ff6ab4 100644 --- a/packages/block-library/src/verse/edit.js +++ b/packages/block-library/src/verse/edit.js @@ -44,6 +44,7 @@ export default function VerseEdit( { { setAttributes( { diff --git a/packages/rich-text/README.md b/packages/rich-text/README.md index 90726ff238c1b..0df0e15f8d88c 100644 --- a/packages/rich-text/README.md +++ b/packages/rich-text/README.md @@ -174,6 +174,7 @@ _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_ diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index 9f7277cc1af50..b53e007996957 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -26,6 +26,7 @@ export function useRichText( { selectionEnd, placeholder, onSelectionChange, + preserveWhiteSpace, onChange, __unstableDisableFormats: disableFormats, __unstableIsSelected: isSelected, @@ -69,7 +70,7 @@ export function useRichText( { function setRecordFromProps() { _value.current = value; - record.current = create( { html: value } ); + record.current = create( { html: value, preserveWhiteSpace } ); if ( disableFormats ) { record.current.formats = Array( value.length ); record.current.replacements = Array( value.length ); diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index b17c8356cd3bc..b7a919dae7d1e 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -135,6 +135,8 @@ 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. @@ -145,6 +147,7 @@ export function create( { html, range, __unstableIsEditableTree: isEditableTree, + preserveWhiteSpace, } = {} ) { if ( typeof text === 'string' && text.length > 0 ) { return { @@ -155,6 +158,7 @@ export function create( { } if ( typeof html === 'string' && html.length > 0 ) { + html = preserveWhiteSpace ? html : collapseWhiteSpace( html ); // It does not matter which document this is, we're just using it to // parse. element = createElement( document, html ); @@ -264,6 +268,24 @@ function filterRange( node, range, filter ) { return { startContainer, startOffset, endContainer, endOffset }; } +/** + * 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 ) { + return string.replace( /[ \n\r\t]+/g, ' ' ).replace( /^ | $/g, '' ); +} + /** * Removes reserved characters used by rich-text (zero width non breaking spaces added by `toTree` and object replacement characters). * From 2ef1e3ab45ebf76bbda4b6eaa8e3b10cbfb2f7a2 Mon Sep 17 00:00:00 2001 From: Ella Date: Fri, 10 Nov 2023 16:18:41 +0200 Subject: [PATCH 6/7] Only collapse white space when initialising rich text --- packages/block-editor/src/components/rich-text/README.md | 3 +-- packages/rich-text/README.md | 1 - packages/rich-text/src/component/index.js | 6 ++++-- packages/rich-text/src/create.js | 6 +----- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/README.md b/packages/block-editor/src/components/rich-text/README.md index 85112af75165a..d17f987a34cf0 100644 --- a/packages/block-editor/src/components/rich-text/README.md +++ b/packages/block-editor/src/components/rich-text/README.md @@ -71,8 +71,7 @@ _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 or +_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/rich-text/README.md b/packages/rich-text/README.md index 0df0e15f8d88c..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_ diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index b53e007996957..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'; @@ -70,7 +70,9 @@ export function useRichText( { function setRecordFromProps() { _value.current = value; - record.current = create( { html: value, preserveWhiteSpace } ); + record.current = create( { + html: preserveWhiteSpace ? value : collapseWhiteSpace( value ), + } ); if ( disableFormats ) { record.current.formats = Array( value.length ); record.current.replacements = Array( value.length ); diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index b7a919dae7d1e..489af33db9420 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 { @@ -158,7 +155,6 @@ export function create( { } if ( typeof html === 'string' && html.length > 0 ) { - html = preserveWhiteSpace ? html : collapseWhiteSpace( html ); // It does not matter which document this is, we're just using it to // parse. element = createElement( document, html ); @@ -282,7 +278,7 @@ function filterRange( node, range, filter ) { * * @param {string} string */ -function collapseWhiteSpace( string ) { +export function collapseWhiteSpace( string ) { return string.replace( /[ \n\r\t]+/g, ' ' ).replace( /^ | $/g, '' ); } From 57a9fd752021a1dcb9680397441f2d39727d2d5e Mon Sep 17 00:00:00 2001 From: Ella Date: Fri, 10 Nov 2023 18:35:57 +0200 Subject: [PATCH 7/7] Restore original regex --- packages/rich-text/src/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index 489af33db9420..63aac8c076b8b 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -279,7 +279,7 @@ function filterRange( node, range, filter ) { * @param {string} string */ export function collapseWhiteSpace( string ) { - return string.replace( /[ \n\r\t]+/g, ' ' ).replace( /^ | $/g, '' ); + return string.replace( /[\n\r\t]+/g, ' ' ); } /**