Skip to content

Commit

Permalink
bump to 1.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
mckervinc committed Dec 19, 2024
1 parent b4caeda commit 6befa63
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 64 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# CHANGELOG

## 1.2.1

_2024-12-19_

### Features

- on initial render, the widths of the column are initialized correctly.
- small typescript changes to remove usage of `any`

## 1.2.0

_2024-12-18_
Expand Down
3 changes: 2 additions & 1 deletion example/src/Props.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const columns: ColumnProps<PropData>[] = [
key: "type",
header: "Type",
minWidth: 120,
maxWidth: 170,
maxWidth: 270,
content: ({ row }: { row: PropData }) => <code>{row.type}</code>
},
{
Expand All @@ -53,6 +53,7 @@ const columns: ColumnProps<PropData>[] = [
{
key: "description",
header: "Description",
minWidth: 200,
content: ({ row }: { row: PropData }) => row.description
}
];
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-fluid-table",
"version": "1.2.0",
"version": "1.2.1",
"description": "A React table inspired by @tanstack/react-virtual",
"author": "Mckervin Ceme <mckervinc@live.com>",
"license": "MIT",
Expand Down
14 changes: 7 additions & 7 deletions src/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { forwardRef, useEffect, useMemo, useState } from "react";
import { ColumnProps, TableProps, TableRef } from "../index";
import { TableProps, TableRef } from "../index";
import AutoSizer from "./AutoSizer";
import List from "./components/List";
import { positive, randomString } from "./util";
Expand Down Expand Up @@ -78,12 +78,12 @@ const Table = forwardRef(function <T>(
height={height}
data={data}
rowHeight={rowHeight}
itemKey={itemKey as any}
onRowClick={onRowClick as any}
rowRenderer={rowRenderer as any}
onExpandRow={onExpandRow as any}
subComponent={subComponent as any}
columns={columns as ColumnProps<any>[]}
itemKey={itemKey}
onRowClick={onRowClick}
rowRenderer={rowRenderer}
onExpandRow={onExpandRow}
subComponent={subComponent}
columns={columns}
{...props}
/>
);
Expand Down
11 changes: 6 additions & 5 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useRef } from "react";
import React, { memo, useCallback, useEffect, useRef } from "react";
import { ColumnProps, FooterProps } from "../..";
import { cx, findTableByUuid } from "../util";

Expand All @@ -9,7 +9,7 @@ type InnerFooterCellProps<T> = {
rows: T[];
};

const FooterCell = React.memo(function <T>({ prevWidth, rows, ...rest }: InnerFooterCellProps<T>) {
function BaseFooterCell<T>({ prevWidth, rows, ...rest }: InnerFooterCellProps<T>) {
// instance
const { width, column } = rest;
const style: React.CSSProperties = {
Expand All @@ -24,9 +24,10 @@ const FooterCell = React.memo(function <T>({ prevWidth, rows, ...rest }: InnerFo
{!!column.footer && <column.footer rows={rows} {...rest} />}
</div>
);
});
}

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

type InnerFooterProps<T> = {
uuid: string;
Expand Down Expand Up @@ -122,7 +123,7 @@ function Footer<T>({
{columns.map((c, i) => (
<FooterCell
key={c.key}
column={c as any}
column={c}
rows={rows}
width={pixelWidths[i]}
prevWidth={c.frozen ? pixelWidths.slice(0, i).reduce((pv, c) => pv + c, 0) : 0}
Expand Down
11 changes: 6 additions & 5 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type HeaderCellProps<T> = {
onHeaderClick: (column: ColumnProps<T>) => void;
};

const HeaderCell = memo(function <T>({
function BaseHeaderCell<T>({
column,
width,
prevWidth,
Expand Down Expand Up @@ -53,9 +53,10 @@ const HeaderCell = memo(function <T>({
style={{ ...style, ...frozenStyle }}
/>
);
});
}

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

type HeaderProps<T> = {
uuid: string;
Expand Down Expand Up @@ -124,8 +125,8 @@ const Header = forwardRef(function <T>(
width={pixelWidths[i]}
sortedCol={sortedCol}
sortedDir={sortedDir}
column={c as ColumnProps<any>}
onHeaderClick={onHeaderClick as any}
column={c}
onHeaderClick={onHeaderClick}
prevWidth={c.frozen ? pixelWidths.slice(0, i).reduce((pv, c) => pv + c, 0) : 0}
/>
))}
Expand Down
54 changes: 31 additions & 23 deletions src/components/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
useCallback,
useEffect,
useImperativeHandle,
useLayoutEffect,
useRef,
useState
} from "react";
Expand All @@ -27,7 +28,7 @@ const syncScroll = (source: HTMLElement | null, target: HTMLElement | null) => {
}
};

const List = forwardRef(function <T>(
function BaseList<T>(
{
id,
uuid,
Expand Down Expand Up @@ -63,8 +64,11 @@ const List = forwardRef(function <T>(
const parentRef = useRef<HTMLDivElement | null>(null);
const headerRef = useRef<HTMLDivElement | null>(null);
const { ref: innerRef, width: innerWidth = 0 } = useResizeDetector<HTMLDivElement>();
const [pixelWidths, setPixelWidths] = useState<number[]>([]);
const [widthConstants, setWidthConstants] = useState(findColumnWidthConstants(columns));
const [pixelWidths, setPixelWidths] = useState<number[]>(() => {
const { fixedWidth, remainingCols } = widthConstants;
return calculateColumnWidths(width, remainingCols, fixedWidth, minColumnWidth, columns);
});
const [expandedCache, setExpandedCache] = useState<Record<string | number, boolean>>({});
const generateKeyFromRow = useCallback(
(row: T, defaultValue: number) => itemKey?.(row) ?? defaultValue,
Expand All @@ -83,18 +87,6 @@ const List = forwardRef(function <T>(
const { fixedWidth, remainingCols } = widthConstants;

// functions
const updatePixelWidths = useCallback(() => {
const widths = calculateColumnWidths(
parentRef.current,
remainingCols,
fixedWidth,
minColumnWidth,
columns
);
if (!arraysMatch(widths, pixelWidths)) {
setPixelWidths(widths);
}
}, [remainingCols, fixedWidth, minColumnWidth, pixelWidths, columns]);
const isRowExpanded = typeof expandedRows === "function" ? expandedRows : undefined;

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

// effects
// update pixel widths every time the width changes
useEffect(() => updatePixelWidths(), [width]);
useLayoutEffect(() => {
const widths = calculateColumnWidths(
parentRef.current?.clientWidth ?? width,
remainingCols,
fixedWidth,
minColumnWidth,
columns
);
if (!arraysMatch(widths, pixelWidths)) {
setPixelWidths(widths);
}
}, [width, remainingCols, fixedWidth, minColumnWidth, pixelWidths, columns]);

// set the width constants
useEffect(() => setWidthConstants(findColumnWidthConstants(columns)), [columns]);
Expand Down Expand Up @@ -198,13 +201,13 @@ const List = forwardRef(function <T>(
style={style}
className={className}
isExpanded={isExpanded}
onRowClick={onRowClick as any}
rowRenderer={rowRenderer as any}
onExpand={onExpand as any}
onRowClick={onRowClick}
rowRenderer={rowRenderer}
onExpand={onExpand}
index={index}
columns={columns as any}
columns={columns}
pixelWidths={pixelWidths}
subComponent={subComponent as any}
subComponent={subComponent}
/>
);
})}
Expand All @@ -215,14 +218,19 @@ const List = forwardRef(function <T>(
uuid={uuid}
rows={data}
sticky={stickyFooter}
columns={columns as ColumnProps<any>[]}
columns={columns}
pixelWidths={pixelWidths}
className={footerClassname}
style={footerStyle}
component={footerComponent as any}
component={footerComponent}
/>
</div>
);
});
}

const List = forwardRef(BaseList) as <T>(
props: ListProps<T> & { ref?: React.ForwardedRef<TableRef> }
) => React.JSX.Element;
(List as React.FC).displayName = "List";

export default List;
18 changes: 11 additions & 7 deletions src/components/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type TableCellProps<T> = {
onExpanderClick: (event?: React.MouseEvent<Element, MouseEvent>) => void;
};

const TableCell = memo(function <T>({
function BaseTableCell<T>({
row,
index,
width,
Expand Down Expand Up @@ -93,9 +93,10 @@ const TableCell = memo(function <T>({
// custom cell styling
const frozenStyle: React.CSSProperties = column.frozen ? { position: "sticky", zIndex: 2 } : {};
return <column.cell row={row} index={index} style={{ ...style, ...frozenStyle }} />;
});
}

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

type RowComponentProps<T> = {
row: T;
Expand Down Expand Up @@ -167,7 +168,7 @@ type RowProps<T> = {
rowRenderer?: (props: RowRenderProps<T>) => JSX.Element;
};

const Row = forwardRef(function <T>(
function BaseRow<T>(
{
uuid,
index,
Expand Down Expand Up @@ -205,7 +206,7 @@ const Row = forwardRef(function <T>(
<TableCell
key={`${uuid}-${rowKey}-${i}`}
row={row}
column={c as any}
column={c}
index={index}
width={pixelWidths[i]}
isExpanded={isExpanded}
Expand All @@ -221,8 +222,11 @@ const Row = forwardRef(function <T>(
)}
</div>
);
});
}

Row.displayName = "Row";
const Row = forwardRef(BaseRow) as <T>(
props: RowProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }
) => React.JSX.Element;
(Row as React.FC).displayName = "Row";

export default Row;
39 changes: 24 additions & 15 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { ColumnProps } from "..";
* @param classes list of potential className strings
* @returns a combined className string
*/
export const cx = (...args: (string | number | null | boolean | undefined)[]) => {
const cx = (...args: (string | number | null | boolean | undefined)[]) => {
return args
.flat()
.filter((x): x is Exclude<typeof x, null | undefined> => !!x)
.map(x => x.toString().trim())
.join(" ");
};

export const arraysMatch = <T>(arr1: T[] | null | undefined, arr2: T[] | null | undefined) => {
const arraysMatch = <T>(arr1: T[] | null | undefined, arr2: T[] | null | undefined) => {
if (arr1 == null && arr2 == null) {
return true;
}
Expand All @@ -35,7 +35,7 @@ export const arraysMatch = <T>(arr1: T[] | null | undefined, arr2: T[] | null |
return false;
};

export const randomString = (num: number) => {
const randomString = (num: number) => {
let result = "";
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const length = characters.length;
Expand All @@ -45,25 +45,22 @@ export const randomString = (num: number) => {
return result;
};

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

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

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

const findFooterByUuid = (uuid: string) => findElementByValue(`[data-footer-key='${uuid}-footer']`);

// table utilities
export const calculateColumnWidths = <T>(
element: HTMLElement | null,
const calculateColumnWidths = <T>(
clientWidth: number,
numColumns: number,
fixedColumnWidths: number,
minColumnWidth: number,
columns: ColumnProps<T>[]
) => {
if (!element) return columns.map(() => minColumnWidth);
const clientWidth = element.clientWidth;
let n = Math.max(numColumns, 1);
let usedSpace = fixedColumnWidths;
let freeSpace = Math.max(clientWidth - usedSpace, 0);
Expand Down Expand Up @@ -99,7 +96,7 @@ export const calculateColumnWidths = <T>(
});
};

export const findColumnWidthConstants = <T>(columns: ColumnProps<T>[]) => {
const findColumnWidthConstants = <T>(columns: ColumnProps<T>[]) => {
return columns.reduce(
(pv, c) => ({
fixedWidth: pv.fixedWidth + (c.width || 0),
Expand All @@ -109,4 +106,16 @@ export const findColumnWidthConstants = <T>(columns: ColumnProps<T>[]) => {
);
};

export const positive = (x: number | null | undefined): x is number => x != null && x > 0;
const positive = (x: number | null | undefined): x is number => x != null && x > 0;

export {
arraysMatch,
calculateColumnWidths,
cx,
positive,
findColumnWidthConstants,
findFooterByUuid,
findHeaderByUuid,
findTableByUuid,
randomString
};

0 comments on commit 6befa63

Please sign in to comment.