Skip to content

Commit 5e9e006

Browse files
authored
Merge pull request #83 from mckervinc/feature/tweaks
v0.4.10
2 parents df17aab + db359b0 commit 5e9e006

File tree

14 files changed

+466
-414
lines changed

14 files changed

+466
-414
lines changed

CHANGELOG.md

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

3+
## 0.4.10
4+
5+
_2023-09-30_
6+
7+
###
8+
9+
- added ability to specify the `footerHeight`
10+
- removed some typescript warnings
11+
- slight performance tweaks
12+
313
## 0.4.7
414

515
_2023-09-28_

example/src/Props.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ const data: PropData[] = [
145145
description:
146146
"This is a fixed height of each row. Subcomponents will not be affected by this value"
147147
},
148+
{
149+
prop: "headerHeight",
150+
type: "number",
151+
description: "This is an optional fixed height of the header"
152+
},
153+
{
154+
prop: "footerHeight",
155+
type: "number",
156+
description: "This is an optional fixed height of the footer"
157+
},
148158
{
149159
prop: "minColumnWidth",
150160
type: "number",
@@ -411,7 +421,8 @@ const Props = () => (
411421
<Header dividing size="small" color="grey">
412422
Interfaces
413423
</Header>
414-
<Snippet code={`import { CSSProperties, ForwardedRef, ReactNode } from "react";
424+
<Snippet
425+
code={`import { CSSProperties, ForwardedRef, ReactNode } from "react";
415426
416427
type SortDirection = "ASC" | "DESC" | null;
417428
@@ -647,6 +658,10 @@ interface TableProps<T> {
647658
* specify a fixed header height
648659
*/
649660
headerHeight?: number;
661+
/**
662+
* specify a fixed footer height
663+
*/
664+
footerHeight?: number;
650665
/**
651666
* Enable or disable row borders. Default: \`false\`.
652667
*/
@@ -716,7 +731,8 @@ interface TableProps<T> {
716731
*/
717732
ref?: ForwardedRef<TableRef>;
718733
}
719-
`} />
734+
`}
735+
/>
720736
</Container>
721737
);
722738

example/src/examples/07-controlled.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable @typescript-eslint/ban-ts-comment */
21
import {
32
randCatchPhrase,
43
randCity,
@@ -115,19 +114,34 @@ const Controlled = ({ data, height, columns: variableColumns }: ControlledProps)
115114
);
116115
};
117116

117+
interface ToggleType {
118+
data: boolean;
119+
height: boolean;
120+
columns: boolean;
121+
}
122+
123+
interface DataType {
124+
data: TestData[];
125+
height: number;
126+
columns: ColumnProps<TestData>[];
127+
}
128+
129+
type keyM = keyof ToggleType;
130+
type keyD = keyof DataType;
131+
118132
const viewableTypes = new Set(["string", "number", "boolean"]);
119133

120134
const Example7 = () => {
121135
// hooks
122-
const [toggles, setToggles] = useState({
136+
const [toggles, setToggles] = useState<ToggleType>({
123137
data: false,
124138
height: false,
125139
columns: false
126140
});
127141

128142
// variables
129-
const keys = Object.keys(toggles);
130-
const props = {
143+
const keys: keyM[] = ["data", "height", "columns"];
144+
const props: DataType = {
131145
data: toggles.data ? testData2 : testData,
132146
height: toggles.height ? 200 : 400,
133147
columns: toggles.columns
@@ -187,22 +201,22 @@ const Example7 = () => {
187201
{"{\n"}
188202
{keys.map((key, index) => {
189203
const ending = index !== keys.length - 1 ? ",\n" : "\n";
190-
// @ts-ignore
191204
const val = viewableTypes.has(typeof props[key]);
192205
let color = "rgb(166, 226, 46)";
193-
// @ts-ignore
194206
if (typeof props[key] === "number") {
195207
color = "rgb(174, 129, 255)";
196-
// @ts-ignore
197208
} else if (typeof props[key] === "boolean") {
198209
color = "rgb(102, 217, 239)";
199210
}
200211
return (
201212
<React.Fragment key={key}>
202213
{` ${key}: `}
203214
<span style={{ color }}>
204-
{/* @ts-ignore */}
205-
{val ? props[key] : toggles[key] ? '"altered"' : '"original"'}
215+
{val
216+
? (props[key as keyD] as string | number)
217+
: toggles[key]
218+
? '"altered"'
219+
: '"original"'}
206220
</span>
207221
{ending}
208222
</React.Fragment>

index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ export interface TableProps<T> {
243243
* specify a fixed header height
244244
*/
245245
headerHeight?: number;
246+
/**
247+
* specify a fixed footer height
248+
*/
249+
footerHeight?: number;
246250
/**
247251
* Enable or disable row borders. Default: `false`.
248252
*/

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": "0.4.9",
3+
"version": "0.4.10",
44
"description": "A React table inspired by react-window",
55
"author": "Mckervin Ceme <mckervinc@live.com>",
66
"license": "MIT",

src/AutoSizer.tsx

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
22
import { TableContext } from "./TableContext";
3-
import { DEFAULT_HEADER_HEIGHT, DEFAULT_ROW_HEIGHT } from "./constants";
3+
import { DEFAULT_FOOTER_HEIGHT, DEFAULT_HEADER_HEIGHT, DEFAULT_ROW_HEIGHT } from "./constants";
44
import { findFooterByUuid, findHeaderByUuid } from "./util";
55

66
interface AutoSizerProps {
77
numRows: number;
88
rowHeight?: number;
99
headerHeight?: number;
10+
footerHeight?: number;
1011
tableWidth?: number;
1112
tableHeight?: number;
1213
minTableHeight?: number;
@@ -64,29 +65,34 @@ const findCorrectHeight = ({
6465
const calculateHeight = (
6566
rowHeight: number,
6667
headerHeight: number,
68+
footerHeight: number,
6769
uuid: string,
6870
size: number,
6971
hasFooter: boolean
7072
) => {
71-
// get the header, footer and nodes
73+
// get the header and the rows of the table
7274
const header = findHeaderByUuid(uuid);
7375
const nodes = [...(header?.nextElementSibling?.children || [])] as HTMLElement[];
74-
let footerHeight = findFooterByUuid(uuid)?.offsetHeight || 0;
7576

76-
if (!!header && !!nodes.length) {
77-
// header height to use
78-
const headerOffset = headerHeight > 0 ? headerHeight : header.offsetHeight;
77+
// calculate header & footer offsets
78+
const headerOffset =
79+
headerHeight > 0 ? headerHeight : header?.offsetHeight || DEFAULT_HEADER_HEIGHT;
80+
let footerOffset = 0;
81+
if (hasFooter) {
82+
footerOffset =
83+
footerHeight > 0
84+
? footerHeight
85+
: findFooterByUuid(uuid)?.offsetHeight || DEFAULT_FOOTER_HEIGHT;
86+
}
7987

80-
// get border height
81-
let borders = 0;
82-
const table = header.parentElement?.parentElement;
83-
if (!!table) {
84-
borders = table.offsetHeight - table.clientHeight;
85-
}
88+
// calculate border offset
89+
const table = header?.parentElement?.parentElement;
90+
const borderOffset = !!table ? table.offsetHeight - table.clientHeight : 0;
8691

87-
// perform calculation
92+
// if there are rows, let's do the calculation
93+
if (!!nodes.length) {
8894
if (rowHeight > 0) {
89-
return headerOffset + nodes.length * rowHeight + footerHeight + borders;
95+
return headerOffset + nodes.length * rowHeight + footerOffset + borderOffset;
9096
}
9197

9298
let overscan = 0;
@@ -97,20 +103,14 @@ const calculateHeight = (
97103
return pv + c.offsetHeight;
98104
}, 0) +
99105
overscan +
100-
footerHeight +
101-
borders
106+
footerOffset +
107+
borderOffset
102108
);
103109
}
104110

105-
// try and guess the header and footer height
106-
const headerOffset = headerHeight || DEFAULT_HEADER_HEIGHT;
107-
if (!footerHeight && hasFooter) {
108-
footerHeight = headerOffset;
109-
}
110-
111-
// if the header and nodes are not specified, guess the height
111+
// if the nodes are not specified, guess the height
112112
const height = Math.max(rowHeight || DEFAULT_ROW_HEIGHT, 10);
113-
return height * Math.min(size || 10, 10) + headerOffset + footerHeight;
113+
return headerOffset + height * Math.min(size || 10, 10) + footerOffset + borderOffset;
114114
};
115115

116116
/**
@@ -127,30 +127,38 @@ const AutoSizer = ({
127127
minTableHeight,
128128
maxTableHeight,
129129
headerHeight,
130+
footerHeight,
130131
children
131132
}: AutoSizerProps) => {
132133
// hooks
133134
const resizeRef = useRef(0);
134135
const ref = useRef<HTMLDivElement>(null);
135-
const { uuid, footerComponent, columns } = useContext(TableContext);
136+
const { uuid, columns, footerComponent } = useContext(TableContext);
136137
const [dimensions, setDimensions] = useState({ containerHeight: 0, containerWidth: 0 });
137138

138139
// variables
139140
const { containerHeight, containerWidth } = dimensions;
140-
141-
// check if footer exists
142-
const hasFooter = useMemo(() => {
143-
return !!footerComponent || !!columns.find(c => !!c.footer);
144-
}, [footerComponent, columns]);
141+
const hasFooter = useMemo(
142+
() => !!footerComponent || !!columns.find(c => !!c.footer),
143+
[columns, footerComponent]
144+
);
145+
const fixedTableSize = !!tableHeight && tableHeight > 0 && !!tableWidth && tableWidth > 0;
145146

146147
// calculate the computed height
147148
const computedHeight = useMemo(() => {
148149
if (!!tableHeight && tableHeight > 0) {
149150
return tableHeight;
150151
}
151152

152-
return calculateHeight(rowHeight || 0, headerHeight || 0, uuid, numRows, hasFooter);
153-
}, [tableHeight, rowHeight, headerHeight, numRows, uuid, hasFooter]);
153+
return calculateHeight(
154+
rowHeight || 0,
155+
headerHeight || 0,
156+
footerHeight || 0,
157+
uuid,
158+
numRows,
159+
hasFooter
160+
);
161+
}, [tableHeight, rowHeight, headerHeight, footerHeight, numRows, uuid, hasFooter]);
154162

155163
// calculate the actual height of the table
156164
const height = findCorrectHeight({
@@ -167,7 +175,7 @@ const AutoSizer = ({
167175
// functions
168176
const calculateDimensions = useCallback(() => {
169177
// base cases
170-
if (!ref.current?.parentElement) {
178+
if (!ref.current?.parentElement || fixedTableSize) {
171179
return;
172180
}
173181

@@ -184,10 +192,15 @@ const AutoSizer = ({
184192
const newWidth = Math.max((parent.offsetWidth || 0) - paddingLeft - paddingRight, 0);
185193

186194
// update state
187-
if (newHeight !== containerHeight || newWidth !== containerWidth) {
188-
setDimensions({ containerHeight: newHeight, containerWidth: newWidth });
189-
}
190-
}, [containerHeight, containerWidth]);
195+
setDimensions(prev => {
196+
const { containerHeight: oldHeight, containerWidth: oldWidth } = prev;
197+
if (oldHeight !== newHeight || oldWidth !== newWidth) {
198+
return { containerHeight: newHeight, containerWidth: newWidth };
199+
}
200+
201+
return prev;
202+
});
203+
}, [fixedTableSize]);
191204

192205
const onResize = useCallback(() => {
193206
window.clearTimeout(resizeRef.current);
@@ -196,10 +209,11 @@ const AutoSizer = ({
196209

197210
// effects
198211
// on mount, calculate the dimensions
199-
useEffect(() => calculateDimensions(), []);
212+
useEffect(() => calculateDimensions(), [calculateDimensions]);
200213

201214
// on resize, we have to re-calculate the dimensions
202215
useEffect(() => {
216+
window.removeEventListener("resize", onResize);
203217
window.addEventListener("resize", onResize);
204218
const m = resizeRef.current;
205219
return () => {

src/Footer.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ const FooterCell = React.memo(function <T>(props: InnerFooterCellProps<T>) {
1414

1515
// instance
1616
const { width, column } = props;
17+
const cellWidth = width ? `${width}px` : undefined;
1718
const style: React.CSSProperties = {
18-
width: width ? `${width}px` : undefined,
19-
minWidth: width ? `${width}px` : undefined,
19+
width: cellWidth,
20+
minWidth: cellWidth,
2021
padding: !column.footer ? 0 : undefined
2122
};
2223

src/Header.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ const HeaderCell = React.memo(function <T>({ column, width }: HeaderCellProps<T>
1919
const { dispatch, sortColumn: col, sortDirection, onSort } = useContext(TableContext);
2020

2121
// constants
22+
const cellWidth = width ? `${width}px` : undefined;
2223
const dir = sortDirection ? (sortDirection.toUpperCase() as SortDirection) : null;
2324

2425
const style: React.CSSProperties = {
2526
cursor: column.sortable ? "pointer" : undefined,
26-
width: width ? `${width}px` : undefined,
27-
minWidth: width ? `${width}px` : undefined
27+
width: cellWidth,
28+
minWidth: cellWidth
2829
};
2930

3031
// function(s)
@@ -61,7 +62,7 @@ const HeaderCell = React.memo(function <T>({ column, width }: HeaderCellProps<T>
6162
<div className="header-cell" onClick={onClick} style={style}>
6263
{column.header ? <div className="header-cell-text">{column.header}</div> : null}
6364
{column.key !== col ? null : (
64-
<div className={`header-cell-arrow ${(dir || "").toLowerCase()}`}></div>
65+
<div className={cx(["header-cell-arrow", dir?.toLowerCase()])}></div>
6566
)}
6667
</div>
6768
);

src/Row.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,10 @@ const TableCell = React.memo(function <T>({
7575
onExpanderClick
7676
}: TableCellProps<T>) {
7777
// cell width
78+
const cellWidth = width ? `${width}px` : undefined;
7879
const style: React.CSSProperties = {
79-
width: width ? `${width}px` : undefined,
80-
minWidth: width ? `${width}px` : undefined
80+
width: cellWidth,
81+
minWidth: cellWidth
8182
};
8283

8384
// expander

0 commit comments

Comments
 (0)