# sortable-table

Drag- and keyboard-driven row/column reordering plus column resizing for an
existing `<table>`. Headless: it manipulates DOM order and column widths,
reflects `data-dragging`, and emits typed events — it applies no visual styles.

> Assumes the Nth `[data-c42-sortable-col]` header maps to the Nth cell in each
> row (1:1 column ↔ cell alignment).

## Markup

```html
<table data-c42-sortable-table>
  <thead>
    <tr>
      <th data-c42-sortable-col data-value="name">
        Name
        <button data-c42-sortable-col-handle aria-label="Reorder column"></button>
        <span data-c42-sortable-resize></span>
      </th>
      <th data-c42-sortable-col data-value="age">
        Age
        <button data-c42-sortable-col-handle aria-label="Reorder column"></button>
        <span data-c42-sortable-resize></span>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr data-c42-sortable-row data-value="r1">
      <td><button data-c42-sortable-row-handle aria-label="Reorder row"></button>Ada</td>
      <td>36</td>
    </tr>
    <tr data-c42-sortable-row data-value="r2">
      <td><button data-c42-sortable-row-handle aria-label="Reorder row"></button>Linus</td>
      <td>54</td>
    </tr>
  </tbody>
</table>
```

### Markup parts

| Selector | Role |
|----------|------|
| `[data-c42-sortable-table]` | Root `<table>` |
| `[data-c42-sortable-col]` | Column header `<th>` with a `data-value` |
| `[data-c42-sortable-col-handle]` | Drag/keyboard handle for column reordering |
| `[data-c42-sortable-resize]` | Resize handle (one per resizable column) |
| `[data-c42-sortable-row]` | Body `<tr>` with a `data-value` |
| `[data-c42-sortable-row-handle]` | Drag/keyboard handle for row reordering |

## Options

```ts
import { SortableTable } from '@42/core/sortable-table';

new SortableTable(root, {
  reorderRows: true,      // row drag + keyboard (default true)
  reorderColumns: false,  // column drag + keyboard (default false)
  resizeColumns: false,   // pointer/keyboard resize (default false)
  resizeStep: 16,         // px per arrow press when resizing (default 16)
  minColumnWidth: 48,     // px floor for resizing (default 48)
});
```

## Interaction

### Rows
- Pointer: drag a `[data-c42-sortable-row-handle]`; the row reorders live as you
  cross other rows' vertical midpoints; the dragged row gets `data-dragging`.
- Keyboard (handle focused): `ArrowUp`/`ArrowDown` move one position,
  `Home`/`End` jump to the top/bottom.

### Columns
- Pointer/keyboard via `[data-c42-sortable-col-handle]`: `ArrowLeft`/`ArrowRight`
  move the column; the header cell and every body cell at that index move
  together.

### Resize
- Pointer: drag `[data-c42-sortable-resize]` horizontally.
- Keyboard (handle focused, `role="separator"`): `ArrowLeft`/`ArrowRight` adjust
  by `resizeStep`, clamped to `minColumnWidth`.

## Methods

| Method | Description |
|--------|-------------|
| `getRowOrder()` | Current row `data-value`s in order |
| `getColumnOrder()` | Current column `data-value`s in order |
| `moveRow(fromValue, toValue)` | Reorder rows programmatically |
| `moveColumn(fromValue, toValue)` | Reorder columns programmatically |
| `setColumnWidth(value, px)` | Set a column width (clamped) |
| `destroy()` | Remove all listeners |

## Events

| Event | Detail |
|-------|--------|
| `sortabletable:reorder` | `{ axis: 'row' \| 'column', from, to, order: string[] }` |
| `sortabletable:resize` | `{ value: string, width: number }` |

## Notes

- The theme sets `table-layout: fixed` so `setColumnWidth` takes effect.
- Reordering is DOM-based: read the new order from the `reorder` event's
  `order` array (or `getRowOrder()` / `getColumnOrder()`).
