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 ea58c212ee3a21..12da83aa2d4d39 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 );
+}