diff --git a/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap b/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap index 71118e8d65118c..ef176d16bb9d75 100644 --- a/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap +++ b/packages/e2e-tests/specs/blocks/__snapshots__/list.test.js.snap @@ -144,6 +144,18 @@ exports[`List should indent and outdent level 2 3`] = ` " `; +exports[`List should insert a line break on shift+enter 1`] = ` +" + +" +`; + +exports[`List should insert a line break on shift+enter in a non trailing list item 1`] = ` +" + +" +`; + exports[`List should outdent with children 1`] = ` " diff --git a/packages/e2e-tests/specs/blocks/list.test.js b/packages/e2e-tests/specs/blocks/list.test.js index 98b7f74bd25362..915c9da4f537a5 100644 --- a/packages/e2e-tests/specs/blocks/list.test.js +++ b/packages/e2e-tests/specs/blocks/list.test.js @@ -280,4 +280,25 @@ describe( 'List', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should insert a line break on shift+enter', async () => { + await insertBlock( 'List' ); + await page.keyboard.type( 'a' ); + await pressKeyWithModifier( 'shift', 'Enter' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'should insert a line break on shift+enter in a non trailing list item', async () => { + await insertBlock( 'List' ); + await page.keyboard.type( 'a' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'b' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'c' ); + await page.keyboard.press( 'ArrowUp' ); + await pressKeyWithModifier( 'shift', 'Enter' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); diff --git a/packages/editor/src/components/rich-text/index.js b/packages/editor/src/components/rich-text/index.js index f91f5f77b17a42..59ba6e6e4225ce 100644 --- a/packages/editor/src/components/rich-text/index.js +++ b/packages/editor/src/components/rich-text/index.js @@ -33,6 +33,7 @@ import { toHTMLString, getTextContent, insert, + insertLineBreak, insertLineSeparator, isEmptyLine, unstableToDom, @@ -599,27 +600,15 @@ export class RichText extends Component { } if ( this.multilineTag ) { - if ( this.onSplit && isEmptyLine( record ) ) { + if ( event.shiftKey ) { + this.onChange( insertLineBreak( record ) ); + } else if ( this.onSplit && isEmptyLine( record ) ) { this.onSplit( ...split( record ).map( this.valueToFormat ) ); } else { this.onChange( insertLineSeparator( record ) ); } } else if ( event.shiftKey || ! this.onSplit ) { - const text = getTextContent( record ); - const length = text.length; - let toInsert = '\n'; - - // If the caret is at the end of the text, and there is no - // trailing line break or no text at all, we have to insert two - // line breaks in order to create a new line visually and place - // the caret there. - if ( record.end === length && ( - text.charAt( length - 1 ) !== '\n' || length === 0 - ) ) { - toInsert = '\n\n'; - } - - this.onChange( insert( record, toInsert ) ); + this.onChange( insertLineBreak( record ) ); } else { this.splitContent(); } diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js index 7ce8ed970e6ebe..423046079132bd 100644 --- a/packages/rich-text/src/index.js +++ b/packages/rich-text/src/index.js @@ -19,6 +19,7 @@ export { removeFormat } from './remove-format'; export { remove } from './remove'; export { replace } from './replace'; export { insert } from './insert'; +export { insertLineBreak } from './insert-line-break'; export { insertLineSeparator } from './insert-line-separator'; export { insertObject } from './insert-object'; export { slice } from './slice'; diff --git a/packages/rich-text/src/insert-line-break.js b/packages/rich-text/src/insert-line-break.js new file mode 100644 index 00000000000000..540214d614f3c6 --- /dev/null +++ b/packages/rich-text/src/insert-line-break.js @@ -0,0 +1,34 @@ +/** + * Internal dependencies + */ + +import { insert } from './insert'; +import { LINE_SEPARATOR } from './special-characters'; + +/** + * Inserts a line break at the given or selected position. Inserts two line + * breaks if at the end of a line. + * + * @param {Object} value Value to modify. + * + * @return {Object} The value with the line break(s) inserted. + */ +export function insertLineBreak( value ) { + const { text, end } = value; + const length = text.length; + + let toInsert = '\n'; + + // If the caret is at the end of the text, and there is no + // trailing line break or no text at all, we have to insert two + // line breaks in order to create a new line visually and place + // the caret there. + if ( + ( end === length || text[ end ] === LINE_SEPARATOR ) && + ( text[ end - 1 ] !== '\n' || length === 0 ) + ) { + toInsert = '\n\n'; + } + + return insert( value, toInsert ); +}