@rainbow-oh/yee-c 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/cjs/Anchor/anchor-item.js +10 -2
  2. package/dist/cjs/Anchor/interface.d.ts +1 -1
  3. package/dist/cjs/Dialog/dialog.js +16 -2
  4. package/dist/cjs/Dialog/interface.d.ts +1 -1
  5. package/dist/cjs/Input/style/index.less +2 -0
  6. package/dist/cjs/Table/demo/components-override.d.ts +3 -0
  7. package/dist/cjs/Table/demo/components-override.js +54 -0
  8. package/dist/cjs/Table/demo/grouping.d.ts +3 -0
  9. package/dist/cjs/Table/demo/grouping.js +129 -0
  10. package/dist/cjs/Table/hooks/useColumns.d.ts +2 -2
  11. package/dist/cjs/Table/hooks/useColumns.js +15 -37
  12. package/dist/cjs/Table/index.d.ts +1 -1
  13. package/dist/cjs/Table/interface.d.ts +59 -8
  14. package/dist/cjs/Table/style/index.less +19 -1
  15. package/dist/cjs/Table/table.js +5 -7
  16. package/dist/cjs/Table/tbody/cell.d.ts +0 -1
  17. package/dist/cjs/Table/tbody/cell.js +0 -4
  18. package/dist/cjs/Table/tbody/index.js +19 -2
  19. package/dist/cjs/Table/tbody/row.js +15 -11
  20. package/dist/cjs/Table/theader/cell.js +7 -1
  21. package/dist/cjs/Table/theader/index.d.ts +5 -5
  22. package/dist/cjs/Table/theader/index.js +41 -27
  23. package/dist/cjs/Table/util/header.d.ts +23 -0
  24. package/dist/cjs/Table/util/header.js +109 -0
  25. package/dist/cjs/TextArea/style/index.less +1 -0
  26. package/dist/cjs/style/size.css +1 -0
  27. package/dist/cjs/style/themes.css +1 -1
  28. package/dist/cjs/style/variables.css +2 -1
  29. package/dist/cjs/version.d.ts +1 -1
  30. package/dist/cjs/version.js +1 -1
  31. package/dist/esm/Anchor/anchor-item.js +4 -3
  32. package/dist/esm/Anchor/interface.d.ts +1 -1
  33. package/dist/esm/Dialog/dialog.js +4 -2
  34. package/dist/esm/Dialog/interface.d.ts +1 -1
  35. package/dist/esm/Input/style/index.less +2 -0
  36. package/dist/esm/Table/demo/components-override.d.ts +3 -0
  37. package/dist/esm/Table/demo/components-override.js +86 -0
  38. package/dist/esm/Table/demo/grouping.d.ts +3 -0
  39. package/dist/esm/Table/demo/grouping.js +102 -0
  40. package/dist/esm/Table/hooks/useColumns.d.ts +2 -2
  41. package/dist/esm/Table/hooks/useColumns.js +24 -50
  42. package/dist/esm/Table/index.d.ts +1 -1
  43. package/dist/esm/Table/interface.d.ts +59 -8
  44. package/dist/esm/Table/style/index.less +19 -1
  45. package/dist/esm/Table/table.js +5 -7
  46. package/dist/esm/Table/tbody/cell.d.ts +0 -1
  47. package/dist/esm/Table/tbody/cell.js +0 -5
  48. package/dist/esm/Table/tbody/index.js +21 -2
  49. package/dist/esm/Table/tbody/row.js +19 -15
  50. package/dist/esm/Table/theader/cell.js +6 -2
  51. package/dist/esm/Table/theader/index.d.ts +5 -5
  52. package/dist/esm/Table/theader/index.js +48 -35
  53. package/dist/esm/Table/util/header.d.ts +23 -0
  54. package/dist/esm/Table/util/header.js +107 -0
  55. package/dist/esm/TextArea/style/index.less +1 -0
  56. package/dist/esm/style/size.css +1 -0
  57. package/dist/esm/style/themes.css +1 -1
  58. package/dist/esm/style/variables.css +2 -1
  59. package/dist/esm/version.d.ts +1 -1
  60. package/dist/esm/version.js +1 -1
  61. package/dist/umd/yee-c.min.css +2 -2
  62. package/dist/umd/yee-c.min.js +1 -1
  63. package/package.json +1 -1
  64. package/src/Anchor/anchor-item.tsx +7 -3
  65. package/src/Anchor/interface.ts +1 -1
  66. package/src/Dialog/dialog.tsx +10 -2
  67. package/src/Dialog/interface.ts +1 -1
  68. package/src/Input/style/index.less +2 -0
  69. package/src/Table/demo/components-override.tsx +49 -0
  70. package/src/Table/demo/grouping.tsx +104 -0
  71. package/src/Table/hooks/useColumns.ts +29 -46
  72. package/src/Table/index.en-US.md +31 -3
  73. package/src/Table/index.ts +4 -0
  74. package/src/Table/index.zh-CN.md +30 -2
  75. package/src/Table/interface.ts +66 -8
  76. package/src/Table/style/index.less +19 -1
  77. package/src/Table/table.tsx +5 -7
  78. package/src/Table/tbody/cell.tsx +0 -6
  79. package/src/Table/tbody/index.tsx +21 -2
  80. package/src/Table/tbody/row.tsx +25 -14
  81. package/src/Table/theader/cell.tsx +4 -0
  82. package/src/Table/theader/index.tsx +61 -42
  83. package/src/Table/util/header.ts +111 -0
  84. package/src/TextArea/style/index.less +1 -0
  85. package/src/style/size.css +1 -0
  86. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-oh/yee-c",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "yee basic components",
5
5
  "keywords": [
6
6
  "react",
@@ -44,10 +44,14 @@ const AnchorItem: React.FC<AnchorItemProps> = (props) => {
44
44
  paddingLeft: `${level * INDENT_WIDTH}px`,
45
45
  };
46
46
 
47
- const renderItem = (
47
+ const node = (
48
48
  <li className={cls} style={itemStyle} {...rest}>
49
49
  <a href={`#${targetKey}`} onClick={handleClick}>
50
- <span className={`${prefixCls}-item-label`} title={String(title)}>
50
+ <span
51
+ className={clsx(`${prefixCls}-item-label`, classNames?.label)}
52
+ style={styles?.label}
53
+ title={String(title)}
54
+ >
51
55
  {title}
52
56
  </span>
53
57
  </a>
@@ -56,7 +60,7 @@ const AnchorItem: React.FC<AnchorItemProps> = (props) => {
56
60
 
57
61
  return (
58
62
  <>
59
- {renderItem}
63
+ {node}
60
64
  {children}
61
65
  </>
62
66
  );
@@ -46,7 +46,7 @@ export interface AnchorItemProps {
46
46
  children?: React.ReactNode;
47
47
  }
48
48
 
49
- export type AnchorSemanticDOM = 'item' | 'active' | 'content';
49
+ export type AnchorSemanticDOM = 'item' | 'active' | 'content' | 'label';
50
50
 
51
51
  export interface AnchorProps extends DataAttributeProps {
52
52
  /**
@@ -171,11 +171,19 @@ const Dialog = (baseprops: DialogProps) => {
171
171
  ></Button>
172
172
  ) : null}
173
173
  {title ? (
174
- <div className={`${prefixCls}-header`}>
174
+ <div
175
+ className={clsx(`${prefixCls}-header`, classNames?.header)}
176
+ style={styles?.header}
177
+ >
175
178
  <div className={`${prefixCls}-title`}>{title}</div>
176
179
  </div>
177
180
  ) : null}
178
- <div className={`${prefixCls}-body`}>{children}</div>
181
+ <div
182
+ className={clsx(`${prefixCls}-body`, classNames?.body)}
183
+ style={styles?.body}
184
+ >
185
+ {children}
186
+ </div>
179
187
  {renderFooter()}
180
188
  </div>
181
189
  </div>
@@ -1,7 +1,7 @@
1
1
  import { ButtonType } from '../Button';
2
2
  import type { DataAttributeProps } from '../utils/types';
3
3
 
4
- export type SemanticDOM = 'content' | 'footer' | 'mask';
4
+ export type SemanticDOM = 'content' | 'header' | 'body' | 'footer' | 'mask';
5
5
 
6
6
  export interface DialogProps extends DataAttributeProps {
7
7
  /**
@@ -11,6 +11,7 @@
11
11
  line-height: var(--yee-input-line-height);
12
12
  border: var(--yee-input-border-width) solid var(--yee-input-border-color);
13
13
  border-radius: var(--yee-input-border-radius, 4px);
14
+ font-family: var(--yee-font-family);
14
15
 
15
16
  &:not(@{pls}-disabled):hover {
16
17
  border-color: var(--yee-input-hover-border-color);
@@ -46,6 +47,7 @@
46
47
 
47
48
  &-inner {
48
49
  width: 100%;
50
+ font-family: var(--yee-font-family);
49
51
  line-height: var(--yee-input-line-height);
50
52
  background-color: inherit;
51
53
  border: none;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 自定义表格元素(可被外部接管)
3
+ *
4
+ * Table 暴露两个接缝供外部库(如 dnd-kit)接管行/体渲染:
5
+ * - components.body.tbody —— 替换 <tbody>,外部可在此包 SortableContext 等 Provider;
6
+ * - components.body.row —— 整行接管,消费方自行渲染 <tr> + 单元格,可在任意单元格里放拖拽手柄。
7
+ *
8
+ * Table 本身不依赖任何拖拽库;本 demo 不引入 dnd,仅证明替换点生效。
9
+ */
10
+ import { Table } from '@rainbow-oh/yee-c';
11
+ import type { TableComponents, TableRowRendererProps } from '@rainbow-oh/yee-c';
12
+ import React from 'react';
13
+
14
+ // 替换 <tbody>:保持渲染 <tbody>,外部库可在此包 SortableContext。
15
+ const CustomTbody = (props: { className?: string; children?: React.ReactNode }) => (
16
+ <tbody className={props.className} data-custom-tbody>
17
+ {props.children}
18
+ </tbody>
19
+ );
20
+
21
+ // 整行接管:消费方渲染整 <tr> + 单元格,可在此放拖拽手柄等任意内容。
22
+ const CustomRow = ({ record, index, columns, rowKey }: TableRowRendererProps) => (
23
+ <tr data-row-key={rowKey} style={{ background: index % 2 === 0 ? '#f8fafc' : undefined }}>
24
+ <td style={{ width: 40, textAlign: 'center', color: '#2563eb', fontWeight: 700 }}>{index + 1}</td>
25
+ {columns.map((col) => (
26
+ <td key={String(col.key)}>{record[col.dataIndex || '']}</td>
27
+ ))}
28
+ </tr>
29
+ );
30
+
31
+ export default () => {
32
+ const columns = [
33
+ { title: 'Name', dataIndex: 'name', key: 'name' },
34
+ { title: 'Age', dataIndex: 'age', key: 'age' },
35
+ { title: 'Address', dataIndex: 'address', key: 'address' },
36
+ ];
37
+
38
+ const dataSource = [
39
+ { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park' },
40
+ { key: '2', name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park' },
41
+ { key: '3', name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park' },
42
+ ];
43
+
44
+ const components: TableComponents = {
45
+ body: { tbody: CustomTbody, row: CustomRow },
46
+ };
47
+
48
+ return <Table columns={columns} dataSource={dataSource} components={components} />;
49
+ };
@@ -0,0 +1,104 @@
1
+ import type { ColumnProps, RowSelectionType } from '@rainbow-oh/yee-c';
2
+ import { Table } from '@rainbow-oh/yee-c';
3
+ import React, { useState } from 'react';
4
+
5
+ export default () => {
6
+ const [selectedRowKeys, setSelectedRowKeys] = useState<
7
+ Array<string | number>
8
+ >([]);
9
+
10
+ const columns: ColumnProps[] = [
11
+ {
12
+ title: 'Name',
13
+ dataIndex: 'name',
14
+ key: 'name',
15
+ fixed: 'left',
16
+ width: 120,
17
+ sorter: true,
18
+ },
19
+ {
20
+ title: 'Info',
21
+ key: 'info',
22
+ children: [
23
+ { title: 'Age', dataIndex: 'age', key: 'age', width: 100, sorter: true },
24
+ {
25
+ title: 'Address',
26
+ dataIndex: 'address',
27
+ key: 'address',
28
+ width: 200,
29
+ },
30
+ ],
31
+ },
32
+ {
33
+ title: 'Company',
34
+ key: 'company',
35
+ children: [
36
+ {
37
+ title: 'Name',
38
+ dataIndex: 'companyName',
39
+ key: 'companyName',
40
+ width: 180,
41
+ },
42
+ {
43
+ title: 'Address',
44
+ dataIndex: 'companyAddress',
45
+ key: 'companyAddress',
46
+ width: 220,
47
+ },
48
+ ],
49
+ },
50
+ {
51
+ title: 'Action',
52
+ key: 'action',
53
+ fixed: 'right',
54
+ width: 100,
55
+ render: (record) => (
56
+ <a onClick={() => console.log(record)}>Edit</a>
57
+ ),
58
+ },
59
+ ];
60
+
61
+ const dataSource = [
62
+ {
63
+ key: '1',
64
+ name: 'John Brown',
65
+ age: 32,
66
+ address: 'New York No. 1 Lake Park',
67
+ companyName: 'Acme Inc.',
68
+ companyAddress: 'NY Office',
69
+ },
70
+ {
71
+ key: '2',
72
+ name: 'Jim Green',
73
+ age: 42,
74
+ address: 'London No. 1 Lake Park',
75
+ companyName: 'Globex',
76
+ companyAddress: 'London Office',
77
+ },
78
+ {
79
+ key: '3',
80
+ name: 'Joe Black',
81
+ age: 28,
82
+ address: 'Sidney No. 1 Lake Park',
83
+ companyName: 'Initech',
84
+ companyAddress: 'Sidney Office',
85
+ },
86
+ ];
87
+
88
+ const rowSelection = {
89
+ type: 'checkbox',
90
+ selectedRowKeys,
91
+ onChange: (keys: string[] | number[]) => setSelectedRowKeys(keys),
92
+ };
93
+
94
+ return (
95
+ <Table
96
+ columns={columns}
97
+ dataSource={dataSource}
98
+ rowKey="key"
99
+ rowSelection={rowSelection as RowSelectionType}
100
+ bordered
101
+ scroll={{ x: 1200 }}
102
+ />
103
+ );
104
+ };
@@ -2,8 +2,18 @@ import React, { useMemo } from 'react';
2
2
  import useDeepCompareMemo from '../../hooks/useDeepCompareMemo';
3
3
  import deepClone from '../../utils/deepClone';
4
4
  import { handleColumns } from '../util';
5
+ import {
6
+ flattenLeafColumns,
7
+ injectSelectionExpand,
8
+ parseHeaderRows,
9
+ } from '../util/header';
5
10
 
6
- import { ColumnProps, ExpandableType, RowSelectionType } from '../interface';
11
+ import type {
12
+ ColumnProps,
13
+ ExpandableType,
14
+ RowSelectionType,
15
+ WrapedColumnProps,
16
+ } from '../interface';
7
17
 
8
18
  export default function useColumns({
9
19
  children,
@@ -22,15 +32,15 @@ export default function useColumns({
22
32
  const shouldRenderExpand = !!expandable;
23
33
 
24
34
  const getColumnsFromChild = (
25
- children: React.ReactElement<ColumnProps>[],
35
+ childs: React.ReactElement<ColumnProps>[],
26
36
  ): Array<ColumnProps> | null => {
27
- const columns: ColumnProps[] = [];
28
- React.Children.forEach(children, (child) => {
37
+ const cols: ColumnProps[] = [];
38
+ React.Children.forEach(childs, (child) => {
29
39
  if (child) {
30
- columns.push({ ...(child.props as ColumnProps) });
40
+ cols.push({ ...(child.props as ColumnProps) });
31
41
  }
32
42
  });
33
- return columns.length ? columns : null;
43
+ return cols.length ? cols : null;
34
44
  };
35
45
 
36
46
  const childColumns: Array<ColumnProps> | null = useMemo(() => {
@@ -39,48 +49,21 @@ export default function useColumns({
39
49
  : null;
40
50
  }, [children]);
41
51
 
42
- // Wrap columns
43
- const wrapColumns = (columns: Array<ColumnProps>) => {
44
- let result = deepClone(columns);
45
- if (rowSelection) {
46
- const { index = 1 } = rowSelection;
47
- const loc = index - 1;
48
- result.splice(loc, 0, {
49
- width: 50,
50
- ...rowSelection,
51
- key: 'YEE_SELECTION_COL',
52
- });
53
- }
54
- if (expandable) {
55
- const { index = 1, visible = true } = expandable;
56
- const loc = index ? index - 1 : rowSelection ? 1 : 0;
57
- if (visible !== false) {
58
- result.splice(loc, 0, {
59
- width: 50,
60
- ...expandable,
61
- key: 'YEE_EXPAND_COL',
62
- });
63
- }
64
- }
65
- result = handleColumns(result);
66
- return result;
67
- };
68
-
69
- // const [mergedColumns, setMergedColumns] = React.useState(
70
- // wrapColumns(childColumns || columns || []),
71
- // );
72
-
73
- // useDeepCompareEffect(() => {
74
- // const merged = wrapColumns(childColumns || columns || []);
75
- // setMergedColumns(merged);
76
- // }, [childColumns, columns, shouldRenderSelection, shouldRenderExpand]);
77
-
78
- const mergedColumns = useDeepCompareMemo(() => {
79
- return wrapColumns(childColumns || columns || []);
52
+ // Build the column tree (with selection/expand injected at the top level),
53
+ // then derive both the flat leaf columns (body/colgroup/summary/sorter) and
54
+ // the 2D header rows (thead multi-level rendering).
55
+ const { wrapedColumns, headerRows } = useDeepCompareMemo(() => {
56
+ const base = (deepClone(childColumns || columns || []) ||
57
+ []) as WrapedColumnProps[];
58
+ const tree = injectSelectionExpand(base, rowSelection, expandable);
59
+ const leaves = flattenLeafColumns(tree);
60
+ const wraped = handleColumns(leaves);
61
+ const rows = parseHeaderRows(tree);
62
+ return { wrapedColumns: wraped, headerRows: rows };
80
63
  }, [childColumns, columns, shouldRenderSelection, shouldRenderExpand]);
81
64
 
82
65
  return {
83
- wrapedColumns: mergedColumns,
84
- columns: childColumns || columns,
66
+ wrapedColumns,
67
+ headerRows,
85
68
  };
86
69
  }
@@ -22,6 +22,8 @@ A table displays rows of data.
22
22
  <code src="./demo/expand.tsx" title="Expandable" description="Expandable rows"></code>
23
23
  <code src="./demo/pagination.tsx" title="Pagination" description="Table with pagination"></code>
24
24
  <code src="./demo/column-filter.tsx" title="column filter" description="Table column filter"></code>
25
+ <code src="./demo/grouping.tsx" title="Grouping" description="Multi-level header"></code>
26
+ <code src="./demo/components-override.tsx" title="components override" description="tbody / row rendering that can be taken over by external libs (e.g. dnd-kit)"></code>
25
27
  ## API
26
28
 
27
29
  ### TableProps
@@ -33,7 +35,7 @@ A table displays rows of data.
33
35
  | style | `React.CSSProperties` | Custom root style | - |
34
36
  | classNames | `Partial<Record<SemanticType, string>>` | Semantic class names | - |
35
37
  | styles | `Partial<Record<SemanticType, React.CSSProperties>>` | Semantic styles | - |
36
- | components | `Partial<Record<SemanticType, React.ReactNode>>` | Custom table elements | - |
38
+ | components | [`TableComponents`](#tablecomponents) | Custom table elements, can be taken over by external libs (e.g. dnd-kit) | - |
37
39
  | bordered | `boolean` | Show border | - |
38
40
  | columns | `ColumnProps[]` | Table column configuration | - |
39
41
  | children | `Array<React.ReactElement<ColumnProps>> | React.ReactElement<ColumnProps>` | Children elements | - |
@@ -77,7 +79,7 @@ A table displays rows of data.
77
79
  | width | `number \| string` | Column width | - |
78
80
  | title | `React.ReactNode` | Column title | - |
79
81
  | helper | `string \| React.ReactNode` | Help icon for column header | - |
80
- | children | `(record: Record<string, any>, rowIndex: number) => React.ReactNode` | Custom cell content | - |
82
+ | children | `ColumnProps[]` | Sub-columns for header grouping (multi-level header); use `render` for custom cell content | - |
81
83
  | onCell | `(record: object, rowIndex: number) => object` | Cell props | - |
82
84
  | onHeaderCell | `(column: ColumnProps) => object` | Header cell props | - |
83
85
  | render | `(record: object, rowIndex: number) => React.ReactNode` | Custom render | - |
@@ -113,4 +115,30 @@ A table displays rows of data.
113
115
  | rowExpandable | `(record: object) => boolean` | Whether row is expandable | - |
114
116
  | onExpand | `(expanded: boolean, record: Record<string, any>) => void` | Expand callback | - |
115
117
  | onExpandedRowsChange | `(expandedKeys?: Array<number \| string>) => void` | Expanded rows change callback | - |
116
- | expandedRowRender | `(record, index, page) => React.ReactNode` | Expanded row render | - |
118
+ | expandedRowRender | `(record, index, page) => React.ReactNode` | Expanded row render | - |
119
+
120
+ ### TableComponents
121
+
122
+ Seams exposed by Table so an external lib (e.g. dnd-kit) can take over rendering. **Table itself has no dependency on any drag library** — it only provides replacement points; drag logic is owned by the consumer.
123
+
124
+ | Property | Type | Description | Default |
125
+ | --- | --- | --- | --- |
126
+ | body | `TableBodyComponents` | Replaceable body elements | - |
127
+
128
+ #### TableBodyComponents
129
+
130
+ | Property | Type | Description | Default |
131
+ | --- | --- | --- | --- |
132
+ | tbody | `React.ElementType` | Replace `<tbody>`; commonly used to wrap a `SortableContext` provider | - |
133
+ | row | `React.ComponentType<TableRowRendererProps>` | Full-row takeover: consumer renders the whole `<tr>` + cells (can place a drag handle, etc.) | - |
134
+
135
+ > Under full-row takeover, the consumer-rendered row **does not** get Table's auto selection / expand / colSpan / stripe row-level features. Table's pagination / sorting / filtering still apply (they mutate `dataSource`).
136
+
137
+ #### TableRowRendererProps (received by components.body.row)
138
+
139
+ | Property | Type | Description |
140
+ | --- | --- | --- |
141
+ | record | `Record<string, any>` | Current row data |
142
+ | index | `number` | Current row index |
143
+ | columns | `WrapedColumnProps[]` | Table-resolved columns |
144
+ | rowKey | `string \| number` | Current row key value; usable as sortable id |
@@ -8,6 +8,10 @@ export type {
8
8
  PaginationType,
9
9
  RowSelectionType,
10
10
  TableProps,
11
+ TableComponents,
12
+ TableBodyComponents,
13
+ TableRowRendererProps,
14
+ HeaderCell,
11
15
  onChangeParams,
12
16
  } from './interface';
13
17
 
@@ -23,9 +23,11 @@ toc: 'content'
23
23
  <code src="./demo/expand.tsx" title="可展开" description="可展开行的表格"></code>
24
24
  <code src="./demo/pagination.tsx" title="分页" description="带分页的表格"></code>
25
25
  <code src="./demo/merge-cell.tsx" title="合并单元格" description="合并单元格的表格"></code>
26
+ <code src="./demo/grouping.tsx" title="表头分组" description="多级表头"></code>
26
27
  <code src="./demo/summary.tsx" title="统计" description="表格的统计行"></code>
27
28
  <code src="./demo/filter.tsx" title="筛选" description="表格的筛选功能"></code>
28
29
  <code src="./demo/column-filter.tsx" title="列筛选" description="表格的列筛选功能"></code>
30
+ <code src="./demo/components-override.tsx" title="自定义表格元素" description="可被外部(如 dnd-kit)接管的 tbody / 行渲染"></code>
29
31
 
30
32
  ## API
31
33
 
@@ -38,7 +40,7 @@ toc: 'content'
38
40
  | style | `React.CSSProperties` | 自定义根样式 | - |
39
41
  | classNames | `Partial<Record<SemanticType, string>>` | 语义化类名 | - |
40
42
  | styles | `Partial<Record<SemanticType, React.CSSProperties>>` | 语义化样式 | - |
41
- | components | `Partial<Record<SemanticType, React.ReactNode>>` | 自定义表格元素 | - |
43
+ | components | [`TableComponents`](#tablecomponents) | 自定义表格元素,可被外部(如 dnd-kit)接管 | - |
42
44
  | bordered | `boolean` | 是否展示外边框和列边框 | - |
43
45
  | columns | `ColumnProps[]` | 表格列的配置信息 | - |
44
46
  | children | `Array<React.ReactElement<ColumnProps>> \| React.ReactElement<ColumnProps>` | 子元素 | - |
@@ -82,7 +84,7 @@ toc: 'content'
82
84
  | width | `number \| string` | 设置宽度 | - |
83
85
  | title | `React.ReactNode` | 设置列头显示文本 | - |
84
86
  | helper | `string \| React.ReactNode` | 设置表头help 帮助图标 | - |
85
- | children | `(record: Record<string, any>, rowIndex: number) => React.ReactNode` | 回调函数,用于自定义单元格内容 | - |
87
+ | children | `ColumnProps[]` | 子列,用于表头分组(多级表头);自定义单元格内容请用 `render` | - |
86
88
  | onCell | `(record: object, rowIndex: number) => object` | 设置单元格属性 | - |
87
89
  | onHeaderCell | `(column: ColumnProps) => object` | 设置表头单元格属性 | - |
88
90
  | render | `(record: Record<string, any>, rowIndex: number) => React.ReactNode` | 自定义渲染函数 | - |
@@ -119,3 +121,29 @@ toc: 'content'
119
121
  | onExpand | `(expanded: boolean, record: Record<string, any>) => void` | 点击展开图标时触发 | - |
120
122
  | onExpandedRowsChange | `(expandedKeys?: Array<number \| string>) => void` | 展开的行变化时触发 | - |
121
123
  | expandedRowRender | `(record, index, page) => React.ReactNode` | 额外的展开行 | - |
124
+
125
+ ### TableComponents
126
+
127
+ Table 暴露的"可被外部接管"接缝。**Table 本身不依赖任何拖拽库**,仅提供替换点;dnd 等逻辑由消费方持有。
128
+
129
+ | 属性名 | 类型 | 描述 | 默认值 |
130
+ | ------ | --------------------- | ---------------- | ------ |
131
+ | body | `TableBodyComponents` | 可替换的表体元素 | - |
132
+
133
+ #### TableBodyComponents
134
+
135
+ | 属性名 | 类型 | 描述 | 默认值 |
136
+ | ------ | ------------------------------------------ | ------------------------------------------------------------- | ------ |
137
+ | tbody | `React.ElementType` | 替换 `<tbody>`,常用于在外部包 `SortableContext` 等 Provider | - |
138
+ | row | `React.ComponentType<TableRowRendererProps>` | 整行接管:消费方自行渲染 `<tr>` + 单元格(可放拖拽手柄等) | - |
139
+
140
+ > 整行接管时,消费方渲染的行**不享受** Table 的自动 selection / expand / colSpan / stripe 等行级特性;Table 的分页 / 排序 / 筛选仍生效(它们改变 `dataSource`)。
141
+
142
+ #### TableRowRendererProps(components.body.row 收到的 props)
143
+
144
+ | 属性名 | 类型 | 描述 |
145
+ | -------- | ----------------------- | --------------------------------- |
146
+ | record | `Record<string, any>` | 当前行数据 |
147
+ | index | `number` | 当前行索引 |
148
+ | columns | `WrapedColumnProps[]` | Table 解析后的列 |
149
+ | rowKey | `string \| number` | 当前行 key 值,可作 sortable id |
@@ -70,6 +70,14 @@ export interface HeadCellProps extends Omit<WrapedColumnProps, 'title'> {
70
70
  internalFilters?: { [dataIndex: string]: boolean }; // Whether this column is filtered
71
71
  onSort?: (dataIndex: string, sorter: any) => void;
72
72
  onInternalFilter?: (dataIndex: string, value: string) => void;
73
+ /**
74
+ * Horizontal span, used for grouped header cells
75
+ */
76
+ colSpan?: number;
77
+ /**
78
+ * Vertical span, used for grouped header cells
79
+ */
80
+ rowSpan?: number;
73
81
  }
74
82
 
75
83
  // Row selection config
@@ -252,9 +260,9 @@ export interface ColumnProps {
252
260
  */
253
261
  helper?: string | React.ReactNode;
254
262
  /**
255
- * Callback function for custom cell content
263
+ * Sub-columns for header grouping (multi-level header). Use cell `render` for custom cell content.
256
264
  */
257
- children?: (record: Record<string, any>, rowIndex: number) => React.ReactNode;
265
+ children?: ColumnProps[];
258
266
  /**
259
267
  * Set cell properties
260
268
  */
@@ -287,8 +295,55 @@ export interface WrapedColumnProps
287
295
  */
288
296
  }
289
297
 
298
+ /**
299
+ * A header cell resolved from the column tree, with computed span info for multi-level headers.
300
+ */
301
+ export interface HeaderCell {
302
+ /**
303
+ * The source wrapped column (leaf or group)
304
+ */
305
+ column: WrapedColumnProps;
306
+ /**
307
+ * Horizontal span (number of leaf columns covered)
308
+ */
309
+ colSpan: number;
310
+ /**
311
+ * Vertical span (number of header rows covered)
312
+ */
313
+ rowSpan: number;
314
+ /**
315
+ * Whether this cell has sub-columns (group header)
316
+ */
317
+ hasSubColumns?: boolean;
318
+ }
319
+
290
320
  type DownloadType = ButtonProps;
291
321
 
322
+ /**
323
+ * 行接管渲染器收到的 props(components.body.row)
324
+ */
325
+ export interface TableRowRendererProps {
326
+ record: Record<string, any>;
327
+ index: number;
328
+ columns: WrapedColumnProps[];
329
+ /** 当前行 key 值(= record[rowKey]),可作 sortable id */
330
+ rowKey: string | number;
331
+ }
332
+
333
+ /**
334
+ * 可被外部接管的 <tbody> / 行渲染
335
+ */
336
+ export interface TableBodyComponents {
337
+ /** 替换 <tbody>;常用于在外部包 SortableContext 等 Provider */
338
+ tbody?: React.ElementType;
339
+ /** 整行接管:消费方自行渲染 <tr> + 单元格(含拖拽手柄等) */
340
+ row?: React.ComponentType<TableRowRendererProps>;
341
+ }
342
+
343
+ export interface TableComponents {
344
+ body?: TableBodyComponents;
345
+ }
346
+
292
347
  export type SemanticProps = {
293
348
  /**
294
349
  * Semantic class names
@@ -301,7 +356,7 @@ export type SemanticProps = {
301
356
  /**
302
357
  * Custom table elements
303
358
  */
304
- components?: Partial<Record<SemanticType, React.ReactNode>>;
359
+ components?: TableComponents;
305
360
  };
306
361
 
307
362
  export interface HeaderProps extends SemanticProps {
@@ -358,11 +413,14 @@ export interface TableRowProps {
358
413
  stripe?: boolean;
359
414
  expandedKeyType?: string;
360
415
  onRow?: (record: Record<string, any>, index: number) => Record<string, any>;
361
- rowClassName?: (record: Record<string, any>, index: number) => string;
416
+ rowClassName?: (
417
+ record: Record<string, any>,
418
+ index: number,
419
+ ) => string | undefined;
362
420
  rowStyle?: (
363
421
  record: Record<string, any>,
364
422
  index: number,
365
- ) => React.CSSProperties;
423
+ ) => React.CSSProperties | undefined;
366
424
  onDoubleClick?: (
367
425
  record: Record<string, any>,
368
426
  event: React.MouseEvent<HTMLTableRowElement>,
@@ -473,7 +531,7 @@ export interface TableProps
473
531
  /**
474
532
  * Custom table elements
475
533
  */
476
- components?: Partial<Record<SemanticType, React.ReactNode>>;
534
+ components?: TableComponents;
477
535
  /**
478
536
  * Whether to show outer and column borders
479
537
  */
@@ -519,11 +577,11 @@ export interface TableProps
519
577
  /**
520
578
  * Row class name, unlike classNames, this prop can be set dynamically via a function
521
579
  */
522
- rowClassName?: (record: object) => string;
580
+ rowClassName?: (record: object) => string | undefined;
523
581
  /**
524
582
  * Row style, unlike styles, this prop can be set dynamically via a function
525
583
  */
526
- rowStyle?: (record: object) => React.CSSProperties;
584
+ rowStyle?: (record: object) => React.CSSProperties | undefined;
527
585
  /**
528
586
  * Pagination config
529
587
  */
@@ -153,7 +153,25 @@
153
153
 
154
154
  &-tbody {
155
155
  @{pls}-cell {
156
- background-color: var(--yee-table-cell-bg-color, #fff);
156
+ background-color: var(--yee-table-cell-bg-color, inherit);
157
+ }
158
+
159
+ @{pls}-row {
160
+ &:hover {
161
+ background-color: var(--yee-table-tbody-tr-hover-bg-color);
162
+ }
163
+ }
164
+ }
165
+
166
+ &-odd-row {
167
+ > @{pls}-cell {
168
+ background-color: var(--yee-table-odd-row-bg-color);
169
+ }
170
+ }
171
+
172
+ &-even-row {
173
+ > @{pls}-cell {
174
+ background-color: var(--yee-table-even-row-bg-color);
157
175
  }
158
176
  }
159
177