Skip to content

Commit

Permalink
Add contextual commands
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad committed May 11, 2023
1 parent 8346327 commit 65eb8ab
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 71 deletions.
52 changes: 30 additions & 22 deletions packages/commands/src/components/command-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,25 @@ export function CommandMenuLoaderWrapper( { hook, search, setLoader, close } ) {
}

export function CommandMenuGroup( { group, search, setLoader, close } ) {
const hasSearch = !! search;
const { commands, loaders } = useSelect(
( select ) => {
const { getCommands, getCommandLoaders } = select( commandsStore );
const {
getCommands,
getCommandLoaders,
getContextualCommands,
getContextualCommandLoaders,
} = select( commandsStore );
return {
commands: getCommands( group ),
loaders: getCommandLoaders( group ),
commands: hasSearch
? getCommands( group )
: getContextualCommands( group ),
loaders: hasSearch
? getCommandLoaders( group )
: getContextualCommandLoaders( group ),
};
},
[ group ]
[ group, hasSearch ]
);

return (
Expand Down Expand Up @@ -219,24 +229,22 @@ export function CommandMenu() {
placeholder={ __( 'Type a command or search' ) }
/>
</div>
{ search && (
<Command.List>
{ ! isLoading && (
<Command.Empty>
{ __( 'No results found.' ) }
</Command.Empty>
) }
{ groups.map( ( group ) => (
<CommandMenuGroup
key={ group }
group={ group }
search={ search }
setLoader={ setLoader }
close={ closeAndReset }
/>
) ) }
</Command.List>
) }
<Command.List>
{ ! isLoading && (
<Command.Empty>
{ __( 'No results found.' ) }
</Command.Empty>
) }
{ groups.map( ( group ) => (
<CommandMenuGroup
key={ group }
group={ group }
search={ search }
setLoader={ setLoader }
close={ closeAndReset }
/>
) ) }
</Command.List>
</Command>
</div>
</Modal>
Expand Down
32 changes: 32 additions & 0 deletions packages/commands/src/hooks/use-command-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* WordPress dependencies
*/
import { useEffect, useRef } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as commandsStore } from '../store';

/**
* Sets the active context of the command center
*
* @param {string} context Context to set.
*/
export default function useCommandContext( context ) {
const { getContext } = useSelect( commandsStore );
const initialContext = useRef( getContext() );
const { setContext } = useDispatch( commandsStore );

useEffect( () => {
setContext( context );
}, [ context, setContext ] );

// This effects ensures that on unmount, we restore the context
// that was set before the component actually mounts.
useEffect( () => {
const initialContextRef = initialContext.current;
return () => setContext( initialContextRef );
}, [ setContext ] );
}
20 changes: 14 additions & 6 deletions packages/commands/src/hooks/use-command-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,25 @@ import { store as commandsStore } from '../store';
*
* @param {import('../store/actions').WPCommandLoaderConfig} loader command loader config.
*/
export default function useCommandLoader( { name, group, hook } ) {
export default function useCommandLoader( loader ) {
const { registerCommandLoader, unregisterCommandLoader } =
useDispatch( commandsStore );
useEffect( () => {
registerCommandLoader( {
name,
group,
hook,
name: loader.name,
group: loader.group,
hook: loader.hook,
context: loader.context,
} );
return () => {
unregisterCommandLoader( name, group );
unregisterCommandLoader( loader.name, loader.group );
};
}, [ name, group, hook, registerCommandLoader, unregisterCommandLoader ] );
}, [
loader.name,
loader.group,
loader.hook,
loader.context,
registerCommandLoader,
unregisterCommandLoader,
] );
}
2 changes: 2 additions & 0 deletions packages/commands/src/hooks/use-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default function useCommand( command ) {
registerCommand( {
name: command.name,
group: command.group,
context: command.context,
label: command.label,
icon: command.icon,
callback: currentCallback.current,
Expand All @@ -37,6 +38,7 @@ export default function useCommand( command ) {
command.label,
command.group,
command.icon,
command.context,
registerCommand,
unregisterCommand,
] );
Expand Down
2 changes: 2 additions & 0 deletions packages/commands/src/private-apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 { default as useCommandContext } from './hooks/use-command-context';
import { store } from './store';

export const { lock, unlock } =
Expand All @@ -20,5 +21,6 @@ export const privateApis = {};
lock( privateApis, {
useCommand,
useCommandLoader,
useCommandContext,
store,
} );
38 changes: 25 additions & 13 deletions packages/commands/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* @property {string} name Command name.
* @property {string} label Command label.
* @property {string=} group Command group.
* @property {string=} context Command context.
* @property {JSX.Element} icon Command icon.
* @property {Function} callback Command callback.
*/
Expand All @@ -21,9 +22,10 @@
*
* @typedef {Object} WPCommandLoaderConfig
*
* @property {string} name Command loader name.
* @property {string=} group Command loader group.
* @property {WPCommandLoaderHook} hook Command loader hook.
* @property {string} name Command loader name.
* @property {string=} group Command loader group.
* @property {string=} context Command loader context.
* @property {WPCommandLoaderHook} hook Command loader hook.
*/

/**
Expand All @@ -33,14 +35,11 @@
*
* @return {Object} action.
*/
export function registerCommand( { name, label, icon, callback, group = '' } ) {
export function registerCommand( config ) {
return {
type: 'REGISTER_COMMAND',
name,
label,
icon,
callback,
group,
...config,
group: config.group ?? '',
};
}

Expand All @@ -67,12 +66,11 @@ export function unregisterCommand( name, group ) {
*
* @return {Object} action.
*/
export function registerCommandLoader( { name, group = '', hook } ) {
export function registerCommandLoader( config ) {
return {
type: 'REGISTER_COMMAND_LOADER',
name,
group,
hook,
...config,
group: config.group ?? '',
};
}

Expand Down Expand Up @@ -113,3 +111,17 @@ export function close() {
type: 'CLOSE',
};
}

/**
* Sets the active context.
*
* @param {string} context Context.
*
* @return {Object} action.
*/
export function setContext( context ) {
return {
type: 'SET_CONTEXT',
context,
};
}
20 changes: 20 additions & 0 deletions packages/commands/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function commands( state = {}, action ) {
name: action.name,
label: action.label,
group: action.group,
context: action.context,
callback: action.callback,
icon: action.icon,
},
Expand Down Expand Up @@ -57,6 +58,7 @@ function commandLoaders( state = {}, action ) {
...state[ action.group ],
[ action.name ]: {
name: action.name,
context: action.context,
hook: action.hook,
},
},
Expand Down Expand Up @@ -93,10 +95,28 @@ function isOpen( state = false, action ) {
return state;
}

/**
* Reducer returning the command center's active context.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {boolean} Updated state.
*/
function context( state = 'root', action ) {
switch ( action.type ) {
case 'SET_CONTEXT':
return action.context;
}

return state;
}

const reducer = combineReducers( {
commands,
commandLoaders,
isOpen,
context,
} );

export default reducer;
22 changes: 22 additions & 0 deletions packages/commands/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,25 @@ export const getCommandLoaders = createSelector(
export function isOpen( state ) {
return state.isOpen;
}

export function getContext( state ) {
return state.context;
}

export const getContextualCommands = createSelector(
( state, group ) => {
return getCommands( state, group ).filter(
( command ) => command.context === state.context
);
},
( state, group ) => [ state.commands[ group ], state.context ]
);

export const getContextualCommandLoaders = createSelector(
( state, group ) => {
return getCommandLoaders( state, group ).filter(
( loader ) => loader.context === state.context
);
},
( state, group ) => [ state.commandLoaders[ group ], state.context ]
);
Loading

0 comments on commit 65eb8ab

Please sign in to comment.