Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/block-library/src/list-item/edit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { useMergeRefs } from '@wordpress/compose';
import { useSelect, useRegistry } from '@wordpress/data';
import { displayShortcut } from '@wordpress/keycodes';
import { useEnter, useSpace, useMultiSelectTab, useMerge } from './hooks';
import { useEnter, useTab, useMultiSelectTab, useMerge } from './hooks';
import {
indentListItems,
outdentListItems,
Expand Down Expand Up @@ -72,7 +72,7 @@ export default function ListItemEdit( {
__unstableDisableDropZone: true,
} );
const useEnterRef = useEnter( clientId );
const useSpaceRef = useSpace();
const useTabRef = useTab();
const useMultiSelectTabRef = useMultiSelectTab( clientId );
const onMerge = useMerge( clientId, mergeBlocks );
return (
Expand All @@ -81,7 +81,7 @@ export default function ListItemEdit( {
<RichText
ref={ useMergeRefs( [
useEnterRef,
useSpaceRef,
useTabRef,
useMultiSelectTabRef,
] ) }
identifier="content"
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/list-item/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { default as useEnter } from './use-enter';
export { default as useSpace } from './use-space';
export { default as useTab } from './use-tab';
export { default as useMultiSelectTab } from './use-multi-select-tab';
export { default as useMerge } from './use-merge';
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { privateApis as richTextPrivateApis } from '@wordpress/rich-text';
import { SPACE, TAB } from '@wordpress/keycodes';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { useRegistry } from '@wordpress/data';
import { isEntirelySelected } from '@wordpress/dom';
import { indentListItems, outdentListItems } from '../utils';
import { unlock } from '../../lock-unlock';

const { subscribeOwnedListener } = unlock( richTextPrivateApis );

export default function useSpace() {
export default function useTab() {
const registry = useRegistry();

return useRefEffect(
Expand All @@ -19,7 +20,7 @@ export default function useSpace() {
if (
event.defaultPrevented ||
( keyCode !== SPACE && keyCode !== TAB ) ||
// Only override when no modifiers are pressed.
// Shift selects outdent; other modifiers pass through.
altKey ||
metaKey ||
ctrlKey
Expand All @@ -29,22 +30,21 @@ export default function useSpace() {

const { getSelectionStart, getSelectionEnd } =
registry.select( blockEditorStore );
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();
const isAtStart =
getSelectionStart().offset === 0 &&
getSelectionEnd().offset === 0;

// Both keys act at the start of an item; Tab also acts on a
// full selection.
if (
selectionStart.offset === 0 &&
selectionEnd.offset === 0
! isAtStart &&
! ( keyCode === TAB && isEntirelySelected( element ) )
) {
if ( shiftKey ) {
// Note that backspace behaviour in defined in onMerge.
if ( keyCode === TAB ) {
if ( outdentListItems( registry ) ) {
event.preventDefault();
}
}
} else if ( indentListItems( registry ) ) {
event.preventDefault();
}
return;
}
const move = shiftKey ? outdentListItems : indentListItems;
if ( move( registry ) ) {
event.preventDefault();
}
}

Expand Down
98 changes: 98 additions & 0 deletions test/e2e/specs/editor/blocks/list.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,104 @@ test.describe( 'List (@firefox)', () => {
);
} );

test( 'should indent and outdent a list item when its content is fully selected', async ( {
editor,
page,
pageUtils,
} ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'b' );

// Select the whole item and Tab to indent it.
await pageUtils.pressKeys( 'primary+a' );
await page.keyboard.press( 'Tab' );

await expect.poll( editor.getEditedPostContent ).toBe(
`<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>a<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>b</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list --></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->`
);

// The item stays fully selected, so typing replaces its content.
await page.keyboard.type( 'c' );
await expect.poll( editor.getEditedPostContent ).toBe(
`<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>a<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>c</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list --></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->`
);

// Select the whole item again and Shift+Tab to outdent it.
await pageUtils.pressKeys( 'primary+a' );
await page.keyboard.press( 'Shift+Tab' );

await expect.poll( editor.getEditedPostContent ).toBe(
`<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>a</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>c</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->`
);
} );

test( 'should indent with Space and outdent with Shift+Space at the start', async ( {
editor,
page,
} ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'b' );

// Move the caret to the start of the item and Space to indent it.
await page.keyboard.press( 'ArrowLeft' );
await page.keyboard.press( 'Space' );

await expect.poll( editor.getEditedPostContent ).toBe(
`<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>a<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>b</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list --></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->`
);

// Shift+Space at the start outdents it back to the top level.
await page.keyboard.press( 'Shift+Space' );

await expect.poll( editor.getEditedPostContent ).toBe(
`<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>a</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>b</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->`
);
} );

test( 'should keep the list type when indenting an ordered list item', async ( {
editor,
page,
Expand Down
Loading