# useTableSortable

## Usage

Call `useTableSortable` with a config object containing sort state and callback. Pass the returned plugin to `Table` via the `plugins` prop.

```ts
import { useTableSortable } from '@astryx-vue/core/Table'
```

## Examples

### useTableSortable — Sortable Columns

Table with sortable columns, click headers to sort ascending or descending.

```vue
<script setup lang="ts">
import type { TableColumn } from '@astryx-vue/core/Table'
import { pixel, proportional, Table, useTableSortable, useTableSortableState } from '@astryx-vue/core/Table'

interface Employee extends Record<string, unknown> {
  id: string
  name: string
  email: string
  role: string
  age: number
}

const employees: Employee[] = [
  { id: '1', name: 'Alice', email: 'alice@example.com', role: 'Engineer', age: 32 },
  { id: '2', name: 'Bob', email: 'bob@example.com', role: 'Designer', age: 28 },
  { id: '3', name: 'Charlie', email: 'charlie@example.com', role: 'Manager', age: 45 },
  { id: '4', name: 'Diana', email: 'diana@example.com', role: 'Engineer', age: 37 },
  { id: '5', name: 'Eve', email: 'eve@example.com', role: 'Admin', age: 29 },
]

const columns: TableColumn<Employee>[] = [
  { key: 'name', header: 'Name', width: proportional(1), sortable: true },
  { key: 'email', header: 'Email', width: proportional(2), sortable: true },
  { key: 'role', header: 'Role', width: proportional(1), sortable: true },
  { key: 'age', header: 'Age', width: pixel(80), sortable: true },
]

const { sortedData, sortConfig } = useTableSortableState<Employee>({
  data: employees,
  defaultSort: [{ sortKey: 'name', direction: 'ascending' }],
})
const sortablePlugin = useTableSortable<Employee>(sortConfig)
</script>

<template>
  <Table
    :data="sortedData"
    :columns="columns"
    id-key="id"
    :plugins="{ sortable: sortablePlugin }"
  />
</template>
```

## Properties

The config is a `MaybeRefOrGetter`, so pass a getter or a ref to keep the plugin on the current sort state.

## Parameters

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `sort` | `TableSortState` | — | Current sort state: an ordered array of `{ sortKey, direction }`. The first entry is the primary sort, the rest are tiebreakers. An empty array means unsorted. Direction is the full word: `'ascending'` / `'descending'`, not `'asc'` / `'desc'`. |
| `onSortChange` | `(sort: TableSortState) => void` | — | Called when the user clicks a header cell to change sort. Receives the next sort state. |
| `allowUnsortedState` | `boolean` | `true` | Allow cycling back to unsorted. When true: 'ascending', 'descending', unsorted. When false: 'ascending', 'descending', 'ascending'. |
| `isMultiSortEnabled` | `boolean` | `false` | Enable multi-sort via Shift+click. Regular click still replaces the entire sort state. |

## Returns

| Field | Type | Description |
| --- | --- | --- |
| `sortFor` | `(column: TableColumn) => TableSortContribution \| null` | Returns the sort contribution for a header cell, or `null` when the column is not sortable. A column is sortable when it declares `sortable: true` or `sortable: { sortKey }`. |
| `sortFor().direction` | `'ascending' \| 'descending' \| null` | The direction this column is currently sorted by, or `null`. |
| `sortFor().rank` | `number \| null` | 1-based position in a multi-sort, shown beside the arrow. `null` unless more than one entry is sorted. |
| `sortFor().label` | `string` | The localized accessible name for the header button, such as "Sort by Name. Sort descending". |
| `sortFor().onClick` | `(event: MouseEvent) => void` | The click handler. A plain click replaces the whole sort state; Shift+click adds, retargets, or removes this column. Read Shift from the event. |
