adwaita-web
Version:
A GTK inspired toolkit designed to build awesome web apps
154 lines (153 loc) • 5.33 kB
JavaScript
import cx from "clsx";
import React, { useEffect, useMemo, useRef } from "react";
import {
useFilters,
useFlexLayout,
useResizeColumns,
useSortBy,
useTable
} from "react-table";
import AutoSizer from "react-virtualized-auto-sizer";
import { FixedSizeList } from "react-window";
import getScrollbarWidth from "scrollbar-size";
import { PanDown } from "../icons";
import { getPropAndCastOr } from "../utils/getPropAndCastOr";
import { hasKey } from "../utils/hasKey";
import { Box } from "./Box";
function Table({
className,
columns: columnsValue,
data,
sortable,
filterable,
...rest
}) {
const bodyRef = useRef(null);
const defaultColumn = useMemo(() => ({ width: 150 }), []);
const columns = useMemo(() => transformColumns(columnsValue), [columnsValue]);
const scrollbarWidth = getScrollbarWidth();
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({
columns,
data,
defaultColumn
}, ...[
filterable ? useFilters : void 0,
sortable ? useSortBy : void 0,
useResizeColumns,
useFlexLayout
].filter((v) => Boolean(v)));
const RenderRow = React.useCallback(({ index, style }) => {
const row = rows[index];
if (!row) {
throw new Error("Row not found");
}
prepareRow(row);
return /* @__PURE__ */ React.createElement("div", {
...row.getRowProps({
style
}),
className: "tr"
}, row.cells.map((cell) => {
return /* @__PURE__ */ React.createElement("div", {
...cell.getCellProps(),
className: "td"
}, attemptRender(cell, "Cell"));
}));
}, [prepareRow, rows]);
const onScrollBody = (event) => {
const headers = document.getElementsByClassName("table__header");
for (const index of Array.from(headers).keys()) {
const header = headers[index];
if (header && event.target && hasKey(event.target, "scrollLeft"))
header.scrollLeft = event.target.scrollLeft;
}
};
useEffect(() => {
const scrollContainer = bodyRef.current?.firstElementChild?.firstElementChild;
if (!scrollContainer)
return;
scrollContainer.addEventListener("scroll", onScrollBody, { capture: true });
return () => {
scrollContainer.removeEventListener("scroll", onScrollBody);
};
}, [bodyRef.current]);
return /* @__PURE__ */ React.createElement("div", {
...getTableProps(),
className: cx("table", className),
...rest
}, /* @__PURE__ */ React.createElement("div", {
className: "table__header"
}, /* @__PURE__ */ React.createElement("div", {
className: "table__header__content",
style: {
paddingRight: scrollbarWidth,
marginBottom: -scrollbarWidth
}
}, headerGroups.map((headerGroup) => /* @__PURE__ */ React.createElement("div", {
...headerGroup.getHeaderGroupProps(),
className: "tr"
}, headerGroup.headers.map((column) => /* @__PURE__ */ React.createElement("div", {
className: cx("th", {
activatable: hasKey(column, "canSort") && column.canSort
}),
...column.getHeaderProps()
}, /* @__PURE__ */ React.createElement(Box, {
horizontal: true,
compact: true,
align: true,
...sortable ? hasKey(column, "getSortByToggleProps") && column.getSortByToggleProps() : void 0
}, /* @__PURE__ */ React.createElement(Box, {
className: "Box__fill"
}, hasKey(column, "Header") && attemptRender(column, "Header")), hasKey(column, "canSort") && column.canSort && /* @__PURE__ */ React.createElement(PanDown, {
containerProps: {
className: cx("table__sortIcon", {
hidden: !hasKey(column, "isSorted") || !column.isSorted,
descending: hasKey(column, "isSortedDesc") && column.isSortedDesc
})
}
})), hasKey(column, "canResize") && column.canResize && /* @__PURE__ */ React.createElement("div", {
...getPropAndCastOr(columns, "getResizerProps", () => ({}))(),
className: cx("table__resizer", {
isResizing: getPropAndCastOr(column, "isResizing", false)
})
}), filterable && getPropAndCastOr(column, "canFilter", false) && hasKey(column, "Filter") && /* @__PURE__ */ React.createElement("div", {
className: "table__filter"
}, attemptRender(column, "Filter")))))))), /* @__PURE__ */ React.createElement("div", {
...getTableBodyProps(),
className: "table__body",
ref: bodyRef
}, /* @__PURE__ */ React.createElement(AutoSizer, null, ({ width, height }) => /* @__PURE__ */ React.createElement(FixedSizeList, {
height,
itemCount: rows.length,
itemSize: 28,
width
}, RenderRow))));
}
function attemptRender(renderable, type, props) {
try {
return renderable.render(type, props);
} catch (e) {
console.error(`Failed to render a ${type} component.`);
console.error(e);
return /* @__PURE__ */ React.createElement(React.Fragment, null);
}
}
function transformColumns(cs) {
return cs.map((c) => {
const nc = { ...c };
if (hasKey(nc, "columns") && Array.isArray(nc.columns)) {
Object.assign(nc, {
columns: transformColumns(nc.columns)
});
} else {
if (hasKey(nc, "filter") || hasKey(nc, "Filter"))
Object.assign(nc, { disableFilters: false });
if (nc.disableFilters !== false)
Object.assign(nc, { disableFilters: true });
}
return nc;
});
}
export {
Table
};