From 7f3ae2efc48a68f61428903ab78018f084b2f339 Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Tue, 1 Oct 2019 17:02:37 +0100 Subject: [PATCH 1/6] Add keyboard navigation options on blocks. --- .../with-keyboard-navigation-handler.js | 86 +++++++++++++++++++ assets/src/stories-editor/components/index.js | 1 + assets/src/stories-editor/index.js | 2 + 3 files changed, 89 insertions(+) create mode 100644 assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js diff --git a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js new file mode 100644 index 00000000000..1b35f80ec9f --- /dev/null +++ b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js @@ -0,0 +1,86 @@ +/** + * WordPress dependencies + */ +import { withDispatch } from '@wordpress/data'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { UP, DOWN, RIGHT, LEFT, DELETE } from '@wordpress/keycodes'; +/** + * Internal dependencies + */ +import { ALLOWED_CHILD_BLOCKS } from '../../constants'; + +const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { + const { isReordering } = select( 'amp/story' ); + const { getSelectedBlock } = select( 'core/block-editor' ); + const { updateBlockAttributes, removeBlock } = dispatch( 'core/block-editor' ); + + const onKeyPress = ( event ) => { + const { keyCode } = event; + const selectedBlock = getSelectedBlock(); + if(!selectedBlock){ + return; + } + + let top = 0; + let left = 0; + switch(keyCode){ + case UP: + top = -1; + break; + case DOWN: + top = 1; + break; + case RIGHT: + left = 1; + break; + case LEFT: + left = -1; + break; + case DELETE: + removeBlock( selectedBlock.clientId ); + return; + default: + return; + } + event.preventDefault(); + const newPositionTop = selectedBlock.attributes.positionTop + top; + const newPositionLeft = selectedBlock.attributes.positionLeft + left; + updateBlockAttributes( selectedBlock.clientId, { positionTop: newPositionTop, positionLeft: newPositionLeft } ); + + }; + + return { + isReordering, + onKeyPress, + }; +} ); + +/** + * Higher-order component that adds right click handler to each inner block. + * + * @return {Function} Higher-order component. + */ +export default createHigherOrderComponent( + ( BlockEdit ) => { + return applyWithDispatch( ( props ) => { + const { name, onKeyPress, isReordering } = props; + const isPageBlock = 'amp/amp-story-page' === name; + + // Add for page block and inner blocks. + if ( ! isPageBlock && ! ALLOWED_CHILD_BLOCKS.includes( name ) ) { + return ; + } + + // Not relevant for reordering. + if ( isReordering() ) { + return ; + } + return ( +
+ +
+ ); + } ); + }, + 'withKeyboardNavigationHandler' +); diff --git a/assets/src/stories-editor/components/index.js b/assets/src/stories-editor/components/index.js index d6744a89c32..e145f7c6244 100644 --- a/assets/src/stories-editor/components/index.js +++ b/assets/src/stories-editor/components/index.js @@ -30,6 +30,7 @@ export { default as withCroppedFeaturedImage } from './with-cropped-featured-ima export { default as withHasSelectedInnerBlock } from './higher-order/with-has-selected-inner-block'; export { default as withPageNumber } from './higher-order/with-page-number'; export { default as withRightClickHandler } from './higher-order/with-right-click-handler'; +export { default as withKeyboardNavigation } from './higher-order/with-keyboard-navigation-handler'; export { default as withStoryFeaturedImageNotice } from './higher-order/with-story-featured-image-notice'; export { default as withEditFeaturedImage } from './with-edit-featured-image'; export { default as withCustomVideoBlockEdit } from './with-custom-video-block-edit'; diff --git a/assets/src/stories-editor/index.js b/assets/src/stories-editor/index.js index 69f98ba9f29..3f9cc9da32a 100644 --- a/assets/src/stories-editor/index.js +++ b/assets/src/stories-editor/index.js @@ -39,6 +39,7 @@ import { withCallToActionValidation, withCroppedFeaturedImage, withRightClickHandler, + withKeyboardNavigation, } from './components'; import { maybeEnqueueFontStyle, @@ -317,6 +318,7 @@ addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/deprecateCoreBlocks addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addStorySettings', withAmpStorySettings ); addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addPageNumber', withPageNumber ); addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/rightClickHandler', withRightClickHandler ); +addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/keyboardHandler', withKeyboardNavigation ); addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/addEditFeaturedImage', withEditFeaturedImage ); addFilter( 'editor.BlockEdit', 'ampEditorBlocks/addVideoBlockPreview', withCustomVideoBlockEdit, 9 ); addFilter( 'editor.PostFeaturedImage', 'ampStoryEditorBlocks/addFeaturedImageNotice', withStoryFeaturedImageNotice ); From 0e9bbe3e5a099e643932e637b05df5aeb399f70e Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Tue, 1 Oct 2019 17:18:13 +0100 Subject: [PATCH 2/6] Fix lints. --- .../with-keyboard-navigation-handler.js | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js index 1b35f80ec9f..31032b0dd9b 100644 --- a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js +++ b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js @@ -7,7 +7,7 @@ import { UP, DOWN, RIGHT, LEFT, DELETE } from '@wordpress/keycodes'; /** * Internal dependencies */ -import { ALLOWED_CHILD_BLOCKS } from '../../constants'; +import { ALLOWED_CHILD_BLOCKS, ALLOWED_MOVABLE_BLOCKS } from '../../constants'; const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { const { isReordering } = select( 'amp/story' ); @@ -17,13 +17,13 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { const onKeyPress = ( event ) => { const { keyCode } = event; const selectedBlock = getSelectedBlock(); - if(!selectedBlock){ + if ( ! selectedBlock ) { return; } let top = 0; let left = 0; - switch(keyCode){ + switch ( keyCode ) { case UP: top = -1; break; @@ -43,10 +43,14 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { return; } event.preventDefault(); - const newPositionTop = selectedBlock.attributes.positionTop + top; - const newPositionLeft = selectedBlock.attributes.positionLeft + left; - updateBlockAttributes( selectedBlock.clientId, { positionTop: newPositionTop, positionLeft: newPositionLeft } ); - + if ( ALLOWED_MOVABLE_BLOCKS.includes( selectedBlock.name ) ) { + const newPositionTop = selectedBlock.attributes.positionTop + top; + const newPositionLeft = selectedBlock.attributes.positionLeft + left; + updateBlockAttributes( selectedBlock.clientId, { + positionTop: newPositionTop, + positionLeft: newPositionLeft, + } ); + } }; return { @@ -76,7 +80,7 @@ export default createHigherOrderComponent( return ; } return ( -
+
); From 3e3fff07737a1113750c216669f68aa5ff15b10a Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Tue, 1 Oct 2019 18:45:05 +0100 Subject: [PATCH 3/6] Add check for text field selected. --- .../higher-order/with-keyboard-navigation-handler.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js index 31032b0dd9b..de5ffde8a84 100644 --- a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js +++ b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js @@ -15,12 +15,18 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { const { updateBlockAttributes, removeBlock } = dispatch( 'core/block-editor' ); const onKeyPress = ( event ) => { - const { keyCode } = event; + const { keyCode, target } = event; + const { classList } = target; const selectedBlock = getSelectedBlock(); + if ( ! selectedBlock ) { return; } + if ( classList.contains( 'editor-rich-text__editable' ) && classList.contains( 'is-selected' ) ) { + return; + } + let top = 0; let left = 0; switch ( keyCode ) { @@ -69,7 +75,6 @@ export default createHigherOrderComponent( return applyWithDispatch( ( props ) => { const { name, onKeyPress, isReordering } = props; const isPageBlock = 'amp/amp-story-page' === name; - // Add for page block and inner blocks. if ( ! isPageBlock && ! ALLOWED_CHILD_BLOCKS.includes( name ) ) { return ; @@ -79,6 +84,7 @@ export default createHigherOrderComponent( if ( isReordering() ) { return ; } + return (
From 314c4d1edd84991dde80a136c2d5bb5e6d0683bb Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Wed, 2 Oct 2019 10:50:17 +0100 Subject: [PATCH 4/6] Fix lints. --- .../components/higher-order/with-keyboard-navigation-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js index de5ffde8a84..fa6f96ccdf1 100644 --- a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js +++ b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js @@ -86,7 +86,7 @@ export default createHigherOrderComponent( } return ( -
+
); From 0d0698e71104073eaed37135be96fe7670b93f95 Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Thu, 3 Oct 2019 11:53:00 +0100 Subject: [PATCH 5/6] Refactor to use keyboard shortcuts from gutenberg library. --- .../with-keyboard-navigation-handler.js | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js index fa6f96ccdf1..d84d7c4cf15 100644 --- a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js +++ b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js @@ -3,7 +3,8 @@ */ import { withDispatch } from '@wordpress/data'; import { createHigherOrderComponent } from '@wordpress/compose'; -import { UP, DOWN, RIGHT, LEFT, DELETE } from '@wordpress/keycodes'; +import { UP, DOWN, RIGHT, LEFT } from '@wordpress/keycodes'; +import { KeyboardShortcuts } from '@wordpress/components'; /** * Internal dependencies */ @@ -13,17 +14,17 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { const { isReordering } = select( 'amp/story' ); const { getSelectedBlock } = select( 'core/block-editor' ); const { updateBlockAttributes, removeBlock } = dispatch( 'core/block-editor' ); + const selectedBlock = getSelectedBlock(); - const onKeyPress = ( event ) => { + const onMoveBlock = ( event ) => { const { keyCode, target } = event; const { classList } = target; - const selectedBlock = getSelectedBlock(); if ( ! selectedBlock ) { return; } - if ( classList.contains( 'editor-rich-text__editable' ) && classList.contains( 'is-selected' ) ) { + if ( classList.contains( 'editor-rich-text__editable' ) && ( classList.contains( 'is-selected' ) || classList.contains( 'is-typing' ) ) ) { return; } @@ -42,11 +43,8 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { case LEFT: left = -1; break; - case DELETE: - removeBlock( selectedBlock.clientId ); - return; default: - return; + break; } event.preventDefault(); if ( ALLOWED_MOVABLE_BLOCKS.includes( selectedBlock.name ) ) { @@ -59,9 +57,23 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { } }; + const deleteSelectedBlocks = ( event ) => { + const { target } = event; + const { classList } = target; + if ( ! selectedBlock ) { + return; + } + if ( classList.contains( 'editor-rich-text__editable' ) && ( classList.contains( 'is-selected' ) || classList.contains( 'is-typing' ) ) ) { + return; + } + event.preventDefault(); + removeBlock( selectedBlock.clientId ); + }; + return { isReordering, - onKeyPress, + onMoveBlock, + deleteSelectedBlocks, }; } ); @@ -73,7 +85,7 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { export default createHigherOrderComponent( ( BlockEdit ) => { return applyWithDispatch( ( props ) => { - const { name, onKeyPress, isReordering } = props; + const { name, onMoveBlock, isReordering, deleteSelectedBlocks } = props; const isPageBlock = 'amp/amp-story-page' === name; // Add for page block and inner blocks. if ( ! isPageBlock && ! ALLOWED_CHILD_BLOCKS.includes( name ) ) { @@ -85,10 +97,19 @@ export default createHigherOrderComponent( return ; } + const shortcuts = { + up: onMoveBlock, + right: onMoveBlock, + down: onMoveBlock, + left: onMoveBlock, + backspace: deleteSelectedBlocks, + del: deleteSelectedBlocks, + }; + return ( -
+ -
+ ); } ); }, From d23e72f8a88a0a0e5c529bb4e0920b1c819b1ec0 Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Thu, 3 Oct 2019 12:24:22 +0100 Subject: [PATCH 6/6] Error handling. --- .../higher-order/with-keyboard-navigation-handler.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js index d84d7c4cf15..99469160335 100644 --- a/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js +++ b/assets/src/stories-editor/components/higher-order/with-keyboard-navigation-handler.js @@ -24,7 +24,7 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { return; } - if ( classList.contains( 'editor-rich-text__editable' ) && ( classList.contains( 'is-selected' ) || classList.contains( 'is-typing' ) ) ) { + if ( classList.contains( 'editor-rich-text__editable' ) && classList.contains( 'is-selected' ) ) { return; } @@ -46,8 +46,9 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { default: break; } - event.preventDefault(); - if ( ALLOWED_MOVABLE_BLOCKS.includes( selectedBlock.name ) ) { + + if ( ALLOWED_MOVABLE_BLOCKS.includes( selectedBlock.name ) && ( left || top ) ) { + event.preventDefault(); const newPositionTop = selectedBlock.attributes.positionTop + top; const newPositionLeft = selectedBlock.attributes.positionLeft + left; updateBlockAttributes( selectedBlock.clientId, { @@ -63,7 +64,7 @@ const applyWithDispatch = withDispatch( ( dispatch, props, { select } ) => { if ( ! selectedBlock ) { return; } - if ( classList.contains( 'editor-rich-text__editable' ) && ( classList.contains( 'is-selected' ) || classList.contains( 'is-typing' ) ) ) { + if ( classList.contains( 'editor-rich-text__editable' ) && classList.contains( 'is-selected' ) ) { return; } event.preventDefault(); @@ -107,7 +108,7 @@ export default createHigherOrderComponent( }; return ( - + );