# useTableColumnResize

## 使用方法

这个组合式函数返回一个 `TablePlugin`，给列表头的边缘加上可以拖的把手。除了最后一列比例列之外，每列行末都有一个把手；最后一列比例列不给把手，它负责吃掉剩下的空间。拖动时先按新宽度预览，松开指针才提交：`onColumnResizeEnd` 拿到所有宽度变了的列，你把它并进 `columnWidths`。

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

比例列把宽度让给旁边可拖的列，所以拖动时表格一直撑满。固定像素列没有邻列可让，只有自己变宽变窄，差值由最后一列吸收。

```ts
const columnWidths = ref<Record<string, number>>({})
const resizePlugin = useTableColumnResize(() => ({
  columnWidths: columnWidths.value,
  minWidth: 80,
  maxWidth: 400,
  onColumnResizeEnd(updates) {
    columnWidths.value = { ...columnWidths.value, ...updates }
  },
}))
```

每次读配置都会重新取值，所以宽度存在 `ref` 里时要传 getter。直接传对象也能跑，但表格会用第一次读到的那份宽度。

### 能拖多窄、多宽

每列的下限来自列自己：`proportional(n, { minWidth })` 用它给的 `minWidth`，`pixel(n)` 的列不会窄过 `n`，没有 `width` 的列停在 60px。配置里的 `minWidth` 一设就盖过这些下限，`maxWidth` 是所有列共同的上限。

### 键盘和 RTL

把手是一个 WAI-ARIA 窗口分隔条：聚焦后按左、右方向键移动 10px，按住 Shift 移动 50px，按 Home 跳到最窄，按 End 跳到 `maxWidth`。左右跟随书写方向，所以在 RTL 下按键调宽的方向是反的。

## 示例

### useTableColumnResize — 可拖动列宽

用 useTableColumnResize 的表格。拖任意列表头的右边缘就能改宽，松开指针后提交。剩下的比例列分掉剩余宽度。

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

interface User extends Record<string, unknown> {
  id: string
  name: string
  email: string
  role: string
}

const users: User[] = [
  { id: '1', name: 'Alice Johnson', email: 'alice@example.com', role: 'Engineer' },
  { id: '2', name: 'Bob Smith', email: 'bob@example.com', role: 'Designer' },
  { id: '3', name: 'Charlie Brown', email: 'charlie@example.com', role: 'PM' },
  { id: '4', name: 'Diana Prince', email: 'diana@example.com', role: 'Engineer' },
  { id: '5', name: 'Eve Davis', email: 'eve@example.com', role: 'Analyst' },
]

const columns: TableColumn<User>[] = [
  { key: 'name', header: 'Name' },
  { key: 'email', header: 'Email', width: proportional(2) },
  { key: 'role', header: 'Role', width: pixel(120) },
]

const columnWidths = ref<Record<string, number>>({})
const resizePlugin = useTableColumnResize<User>(() => ({
  columnWidths: columnWidths.value,
  onColumnResizeEnd: (updates) => {
    columnWidths.value = { ...columnWidths.value, ...updates }
  },
}))
</script>

<template>
  <Table
    :data="users"
    :columns="columns"
    id-key="id"
    has-hover
    :plugins="{ columnResize: resizePlugin }"
  />
</template>
```

## 参数

`useTableColumnResize()` 只接一个配置对象。宽度存在 `ref` 里时用 getter 包一层，表格每次读都能拿到最新的值：`useTableColumnResize(() => ({ ... }))`。

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `columnWidths` | `Record<string, number>` | `{}` | 已经提交的像素宽度，键是列 key。有值时覆盖列自己声明的宽度。 |
| `onColumnResizeEnd` | `(updates: Record<string, number>) => void` | — | 一次拖动结束（松开指针或按键）时调用。参数是「列 key → 新宽度」的映射，包含所有宽度变了的列，把它并进 `columnWidths` 就是新的状态。最后一列不在里面，它的宽度跟着剩余空间走。 |
| `minWidth` | `number` | — | 拖动时所有列共用的最窄像素，一设就盖过每一列自己的下限。 |
| `maxWidth` | `number` | `Infinity` | 拖动时所有列共用的最宽像素。 |
| `columns` | `readonly TableColumn[]` | — | 列定义。用来取每一列的下限，并区分比例列和固定像素列，好决定相邻列和最后一列怎么动。表格自己会传，只有自己调下面的辅助函数时才需要给。 |

## 返回值

`useTableColumnResize()` 返回一个 `TablePlugin&lt;T&gt;`，放进 `Table` 的 `plugins` 里。它填的是插件约定里的三个字段：

| 名称 | 类型 | 说明 |
| --- | --- | --- |
| `widthFor` | `(column: TableColumn) => number \| undefined` | 返回某一列已经提交的宽度，没有就返回 `undefined`。 |
| `resizeFor` | `(column: TableColumn, columns: readonly TableColumn[]) => TableColumnResizeContribution \| null` | 说明一列怎么参与拖动：当前宽度、最窄、最宽、让出宽度的相邻列，以及这一列有没有把手。 |
| `onColumnResizeEnd` | `(updates: Record<string, number>) => void` | `Table` 把变了的列交给它。它把宽度取整到整像素，再转给你的 `onColumnResizeEnd`。 |

## 辅助函数

同一个模块也导出插件内部用的计算函数，自己的界面需要算宽度时可以直接用。

| 名称 | 类型 | 说明 |
| --- | --- | --- |
| `columnResizeMinWidth` | `(width: ColumnWidth \| undefined, globalMinWidth?: number) => number` | 一列能拖到的最窄像素：设了全局下限就用它，否则用列自己的下限。 |
| `isProportionalColumnWidth` | `(width: ColumnWidth \| undefined) => boolean` | 比例列和没写宽度的列都算比例列。 |
| `resizeColumnWidths` | `(plan: ColumnResizePlan, delta: number) => number[]` | 把指针位移（像素）套到一组列宽快照上，返回算好的每一列宽度。 |
| `columnResizeStep` | `(isShiftKey: boolean) => number` | 按一下方向键走多少像素：10px，按住 Shift 是 50px。 |
| `columnResizeDirectionSign` | `(direction: string) => 1 \| -1` | 横向位移在书写方向上的符号。RTL 返回 `-1`。 |
