# Render And Style Vector Items

Committed vector items render from canvas state.

The standard runtime already knows how to place vector items in the world
vector layer. Most drawing apps do not need to render SVG vector items by hand.

## Standard Runtime Rendering

Use the normal runtime:

```heex
<.canvas_runtime {canvas_runtime_attrs(assigns, cursor_mode: @cursor_mode)}>
  <:item :let={context}>
    <article class="item-frame">
      <header {drag_handle_attrs()}>{context.item.label}</header>
      {context.content}
      <.resize_handles :if={context.view.resizable?} />
    </article>
  </:item>
</.canvas_runtime>
```

Committed vector items are projected before ordinary HTML item frames. They render as
world-space SVG vector items, with selection and resize behavior attached to
the same item model as the rest of the canvas.

Keep the `:item` slot focused on ordinary item frames and content. Drawing
vector items do not need a LiveView content process.

## Drafts Versus Committed Vector Items

Drafts and committed vector items have different lifecycles:

| State | Owner | Rendered By | Persisted |
|---|---|---|---|
| Active draft | Browser runtime | Browser draft layer | No |
| Committed vector item | Canvas state | Runtime vector layer | Yes |

Use `set_draw_style_js/3` for the browser draft style. Use drawing commands or
attrs for committed vector item style.

## Style Committed Vector Items

Use `update_style_attrs/3` for application controls:

```heex
<button
  :if={@selected_vector_item}
  {update_style_attrs(@selected_vector_item, %{
    color: "#16a34a",
    width: 3,
    fill_color: "none",
    stroke_style: "solid",
    opacity: 100,
    roundness: 0
  })}
>
  Green
</button>
```

Server equivalent:

```elixir
socket =
  LivePanels.Drawing.update_style!(socket, item, %{
    color: "#16a34a",
    width: 3,
    fill_color: "none",
    stroke_style: "solid",
    opacity: 100,
    roundness: 0
  })
```

The style map is complete on purpose. Application palettes should normalize partial UI
changes into a full style before sending the update.

## Apply Palette Changes To Selected Vector Items

A common drawing app pattern is to update draft style and any selected vector items at
the same time:

```elixir
def handle_event("set_draw_style", style, socket) do
  style = normalize_draw_style(style, socket.assigns.draw_style)
  socket = assign(socket, :draw_style, style)

  socket =
    socket
    |> selected_vector_items()
    |> Enum.reduce(socket, fn item, acc ->
      LivePanels.Drawing.update_style!(acc, item, style)
    end)

  {:noreply, socket}
end
```

Keep this as application behavior. Some products want palette changes to affect only
new vector items, while others expect selected vector items to change immediately.

## Manual Vector Item Rendering

Only use manual rendering when you are building a custom render loop or a
custom SVG editor.

Render a neutral SVG vector item:

```heex
<LivePanels.Toolkit.Integration.Render.vector_item item={context.item} class="annotation-vector" />
```

Render the canonical world SVG vector item:

```heex
<LivePanels.Toolkit.Integration.Render.svg_vector_item
  id={"vector-item-#{context.item.id}"}
  item={context.item}
  selected={false}
  active={false}
/>
```

The `svg_vector_item/1` component includes the runtime protocol attrs needed
for dragging, selection bounds, resize handles, and erase hit targets. If you
replace it with fully custom SVG, your application must provide the interaction attrs
it needs.

## Use Vector State For Custom SVG

Use normalized vector state instead of reading raw item maps:

```elixir
case LivePanels.Drawing.vector_state(item) do
  {:ok, draw} ->
    assign(socket, :draw, draw)

  :error ->
    socket
end
```

The state includes kind, style, points, text, labels, route presentation,
and other drawing fields that the runtime has already normalized.

## Z-Order And Visibility

Vector items are canvas items, so normal item ordering and visibility apply. Use the
same application controls you use for other item types:

```heex
<button {z_order_selection_attrs(:front)}>Front</button>
<button {z_order_selection_attrs(:back)}>Back</button>
```

If your app layers drawings over a document, keep the document as an item or
background layer and let vector items stay in world space. Avoid a second drawing
coordinate system unless the product truly needs one.
