{"_id":"@bestcoder/react-native-data-table","_rev":"6-1a9b2398bba1e5f7524ff39f06f819af","name":"@bestcoder/react-native-data-table","dist-tags":{"latest":"1.0.5"},"versions":{"1.0.0":{"name":"@bestcoder/react-native-data-table","version":"1.0.0","keywords":["react-native","expo","data-table","flash-list","typescript"],"license":"UNLICENSED","_id":"@bestcoder/react-native-data-table@1.0.0","maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"dist":{"shasum":"3229f6282785cde25f406835c7341277cebd7431","tarball":"https://registry.npmjs.org/@bestcoder/react-native-data-table/-/react-native-data-table-1.0.0.tgz","fileCount":42,"integrity":"sha512-j/DyUisP9oK5Vm4b1UEwXCJ2iU2W3bOgKTuHU+nnZoaVfSD6DFFBUlSUdW76odloVRSQVY7K/Thobgi/r4XYwg==","signatures":[{"sig":"MEYCIQDYUQYSacKVlBwuKGc3FntVtTjsFHGmejmQq8d0iE/TRwIhAPAC8WYj4a6kSIWlpArTidoKNlBnanP+BFCwiheKx2p8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":169020},"main":"dist/index.js","_from":"file:bestcoder-react-native-data-table-1.0.0.tgz","types":"dist/index.d.ts","engines":{"node":">=22.13.0"},"scripts":{"lint":"eslint .","build":"tsc -p tsconfig.build.json","prepack":"npm run build"},"_npmUser":{"name":"bestcoder","email":"coolestcode@163.com"},"_resolved":"/Users/guoguo/Desktop/react-native-data-table/bestcoder-react-native-data-table-1.0.0.tgz","_integrity":"sha512-j/DyUisP9oK5Vm4b1UEwXCJ2iU2W3bOgKTuHU+nnZoaVfSD6DFFBUlSUdW76odloVRSQVY7K/Thobgi/r4XYwg==","_npmVersion":"11.16.0","description":"A high-performance cross-platform data table for React Native and Expo.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","eslint":"^9.39.5","typescript":"~6.0.3","@types/react":"~19.2.2","react-native":"0.86.0","eslint-config-expo":"~57.0.0","@shopify/flash-list":"2.0.2"},"peerDependencies":{"react":">=19.2.3 <20","react-native":">=0.86.0 <0.87","@shopify/flash-list":">=2.0.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/react-native-data-table_1.0.0_1784183906660_0.783849216251066","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@bestcoder/react-native-data-table","version":"1.0.1","keywords":["react-native","expo","data-table","flash-list","typescript"],"author":{"name":"bestcoder"},"license":"MIT","_id":"@bestcoder/react-native-data-table@1.0.1","maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"dist":{"shasum":"21dd4e9032c518ec65845a468496ad9bec4475cd","tarball":"https://registry.npmjs.org/@bestcoder/react-native-data-table/-/react-native-data-table-1.0.1.tgz","fileCount":43,"integrity":"sha512-3EywPgNEuM0tHnOdHDhrCXLll32ZtyKlYvceYgDUfjzHdEjIu/eHig+2mcc+HEwBr42raadWaTeZqDimAiHDOw==","signatures":[{"sig":"MEUCIQCG5HLsM4dVU6MxpBIfwAwyfqknG7HOk3jwyK7IHncgDQIgeztSj7n4xWdpiqzRjaEc1B2zi/65GL43zn5hiBZSAXY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170067},"main":"dist/index.js","_from":"file:bestcoder-react-native-data-table-1.0.1.tgz","types":"dist/index.d.ts","engines":{"node":">=22.13.0"},"scripts":{"lint":"eslint .","build":"tsc -p tsconfig.build.json","prepack":"npm run build"},"_npmUser":{"name":"bestcoder","email":"coolestcode@163.com"},"_resolved":"/Users/guoguo/Desktop/react-native-data-table/bestcoder-react-native-data-table-1.0.1.tgz","_integrity":"sha512-3EywPgNEuM0tHnOdHDhrCXLll32ZtyKlYvceYgDUfjzHdEjIu/eHig+2mcc+HEwBr42raadWaTeZqDimAiHDOw==","_npmVersion":"11.16.0","description":"A high-performance cross-platform data table for React Native and Expo.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","eslint":"^9.39.5","typescript":"~6.0.3","@types/react":"~19.2.2","react-native":"0.86.0","eslint-config-expo":"~57.0.0","@shopify/flash-list":"2.0.2"},"peerDependencies":{"react":">=19.2.3 <20","react-native":">=0.86.0 <0.87","@shopify/flash-list":">=2.0.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/react-native-data-table_1.0.1_1784184554784_0.14213373103150517","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@bestcoder/react-native-data-table","version":"1.0.2","keywords":["react-native","expo","data-table","flash-list","typescript"],"author":{"name":"bestcoder"},"license":"MIT","_id":"@bestcoder/react-native-data-table@1.0.2","maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"homepage":"https://github.com/yuanxinn/react-native-data-table#readme","bugs":{"url":"https://github.com/yuanxinn/react-native-data-table/issues"},"dist":{"shasum":"596f7e0321dad216e9ac240f8b0c04b17a091d80","tarball":"https://registry.npmjs.org/@bestcoder/react-native-data-table/-/react-native-data-table-1.0.2.tgz","fileCount":45,"integrity":"sha512-5ZpcZugpe4T2SwVzyZJdOtfoqK2v4zizihVWjRhHLxehLgE50cglItlKp3gOSsf28PJuvth1Vwl3o7oCUzQ90Q==","signatures":[{"sig":"MEYCIQDyVhZP/uE7IlZ1tS6Izy1ksH7NkWvEHcyaBGeABiT6YAIhANah9mPWkl4HmYtI9Ewbp2F2LMMW7R8H9yZXhrQNJywy","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bestcoder%2freact-native-data-table@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":172524},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.13.0"},"gitHead":"99e693ea3d72aa7ca710c0311c7804e3140346ef","scripts":{"lint":"eslint .","build":"tsc -p tsconfig.build.json","prepack":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e7d2e19c-fd78-44dc-aa75-973c07553f8b"}},"repository":{"url":"git+https://github.com/yuanxinn/react-native-data-table.git","type":"git"},"_npmVersion":"11.16.0","description":"A high-performance cross-platform data table for React Native and Expo.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","eslint":"^9.39.5","typescript":"~6.0.3","@types/react":"~19.2.2","react-native":"0.86.0","eslint-config-expo":"~57.0.0","@shopify/flash-list":"2.0.2"},"peerDependencies":{"react":">=19.2.3 <20","react-native":">=0.86.0 <0.87","@shopify/flash-list":">=2.0.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/react-native-data-table_1.0.2_1784192915432_0.1421687329380621","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@bestcoder/react-native-data-table","version":"1.0.3","keywords":["react-native","expo","data-table","flash-list","typescript"],"author":{"name":"bestcoder"},"license":"MIT","_id":"@bestcoder/react-native-data-table@1.0.3","maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"homepage":"https://github.com/yuanxinn/react-native-data-table#readme","bugs":{"url":"https://github.com/yuanxinn/react-native-data-table/issues"},"dist":{"shasum":"bda9b4360ecf69410579ccb3d0c4652122be8ab8","tarball":"https://registry.npmjs.org/@bestcoder/react-native-data-table/-/react-native-data-table-1.0.3.tgz","fileCount":45,"integrity":"sha512-bXM9Sx1QBaN27rtzTNQu+CkcHBR3sKh61TYBwl+TBNrcZExupgoagVoux0KimVw93Yo/zncHR5ABcLYYoboEJA==","signatures":[{"sig":"MEUCIQCqhE7JsAinWWhzFcopwGmeJqgz2vov81Xl7bLQChGLAQIgeCT1KGjoHPaF8ruojL0hPvSJM0z4k6yYzOU9t0X1M2o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bestcoder%2freact-native-data-table@1.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":173694},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.13.0"},"gitHead":"704c615666a575eb3eeaeee450bce4f77ec7d49b","scripts":{"lint":"eslint .","build":"tsc -p tsconfig.build.json","prepack":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e7d2e19c-fd78-44dc-aa75-973c07553f8b"}},"repository":{"url":"git+https://github.com/yuanxinn/react-native-data-table.git","type":"git"},"_npmVersion":"11.16.0","description":"A high-performance cross-platform data table for React Native and Expo.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","eslint":"^9.39.5","typescript":"~6.0.3","@types/react":"~19.2.2","react-native":"0.86.0","eslint-config-expo":"~57.0.0","@shopify/flash-list":"2.0.2"},"peerDependencies":{"react":">=19.2.3 <20","react-native":">=0.86.0 <0.87","@shopify/flash-list":">=2.0.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/react-native-data-table_1.0.3_1784214076226_0.5428645753115184","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@bestcoder/react-native-data-table","version":"1.0.4","keywords":["react-native","expo","data-table","flash-list","typescript"],"author":{"name":"bestcoder"},"license":"MIT","_id":"@bestcoder/react-native-data-table@1.0.4","maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"homepage":"https://github.com/yuanxinn/react-native-data-table#readme","bugs":{"url":"https://github.com/yuanxinn/react-native-data-table/issues"},"dist":{"shasum":"5a239a13a68afb495aa9d144dca319d6647769fd","tarball":"https://registry.npmjs.org/@bestcoder/react-native-data-table/-/react-native-data-table-1.0.4.tgz","fileCount":45,"integrity":"sha512-ff7ZFgM6qmoqGPbIn3L61LcFrTKU3XFkSxhxiq0K/f3AocX9+jIwyDgLlsRAGq4cr+4nmaC/iOPTCw6Dnzjqpg==","signatures":[{"sig":"MEUCIGRLKcfpKmfyRrQXSerM1NEY1KWOtkDN7FE5MRxDUQ9lAiEA9cd1E88kEwbgsj6P5mTo2D3zMnN9/4W/72R6rDFpGAM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bestcoder%2freact-native-data-table@1.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":178979},"jest":{"roots":["<rootDir>/src"],"preset":"@react-native/jest-preset"},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.13.0"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"c608ef135a06deb35c4630a5202a554e6a05fb22","scripts":{"lint":"eslint .","test":"jest","build":"tsc -p tsconfig.build.json","prepack":"npm run build","prepare":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e7d2e19c-fd78-44dc-aa75-973c07553f8b"}},"repository":{"url":"git+https://github.com/yuanxinn/react-native-data-table.git","type":"git"},"_npmVersion":"11.16.0","description":"A high-performance cross-platform data table for React Native and Expo.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","react":"19.2.3","eslint":"^9.39.5","typescript":"~6.0.3","@types/jest":"^29.5.14","@types/react":"~19.2.2","react-native":"0.86.0","eslint-config-expo":"~57.0.0","@shopify/flash-list":"2.3.2","@react-native/jest-preset":"^0.86.0","@react-native/babel-preset":"0.86.0","@testing-library/react-native":"^14.0.1"},"peerDependencies":{"react":">=19.0.0 <20","react-native":">=0.78.0","@shopify/flash-list":">=2.2.1 <3"},"_npmOperationalInternal":{"tmp":"tmp/react-native-data-table_1.0.4_1784909473005_0.10459355847000373","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@bestcoder/react-native-data-table","version":"1.0.5","description":"A high-performance cross-platform data table for React Native and Expo.","main":"dist/index.js","types":"dist/index.d.ts","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","lint":"eslint .","typecheck":"tsc --noEmit","test":"jest","prepack":"npm run build","prepare":"npm run build"},"jest":{"preset":"@react-native/jest-preset","roots":["<rootDir>/src"]},"keywords":["react-native","expo","data-table","flash-list","typescript"],"license":"MIT","author":{"name":"bestcoder"},"repository":{"type":"git","url":"git+https://github.com/yuanxinn/react-native-data-table.git"},"homepage":"https://github.com/yuanxinn/react-native-data-table#readme","bugs":{"url":"https://github.com/yuanxinn/react-native-data-table/issues"},"publishConfig":{"access":"public"},"peerDependencies":{"@shopify/flash-list":">=2.2.1 <3","react":">=19.0.0 <20","react-native":">=0.78.0"},"devDependencies":{"@react-native/babel-preset":"0.86.0","@react-native/jest-preset":"^0.86.0","@shopify/flash-list":"2.3.2","@testing-library/react-native":"^14.0.1","@types/jest":"^29.5.14","@types/react":"~19.2.2","eslint":"^9.39.5","eslint-config-expo":"~57.0.0","jest":"^29.7.0","react":"19.2.3","react-native":"0.86.0","typescript":"~6.0.3"},"engines":{"node":">=22.13.0"},"gitHead":"f38adb882f596e7284776a6fdc5a36f1bfe766b0","_id":"@bestcoder/react-native-data-table@1.0.5","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-OllHEkCs0yfhavghkz6Ny0x4qzr7Abve5qi3pvYyrSAeRSeVV4MdCXdo4f+MRKCU92oCNOyj/zj8Ofhf87vprQ==","shasum":"b975065d6c12a76cda4fda71b92ca041853606d7","tarball":"https://registry.npmjs.org/@bestcoder/react-native-data-table/-/react-native-data-table-1.0.5.tgz","fileCount":47,"unpackedSize":189617,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bestcoder%2freact-native-data-table@1.0.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDSqRNeNO2XQ+Tm2Cf5rclbgnCgL2EI2yue2fEavIbQeQIhAL95Eyc/4ThyFInSqXYpIe/zeB58L68AX43XynsoqjLe"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e7d2e19c-fd78-44dc-aa75-973c07553f8b"}},"directories":{},"maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native-data-table_1.0.5_1784910406460_0.033987229746352154"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-16T06:38:26.460Z","modified":"2026-07-24T16:26:47.037Z","1.0.0":"2026-07-16T06:38:26.858Z","1.0.1":"2026-07-16T06:49:14.947Z","1.0.2":"2026-07-16T09:08:35.587Z","1.0.3":"2026-07-16T15:01:16.359Z","1.0.4":"2026-07-24T16:11:13.221Z","1.0.5":"2026-07-24T16:26:46.670Z"},"bugs":{"url":"https://github.com/yuanxinn/react-native-data-table/issues"},"author":{"name":"bestcoder"},"license":"MIT","homepage":"https://github.com/yuanxinn/react-native-data-table#readme","keywords":["react-native","expo","data-table","flash-list","typescript"],"repository":{"type":"git","url":"git+https://github.com/yuanxinn/react-native-data-table.git"},"description":"A high-performance cross-platform data table for React Native and Expo.","maintainers":[{"name":"bestcoder","email":"coolestcode@163.com"}],"readme":"# @bestcoder/react-native-data-table\n\n简体中文 | [English](./README.en.md)\n\n[![npm version](https://img.shields.io/npm/v/%40bestcoder%2Freact-native-data-table.svg)](https://www.npmjs.com/package/@bestcoder/react-native-data-table)\n[![license](https://img.shields.io/npm/l/%40bestcoder%2Freact-native-data-table.svg)](https://www.npmjs.com/package/@bestcoder/react-native-data-table)\n[![npm downloads](https://img.shields.io/npm/dm/%40bestcoder%2Freact-native-data-table.svg)](https://www.npmjs.com/package/@bestcoder/react-native-data-table)\n\n基于 FlashList v2 的高性能 React Native 数据表格，支持 iOS、Android 和 Web。内置横纵滚动、固定列、自适应列宽、行选择、受控排序、展开行、异步子表、主题与边框配置。\n\nA high-performance, cross-platform data table for React Native, Expo, and React Native Web.\n\n## 特性\n\n- FlashList v2 虚拟化，适合大数据列表。\n- 纵向滚动、横向滚动与可关闭的吸顶表头。\n- `fixed: 'left' | 'right'` 左右固定列。\n- 按真实渲染内容测量自适应列宽，支持 `minWidth` 和定宽列。\n- 受控行选择、全选/半选、禁用行、自定义 Checkbox 及选择列合并。\n- 受控三态排序：`null → ascend → descend → null`。\n- 自定义展开面板或异步联动子表。\n- 下拉刷新、触底加载、空态、页面级头尾内容。\n- 可配置主题、斑马纹、按压高亮、单元格样式和网格边框。\n- TypeScript 类型声明随包发布。\n\n## 兼容性\n\n| 环境 | 支持范围 |\n|---|---|\n| Expo | SDK 57 |\n| React Native | `>=0.78.0` |\n| React | `>=19.0.0 <20` |\n| `@shopify/flash-list` | `>=2.2.1 <3` |\n| Node.js | `>=22.13.0` |\n| 平台 | iOS / Android / Web |\n\nWeb 端需要宿主项目已正常配置 React Native Web；Expo 项目默认已包含该能力。\n\n## 安装\n\n### Expo SDK 57\n\n```bash\nnpx expo install @shopify/flash-list\nnpm install @bestcoder/react-native-data-table\n```\n\n### React Native\n\n```bash\nnpm install @bestcoder/react-native-data-table @shopify/flash-list\n```\n\n本包没有自定义原生模块；原生端要求取决于 `@shopify/flash-list` 和宿主 React Native 项目。\n\n## 快速上手\n\n`DataTable` 默认使用 `flex: 1`，父容器必须有可计算的高度；也可直接传入 `height` 或 `maxHeight`。\n\n```tsx\nimport { Text, View } from 'react-native';\nimport {\n  DataTable,\n  type TableColumn,\n} from '@bestcoder/react-native-data-table';\n\ninterface Order {\n  id: string;\n  customer: string;\n  amount: number;\n  status: 'paid' | 'pending';\n}\n\nconst rows: Order[] = [\n  { id: 'SO-001', customer: 'Alice', amount: 1280, status: 'paid' },\n  { id: 'SO-002', customer: 'Bob', amount: 860, status: 'pending' },\n];\n\nconst columns: TableColumn<Order>[] = [\n  { title: '订单号', dataIndex: 'id', width: 110, fixed: 'left' },\n  { title: '客户', dataIndex: 'customer', minWidth: 120 },\n  { title: '金额', dataIndex: 'amount', align: 'right', sorter: true },\n  { title: '状态', dataIndex: 'status', minWidth: 100 },\n];\n\nexport function OrderList() {\n  return (\n    <View style={{ flex: 1 }}>\n      <DataTable\n        data={rows}\n        columns={columns}\n        keyExtractor={(item) => item.id}\n        striped\n        highlightOnRowPress\n      />\n    </View>\n  );\n}\n```\n\n## 核心用法\n\n### 受控排序\n\n组件只输出排序意图，**不会修改 `data`**。调用方需根据 `currentSort` 排序数据后再传回。\n\n```tsx\nconst [sort, setSort] = useState<SortParams>();\nconst sortedRows = useMemo(() => sortRows(rows, sort), [rows, sort]);\n\n<DataTable\n  data={sortedRows}\n  columns={columns}\n  keyExtractor={(item) => item.id}\n  currentSort={sort}\n  onSort={setSort}\n/>\n```\n\n### 行选择\n\n`rowSelection` 是受控配置。不传时不渲染选择列。\n\n```tsx\nconst tableRef = useRef<DataTableHandle>(null);\nconst [selectedKeys, setSelectedKeys] = useState<string[]>([]);\n\n<DataTable\n  ref={tableRef}\n  data={rows}\n  columns={columns}\n  keyExtractor={(item) => item.id}\n  rowSelection={{\n    selectedRowKeys: selectedKeys,\n    onChange: (keys) => setSelectedKeys(keys),\n    getCheckboxProps: (record) => ({ disabled: record.status === 'paid' }),\n    position: 'first',\n  }}\n/>\n\ntableRef.current?.selectAll();\ntableRef.current?.clearSelection();\ntableRef.current?.scrollToTop();\n```\n\n### 展开行\n\n`custom` 是默认模式。展开内容占满当前视口宽度，不跟随主表横向滚动。\n\n```tsx\n<DataTable\n  data={rows}\n  columns={columns}\n  keyExtractor={(item) => item.id}\n  renderExpandedRow={(record) => (\n    <View style={{ padding: 16 }}>\n      <Text>订单：{record.id}</Text>\n    </View>\n  )}\n/>\n```\n\n### 异步子表\n\n`sub-table` 模式先通过 `onExpandFetch` 获取子数据，再由 `getSubTable` 返回子表规格。子表没有表头，但可与父表共享横向滚动、固定列和最终列宽。\n\n```tsx\n<DataTable<Order, LineItem[]>\n  data={rows}\n  columns={columns}\n  keyExtractor={(item) => item.id}\n  expandedRowType=\"sub-table\"\n  onExpandFetch={(order) => fetchLineItems(order.id)}\n  getSubTable={(_order, _index, items) => ({\n    rows: items,\n    columns: [\n      { colIndex: 0, dataIndex: 'sku' },\n      { colIndex: 1, dataIndex: 'name' },\n      { colIndex: 2, dataIndex: 'quantity', align: 'right' },\n    ],\n  })}\n/>\n```\n\n- `SubColumn.colIndex` 按父表**视觉列顺序**对齐，包含内部选择列和固定列归位后的顺序。\n- `colSpan` 可横跨多个父列。\n- Loading、Error 和 Empty 有默认面板，均可自定义。\n- `subTableSyncScroll` 和 `subTableSyncFixedColumns` 默认都为 `true`。\n\n### 主题\n\n`theme` 接受 `Partial<DataTableTheme>`，与内置主题合并。只需覆盖要修改的 token。\n\n```tsx\n<DataTable\n  data={rows}\n  columns={columns}\n  keyExtractor={(item) => item.id}\n  theme={{\n    primary: '#6D5EF7',\n    primaryLight: '#EFEDFF',\n    headerBg: '#F8F7FF',\n  }}\n/>\n```\n\n| Token | 用途 |\n|---|---|\n| `headerBg` | 表头、展开区和斑马纹奇数行默认背景 |\n| `rowBg` | 数据行、Checkbox 和斑马纹偶数行默认背景 |\n| `text` | 主文字 |\n| `textSecondary` | 次级文字、错误和空态 |\n| `primary` | Checkbox、排序激活态和 Loading |\n| `primaryLight` | 默认行按压高亮 |\n| `onPrimary` | 主色上的对勾/半选标记 |\n| `line` | 默认边框颜色 |\n| `disabled` | Checkbox 和排序禁用/未激活态 |\n\n也可导入 `DEFAULT_DATA_TABLE_THEME` 作为完整基线。\n\n### 边框\n\n```tsx\n<DataTable\n  data={rows}\n  columns={columns}\n  keyExtractor={(item) => item.id}\n  border={{\n    horizontal: true,\n    vertical: true,\n    outer: true,\n    color: '#D7D9E0',\n    width: 1,\n  }}\n/>\n```\n\n- 省略 `border`：只开启默认横向分隔线。\n- `false`：关闭全部边框。\n- `true`：开启默认横向分隔线。\n- 对象：通过 `horizontal`、`vertical`、`outer`、`color` 和 `width` 组合配置。\n\n## API\n\n### `DataTableProps<T, D>`\n\n| Prop | 类型 | 默认值 | 说明 |\n|---|---|---|---|\n| `data` | `T[]` | 必填 | 原始数据源 |\n| `columns` | `TableColumn<T>[]` | 必填 | 列配置 |\n| `keyExtractor` | `(item, index) => string` | 必填 | 返回全局唯一且稳定的行 key |\n| `remeasureKey` | `string \\| number` | — | 变化时原地重新测量自适应列 |\n| `height` | `DimensionValue` | — | 固定表格高度，优先于 `maxHeight` |\n| `maxHeight` | `DimensionValue` | — | 父 flex 布局中的最大高度 |\n| `striped` | `boolean` | `false` | 开启斑马纹 |\n| `stripeColors` | `[string, string]` | `[theme.rowBg, theme.headerBg]` | 偶数/奇数行背景 |\n| `highlightOnRowPress` | `boolean` | `false` | 按下行时高亮 |\n| `highlightColor` | `string` | `theme.primaryLight` | 行按压高亮色 |\n| `rowSelection` | `RowSelectionConfig<T>` | — | 受控行选择配置；开关选择模式或切换合并宿主列时会自动原地重测列宽 |\n| `stickyHeader` | `boolean` | `true` | 表头吸顶开关 |\n| `ref` | `Ref<DataTableHandle>` | — | 命令式句柄：行选择与纵/横向滚动方法，见 `DataTableHandle` |\n| `onSort` | `(params: SortParams) => void` | — | 排序状态变化回调 |\n| `currentSort` | `SortParams` | — | 当前受控排序状态 |\n| `renderSortIcon` | `(order) => ReactNode` | — | 全局自定义排序图标，三态宽度应保持一致 |\n| `refreshing` | `boolean` | — | 下拉刷新状态 |\n| `onRefresh` | `() => void` | — | 下拉刷新回调 |\n| `onEndReached` | `() => void` | — | 触底加载回调 |\n| `onEndReachedThreshold` | `number` | — | FlashList 触底阈值 |\n| `ListHeaderComponent` | `ComponentType \\| ReactElement \\| null` | — | 只跟随纵向滚动的页面级头部 |\n| `ListFooterComponent` | `ComponentType \\| ReactElement \\| null` | — | 只跟随纵向滚动的页面级尾部 |\n| `ListEmptyComponent` | `ComponentType \\| ReactElement \\| null` | — | `data` 为空时渲染 |\n| `expandedRowType` | `'custom' \\| 'sub-table'` | `'custom'` | 展开行模式 |\n| `expandedRowStyle` | `StyleProp<ViewStyle>` | — | 展开区容器样式 |\n| `renderExpandedRow` | `(record, index, columnWidths, subData?) => ReactNode` | — | 自定义展开内容 |\n| `onExpandFetch` | `(record, index) => Promise<D>` | — | 展开时异步获取数据，按行 key 缓存 |\n| `getSubTable` | `(record, index, subData) => SubTableSpec` | — | 将子数据转换为子表规格 |\n| `isExpandedDataEmpty` | `(subData) => boolean` | 内置判空 | 自定义子数据判空 |\n| `renderExpandedLoading` | `(columnWidths) => ReactNode` | 内置 Loading | 自定义加载面板 |\n| `renderExpandedError` | `(error, retry, columnWidths) => ReactNode` | 内置可重试错误面板 | 自定义错误面板 |\n| `renderExpandedEmpty` | `(columnWidths) => ReactNode` | 内置空面板 | 自定义空数据面板 |\n| `subTableSyncScroll` | `boolean` | `true` | 子表与父表横向滚动联动 |\n| `subTableSyncFixedColumns` | `boolean` | `true` | 子表同步父表固定列 |\n| `expandAnimationDuration` | `number` | `200` | 展开/折叠过渡动画时长（ms），传 `0` 关闭动画 |\n| `onRowPress` | `(record, index) => void` | — | 行点击回调（横向拖动不触发）；与展开行共存时先回调再切换展开 |\n| `style` | `StyleProp<ViewStyle>` | — | 最外层容器样式 |\n| `headerStyle` | `StyleProp<ViewStyle>` | — | 表头行样式 |\n| `headerTextStyle` | `StyleProp<TextStyle>` | — | 全局表头文字样式 |\n| `rowStyle` | `StyleProp<ViewStyle>` | — | 数据行样式 |\n| `cellStyle` | `StyleProp<ViewStyle>` | — | 全局单元格基础样式 |\n| `cellTextStyle` | `StyleProp<TextStyle>` | — | 默认单元格文字样式 |\n| `border` | `boolean \\| DataTableBorder` | 横向分隔线 | 边框配置 |\n| `theme` | `Partial<DataTableTheme>` | 内置主题 | 覆盖主题 token |\n\n`T` 是父行数据类型，`D` 是 `onExpandFetch` 返回的子数据类型，默认为 `unknown`。\n\n### `TableColumn<T>`\n\n| 字段 | 类型 | 说明 |\n|---|---|---|\n| `title` | `string` | 默认表头标题 |\n| `dataIndex` | `keyof T \\| string` | 无 `render` 时用于读取单元格值 |\n| `width` | `number` | 固定列宽，跳过内容测量和弹性分配 |\n| `minWidth` | `number` | 自适应列的最小宽度 |\n| `align` | `'left' \\| 'center' \\| 'right'` | 单元格和表头对齐，默认 `left` |\n| `fixed` | `'left' \\| 'right'` | 左/右固定列 |\n| `sorter` | `boolean` | 启用表头排序交互 |\n| `cellStyle` | `StyleProp<ViewStyle>` | 列样式，同时影响表头和数据单元格 |\n| `renderCellStyle` | `(record, index) => StyleProp<ViewStyle>` | 数据单元格动态样式，优先级最高 |\n| `render` | `(record, index) => ReactNode` | 自定义数据单元格 |\n| `renderHeader` | `() => ReactNode` | 自定义表头内容，优先于 `title` |\n| `headerCellStyle` | `StyleProp<ViewStyle>` | 仅表头单元格样式 |\n| `headerTextStyle` | `StyleProp<TextStyle>` | 仅默认表头文字样式 |\n\n样式优先级：\n\n- 数据单元格：内置基础样式 → 全局 `cellStyle` → 列 `cellStyle` → `renderCellStyle`。\n- 表头单元格：内置基础样式 → 全局 `cellStyle` → 列 `cellStyle` → `headerCellStyle`。\n- 表头文字：内置文字样式 → 全局 `headerTextStyle` → 列 `headerTextStyle`。\n\n### `RowSelectionConfig<T>`\n\n| 字段 | 类型 | 默认值 | 说明 |\n|---|---|---|---|\n| `selectedRowKeys` | `string[]` | 必填 | 当前选中 key |\n| `onChange` | `(keys, rows) => void` | 必填 | 按 `data` 顺序返回 key 和行数据 |\n| `getCheckboxProps` | `(record) => { disabled?: boolean }` | — | 按行禁用选择 |\n| `position` | `'first' \\| 'last'` | `'first'` | 独立选择列位置，自动归入对应固定列组 |\n| `renderCheckbox` | `(selected, record) => ReactNode` | 内置 Checkbox | 自定义行选择框内容 |\n| `renderHeaderCheckbox` | `({ checked, indeterminate, disabled }) => ReactNode` | 内置 Checkbox | 自定义全选/半选内容 |\n| `mergeIntoDataIndex` | `string` | — | 将选择框合并进指定 `dataIndex` 列 |\n| `checkboxAlign` | `'top' \\| 'center' \\| 'bottom'` | `'center'` | 合并模式的垂直对齐 |\n\n### `SubColumn<S>` 与 `SubTableSpec<S>`\n\n`SubColumn<S>`：\n\n| 字段 | 类型 | 说明 |\n|---|---|---|\n| `colIndex` | `number` | 对齐父表视觉列顺序的下标 |\n| `colSpan` | `number` | 横跨父列数，默认 `1` |\n| `dataIndex` | `keyof S \\| string` | 无 `render` 时读取子行字段 |\n| `align` | `'left' \\| 'center' \\| 'right'` | 默认继承对应父列 |\n| `cellStyle` | `StyleProp<ViewStyle>` | 子列基础样式 |\n| `renderCellStyle` | `(row, index) => StyleProp<ViewStyle>` | 子单元格动态样式 |\n| `render` | `(row, index) => ReactNode` | 自定义子单元格 |\n\n`SubTableSpec<S>`：\n\n| 字段 | 类型 | 说明 |\n|---|---|---|\n| `rows` | `S[]` | 子表行数据 |\n| `columns` | `SubColumn<S>[]` | 子列配置 |\n| `rowStyle` | `StyleProp<ViewStyle>` | 子表行样式 |\n| `cellStyle` | `StyleProp<ViewStyle>` | 全局子单元格样式 |\n| `cellTextStyle` | `StyleProp<TextStyle>` | 默认子单元格文字样式 |\n\n### `DataTableBorder`\n\n| 字段 | 类型 | 默认值 | 说明 |\n|---|---|---|---|\n| `color` | `string` | `theme.line` | 边框颜色 |\n| `width` | `number` | `StyleSheet.hairlineWidth` | 边框宽度 |\n| `horizontal` | `boolean` | `true` | 行分隔线 |\n| `vertical` | `boolean` | `false` | 列分隔线 |\n| `outer` | `boolean` | `false` | 表格外边框 |\n\n### 其他公开类型\n\n`DataTableHandle`：\n\n| 方法 | 说明 |\n|---|---|\n| `selectAll` | 全选所有未禁用行；已选中的禁用行保持不变 |\n| `clearSelection` | 清空可选行；禁用行的已选状态保留 |\n| `scrollToTop(animated?)` | 纵向滚动回顶部；适用于筛选后数据变短导致滚动偏移越界的场景 |\n| `scrollToIndex(index, animated?)` | 纵向滚动到指定数据行；下标基于当前已上屏数据（测绘扣留中的行不计入） |\n| `scrollToEnd(animated?)` | 纵向滚动到底部 |\n| `scrollToLeft` | 横向滚动归零，表头与所有行同步回到最左侧 |\n\n`SortParams`：\n\n| 字段 | 类型 | 说明 |\n|---|---|---|\n| `dataIndex` | `string` | 排序列的 `dataIndex` |\n| `order` | `'ascend' \\| 'descend' \\| null` | 目标排序方向；`null` 表示取消排序 |\n\n## 公开导出\n\n```ts\nexport { DataTable, DEFAULT_DATA_TABLE_THEME };\nexport type {\n  DataTableBorder,\n  DataTableHandle,\n  DataTableProps,\n  DataTableTheme,\n  RowSelectionConfig,\n  SortParams,\n  SubColumn,\n  SubTableSpec,\n  TableColumn,\n};\n```\n\n## 使用注意事项\n\n- `keyExtractor` 必须返回全局唯一、稳定的字符串，不要使用可变数组下标。\n- 未传 `height` / `maxHeight` 时，父容器必须有明确高度。\n- 排序、行选择均为受控能力，组件不会自动排序 `data` 或持久化选中状态。\n- 自定义 `render`、`renderHeader` 和 Checkbox 的各个状态应尽量保持稳定尺寸，避免列宽抖动。\n- 自适应列会真实挂载内容进行离屏测量；高成本自定义单元格建议设置明确 `width` 或简化测量期渲染。\n- `onEndReached` 在首次测量或原地重测期间会被暂时屏蔽，以避免重复翻页。\n- 子表的 `colIndex` 是父表最终视觉列顺序，不一定等于原始 `columns` 下标。\n- Web 端的固定列依赖 React Native Web 对 CSS `position: sticky` 的支持。\n\n## License\n\nMIT © bestcoder。标准许可证文本已包含在 npm 包的 `LICENSE` 文件中；版本变化参见 [CHANGELOG.md](./CHANGELOG.md)。\n","readmeFilename":"README.md"}