diff --git a/packages/commands/src/components/command-menu.js b/packages/commands/src/components/command-menu.js index f65b2143124a50..d7bafca0a3931f 100644 --- a/packages/commands/src/components/command-menu.js +++ b/packages/commands/src/components/command-menu.js @@ -139,13 +139,14 @@ export function CommandMenuGroup( { group, search, setLoader, close } ) { export function CommandMenu() { const { registerShortcut } = useDispatch( keyboardShortcutsStore ); const [ search, setSearch ] = useState( '' ); - const [ open, setOpen ] = useState( false ); - const { groups } = useSelect( ( select ) => { - const { getGroups } = select( commandsStore ); + const { groups, isOpen } = useSelect( ( select ) => { + const { getGroups, isOpen: _isOpen } = select( commandsStore ); return { groups: getGroups(), + isOpen: _isOpen(), }; }, [] ); + const { open, close } = useDispatch( commandsStore ); const [ loaders, setLoaders ] = useState( {} ); const commandMenuInput = useRef(); @@ -165,7 +166,11 @@ export function CommandMenu() { 'core/commands', ( event ) => { event.preventDefault(); - setOpen( ( prevOpen ) => ! prevOpen ); + if ( isOpen ) { + close(); + } else { + open(); + } }, { bindGlobal: true, @@ -180,19 +185,19 @@ export function CommandMenu() { } ) ), [] ); - const close = () => { + const closeAndReset = () => { setSearch( '' ); - setOpen( false ); + close(); }; useEffect( () => { // Focus the command menu input when mounting the modal. - if ( open ) { + if ( isOpen ) { commandMenuInput.current.focus(); } - }, [ open ] ); + }, [ isOpen ] ); - if ( ! open ) { + if ( ! isOpen ) { return false; } const isLoading = Object.values( loaders ).some( Boolean ); @@ -201,7 +206,7 @@ export function CommandMenu() {
@@ -227,7 +232,7 @@ export function CommandMenu() { group={ group } search={ search } setLoader={ setLoader } - close={ close } + close={ closeAndReset } /> ) ) } diff --git a/packages/commands/src/private-apis.js b/packages/commands/src/private-apis.js index ef81227bdb7206..a116c089fb8414 100644 --- a/packages/commands/src/private-apis.js +++ b/packages/commands/src/private-apis.js @@ -8,6 +8,7 @@ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/pri */ import { default as useCommand } from './hooks/use-command'; import { default as useCommandLoader } from './hooks/use-command-loader'; +import { store } from './store'; export const { lock, unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules( @@ -19,4 +20,5 @@ export const privateApis = {}; lock( privateApis, { useCommand, useCommandLoader, + store, } ); diff --git a/packages/commands/src/store/actions.js b/packages/commands/src/store/actions.js index 4ff9ca54e2d106..66d3c62af57065 100644 --- a/packages/commands/src/store/actions.js +++ b/packages/commands/src/store/actions.js @@ -91,3 +91,25 @@ export function unregisterCommandLoader( name, group ) { group, }; } + +/** + * Opens the command center. + * + * @return {Object} action. + */ +export function open() { + return { + type: 'OPEN', + }; +} + +/** + * Closes the command center. + * + * @return {Object} action. + */ +export function close() { + return { + type: 'CLOSE', + }; +} diff --git a/packages/commands/src/store/reducer.js b/packages/commands/src/store/reducer.js index a94fe8041113d0..df2e4bfdc7a791 100644 --- a/packages/commands/src/store/reducer.js +++ b/packages/commands/src/store/reducer.js @@ -74,9 +74,29 @@ function commandLoaders( state = {}, action ) { return state; } +/** + * Reducer returning the command center open state. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {boolean} Updated state. + */ +function isOpen( state = false, action ) { + switch ( action.type ) { + case 'OPEN': + return true; + case 'CLOSE': + return false; + } + + return state; +} + const reducer = combineReducers( { commands, commandLoaders, + isOpen, } ); export default reducer; diff --git a/packages/commands/src/store/selectors.js b/packages/commands/src/store/selectors.js index b8ad97fb0d4963..4b2d9cc8147813 100644 --- a/packages/commands/src/store/selectors.js +++ b/packages/commands/src/store/selectors.js @@ -18,6 +18,7 @@ export const getGroups = createSelector( ), ( state ) => [ state.commands, state.commandLoaders ] ); + export const getCommands = createSelector( ( state, group ) => Object.values( state.commands[ group ] ?? {} ), ( state, group ) => [ state.commands[ group ] ] @@ -27,3 +28,7 @@ export const getCommandLoaders = createSelector( ( state, group ) => Object.values( state.commandLoaders[ group ] ?? {} ), ( state, group ) => [ state.commandLoaders[ group ] ] ); + +export function isOpen( state ) { + return state.isOpen; +}