# Canvas Toolbar

Two toolbars for node-based canvases. `CanvasToolbar` is the tool switcher: a rounded pill of icon buttons where a lighter pill slides to the active tool. Press `1`–`4` to switch tools, or hover a button to see its name and shortcut. `CanvasSelectionToolbar` floats above the selected node: the blue pill picks how the node is shown (Chart, Table or Number), the arrow opens the node in full view, and the dots open a menu of actions. Both ship from the same registry item.

The demo wires both toolbars to a [Node Canvas](/docs/components/node-canvas). Pick the source, note or frame tool and click the canvas to place a node. Select a node to drag it, resize it from a corner, switch a card between Chart, Table and Number, open it in a larger view, or duplicate, lock and delete it (Delete or Backspace works too). The toolbars themselves only emit what was picked; the canvas does the rest.

<demo-canvas-toolbar>



</demo-canvas-toolbar>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/canvas-toolbar.json"
```

## Usage

```vue
<script setup lang="ts">
  import { ref } from 'vue';
  import CanvasToolbar from '~/components/ui/canvas-toolbar/CanvasToolbar.vue';
  import CanvasSelectionToolbar from '~/components/ui/canvas-toolbar/CanvasSelectionToolbar.vue';

  const tool = ref('select');
  const view = ref('chart');

  function onAction(id: string) {
    // 'duplicate' | 'lock' | 'delete'
  }
</script>

<template>
  <CanvasToolbar v-model="tool" />

  <CanvasSelectionToolbar
    v-model:view="view"
    @expand="openFullView"
    @action="onAction"
  />
</template>
```

The defaults match the demo: tools `source`, `select`, `note` and `frame`; views `chart`, `table` and `number`; actions `duplicate`, `lock` and `delete`. They are exported as `DEFAULT_CANVAS_TOOLS`, `DEFAULT_CANVAS_VIEWS` and `DEFAULT_CANVAS_ACTIONS`, so you can extend them.

## CanvasToolbar props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        v-model
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      <code>
        id
      </code>
      
       of the active tool.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tools
      </code>
    </td>
    
    <td>
      <code>
        CanvasTool[]
      </code>
    </td>
    
    <td>
      <code>
        DEFAULT_CANVAS_TOOLS
      </code>
    </td>
    
    <td>
      Tools to show. Each has <code>
        id
      </code>
      
      , <code>
        label
      </code>
      
      , <code>
        icon
      </code>
      
       and an optional <code>
        shortcut
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shortcuts
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Listens for each tool's key. A tool's key defaults to its position.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Canvas tools'
      </code>
    </td>
    
    <td>
      Accessible name of the radio group.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the root element.
    </td>
  </tr>
</tbody>
</table>

## CanvasSelectionToolbar props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        v-model:view
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      <code>
        id
      </code>
      
       of the current view. Falls back to the first.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        views
      </code>
    </td>
    
    <td>
      <code>
        CanvasViewOption[]
      </code>
    </td>
    
    <td>
      <code>
        DEFAULT_CANVAS_VIEWS
      </code>
    </td>
    
    <td>
      Options in the view menu. Pass <code>
        []
      </code>
      
       to hide the view pill.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        actions
      </code>
    </td>
    
    <td>
      <code>
        CanvasMenuAction[]
      </code>
    </td>
    
    <td>
      <code>
        DEFAULT_CANVAS_ACTIONS
      </code>
    </td>
    
    <td>
      Items in the "more" menu. Set <code>
        destructive
      </code>
      
       for red.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        expand-label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Open in full view'
      </code>
    </td>
    
    <td>
      Accessible name of the arrow button.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        more-label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'More actions'
      </code>
    </td>
    
    <td>
      Accessible name of the dots button.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Selection'
      </code>
    </td>
    
    <td>
      Accessible name of the toolbar.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the root element.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        expand
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      The arrow button was pressed.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        action
      </code>
    </td>
    
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      An item in the "more" menu was picked.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        update:view
      </code>
    </td>
    
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      A view was picked in the view menu.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The tool switcher is a `radiogroup`. Only the active tool is in the tab order; the arrow keys, Home and End move and select.
- Shortcut keys are ignored while a text field has focus or a modifier key is held. Each tool sets `aria-keyshortcuts`.
- The tooltip shows on hover and on focus and is linked with `aria-describedby`.
- The selection toolbar uses `role="toolbar"`. Left and Right move between its buttons.
- Menu triggers set `aria-haspopup` and `aria-expanded`. Down opens a menu. Up, Down, Home and End move inside it. Escape closes it and returns focus to the trigger. A click outside also closes it.
- The view menu uses `menuitemradio` with `aria-checked` on the current view.
- The sliding pill does not animate when the user prefers reduced motion.
