UNPKG

@activecollab/components

Version:

ActiveCollab Components

368 lines • 13.1 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import React, { useCallback, useState, useEffect, useRef, useMemo, Fragment } from "react"; import classNames from "classnames"; import { StyledDataTable } from "./Styles"; import { Table, Tbody, Thead } from "./Table"; import CollapseAllIcon from "../Icons/collection/CollapseAll"; import CollapseExpandSingleIcon from "../Icons/collection/CollapseExpandSingle"; import ExpandAllIcon from "../Icons/collection/ExpandAll"; import SortIcon from "../Icons/collection/SortIcon"; import { SkeletonLoader } from "../Loaders"; export let SortDirection = /*#__PURE__*/function (SortDirection) { SortDirection["None"] = "none"; SortDirection["Asc"] = "asc"; SortDirection["Desc"] = "desc"; return SortDirection; }({}); const groupByKey = (items, key) => { if (items[0] instanceof Array) { items = items[0]; } return items.reduce((result, item) => { return { ...result, [item[key] !== null ? " " + item[key] : item[key]]: [...(result[item[key] !== null ? " " + item[key] : item[key]] || []), item] }; }, {}); }; const initialCollapsed = (rows, groupBy) => { if (groupBy) { const groupedData = groupByKey(rows, groupBy); const keys = Object.keys(groupedData); const collapsedKeys = {}; keys.forEach(key => { collapsedKeys[key] = true; }); return collapsedKeys; } return {}; }; export const DataTable = _ref => { let { header, rows = [], className, sortBy, sortDirection = SortDirection.None, onSortCallback, theadClass, noResultsCallback, groupBy, groupHead = () => null, isCollapsible, emptyValue, loading, loadingRows = 7, ...args } = _ref; const [columnDirection, setColumnDirection] = useState(sortDirection); const [active, setActive] = useState(sortBy); const [hovered, setHovered] = useState(); const [collapsed, setCollapsed] = useState(() => { return initialCollapsed(rows, groupBy); }); const sort = (sortByKey, direction, rowsData) => { if (direction === SortDirection.None) { return rowsData; } if (rowsData instanceof Array) return rowsData.sort((a, b) => { if (direction === SortDirection.Asc) { if (a[sortByKey] === null) { return 1; } if (b[sortByKey] === null) { return -1; } } if (a[sortByKey] === null) { return -1; } if (b[sortByKey] === null) { return 1; } if (typeof a[sortByKey] === "number") { if (direction === SortDirection.Asc) { return a[sortByKey] - b[sortByKey]; } return b[sortByKey] - a[sortByKey]; } const first = a[sortByKey].toString(); const second = b[sortByKey].toString(); if (direction === SortDirection.Asc) { return first.localeCompare(second); } return second.localeCompare(first); }); return {}; }; const initialData = useCallback(() => { if (sortBy && !groupBy) { return sort(sortBy, sortDirection, rows); } if (sortBy && groupBy) { sort(sortBy, sortDirection, rows); return groupByKey(rows, groupBy); } if (!sortBy && groupBy) { return groupByKey(rows, groupBy); } return rows; }, [groupBy, rows, sortBy, sortDirection]); const [data, setData] = useState(initialData); const getNextSortDirection = (previousDirection, sameColumn) => { if (!sameColumn) { return SortDirection.Asc; } if (previousDirection === SortDirection.Asc) { return SortDirection.Desc; } return SortDirection.Asc; }; const sortColumn = useCallback(event => { const index = event.currentTarget.dataset.index; if (index && header[index] && header[index].sortable) { const direction = getNextSortDirection(columnDirection, header[index].key === active); setActive(header[index].key); setColumnDirection(direction); if (groupBy) { let grouped = { ...data }; if (groupBy !== header[index].key) { Object.keys(grouped).map(key => { grouped[key] = sort(header[index].key, direction, grouped[key]); }); } else { if (rows instanceof Object) { grouped = sort(header[index].key, direction, rows); grouped = groupByKey([grouped], groupBy); } } setData(grouped); } else { setData(sort(header[index].key, direction, data)); } if (onSortCallback) { onSortCallback(header[index].key, direction); } } return null; }, [setData, data, columnDirection, setColumnDirection, header, active, setActive, onSortCallback, groupBy, rows]); const cellMouseOver = useCallback(e => { if (e.target instanceof HTMLElement) { if (e.target.dataset.key) { setHovered(e.target.dataset.key); } } }, []); const cellMouseOut = useCallback(() => { setHovered(null); }, []); useEffect(() => { setData(initialData()); setCollapsed(initialCollapsed(rows, groupBy)); }, [rows, groupBy, initialData]); const renderNoResults = useCallback(() => { return /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", { colSpan: header.length, className: classNames({ "text-center": !noResultsCallback }) }, noResultsCallback ? noResultsCallback() : "There is no data.")); }, [header, noResultsCallback]); const tableRef = useRef(null); const overlayStyles = () => { if (tableRef.current) { return tableRef.current.clientHeight + 5; } }; const renderCell = useCallback((h, row, colIndex) => { if (h.renderCallback) { return h.renderCallback(row, h.key, colIndex); } if (row[h.key] === null && emptyValue) { return /*#__PURE__*/React.createElement("i", { className: "opacity-75" }, emptyValue[h.key]); } return row[h.key]; }, [emptyValue]); const renderRow = useCallback((row, rowIndex) => { return /*#__PURE__*/React.createElement("tr", { key: rowIndex, "data-index": rowIndex, "data-direction": "asc", className: "c-table__row", onMouseOver: cellMouseOver, onMouseLeave: cellMouseOut }, header.map((h, colIndex) => { return /*#__PURE__*/React.createElement("td", { key: colIndex, className: classNames("c-table__cell c-data-table__item", { hovered: hovered === h.key }), "data-key": h.key, style: header[colIndex].style ? header[colIndex].style : {} }, renderCell(h, row, colIndex)); })); }, [cellMouseOut, cellMouseOver, header, hovered, renderCell]); const toggleCollapse = useCallback(event => { const collapseKey = event.currentTarget.dataset.groupkey; setCollapsed(prevState => { const newState = { ...prevState }; newState[collapseKey] = !prevState[collapseKey]; return newState; }); }, []); const renderPlaceholders = useMemo(() => { const placeholders = Array(loadingRows).fill({}).map((_, index) => { return /*#__PURE__*/React.createElement("tr", { key: index, className: "c-table__row", onMouseOver: cellMouseOver, onMouseLeave: cellMouseOut }, header.map((col, colIndex) => { return /*#__PURE__*/React.createElement("td", { key: colIndex, className: classNames("c-table__cell c-data-table__item", { hovered: hovered === col.key }), "data-key": col.key }, /*#__PURE__*/React.createElement(SkeletonLoader, null)); })); }); return /*#__PURE__*/React.createElement(Tbody, null, placeholders); }, [cellMouseOut, cellMouseOver, header, hovered, loadingRows]); const renderRows = useMemo(() => { if (data && data instanceof Array && data.length > 0 || typeof data === "object" && Object.keys(data).length > 0) { if (groupBy) { const keys = Object.keys(data); return keys.map((key, i) => { return /*#__PURE__*/React.createElement(Fragment, { key: key }, isCollapsible && /*#__PURE__*/React.createElement(Tbody, { className: "c-table__collapse_body" }, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", { "data-groupkey": key, onClick: toggleCollapse, className: "c-table__body__icon c-table--toggle-collapsed" }, /*#__PURE__*/React.createElement(CollapseExpandSingleIcon, { className: classNames({ "c-table__collapse_icon--expanded": !collapsed[key], "c-table__collapse_icon--collapsed": collapsed[key] }) })))), /*#__PURE__*/React.createElement(Tbody, { className: classNames("c-table__grouped__head", "head_" + i, { "c-table__grouped__head--expanded": isCollapsible && !collapsed[key], "c-table__grouped__head--collapsed": isCollapsible && collapsed[key], last: i === keys.length - 1, first: i === 0 }) }, groupHead(data[key], keys[i] !== "null" ? keys[i].trim() : null)), /*#__PURE__*/React.createElement(Tbody, { className: classNames("c-table__group c-table_group_" + i, { hidden: collapsed[key] }) }, data[key].map((row, index) => { return renderRow(row, index); }))); }); } return /*#__PURE__*/React.createElement(Tbody, null, data instanceof Array && data.map((row, rowIndex) => { return renderRow(row, rowIndex); })); } return renderNoResults(); }, [data, groupBy, renderRow, groupHead, collapsed, isCollapsible, renderNoResults, toggleCollapse]); const allGroupsCollapsed = useMemo(() => { return Object.keys(collapsed).every(key => { return collapsed[key]; }); }, [collapsed]); const hasCollapsed = useMemo(() => { return Object.keys(collapsed).some(key => { return collapsed[key]; }); }, [collapsed]); const toggleAllCollapsed = useCallback(() => { if (hasCollapsed) { setCollapsed(prevState => { const newState = { ...prevState }; Object.keys(newState).forEach(key => { newState[key] = false; }); return newState; }); } else { setCollapsed(prevState => { const newState = { ...prevState }; Object.keys(newState).forEach(key => { newState[key] = true; }); return newState; }); } }, [hasCollapsed]); return /*#__PURE__*/React.createElement(StyledDataTable, _extends({ as: Table, innerRef: tableRef, className: classNames("c-data-table", className, { "c-table__grouped": groupBy, "c-table__collapsible": isCollapsible, "padding-b-0": groupBy && collapsed[Object.keys(data).slice(-1)[0]] }) }, args), /*#__PURE__*/React.createElement(Thead, { className: theadClass }, header.length > 0 && /*#__PURE__*/React.createElement("tr", { className: "c-table__row" }, header.map((h, index) => { return /*#__PURE__*/React.createElement("th", { key: h.key, className: classNames("c-table__cell", { "c-table__cell--hovered": hovered === h.key, "c-table__head--hidden": groupBy && allGroupsCollapsed && h.hideCollapsed }), onMouseOver: cellMouseOver, onMouseLeave: cellMouseOut, "data-key": h.key, style: h.style }, isCollapsible && groupBy && index === 0 && /*#__PURE__*/React.createElement("span", { className: "c-table__head__icon-wrapper", onClick: toggleAllCollapsed, "data-test": "toggle-collapse" }, hasCollapsed ? /*#__PURE__*/React.createElement(ExpandAllIcon, { className: "c-table__head__icon-wrapper__icon" }) : /*#__PURE__*/React.createElement(CollapseAllIcon, { className: "c-table__head__icon-wrapper__icon" })), hovered === h.key && /*#__PURE__*/React.createElement("div", { className: "c-table__overlay", style: { height: overlayStyles() + "px" } }), /*#__PURE__*/React.createElement("div", { onClick: sortColumn, "data-index": index, className: classNames("c-table__icon-wrapper", { "cursor-pointer": h.sortable === true }) }, /*#__PURE__*/React.createElement("span", { className: "c-table__label" }, h.label), h.sortable && /*#__PURE__*/React.createElement(SortIcon, { width: "10px", height: "10px", className: classNames("c-table__icon", { "c-table__icon--inactive": h.key !== active, "c-table__icon--active": h.key === active, "c-table__icon--asc": columnDirection === SortDirection.Asc && h.key === active, "c-table__icon--desc": columnDirection === SortDirection.Desc && h.key === active }) }))); }))), loading ? renderPlaceholders : renderRows); }; DataTable.displayName = "DataTable"; //# sourceMappingURL=DataTable.js.map