Actions
The current implementation of the action system is experimental and is likely to undergo significant revisions to meet the performance demands of real-world applications with thousands of actions.
An action represents an available functionality, without specifying how it's invoked. Shortcuts can separately be
assigned to actions via a keymap
, allowing for a customizable and personalized user experience. The action system,
at its core, is only about defining actions for each part of the UI and associating these actions with
shortcuts, without any direct dependencies on other aspects of the design system. However, there are
UI components available to facilitate creation of toolbars and menus based on actions.
The core functionality of the action system may be extracted into a standalone package in the future, making it a reusable component for applications built using any design system.
The action system consists of the following primary components:
ActionsProvider
component, which allows for defining actions for a UI area.KeymapProvider
component, which allows for assigning shortcut(s) to actions.- UI components that helps with creating menus, toolbars, etc. based on action system abstractions.
Below is a basic example of how these components are used. Subsequent sections will provide detailed explanations of the components and interfaces involved.
Defining actions
ActionsProvider
is used as a wrapper component that defines available actions for the wrapped UI.
Multiple, potentially nested ActionsProvider
may be rendered in an application. ActionProvider
itself doesn't render
any wrapper element. Shortcut event handler props are passed to children
which is expected to be a render function:
<ActionsProvider actions={actions}>
{({ shortcutHandlerProps }) => <div {...shortcutHandlerProps}>...</div>}
</ActionsProvider>
actions
is an array of objects implementing ActionDefinition
interface. At minimum, an action must have:
id
: A unique identifier based on which shortcuts are assigned inkeymap
.actionPerformed
: A function to be invoked when the action is triggered, e.g. via a shortcut.title
: The only mandatory presentation information for the action.
Moreover, an action has the following optional properties:
isDisabled
: Iftrue
, prevents action from being performed. Action UI components will also utilize this field to either disable or hide the corresponding UI component.icon
: A React node to be used as the associated icon for the action. It's required if the action is to be rendered as an ActionButton, and optional for menu items.description
: Plain text, additional description about the action. Not used in ActionButton, or menu items.
Action Groups
An ActionGroup is a special type of action with a list of children actions. An action group itself can be performed.
Default action group
A default implementation of action group is available, which when performed, opens a Popup, presenting the children actions in a SpeedSearchMenu. The default action group requires PopupManager, for opening the popup.
useCreateDefaultActionGroup
returns a function that creates action groups:
import { useCreateDefaultActionGroup } from "@intellij-platform/core";
const createDefaultActionGroup = useCreateDefaultActionGroup();
createDefaultActionGroup({
id: "MY_ACTION_GROUP",
title: "My Action Group",
children: [
/* action definitions */
],
});
Using actions
useActions
can be used to query the list of all provided actions. Use useAction
instead to query an specific action,
by id. The queried Action
object has a perform
method which can be invoked e.g. when a menu item or a button is
pressed. Note that Action
interface is quite similar but not identical to ActionDefinition
.
function MyActionButton() {
const action = useAction("MY_ACTION");
return action && <Button onPress={() => action.perform()}>My Action</Button>;
}
useActionGroup
is also similar to useAction
, but it asserts the queried action is a group.
Query actions based on DOM elements
useAction
or useActions
is the canonical API for accessing currently provided actions from a React component.
getAvailableActionsFor
is an alternative API that allows for querying available actions from a DOM element. This can
be useful in specific scenarios such as the implementation of the find action.
You can also check out the implementation of "find action" action in the example app.
UI components
useAction
, and useActionGroup
can be used to query actions and create a menu or toolbar out of them. For typical
use cases, however, there are convenient components that interface on Action
or action id.
Menu
Use ActionsMenu
to render a list of action objects as a menu. ActionGroup
items are rendered as a section or a
submenu, depending on menuPresentation
property of the action group object.
Note that ActionsMenu
just provides an interface based on action items, but it doesn't query any action from the
actions context, and just uses action properties to create menu items from it.
Use ActionGroupMenu
to render actions of an action group, as a menu:
ActionButton
Use ActionButton
to create an IconButton
based on a provided action. Unlike ActionsMenu
and ActionGroupMenu
,
ActionButton
interfaces on action ID, and queries the target action via useAction
. If the action doesn't exist,
it renders nothing.
Shortcuts and key mapping
A Keymap
is a mapping from action ids to a list of associated shortcuts. In an application that uses actions, the
KeymapProvider
is typically used as a top level wrapper, to provide a keymap.
import {Keymap, KeymapProvider} from '@intellij-platform/core';
const keymap: Keymap = isMac() ? macKeymap : defaultKeymap;
<KeymapProvider keymap={keymap}>...</KeyMapProvider>
Differences with the Intellij Platform
While the action system almost replicates Intellij Platform's Action System, there are some design differences worth noting:
TODO