Skip to content

Commit

Permalink
feat: Split formatted text on triple Enter (#53354)
Browse files Browse the repository at this point in the history
* feat: Split formatted text on triple enter

It is difficult to exit a formatted text block, e.g. Verse, using only
the keyboard. This splits the block when pressing enter and the two
previous characters are line breaks.

* feat: Split Code block on triple enter

Apply Verse and Preformatted block behavior to the Code block. However,
this applied code does not currently run as Code relies upon the older
version of `PlainText`.

* feat: Enable PlainText v2 for the Code block

Improve splitting and merging block functionality by relying upon the
more robust `RichText` component. Merging blocks into Code does not
always work as expected, e.g. a Paragraph into a Code block fails.

* fix: RichText applies direction-specific padding

Certain contexts apply different padding for different directions, e.g.
horizontal vs vertical, left vs right.

* Revert "fix: RichText applies direction-specific padding"

This reverts commit 6205651.

* Revert "feat: Enable PlainText v2 for the Code block"

This reverts commit 37d3fa3.

* test: Split formatted text block on triple Enter

* docs: Add change log entry
  • Loading branch information
dcalhoun authored Oct 5, 2023
1 parent 94de5db commit 8b09de4
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 4 deletions.
22 changes: 19 additions & 3 deletions packages/block-editor/src/components/rich-text/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
__unstableCreateElement,
isEmpty,
insert,
remove,
create,
split,
toHTMLString,
Expand Down Expand Up @@ -70,6 +71,7 @@ function RichTextWrapper(
onSplit,
__unstableOnSplitAtEnd: onSplitAtEnd,
__unstableOnSplitMiddle: onSplitMiddle,
__unstableOnSplitAtDoubleLineEnd: onSplitAtDoubleLineEnd,
identifier,
preserveWhiteSpace,
__unstablePastePlainText: pastePlainText,
Expand Down Expand Up @@ -339,14 +341,28 @@ function RichTextWrapper(
splitStart === splitEnd &&
splitEnd === text.length;

if ( shiftKey || ( ! canSplit && ! canSplitAtEnd ) ) {
if ( shiftKey ) {
if ( ! disableLineBreaks ) {
onChange( insert( value, '\n' ) );
}
} else if ( ! canSplit && canSplitAtEnd ) {
onSplitAtEnd();
} else if ( canSplit ) {
splitValue( value );
} else if ( canSplitAtEnd ) {
onSplitAtEnd();
} else if (
// For some blocks it's desirable to split at the end of the
// block when there are two line breaks at the end of the
// block, so triple Enter exits the block.
onSplitAtDoubleLineEnd &&
splitStart === splitEnd &&
splitEnd === text.length &&
text.slice( -2 ) === '\n\n'
) {
value.start = value.end - 2;
onChange( remove( value ) );
onSplitAtDoubleLineEnd();
} else if ( ! disableLineBreaks ) {
onChange( insert( value, '\n' ) );
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
16 changes: 15 additions & 1 deletion packages/block-library/src/code/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { View } from 'react-native';
import { PlainText } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
import { createBlock, getDefaultBlockName } from '@wordpress/blocks';

/**
* Internal dependencies
Expand All @@ -22,7 +23,15 @@ import styles from './theme.scss';
// Note: styling is applied directly to the (nested) PlainText component. Web-side components
// apply it to the container 'div' but we don't have a proper proposal for cascading styling yet.
export function CodeEdit( props ) {
const { attributes, setAttributes, onFocus, onBlur, style } = props;
const {
attributes,
setAttributes,
onFocus,
onBlur,
style,
insertBlocksAfter,
mergeBlocks,
} = props;
const codeStyle = {
...usePreferredColorSchemeStyle(
styles.blockCode,
Expand All @@ -40,16 +49,21 @@ export function CodeEdit( props ) {
<View>
<PlainText
value={ attributes.content }
identifier="content"
style={ codeStyle }
multiline={ true }
underlineColorAndroid="transparent"
onChange={ ( content ) => setAttributes( { content } ) }
onMerge={ mergeBlocks }
placeholder={ __( 'Write code…' ) }
aria-label={ __( 'Code' ) }
isSelected={ props.isSelected }
onFocus={ onFocus }
onBlur={ onBlur }
placeholderTextColor={ placeholderStyle.color }
__unstableOnSplitAtDoubleLineEnd={ () =>
insertBlocksAfter( createBlock( getDefaultBlockName() ) )
}
/>
</View>
);
Expand Down
38 changes: 38 additions & 0 deletions packages/block-library/src/preformatted/test/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,42 @@ describe( 'Preformatted', () => {
<!-- /wp:preformatted -->"
` );
} );

it( 'should split on triple Enter', async () => {
// Arrange
const screen = await initializeEditor();

// Act
await addBlock( screen, 'Preformatted' );
const preformattedTextInput = await screen.findByPlaceholderText(
'Write preformatted text…'
);
typeInRichText( preformattedTextInput, 'Hello' );
fireEvent( preformattedTextInput, 'onKeyDown', {
nativeEvent: {},
preventDefault() {},
keyCode: ENTER,
} );
fireEvent( preformattedTextInput, 'onKeyDown', {
nativeEvent: {},
preventDefault() {},
keyCode: ENTER,
} );
fireEvent( preformattedTextInput, 'onKeyDown', {
nativeEvent: {},
preventDefault() {},
keyCode: ENTER,
} );

// Assert
expect( getEditorHtml() ).toMatchInlineSnapshot( `
"<!-- wp:preformatted -->
<pre class="wp-block-preformatted">Hello</pre>
<!-- /wp:preformatted -->
<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->"
` );
} );
} );
37 changes: 37 additions & 0 deletions packages/block-library/src/verse/test/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,41 @@ describe( 'Verse block', () => {
<!-- /wp:verse -->"
` );
} );

it( 'should split on triple Enter', async () => {
// Arrange
const screen = await initializeEditor();
await addBlock( screen, 'Verse' );

// Act
const verseTextInput =
await screen.findByPlaceholderText( 'Write verse…' );
typeInRichText( verseTextInput, 'Hello' );
fireEvent( verseTextInput, 'onKeyDown', {
nativeEvent: {},
preventDefault() {},
keyCode: ENTER,
} );
fireEvent( verseTextInput, 'onKeyDown', {
nativeEvent: {},
preventDefault() {},
keyCode: ENTER,
} );
fireEvent( verseTextInput, 'onKeyDown', {
nativeEvent: {},
preventDefault() {},
keyCode: ENTER,
} );

// Assert
expect( getEditorHtml() ).toMatchInlineSnapshot( `
"<!-- wp:verse -->
<pre class="wp-block-verse">Hello</pre>
<!-- /wp:verse -->
<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->"
` );
} );
} );
1 change: 1 addition & 0 deletions packages/react-native-editor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ For each user feature we should also add a importance categorization label to i
-->

## Unreleased
- [*] Exit Preformatted and Verse blocks by triple pressing the Return key [#53354]

## 1.105.0
- [*] Limit inner blocks nesting depth to avoid call stack size exceeded crash [#54382]
Expand Down

1 comment on commit 8b09de4

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 8b09de4.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/6420056685
📝 Reported issues:

Please sign in to comment.