# Edit Points, Labels, Text, And Arrowheads

Committed vector items can be inspected and edited because their vector state is
part of canvas state.

The application decides which edit controls are visible and when. LivePanels provides
commands and attrs for the common vector item edits.

## Read Vector State

Start with the selected item and ask LivePanels for normalized vector state:

```elixir
defp selected_vector_item(item) do
  case LivePanels.Drawing.vector_state(item) do
    {:ok, draw} -> %{item: item, draw: draw}
    :error -> nil
  end
end
```

Use that data to choose the inspector:

```heex
<aside :if={@selected_vector_item} class="vector-item-inspector">
  <p>{@selected_vector_item.draw.kind}</p>
</aside>
```

## Point Handles

Point-backed vector items include freehand, polyline, arrow, and line vector items.

When rendering a custom SVG editor, add point handle attrs to handles that
share the vector item coordinate system:

```heex
<circle
  :for={{point, index} <- Enum.with_index(@draw.points)}
  cx={point.x}
  cy={point.y}
  r="5"
  {vector_point_handle_attrs(@item, index)}
/>
```

The browser drags the handle locally and pushes the committed point update on
release.

Server equivalent:

```elixir
socket =
  LivePanels.Drawing.replace_point!(socket, item, index, %{x: 120, y: 48})
```

## Add Points

For polyline-like editors, render midpoint add handles:

```heex
<circle
  :for={{point, index} <- Enum.with_index(@add_points)}
  cx={point.x}
  cy={point.y}
  r="4"
  {vector_point_add_handle_attrs(@item, index)}
/>
```

Or use an explicit control:

```heex
<button {add_point_attrs(@item, 2, %{x: 180, y: 72})}>
  Add point
</button>
```

Server equivalent:

```elixir
socket =
  LivePanels.Drawing.Point.add!(socket, item, 2, %{x: 180, y: 72})
```

## Remove Points

Use `remove_point_attrs/3` for application controls:

```heex
<button {remove_point_attrs(@item, index)}>
  Remove point
</button>
```

Server equivalent:

```elixir
socket = LivePanels.Drawing.Point.remove!(socket, item, index)
```

The server validates that the resulting vector item still has valid point topology.

## Text Vector Items

Update committed text vector items through the drawing command path:

```elixir
socket =
  LivePanels.Drawing.update_text!(socket, item, %{
    text: "Needs review",
    font: %{size: 22, family: "Inter"},
    align: :center,
    vertical_align: :middle
  })
```

For a simple text-only update:

```elixir
socket = LivePanels.Drawing.update_text!(socket, item, "Needs review")
```

Use this for drawing-owned text. Use a normal item LiveView when the user is
editing rich product content.

## Bound Labels

Line, arrow, and box-shape vector items can carry a bound label:

```elixir
socket =
  LivePanels.Drawing.update_label!(socket, item, %{
    text: "approved",
    align: :center,
    vertical_align: :middle
  })
```

Clear it:

```elixir
socket = LivePanels.Drawing.clear_label!(socket, item)
```

Labels are vector item presentation. If a label is the only copy of a domain value,
store it in your app and write the vector item label as a projection of that value.

## Arrowheads And Routes

Arrowheads and route presentation are accepted when creating or importing
linear vector items:

```elixir
LivePanels.Drawing.vector_item!(socket, :arrow, placement,
  points: [%{x: 0, y: 40}, %{x: 280, y: 40}],
  arrowheads: %{start: false, end: true},
  route: :straight,
  style: style
)
```

Use graph connectors when endpoints and topology matter. Use drawing arrows when the
line is visual annotation.

## Edit In Transactions

Group related edits in a transaction when one UI action should create one
history entry:

```elixir
socket =
  LivePanels.Canvas.transaction!(socket, fn tx ->
    tx
    |> LivePanels.Drawing.update_style!(item, style)
    |> LivePanels.Drawing.update_label!(item, "review")
  end)
```

This is useful for inspector forms that submit several vector item fields at once.
