# `Hakushi.Components`
[🔗](https://github.com/hattoriai/hakushi/blob/v0.1.0/lib/hakushi/components.ex#L1)

Function components for the canvas.

    import Hakushi.Components

    <.canvas id="schema" graph={@graph} on_change={&Schema.change/2}>
      <:node type="table" :let={node}>
        <div class="table">
          <h3>{node.data.name}</h3>
          <div :for={column <- node.data.columns} class="relative">
            <.handle id={column.name} kind={:target} side={:left} />
            {column.name}
            <.handle id={column.name} kind={:source} side={:right} />
          </div>
        </div>
      </:node>
    </.canvas>

`canvas/1` needs the `Hakushi` hook in the LiveSocket and the Hakushi
CSS (see the README).

# `canvas`

Renders a canvas: an endless sheet that people pan and zoom, with the
nodes of `graph` on it, drawn by the `:node` slots, and its edges.

People move nodes by dragging them (or with the arrow keys), select
them with a click, Shift and a box, connect them by dragging from a
handle to a handle (or with C, see the [Navigation](navigation.md)
guide), delete them with Delete, and copy, paste, duplicate, undo and
redo with the usual keys. Each change goes to the server, which checks
it (`rules`, then `on_change`) before anyone sees it, and takes it back
in the browser when it refuses it.

## Nodes

A `:node` slot draws the nodes of its `type`; a `:node` slot without
a `type` draws the others. The slot gets the `Hakushi.Node`, and draws
it from its `data`, with the handles where edges start and end
(`handle/1`). A canvas with no `:node` slot draws each node as a box
with its label.

A node is drawn once, and again when it changes: a change of its
`data` (a change `:update`, or a new `graph`) draws it again; a change
of the LiveView's own assigns does not.

## The graph

Without `live`, the canvas keeps its own copy of `graph`, which its
changes change. Give it a new `graph` (after the app's own change, say)
and it shows what changed. With `live`, the graph is the room's (see
`Hakushi.Issho`): make the app's changes with `Hakushi.Live.change/2`
or `Hakushi.Issho.change/3`.

## Attributes

* `id` (`:string`) (required) - the id of the canvas.
* `graph` (`Hakushi.Graph`) (required) - the nodes and edges, a `Hakushi.Graph`.
* `on_change` (`:any`) - `fn change, context -> :ok | {:error, reason} end`: the app's own check of each change, and where it saves it. `context` has the `graph` before the change and the `result` after it, the `user` and the `canvas`. See the [Changes](changes.md) guide. Defaults to `nil`.
* `new_node` (`:any`) - `fn item, {x, y} -> node | nil end`: the node for an item dropped on the canvas (`canvas_item/1`), or for a double click on the sheet (`item` is `nil`). A node with no `id` gets one. Defaults to `nil`.
* `rules` (`:list`) - the rules of the edges, see `Hakushi.Rules`. Defaults to `[]`.
* `live` (`:any`) - `{issho, topic}`: a canvas that everyone in the Issho room `topic` shares, see `Hakushi.Issho`. Defaults to `nil`.
* `user` (`:map`) - the person, on a shared canvas: a map with an `:id`, and a `:name`, `:color` and `:avatar`. Defaults to `nil`.
* `background` (`:atom`) - the paper: dots, lines (graph paper), crosses, or none. Defaults to `:dots`. Must be one of `:dots`, `:lines`, `:cross`, or `:none`.
* `grid` (`:integer`) - the size of a square of the paper, in pixels at 100%. Defaults to `20`.
* `snap` (`:boolean`) - when `true`, nodes snap to the paper's grid. Defaults to `false`.
* `wheel` (`:atom`) - what the mouse wheel does: pan (and zoom with ⌘ or Ctrl), or zoom. Defaults to `:pan`. Must be one of `:pan`, or `:zoom`.
* `fit` (`:boolean`) - when `true`, the canvas opens on all of its nodes. Defaults to `true`.
* `min_zoom` (`:float`) - the smallest zoom. Defaults to `0.1`.
* `max_zoom` (`:float`) - the largest zoom. Defaults to `4.0`.
* `minimap` (`:boolean`) - when `true`, an overview of the canvas in a corner. Defaults to `true`.
* `controls` (`:boolean`) - when `true`, buttons to zoom, fit, tidy up, undo and redo, and to download the canvas. Defaults to `true`.
* `layout` (`:atom`) - the way the tidy up (⇧L, the controls) lays the nodes out: in layers from left to right, or from top to bottom; see [Layout and export](layout.md). Defaults to `:right`. Must be one of `:right`, or `:down`.
* `export` (`:boolean`) - when `true`, a button of the controls downloads the canvas as an image. Defaults to `true`.
* `readonly` (`:boolean`) - when `true`, people pan, zoom and select, and change nothing. Defaults to `false`.
* `label` (`:string`) - the name of the canvas, for screen readers. Defaults to `nil`.
* `node_label` (`:any`) - `fn node -> text end`: the name of a node for screen readers; the default is its data's `label` or `name`, or its id. Defaults to `&Hakushi.Canvas.label/1`.
* `locale` (`:string`) - the locale of the canvas's own words; the default is `config :hakushi, locale:`, else "en". Defaults to `nil`.
* `messages` (`:map`) - words that replace the built-in ones, see `Hakushi.Messages`. Defaults to `nil`.
* `class` (`:any`) - classes for the canvas element. Defaults to `nil`.
* Global attributes are accepted. attributes for the canvas element.
## Slots

* `node` - draws the nodes of a type (`:let` gets the `Hakushi.Node`). Accepts attributes:

  * `type` (`:string`) - the type of the nodes it draws; none for every other type.
  * `resizable` (`:boolean`) - when `true`, people resize these nodes by their corners.
  * `group` (`:boolean`) - when `true`, these nodes hold others: a node dropped on one goes in it, see [Groups](groups.md).
* `person` - draws a person on a shared canvas (`:let` gets a map with "id", "name", "color", "avatar").
* `empty` - shows on a canvas without nodes.

# `canvas_item`

Renders an item that people drag onto a canvas, outside it: a palette
of the things the canvas makes. Dropped on the canvas, it becomes the
node that the canvas's `new_node` gives for `item`. Enter or a click
puts it in the middle of the canvas, for the keyboard and for a touch
screen.

    <.canvas_item for="schema" item="table">New table</.canvas_item>

## Attributes

* `for` (`:string`) (required) - the id of the canvas.
* `item` (`:string`) (required) - what it makes, for `new_node`.
* `class` (`:any`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `inner_block` (required)

# `handle`

Renders a handle: a point of a node where edges start (`:source`), end
(`:target`), or both.

A handle sits on a `side` of its nearest positioned ancestor: the node,
or an element of it with `position: relative`, as a row of a table
whose edges start at the row.

    <div :for={column <- node.data.columns} class="relative">
      {column.name}
      <.handle id={column.name} side={:right} type={column.type} />
    </div>

A node may have several handles with one `id`, on different sides (a
row with a handle at each end): an edge meets the one nearest its
other end, so the line takes the short way whichever side the other
node is on.

`type` and `accepts` say what connects to what: a handle connects to a
handle that `accepts` its `type` (any, when `accepts` is `nil`). While
a person draws an edge, the handles it may end on show, and no others.

## Attributes

* `id` (`:string`) - the id of the handle in its node, the edges' `source_handle` or `target_handle`. Defaults to `nil`.
* `kind` (`:atom`) - where edges start (`:source`), end (`:target`), or both. Defaults to `:both`. Must be one of `:source`, `:target`, or `:both`.
* `side` (`:atom`) - the side it sits on. Defaults to `:right`. Must be one of `:left`, `:right`, `:top`, or `:bottom`.
* `type` (`:string`) - what its edges carry, for `accepts`. Defaults to `nil`.
* `accepts` (`:list`) - the types it takes; `nil` for any. Defaults to `nil`.
* `max` (`:integer`) - the most edges it has; `nil` for any number. Defaults to `nil`.
* `label` (`:string`) - its name, for screen readers. Defaults to `nil`.
* `class` (`:any`) - Defaults to `nil`.
* Global attributes are accepted.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
