Skip to content

Commit f761037

Browse files
Gerardo PachecoellatrixJustinyAhin
authored
[Mobile] List V2 - Fixes split issues (#43949)
* Mobile - List V2 - Add useEnter to fix splitting issue * Merging blocks: allow x to be merged into wrapper blocks (quote, list, group...) (#42780) * Add test for the group block (#42801) Co-authored-by: Ella van Durpe <4710635+ellatrix@users.noreply.github.com> Co-authored-by: Justin Ahinon <justiny.ahinon@gmail.com>
1 parent 59dd5de commit f761037

14 files changed

+250
-110
lines changed

packages/block-editor/src/components/rich-text/index.native.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function RichTextWrapper(
114114
disableSuggestions,
115115
disableAutocorrection,
116116
containerWidth,
117+
onEnter: onCustomEnter,
117118
...props
118119
},
119120
forwardedRef
@@ -345,6 +346,10 @@ function RichTextWrapper(
345346
}
346347
}
347348

349+
if ( onCustomEnter ) {
350+
onCustomEnter();
351+
}
352+
348353
if ( multiline ) {
349354
if ( shiftKey ) {
350355
if ( ! disableLineBreaks ) {

packages/block-editor/src/store/actions.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,21 +1002,49 @@ export const __unstableExpandSelection =
10021002
*/
10031003
export const mergeBlocks =
10041004
( firstBlockClientId, secondBlockClientId ) =>
1005-
( { select, dispatch } ) => {
1005+
( { registry, select, dispatch } ) => {
10061006
const blocks = [ firstBlockClientId, secondBlockClientId ];
10071007
dispatch( { type: 'MERGE_BLOCKS', blocks } );
10081008

10091009
const [ clientIdA, clientIdB ] = blocks;
10101010
const blockA = select.getBlock( clientIdA );
10111011
const blockAType = getBlockType( blockA.name );
10121012

1013-
// Only focus the previous block if it's not mergeable.
1013+
if ( ! blockAType ) return;
1014+
1015+
const blockB = select.getBlock( clientIdB );
1016+
10141017
if ( blockAType && ! blockAType.merge ) {
1015-
dispatch.selectBlock( blockA.clientId );
1018+
// If there's no merge function defined, attempt merging inner
1019+
// blocks.
1020+
const blocksWithTheSameType = switchToBlockType(
1021+
blockB,
1022+
blockAType.name
1023+
);
1024+
// Only focus the previous block if it's not mergeable.
1025+
if ( blocksWithTheSameType?.length !== 1 ) {
1026+
dispatch.selectBlock( blockA.clientId );
1027+
return;
1028+
}
1029+
const [ blockWithSameType ] = blocksWithTheSameType;
1030+
if ( blockWithSameType.innerBlocks.length < 1 ) {
1031+
dispatch.selectBlock( blockA.clientId );
1032+
return;
1033+
}
1034+
registry.batch( () => {
1035+
dispatch.insertBlocks(
1036+
blockWithSameType.innerBlocks,
1037+
undefined,
1038+
clientIdA
1039+
);
1040+
dispatch.removeBlock( clientIdB );
1041+
dispatch.selectBlock(
1042+
blockWithSameType.innerBlocks[ 0 ].clientId
1043+
);
1044+
} );
10161045
return;
10171046
}
10181047

1019-
const blockB = select.getBlock( clientIdB );
10201048
const blockBType = getBlockType( blockB.name );
10211049
const { clientId, attributeKey, offset } = select.getSelectionStart();
10221050
const selectedBlockType =

packages/block-library/src/list-item/edit.native.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ import {
1616
import { __ } from '@wordpress/i18n';
1717
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
1818
import { useSelect } from '@wordpress/data';
19-
import { useState, useCallback } from '@wordpress/element';
19+
import { useState, useCallback, useRef } from '@wordpress/element';
2020

2121
/**
2222
* Internal dependencies
2323
*/
24-
import { useSplit, useMerge } from './hooks';
24+
import { useSplit, useMerge, useEnter } from './hooks';
2525
import { convertToListItems } from './utils';
2626
import { IndentUI } from './edit.js';
2727
import styles from './style.scss';
@@ -116,8 +116,26 @@ export default function ListItemEdit( {
116116
} ),
117117
};
118118

119+
const preventDefault = useRef( false );
120+
const { onEnter } = useEnter( { content, clientId }, preventDefault );
119121
const onSplit = useSplit( clientId );
120122
const onMerge = useMerge( clientId );
123+
const onSplitList = useCallback(
124+
( value ) => {
125+
if ( ! preventDefault.current ) {
126+
return onSplit( value );
127+
}
128+
},
129+
[ clientId, onSplit ]
130+
);
131+
const onReplaceList = useCallback(
132+
( blocks, ...args ) => {
133+
if ( ! preventDefault.current ) {
134+
onReplace( convertToListItems( blocks ), ...args );
135+
}
136+
},
137+
[ clientId, onReplace, convertToListItems ]
138+
);
121139
const onLayout = useCallback( ( { nativeEvent } ) => {
122140
setContentWidth( ( prevState ) => {
123141
const { width } = nativeEvent.layout;
@@ -158,11 +176,10 @@ export default function ListItemEdit( {
158176
placeholderTextColor={
159177
defaultPlaceholderTextColorWithOpacity
160178
}
161-
onSplit={ onSplit }
179+
onSplit={ onSplitList }
162180
onMerge={ onMerge }
163-
onReplace={ ( blocks, ...args ) => {
164-
onReplace( convertToListItems( blocks ), ...args );
165-
} }
181+
onReplace={ onReplaceList }
182+
onEnter={ onEnter }
166183
style={ styleWithPlaceholderOpacity }
167184
deleteEnter={ true }
168185
containerWidth={ contentWidth }
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import {
5+
createBlock,
6+
getDefaultBlockName,
7+
cloneBlock,
8+
} from '@wordpress/blocks';
9+
import { useRef } from '@wordpress/element';
10+
import { useSelect, useDispatch } from '@wordpress/data';
11+
import { store as blockEditorStore } from '@wordpress/block-editor';
12+
13+
/**
14+
* Internal dependencies
15+
*/
16+
import useOutdentListItem from './use-outdent-list-item';
17+
18+
export default function useEnter( props, preventDefault ) {
19+
const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore );
20+
const { getBlock, getBlockRootClientId, getBlockIndex } =
21+
useSelect( blockEditorStore );
22+
const propsRef = useRef( props );
23+
propsRef.current = props;
24+
const [ canOutdent, outdentListItem ] = useOutdentListItem(
25+
propsRef.current.clientId
26+
);
27+
28+
return {
29+
onEnter() {
30+
const { content, clientId } = propsRef.current;
31+
if ( content.length ) {
32+
return;
33+
}
34+
preventDefault.current = true;
35+
if ( canOutdent ) {
36+
outdentListItem();
37+
return;
38+
}
39+
// Here we are in top level list so we need to split.
40+
const topParentListBlock = getBlock(
41+
getBlockRootClientId( clientId )
42+
);
43+
const blockIndex = getBlockIndex( clientId );
44+
const head = cloneBlock( {
45+
...topParentListBlock,
46+
innerBlocks: topParentListBlock.innerBlocks.slice(
47+
0,
48+
blockIndex
49+
),
50+
} );
51+
const middle = createBlock( getDefaultBlockName() );
52+
// Last list item might contain a `list` block innerBlock
53+
// In that case append remaining innerBlocks blocks.
54+
const after = [
55+
...( topParentListBlock.innerBlocks[ blockIndex ]
56+
.innerBlocks[ 0 ]?.innerBlocks || [] ),
57+
...topParentListBlock.innerBlocks.slice( blockIndex + 1 ),
58+
];
59+
const tail = after.length
60+
? [
61+
cloneBlock( {
62+
...topParentListBlock,
63+
innerBlocks: after,
64+
} ),
65+
]
66+
: [];
67+
replaceBlocks(
68+
topParentListBlock.clientId,
69+
[ head, middle, ...tail ],
70+
1
71+
);
72+
// We manually change the selection here because we are replacing
73+
// a different block than the selected one.
74+
selectionChange( middle.clientId );
75+
},
76+
};
77+
}

packages/e2e-tests/specs/editor/blocks/__snapshots__/group.test.js.snap

Lines changed: 0 additions & 21 deletions
This file was deleted.

packages/e2e-tests/specs/editor/blocks/__snapshots__/quote.test.js.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ exports[`Quote can be split at the end 2`] = `
114114
"<!-- wp:quote -->
115115
<blockquote class=\\"wp-block-quote\\"><!-- wp:paragraph -->
116116
<p>1</p>
117+
<!-- /wp:paragraph -->
118+
119+
<!-- wp:paragraph -->
120+
<p></p>
117121
<!-- /wp:paragraph --></blockquote>
118122
<!-- /wp:quote -->"
119123
`;

packages/e2e-tests/specs/editor/blocks/group.test.js

Lines changed: 0 additions & 78 deletions
This file was deleted.

packages/e2e-tests/specs/editor/blocks/quote.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ describe( 'Quote', () => {
143143
expect( await getEditedPostContent() ).toMatchSnapshot();
144144

145145
await page.keyboard.press( 'Backspace' );
146+
await page.keyboard.type( '2' );
146147

147-
// Expect the paragraph to be deleted.
148+
// Expect the paragraph to be merged into the quote block.
148149
expect( await getEditedPostContent() ).toMatchSnapshot();
149150
} );
150151

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<!-- wp:group -->
2+
<div class="wp-block-group"></div>
3+
<!-- /wp:group -->
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<!-- wp:group -->
2+
<div class="wp-block-group"></div>
3+
<!-- /wp:group -->

0 commit comments

Comments
 (0)