import { createSelector } from '@wordpress/data'; import { displayShortcut, shortcutAriaLabel, rawShortcut, } from '@wordpress/keycodes'; import type { ShortcutKeyCombination } from './actions'; interface ShortcutState { category: string; keyCombination: ShortcutKeyCombination; aliases?: ShortcutKeyCombination[]; description: string; } type ShortcutsState = Record< string, ShortcutState >; /** * Shared reference to an empty array for cases where it is important to avoid * returning a new array reference on every invocation. */ const EMPTY_ARRAY: ShortcutKeyCombination[] = []; /** * Shortcut formatting methods. */ const FORMATTING_METHODS = { /** * Display formatting. */ display: displayShortcut, /** * Raw shortcut formatting. */ raw: rawShortcut, /** * ARIA label formatting. */ ariaLabel: shortcutAriaLabel, }; /** * Returns a string representing the key combination. * * @param shortcut Key combination. * @param representation Type of representation * (display, raw, ariaLabel). * * @return Shortcut representation. */ function getKeyCombinationRepresentation( shortcut: ShortcutKeyCombination | null, representation: keyof typeof FORMATTING_METHODS ): string | null { if ( ! shortcut ) { return null; } return shortcut.modifier ? FORMATTING_METHODS[ representation ][ shortcut.modifier ]( shortcut.character ) : shortcut.character; } /** * Returns the main key combination for a given shortcut name. * * @param {Object} state Global state. * @param {string} name Shortcut name. * * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * import { createInterpolateElement } from '@wordpress/element'; * import { sprintf } from '@wordpress/i18n'; * const ExampleComponent = () => { * const {character, modifier} = useSelect( * ( select ) => * select( keyboardShortcutsStore ).getShortcutKeyCombination( * 'core/editor/next-region' * ), * [] * ); * * return ( *
* { createInterpolateElement( * sprintf( * 'Character: %s / Modifier: %s', * character, * modifier * ), * { * code: , * } * ) } *
* ); * }; *``` * * @return {ShortcutKeyCombination?} Key combination. */ export function getShortcutKeyCombination( state: ShortcutsState, name: string ): ShortcutKeyCombination | null { return state[ name ] ? state[ name ].keyCombination : null; } /** * Returns a string representing the main key combination for a given shortcut name. * * @param {Object} state Global state. * @param {string} name Shortcut name. * @param {keyof FORMATTING_METHODS} representation Type of representation * (display, raw, ariaLabel). * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * import { sprintf } from '@wordpress/i18n'; * * const ExampleComponent = () => { * const {display, raw, ariaLabel} = useSelect( * ( select ) =>{ * return { * display: select( keyboardShortcutsStore ).getShortcutRepresentation('core/editor/next-region' ), * raw: select( keyboardShortcutsStore ).getShortcutRepresentation('core/editor/next-region','raw' ), * ariaLabel: select( keyboardShortcutsStore ).getShortcutRepresentation('core/editor/next-region', 'ariaLabel') * } * }, * [] * ); * * return ( * * ); * }; *``` * * @return {?string} Shortcut representation. */ export function getShortcutRepresentation( state: ShortcutsState, name: string, representation: keyof typeof FORMATTING_METHODS = 'display' ): string | null { const shortcut = getShortcutKeyCombination( state, name ); return getKeyCombinationRepresentation( shortcut, representation ); } /** * Returns the shortcut description given its name. * * @param {Object} state Global state. * @param {string} name Shortcut name. * * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * import { __ } from '@wordpress/i18n'; * const ExampleComponent = () => { * const shortcutDescription = useSelect( * ( select ) => * select( keyboardShortcutsStore ).getShortcutDescription( 'core/editor/next-region' ), * [] * ); * * return shortcutDescription ? ( *
{ shortcutDescription }
* ) : ( *
{ __( 'No description.' ) }
* ); * }; *``` * @return {?string} Shortcut description. */ export function getShortcutDescription( state: ShortcutsState, name: string ): string | null { return state[ name ] ? state[ name ].description : null; } /** * Returns the aliases for a given shortcut name. * * @param {Object} state Global state. * @param {string} name Shortcut name. * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * import { createInterpolateElement } from '@wordpress/element'; * import { sprintf } from '@wordpress/i18n'; * const ExampleComponent = () => { * const shortcutAliases = useSelect( * ( select ) => * select( keyboardShortcutsStore ).getShortcutAliases( * 'core/editor/next-region' * ), * [] * ); * * return ( * shortcutAliases.length > 0 && ( * * ) * ); * }; *``` * * @return {ShortcutKeyCombination[]} Key combinations. */ export function getShortcutAliases( state: ShortcutsState, name: string ): ShortcutKeyCombination[] { return state[ name ] && state[ name ].aliases ? state[ name ].aliases : EMPTY_ARRAY; } /** * Returns the shortcuts that include aliases for a given shortcut name. * * @param {Object} state Global state. * @param {string} name Shortcut name. * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * import { createInterpolateElement } from '@wordpress/element'; * import { sprintf } from '@wordpress/i18n'; * * const ExampleComponent = () => { * const allShortcutKeyCombinations = useSelect( * ( select ) => * select( keyboardShortcutsStore ).getAllShortcutKeyCombinations( * 'core/editor/next-region' * ), * [] * ); * * return ( * allShortcutKeyCombinations.length > 0 && ( * * ) * ); * }; *``` * * @return {ShortcutKeyCombination[]} Key combinations. */ export const getAllShortcutKeyCombinations = createSelector( ( state, name ) => { return [ getShortcutKeyCombination( state, name ), ...getShortcutAliases( state, name ), ].filter( ( combination ): combination is ShortcutKeyCombination => !! combination ); }, ( state, name ) => [ state[ name ] ] ); /** * Returns the raw representation of all the keyboard combinations of a given shortcut name. * * @param {Object} state Global state. * @param {string} name Shortcut name. * * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * import { createInterpolateElement } from '@wordpress/element'; * import { sprintf } from '@wordpress/i18n'; * * const ExampleComponent = () => { * const allShortcutRawKeyCombinations = useSelect( * ( select ) => * select( keyboardShortcutsStore ).getAllShortcutRawKeyCombinations( * 'core/editor/next-region' * ), * [] * ); * * return ( * allShortcutRawKeyCombinations.length > 0 && ( *
    * { allShortcutRawKeyCombinations.map( * ( shortcutRawKeyCombination, index ) => ( *
  • * { createInterpolateElement( * sprintf( * ' %s', * shortcutRawKeyCombination * ), * { * code: , * } * ) } *
  • * ) * ) } *
* ) * ); * }; *``` * * @return {string[]} Shortcuts. */ export const getAllShortcutRawKeyCombinations = createSelector( ( state, name ) => { return getAllShortcutKeyCombinations( state, name ).map( ( combination ) => getKeyCombinationRepresentation( combination, 'raw' ) ); }, ( state, name ) => [ state[ name ] ] ); /** * Returns the shortcut names list for a given category name. * * @param {Object} state Global state. * @param {string} name Category name. * @example * *```js * import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; * import { useSelect } from '@wordpress/data'; * * const ExampleComponent = () => { * const categoryShortcuts = useSelect( * ( select ) => * select( keyboardShortcutsStore ).getCategoryShortcuts( * 'block' * ), * [] * ); * * return ( * categoryShortcuts.length > 0 && ( *
    * { categoryShortcuts.map( ( categoryShortcut ) => ( *
  • { categoryShortcut }
  • * ) ) } *
* ) * ); * }; *``` * @return {string[]} Shortcut names. */ export const getCategoryShortcuts = createSelector( ( state: ShortcutsState, categoryName: string ): string[] => { return Object.entries< ShortcutState >( state ) .filter( ( [ , shortcut ] ) => shortcut.category === categoryName ) .map( ( [ name ] ) => name ); }, ( state: ShortcutsState ) => [ state ] );