From 95e78eea334cca33b0ba2bece5e3ee7f8e57ffe2 Mon Sep 17 00:00:00 2001 From: Sukhendu Sekhar Guria Date: Thu, 27 Feb 2025 19:08:36 +0530 Subject: [PATCH] Add option to toggle keyboard shortcuts on/off --- .../data/data-core-keyboard-shortcuts.md | 45 ++++++++++++++++ .../keyboard-shortcut-help-modal/index.js | 25 ++++++++- .../src/hooks/use-shortcut.js | 11 +++- .../keyboard-shortcuts/src/store/actions.js | 14 +++++ .../keyboard-shortcuts/src/store/reducer.js | 29 +++++++++- .../keyboard-shortcuts/src/store/selectors.js | 53 ++++++++++++++++--- 6 files changed, 164 insertions(+), 13 deletions(-) diff --git a/docs/reference-guides/data/data-core-keyboard-shortcuts.md b/docs/reference-guides/data/data-core-keyboard-shortcuts.md index 426fb316021a42..924798d7aa8dfd 100644 --- a/docs/reference-guides/data/data-core-keyboard-shortcuts.md +++ b/docs/reference-guides/data/data-core-keyboard-shortcuts.md @@ -6,6 +6,39 @@ Namespace: `core/keyboard-shortcuts`. +### areShortcutsEnabled + +Returns whether keyboard shortcuts are enabled. + +_Usage_ + +```js +import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; +import { useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; + +const ExampleComponent = () => { + const shortcutsEnabled = useSelect( + ( select ) => select( keyboardShortcutsStore ).areShortcutsEnabled(), + [] + ); + + return shortcutsEnabled ? ( +
{ __( 'Shortcuts enabled.' ) }
+ ) : ( +
{ __( 'Shortcuts disabled.' ) }
+ ); +}; +``` + +_Parameters_ + +- _state_ `Object`: Global state. + +_Returns_ + +- `boolean`: Whether shortcuts are enabled. + ### getAllShortcutKeyCombinations Returns the shortcuts that include aliases for a given shortcut name. @@ -394,6 +427,18 @@ _Returns_ - `Object`: action. +### toggleShortcutsEnabled + +Returns an action object used to toggle keyboard shortcuts on or off. + +_Parameters_ + +- _areShortcutsEnabled_ `boolean`: True to enable shortcuts, false to disable. + +_Returns_ + +- `Object`: action. + ### unregisterShortcut Returns an action object used to unregister a keyboard shortcut. diff --git a/packages/editor/src/components/keyboard-shortcut-help-modal/index.js b/packages/editor/src/components/keyboard-shortcut-help-modal/index.js index 81a821c7783838..d30487ff0e0d9f 100644 --- a/packages/editor/src/components/keyboard-shortcut-help-modal/index.js +++ b/packages/editor/src/components/keyboard-shortcut-help-modal/index.js @@ -6,7 +6,7 @@ import clsx from 'clsx'; /** * WordPress dependencies */ -import { Modal } from '@wordpress/components'; +import { Modal, ToggleControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useShortcut, @@ -104,6 +104,13 @@ function KeyboardShortcutHelpModal() { openModal( KEYBOARD_SHORTCUT_HELP_MODAL_NAME ); } }; + + const { toggleShortcutsEnabled } = useDispatch( keyboardShortcutsStore ); + const shortcutsEnabled = useSelect( + ( select ) => select( keyboardShortcutsStore ).areShortcutsEnabled(), + [] + ); + useShortcut( 'core/editor/keyboard-shortcuts', toggleModal ); if ( ! isModalActive ) { @@ -117,6 +124,22 @@ function KeyboardShortcutHelpModal() { closeButtonLabel={ __( 'Close' ) } onRequestClose={ toggleModal } > +
+ + toggleShortcutsEnabled( ! shortcutsEnabled ) + } + help={ + shortcutsEnabled + ? __( 'Keyboard shortcuts are enabled.' ) + : __( 'Keyboard shortcuts are disabled.' ) + } + /> +
+ select( keyboardShortcutsStore ).areShortcutsEnabled(), + [] + ); + useEffect( () => { callbackRef.current = callback; }, [ callback ] ); useEffect( () => { - if ( isDisabled ) { + if ( isDisabled || ! areShortcutsEnabled ) { return; } @@ -45,5 +52,5 @@ export default function useShortcut( return () => { shortcuts.delete( _callback ); }; - }, [ name, isDisabled, shortcuts ] ); + }, [ name, isDisabled, shortcuts, areShortcutsEnabled ] ); } diff --git a/packages/keyboard-shortcuts/src/store/actions.js b/packages/keyboard-shortcuts/src/store/actions.js index 4f40ba05ff85a9..44cf6bd64327b6 100644 --- a/packages/keyboard-shortcuts/src/store/actions.js +++ b/packages/keyboard-shortcuts/src/store/actions.js @@ -126,3 +126,17 @@ export function unregisterShortcut( name ) { name, }; } + +/** + * Returns an action object used to toggle keyboard shortcuts on or off. + * + * @param {boolean} areShortcutsEnabled True to enable shortcuts, false to disable. + * + * @return {Object} action. + */ +export function toggleShortcutsEnabled( areShortcutsEnabled ) { + return { + type: 'TOGGLE_SHORTCUTS_ENABLED', + areShortcutsEnabled, + }; +} diff --git a/packages/keyboard-shortcuts/src/store/reducer.js b/packages/keyboard-shortcuts/src/store/reducer.js index ed0e14bfa625ba..672971b30cba09 100644 --- a/packages/keyboard-shortcuts/src/store/reducer.js +++ b/packages/keyboard-shortcuts/src/store/reducer.js @@ -1,3 +1,8 @@ +/** + * WordPress dependencies + */ +import { combineReducers } from '@wordpress/data'; + /** * Reducer returning the registered shortcuts * @@ -6,7 +11,7 @@ * * @return {Object} Updated state. */ -function reducer( state = {}, action ) { +function registeredShortcuts( state = {}, action ) { switch ( action.type ) { case 'REGISTER_SHORTCUT': return { @@ -26,4 +31,24 @@ function reducer( state = {}, action ) { return state; } -export default reducer; +/** + * Reducer returning whether shortcuts are enabled. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {boolean} Updated state. + */ +function shortcutsEnabled( state = true, action ) { + switch ( action.type ) { + case 'TOGGLE_SHORTCUTS_ENABLED': + return action.areShortcutsEnabled; + } + + return state; +} + +export default combineReducers( { + registeredShortcuts, + shortcutsEnabled, +} ); diff --git a/packages/keyboard-shortcuts/src/store/selectors.js b/packages/keyboard-shortcuts/src/store/selectors.js index 1e4872b46a4a77..e96bf0c1e99ae0 100644 --- a/packages/keyboard-shortcuts/src/store/selectors.js +++ b/packages/keyboard-shortcuts/src/store/selectors.js @@ -96,7 +96,9 @@ function getKeyCombinationRepresentation( shortcut, representation ) { * @return {WPShortcutKeyCombination?} Key combination. */ export function getShortcutKeyCombination( state, name ) { - return state[ name ] ? state[ name ].keyCombination : null; + return state.registeredShortcuts[ name ] + ? state.registeredShortcuts[ name ].keyCombination + : null; } /** @@ -175,7 +177,9 @@ export function getShortcutRepresentation( * @return {?string} Shortcut description. */ export function getShortcutDescription( state, name ) { - return state[ name ] ? state[ name ].description : null; + return state.registeredShortcuts[ name ] + ? state.registeredShortcuts[ name ].description + : null; } /** @@ -225,8 +229,9 @@ export function getShortcutDescription( state, name ) { * @return {WPShortcutKeyCombination[]} Key combinations. */ export function getShortcutAliases( state, name ) { - return state[ name ] && state[ name ].aliases - ? state[ name ].aliases + return state.registeredShortcuts[ name ] && + state.registeredShortcuts[ name ].aliases + ? state.registeredShortcuts[ name ].aliases : EMPTY_ARRAY; } @@ -286,7 +291,7 @@ export const getAllShortcutKeyCombinations = createSelector( ...getShortcutAliases( state, name ), ].filter( Boolean ); }, - ( state, name ) => [ state[ name ] ] + ( state, name ) => [ state.registeredShortcuts[ name ] ] ); /** @@ -345,7 +350,7 @@ export const getAllShortcutRawKeyCombinations = createSelector( getKeyCombinationRepresentation( combination, 'raw' ) ); }, - ( state, name ) => [ state[ name ] ] + ( state, name ) => [ state.registeredShortcuts[ name ] ] ); /** @@ -383,9 +388,41 @@ export const getAllShortcutRawKeyCombinations = createSelector( */ export const getCategoryShortcuts = createSelector( ( state, categoryName ) => { - return Object.entries( state ) + return Object.entries( state.registeredShortcuts ) .filter( ( [ , shortcut ] ) => shortcut.category === categoryName ) .map( ( [ name ] ) => name ); }, - ( state ) => [ state ] + ( state ) => [ state.registeredShortcuts ] ); + +/** + * Returns whether keyboard shortcuts are enabled. + * + * @param {Object} state Global state. + * + * @example + * + *```js + * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; + * import { useSelect } from '@wordpress/data'; + * import { __ } from '@wordpress/i18n'; + * + * const ExampleComponent = () => { + * const shortcutsEnabled = useSelect( + * ( select ) => + * select( keyboardShortcutsStore ).areShortcutsEnabled(), + * [] + * ); + * + * return shortcutsEnabled ? ( + *
{ __( 'Shortcuts enabled.' ) }
+ * ) : ( + *
{ __( 'Shortcuts disabled.' ) }
+ * ); + * }; + *``` + * @return {boolean} Whether shortcuts are enabled. + */ +export function areShortcutsEnabled( state ) { + return state.shortcutsEnabled; +}