From 36b6a1996bfbac563167cd319aa454ebb9e316b2 Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Mon, 14 Nov 2022 17:54:03 +0200 Subject: [PATCH] Converts paragraphs to headings with keyboard shortcuts (#44681) * adds shortcuts for heading transforms to the paragraph block * Implements feedback on hook location, UX and usage. - Moves the functionality from the paragraph block to the block editor package - Implements the shortcuts for paragraph and heading allowing cycling between them - Refactors the code in a less repetitive shape - Adds access+0 as a way to convert headings to paragraphs - Implements cycling through heading levels via access+[1-6] - Registers shortcuts only once - Adds a new prop to RichText allowing for onKeyDown custom handlers - Removes the keyboard-shortcuts dependency from block libary Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com> Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Co-authored-by: Dave Smith <444434+getdave@users.noreply.github.com> * Refactors so that setting up the text level shortcuts is handled by the post editor. * removes the old hook * adds the text level keyboard shortcuts to the help modal of the post editor * Removes the hook based approach and inlines every shortcut definition and handler into edit post shortcut conf file. Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com> * updated snapshot for keyboard help modal * Refactores the shortcut handler to be a bit quicker returning early for multiselection and avoiding an extra state select. Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com> Co-authored-by: Daniel Richards <677833+talldan@users.noreply.github.com> Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Co-authored-by: Dave Smith <444434+getdave@users.noreply.github.com> --- .../keyboard-shortcut-help-modal/config.js | 10 +++ .../test/__snapshots__/index.js.snap | 70 +++++++++++++++++++ .../components/keyboard-shortcuts/index.js | 67 ++++++++++++++++++ packages/keycodes/src/index.js | 2 +- 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js index 7e098a87be2cd9..fd11d14e08cde0 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js @@ -36,4 +36,14 @@ export const textFormattingShortcuts = [ keyCombination: { modifier: 'access', character: 'x' }, description: __( 'Make the selected text inline code.' ), }, + { + keyCombination: { modifier: 'access', character: '0' }, + description: __( 'Convert the current heading to a paragraph.' ), + }, + { + keyCombination: { modifier: 'access', character: '1-6' }, + description: __( + 'Convert the current paragraph or heading to a heading of level 1 to 6.' + ), + }, ]; diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap index 7cc2c124e6fbbd..7b2ba852ad5aab 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap @@ -821,6 +821,76 @@ exports[`KeyboardShortcutHelpModal should match snapshot when the modal is activ +
  • +
    + Convert the current heading to a paragraph. +
    +
    + + + Shift + + + + + Alt + + + + + 0 + + +
    +
  • +
  • +
    + Convert the current paragraph or heading to a heading of level 1 to 6. +
    +
    + + + Shift + + + + + Alt + + + + + 1-6 + + +
    +
  • diff --git a/packages/edit-post/src/components/keyboard-shortcuts/index.js b/packages/edit-post/src/components/keyboard-shortcuts/index.js index df5205de1c94a7..d3d6569e398a45 100644 --- a/packages/edit-post/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-post/src/components/keyboard-shortcuts/index.js @@ -12,6 +12,7 @@ import { store as editorStore } from '@wordpress/editor'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as noticesStore } from '@wordpress/notices'; import { store as preferencesStore } from '@wordpress/preferences'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies @@ -53,6 +54,35 @@ function KeyboardShortcuts() { closeGeneralSidebar(); }; + const { replaceBlocks } = useDispatch( blockEditorStore ); + const { getBlockName, getSelectedBlockClientId, getBlockAttributes } = + useSelect( blockEditorStore ); + + const handleTextLevelShortcut = ( event, level ) => { + event.preventDefault(); + const destinationBlockName = + level === 0 ? 'core/paragraph' : 'core/heading'; + const currentClientId = getSelectedBlockClientId(); + if ( currentClientId === null ) { + return; + } + const blockName = getBlockName( currentClientId ); + if ( blockName !== 'core/paragraph' && blockName !== 'core/heading' ) { + return; + } + const currentAttributes = getBlockAttributes( currentClientId ); + const { content: currentContent, align: currentAlign } = + currentAttributes; + replaceBlocks( + currentClientId, + createBlock( destinationBlockName, { + level, + content: currentContent, + align: currentAlign, + } ) + ); + }; + useEffect( () => { registerShortcut( { name: 'core/edit-post/toggle-mode', @@ -149,6 +179,28 @@ function KeyboardShortcuts() { character: 'h', }, } ); + + registerShortcut( { + name: `core/block-editor/transform-heading-to-paragraph`, + category: 'block-library', + description: __( 'Transform heading to paragraph.' ), + keyCombination: { + modifier: 'access', + character: `0`, + }, + } ); + + [ 1, 2, 3, 4, 5, 6 ].forEach( ( level ) => { + registerShortcut( { + name: `core/block-editor/transform-paragraph-to-heading-${ level }`, + category: 'block-library', + description: __( 'Transform paragraph to heading.' ), + keyCombination: { + modifier: 'access', + character: `${ level }`, + }, + } ); + } ); }, [] ); useShortcut( @@ -202,6 +254,21 @@ function KeyboardShortcuts() { setIsListViewOpened( ! isListViewOpened() ) ); + useShortcut( + 'core/block-editor/transform-heading-to-paragraph', + ( event ) => handleTextLevelShortcut( event, 0 ) + ); + + [ 1, 2, 3, 4, 5, 6 ].forEach( ( level ) => { + //the loop is based off on a constant therefore + //the hook will execute the same way every time + //eslint-disable-next-line react-hooks/rules-of-hooks + useShortcut( + `core/block-editor/transform-paragraph-to-heading-${ level }`, + ( event ) => handleTextLevelShortcut( event, level ) + ); + } ); + return null; } diff --git a/packages/keycodes/src/index.js b/packages/keycodes/src/index.js index 4d902f4ba4e278..5bb776127d95e7 100644 --- a/packages/keycodes/src/index.js +++ b/packages/keycodes/src/index.js @@ -237,7 +237,7 @@ export const displayShortcutList = mapValues( modifiers, ( modifier ) => { // so override the rule to allow symbols used for shortcuts. // see: https://github.com/blakeembrey/change-case#options const capitalizedCharacter = capitalCase( character, { - stripRegexp: /[^A-Z0-9`,\.\\]/gi, + stripRegexp: /[^A-Z0-9`,\.\\\-]/gi, } ); return [ ...modifierKeys, capitalizedCharacter ];