# 이벤트 핸들러 (event handlers)

컴포넌트에 사용자 상호작용 (click, hover, longpress, ...) 이 발생했을 때의
동작을 정의한다. 기존의 *hover event* / *tap event* 설정을 대체한다 — 이전
설정은 로드 시 자동으로 마이그레이션된다.

## 개념

하나의 컴포넌트에 *여러 개* 의 이벤트 핸들러를 등록할 수 있다. 각 핸들러는
다음의 조합이다.

- **trigger** — 발화 시점 (DOM 이벤트 / 제스처)
- **action** — 수행할 동작 (declarative 액션 중 하나 또는 `script`)
- **target** — 동작을 적용할 대상 컴포넌트 선택자
- **value** — 액션 / 스크립트에 전달할 데이터
- **disabled** — 잠시 비활성화

핸들러는 목록의 순서대로 실행된다. 각 핸들러는 독립적이라 한 핸들러의 오류가
다음 핸들러 실행을 막지 않는다.

## Trigger (트리거)

| trigger      | 의미                                                              |
| ------------ | ----------------------------------------------------------------- |
| `click`      | 마우스 클릭 / 탭. 가장 일반적인 트리거.                           |
| `dblclick`   | 더블 클릭. 빠르게 연속 2회 클릭해야 발화.                         |
| `mouseenter` | 포인터가 컴포넌트 영역에 *진입* 한 순간 1회.                      |
| `mouseleave` | 포인터가 컴포넌트 영역을 *이탈* 한 순간 1회.                      |
| `longpress`  | 약 500ms 이상 누름. 일반 클릭과 별개로 발화.                      |
| `mousedown`  | 버튼 누름 시작 시점.                                              |
| `mouseup`    | 버튼 누름 해제 시점.                                              |
| `pressed`    | `mousedown` ↔ `mouseup` 페어 (legacy 호환).                       |
| `tap`        | `click` 의 alias (legacy). 새 핸들러에는 `click` 사용 권장.       |
| `hover`      | `mouseenter` 의 alias (legacy). 새 핸들러에는 `mouseenter` 권장. |

`mouseenter` / `mouseleave` 는 *적용 → 해제* 패턴 (예: emphasize) 으로 짝지어
사용하는 경우가 많다.

## Action (액션)

핸들러가 *무엇을 하는지* 결정한다. 크게 **script** (자유 JS) 와 **declarative**
(미리 정의된 액션 중 하나) 두 갈래이다.

### script

트리거가 발화하면 작성한 JavaScript 를 실행한다. 스크립트 본문에서는 다음
변수를 사용할 수 있다.

| 변수        | 의미                                                                |
| ----------- | ------------------------------------------------------------------- |
| `component` | 핸들러가 등록된 현재 컴포넌트.                                      |
| `scene`     | 루트 scene. `scene.root.findAll(selector, component)` 로 다른 컴포넌트 검색. |
| `event`     | 원본 DOM (또는 합성) 이벤트.                                        |
| `targets`   | `target` 선택자로 찾은 컴포넌트 배열. target 이 비면 빈 배열.       |
| `value`     | 핸들러의 `value` 필드. 스크립트로 추가 데이터를 넘기려면 Value 입력에 값을 적는다. |

`await` 사용 가능. 스크립트는 async function 으로 실행되며, rejection 은
콘솔에 로그된다.

예시:

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

### Declarative 액션

코드를 작성하지 않고 사용할 수 있는 흔한 패턴들.

- **data-toggle** — `target.data` 를 truthy ↔ falsy 로 토글.
- **data-tristate** — `target.data` 를 `0 → 1 → 2 → 0` 순환.
- **data-spreading** — target 의 현재 data 로 강제 데이터 전파.
- **data-set** — `target.data` 를 `value` 로 설정.
- **partial-data-set** — `target.data` 가 객체일 때, `value` 의 키만 partial
  merge.
- **value-set** — `target.value` 를 `value` 로 설정 (data 가 아닌 value
  속성을 다루는 컴포넌트용).
- **partial-value-set** — `target.value` 가 객체일 때 partial merge.
- **info-window** — `target` 과 연결된 info-window 를 띄움.
- **emphasize** — `target` 을 시각적으로 강조 (애니메이션). 보통
  `mouseleave` + restore 와 짝지어 복귀.

## Target (선택자)

대상 컴포넌트를 찾는 선택자. `scene.root.findAll(selector, component)` 으로
해석된다.

| 표기                          | 매칭 대상                                                   |
| ----------------------------- | ----------------------------------------------------------- |
| `#id`                         | id 가 일치하는 컴포넌트.                                    |
| `.class`                      | class 목록에 해당 값을 포함하는 컴포넌트 (공백 구분 다중). |
| `<타입이름>`                  | type 이 일치하는 컴포넌트 (예: `rect`, `button`).           |
| `(self)`                      | 현재 컴포넌트 자기 자신.                                    |
| `(all)`                       | scene 안 모든 컴포넌트.                                     |
| `(root)`                      | 루트 컴포넌트.                                              |
| `(parent)`                    | 현재 컴포넌트의 부모.                                       |
| `(child)` / `(children)`      | 현재 컴포넌트의 직접 자식들.                                |
| `(sibling)` / `(siblings)`    | 현재 컴포넌트의 형제들 (자기 자신 제외).                    |

복수 매칭이 가능하며, 액션은 매칭된 모든 컴포넌트에 적용된다.

`target` 을 비워두면 매칭되는 컴포넌트가 없다 (스크립트의 `targets` 는 빈
배열). 현재 컴포넌트를 명시적으로 대상으로 하려면 `(self)` 를 사용한다.

## Value (값)

액션 또는 스크립트의 `value` 변수로 전달되는 데이터.

- `data-set` / `value-set` 등에서는 그대로 대입될 *리터럴* (문자열 / 숫자 /
  boolean / 객체).
- `value` 가 accessor 표현식 형태 (예: `accessor.foo`) 인 경우
  `component.access(value)` 로 평가되어 주변 데이터 컨텍스트의 값을 가져온다.

## Disabled (비활성화)

핸들러마다 *enable / disable* 토글이 있다. 비활성화된 핸들러는 목록에는
남지만 실행되지 않는다 — 초안을 보존하거나 디버깅 시 임시로 끄는 용도.

## Legacy 마이그레이션

컴포넌트에 옛 `state.event = { tap, hover, ... }` 형태가 남아 있으면, 런타임이
로드 시 자동으로 `state.eventHandlers[]` 로 변환한다. 원본 `state.event` 는
손대지 않는다 (rollback 안전망 + 옛 뷰어 호환). 새 편집기는
`state.eventHandlers` 에만 쓴다.
