[]previous and next page

Actions and shortcuts

One declaration per command feeds the keyboard, the menus, the command palette and the shortcuts sheet. Add your own, rebind keys, and find conflicts.

An action is a command with a name, an optional shortcut, and a function to run. Every command in CanvasFlow is one: undo, duplicate, align left, zoom to fit, switch to the arrow tool.

The point of declaring commands this way is that you write each one once. The same declaration drives:

  • the keyboard shortcut,
  • the item in the main and context menus,
  • the entry in the ⌘K command palette,
  • the tooltip that teaches the shortcut,
  • the shortcuts help sheet,
  • and a conflict check that tells you when two actions claim the same keys.

Run an action#

ts
editor.actions.run('align-left')
editor.actions.isEnabled('group') // false when fewer than two shapes are selected
editor.actions.shortcutText('duplicate') // '⌘D' on a Mac, 'Ctrl+D' elsewhere

Add your own#

actions.tsts
const off = editor.actions.register({
  id: 'insert-timestamp',
  label: 'Insert timestamp',
  kbd: 'mod+shift+t',
  group: 'edit',
  keywords: ['date', 'time', 'now'],
  run(editor) {
    const center = editor.screenToPage({ x: editor.state.viewport.w / 2, y: editor.state.viewport.h / 2 })
    editor.createShape({ type: 'text', x: center.x, y: center.y, props: { text: new Date().toLocaleString() } })
  },
})

It's immediately in the palette (search "time"), and ⇧⌘T works. off() removes it.

The fields#

Field What it does
id Stable id, used by run, rebind and menus
label What people read in menus and the palette
kbd Shortcuts, comma separated: 'mod+z', 'v,1', 'mod+shift+z,mod+y'
group Where it appears in the help sheet (edit, arrange, align, view…)
icon Icon name for UI kits
keywords Extra words the palette matches
enabled(editor) Return false to disable it (and let its keys pass through to tools)
checked(editor) For toggles: shows a check mark in menus
readonlyOk Allow it in view mode
hidden Keep it out of the palette
run(editor, source) Do the work. source says where it came from: kbd, menu, context-menu, toolbar, palette or api

Shortcut syntax#

  • mod is ⌘ on Apple devices and Ctrl everywhere else. Use it instead of hard-coding either.
  • Combine with +: mod+shift+g, alt+h.
  • Separate alternatives with ,: delete,backspace.
  • Keys match by their position on the keyboard when it makes sense, so shortcuts keep working on non-US layouts.

Rebind keys#

ts
editor.actions.rebind('tool.draw', 'b') // B for brush
editor.actions.rebind('toggle-grid', undefined) // remove a shortcut

Check for conflicts#

ts
for (const [keys, a, b] of editor.actions.conflicts()) {
  console.warn(`${keys} is claimed by both ${a} and ${b}`)
}

CanvasFlow's own test suite runs this check on the defaults, so a release never ships two commands on one key.

Ship actions in a plugin#

Plugins can bring actions along with shapes and tools:

ts
editor.use({
  name: 'timestamps',
  actions: [
    { id: 'insert-timestamp', label: 'Insert timestamp', kbd: 'mod+shift+t', run: (editor) => editor.selectAll() },
  ],
})

Default actions#

The full list, with every shortcut, is on the Keyboard shortcuts page.