Skip to content

Commit

Permalink
Html table next (#730)
Browse files Browse the repository at this point in the history
* handle runtime size change, border on table

prepare for percentage scroll calculation, to
account for large datasets

* add sort detection to cell headers

* add sortindicator to tablenext
  • Loading branch information
heswell committed Jun 1, 2023
1 parent b315f8e commit ff1455b
Show file tree
Hide file tree
Showing 12 changed files with 501 additions and 106 deletions.
Expand Up @@ -347,8 +347,13 @@ export class ArrayDataSource
}

set sort(sort: VuuSort) {
// TODO should we wait until server ACK before we assign #sort ?
// this.#sort = sort;
debug?.(`sort ${JSON.stringify(sort)}`);
this.#config = {
...this.#config,
sort,
};

this.emit("config", this.#config);
}

get filter() {
Expand Down
48 changes: 45 additions & 3 deletions vuu-ui/packages/vuu-table/src/useMeasuredContainer.ts
@@ -1,5 +1,5 @@
import { isValidNumber } from "@finos/vuu-utils";
import { RefObject, useCallback, useRef, useState } from "react";
import { RefObject, useCallback, useMemo, useRef, useState } from "react";
import { useResizeObserver, ResizeHandler } from "./useResizeObserver";

const ClientWidthHeight = ["clientHeight", "clientWidth"];
Expand Down Expand Up @@ -27,14 +27,22 @@ export interface MeasuredSize {
}

interface MeasuredState {
css: CssSize;
outer: Size;
inner?: MeasuredSize;
}

const isNumber = (val: unknown): val is number => Number.isFinite(val);

export type CssSize = {
height: string;
width: string;
};
const FULL_SIZE: CssSize = { height: "100%", width: "100%" };

export interface MeasuredContainerHookResult {
containerRef: RefObject<HTMLDivElement>;
cssSize: CssSize;
outerSize: Size;
innerSize?: MeasuredSize;
}
Expand All @@ -43,6 +51,17 @@ export interface MeasuredContainerHookResult {
// were passed as props), use as initial values for inner size. If there
// is no border on Table, these values will not change. If there is a border,
// inner values will be updated once measured.
const getInitialCssSize = (height: unknown, width: unknown): CssSize => {
if (isValidNumber(height) && isValidNumber(width)) {
return {
height: `${height}px`,
width: `${width}px`,
};
} else {
return FULL_SIZE;
}
};

const getInitialInnerSize = (
height: unknown,
width: unknown
Expand All @@ -63,22 +82,44 @@ export const useMeasuredContainer = ({
}: MeasuredProps): MeasuredContainerHookResult => {
const containerRef = useRef<HTMLDivElement>(null);
const [size, setSize] = useState<MeasuredState>({
css: getInitialCssSize(height, width),
inner: getInitialInnerSize(height, width),
outer: {
height: height ?? "100%",
width: width ?? "100%",
},
});

useMemo(() => {
setSize((currentSize) => {
const { inner, outer } = currentSize;
if (isValidNumber(height) && isValidNumber(width) && inner && outer) {
const { height: innerHeight, width: innerWidth } = inner;
const { height: outerHeight, width: outerWidth } = outer;

if (outerHeight !== height || outerWidth !== width) {
const heightDiff = outerHeight - innerHeight;
const widthDiff = outerWidth - innerWidth;
return {
...currentSize,
outer: { height, width },
inner: { height: height - heightDiff, width: width - widthDiff },
};
}
}
return currentSize;
});
}, [height, width]);

const onResize: ResizeHandler = useCallback(
({ clientWidth, clientHeight }: Partial<ClientSize>) => {
console.log(`Resize ${clientHeight}`);
setSize((currentSize) => {
const { inner, outer } = currentSize;
const { css, inner, outer } = currentSize;
return isNumber(clientHeight) &&
isNumber(clientWidth) &&
(clientWidth !== inner?.width || clientHeight !== inner?.height)
? {
css,
outer,
inner: {
width: Math.floor(clientWidth) || defaultWidth,
Expand All @@ -95,6 +136,7 @@ export const useMeasuredContainer = ({

return {
containerRef,
cssSize: size.css,
outerSize: size.outer,
innerSize: size.inner,
};
Expand Down
6 changes: 0 additions & 6 deletions vuu-ui/packages/vuu-table/src/useTableViewport.ts
Expand Up @@ -103,12 +103,6 @@ export const useTableViewport = ({
[columns]
);

console.log({
pinnedWidthLeft,
pinnedWidthRight,
unpinnedWidth,
});

const [actualRowOffset, actualRowAtPosition] = useMemo<RowPositioning>(
() => actualRowPositioning(rowHeight),
[rowHeight]
Expand Down
206 changes: 206 additions & 0 deletions vuu-ui/showcase/src/examples/html/HtmlTable.examples.tsx
Expand Up @@ -9,6 +9,13 @@ import {
} from "./html-table-components";

import { RowProps } from "@finos/vuu-table/src/TableRow";
import { useMemo, useState } from "react";
import {
ToggleButton,
ToggleButtonGroup,
ToggleButtonGroupChangeEventHandler,
} from "@heswell/salt-lab";
import { Flexbox } from "@finos/vuu-layout";

let displaySequence = 1;

Expand Down Expand Up @@ -143,3 +150,202 @@ export const DefaultTableNext = () => {
);
};
DefaultTableNext.displaySequence = displaySequence++;

export const TableNextAutoSize = () => {
const { typeaheadHook: _, ...config } = useTableConfig({
columnCount: 10,
count: 1000,
rangeChangeRowset: "full",
});

return (
<div style={{ height: 800, width: 900, background: "#ccc" }}>
<TableNext
{...config}
headerHeight={30}
renderBufferSize={0}
rowHeight={30}
/>
</div>
);
};
DefaultTableNext.displaySequence = displaySequence++;

export const TableNextStaticBorders = () => {
const { typeaheadHook: _, ...config } = useTableConfig({
columnCount: 10,
count: 1000,
rangeChangeRowset: "full",
});

return (
<TableNext
{...config}
headerHeight={30}
height={600}
renderBufferSize={0}
rowHeight={30}
style={{ border: "solid 10px #ccc" }}
width={600}
/>
);
};
TableNextStaticBorders.displaySequence = displaySequence++;

export const TableNextAutoBorders = () => {
const { typeaheadHook: _, ...config } = useTableConfig({
columnCount: 10,
count: 1000,
rangeChangeRowset: "full",
});

return (
<div style={{ height: 600, width: 600, background: "#ccc" }}>
<TableNext
{...config}
headerHeight={30}
renderBufferSize={0}
rowHeight={30}
style={{ border: "solid 10px #ccc" }}
/>
</div>
);
};
TableNextAutoBorders.displaySequence = displaySequence++;

export const ResizeTableNext = () => {
const tableSize = useMemo(
() => [
{ height: 645, width: 715 },
{ height: 645, width: 915 },
{ height: 745, width: 715 },
{ height: 745, width: 915 },
{ height: undefined, width: undefined },
],
[]
);
const [selectedIndex, setSelectedIndex] = useState(0);
const { typeaheadHook: _, ...config } = useTableConfig({
columnCount: 10,
count: 1000,
rangeChangeRowset: "full",
});

const handleChangeSize: ToggleButtonGroupChangeEventHandler = (
_event,
index
) => {
setSelectedIndex(index);
};

const handleChangeBorder: ToggleButtonGroupChangeEventHandler = (
_event,
index
) => {
setSelectedIndex(index);
};

const { height, width } = tableSize[selectedIndex];
return (
<>
<ToggleButtonGroup
onChange={handleChangeSize}
selectedIndex={selectedIndex}
>
<ToggleButton>715 X 645</ToggleButton>
<ToggleButton>915 x 645</ToggleButton>
<ToggleButton>715 x 745</ToggleButton>
<ToggleButton>915 x 745</ToggleButton>
</ToggleButtonGroup>

<ToggleButtonGroup
onChange={handleChangeBorder}
selectedIndex={selectedIndex}
>
<ToggleButton>No border</ToggleButton>
<ToggleButton>1px 4 sides</ToggleButton>
<ToggleButton>10px 4 sides</ToggleButton>
</ToggleButtonGroup>

<div style={{ height: 800, width: "100%", background: "#ccc" }}>
<TableNext
{...config}
headerHeight={30}
height={height}
renderBufferSize={0}
rowHeight={30}
width={width}
/>
</div>
</>
);
};
DefaultTableNext.displaySequence = displaySequence++;

export const TableNextResizeable = () => {
const { typeaheadHook: _, ...config } = useTableConfig({
columnCount: 10,
count: 1000,
rangeChangeRowset: "full",
});

return (
<div
style={{
height: 802,
width: 902,
background: "#ccc",
border: "solid 1px brown",
margin: 10,
}}
>
<Flexbox style={{ height: "100%", width: "100%" }}>
<div data-resizeable style={{ background: "white", flex: "1 1 0px" }} />
<Flexbox style={{ flexDirection: "column", flex: "1 1 0px" }}>
<div
data-resizeable
style={{ background: "white", flex: "1 1 0px" }}
/>
<div data-resizable style={{ flex: "1 1 0px" }}>
<TableNext
{...config}
data-resizeable
headerHeight={30}
renderBufferSize={0}
rowHeight={30}
/>
</div>
</Flexbox>
</Flexbox>
</div>
);
};
TableNextResizeable.displaySequence = displaySequence++;

export const TableNext2MillionRows = () => {
// const { typeaheadHook: _, ...config } = useTableConfig({ count: 2_000_000 });
const { typeaheadHook: _, ...config } = useTableConfig({
count: 100_000,
rangeChangeRowset: "full",
});

// const { typeaheadHook: _, ...config } = useTableConfig({
// columnCount: 10,
// count: 1000,
// rangeChangeRowset: "full",
// });

return (
// <div style={{ height: 600, width: 600, background: "#ccc" }}>
<TableNext
{...config}
headerHeight={30}
height={600}
renderBufferSize={0}
rowHeight={30}
width={600}
/>
// </div>
);
};
TableNext2MillionRows.displaySequence = displaySequence++;

0 comments on commit ff1455b

Please sign in to comment.