# Kanban

Quadro de tarefas por etapa: arraste o cartão de uma coluna para outra. No celular as colunas empilham.

- Nome no registry: `kanban`
- Tipo: bloco
- Dependências npm: @air/react-drag-to-select, @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities, framer-motion, motion
- Demo: https://ui.visantlabs.com/c/kanban
- Categorias: conteudo, board, dnd, selecao

## Quando usar

- Use quando: Board de tarefas ou pipeline com arrastar entre colunas e multi-seleção, em ferramenta interna
- Evite quando: Lista densa pra ordenar e editar: data-table; triagem rápida no celular, swipe-actions

## Instalar

```bash
npx shadcn@latest add @visant/kanban
```

## Usar

```tsx
<Kanban />
```

## API

### Kanban

- `columns: KanbanColumn<C>[]`
- `items: KanbanItem<T>[]`
- `renderCard: (args: KanbanRenderCardArgs<T>) => any` — Slot obrigatório: o consumidor desenha o card (mantém o core de DnD genérico).
- `className?: string`
- `columnClassName?: string` — Classe extra por coluna (largura, etc.).
- `enabled?: boolean = true` — DnD ligado. Off = board somente-leitura (ex.: board do cliente).
- `onMove?: (move: KanbanMove) => void` — Disparado ao soltar: mover entre colunas E reordenar dentro da mesma. O consumidor persiste (status + ordem) e/ou revalida.
- `onSelectionChange?: (ids: string[]) => void` — Notifica a nova seleção — SSoT do consumidor + gatilho da barra de batch.
- `renderColumnEmpty?: (column: KanbanColumn<C>) => any` — Slot opcional do vazio da coluna.
- `renderColumnHeader?: (column: KanbanColumn<C>) => any` — Slot opcional do cabeçalho da coluna.
- `selectable?: boolean = false` — Liga a seleção múltipla: marquee "select by area" (arrastar sobre o vazio) + shift/ctrl/cmd-clique num card. Só faz efeito com `enabled` (board editável). O consumidor desenha a UI de batch a partir de `onSelectionChange`.
- `selectedIds?: string[]` — Ids selecionados (controlado). Se omitido, o Kanban mantém a seleção interna.

### KanbanColumn

Coluna droppable + SortableContext. Também aceita drop quando vazia (o useDroppable no corpo inteiro), senão colunas sem card não seriam alvo.

- `column: KanbanColumn<C>`
- `enabled: boolean`
- `isOver: boolean`
- `items: KanbanItem<T>[]`
- `render: (args: KanbanRenderCardArgs<T>) => any`
- `className?: string`
- `landingId?: string` — Cartão ainda pousando: segue como buraco até o fantasma chegar.
- `onSelectToggle?: (id: string) => void`
- `renderEmpty?: (column: KanbanColumn<C>) => any`
- `renderHeader?: (column: KanbanColumn<C>) => any`
- `selectable?: boolean = false`
- `selectedIds?: Set<string>`

### KanbanCard

Card arrastável (useSortable). O card inteiro é a alça — a distância de ativação do sensor (no <Kanban>) garante que um CLIQUE simples ainda passe para o onClick do conteúdo; só vira arraste depois de mover alguns px.

- `enabled: boolean`
- `item: KanbanItem<T>`
- `render: (args: KanbanRenderCardArgs<T>) => any`
- `landing?: boolean = false` — O fantasma ainda está descendo até aqui.
- `onSelectToggle?: (id: string) => void`
- `selectable?: boolean = false` — Seleção múltipla ligada — habilita o shift/ctrl/cmd-clique de toggle.
- `selected?: boolean = false`

### Kanban

- `columns: KanbanColumn<C>[]`
- `items: KanbanItem<T>[]`
- `renderCard: (args: KanbanRenderCardArgs<T>) => any` — Slot obrigatório: o consumidor desenha o card (mantém o core de DnD genérico).
- `className?: string`
- `columnClassName?: string` — Classe extra por coluna (largura, etc.).
- `enabled?: boolean = true` — DnD ligado. Off = board somente-leitura (ex.: board do cliente).
- `onMove?: (move: KanbanMove) => void` — Disparado ao soltar: mover entre colunas E reordenar dentro da mesma. O consumidor persiste (status + ordem) e/ou revalida.
- `onSelectionChange?: (ids: string[]) => void` — Notifica a nova seleção — SSoT do consumidor + gatilho da barra de batch.
- `renderColumnEmpty?: (column: KanbanColumn<C>) => any` — Slot opcional do vazio da coluna.
- `renderColumnHeader?: (column: KanbanColumn<C>) => any` — Slot opcional do cabeçalho da coluna.
- `selectable?: boolean = false` — Liga a seleção múltipla: marquee "select by area" (arrastar sobre o vazio) + shift/ctrl/cmd-clique num card. Só faz efeito com `enabled` (board editável). O consumidor desenha a UI de batch a partir de `onSelectionChange`.
- `selectedIds?: string[]` — Ids selecionados (controlado). Se omitido, o Kanban mantém a seleção interna.
