# @canvas-components/react-list-table

`@canvas-components/react-list-table` 是 `@canvas-components/list-table` 的 React 适配层，负责把原生 Canvas 表格接入 React 应用，并提供更接近业务开发习惯的组件化入口。

通过顶层 `loading` 属性控制数据加载状态：`<ReactListTable loading={loading} dataSource={rows} columns={columns} />`。加载期间展示加载提示并保留汇总标题；加载完成后，组件自动计算并统一展示完整汇总结果。服务端汇总可通过 `query.summaryValues` 提供，业务侧无需单独管理汇总计算状态。

## 属性更新与性能

- 相同属性引用的父组件重渲染由 `React.memo` 跳过；组件内部交互仍正常更新。
- `onChange`、`onRow` 以及查询、分页、行选择、展开、拖拽和性能通知等事件使用稳定入口，调用时读取最近一次已提交的回调，避免仅回调引用变化就重置底层查询。
- `scroll`、`theme`、`pagination` 等常用配置进行第一层字段比较，内容相同的新对象复用之前的配置。嵌套对象和数组仍按引用判断。
- `columns`、`dataSource`、受控选中/展开数组，以及 `rowKey`、列渲染、`getCheckboxProps` 等影响数据或展示的函数，变化时继续刷新。大数据数组不做深比较，建议用 `useMemo` 或稳定状态保存，并在内容改变时更新引用。

## 示例效果

![React List Table 基础示例](./assets/examples/basic.gif)

### 完整示例图集

<details>
<summary>100w 数据渲染</summary>

![100w 数据渲染](./assets/examples/million-rows.gif)

</details>

<details>
<summary>行选择</summary>

![行选择](./assets/examples/row-selection.gif)

</details>

<details>
<summary>单元格内容</summary>

![单元格内容](./assets/examples/cell-content.gif)

</details>

<details>
<summary>斑马条纹</summary>

![斑马条纹](./assets/examples/striped.gif)

</details>

<details>
<summary>主题切换</summary>

![主题切换](./assets/examples/theme.gif)

</details>

<details>
<summary>高亮模式</summary>

![高亮模式](./assets/examples/highlight-mode.gif)

</details>

<details>
<summary>右键菜单</summary>

![右键菜单](./assets/examples/context-menu.gif)

</details>

<details>
<summary>数据格式</summary>

![数据格式](./assets/examples/data-format.gif)

</details>

<details>
<summary>省略提示</summary>

![省略提示](./assets/examples/ellipsis-tooltip.gif)

</details>

<details>
<summary>可展开行</summary>

![可展开行](./assets/examples/expandable.gif)

</details>

<details>
<summary>单元格编辑</summary>

![单元格编辑](./assets/examples/editable-cell.gif)

</details>

<details>
<summary>远程查询</summary>

![远程查询](./assets/examples/remote-query.gif)

</details>

<details>
<summary>表格分页</summary>

![表格分页](./assets/examples/pagination.gif)

</details>

<details>
<summary>空状态</summary>

![空状态](./assets/examples/empty-state.gif)

</details>

<details>
<summary>宽高配置</summary>

![宽高配置](./assets/examples/sized.gif)

</details>

<details>
<summary>表头排序、过滤、固定</summary>

![表头排序、过滤、固定](./assets/examples/header-actions.gif)

</details>

<details>
<summary>多级表头</summary>

![多级表头](./assets/examples/multi-header.gif)

</details>

<details>
<summary>汇总行</summary>

![汇总行](./assets/examples/summary-row.gif)

</details>

<details>
<summary>合并行列</summary>

![合并行列](./assets/examples/merged-cells.gif)

</details>

<details>
<summary>拖动改变列宽</summary>

![拖动改变列宽](./assets/examples/resize.gif)

</details>

<details>
<summary>轮播滚动</summary>

![轮播滚动](./assets/examples/carousel-scroll.gif)

</details>

<details>
<summary>缓存配置</summary>

![缓存配置](./assets/examples/cached-columns.gif)

</details>

<details>
<summary>拖拽表头排序</summary>

![拖拽表头排序](./assets/examples/draggable.gif)

</details>

<details>
<summary>跨表行拖拽</summary>

![跨表行拖拽](./assets/examples/row-drag.gif)

</details>

<details>
<summary>超级示例</summary>

![超级示例](./assets/examples/super.gif)

</details>

## 功能作用

- 提供 `ReactListTable` 组件
- 内置工具栏、分页层、编辑层、tooltip、图片预览
- 暴露 `ref` 方法，方便外部校验和滚动定位
- 保持底层大数据性能和纯原生渲染能力

## 安装方法

```bash
pnpm add @canvas-components/react-list-table @canvas-components/list-table react@^16.8 react-dom@^16.8
```

最低依赖版本：

- `react >= 16.8.0`
- `react-dom >= 16.8.0`
- `Node.js >= 18.12.0`
- `pnpm >= 9.0.0`

## 使用方法

打印配置可以通过 `printPresets` 预设交给 `ReactListTable`。每个预设有一个用于选择的名称和打印配置；未提供的字段使用默认值。没有已保存配置时默认使用第一个预设，也可以在打印配置弹窗中切换；启用本地缓存后，后续打开优先恢复所选预设和本地修改。

```tsx
import {
  ReactListTable,
  type ReactListTablePrintPreset,
} from "@canvas-components/react-list-table";

const printPresets: ReactListTablePrintPreset[] = [
  {
    name: "横向明细",
    config: {
      title: "明细清单",
      paperSize: "a4",
      orientation: "landscape",
      rowsPerPage: 24,
      pageMargins: { top: 10, right: 10, bottom: 10, left: 10 },
      columns: [
        { key: "name", width: 60, align: "left" },
        { key: "amount", width: 35, align: "right" },
      ],
      selectedKeys: ["name", "amount"],
    },
  },
];

<ReactListTable
  storageKey="invoice-list"
  printPresets={printPresets}
  columns={columns}
  dataSource={data}
/>;
```

配置名称显示在打印配置弹窗顶部。列通过 `key` 对应表格列；列宽单位为毫米。需要缓存预设选择和用户调整时提供 `storageKey` 并保持弹窗中的本地缓存选项开启。

右键直接打印（包括选择模板打印）会先显示“每次打印页数”设置，默认每批 50 页。可通过 `directPrintPagesPerBatch={20}` 修改默认值，用户仍可在开始前调整。每批只生成并加载指定数量的实际打印页（包括自动续页），关闭浏览器打印窗口后释放该批 iframe；点击“继续下一批”才生成后续批次，也可以取消剩余任务。浏览器无法区分打印窗口中的“打印”和“取消”，因此批次之间不会自动继续。

```tsx
import { useMemo, useRef } from "react";
import {
  ReactListTable,
  type ReactListTableRef,
} from "@canvas-components/react-list-table";

interface UserRow {
  id: number;
  name: string;
  age: number;
}

export function DemoTable() {
  const tableRef = useRef<ReactListTableRef<UserRow> | null>(null);

  const columns = useMemo(
    () => [
      { key: "name", title: "姓名", dataIndex: "name", width: 180 },
      {
        key: "age",
        title: "年龄",
        dataIndex: "age",
        width: 120,
        align: "right" as const,
      },
    ],
    [],
  );

  return (
    <ReactListTable<UserRow>
      ref={tableRef}
      rowKey="id"
      height={480}
      columns={columns}
      dataSource={[
        { id: 1, name: "张三", age: 28 },
        { id: 2, name: "李四", age: 31 },
      ]}
      toolbar={{ showRefresh: true, showExport: true }}
    />
  );
}
```

## 属性说明

### `ReactListTableProps`

`ReactListTableProps` 继承自 `ListTableOptions`，并额外补充 React 宿主相关能力。

| 属性        | 类型                                    | 说明                        |
| ----------- | --------------------------------------- | --------------------------- |
| `width`     | `number \| string`                      | 表格宽度                    |
| `height`    | `number \| string`                      | 表格高度                    |
| `emptyText` | `string`                                | 空状态文案                  |
| `scroll`    | `ReactListTableScrollConfig`            | React 风格滚动尺寸配置      |
| `locale`    | `ReactListTableLocale`                  | 本地化文案                  |
| `onChange`  | `ListTableQueryChange<RecordType>`      | 查询状态变更回调            |
| `className` | `string`                                | 根节点类名                  |
| `style`     | `CSSProperties`                         | 根节点样式                  |
| `title`     | `ReactNode`                             | 标题栏左侧内容              |
| `toolbar`   | `false \| ReactListTableToolbarOptions` | 工具栏配置，传 `false` 隐藏 |

其余如 `columns`、`dataSource`、`rowSelection`、`expandable`、`pagination`、`rowDrag`、`draggable`、`resizable` 等属性与 `@canvas-components/list-table` 保持一致。

### `ReactListTableToolbarOptions`

| 属性                       | 类型                         | 说明                               |
| -------------------------- | ---------------------------- | ---------------------------------- |
| `showRefresh`              | `boolean`                    | 是否显示刷新按钮                   |
| `showFullscreen`           | `boolean`                    | 是否显示全屏按钮                   |
| `showDensity`              | `boolean`                    | 是否显示密度切换                   |
| `showColumnSetting`        | `boolean`                    | 是否显示列设置                     |
| `columnSettingWidth`       | `number \| string`           | 列设置面板宽度                     |
| `columnSettingHeaderExtra` | `ReactNode`                  | 列设置标题区中重置按钮前的扩展内容 |
| `showExport`               | `boolean`                    | 是否显示导出按钮                   |
| `exportOptions`            | `ListTableExportXlsxOptions` | 默认导出的文件名和汇总行配置       |
| `onRefresh`                | `() => void`                 | 点击刷新回调                       |
| `onExport`                 | `() => void`                 | 自定义导出回调                     |
| `getFullscreenNode`        | `() => HTMLElement \| null`  | 自定义全屏节点                     |
| `extra`                    | `ReactNode`                  | 工具栏右侧额外内容                 |

## 统一切换调试模式

`ReactListTableDebugProvider` 可为后代中的全部 `ReactListTable` 同步开启核心调试模式，并默认显示表头、表体、固定列分割线、命中区域和表头操作区。表格自身通过 `debug` 传入的其他选项仍会保留，也可以显式关闭某个可视化项：

```tsx
import {
  ReactListTable,
  ReactListTableDebugProvider,
} from "@canvas-components/react-list-table";

<ReactListTableDebugProvider enabled={statsEnabled}>
  <ReactListTable
    columns={columns}
    dataSource={dataSource}
    debug={{ showBodyBounds: true }}
  />
</ReactListTableDebugProvider>;
```

## 方法说明

### `ReactListTableRef`

| 方法               | 签名                                             | 说明                            |
| ------------------ | ------------------------------------------------ | ------------------------------- |
| `validate`         | `() => Promise<RecordType[]>`                    | 触发表格校验                    |
| `exportXlsx`       | `(options?: ListTableExportXlsxOptions) => void` | 导出 XLSX，可配置文件名和汇总行 |
| `scrollTo`         | `(options) => void`                              | 滚动到指定行                    |
| `getDebugSnapshot` | `() => ListTableDebugSnapshot \| null`           | 获取调试快照                    |

导出文件名弹窗使用 `react-components` 的 `ReactModal`、`ReactInput`，默认开启，文件后缀不可编辑。通过表格 `exportOptions={{ fileName: "报表", promptFileName: false }}` 可配置默认名称并跳过弹窗；工具栏 `toolbar.exportOptions` 或实例 `exportXlsx` 的同名选项可覆盖默认配置。取消不会生成文件。XLSX 默认追加当前已显示的汇总行，传入 `includeSummary: false` 可关闭。

## 类型别名

| 类型                                     | 说明                                     |
| ---------------------------------------- | ---------------------------------------- |
| `ReactListTableTableProps<RecordType>`   | `ReactListTableProps<RecordType>` 的别名 |
| `ReactListTableColumnType<RecordType>`   | 单列类型别名                             |
| `ReactListTableColumnsType<RecordType>`  | 列数组类型别名                           |
| `ReactListTableRowSelection<RecordType>` | 行选择类型别名                           |
| `ReactListTablePagination`               | 分页类型别名                             |
| `ReactListTableQuery<RecordType>`        | 查询类型别名                             |

## 推荐场景

- React 后台管理表格
- 大数据量只读 / 可编辑表格
- 需要原生性能但又希望保留 React 组件用法的场景

## 清空行选择

通过组件 ref 调用 `tableRef.current?.clearRowSelection()`。该方法清空行勾选和 Shift 选择锚点，选择发生变化时触发 `rowSelection.onChange([], [], { type: "none" })`。受控模式请在回调中同步 `selectedRowKeys`。

过滤面板勾选或取消过滤项并即时应用时，会立即清空全部已选行，不保留仍在过滤结果中的勾选。

调用 `tableRef.current?.setSelectedRowKeys(["1", "2", "3"])` 可以主动设置勾选；单选模式只保留第一个 key。设置后触发 `onChange`，传入空数组等同清空。
