UNPKG

adwaita-web

Version:

A GTK inspired toolkit designed to build awesome web apps

154 lines (153 loc) 5.33 kB
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 };