Skip to content

Commit

Permalink
[List v2]: Indent multiple list items (#40991)
Browse files Browse the repository at this point in the history
* [List v2]: Indent multiple list items

* simplify logic
  • Loading branch information
ntsekouras authored May 12, 2022
1 parent ed1f17d commit db7b40e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 64 deletions.
113 changes: 50 additions & 63 deletions packages/block-library/src/list-item/hooks/use-indent-list-item.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,76 @@
/**
* External dependencies
*/
import { first } from 'lodash';

/**
* WordPress dependencies
*/
import { useCallback } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { createListItem } from '../utils';
import { createBlock, cloneBlock } from '@wordpress/blocks';

export default function useIndentListItem( clientId ) {
const { canIndent } = useSelect(
( innerSelect ) => {
const { getBlockIndex } = innerSelect( blockEditorStore );
return {
canIndent: getBlockIndex( clientId ) > 0,
};
},
const canIndent = useSelect(
( select ) => select( blockEditorStore ).getBlockIndex( clientId ) > 0,
[ clientId ]
);
const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore );
const { replaceBlocks, selectionChange, multiSelect } = useDispatch(
blockEditorStore
);
const {
getBlockRootClientId,
getBlock,
getBlockOrder,
getPreviousBlockClientId,
getSelectionStart,
getSelectionEnd,
getBlockIndex,
hasMultiSelection,
getMultiSelectedBlockClientIds,
} = useSelect( blockEditorStore );

return [
canIndent,
useCallback( () => {
const _hasMultiSelection = hasMultiSelection();
const clientIds = _hasMultiSelection
? getMultiSelectedBlockClientIds()
: [ clientId ];
const clonedBlocks = clientIds.map( ( _clientId ) =>
cloneBlock( getBlock( _clientId ) )
);
const previousSiblingId = getPreviousBlockClientId( clientId );
const newListItem = cloneBlock( getBlock( previousSiblingId ) );
// If the sibling has no innerBlocks, create a new `list` block.
if ( ! newListItem.innerBlocks?.length ) {
newListItem.innerBlocks = [ createBlock( 'core/list' ) ];
}
// A list item usually has one `list`, but it's possible to have
// more. So we need to preserve the previous `list` blocks and
// merge the new blocks to the last `list`.
newListItem.innerBlocks[
newListItem.innerBlocks.length - 1
].innerBlocks.push( ...clonedBlocks );

// We get the selection start/end here, because when
// we replace blocks, the selection is updated too.
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();

const parentId = getBlockRootClientId( clientId );
const previousSiblingId = getBlockOrder( parentId )[
getBlockIndex( clientId ) - 1
];
const previousSibling = getBlock( previousSiblingId );
const previousSiblingChildren =
first( previousSibling.innerBlocks )?.innerBlocks || [];
const previousSiblingListAttributes =
first( previousSibling.innerBlocks )?.attributes || {};
const block = getBlock( clientId );

const childListAttributes = first( block.innerBlocks )?.attributes;
const childItemBlocks =
first( block.innerBlocks )?.innerBlocks || [];

const newBlock = createListItem(
block.attributes,
childListAttributes,
childItemBlocks
);
// Replace the previous sibling of the block being indented and the indented block,
// Replace the previous sibling of the block being indented and the indented blocks,
// with a new block whose attributes are equal to the ones of the previous sibling and
// whose descendants are the children of the previous sibling, followed by the indented block.
// whose descendants are the children of the previous sibling, followed by the indented blocks.
replaceBlocks(
[ previousSiblingId, clientId ],
[
createListItem(
previousSibling.attributes,
previousSiblingListAttributes,
[ ...previousSiblingChildren, newBlock ]
),
]
);

// Restore the selection state.
selectionChange(
newBlock.clientId,
selectionEnd.attributeKey,
selectionEnd.clientId === selectionStart.clientId
? selectionStart.offset
: selectionEnd.offset,
selectionEnd.offset
[ previousSiblingId, ...clientIds ],
[ newListItem ]
);
if ( ! _hasMultiSelection ) {
selectionChange(
clonedBlocks[ 0 ].clientId,
selectionEnd.attributeKey,
selectionEnd.clientId === selectionStart.clientId
? selectionStart.offset
: selectionEnd.offset,
selectionEnd.offset
);
} else {
multiSelect(
clonedBlocks[ 0 ].clientId,
clonedBlocks[ clonedBlocks.length - 1 ].clientId
);
}
}, [ clientId ] ),
];
}
2 changes: 1 addition & 1 deletion packages/block-library/src/list-item/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function createListItem( listItemAttributes, listAttributes, children ) {
return createBlock(
'core/list-item',
listItemAttributes,
! children || ! children.length
! children?.length
? []
: [ createBlock( 'core/list', listAttributes, children ) ]
);
Expand Down

0 comments on commit db7b40e

Please sign in to comment.