diff --git a/config/hooks.ts b/config/hooks.ts index fa74274cf2..34e6b09e97 100644 --- a/config/hooks.ts +++ b/config/hooks.ts @@ -19,6 +19,7 @@ export const menus = [ title: 'Scene', children: [ 'useAntdTable', + 'useAntdTableSelection', 'useFusionTable', 'useInfiniteScroll', 'usePagination', diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 58cefd9c79..6bcc080c52 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -75,6 +75,7 @@ import useVirtualList from './useVirtualList'; import useWebSocket from './useWebSocket'; import useWhyDidYouUpdate from './useWhyDidYouUpdate'; import useMutationObserver from './useMutationObserver'; +import useAntdTableSelection from './useAntdTableSelection'; export { useRequest, @@ -156,4 +157,5 @@ export { useRafTimeout, useResetState, useMutationObserver, + useAntdTableSelection, }; diff --git a/packages/hooks/src/useAntdTableSelection/__tests__/index.test.ts b/packages/hooks/src/useAntdTableSelection/__tests__/index.test.ts new file mode 100644 index 0000000000..d477d5774c --- /dev/null +++ b/packages/hooks/src/useAntdTableSelection/__tests__/index.test.ts @@ -0,0 +1,316 @@ +import { act, renderHook, waitFor } from '@testing-library/react'; +import useAntdTableSelection from '../index'; + +const dataSource = [{ id: 0 }, { id: 1 }, { id: 2 }]; + +const setUp = (list, config?: Record) => + renderHook(() => useAntdTableSelection(list, config)); + +let hook: any; + +describe('useAntdTableSelection type default is checkbox', () => { + it('should dataSource is undefined work', async () => { + act(() => { + hook = setUp(undefined, { rowKey: 'id' }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + await waitFor(() => expect(hook.result.current.state.selectedRows).toEqual([])); + }); + + it('should config is undefined work', async () => { + act(() => { + hook = setUp(dataSource); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(dataSource.length).toBe(3)); + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + }); + + it('should config.rowKey is undefined work', async () => { + act(() => { + hook = setUp(dataSource, {}); + }); + + const { state, action } = hook.result.current; + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(state.selectedRowKeys).toEqual([undefined, undefined, undefined])); + await waitFor(() => expect(state.allSelected).toBe(false)); + + act(() => { + action.toggleAll(); + }); + + await waitFor(() => expect(state.allSelected).toBe(false)); + await waitFor(() => expect(state.selectedRowKeys).toEqual([])); + }); + + it('should config.rowKey is undefined but dataSource has key work', async () => { + act(() => { + hook = setUp(dataSource.map((t, idx) => ({ ...t, key: idx + '__key__' }))); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => + expect(hook.result.current.state.selectedRowKeys).toEqual([ + '0__key__', + '1__key__', + '2__key__', + ]), + ); + + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(true)); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(false)); + }); + + it('should config.rowKey is function work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: (row) => row.id, + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 1, 2])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(true)); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(false)); + }); + + it('should config.rowKey is function and args[1] is index(in table dataSource) case1 work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: (row, idx) => row.id + idx, + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 2, 4])); + }); + + it('should config.rowKey is function and args[1] is index(in table dataSource) case2 work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: (row, idx) => `${row.id}_${idx + 1}`, + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => + expect(hook.result.current.state.selectedRowKeys).toEqual(['0_1', '1_2', '2_3']), + ); + }); + + it('should config.rowKey is function and args[1] is index(in table dataSource), than disabled is function, work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: (row, idx) => row.id + idx, + disabled: (row) => row.id === 2, + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 2])); + }); + + it('should config.rowKey is string work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: 'id', + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 1, 2])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(true)); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(false)); + }); + + it('should config.disabled is true', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: 'id', + disabled: true, + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(false)); + + act(() => { + hook.result.current.action.setSelected([0, 1, 2]); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(false)); + }); + + it('should config.disabled is true but has config.getCheckboxProps return disabled false', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: 'id', + disabled: true, + getCheckboxProps: () => ({ disabled: false }), + }); + }); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 1, 2])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(true)); + + act(() => { + hook.result.current.action.setSelected([0, 1]); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 1])); + await waitFor(() => expect(hook.result.current.state.allSelected).toBe(false)); + }); + + it('should toogle work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: 'id', + }); + }); + + act(() => { + hook.result.current.action.toggle(dataSource[0]); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0])); + }); + + it('should select/toggle data other than list work', async () => { + act(() => { + hook = setUp(dataSource, { + rowKey: 'id', + }); + }); + + act(() => { + hook.result.current.action.toggle({ id: 4 }); + hook.result.current.action.toggle({ id: 5 }); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + + act(() => { + hook.result.current.action.select({ id: 4 }); + hook.result.current.action.select({ id: 5 }); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + }); + + it('should setSelected work', async () => { + act(() => { + hook = setUp(dataSource, { rowKey: 'id' }); + }); + + act(() => { + hook.result.current.action.setSelected(dataSource.map((t) => t.id)); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0, 1, 2])); + + act(() => { + hook.result.current.action.unSelect(dataSource[0]); + hook.result.current.action.unSelect(dataSource[1]); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([2])); + + act(() => { + hook.result.current.action.unSelectAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + }); +}); + +describe('useAntdTableSelection type is radio', () => { + it('should config.type is radio then call action.setSelected/action.toggleAll/action.selectAll/ work', async () => { + act(() => { + hook = setUp(dataSource, { rowKey: 'id', type: 'radio' }); + }); + + act(() => { + hook.result.current.action.setSelected(dataSource.map((t) => t.id)); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0])); + + act(() => { + hook.result.current.action.toggleAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0])); + + act(() => { + hook.result.current.action.selectAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([0])); + await waitFor(() => expect(hook.result.current.action.isSelected(dataSource[0])).toBe(true)); + + act(() => { + hook.result.current.action.unSelectAll(); + }); + + await waitFor(() => expect(hook.result.current.state.selectedRowKeys).toEqual([])); + }); +}); diff --git a/packages/hooks/src/useAntdTableSelection/demo/table.tsx b/packages/hooks/src/useAntdTableSelection/demo/table.tsx new file mode 100644 index 0000000000..5c9e85eb04 --- /dev/null +++ b/packages/hooks/src/useAntdTableSelection/demo/table.tsx @@ -0,0 +1,90 @@ +import { Button, Space, Table } from 'antd'; +import React from 'react'; +import { useAntdTable, useAntdTableSelection } from 'ahooks'; +import ReactJson from 'react-json-view'; + +interface Item { + name: { + last: string; + }; + email: string; + phone: string; + gender: 'male' | 'female'; + id: { + name: string; + value: string; + }; +} + +interface Result { + total: number; + list: Item[]; +} + +const getTableData = ({ current, pageSize }): Promise => { + const query = `page=${current}&size=${pageSize}`; + + return fetch(`https://randomuser.me/api?results=10&${query}`) + .then((res) => res.json()) + .then((res) => ({ + total: res.info.results, + list: res.results, + })); +}; + +export default () => { + const { tableProps } = useAntdTable(getTableData); + + const { state, action, rowSelection } = useAntdTableSelection(tableProps.dataSource, { + rowKey: 'email', + disabled: (row) => row.gender === 'male', + // getCheckboxProps: (row) => ({ disabled: row.gender === 'female' }), + }); + + const columns = [ + { + title: 'name', + dataIndex: ['name', 'last'], + }, + { + title: 'email', + dataIndex: 'email', + }, + { + title: 'phone', + dataIndex: 'phone', + }, + { + title: 'gender', + dataIndex: 'gender', + }, + ]; + + return ( + <> + + + + + + + + + + + +
+

Current selectedRows:

+ +

Current selectedRowKeys:

+ +
+ + ); +}; diff --git a/packages/hooks/src/useAntdTableSelection/index.en-US.md b/packages/hooks/src/useAntdTableSelection/index.en-US.md new file mode 100644 index 0000000000..b353c3fc41 --- /dev/null +++ b/packages/hooks/src/useAntdTableSelection/index.en-US.md @@ -0,0 +1,101 @@ +--- +nav: + path: /hooks +--- + +# useAntdTableSelection + +useAntdTableSelection is used to manage the selectable related status of Ant Design Table component, providing built-in common functionalities like select all, select single, toggle。 + +## Antd Table Selection management + +`useAntdTableSelection` automatically manages the selection data for the `Table` component, you just need to pass the returned `rowSelection` to the `Table` component. + +## Examples + +```tsx | pure +const { tableProps, search } = useAntdTable(getTableData, { + form, +}); + +const { state, action, rowSelection } = useAntdTableSelection(tableProps.dataSource, { + rowKey: (row) => row.id, + disabled: (row) => row.name === 'foo', + /** + * For more details, refer to the interface type + * descriptions, all are the same as Ant Design. + * https://ant-design.antgroup.com/components/table-cn#rowselection + */ +}); + +return ( +
row.id} + /> +) +``` + +
+ + + +### API + +#### Result + +`useAntdTableSelection` return overview + +```tsx | pure + +interface TableSelectionResult { + state: { + allSelected: boolean; + selectedRows: RecordType[]; + selectedRowKeys: React.Key[]; + }; + action: { + select: (item: RecordType) => void; + toggle: (item: RecordType) => void; + unSelect: (item: RecordType) => void; + toggleAll: () => void; + selectAll: () => void; + isSelected: (item: RecordType) => boolean; + unSelectAll: () => void; + setSelected: (keys: React.Key[]) => void; + }; + rowSelection: Omit, 'rowKey' | 'disabled'>; +} + +``` + +| Return Value | Description | Type | +| --------------------- | --------------------------------------------------------------------------- | ------------------------------- | +| rowSelection | `rowSelection` property needed by the `Table` component, pass it to `Table` | `TableRowSelection` | +| state.allSelected | Whether all items are selected | `boolean` | +| state.selectedRows | Rows that are selected | `RecordType[]` | +| state.selectedRowKeys | Row keys that are selected | `React.Key[]` | +| action.select | Select a single row | `(item: RecordType) => void` | +| action.toggle | Toggle a single row | `(item: RecordType) => void` | +| action.toggleAll | Toggle all rows | `() => void` | +| action.unSelect | Deselect a single row | `(item: RecordType) => void` | +| action.selectAll | Select all rows | `() => void` | +| action.unSelectAll | Deselect all rows | `() => void` | +| action.setSelected | Select a specific set of rows | `(keys: React.Key[]) => void` | +| action.isSelected | Check if a specific row is selected | `(item: RecordType) => boolean` | + +#### Options + +| Parameter | Description | Type | Default Value | +| --------- | -------------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------ | +| rows | Data source for the Table `dataSource` | `RecordType[]` | [] | +| config | All parameters supported by Table `rowSelection` and additional `rowKey` and `disabled` properties | `TableRowSelection` | {type:"checkbox", rowKey:"key", disabled: false} | + +- Detailed Explanation + > 1. The first parameter `rows` represents the data source for the Table `dataSource`. + > 2. The second parameter `config` includes all the fields accepted by the `rowSelection` property of the Table component. + > 1. Additional `config.disabled` property can be either `boolean` or `(row: RecordType) => boolean`. + > 2. **Additional `config.rowKey` can be `React.Key` or `(row: RecordType, index:number) => React.Key`, and it must be consistent with the `rowKey` used in the `Table` component.** + > 3. `config.getCheckboxProps` can return disabled property for the selection box, with higher priority than `config.disabled`. diff --git a/packages/hooks/src/useAntdTableSelection/index.tsx b/packages/hooks/src/useAntdTableSelection/index.tsx new file mode 100644 index 0000000000..5f069457ad --- /dev/null +++ b/packages/hooks/src/useAntdTableSelection/index.tsx @@ -0,0 +1,213 @@ +import React, { useMemo, useState } from 'react'; +import useMemoizedFn from '../useMemoizedFn'; +import type { GetRowKey, AntdTableRowSelection, AntdTableSelectionResult } from './types'; +import isDev from '../utils/isDev'; +import { isUndef } from '../utils'; + +function useAntdTableSelection( + rows: RecordType[] = [], + config?: Partial>, +): AntdTableSelectionResult { + if (isDev) { + if (isUndef(config?.rowKey)) { + console.error( + `useAntdTableSelection expected config.rowKey is a function|string|number, got undefined. + Will default to using "key" as rowKey. + The value must be the same as the rowKey of the Antd Table component`, + ); + } + } + + const { + rowKey = 'key', + disabled = false, + type = 'checkbox', + defaultSelectedRowKeys = [], + ...rest + } = config || {}; + + const getRowKey = React.useMemo>(() => { + if (typeof rowKey === 'function') { + return rowKey; + } + + return (record: RecordType) => (record as any)?.[rowKey]; + }, [rowKey]); + + const allRowKeys = useMemo(() => rows.map((t, idx) => getRowKey(t, idx)), [rows]); + + const rowKeyMapRow = React.useMemo( + () => + rows.reduce>((prev, cur, idx) => { + prev[getRowKey(cur, idx)] = cur; + return prev; + }, {}), + [rows], + ); + + // ========================= States ========================= + const [selectedRows, setSelectedRows] = useState( + defaultSelectedRowKeys.map((key) => rowKeyMapRow[key]).filter((t) => !isUndef(t)), + ); + const [selectedRowKeys, setSelectedRowKeys] = useState(defaultSelectedRowKeys); + + const getDisabled = React.useMemo(() => { + if (typeof disabled === 'function') { + return (row: RecordType) => disabled(row); + } + if (typeof disabled === 'boolean') { + return () => disabled; + } + return () => false; + }, [disabled]); + + const getCheckboxProps = useMemoizedFn((row: RecordType) => { + const checkboxProps = + typeof rest?.getCheckboxProps === 'function' ? rest.getCheckboxProps?.(row) : {}; + + return Object.assign({ disabled: getDisabled(row) }, checkboxProps); + }); + + const isValidRow = useMemoizedFn( + (row: RecordType, idx?: number) => + !getCheckboxProps(row).disabled && allRowKeys.includes(getRowKey(row, idx)), + ); + + // ========================= Funcs ========================= + const onSelectionChange: AntdTableRowSelection['onChange'] = useMemoizedFn( + (rowKeys, records, info) => { + setSelectedRows(records); + setSelectedRowKeys(rowKeys); + rest?.onChange?.(rowKeys, records, info); + }, + ); + + const onRowsChange = useMemoizedFn((records: RecordType[]) => { + /** based action change state, must have rowKey and row is't disabled. + * because of this, the config.rowKey is must + */ + const willSelected = records.reduce<{ + selectedRow: RecordType[]; + selectedRowKeys: React.Key[]; + }>( + (prev, cur, idx) => { + const isValid = isValidRow(cur, idx); + if (isValid) { + prev.selectedRow.push(cur); + prev.selectedRowKeys.push(getRowKey(cur, idx)); + } + return prev; + }, + { selectedRow: [], selectedRowKeys: [] }, + ); + + setSelectedRows(willSelected.selectedRow); + setSelectedRowKeys(willSelected.selectedRowKeys); + }); + + // ========================= Select Memo States ========================= + const selectedSet = useMemo(() => new Set(selectedRows), [selectedRows]); + + const noneSelected = useMemo(() => rows.every((o) => !selectedSet.has(o)), [rows, selectedSet]); + + const allSelected = useMemo( + () => + rows.filter((t) => !getCheckboxProps(t).disabled).length === selectedRows.length && + !noneSelected, + [rows, selectedRows.length, noneSelected], + ); + + // ========================= Select Action ========================= + const isSelected = useMemoizedFn((item: RecordType) => selectedSet.has(item)); + + const select = useMemoizedFn((item: RecordType, idx?: number) => { + if (isValidRow(item, idx)) { + selectedSet.add(item); + onRowsChange(Array.from(selectedSet)); + } + }); + + const unSelect = useMemoizedFn((item: RecordType) => { + selectedSet.delete(item); + onRowsChange(Array.from(selectedSet)); + }); + + const selectAll = useMemoizedFn(() => { + selectedSet.clear(); + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if (isValidRow(row, i)) { + selectedSet.add(row); + if (type === 'radio') break; + } + } + + onRowsChange(Array.from(selectedSet)); + }); + + const unSelectAll = useMemoizedFn(() => { + selectedSet.clear(); + onRowsChange(Array.from(selectedSet)); + }); + + const toggle = useMemoizedFn((item: RecordType, idx?: number) => { + if (isSelected(item)) { + unSelect(item); + } else { + select(item, idx); + } + }); + + const toggleAll = useMemoizedFn(() => (allSelected ? unSelectAll() : selectAll())); + + const setSelected = useMemoizedFn((rowKeys: React.Key[]) => { + selectedSet.clear(); + + const willRowKeys: React.Key[] = []; + let key: any = null; + let row: any = null; + + for (let i = 0; i < rowKeys.length; i++) { + key = rowKeys[i]; + row = rowKeyMapRow[key]; + if (isValidRow(row, i)) { + selectedSet.add(rowKeyMapRow[key]); + willRowKeys.push(key); + /* if type is radio, should be used the first */ + if (type === 'radio') break; + } + } + + setSelectedRows(Array.from(selectedSet)); + setSelectedRowKeys(willRowKeys); + }); + + return { + state: { + allSelected, + selectedRows, + selectedRowKeys, + }, + action: { + select, + toggle, + unSelect, + toggleAll, + selectAll, + isSelected, + unSelectAll, + setSelected, + }, + rowSelection: { + ...rest, + type, + onChange: onSelectionChange, + getCheckboxProps, + selectedRowKeys, + defaultSelectedRowKeys, + }, + }; +} + +export default useAntdTableSelection; diff --git a/packages/hooks/src/useAntdTableSelection/index.zh-CN.md b/packages/hooks/src/useAntdTableSelection/index.zh-CN.md new file mode 100644 index 0000000000..e0127071f7 --- /dev/null +++ b/packages/hooks/src/useAntdTableSelection/index.zh-CN.md @@ -0,0 +1,102 @@ +--- +nav: + title: Hooks + path: /hooks +--- + +# useAntdTableSelection + +`useAntdTableSelection` 用于管理 Antd Table 组件的可选择相关状态,内置了常用的全选、单选、toogle 等。 + +## Antd Table Selection 管理 + +`useAntdTableSelection` 会自动管理 `Table` 选择项数据,你只需要把返回的 `rowSelection` 传递给 `Table` 组件就可以了。 + +## 代码演示 + +```tsx | pure +const { tableProps, search } = useAntdTable(getTableData, { + form, +}); + +const { state, action, rowSelection } = useAntdTableSelection(tableProps.dataSource, { + rowKey: (row) => row.id, + disabled: (row) => row.name === 'foo', + /** 更多详见接口类型描述,均同 Antd + * https://ant-design.antgroup.com/components/table-cn#rowselection + * */ +}); + + +return ( +
row.id} + /> +) + +``` + +
+ + + +## API + +### Result + +`useAntdTableSelection` 返回值概览 + +```tsx | pure + +interface TableSelectionResult { + state: { + allSelected: boolean; + selectedRows: RecordType[]; + selectedRowKeys: React.Key[]; + }; + action: { + select: (item: RecordType) => void; + toggle: (item: RecordType) => void; + unSelect: (item: RecordType) => void; + toggleAll: () => void; + selectAll: () => void; + isSelected: (item: RecordType) => boolean; + unSelectAll: () => void; + setSelected: (keys: React.Key[]) => void; + }; + rowSelection: Omit, 'rowKey' | 'disabled'>; +} + +``` + +| 返回值 | 说明 | 类型 | +| --------------------- | ----------------------------------------------------------------- | ------------------------------- | +| rowSelection | `Table` 组件需要的`rowSelection`属性,直接透传给 `Table` 组件即可 | `TableRowSelection` | +| state.allSelected | 是否全选 | `boolean` | +| state.selectedRows | 已经选中的 row | `RecordType[]` | +| state.selectedRowKeys | 已经选中的 rowKey | `React.Key[]` | +| action.select | 选中单个 | `(item: RecordType) => void` | +| action.toggle | toggle 单个 | `(item: RecordType) => void` | +| action.toggleAll | toggle 全部 | `() => void` | +| action.unSelect | 取消选中单个 | `(item: RecordType) => void` | +| action.selectAll | 选中 全部 | `() => void` | +| action.unSelectAll | 取消选中全部 | `() => void` | +| action.setSelected | 选中特定一批 | `(keys: React.Key[]) => void` | +| action.isSelected | 查询特定单个是否被选中 | `(item: RecordType) => boolean` | + +### Options + +| 参数 | 说明 | 类型 | 默认值 | +| ------ | ---------------------------------------------------------------- | ------------------------------- | -------------------------------------------------- | +| rows | Table 的数据源 `dataSource` | `RecordType` | [] | +| config | Table rowSelection 支持的所有参数以及拓展的 `rowKey`和`disabled` | `TableRowSelection` | {type:"checkbox", rowKey: "key", disabled: false } | + +- 详细说明 + > 1. 第一个参数 `rows` 为 Table 的数据源 `dataSource`。 + > 2. 第二个参数`config` 为 Table 所能接受的 `rowSelections`属性的所有字段,以及。 + > 1. 额外接受 `config.disabled` 属性可以是 `boolean` | `(row:RecordType) => boolean`。 + > 2. **额外接受 `config.rowKey` 可以是 `React.Key` | `(row:RecordType, index:number) => React.Key`,这项必须和`Table`组件中使用的`rowKey`保持一致。** + > 3. `config.gerCheckboxProps` 同样可以返回选择框的`disabled`属性,此项优先级高于`config.disabled` diff --git a/packages/hooks/src/useAntdTableSelection/types.ts b/packages/hooks/src/useAntdTableSelection/types.ts new file mode 100644 index 0000000000..f83a13dfd8 --- /dev/null +++ b/packages/hooks/src/useAntdTableSelection/types.ts @@ -0,0 +1,39 @@ +import type React from 'react'; + +export type RowSelectionType = 'checkbox' | 'radio'; +export type RowSelectMethod = 'all' | 'none' | 'invert' | 'single' | 'multiple'; +export type GetRowKey = (record: RecordType, idx?: number) => React.Key; + +export interface AntdTableRowSelection { + type: RowSelectionType; + selectedRowKeys: React.Key[]; + defaultSelectedRowKeys: React.Key[]; + getCheckboxProps: (row: RecordType) => Partial<{ disabled: boolean }>; + onChange: ( + selectedRowKeys: React.Key[], + selectedRows: RecordType[], + info: { type: RowSelectMethod }, + ) => void; + rowKey: string | keyof RecordType | GetRowKey; + disabled: boolean | ((row: RecordType) => boolean); + [key: string]: any; +} + +export interface AntdTableSelectionResult { + state: { + allSelected: boolean; + selectedRows: RecordType[]; + selectedRowKeys: React.Key[]; + }; + action: { + select: (item: RecordType, idx?: number) => void; + toggle: (item: RecordType, idx?: number) => void; + unSelect: (item: RecordType) => void; + toggleAll: () => void; + selectAll: () => void; + isSelected: (item: RecordType) => boolean; + unSelectAll: () => void; + setSelected: (keys: React.Key[]) => void; + }; + rowSelection: Omit, 'rowKey' | 'disabled'>; +}