Skip to content

Commit 6befa63

Browse files
committed
bump to 1.2.1
1 parent b4caeda commit 6befa63

File tree

9 files changed

+97
-64
lines changed

9 files changed

+97
-64
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# CHANGELOG
22

3+
## 1.2.1
4+
5+
_2024-12-19_
6+
7+
### Features
8+
9+
- on initial render, the widths of the column are initialized correctly.
10+
- small typescript changes to remove usage of `any`
11+
312
## 1.2.0
413

514
_2024-12-18_

example/src/Props.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const columns: ColumnProps<PropData>[] = [
3030
key: "type",
3131
header: "Type",
3232
minWidth: 120,
33-
maxWidth: 170,
33+
maxWidth: 270,
3434
content: ({ row }: { row: PropData }) => <code>{row.type}</code>
3535
},
3636
{
@@ -53,6 +53,7 @@ const columns: ColumnProps<PropData>[] = [
5353
{
5454
key: "description",
5555
header: "Description",
56+
minWidth: 200,
5657
content: ({ row }: { row: PropData }) => row.description
5758
}
5859
];

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-fluid-table",
3-
"version": "1.2.0",
3+
"version": "1.2.1",
44
"description": "A React table inspired by @tanstack/react-virtual",
55
"author": "Mckervin Ceme <mckervinc@live.com>",
66
"license": "MIT",

src/Table.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { forwardRef, useEffect, useMemo, useState } from "react";
2-
import { ColumnProps, TableProps, TableRef } from "../index";
2+
import { TableProps, TableRef } from "../index";
33
import AutoSizer from "./AutoSizer";
44
import List from "./components/List";
55
import { positive, randomString } from "./util";
@@ -78,12 +78,12 @@ const Table = forwardRef(function <T>(
7878
height={height}
7979
data={data}
8080
rowHeight={rowHeight}
81-
itemKey={itemKey as any}
82-
onRowClick={onRowClick as any}
83-
rowRenderer={rowRenderer as any}
84-
onExpandRow={onExpandRow as any}
85-
subComponent={subComponent as any}
86-
columns={columns as ColumnProps<any>[]}
81+
itemKey={itemKey}
82+
onRowClick={onRowClick}
83+
rowRenderer={rowRenderer}
84+
onExpandRow={onExpandRow}
85+
subComponent={subComponent}
86+
columns={columns}
8787
{...props}
8888
/>
8989
);

src/components/Footer.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useEffect, useRef } from "react";
1+
import React, { memo, useCallback, useEffect, useRef } from "react";
22
import { ColumnProps, FooterProps } from "../..";
33
import { cx, findTableByUuid } from "../util";
44

@@ -9,7 +9,7 @@ type InnerFooterCellProps<T> = {
99
rows: T[];
1010
};
1111

12-
const FooterCell = React.memo(function <T>({ prevWidth, rows, ...rest }: InnerFooterCellProps<T>) {
12+
function BaseFooterCell<T>({ prevWidth, rows, ...rest }: InnerFooterCellProps<T>) {
1313
// instance
1414
const { width, column } = rest;
1515
const style: React.CSSProperties = {
@@ -24,9 +24,10 @@ const FooterCell = React.memo(function <T>({ prevWidth, rows, ...rest }: InnerFo
2424
{!!column.footer && <column.footer rows={rows} {...rest} />}
2525
</div>
2626
);
27-
});
27+
}
2828

29-
FooterCell.displayName = "FooterCell";
29+
const FooterCell = memo(BaseFooterCell) as <T>(props: InnerFooterCellProps<T>) => React.JSX.Element;
30+
(FooterCell as React.FC).displayName = "FooterCell";
3031

3132
type InnerFooterProps<T> = {
3233
uuid: string;
@@ -122,7 +123,7 @@ function Footer<T>({
122123
{columns.map((c, i) => (
123124
<FooterCell
124125
key={c.key}
125-
column={c as any}
126+
column={c}
126127
rows={rows}
127128
width={pixelWidths[i]}
128129
prevWidth={c.frozen ? pixelWidths.slice(0, i).reduce((pv, c) => pv + c, 0) : 0}

src/components/Header.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type HeaderCellProps<T> = {
1111
onHeaderClick: (column: ColumnProps<T>) => void;
1212
};
1313

14-
const HeaderCell = memo(function <T>({
14+
function BaseHeaderCell<T>({
1515
column,
1616
width,
1717
prevWidth,
@@ -53,9 +53,10 @@ const HeaderCell = memo(function <T>({
5353
style={{ ...style, ...frozenStyle }}
5454
/>
5555
);
56-
});
56+
}
5757

58-
HeaderCell.displayName = "HeaderCell";
58+
const HeaderCell = memo(BaseHeaderCell) as <T>(props: HeaderCellProps<T>) => React.JSX.Element;
59+
(HeaderCell as React.FC).displayName = "HeaderCell";
5960

6061
type HeaderProps<T> = {
6162
uuid: string;
@@ -124,8 +125,8 @@ const Header = forwardRef(function <T>(
124125
width={pixelWidths[i]}
125126
sortedCol={sortedCol}
126127
sortedDir={sortedDir}
127-
column={c as ColumnProps<any>}
128-
onHeaderClick={onHeaderClick as any}
128+
column={c}
129+
onHeaderClick={onHeaderClick}
129130
prevWidth={c.frozen ? pixelWidths.slice(0, i).reduce((pv, c) => pv + c, 0) : 0}
130131
/>
131132
))}

src/components/List.tsx

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, {
44
useCallback,
55
useEffect,
66
useImperativeHandle,
7+
useLayoutEffect,
78
useRef,
89
useState
910
} from "react";
@@ -27,7 +28,7 @@ const syncScroll = (source: HTMLElement | null, target: HTMLElement | null) => {
2728
}
2829
};
2930

30-
const List = forwardRef(function <T>(
31+
function BaseList<T>(
3132
{
3233
id,
3334
uuid,
@@ -63,8 +64,11 @@ const List = forwardRef(function <T>(
6364
const parentRef = useRef<HTMLDivElement | null>(null);
6465
const headerRef = useRef<HTMLDivElement | null>(null);
6566
const { ref: innerRef, width: innerWidth = 0 } = useResizeDetector<HTMLDivElement>();
66-
const [pixelWidths, setPixelWidths] = useState<number[]>([]);
6767
const [widthConstants, setWidthConstants] = useState(findColumnWidthConstants(columns));
68+
const [pixelWidths, setPixelWidths] = useState<number[]>(() => {
69+
const { fixedWidth, remainingCols } = widthConstants;
70+
return calculateColumnWidths(width, remainingCols, fixedWidth, minColumnWidth, columns);
71+
});
6872
const [expandedCache, setExpandedCache] = useState<Record<string | number, boolean>>({});
6973
const generateKeyFromRow = useCallback(
7074
(row: T, defaultValue: number) => itemKey?.(row) ?? defaultValue,
@@ -83,18 +87,6 @@ const List = forwardRef(function <T>(
8387
const { fixedWidth, remainingCols } = widthConstants;
8488

8589
// functions
86-
const updatePixelWidths = useCallback(() => {
87-
const widths = calculateColumnWidths(
88-
parentRef.current,
89-
remainingCols,
90-
fixedWidth,
91-
minColumnWidth,
92-
columns
93-
);
94-
if (!arraysMatch(widths, pixelWidths)) {
95-
setPixelWidths(widths);
96-
}
97-
}, [remainingCols, fixedWidth, minColumnWidth, pixelWidths, columns]);
9890
const isRowExpanded = typeof expandedRows === "function" ? expandedRows : undefined;
9991

10092
const onExpand = useCallback(
@@ -119,7 +111,18 @@ const List = forwardRef(function <T>(
119111

120112
// effects
121113
// update pixel widths every time the width changes
122-
useEffect(() => updatePixelWidths(), [width]);
114+
useLayoutEffect(() => {
115+
const widths = calculateColumnWidths(
116+
parentRef.current?.clientWidth ?? width,
117+
remainingCols,
118+
fixedWidth,
119+
minColumnWidth,
120+
columns
121+
);
122+
if (!arraysMatch(widths, pixelWidths)) {
123+
setPixelWidths(widths);
124+
}
125+
}, [width, remainingCols, fixedWidth, minColumnWidth, pixelWidths, columns]);
123126

124127
// set the width constants
125128
useEffect(() => setWidthConstants(findColumnWidthConstants(columns)), [columns]);
@@ -198,13 +201,13 @@ const List = forwardRef(function <T>(
198201
style={style}
199202
className={className}
200203
isExpanded={isExpanded}
201-
onRowClick={onRowClick as any}
202-
rowRenderer={rowRenderer as any}
203-
onExpand={onExpand as any}
204+
onRowClick={onRowClick}
205+
rowRenderer={rowRenderer}
206+
onExpand={onExpand}
204207
index={index}
205-
columns={columns as any}
208+
columns={columns}
206209
pixelWidths={pixelWidths}
207-
subComponent={subComponent as any}
210+
subComponent={subComponent}
208211
/>
209212
);
210213
})}
@@ -215,14 +218,19 @@ const List = forwardRef(function <T>(
215218
uuid={uuid}
216219
rows={data}
217220
sticky={stickyFooter}
218-
columns={columns as ColumnProps<any>[]}
221+
columns={columns}
219222
pixelWidths={pixelWidths}
220223
className={footerClassname}
221224
style={footerStyle}
222-
component={footerComponent as any}
225+
component={footerComponent}
223226
/>
224227
</div>
225228
);
226-
});
229+
}
230+
231+
const List = forwardRef(BaseList) as <T>(
232+
props: ListProps<T> & { ref?: React.ForwardedRef<TableRef> }
233+
) => React.JSX.Element;
234+
(List as React.FC).displayName = "List";
227235

228236
export default List;

src/components/Row.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type TableCellProps<T> = {
1414
onExpanderClick: (event?: React.MouseEvent<Element, MouseEvent>) => void;
1515
};
1616

17-
const TableCell = memo(function <T>({
17+
function BaseTableCell<T>({
1818
row,
1919
index,
2020
width,
@@ -93,9 +93,10 @@ const TableCell = memo(function <T>({
9393
// custom cell styling
9494
const frozenStyle: React.CSSProperties = column.frozen ? { position: "sticky", zIndex: 2 } : {};
9595
return <column.cell row={row} index={index} style={{ ...style, ...frozenStyle }} />;
96-
});
96+
}
9797

98-
TableCell.displayName = "TableCell";
98+
const TableCell = memo(BaseTableCell) as <T>(props: TableCellProps<T>) => React.JSX.Element;
99+
(TableCell as React.FC).displayName = "TableCell";
99100

100101
type RowComponentProps<T> = {
101102
row: T;
@@ -167,7 +168,7 @@ type RowProps<T> = {
167168
rowRenderer?: (props: RowRenderProps<T>) => JSX.Element;
168169
};
169170

170-
const Row = forwardRef(function <T>(
171+
function BaseRow<T>(
171172
{
172173
uuid,
173174
index,
@@ -205,7 +206,7 @@ const Row = forwardRef(function <T>(
205206
<TableCell
206207
key={`${uuid}-${rowKey}-${i}`}
207208
row={row}
208-
column={c as any}
209+
column={c}
209210
index={index}
210211
width={pixelWidths[i]}
211212
isExpanded={isExpanded}
@@ -221,8 +222,11 @@ const Row = forwardRef(function <T>(
221222
)}
222223
</div>
223224
);
224-
});
225+
}
225226

226-
Row.displayName = "Row";
227+
const Row = forwardRef(BaseRow) as <T>(
228+
props: RowProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }
229+
) => React.JSX.Element;
230+
(Row as React.FC).displayName = "Row";
227231

228232
export default Row;

src/util.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import { ColumnProps } from "..";
55
* @param classes list of potential className strings
66
* @returns a combined className string
77
*/
8-
export const cx = (...args: (string | number | null | boolean | undefined)[]) => {
8+
const cx = (...args: (string | number | null | boolean | undefined)[]) => {
99
return args
1010
.flat()
1111
.filter((x): x is Exclude<typeof x, null | undefined> => !!x)
1212
.map(x => x.toString().trim())
1313
.join(" ");
1414
};
1515

16-
export const arraysMatch = <T>(arr1: T[] | null | undefined, arr2: T[] | null | undefined) => {
16+
const arraysMatch = <T>(arr1: T[] | null | undefined, arr2: T[] | null | undefined) => {
1717
if (arr1 == null && arr2 == null) {
1818
return true;
1919
}
@@ -35,7 +35,7 @@ export const arraysMatch = <T>(arr1: T[] | null | undefined, arr2: T[] | null |
3535
return false;
3636
};
3737

38-
export const randomString = (num: number) => {
38+
const randomString = (num: number) => {
3939
let result = "";
4040
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
4141
const length = characters.length;
@@ -45,25 +45,22 @@ export const randomString = (num: number) => {
4545
return result;
4646
};
4747

48-
export const findTableByUuid = (uuid: string): HTMLElement | null =>
49-
document.querySelector(`[data-table-key='${uuid}']`);
48+
const findElementByValue = (value: string) => document.querySelector<HTMLElement>(value);
5049

51-
export const findHeaderByUuid = (uuid: string): HTMLElement | null =>
52-
document.querySelector(`[data-header-key='${uuid}-header']`);
50+
const findTableByUuid = (uuid: string) => findElementByValue(`[data-table-key='${uuid}']`);
5351

54-
export const findFooterByUuid = (uuid: string): HTMLElement | null =>
55-
document.querySelector(`[data-footer-key='${uuid}-footer']`);
52+
const findHeaderByUuid = (uuid: string) => findElementByValue(`[data-header-key='${uuid}-header']`);
53+
54+
const findFooterByUuid = (uuid: string) => findElementByValue(`[data-footer-key='${uuid}-footer']`);
5655

5756
// table utilities
58-
export const calculateColumnWidths = <T>(
59-
element: HTMLElement | null,
57+
const calculateColumnWidths = <T>(
58+
clientWidth: number,
6059
numColumns: number,
6160
fixedColumnWidths: number,
6261
minColumnWidth: number,
6362
columns: ColumnProps<T>[]
6463
) => {
65-
if (!element) return columns.map(() => minColumnWidth);
66-
const clientWidth = element.clientWidth;
6764
let n = Math.max(numColumns, 1);
6865
let usedSpace = fixedColumnWidths;
6966
let freeSpace = Math.max(clientWidth - usedSpace, 0);
@@ -99,7 +96,7 @@ export const calculateColumnWidths = <T>(
9996
});
10097
};
10198

102-
export const findColumnWidthConstants = <T>(columns: ColumnProps<T>[]) => {
99+
const findColumnWidthConstants = <T>(columns: ColumnProps<T>[]) => {
103100
return columns.reduce(
104101
(pv, c) => ({
105102
fixedWidth: pv.fixedWidth + (c.width || 0),
@@ -109,4 +106,16 @@ export const findColumnWidthConstants = <T>(columns: ColumnProps<T>[]) => {
109106
);
110107
};
111108

112-
export const positive = (x: number | null | undefined): x is number => x != null && x > 0;
109+
const positive = (x: number | null | undefined): x is number => x != null && x > 0;
110+
111+
export {
112+
arraysMatch,
113+
calculateColumnWidths,
114+
cx,
115+
positive,
116+
findColumnWidthConstants,
117+
findFooterByUuid,
118+
findHeaderByUuid,
119+
findTableByUuid,
120+
randomString
121+
};

0 commit comments

Comments
 (0)