# Event Handlers

Defines what happens when user interactions (click, hover, longpress, ...) occur
on a component. Replaces the legacy *hover event* / *tap event* configuration — old
settings are automatically migrated on load.

## Concept

A component can have *multiple* event handlers. Each handler is one combination of:

- **trigger** — when to fire (DOM event / gesture)
- **action** — what to do (one declarative action *or* `script`)
- **target** — which component(s) to operate on
- **value** — the data passed to the action / script
- **disabled** — temporary off switch

Handlers fire in the order they appear in the list. Each handler is independent —
errors in one do not block the others.

## Trigger

| trigger      | meaning                                                                |
| ------------ | ---------------------------------------------------------------------- |
| `click`      | Mouse click / tap. The most common trigger.                            |
| `dblclick`   | Double click. Two rapid consecutive clicks.                            |
| `mouseenter` | Pointer entered the component area. Fires once on entry.               |
| `mouseleave` | Pointer left the component area. Fires once on exit.                   |
| `longpress`  | Press and hold (≈ 500ms). Distinct from a normal click.                |
| `mousedown`  | The moment the mouse button is pressed.                                |
| `mouseup`    | The moment the mouse button is released.                               |
| `pressed`    | `mousedown` ↔ `mouseup` pair (legacy convenience).                     |
| `tap`        | Alias of `click` (legacy). New handlers should use `click`.            |
| `hover`      | Alias of `mouseenter` (legacy). New handlers should use `mouseenter`. |

`mouseenter` / `mouseleave` are often paired to apply and revert a visual state
(such as emphasize).

## Action

The action determines *what the handler does*. Two families: **script** (free JS)
and **declarative** (one of the predefined actions).

### script

Run free-form JavaScript when the trigger fires. The script body has access to
these variables:

| variable    | meaning                                                                  |
| ----------- | ------------------------------------------------------------------------ |
| `component` | The current component (the one the handler is registered on).            |
| `scene`     | The root scene. Use `scene.root.findAll(selector, component)` to lookup. |
| `event`     | The original DOM (or synthetic) event.                                   |
| `targets`   | Components found by the `target` selector — empty array if target blank. |
| `value`     | The handler's `value` field. Set it in the Value input to pass extra data into the script. |

`await` is supported. The script runs as an async function; rejections are
caught and logged.

Example:

```js
const res = await fetch('/api/inventory/' + component.data)
component.data = await res.json()
```

### Declarative actions

These cover common patterns without writing code.

- **data-toggle** — flip `target.data` between truthy / falsy.
- **data-tristate** — cycle `target.data` through `0 → 1 → 2 → 0`.
- **data-spreading** — force re-run of the target's data spread mapping (using
  its current data).
- **data-set** — set `target.data` to `value`.
- **partial-data-set** — when `target.data` is an object, merge `value` keys
  into it (partial update).
- **value-set** — set `target.value` to `value` (for components that expose a
  `value` property distinct from `data`).
- **partial-value-set** — partial merge into `target.value` when it is an
  object.
- **info-window** — open the info-window associated with `target`.
- **emphasize** — visually emphasize `target` (animation). Often paired with
  `mouseleave` + restore to revert.

## Target

A selector that locates components. Resolved by `scene.root.findAll(selector, component)`.

| selector form  | matches                                                          |
| -------------- | ---------------------------------------------------------------- |
| `#id`          | Component whose id equals `id`.                                  |
| `.class`       | Components whose class list contains `class` (space-separated).  |
| `<type>`       | Components whose `type` equals the given name (e.g. `rect`, `button`). |
| `(self)`       | The current component itself.                                    |
| `(all)`        | All components in the scene.                                     |
| `(root)`       | The root component.                                              |
| `(parent)`     | The current component's parent.                                  |
| `(child)` / `(children)` | The current component's direct children.               |
| `(sibling)` / `(siblings)` | Siblings of the current component (excluding itself). |

Multiple components can match — the action applies to each.

If `target` is left empty, no components are matched (`targets` is an empty
array in scripts). Use `(self)` to explicitly target the current component.

## Value

The data passed to the action (or to the script via the `value` variable).

- For `data-set` / `value-set` etc., `value` is the literal to assign — string,
  number, boolean, or object.
- If `value` looks like an accessor expression (e.g. `accessor.foo`), it is
  evaluated as `component.access(value)` so it can read from the surrounding data
  context.

## Disabled

Each handler has a per-row enable / disable toggle. Disabled handlers stay in
the list but skip execution — useful for keeping a draft or debugging without
deleting the row.

## Migration from legacy

If a component still has the old `state.event = { tap, hover, ... }` shape, the
runtime converts it to `state.eventHandlers[]` automatically on load. The
original `state.event` is kept untouched (rollback safety / old viewer
compatibility) — the new editor writes only to `state.eventHandlers`.
