import { ComponentType, CSSProperties, ReactElement, ReactNode, TableHTMLAttributes } from 'react' import { CheckboxValue } from '../Checkbox' import { ComponentSize } from '../ConfigProvider' import { CellRender, CellRowSpan } from './Cell' export type { CellRender as TableColumnRender } from './Cell' export type TablePagination = false | TablePaginationOptions export type TablePaginationAlign = 'center' | 'right' export type TablePaginationOptions = { /** * 对齐方式 * @default 'right' */ align?: TablePaginationAlign /** 当前页 */ currentPage: number /** * 每页有多少 `record` * @default 10 */ pageSize?: number /** * `records` 总数 */ total: number /** * `currentPage` 或者 `pageSize` 发生改变后触发 * @param nextPage 下一页的页码 0 开始 * @param nextPageSize 下一个 pageSize */ onChange?(nextPage: number, nextPageSize: number): void } export type TableSelectionOptions = { /** * 行选择类型 * + `multiple` 多选 * + `single` 单选 * @default 'multiple' */ type?: TableSelectionType /** * 当前选中的 id 数组 */ selectedIds: string[] /** * 选中或者取消选中后触发的回调 * @param ids, 对应 `recordIdAccessor` 拿到的 id */ onChange?: TableSelectionChangeHandler /** * 固定行选择这一列,用法和 Column 的 fixed 相同 */ fixed?: 'left' } export type TableSelectionType = 'single' | 'multiple' export type TableSelectionChangeHandler = (ids: string[]) => void export type TableColumnWidths = { [id in string]: number | string } export type TableProps = { /** * Table 大小 - 不支持 'large' * * @default 'default' */ size?: ComponentSize /** * 列的配置信息 */ columns?: Array> /** * 生成行类名 */ getRowClassName?: (record: R, index: number) => string /** * 自定义单元格类名 */ getCellClassName?: (type: 'header' | 'body') => string /** * 行数据 */ records: R[] /** * `record` 的 id,不得重复 */ recordIdAccessor?: keyof R /** * 行选择 * * 使用此功能 `recordIdAccessor` 必传 * * @default undefined 关闭行选择 */ selection?: TableSelectionOptions // TODO 小号的 table // size?: ComponentSize /** * 分页。`false` 或者 `TablePaginationOptions` * * @default false 关闭分页 */ pagination?: TablePagination /** * @default false */ loading?: boolean /** * 通过 `children` 传入 `` 也可以指定列的配置信息。 * 若指定了 prop `columns`,`children` 会被忽略。 * */ children?: ReactNode /** 会加在 wrap 上 */ className?: string /** 会加在 wrap 上 */ style?: CSSProperties /** * table 元素的 html 属性 * * + 当 `fixHead` 为 `true` 时, 会被传给 thead 和 tbody 的 table */ tableHtmlProps?: TableHTMLAttributes /** 空状态下展示的内容,建议用 Empty 组件 */ empty?: ReactNode /** * 边框配置 * + 'full' - 全边框 * + 'row' - 行与行之间才有边框 * + 'none' - 无边框 * * @default 'row' */ border?: 'row' | 'full' | 'none' /** * 是否有斑马纹 * * 有斑马纹则 icecream 会把 `border` 的任意值都视为 `none` 处理 * * @default false */ zebra?: boolean /** * 是否开启"固定表头" * * + 为 `true` 时,table 会被渲染为 div 元素,thead 和 tbody 被渲染成两个独立的 table * + table-layout 会被设置为 `fixed` */ fixHead?: boolean /** * 配置使用固定列时的表格内容的宽度,需要与 Column 里的 fixed 属性一起使用 * * 如果表格的宽度小于该宽度,则表格可以左右滑动,设置了 fixed 的列会在滑动到边缘时固定住 * * 内部通过 sticky 实现固定效果,不支持 IE11 */ fixColumn?: { contentWidth: string } /** * 行点击事件 */ onRowClick?: (record: R, index: number) => void } export type TableSortOrder = 'desc' | 'asc' | 'none' export type TableColumnFixType = 'left' | 'right' export interface TableColumnSortOptions { /** 排序方式 */ order: TableSortOrder /** 响应排序方式变更的回调函数 */ onChange: (order: TableSortOrder) => void } export type TableColumnSelectFilterValue = CheckboxValue export type TableColumnSelectFilterItem = { text: string value: T } export type TableColumnSelectFilterCallback = (value: T) => void export type TableColumnMultiSelectFilterOptions = { type: 'multi-select' value: T[] /** * 过滤项 */ optionItems: Array> onChange: TableColumnSelectFilterCallback } export type TableColumnSelectFilterOptions = { type: 'select' value: T | null /** * 过滤项 */ optionItems: Array> onChange: TableColumnSelectFilterCallback } // TODO 实现搜索选择过滤器 export type TableColumnFilterOptions = TableColumnSelectFilterOptions | TableColumnMultiSelectFilterOptions export interface TableCommonColumnOptions { /** * `column` 的标识,作用类似 `key` 之于 React list,帮助 `Table` 将状态变更前后的 `column` 项正确地对应上; * 如果 `columns` 列表会动态变化(如某列在特定条件下才会展示),为了避免列(`td`)中的内容丢失局部状态,建议给每个列添加 `id` 信息 * 如果有 `accessor`,则取其为 id。 */ id?: string title: ReactNode /** * 列宽度 * + 如果是 px 单位,则是 content box 宽度,如果是百分比则是 border box 宽度 * * @default 'auto' */ width?: string /** 对排序行为的配置 */ sort?: TableColumnSortOptions filter?: TableColumnFilterOptions /** 固定列,left 表示表格左侧的固定列,right 表示右侧 */ fixed?: TableColumnFixType } export interface TableColumnOptionsWithAccessor extends TableCommonColumnOptions { /** * `record` 的 key,如果有此项则可以不填 id */ accessor: K /** * 跨列数,用于行合并 */ getRowSpan?: CellRowSpan render?: CellRender } export interface TableColumnOptionsWithoutAccessor extends TableCommonColumnOptions { /** * 跨列数,用于行合并 */ getRowSpan?: CellRowSpan render?: CellRender } // 对外接口上的 column options 类型 export type TableColumnOptions = ( K extends keyof R ? TableColumnOptionsWithAccessor : TableColumnOptionsWithoutAccessor ) /** * 内部使用的 column options 类型,在 R 不明确时更准确 * `InternalColumnOptions` vs `ColumnOptions`: * - 在 R 明确时,`ColumnOptions` 可以提供更好的类型提示、补全 * - 在 R 不明确时,`ColumnOptions` 不能正确地分解为 `WithAccessor` | `WithoutAccessor`,此时 `InternalColumnOptions` 可以提供更准确的信息 * 类型为 `ColumnOptions` 的值可以赋值给类型为 `InternalColumnOptions` 的变量 */ export type TableInternalColumnOptions = ( TableColumnOptionsWithAccessor | TableColumnOptionsWithoutAccessor ) interface WithColumn { // eslint-disable-next-line @typescript-eslint/naming-convention Column(props: TableColumnOptionsWithAccessor): ReactElement | null // eslint-disable-next-line @typescript-eslint/naming-convention Column(props: TableColumnOptionsWithoutAccessor): ReactElement | null } /** * 用于方便地去定义含自定义 `Record` 类型的 `Table` / `TableColumn` 组件,使用者姿势: * ```ts * const MyTable: TableType = Table * const MyTableColumn: TableColumnType = TableColumn * ``` * 在后续使用中 `MyTable` 等价于 `Table`,`MyTableColumn` 等价于 `TableColumn` */ export type TableType = ComponentType> & WithColumn export type TableColumnType = WithColumn['Column'] /* column */