Skip to content

Commit 6beaf15

Browse files
committed
WIP
1 parent 27125f8 commit 6beaf15

File tree

17 files changed

+753
-4
lines changed

17 files changed

+753
-4
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "vuu-tanstack-table",
3+
"version": "0.0.26",
4+
"author": "heswell",
5+
"main": "src/index.ts",
6+
"license": "Apache-2.0",
7+
"scripts": {
8+
"build:dev": "node ../../scripts/run-build.mjs",
9+
"build": "node ../../scripts/run-build-rollup.mjs",
10+
"type-defs": "node ../../scripts/build-type-defs.mjs"
11+
},
12+
"devDependencies": {},
13+
"dependencies": {
14+
"@finos/vuu-table-types": "0.0.26",
15+
"@salt-ds/core": "1.43.0",
16+
"@salt-ds/styles": "0.2.1",
17+
"@salt-ds/window": "0.1.1",
18+
"@tanstack/react-table": "^8.21.2",
19+
"@tanstack/react-virtual": "^3.13.6"
20+
},
21+
"peerDependencies": {
22+
"clsx": "^2.0.0",
23+
"react": "^18.3.1",
24+
"react-dom": "^18.3.1"
25+
}
26+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.TanstackTable {
2+
tr {
3+
height: 33px;
4+
}
5+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import React, { useRef } from "react";
2+
import { useComponentCssInjection } from "@salt-ds/styles";
3+
import { useWindow } from "@salt-ds/window";
4+
import { flexRender } from "@tanstack/react-table";
5+
import {
6+
TanstackTableProps,
7+
useTanstackTableWithVuuDatasource,
8+
} from "./useTanstackTableWithVuuDatasource";
9+
import { PaginationControl } from "@finos/vuu-table";
10+
11+
import tableCss from "./TanstackTable.css";
12+
13+
const classBase = "TanstackTable";
14+
15+
export const TanstackTable = ({ columns }: TanstackTableProps) => {
16+
const targetWindow = useWindow();
17+
useComponentCssInjection({
18+
testId: "vuu-table",
19+
css: tableCss,
20+
window: targetWindow,
21+
});
22+
23+
const parentRef = useRef<HTMLDivElement>(null);
24+
25+
const { dataSource, table } = useTanstackTableWithVuuDatasource({ columns });
26+
27+
const { rows } = table.getRowModel();
28+
29+
// const virtualizer = useVirtualizer({
30+
// count: rows.length,
31+
// getScrollElement: () => parentRef.current,
32+
// estimateSize: () => 34,
33+
// overscan: 20,
34+
// });
35+
36+
return (
37+
<div className={classBase}>
38+
<div ref={parentRef} className="container">
39+
{/* <div style={{ height: `${virtualizer.getTotalSize()}px` }}> */}
40+
<div>
41+
<table>
42+
<thead>
43+
{table.getHeaderGroups().map((headerGroup) => (
44+
<tr key={headerGroup.id}>
45+
{headerGroup.headers.map((header) => {
46+
return (
47+
<th
48+
key={header.id}
49+
colSpan={header.colSpan}
50+
style={{ width: header.getSize() }}
51+
>
52+
{header.isPlaceholder ? null : (
53+
<div
54+
{...{
55+
className: header.column.getCanSort()
56+
? "cursor-pointer select-none"
57+
: "",
58+
onClick: header.column.getToggleSortingHandler(),
59+
}}
60+
>
61+
{flexRender(
62+
header.column.columnDef.header,
63+
header.getContext(),
64+
)}
65+
{{
66+
asc: " 🔼",
67+
desc: " 🔽",
68+
}[header.column.getIsSorted() as string] ?? null}
69+
</div>
70+
)}
71+
</th>
72+
);
73+
})}
74+
</tr>
75+
))}
76+
</thead>
77+
<tbody>
78+
{rows.map((row) => {
79+
return (
80+
<tr key={row.id}>
81+
{row.getVisibleCells().map((cell) => {
82+
return (
83+
<td key={cell.id}>
84+
{flexRender(
85+
cell.column.columnDef.cell,
86+
cell.getContext(),
87+
)}
88+
</td>
89+
);
90+
})}
91+
</tr>
92+
);
93+
})}
94+
</tbody>
95+
</table>
96+
</div>
97+
</div>
98+
<PaginationControl dataSource={dataSource} />
99+
</div>
100+
);
101+
};
102+
103+
/**
104+
*
105+
* {virtualizer.getVirtualItems().map((virtualRow, index) => {
106+
const row = rows[virtualRow.index];
107+
console.log(`[TanstackTable] [${index}]`, {
108+
virtualRow,
109+
});
110+
return (
111+
<tr
112+
113+
*/
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { createRow } from "@tanstack/react-table";
2+
import type { Table, Row, RowModel, RowData } from "@tanstack/react-table";
3+
import { getMemoOptions, memo } from "./utils";
4+
5+
export function getCoreRowModel<TData extends RowData>(): (
6+
table: Table<TData>,
7+
) => () => RowModel<TData> {
8+
return (table) =>
9+
memo(
10+
() => [table.options.data],
11+
(
12+
data,
13+
): {
14+
rows: Row<TData>[];
15+
flatRows: Row<TData>[];
16+
rowsById: Record<string, Row<TData>>;
17+
} => {
18+
const rowModel: RowModel<TData> = {
19+
rows: [],
20+
flatRows: [],
21+
rowsById: {},
22+
};
23+
24+
const accessRows = (
25+
originalRows: TData[],
26+
depth = 0,
27+
parentRow?: Row<TData>,
28+
): Row<TData>[] => {
29+
const rows = [] as Row<TData>[];
30+
31+
for (let i = 0; i < originalRows.length; i++) {
32+
// This could be an expensive check at scale, so we should move it somewhere else, but where?
33+
// if (!id) {
34+
// if (process.env.NODE_ENV !== 'production') {
35+
// throw new Error(`getRowId expected an ID, but got ${id}`)
36+
// }
37+
// }
38+
39+
// Make the row
40+
const row = createRow(
41+
table,
42+
table._getRowId(originalRows[i]!, i, parentRow),
43+
originalRows[i]!,
44+
i,
45+
depth,
46+
undefined,
47+
parentRow?.id,
48+
);
49+
50+
// Keep track of every row in a flat array
51+
rowModel.flatRows.push(row);
52+
// Also keep track of every row by its ID
53+
rowModel.rowsById[row.id] = row;
54+
// Push table row into parent
55+
rows.push(row);
56+
57+
// Get the original subrows
58+
if (table.options.getSubRows) {
59+
row.originalSubRows = table.options.getSubRows(
60+
originalRows[i]!,
61+
i,
62+
);
63+
64+
// Then recursively access them
65+
if (row.originalSubRows?.length) {
66+
row.subRows = accessRows(row.originalSubRows, depth + 1, row);
67+
}
68+
}
69+
}
70+
71+
return rows;
72+
};
73+
74+
rowModel.rows = accessRows(data);
75+
76+
return rowModel;
77+
},
78+
getMemoOptions(table.options, "debugTable", "getRowModel", () =>
79+
table._autoResetPageIndex(),
80+
),
81+
);
82+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./TanstackTable";
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { SimulTableName, vuuModule } from "@finos/vuu-data-test";
2+
import { DataSource, SubscribeCallback } from "@finos/vuu-data-types";
3+
import { VuuDataRow } from "@finos/vuu-protocol-types";
4+
import {
5+
OnChangeFn,
6+
type SortingState,
7+
useReactTable,
8+
} from "@tanstack/react-table";
9+
import { useCallback, useMemo, useRef, useState } from "react";
10+
import { getCoreRowModel } from "./getCoreRowModel";
11+
import {
12+
tanstackSortToVuuSort,
13+
vuuColumnsToTanstackColumns,
14+
} from "./vuu-tanstack-utils";
15+
import { ColumnDescriptor } from "@finos/vuu-table-types";
16+
import { buildReverseColumnMap, ReverseColumnMap } from "@finos/vuu-utils";
17+
18+
const NO_DATA: VuuDataRow[] = [] as const;
19+
const NO_SORT: SortingState = [] as const;
20+
21+
export interface TanstackTableProps {
22+
debug?: string;
23+
columns: ColumnDescriptor[];
24+
}
25+
26+
export const useTanstackTableWithVuuDatasource = ({
27+
columns,
28+
}: TanstackTableProps) => {
29+
const [data, setData] = useState<VuuDataRow[]>(NO_DATA);
30+
const sortStateRef = useRef<SortingState>(NO_SORT);
31+
32+
const tanstackColumns = vuuColumnsToTanstackColumns(columns);
33+
console.log({ sortState: sortStateRef.current, tanstackColumns });
34+
35+
const [dataSource, reverseColumnMap] = useMemo<
36+
[DataSource, ReverseColumnMap]
37+
>(() => {
38+
const ds =
39+
vuuModule<SimulTableName>("SIMUL").createDataSource("instruments");
40+
41+
const dataSourceMessageHandler: SubscribeCallback = (message) => {
42+
switch (message.type) {
43+
case "subscribed":
44+
console.log("[useVuuData] dataSourceMessageHandler subscribed");
45+
break;
46+
case "viewport-update":
47+
console.log({ message });
48+
if (message.rows) {
49+
setData(message.rows);
50+
}
51+
break;
52+
default:
53+
console.log(
54+
`[useVuuData] dataSourceMessageHandler message type ${message.type}`,
55+
);
56+
}
57+
};
58+
59+
ds.subscribe(
60+
{
61+
range: { from: 0, to: 16 },
62+
},
63+
dataSourceMessageHandler,
64+
);
65+
66+
const columnMap = buildReverseColumnMap(ds.columns);
67+
68+
return [ds, columnMap];
69+
}, []);
70+
71+
const handleSortRequest = useCallback<OnChangeFn<SortingState>>(
72+
(updaterOrValue) => {
73+
sortStateRef.current =
74+
typeof updaterOrValue === "function"
75+
? updaterOrValue(sortStateRef.current)
76+
: updaterOrValue;
77+
dataSource.sort = tanstackSortToVuuSort(
78+
sortStateRef.current,
79+
reverseColumnMap,
80+
);
81+
},
82+
[dataSource, reverseColumnMap],
83+
);
84+
85+
const table = useReactTable({
86+
data,
87+
columns: tanstackColumns,
88+
onSortingChange: handleSortRequest,
89+
getCoreRowModel: getCoreRowModel(),
90+
debugTable: true,
91+
manualPagination: true,
92+
rowCount: dataSource.size,
93+
state: {
94+
sorting: sortStateRef.current,
95+
},
96+
});
97+
98+
return {
99+
dataSource,
100+
table,
101+
};
102+
};

0 commit comments

Comments
 (0)