@rainbow-oh/yee-c 0.5.1 → 0.6.0

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 (65) hide show
  1. package/dist/cjs/Table/demo/components-override.d.ts +3 -0
  2. package/dist/cjs/Table/demo/components-override.js +54 -0
  3. package/dist/cjs/Table/demo/grouping.d.ts +3 -0
  4. package/dist/cjs/Table/demo/grouping.js +129 -0
  5. package/dist/cjs/Table/hooks/useColumns.d.ts +2 -2
  6. package/dist/cjs/Table/hooks/useColumns.js +15 -37
  7. package/dist/cjs/Table/index.d.ts +1 -1
  8. package/dist/cjs/Table/interface.d.ts +59 -8
  9. package/dist/cjs/Table/style/index.less +19 -1
  10. package/dist/cjs/Table/table.js +5 -7
  11. package/dist/cjs/Table/tbody/cell.d.ts +0 -1
  12. package/dist/cjs/Table/tbody/cell.js +0 -4
  13. package/dist/cjs/Table/tbody/index.js +19 -2
  14. package/dist/cjs/Table/tbody/row.js +15 -11
  15. package/dist/cjs/Table/theader/cell.js +7 -1
  16. package/dist/cjs/Table/theader/index.d.ts +5 -5
  17. package/dist/cjs/Table/theader/index.js +41 -27
  18. package/dist/cjs/Table/util/header.d.ts +23 -0
  19. package/dist/cjs/Table/util/header.js +109 -0
  20. package/dist/cjs/style/themes.css +1 -1
  21. package/dist/cjs/style/variables.css +1 -1
  22. package/dist/cjs/version.d.ts +1 -1
  23. package/dist/cjs/version.js +1 -1
  24. package/dist/esm/Table/demo/components-override.d.ts +3 -0
  25. package/dist/esm/Table/demo/components-override.js +86 -0
  26. package/dist/esm/Table/demo/grouping.d.ts +3 -0
  27. package/dist/esm/Table/demo/grouping.js +102 -0
  28. package/dist/esm/Table/hooks/useColumns.d.ts +2 -2
  29. package/dist/esm/Table/hooks/useColumns.js +24 -50
  30. package/dist/esm/Table/index.d.ts +1 -1
  31. package/dist/esm/Table/interface.d.ts +59 -8
  32. package/dist/esm/Table/style/index.less +19 -1
  33. package/dist/esm/Table/table.js +5 -7
  34. package/dist/esm/Table/tbody/cell.d.ts +0 -1
  35. package/dist/esm/Table/tbody/cell.js +0 -5
  36. package/dist/esm/Table/tbody/index.js +21 -2
  37. package/dist/esm/Table/tbody/row.js +19 -15
  38. package/dist/esm/Table/theader/cell.js +6 -2
  39. package/dist/esm/Table/theader/index.d.ts +5 -5
  40. package/dist/esm/Table/theader/index.js +48 -35
  41. package/dist/esm/Table/util/header.d.ts +23 -0
  42. package/dist/esm/Table/util/header.js +107 -0
  43. package/dist/esm/style/themes.css +1 -1
  44. package/dist/esm/style/variables.css +1 -1
  45. package/dist/esm/version.d.ts +1 -1
  46. package/dist/esm/version.js +1 -1
  47. package/dist/umd/yee-c.min.css +1 -1
  48. package/dist/umd/yee-c.min.js +1 -1
  49. package/package.json +1 -1
  50. package/src/Table/demo/components-override.tsx +49 -0
  51. package/src/Table/demo/grouping.tsx +104 -0
  52. package/src/Table/hooks/useColumns.ts +29 -46
  53. package/src/Table/index.en-US.md +31 -3
  54. package/src/Table/index.ts +4 -0
  55. package/src/Table/index.zh-CN.md +30 -2
  56. package/src/Table/interface.ts +66 -8
  57. package/src/Table/style/index.less +19 -1
  58. package/src/Table/table.tsx +5 -7
  59. package/src/Table/tbody/cell.tsx +0 -6
  60. package/src/Table/tbody/index.tsx +21 -2
  61. package/src/Table/tbody/row.tsx +25 -14
  62. package/src/Table/theader/cell.tsx +4 -0
  63. package/src/Table/theader/index.tsx +61 -42
  64. package/src/Table/util/header.ts +111 -0
  65. package/src/version.ts +1 -1
@@ -8,7 +8,7 @@ import TableRow from './row';
8
8
  const TableBody: React.FC<TableBodyProps> = (props) => {
9
9
  const { columns, pageData, lazyLoad, ...rest } = props;
10
10
 
11
- const { prefixCls } = React.useContext(TableCtx);
11
+ const { prefixCls, components, rowKey } = React.useContext(TableCtx);
12
12
  const { locale } = useLocale();
13
13
  const { table: tableLocale } = locale;
14
14
 
@@ -23,11 +23,30 @@ const TableBody: React.FC<TableBodyProps> = (props) => {
23
23
  const dataLength = pageData.length;
24
24
  if (dataLength === 0) return empty;
25
25
 
26
+ const BodyWrapper = components?.body?.tbody ?? 'tbody';
27
+ const RowRenderer = components?.body?.row;
28
+
29
+ const resolveRowKey = (record: Record<string, any>) =>
30
+ typeof rowKey === 'function' ? rowKey(record) : record[rowKey];
31
+
26
32
  const getRenderRows = () => {
27
33
  if (lazyLoad) {
28
34
  return <LazyRow {...rest} pageData={pageData} columns={columns} />;
29
35
  }
30
36
  return pageData.map((record: Record<string, any>, index: number) => {
37
+ // 整行接管:由外部组件渲染 <tr> + 单元格(可放拖拽手柄等)
38
+ if (RowRenderer) {
39
+ const rk = resolveRowKey(record);
40
+ return (
41
+ <RowRenderer
42
+ key={rk ?? index}
43
+ record={record}
44
+ index={index}
45
+ columns={columns}
46
+ rowKey={rk}
47
+ />
48
+ );
49
+ }
31
50
  return (
32
51
  <TableRow
33
52
  {...rest}
@@ -41,7 +60,7 @@ const TableBody: React.FC<TableBodyProps> = (props) => {
41
60
  };
42
61
 
43
62
  const tbody = (
44
- <tbody className={`${prefixCls}-tbody`}>{getRenderRows()}</tbody>
63
+ <BodyWrapper className={`${prefixCls}-tbody`}>{getRenderRows()}</BodyWrapper>
45
64
  );
46
65
 
47
66
  return tbody;
@@ -56,27 +56,38 @@ const TableRow: React.FC<TableRowProps> = (props) => {
56
56
  };
57
57
 
58
58
  const getSelection = (column: WrapedColumnProps) => {
59
- const { type, onCell, ...restCol } = column;
60
- const key = record[rowKey];
61
- const props = onCell ? onCell(record, index) : {};
62
- const checked = selectedRowKeys?.includes(key);
63
-
59
+ const { type, disabled: colDisabled, onCell } = column;
60
+ const rowKeyValue = record[rowKey];
61
+ const props = (onCell?.(record, index) || {}) as Record<string, unknown>;
62
+ const checked = selectedRowKeys?.includes(rowKeyValue);
63
+
64
+ // rowSelection.disabled may be a boolean, a per-row array, or a function
65
+ const disabled =
66
+ typeof colDisabled === 'function'
67
+ ? colDisabled(record, index)
68
+ : Array.isArray(colDisabled)
69
+ ? colDisabled[index]
70
+ : !!colDisabled;
71
+
72
+ // Only forward input-relevant props. Spreading the whole column would leak
73
+ // rowSelection fields (selectedRowKeys/selectAll/...) and the synthetic
74
+ // `key` onto the DOM <input>.
64
75
  const commonProps = {
65
- // ...rest,
66
- ...restCol,
67
- ...props,
68
76
  checked,
69
- value: key,
77
+ value: rowKeyValue,
70
78
  onChange: onSelectionChange,
79
+ disabled,
80
+ ...props,
71
81
  };
72
82
 
73
83
  if (type === 'checkbox') {
74
- // @ts-ignore
75
- return <Checkbox {...commonProps} />;
76
- } else {
77
- // @ts-ignore
78
- return <Radio {...commonProps} />;
84
+ return (
85
+ <Checkbox
86
+ {...(commonProps as React.ComponentProps<typeof Checkbox>)}
87
+ />
88
+ );
79
89
  }
90
+ return <Radio {...(commonProps as React.ComponentProps<typeof Radio>)} />;
80
91
  };
81
92
 
82
93
  let colSpanStart = Infinity;
@@ -26,6 +26,8 @@ const HeadCell: React.FC<HeadCellProps> = (props) => {
26
26
  internalFilters,
27
27
  style,
28
28
  width,
29
+ colSpan,
30
+ rowSpan,
29
31
  onHeaderCell,
30
32
  onSort,
31
33
  onInternalFilter,
@@ -141,6 +143,8 @@ const HeadCell: React.FC<HeadCellProps> = (props) => {
141
143
  className: cls,
142
144
  scope: 'col',
143
145
  style: styles,
146
+ colSpan,
147
+ rowSpan,
144
148
  };
145
149
  };
146
150
 
@@ -1,65 +1,84 @@
1
1
  import clsx from 'clsx';
2
2
  import React, { memo, useContext } from 'react';
3
3
  import Checkbox from '../../Checkbox';
4
- import { HeadCellProps, WrapedColumnProps } from '../interface';
4
+ import type { HeaderCell } from '../interface';
5
5
  import { TableCtx } from '../table';
6
6
  import HeadCell from './cell';
7
7
 
8
8
  export interface TableHeadProps {
9
- children?: React.ReactNode;
10
- columns?: Array<HeadCellProps>;
11
- isExpandable?: boolean;
12
- expandedColumn?: number;
9
+ /**
10
+ * Resolved 2D header rows (one array per header row), produced by parseHeaderRows
11
+ */
12
+ headerRows?: HeaderCell[][];
13
13
  }
14
14
 
15
15
  const TableHead: React.FC<any> = (props) => {
16
- const { columns, onCheckAll, checkedAll, onHeaderRow, ...rest } = props;
16
+ const { headerRows = [], onCheckAll, checkedAll, onHeaderRow, ...rest } =
17
+ props;
17
18
 
18
19
  const { prefixCls } = useContext(TableCtx);
19
20
 
20
- const renderHeadCell = () => {
21
- return columns.map((column: WrapedColumnProps, index: number) => {
22
- const { key, type, visible } = column;
23
- if (key === 'YEE_SELECTION_COL') {
24
- const common = {
25
- className: `${prefixCls}-cell ${prefixCls}-selection-col`,
26
- scope: 'col',
27
- key: 'title-column-selection',
28
- };
29
- return (
30
- <th {...common} key={column.key || column.dataIndex}>
31
- {type === 'checkbox' ? (
32
- <Checkbox checked={checkedAll} onChange={onCheckAll} />
33
- ) : null}
34
- </th>
35
- );
36
- }
37
- if (key === 'YEE_EXPAND_COL' && visible !== false) {
38
- return (
39
- <th
40
- className={clsx(`${prefixCls}-cell`, `${prefixCls}-expand-col`)}
41
- scope="col"
42
- key="title-column-expandable"
43
- ></th>
44
- );
45
- }
21
+ const renderCell = (
22
+ cell: HeaderCell,
23
+ rowIndex: number,
24
+ colIndex: number,
25
+ ) => {
26
+ const { column, colSpan, rowSpan } = cell;
27
+ const { key, type, visible } = column;
28
+ const cellKey =
29
+ 'title-column-' +
30
+ (column.key || column.dataIndex || `${rowIndex}-${colIndex}`);
31
+
32
+ if (key === 'YEE_SELECTION_COL') {
46
33
  return (
47
- <HeadCell
48
- {...rest}
49
- {...column}
50
- key={'title-column-' + (column.key || column.dataIndex || index)}
34
+ <th
35
+ className={`${prefixCls}-cell ${prefixCls}-selection-col`}
36
+ scope="col"
37
+ key={cellKey}
38
+ colSpan={colSpan}
39
+ rowSpan={rowSpan}
40
+ >
41
+ {type === 'checkbox' ? (
42
+ <Checkbox checked={checkedAll} onChange={onCheckAll} />
43
+ ) : null}
44
+ </th>
45
+ );
46
+ }
47
+ if (key === 'YEE_EXPAND_COL' && visible !== false) {
48
+ return (
49
+ <th
50
+ className={clsx(`${prefixCls}-cell`, `${prefixCls}-expand-col`)}
51
+ scope="col"
52
+ key={cellKey}
53
+ colSpan={colSpan}
54
+ rowSpan={rowSpan}
51
55
  />
52
56
  );
53
- });
57
+ }
58
+ return (
59
+ <HeadCell
60
+ {...rest}
61
+ {...column}
62
+ colSpan={colSpan}
63
+ rowSpan={rowSpan}
64
+ key={cellKey}
65
+ />
66
+ );
54
67
  };
55
68
 
56
- const rowProps = onHeaderRow ? onHeaderRow(columns) : {};
57
-
58
69
  return (
59
70
  <thead className={clsx(`${prefixCls}-thead`)}>
60
- <tr {...rowProps} key="thead">
61
- {renderHeadCell()}
62
- </tr>
71
+ {headerRows.map((row: HeaderCell[], rowIndex: number) => {
72
+ const rowColumns = row.map((cell) => cell.column);
73
+ const rowProps = onHeaderRow ? onHeaderRow(rowColumns) : {};
74
+ return (
75
+ <tr {...rowProps} key={`thead-row-${rowIndex}`}>
76
+ {row.map((cell, colIndex) =>
77
+ renderCell(cell, rowIndex, colIndex),
78
+ )}
79
+ </tr>
80
+ );
81
+ })}
63
82
  </thead>
64
83
  );
65
84
  };
@@ -0,0 +1,111 @@
1
+ import type {
2
+ ColumnProps,
3
+ ExpandableType,
4
+ HeaderCell,
5
+ RowSelectionType,
6
+ WrapedColumnProps,
7
+ } from '../interface';
8
+
9
+ type FixedType = ColumnProps['fixed'];
10
+
11
+ /**
12
+ * Recursively flatten a (possibly grouped) column tree into its leaf columns.
13
+ * A parent's `fixed` is inherited by its children when the child does not set its own.
14
+ */
15
+ export function flattenLeafColumns(
16
+ columns: WrapedColumnProps[],
17
+ parentFixed?: FixedType,
18
+ ): WrapedColumnProps[] {
19
+ return columns.reduce<WrapedColumnProps[]>((list, column) => {
20
+ const fixed = column.fixed ?? parentFixed;
21
+ const subColumns = column.children as WrapedColumnProps[] | undefined;
22
+ if (subColumns && subColumns.length > 0) {
23
+ return [...list, ...flattenLeafColumns(subColumns, fixed)];
24
+ }
25
+ return [...list, { ...column, fixed }];
26
+ }, []);
27
+ }
28
+
29
+ /**
30
+ * Convert a column tree into a 2D array of header cells (one array per header row),
31
+ * computing each cell's colSpan/rowSpan. Mirrors rc-table's parseHeaderRows.
32
+ *
33
+ * - Pass 1 (DFS): place each column into the row matching its depth; a group's
34
+ * colSpan equals the sum of its children's colSpans.
35
+ * - Pass 2: leaf cells (no sub-columns) get rowSpan = rowCount - rowIndex so
36
+ * they stretch down to the last header row; group cells keep rowSpan = 1.
37
+ */
38
+ export function parseHeaderRows(
39
+ rootColumns: WrapedColumnProps[],
40
+ ): HeaderCell[][] {
41
+ const rows: HeaderCell[][] = [];
42
+
43
+ const fillRowCells = (
44
+ columns: WrapedColumnProps[],
45
+ rowIndex: number,
46
+ ): number => {
47
+ rows[rowIndex] = rows[rowIndex] || [];
48
+ let colSpanTotal = 0;
49
+ columns.filter(Boolean).forEach((column) => {
50
+ const cell: HeaderCell = {
51
+ column,
52
+ colSpan: 1,
53
+ rowSpan: 1,
54
+ };
55
+ const subColumns = column.children as WrapedColumnProps[] | undefined;
56
+ if (subColumns && subColumns.length > 0) {
57
+ cell.colSpan = fillRowCells(subColumns, rowIndex + 1);
58
+ cell.hasSubColumns = true;
59
+ }
60
+ rows[rowIndex].push(cell);
61
+ colSpanTotal += cell.colSpan;
62
+ });
63
+ return colSpanTotal;
64
+ };
65
+
66
+ fillRowCells(rootColumns, 0);
67
+
68
+ const rowCount = rows.length;
69
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
70
+ rows[rowIndex].forEach((cell) => {
71
+ // Leaf cells stretch to the bottom row; group cells stay at rowSpan = 1.
72
+ if (!cell.hasSubColumns) {
73
+ cell.rowSpan = rowCount - rowIndex;
74
+ }
75
+ });
76
+ }
77
+
78
+ return rows;
79
+ }
80
+
81
+ /**
82
+ * Inject selection / expand columns into the top level of the column tree.
83
+ * `index` is a 1-based position among the top-level columns.
84
+ */
85
+ export function injectSelectionExpand(
86
+ columns: WrapedColumnProps[],
87
+ rowSelection?: RowSelectionType,
88
+ expandable?: ExpandableType,
89
+ ): WrapedColumnProps[] {
90
+ const result = [...columns];
91
+ if (rowSelection) {
92
+ const { index = 1 } = rowSelection;
93
+ result.splice(index - 1, 0, {
94
+ width: 50,
95
+ ...rowSelection,
96
+ key: 'YEE_SELECTION_COL',
97
+ } as WrapedColumnProps);
98
+ }
99
+ if (expandable) {
100
+ const { index = 1, visible = true } = expandable;
101
+ const loc = index ? index - 1 : rowSelection ? 1 : 0;
102
+ if (visible !== false) {
103
+ result.splice(loc, 0, {
104
+ width: 50,
105
+ ...expandable,
106
+ key: 'YEE_EXPAND_COL',
107
+ } as WrapedColumnProps);
108
+ }
109
+ }
110
+ return result;
111
+ }
package/src/version.ts CHANGED
@@ -4,7 +4,7 @@ declare global {
4
4
  }
5
5
  }
6
6
 
7
- export const version = "0.5.1";
7
+ export const version = "0.6.0";
8
8
 
9
9
  if (typeof window !== 'undefined') {
10
10
  window.__yee_c_version__ = version;