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
117 changes: 101 additions & 16 deletions packages/block-editor/src/components/block-tools/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
/**
* External dependencies
*/
import { first, last } from 'lodash';

/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { useSelect, useDispatch } from '@wordpress/data';
import { useViewportMatch } from '@wordpress/compose';
import { Popover } from '@wordpress/components';
import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts';

/**
* Internal dependencies
Expand All @@ -23,29 +29,108 @@ import { usePopoverScroll } from './use-popover-scroll';
* @param {Object} $0.children The block content and style container.
* @param {Object} $0.__unstableContentRef Ref holding the content scroll container.
*/
export default function BlockTools( { children, __unstableContentRef } ) {
export default function BlockTools( {
children,
__unstableContentRef,
...props
} ) {
const isLargeViewport = useViewportMatch( 'medium' );
const hasFixedToolbar = useSelect(
( select ) => select( blockEditorStore ).getSettings().hasFixedToolbar,
[]
);
const isMatch = useShortcutEventMatch();
const { getSelectedBlockClientIds, getBlockRootClientId } = useSelect(
blockEditorStore
);
const {
duplicateBlocks,
removeBlocks,
insertAfterBlock,
insertBeforeBlock,
clearSelectedBlock,
moveBlocksUp,
moveBlocksDown,
} = useDispatch( blockEditorStore );

function onKeyDown( event ) {
if ( isMatch( 'core/block-editor/move-up', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
const rootClientId = getBlockRootClientId( first( clientIds ) );
moveBlocksUp( clientIds, rootClientId );
}
} else if ( isMatch( 'core/block-editor/move-down', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
const rootClientId = getBlockRootClientId( first( clientIds ) );
moveBlocksDown( clientIds, rootClientId );
}
} else if ( isMatch( 'core/block-editor/duplicate', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
duplicateBlocks( clientIds );
}
} else if ( isMatch( 'core/block-editor/remove', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
removeBlocks( clientIds );
}
} else if ( isMatch( 'core/block-editor/insert-after', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
insertAfterBlock( last( clientIds ) );
}
} else if ( isMatch( 'core/block-editor/insert-before', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length ) {
event.preventDefault();
insertBeforeBlock( first( clientIds ) );
}
} else if (
isMatch( 'core/block-editor/delete-multi-selection', event )
) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length > 1 ) {
event.preventDefault();
removeBlocks( clientIds );
}
} else if ( isMatch( 'core/block-editor/unselect', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length > 1 ) {
event.preventDefault();
clearSelectedBlock();
event.target.ownerDocument.defaultView
.getSelection()
.removeAllRanges();
}
}
}

return (
<InsertionPoint __unstableContentRef={ __unstableContentRef }>
{ ( hasFixedToolbar || ! isLargeViewport ) && (
<BlockContextualToolbar isFixed />
) }
{ /* Even if the toolbar is fixed, the block popover is still
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div { ...props } onKeyDown={ onKeyDown }>
<InsertionPoint __unstableContentRef={ __unstableContentRef }>
{ ( hasFixedToolbar || ! isLargeViewport ) && (
<BlockContextualToolbar isFixed />
) }
{ /* Even if the toolbar is fixed, the block popover is still
needed for navigation mode. */ }
<BlockPopover __unstableContentRef={ __unstableContentRef } />
{ /* Used for the inline rich text toolbar. */ }
<Popover.Slot
name="block-toolbar"
ref={ usePopoverScroll( __unstableContentRef ) }
/>
{ children }
{ /* Forward compatibility: a place to render block tools behind the
<BlockPopover __unstableContentRef={ __unstableContentRef } />
{ /* Used for the inline rich text toolbar. */ }
<Popover.Slot
name="block-toolbar"
ref={ usePopoverScroll( __unstableContentRef ) }
/>
{ children }
{ /* Forward compatibility: a place to render block tools behind the
content so it can be tabbed to properly. */ }
</InsertionPoint>
</InsertionPoint>
</div>
);
}
149 changes: 3 additions & 146 deletions packages/block-editor/src/components/keyboard-shortcuts/index.js
Original file line number Diff line number Diff line change
@@ -1,155 +1,12 @@
/**
* External dependencies
*/
import { first, last } from 'lodash';
/**
* WordPress dependencies
*/
import { useEffect, useCallback } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import {
useShortcut,
store as keyboardShortcutsStore,
} from '@wordpress/keyboard-shortcuts';
import { useEffect } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';

function KeyboardShortcuts() {
// Shortcuts Logic
const { clientIds, rootClientId } = useSelect( ( select ) => {
const { getSelectedBlockClientIds, getBlockRootClientId } = select(
blockEditorStore
);
const selectedClientIds = getSelectedBlockClientIds();
const [ firstClientId ] = selectedClientIds;
return {
clientIds: selectedClientIds,
rootClientId: getBlockRootClientId( firstClientId ),
};
}, [] );

const {
duplicateBlocks,
removeBlocks,
insertAfterBlock,
insertBeforeBlock,
clearSelectedBlock,
moveBlocksUp,
moveBlocksDown,
} = useDispatch( blockEditorStore );

// Moves selected block/blocks up
useShortcut(
'core/block-editor/move-up',
useCallback(
( event ) => {
event.preventDefault();
moveBlocksUp( clientIds, rootClientId );
},
[ clientIds, moveBlocksUp ]
),
{ bindGlobal: true, isDisabled: clientIds.length === 0 }
);

// Moves selected block/blocks up
useShortcut(
'core/block-editor/move-down',
useCallback(
( event ) => {
event.preventDefault();
moveBlocksDown( clientIds, rootClientId );
},
[ clientIds, moveBlocksDown ]
),
{ bindGlobal: true, isDisabled: clientIds.length === 0 }
);

// Prevents bookmark all Tabs shortcut in Chrome when devtools are closed.
// Prevents reposition Chrome devtools pane shortcut when devtools are open.
useShortcut(
'core/block-editor/duplicate',
useCallback(
( event ) => {
event.preventDefault();
duplicateBlocks( clientIds );
},
[ clientIds, duplicateBlocks ]
),
{ bindGlobal: true, isDisabled: clientIds.length === 0 }
);

// Does not clash with any known browser/native shortcuts, but preventDefault
// is used to prevent any obscure unknown shortcuts from triggering.
useShortcut(
'core/block-editor/remove',
useCallback(
( event ) => {
event.preventDefault();
removeBlocks( clientIds );
},
[ clientIds, removeBlocks ]
),
{ bindGlobal: true, isDisabled: clientIds.length === 0 }
);

// Does not clash with any known browser/native shortcuts, but preventDefault
// is used to prevent any obscure unknown shortcuts from triggering.
useShortcut(
'core/block-editor/insert-after',
useCallback(
( event ) => {
event.preventDefault();
insertAfterBlock( last( clientIds ) );
},
[ clientIds, insertAfterBlock ]
),
{ bindGlobal: true, isDisabled: clientIds.length === 0 }
);

// Prevent 'view recently closed tabs' in Opera using preventDefault.
useShortcut(
'core/block-editor/insert-before',
useCallback(
( event ) => {
event.preventDefault();
insertBeforeBlock( first( clientIds ) );
},
[ clientIds, insertBeforeBlock ]
),
{ bindGlobal: true, isDisabled: clientIds.length === 0 }
);

useShortcut(
'core/block-editor/delete-multi-selection',
useCallback(
( event ) => {
event.preventDefault();
removeBlocks( clientIds );
},
[ clientIds, removeBlocks ]
),
{ isDisabled: clientIds.length < 2 }
);

useShortcut(
'core/block-editor/unselect',
useCallback(
( event ) => {
event.preventDefault();
clearSelectedBlock();
event.target.ownerDocument.defaultView
.getSelection()
.removeAllRanges();
},
[ clientIds, clearSelectedBlock ]
),
{ isDisabled: clientIds.length < 2 }
);

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ export default function SidebarBlockEditor( {
<KeyboardShortcuts.Register />

<SidebarEditorProvider sidebar={ sidebar } settings={ settings }>
<BlockEditorKeyboardShortcuts />
<KeyboardShortcuts
undo={ sidebar.undo }
redo={ sidebar.redo }
Expand Down
1 change: 1 addition & 0 deletions packages/e2e-tests/specs/widgets/editing-widgets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ describe( 'Widgets screen', () => {
await page.keyboard.type( 'Second Paragraph' );

await saveWidgets();
await page.focus( '.block-editor-writing-flow' );

// Delete the last block and save again.
await pressKeyWithModifier( 'access', 'z' );
Expand Down
Loading