# kanban

Drag- and keyboard-driven kanban board. Headless: it moves item elements
between columns and reorders them within a column, reflects `data-dragging` on
the active item, and emits a typed move event — it applies no visual styles.

## Markup

```html
<div data-c42-kanban>
  <div data-c42-kanban-column data-value="todo" data-label="To do">
    <div data-c42-kanban-list>
      <div data-c42-kanban-item data-value="t1">First task</div>
      <div data-c42-kanban-item data-value="t2">Second task</div>
    </div>
  </div>
  <div data-c42-kanban-column data-value="doing" data-label="In progress">
    <div data-c42-kanban-list></div>
  </div>
  <div data-c42-kanban-column data-value="done" data-label="Done">
    <div data-c42-kanban-list></div>
  </div>
</div>
```

### Markup parts

| Selector | Role |
|----------|------|
| `[data-c42-kanban]` | Board root |
| `[data-c42-kanban-column]` | A column; needs a `data-value` (and optional `data-label` for the themed heading) |
| `[data-c42-kanban-list]` | The drop container inside a column (becomes `role="list"`) |
| `[data-c42-kanban-item]` | A card; needs a `data-value`; made focusable (`tabindex="0"`) |

## Options

```ts
import { Kanban } from '@42/core/kanban';

new Kanban(root, {
  drag: true,      // pointer drag to move/reorder (default true)
  keyboard: true,  // arrow/Home/End keyboard moves (default true)
});
```

## Interaction

- **Pointer**: press an item and drag; it reorders live as you cross other
  items' vertical midpoints, and moves into whichever list is under the pointer.
  The dragged item carries `data-dragging`. A single `kanban:move` fires on drop
  if the position changed.
- **Keyboard** (item focused):
  - `ArrowUp` / `ArrowDown` — reorder within the column.
  - `Home` / `End` — jump to the top/bottom of the column.
  - `ArrowLeft` / `ArrowRight` — move to the adjacent column (keeping the same
    index, clamped). No-op at the first/last column.

## Methods

| Method | Description |
|--------|-------------|
| `getOrder()` | `Record<columnValue, itemValue[]>` snapshot of the board |
| `moveItem(itemValue, toColumnValue, toIndex?)` | Move programmatically (defaults to the end); returns `true` if it changed and emitted |
| `destroy()` | Remove all listeners |

## Events

| Event | Detail |
|-------|--------|
| `kanban:move` | `{ item, from, to, fromIndex, toIndex, order }` where `order` is the post-move `getOrder()` snapshot |

## Notes

- The controller reorders the actual DOM nodes; read the resulting state from
  the event's `order` or from `getOrder()`.
- Columns can start empty — the list is still a valid drop target (give it a
  min-height in CSS so it is reachable, as the theme does).
