Skip to content

Commit

Permalink
Add contextual commands (#50543)
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad authored May 16, 2023
1 parent 25dbbbb commit b9b7c1b
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 143 deletions.
69 changes: 36 additions & 33 deletions packages/commands/src/components/command-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ function CommandMenuLoader( { name, search, hook, setLoader, close } ) {
setLoader( name, isLoading );
}, [ setLoader, name, isLoading ] );

if ( ! commands.length ) {
return null;
}

return (
<>
<Command.List>
{ isLoading && (
<Command.Loading>{ __( 'Searching…' ) }</Command.Loading>
) }

{ commands.map( ( command ) => (
<Command.Item
key={ command.name }
Expand Down Expand Up @@ -89,18 +89,22 @@ export function CommandMenuLoaderWrapper( { hook, search, setLoader, close } ) {
);
}

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

if ( ! commands.length && ! loaders.length ) {
return null;
}

return (
<Command.Group>
{ commands.map( ( command ) => (
Expand Down Expand Up @@ -139,13 +143,10 @@ export function CommandMenuGroup( { group, search, setLoader, close } ) {
export function CommandMenu() {
const { registerShortcut } = useDispatch( keyboardShortcutsStore );
const [ search, setSearch ] = useState( '' );
const { groups, isOpen } = useSelect( ( select ) => {
const { getGroups, isOpen: _isOpen } = select( commandsStore );
return {
groups: getGroups(),
isOpen: _isOpen(),
};
}, [] );
const isOpen = useSelect(
( select ) => select( commandsStore ).isOpen(),
[]
);
const { open, close } = useDispatch( commandsStore );
const [ loaders, setLoaders ] = useState( {} );
const commandMenuInput = useRef();
Expand Down Expand Up @@ -219,24 +220,26 @@ 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>
{ search && ! isLoading && (
<Command.Empty>
{ __( 'No results found.' ) }
</Command.Empty>
) }
<CommandMenuGroup
search={ search }
setLoader={ setLoader }
close={ closeAndReset }
isContextual
/>
{ search && (
<CommandMenuGroup
search={ search }
setLoader={ setLoader }
close={ closeAndReset }
/>
) }
</Command.List>
</Command>
</div>
</Modal>
Expand Down
9 changes: 8 additions & 1 deletion packages/commands/src/components/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@
[cmdk-root] > [cmdk-list] {
max-height: 400px;
overflow: auto;
padding: $grid-unit;

& > [cmdk-list-sizer] :has([cmdk-group-items]:not(:empty)) {
padding: $grid-unit;
}
}

[cmdk-empty] {
Expand All @@ -112,6 +115,10 @@
[cmdk-list-sizer] {
position: relative;
}

[cmdk-group]:has([cmdk-group-items]:not(:empty)) + [cmdk-group]:has([cmdk-group-items]:not(:empty)) {
border-top: 1px solid $gray-200;
}
}

.commands-command-menu__item mark {
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 ] );
}
18 changes: 12 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,23 @@ 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,
hook: loader.hook,
context: loader.context,
} );
return () => {
unregisterCommandLoader( name, group );
unregisterCommandLoader( loader.name );
};
}, [ name, group, hook, registerCommandLoader, unregisterCommandLoader ] );
}, [
loader.name,
loader.hook,
loader.context,
registerCommandLoader,
unregisterCommandLoader,
] );
}
6 changes: 3 additions & 3 deletions packages/commands/src/hooks/use-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ export default function useCommand( command ) {
useEffect( () => {
registerCommand( {
name: command.name,
group: command.group,
context: command.context,
label: command.label,
icon: command.icon,
callback: currentCallback.current,
} );
return () => {
unregisterCommand( command.name, command.group );
unregisterCommand( command.name );
};
}, [
command.name,
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,
} );
48 changes: 26 additions & 22 deletions packages/commands/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,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 +21,9 @@
*
* @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=} context Command loader context.
* @property {WPCommandLoaderHook} hook Command loader hook.
*/

/**
Expand All @@ -33,30 +33,24 @@
*
* @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,
};
}

/**
* Returns an action object used to unregister a command.
*
* @param {string} name Command name.
* @param {string} group Command group.
* @param {string} name Command name.
*
* @return {Object} action.
*/
export function unregisterCommand( name, group ) {
export function unregisterCommand( name ) {
return {
type: 'UNREGISTER_COMMAND',
name,
group,
};
}

Expand All @@ -67,28 +61,24 @@ 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,
};
}

/**
* Unregister command loader hook.
*
* @param {string} name Command loader name.
* @param {string} group Command loader group.
* @param {string} name Command loader name.
*
* @return {Object} action.
*/
export function unregisterCommandLoader( name, group ) {
export function unregisterCommandLoader( name ) {
return {
type: 'UNREGISTER_COMMAND_LOADER',
name,
group,
};
}

Expand All @@ -113,3 +103,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,
};
}
Loading

0 comments on commit b9b7c1b

Please sign in to comment.