UNPKG

window-table

Version:

Windowing Table for React based on React Window

280 lines (265 loc) 14.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var ReactWindow = require('react-window'); var debounce = _interopDefault(require('lodash/debounce')); var isEqual = _interopDefault(require('lodash/isEqual')); var AutoSizer = _interopDefault(require('react-virtualized-auto-sizer')); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; } var useMemo = React.useMemo, useReducer = React.useReducer; // Define the initial state of dimensions // Also to be used as a state which will not trigger a re-render on changes // So that we can change state from the useReducer, only when required var cache = { header: [0, 0], row: [0, 0], table: [0, 0] }; var reducer = function (state, _a) { var _b; var entity = _a.entity, dimensions = _a.dimensions; if (entity) { // Keep updates in cache cache = __assign({}, cache, (_b = {}, _b[entity] = dimensions, _b)); if (!isEqual(state[entity], cache[entity])) { return cache; } } return state; }; var Measurer = function (_a) { var measure = _a.measure, entity = _a.entity, debounceWait = _a.debounceWait; var debounced = useMemo(function () { return debounce(measure, debounceWait, { leading: true }); }, [measure, debounceWait]); var dispatch = debounceWait > 0 ? debounced : measure; return (React.createElement(AutoSizer, null, function (_a) { var height = _a.height, width = _a.width; dispatch({ dimensions: [height, width], entity: entity }); return null; })); }; var useTableMeasurer = function () { return useReducer(reducer, cache); }; var objectProps = ['style', 'sampleRow']; var otherProps = [ 'columns', 'data', 'rowHeight', 'height', 'width', 'className', 'rowClassName', 'classNamePrefix' ]; function areTablePropsEqual(prev, next) { var areObjectPropsEqual = objectProps.every(function (propName) { return JSON.stringify(prev[propName]) === JSON.stringify(next[propName]); }); if (!areObjectPropsEqual) { return false; } return otherProps.every(function (propName) { return prev[propName] === next[propName]; }); } var FixedSizeList = ReactWindow.FixedSizeList, VariableSizeList = ReactWindow.VariableSizeList, areEqual = ReactWindow.areEqual; var useContext = React.useContext, createContext = React.createContext, memo = React.memo, useMemo$1 = React.useMemo; var TableContext = createContext({ columns: [], data: [], Cell: 'div', Row: 'div', classNamePrefix: '', rowClassName: '' }); var RowCells = function (_a) { var columns = _a.columns, classNamePrefix = _a.classNamePrefix, datum = _a.datum, Cell = _a.Cell, _b = _a.index, index = _b === void 0 ? 0 : _b; return (React.createElement(React.Fragment, null, columns.map(function (column, i) { var key = column.key, width = column.width, _a = column.Component, Component = _a === void 0 ? 'div' : _a; // Using i as the key, because it doesn't matter much, // as we are only looping through columns in one row only return (React.createElement(Cell, { key: i, style: { width: width + "px", flexGrow: width, display: 'inline-block', overflow: 'auto', boxSizing: 'border-box' }, className: classNamePrefix + "table-cell", row: datum, column: column, index: index }, React.createElement(Component, { row: datum, column: column, index: index }, datum[key]))); }))); }; var RowRenderer = function (_a) { var index = _a.index, style = _a.style; var _b = useContext(TableContext), columns = _b.columns, data = _b.data, Cell = _b.Cell, classNamePrefix = _b.classNamePrefix, Row = _b.Row, rowClassName = _b.rowClassName; var rowClassNameStr = useMemo$1(function () { return typeof rowClassName === 'function' ? rowClassName(index) : rowClassName; }, [index, rowClassName]); return (React.createElement(Row, { style: __assign({}, style, { display: 'flex' }), className: "" + classNamePrefix + rowClassNameStr, index: index, row: data[index] }, React.createElement(RowCells, { datum: data[index], Cell: Cell, classNamePrefix: classNamePrefix, columns: columns, index: index }))); }; var MemoRowRenderer = memo(RowRenderer, areEqual); var HeaderRowRenderer = function (_a) { var Header = _a.Header, HeaderRow = _a.HeaderRow, DefaultHeaderCell = _a.HeaderCell, children = _a.children; var _b = useContext(TableContext), columns = _b.columns, classNamePrefix = _b.classNamePrefix; return (React.createElement(Header, { className: classNamePrefix + "table-header" }, React.createElement(HeaderRow, { style: { display: 'flex' }, className: classNamePrefix + "table-header-row" }, children, columns.map(function (column) { var key = column.key, width = column.width, title = column.title, _a = column.HeaderCell, HeaderCell = _a === void 0 ? DefaultHeaderCell : _a; return (React.createElement(HeaderCell, { key: "header" + key, style: { width: width + "px", display: 'inline-block', flexGrow: width }, className: classNamePrefix + "table-header-cell", column: column }, title)); })))); }; function WindowTable(_a) { var columns = _a.columns, data = _a.data, rowHeight = _a.rowHeight, height = _a.height, width = _a.width, _b = _a.overscanCount, overscanCount = _b === void 0 ? 1 : _b, _c = _a.style, style = _c === void 0 ? {} : _c, _d = _a.Cell, Cell = _d === void 0 ? 'div' : _d, _e = _a.HeaderCell, HeaderCell = _e === void 0 ? 'div' : _e, _f = _a.Table, Table = _f === void 0 ? 'div' : _f, _g = _a.Header, Header = _g === void 0 ? 'div' : _g, _h = _a.HeaderRow, HeaderRow = _h === void 0 ? 'div' : _h, _j = _a.Row, Row = _j === void 0 ? 'div' : _j, _k = _a.Body, Body = _k === void 0 ? 'div' : _k, _l = _a.sampleRowIndex, sampleRowIndex = _l === void 0 ? 0 : _l, sampleRow = _a.sampleRow, _m = _a.className, className = _m === void 0 ? '' : _m, _o = _a.rowClassName, rowClassName = _o === void 0 ? 'table-row' : _o, _p = _a.classNamePrefix, classNamePrefix = _p === void 0 ? '' : _p, _q = _a.debounceWait, debounceWait = _q === void 0 ? 0 : _q, rest = __rest(_a, ["columns", "data", "rowHeight", "height", "width", "overscanCount", "style", "Cell", "HeaderCell", "Table", "Header", "HeaderRow", "Row", "Body", "sampleRowIndex", "sampleRow", "className", "rowClassName", "classNamePrefix", "debounceWait"]); var List = rowHeight && typeof rowHeight === 'function' ? VariableSizeList : FixedSizeList; var columnWidthsSum = columns.reduce(function (sum, _a) { var width = _a.width; return sum + width; }, 0); var _r = useTableMeasurer(), dimensions = _r[0], measure = _r[1]; var _s = dimensions.table, tableHeight = _s[0], tableWidth = _s[1]; var headerHeight = dimensions.header[0]; var sampleRowHeight = dimensions.row[0]; var bodyHeight = (height || tableHeight) - headerHeight; var effectiveWidth = width || Math.max(columnWidthsSum, tableWidth); var tableClassName = classNamePrefix + "table " + className; var TableBody = function (_a) { var children = _a.children, props = __rest(_a, ["children"]); return (React.createElement(Table, __assign({}, props, { className: tableClassName }), React.createElement(Body, { className: classNamePrefix + "table-body" }, children))); }; return (React.createElement("div", __assign({ style: __assign({ height: height ? height + "px" : 'calc(100% - 16px)', width: width ? width + "px" : '100%', overflow: 'auto', maxHeight: '100vh' }, style) }, rest), !rowHeight && !!data.length && ( /*Measure row height only if not supplied explicitly*/ React.createElement(Table, { style: { height: 0, opacity: 0, display: 'grid', margin: 0, width: effectiveWidth + "px" }, className: tableClassName }, React.createElement(HeaderRowRenderer, { Header: Header, HeaderRow: HeaderRow, HeaderCell: HeaderCell }, React.createElement(Measurer, { measure: measure, entity: "header", debounceWait: debounceWait })), React.createElement(Body, { className: classNamePrefix + "table-body" }, React.createElement(Row, { className: classNamePrefix + "table-row" }, React.createElement(Measurer, { measure: measure, entity: "row", debounceWait: debounceWait }), React.createElement(RowCells, { datum: sampleRow || data[sampleRowIndex], columns: columns, classNamePrefix: classNamePrefix, Cell: Cell }))))), React.createElement(TableContext.Provider, { value: { columns: columns, data: data, Cell: Cell, Row: Row, classNamePrefix: classNamePrefix, rowClassName: rowClassName } }, React.createElement("div", null, tableWidth > 0 && (React.createElement(Table, { style: { width: effectiveWidth + "px", marginBottom: 0 }, className: tableClassName }, React.createElement(HeaderRowRenderer, { Header: Header, HeaderRow: HeaderRow, HeaderCell: HeaderCell }))), !!data.length && (React.createElement(List, { height: bodyHeight, itemCount: data.length, itemSize: rowHeight || sampleRowHeight, width: effectiveWidth, innerElementType: TableBody, overscanCount: overscanCount }, MemoRowRenderer)))), (!height || !width) && ( /*Measure table dimensions only if explicit height or width are not supplied*/ React.createElement(Measurer, { measure: measure, entity: "table", debounceWait: debounceWait })))); } var WindowTable$1 = memo(WindowTable, areTablePropsEqual); var getTHead = function (headerClassName) { if (headerClassName === void 0) { headerClassName = ''; } var THead = function (props) { return (React.createElement("thead", __assign({}, props, { className: headerClassName + " " + props.className }))); }; return THead; }; function Html5Table(_a) { var headerClassName = _a.headerClassName, props = __rest(_a, ["headerClassName"]); return (React.createElement(WindowTable$1, __assign({ Cell: "td", HeaderCell: "th", Header: getTHead(headerClassName), HeaderRow: "tr", Row: "tr", Body: "tbody", Table: "table" }, props))); } var useState = React.useState, useMemo$2 = React.useMemo; /** * A hook giving a combination of immediate and debounced state * @param initialState * @param wait */ function useDebouncedState(initialState, wait) { if (wait === void 0) { wait = 100; } var _a = useState(initialState), immediateState = _a[0], setImmediateState = _a[1]; var _b = useState(initialState), debouncedState = _b[0], setState = _b[1]; var setDebouncedState = useMemo$2(function () { return debounce(setState, wait); }, [wait]); var setCombinedState = function (state) { setDebouncedState.cancel(); setImmediateState(state); setDebouncedState(state); }; return [immediateState, debouncedState, setCombinedState]; } /** * A hook for fast data filtering * @param filterFn * @param data * @param filterText */ var useFilter = function (filterFn, data, filterText) { return useMemo$2(function () { if (!filterText.length) { return data; } return filterFn(data, filterText); }, [data, filterFn, filterText]); }; /** * A simple utility for creating functions for trivial data filtering * @param fields */ function createFilter(fields) { return function (originalData, filterText) { return originalData.filter(function (data) { return fields.some(function (field) { var fieldData = data[field] ? String(data[field]) : ''; return !!(filterText && fieldData.toLowerCase().includes(filterText.trim().toLowerCase())); }); }); }; } exports.Html5Table = Html5Table; exports.WindowTable = WindowTable$1; exports.createFilter = createFilter; exports.default = WindowTable$1; exports.useDebouncedState = useDebouncedState; exports.useFilter = useFilter; //# sourceMappingURL=index.js.map