# `Dala.Ui.Diff`
[🔗](https://github.com/manhvu/dala/blob/main/lib/dala/ui/diff.ex#L1)

Diff engine for incremental UI updates.

Compares two UI trees (as `Dala.Node` structs) and produces a minimal
set of patches to transform the old tree into the new tree.

## Patch format

Patches are tuples tagged with an action:

    {:replace, id, node}           # Replace entire node
    {:update_props, id, props}     # Update props on existing node (full replacement)
    {:patch_node, id, mask, props}  # Patch only changed fields (field-mask based)
    {:insert, parent_id, index, node}  # Insert new node
    {:remove, id}                  # Remove node

## Usage

    old_tree = Dala.Node.from_map(old_map, "root")
    new_tree = Dala.Node.from_map(new_map, "root")
    patches = Dala.Diff.diff(old_tree, new_tree)

## Node identity

Nodes are identified by the `:id` field in `Dala.Node`. This must be
stable across renders for proper reconciliation.

## Field masks

When only a few props change, `{:patch_node, id, mask, props}` is emitted
instead of `{:update_props, id, props}`. The mask is a 16-bit bitmask
where bit N corresponds to field tag (N+1). If more than half the fields
changed, a full `{:update_props, ...}` is sent instead.

# `node_id`

```elixir
@type node_id() :: String.t() | atom()
```

# `patch`

```elixir
@type patch() ::
  {:replace, node_id(), Dala.Node.t()}
  | {:update_props, node_id(), map()}
  | {:patch_node, node_id(), non_neg_integer(), map()}
  | {:insert, node_id(), non_neg_integer(), Dala.Node.t()}
  | {:remove, node_id()}
```

# `compute_field_mask`

```elixir
@spec compute_field_mask(map(), map()) :: {non_neg_integer(), map()}
```

Compute a field mask and changed props map from old and new props.

Returns a `{mask, changed_map}` tuple where `mask` is a 16-bit bitmask
and `changed_map` contains only the props that differ.

# `diff`

```elixir
@spec diff(Dala.Node.t() | map() | nil, Dala.Node.t() | map() | nil) :: [patch()]
```

Compute the diff between two UI trees.

Returns a list of patches to transform `old_tree` into `new_tree`.
Trees can be either `Dala.Node` structs or raw maps (as produced by
`Dala.Ui.Widgets` / `render/1`).

---

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