A command is a reusable action. Every command is identified by a name, and has up to three properties:
- A value that identifies the command action, typically a callback;
- Zero or more keyboard shortcuts that can be used to activate the command;
- An optional
disabled
value that indicates whether the command is currently unavailable (commands are enabled by default).
The useCommandGroup()
hook defines a group of reusable commands, while the <CommandProvider>
component makes them available to child components.
Commands can be attached to any component using the hook useCommand()
. The following components have built-in support for commands (via the command
prop, which takes a command name):
If you only wish to associate functionality with keyboard shortcuts, and not expose named commands to child components, consider using a ShortcutMap
instead.
Define some commands with useCommandGroup()
and expose them with <CommandProvider>
:
import {CommandGroup, CommandProvider, Shortcuts} from '@condict/ui';
// A pair of commands that update some component state, with shortcuts:
const commands = useCommandGroup({
commands: {
undo: {
exec: () => handleUndo(),
disabled: !canUndo,
shortcut: Shortcuts.undo,
},
redo: {
exec: () => handleRedo(),
disabled: !canRedo,
shortcut: Shortcuts.redo,
},
},
exec: cmd => cmd(),
});
<div onKeyDown={e => { CommandGroup.handleKey(commands, e); }}>
<CommandProvider commands={commands}>
{/* Command consumers go here */}
</CommandProvider>
</div>
// Passing values into the command's exec function:
const commands = useCommandGroup({
commands: {
toUpper: {
exec: value => value.toUpperCase(),
},
toLower: {
exec: value => value.toLowerCase(),
},
},
exec: cmd => setValue(cmd(value)),
});
<CommandProvider commands={commands}>
{/* Command consumers go here */}
</CommandProvider>
Bind components to some commands using the hook useCommand()
:
import {useCommand} from '@condict/ui';
// Using useCommand to create a new component with command support:
const MyCommandButton = props => {
const command = useCommand(props.command);
return (
<MyButton disabled={command.disabled} onClick={command.exec}>
...
</MyButton>
);
};
<MyCommandButton command='toUpper'>
...
</MyCommandButton>
useCommandGroup<T>(options: CommandGroupOptions<T>): CommandGroup
This hook creates a command group with the specified commands, executor and optional disabled status. On its own, a CommandGroup
does not do anything. It must be exposed to consumers with a <CommandProvider>
. Shortcut keys must be listened to manually; the helper function CommandGroup.handleKey()
takes care of this.
The options object passed to the hook contains three properties:
Name | Type | Description |
---|---|---|
commands |
CommandSpecMap<T> |
An object containing the commands in the group. The key is the name of the command, and the value is the command itself. See command structure below for details. |
exec |
function | A function that executes the commands. It receives the command's action . The return value is ignored. |
disabled |
boolean | If true, all commands in the group are disabled. Invidiual commands can be disabled as well. This property is optional; if omitted, it defaults to false . |
The commands
prop takes an object that defines the available commands. The key is the name of the command, and each value is an object. The following properties are recognised on the command object:
Name | Type | Description |
---|---|---|
action |
any | A value that contains the command's action, typically a function. The command group's exec prop is responsible for handling this value. See useCommandGroup() above for details. |
shortcut |
Shortcut , null or undefined |
Keyboard shortcuts attached to the command. If set to null or undefined, the command has no keyboard shortcut. |
disabled |
boolean | If true, the command is disabled. A disabled command cannot be triggered by its keyboard shortcut, and components that use it are automatically disabled. Commands are enabled by default. |
Any other properties on the command object are ignored.
See more under examples.
type CommandGroup
const CommandGroup
The CommandGroup
type contains a mapping from command name to command object, as well as a shortcut lookup map. The exported constant contains a few helper functions for working with command groups:
CommandGroup.get(group: CommandGroup, name: string): Command | null
Gets the command with the specified name. If the group has no command of that name, returns null.
CommandGroup.exec(group: CommandGroup, name: string): boolean
Executes the command with the specified name. If the command is disabled, this function is a no-op. Returns true if the command was found and executed; false if the command could not be found or the command was disabled.
CommandGroup.handleKey(group: CommandGroup, e: KeyboardEvent): boolean
Executes the command whose shortcut matches a key event.
If the keyboard event has had its default prevented (e.defaultPrevented
is true), this function is a no-op. If a matching command is found and executed, this function calls e.preventDefault()
.
Returns true if the keyboard event was handled (the event was not already handled, a command was found, and the command was not disabled); false if the event was already handled, no command was found, or the command was disabled.
The <CommandProvider>
component exposes commands to child components. Commands can only be accessed by useCommand()
when mounted inside a <CommandProvider>
.
Command groups can be arbitrarily nested. Commands are inherited from groups higher up in the tree. Nested commands can override inherited commands if given the same name. The useCommand()
hook can reference commands from any parent group. See more under examples.
Name | Type | Default | Description |
---|---|---|---|
commands |
CommandGroup |
none; required | The command group to expose. |
children |
node | undefined |
The command provider's children. |
Other props are ignored.
useCommand(name: string | undefined | null): Command | null
useCommand()
is a hook that translates a command name to a command object.
Given a command name, it attempts to resolve the name to a command object, which it returns. If the command cannot be found, or if the name is null, the hook returns null. The command must be exposed to the component by a <CommandProvider>
.
The returned command object has the following properties:
Name | Type | Description |
---|---|---|
exec |
function | Executes the command. This function takes no arguments and returns no value. |
shortcut |
Shortcut or null |
The keyboard shortcut(s) bound to the command. This should mainly be used for formatting a string description of the shortcut. |
disabled |
boolean | If true, the command is disabled. The component that uses the command should be enabled or disabled according to this value. |
Name | Type | Default | Description |
---|---|---|---|
name |
string | none; required | The name of the command to bind to. |
children |
function | none; required | A render function that receives the command, or null if the command could not be found. |
The command object passed to children
has the same properties as the value returned by useCommand()
.