@yester/virtual-table 1.0.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.
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # Virtual Table
2
+
3
+ A high-performance virtual scrolling table component for React, supporting Pivot Table, Group Table, and Detail Table modes. Capable of handling large datasets efficiently using `react-window`.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **High Performance**: Renders thousands of rows smoothly using virtual scrolling.
8
+ - 📊 **Pivot Table**: Supports multi-dimensional data analysis with row/column grouping and aggregation.
9
+ - 📑 **Group Table**: Supports row grouping with expandable/collapsible rows.
10
+ - 📋 **Detail Table**: Standard list view for detailed data.
11
+ - 🔄 **Sortable**: Supports sorting on multiple fields.
12
+ - 🎨 **Customizable**: Flexible styling and cell rendering.
13
+ - 📦 **Lightweight**: No heavy dependencies (lodash removed, icons extracted).
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add virtual-table
19
+ # or
20
+ npm install virtual-table
21
+ # or
22
+ yarn add virtual-table
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Basic Usage
28
+
29
+ ```tsx
30
+ import React from 'react';
31
+ import { VirtualTable } from 'virtual-table';
32
+ import 'virtual-table/dist/style.css'; // Import styles
33
+
34
+ const App = () => {
35
+ const data = [
36
+ { province: 'Zhejiang', city: 'Hangzhou', type: 'Furniture', amount: 10 },
37
+ // ... more data
38
+ ];
39
+
40
+ const params = {
41
+ data,
42
+ meta: [],
43
+ sortParams: [],
44
+ fields: {
45
+ rows: [{ field: 'province', title: 'Province', width: 150 }],
46
+ columns: [{ field: 'type', title: 'Type', width: 120 }],
47
+ values: [{ field: 'amount', title: 'Amount', calculateType: 'sum', width: 100 }]
48
+ }
49
+ };
50
+
51
+ return (
52
+ <div style={{ height: 500 }}>
53
+ <VirtualTable
54
+ {...params}
55
+ scroll={{ y: 500 }}
56
+ />
57
+ </div>
58
+ );
59
+ };
60
+ ```
61
+
62
+ ## Modes
63
+
64
+ ### 1. Pivot Table Mode
65
+ Configure `rows`, `columns`, and `values` in `fields`.
66
+
67
+ ```tsx
68
+ const pivotFields = {
69
+ rows: [
70
+ { field: 'province', title: 'Province', width: 120, total: { enabled: true, label: 'Total' } },
71
+ { field: 'city', title: 'City', width: 120 }
72
+ ],
73
+ columns: [
74
+ { field: 'type', title: 'Type', width: 120 }
75
+ ],
76
+ values: [
77
+ { field: 'amount', title: 'Amount', calculateType: 'sum', width: 100 }
78
+ ]
79
+ };
80
+ ```
81
+
82
+ ### 2. Group Table Mode
83
+ Configure `rows` and `values`, leave `columns` empty.
84
+
85
+ ```tsx
86
+ const groupFields = {
87
+ rows: [
88
+ { field: 'province', title: 'Province', width: 120 },
89
+ { field: 'city', title: 'City', width: 120 }
90
+ ],
91
+ columns: [],
92
+ values: [
93
+ { field: 'amount', title: 'Amount', calculateType: 'sum', width: 100 }
94
+ ]
95
+ };
96
+ ```
97
+
98
+ ### 3. Detail Table Mode
99
+ Configure only `values` as a flat list of columns.
100
+
101
+ ```tsx
102
+ const detailFields = {
103
+ rows: [],
104
+ columns: [],
105
+ values: [
106
+ { field: 'province', title: 'Province', width: 120 },
107
+ { field: 'city', title: 'City', width: 120 },
108
+ { field: 'amount', title: 'Amount', width: 100 }
109
+ ]
110
+ };
111
+ ```
112
+
113
+ ## API
114
+
115
+ ### VirtualTable Props
116
+
117
+ | Property | Type | Description |
118
+ |Data | `any[]` | Source data array |
119
+ | `fields` | `PivotFields` | Configuration for rows, columns, and values |
120
+ | `meta` | `any[]` | Meta information (optional) |
121
+ | `sortParams` | `SortParam[]` | Sorting configuration |
122
+ | `scroll` | `{ x?: number \| string; y?: number \| string }` | Scroll configuration. `y` is required for virtual scrolling height |
123
+ | `className` | `string` | Custom CSS class |
124
+ | `style` | `React.CSSProperties` | Custom styles |
125
+
126
+ ### PivotFields
127
+
128
+ ```typescript
129
+ interface PivotFields {
130
+ rows: CustomTreeNode[]; // Row dimensions
131
+ columns: CustomTreeNode[]; // Column dimensions
132
+ values: CustomTreeNode[]; // Value fields (metrics)
133
+ }
134
+ ```
135
+
136
+ ### CustomTreeNode (Field Configuration)
137
+
138
+ | Property | Type | Description |
139
+ |----------|------|-------------|
140
+ | `field` | `string` | Data field key |
141
+ | `title` | `ReactNode` | Column header title |
142
+ | `width` | `number \| string` | Column width |
143
+ | `calculateType` | `'sum' \| 'avg' \| 'count' ...` | Aggregation type (for values) |
144
+ | `total` | `{ enabled: boolean; label?: string }` | Subtotal configuration (for rows) |
145
+ | `emptyReplace` | `string` | Replacement for empty values |
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ # Install dependencies
151
+ pnpm install
152
+
153
+ # Run dev server
154
+ pnpm dev
155
+
156
+ # Build library
157
+ pnpm build
158
+
159
+ # Run tests
160
+ pnpm test
161
+
162
+ # Release (Test -> Build -> Publish)
163
+ pnpm release
164
+ ```
165
+
166
+ ## License
167
+
168
+ MIT
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+
3
+ declare const DownCircleOutlined: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
4
+ export default DownCircleOutlined;
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+
3
+ declare const UpCircleOutlined: (props: React.SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
4
+ export default UpCircleOutlined;
@@ -0,0 +1,15 @@
1
+ import { default as React } from 'react';
2
+ import { DataCell, CustomTreeNode, MetaItem } from '../../types';
3
+
4
+ export interface CellProps {
5
+ columnIndex: number;
6
+ rowIndex: number;
7
+ style: React.CSSProperties;
8
+ mergedData: DataCell[][];
9
+ columns: CustomTreeNode[];
10
+ data: any[];
11
+ handleExpand: (record: any) => void;
12
+ meta?: MetaItem[];
13
+ }
14
+ declare const Cell: React.FC<CellProps>;
15
+ export default Cell;
@@ -0,0 +1,25 @@
1
+ import { default as React } from 'react';
2
+ import { TableRow, CustomTreeNode, MetaItem } from '../../types';
3
+
4
+ interface RendererProps {
5
+ data: TableRow[];
6
+ info: {
7
+ ref: any;
8
+ onScroll: (props: {
9
+ scrollLeft: number;
10
+ scrollTop: number;
11
+ }) => void;
12
+ scrollbarSize?: number;
13
+ };
14
+ scroll?: {
15
+ x?: number | string;
16
+ y?: number | string;
17
+ };
18
+ columns: CustomTreeNode[];
19
+ tableWidth: number;
20
+ gridWidth: number;
21
+ handleExpand: (record: any) => void;
22
+ meta?: MetaItem[];
23
+ }
24
+ declare const Renderer: React.FC<RendererProps>;
25
+ export default Renderer;
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ import { CustomTreeNode } from '../../types';
3
+
4
+ interface TableHeaderProps {
5
+ columns: CustomTreeNode[];
6
+ width: number;
7
+ onScroll: (e: React.UIEvent<HTMLDivElement>) => void;
8
+ }
9
+ declare const TableHeader: React.ForwardRefExoticComponent<TableHeaderProps & React.RefAttributes<HTMLDivElement>>;
10
+ export default TableHeader;
@@ -0,0 +1,13 @@
1
+ import { default as React } from 'react';
2
+ import { PivotParams } from '../../types';
3
+
4
+ interface VirtualTableProps extends PivotParams {
5
+ scroll?: {
6
+ x?: number | string;
7
+ y?: number | string;
8
+ };
9
+ className?: string;
10
+ style?: React.CSSProperties;
11
+ }
12
+ declare const _default: React.MemoExoticComponent<(props: VirtualTableProps) => import("react/jsx-runtime").JSX.Element>;
13
+ export default _default;
@@ -0,0 +1,4 @@
1
+ export { default as VirtualTable } from './components/VirtualTable';
2
+ export * from './types';
3
+ export { dataHandler } from './utils/dataHandler';
4
+ export { default as pivotDataHandler } from './utils/pivotHandler';
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .virtual-table .virtual-table-container:before,.virtual-table .virtual-table-container:after{display:none}.virtual-table,.virtual-table .virtual-table{--virtual-table-scrollbar-width: 0px !important}.virtual-table table{table-layout:fixed!important;width:100%!important;border-spacing:0}.virtual-table .virtual-table-header th.virtual-table-cell{background:#fafafa;border-bottom:1px solid #e8e8e8;font-weight:500;padding:10px 16px;border-right:1px solid #e8e8e8;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.virtual-table .virtual-table-thead>tr:first-child>th{border-top:1px solid #e8e8e8}.virtual-table .virtual-table-thead>tr>th:first-child{border-left:1px solid #e8e8e8}.virtual-table .virtual-table-thead>tr:not(:last-child)>th[colspan]{border-bottom:1px solid #e8e8e8}.virtual-table-cell{box-sizing:border-box;padding:10px 16px;line-height:1.5;border-bottom:1px solid #e8e8e8;background:#fff}[data-theme=dark] .virtual-table-cell{box-sizing:border-box;line-height:1.5;padding:10px 16px;border-bottom:1px solid #303030;background:#141414}[data-theme=dark] .virtual-table .virtual-table-header th.virtual-table-cell{background:#1d1d1d;border-bottom:1px solid #303030;border-right:1px solid #303030}[data-theme=dark] .virtual-table .virtual-table-thead>tr:not(:last-child)>th[colspan]{border-bottom:1px solid #303030}.expand-icon{cursor:pointer;color:var(--primary-color);margin-right:4px;line-height:0}.hide-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.hide-scrollbar::-webkit-scrollbar{display:none}
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,80 @@
1
+ import { default as React } from 'react';
2
+
3
+ export interface CustomTreeNode {
4
+ /**
5
+ * 字段唯一标识
6
+ */
7
+ field: string;
8
+ /**
9
+ * 标题
10
+ */
11
+ title?: string;
12
+ /**
13
+ * 是否收起(默认都展开)
14
+ * @description 优先级 `collapseFields` > `expandDepth` > `collapseAll` > `collapsed`
15
+ */
16
+ collapsed?: boolean;
17
+ /**
18
+ * 字段描述
19
+ */
20
+ description?: string;
21
+ /**
22
+ * 子节点
23
+ */
24
+ children?: CustomTreeNode[];
25
+ width?: number | string;
26
+ total?: {
27
+ enabled: boolean;
28
+ label?: string;
29
+ position?: 'top' | 'bottom';
30
+ };
31
+ emptyReplace?: string;
32
+ calculateType?: 'sum' | 'avg' | 'count' | 'min' | 'max' | 'd_count' | 'variance' | 'stddev';
33
+ sort?: {
34
+ enabled: boolean;
35
+ type: 'asc' | 'desc';
36
+ };
37
+ style?: React.CSSProperties;
38
+ fixed?: boolean | string;
39
+ colSpan?: number;
40
+ dataIndex?: string;
41
+ render?: (val: any, record: any, index: number) => React.ReactNode;
42
+ type?: string;
43
+ }
44
+ export interface DataCell {
45
+ content: string | number | null | undefined;
46
+ rowspan: number;
47
+ colspan: number;
48
+ data?: any;
49
+ rowKey?: string;
50
+ expandable?: boolean;
51
+ expanded?: boolean;
52
+ level?: number;
53
+ onClick?: (record: any) => void;
54
+ style?: React.CSSProperties;
55
+ }
56
+ export interface TableRow {
57
+ cells: DataCell[];
58
+ rowKey: string;
59
+ }
60
+ export interface MetaItem {
61
+ field?: string;
62
+ title?: string;
63
+ description?: string;
64
+ clickHandler?: (data: any) => void;
65
+ }
66
+ export interface SortParam {
67
+ field: string;
68
+ sortType: 'asc' | 'desc';
69
+ }
70
+ export interface PivotFields {
71
+ rows: CustomTreeNode[];
72
+ columns: CustomTreeNode[];
73
+ values: CustomTreeNode[];
74
+ }
75
+ export interface PivotParams {
76
+ data: any[];
77
+ meta: MetaItem[];
78
+ sortParams: SortParam[];
79
+ fields: PivotFields;
80
+ }
@@ -0,0 +1 @@
1
+ export declare const cloneDeep: <T>(obj: T) => T;
@@ -0,0 +1,47 @@
1
+ import { PivotParams, DataCell, TableRow } from '../types';
2
+
3
+ export declare const dataHandler: (params: PivotParams) => {
4
+ list: never[];
5
+ dataExpandFilter: (list: any[]) => any[];
6
+ tableColumns?: undefined;
7
+ } | {
8
+ list: {
9
+ cells: DataCell[];
10
+ rowKey: string;
11
+ }[];
12
+ dataExpandFilter: (list: TableRow[]) => TableRow[];
13
+ tableColumns: import('../types').CustomTreeNode[];
14
+ } | {
15
+ list: never[];
16
+ dataExpandFilter: (l: any) => any;
17
+ tableColumns?: undefined;
18
+ } | {
19
+ list: TableRow[];
20
+ dataExpandFilter: (l: any[]) => any[];
21
+ tableColumns: {
22
+ width: string | number;
23
+ key: string;
24
+ field: string;
25
+ title?: string;
26
+ collapsed?: boolean;
27
+ description?: string;
28
+ children?: import('../types').CustomTreeNode[];
29
+ total?: {
30
+ enabled: boolean;
31
+ label?: string;
32
+ position?: "top" | "bottom";
33
+ };
34
+ emptyReplace?: string;
35
+ calculateType?: "sum" | "avg" | "count" | "min" | "max" | "d_count" | "variance" | "stddev";
36
+ sort?: {
37
+ enabled: boolean;
38
+ type: "asc" | "desc";
39
+ };
40
+ style?: React.CSSProperties;
41
+ fixed?: boolean | string;
42
+ colSpan?: number;
43
+ dataIndex?: string;
44
+ render?: (val: any, record: any, index: number) => React.ReactNode;
45
+ type?: string;
46
+ }[];
47
+ };
@@ -0,0 +1,15 @@
1
+ import { CustomTreeNode, PivotParams, DataCell, TableRow } from '../types';
2
+
3
+ declare const pivotDataHandler: (params: PivotParams) => {
4
+ list: never[];
5
+ dataExpandFilter: (list: any[]) => any[];
6
+ tableColumns?: undefined;
7
+ } | {
8
+ list: {
9
+ cells: DataCell[];
10
+ rowKey: string;
11
+ }[];
12
+ dataExpandFilter: (list: TableRow[]) => TableRow[];
13
+ tableColumns: CustomTreeNode[];
14
+ };
15
+ export default pivotDataHandler;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 表格中,单元格的值为该值时不显示单元格
3
+ * 用于与空值区分
4
+ */
5
+ export declare const DISPLAY_NONE = "display__none";
6
+ export declare const ROW_HEIGHT = 43;
7
+ export declare const COL_WIDTH = 100;
8
+ export declare const EMPTY_VALUE = "-";
9
+ export declare const TOTAL_DEFAULT_VALUE = "\u5408\u8BA1";