UNPKG

react-select-table

Version:
1,433 lines (1,379 loc) 102 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.js var src_exports = {}; __export(src_exports, { SlaveTable: () => SlaveTable_default, SortOrders: () => SortOrders, Table: () => Table_default, actionTypes: () => actionTypes_default, createTable: () => createTable, dlMapUtils: () => dlMapUtils_exports, eventMiddleware: () => eventMiddleware_default, flagUtils: () => flagUtils_exports, getTableUtils: () => getTableUtils, saveModules: () => saveModules_exports, setDefaultOptions: () => setDefaultOptions, setUtils: () => setUtils_exports, trieUtils: () => trieUtils_exports }); module.exports = __toCommonJS(src_exports); // src/components/Table.jsx var import_react25 = __toESM(require("react")); // src/models/Hooks.js var import_react = require("react"); var import_react_redux = require("react-redux"); var import_redux = require("redux"); // src/utils/classUtils.js function bindPrototypeMethods(instance4) { const propertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf(instance4)); for (const name of propertyNames) { if (name === "constructor") continue; if (typeof instance4[name] !== "function") continue; instance4[name] = instance4[name].bind(instance4); } } // src/models/Hooks.js var Hooks = class { constructor(options, selectors, actions) { bindPrototypeMethods(this); const { context } = options; this.actions = actions; this.selectors = selectors; this.useRootSelector = (0, import_react_redux.createSelectorHook)(context); this.useDispatch = (0, import_react_redux.createDispatchHook)(context); this.useStore = (0, import_react_redux.createStoreHook)(context); } useSelector(selector, equalityFn) { return this.useRootSelector((state) => selector(this.selectors.getTableState(state)), equalityFn); } useGetState() { const store = this.useStore(); return (0, import_react.useCallback)(() => this.selectors.getTableState(store.getState()), [store]); } useActions(metadata = null) { const dispatch = this.useDispatch(); return (0, import_react.useMemo)(() => { const dispatchWithExtra = (action) => dispatch(Object.assign(action, metadata)); return (0, import_redux.bindActionCreators)(this.actions, dispatchWithExtra); }, [dispatch, metadata]); } }; // src/constants/actionTypes.js var types = { SET_ITEMS: "", ADD_ITEMS: "", DELETE_ITEMS: "", PATCH_ITEMS: "", PATCH_ITEMS_BY_KEY: "", CLEAR_ITEMS: "", SORT_ITEMS: "", REPLACE_ITEMS: "", SET_ITEM_FILTER: "", SET_ERROR: "", START_LOADING: "", SET_SELECTED: "", SELECT: "", CLEAR_SELECTION: "", SELECT_ALL: "", SET_ACTIVE: "", SEARCH: "", GO_TO_MATCH: "", SET_PAGE_SIZE: "", DEBUG: "" }; for (const name in types) types[name] = `RST_${name}`; var actionTypes_default = Object.freeze(types); // src/constants/enums.js var DragModes = Object.freeze({ Resize: "resize", Select: "select" }); var GestureTargetTypes = Object.freeze({ None: "none", Header: "header", BelowRows: "belowRows", Row: "row" }); var SortOrders = Object.freeze({ Ascending: true, Descending: false, None: null, Toggle: "toggle" }); // src/models/Actions.js var Actions = class { constructor(namespace) { bindPrototypeMethods(this); this.getAction = (type, payload = null) => ({ namespace, type, payload }); } search(phrase) { return this.getAction(actionTypes_default.SEARCH, { phrase }); } goToMatch(index) { return this.getAction(actionTypes_default.GO_TO_MATCH, { index }); } setPageSize(size) { return this.getAction(actionTypes_default.SET_PAGE_SIZE, { size }); } clearItems() { return this.getAction(actionTypes_default.CLEAR_ITEMS); } setItemFilter(filter) { return this.getAction(actionTypes_default.SET_ITEM_FILTER, { filter }); } patchItems(...patches) { return this.getAction(actionTypes_default.PATCH_ITEMS, { patches }); } patchItemsByKey(patchMap) { return this.getAction(actionTypes_default.PATCH_ITEMS_BY_KEY, { patchMap }); } deleteItems(...keys) { return this.getAction(actionTypes_default.DELETE_ITEMS, { keys }); } addItems(...items) { return this.getAction(actionTypes_default.ADD_ITEMS, { items }); } setItems(items) { return this.getAction(actionTypes_default.SET_ITEMS, { items }); } replaceItems(items) { return this.getAction(actionTypes_default.REPLACE_ITEMS, { items }); } sortItems(path, addToPrev = false, order = SortOrders.Toggle) { return this.getAction(actionTypes_default.SORT_ITEMS, { path, addToPrev, order }); } select(index, isRange = false, addToPrev = false) { return this.getAction(actionTypes_default.SELECT, { index, addToPrev, isRange }); } clearSelection() { return this.getAction(actionTypes_default.CLEAR_SELECTION); } setActive(index) { return this.getAction(actionTypes_default.SET_ACTIVE, { index }); } selectAll() { return this.getAction(actionTypes_default.SELECT_ALL); } setSelected(map, activeIndex = null, pivotIndex = null) { return this.getAction(actionTypes_default.SET_SELECTED, { map, activeIndex, pivotIndex }); } setError(error) { return this.getAction(actionTypes_default.SET_ERROR, { error }); } startLoading() { return this.getAction(actionTypes_default.START_LOADING); } }; // src/types/TableProps.js var import_prop_types = __toESM(require("prop-types")); var import_react2 = __toESM(require("react")); var columnShape = { title: import_prop_types.default.string, path: import_prop_types.default.string, key: import_prop_types.default.string, render: import_prop_types.default.func, isHeader: import_prop_types.default.bool, defaultWidth: import_prop_types.default.number }; var componentEventHandlersPropTypes = { onColumnResizeEnd: import_prop_types.default.func, onKeyDown: import_prop_types.default.func, onItemsOpen: import_prop_types.default.func }; var reduxEventHandlersPropTypes = { onContextMenu: import_prop_types.default.func, onSelectionChange: import_prop_types.default.func, onActionDispatched: import_prop_types.default.func }; var commonTablePropTypes = { ...componentEventHandlersPropTypes, namespace: import_prop_types.default.string.isRequired, columns: import_prop_types.default.arrayOf(import_prop_types.default.shape(columnShape)).isRequired, initColumnWidths: import_prop_types.default.objectOf(import_prop_types.default.number), errorComponent: import_prop_types.default.elementType, paginationComponent: import_prop_types.default.elementType, loadingIndicator: import_prop_types.default.node, emptyPlaceholder: import_prop_types.default.node, id: import_prop_types.default.string, className: import_prop_types.default.string, autoFocus: import_prop_types.default.bool, dragSelectScrollFactor: import_prop_types.default.number, columnResizeScrollFactor: import_prop_types.default.number, getRowClassName: import_prop_types.default.func }; var tablePropTypes = { ...commonTablePropTypes, ...reduxEventHandlersPropTypes }; var slaveTablePropTypes = { ...commonTablePropTypes, name: import_prop_types.default.string.isRequired }; // src/models/Events.js var import_lodash = __toESM(require("lodash")); var handlersSymbol = Symbol("Event handlers"); var noopEventHandler = () => { }; var getNoopHandlers = () => import_lodash.default.mapValues(reduxEventHandlersPropTypes, import_lodash.default.constant(noopEventHandler)); var Events = class { constructor(selectors) { bindPrototypeMethods(this); this.selectors = selectors; this[handlersSymbol] = getNoopHandlers(); } hasListener(event) { return this[handlersSymbol][event] !== noopEventHandler; } selectionChange(state) { this[handlersSymbol].onSelectionChange(this.selectors.getSelectionArg(state)); } contextMenu(state, forceEmpty, forceSelection) { this[handlersSymbol].onContextMenu(this.selectors.getContextMenuArg(state, forceEmpty, forceSelection)); } actionDispatched(internal = false) { this[handlersSymbol].onActionDispatched(internal); } }; // src/models/Selectors.js var import_lodash5 = __toESM(require("lodash")); // src/constants/saveModules.js var saveModules_exports = {}; __export(saveModules_exports, { Active: () => Active, Filter: () => Filter, Items: () => Items, Pagination: () => Pagination, Pivot: () => Pivot, Search: () => Search, Selection: () => Selection, SortOrder: () => SortOrder }); // src/utils/flagUtils.js var flagUtils_exports = {}; __export(flagUtils_exports, { addFlag: () => addFlag, flagGenerator: () => flagGenerator, hasFlag: () => hasFlag, removeFlag: () => removeFlag, toggleFlag: () => toggleFlag }); var import_lodash2 = __toESM(require("lodash")); function flagGenerator() { let power = 0; return () => Math.pow(2, power++); } function hasFlag(flags2, flag) { return (flags2 & flag) === flag; } function addFlag(flags2, flag) { return flags2 | flag; } function removeSingleFlag(flags2, flag) { return flags2 & ~flag; } function isolateFlag(flag) { return 1 << 31 - Math.clz32(flag); } function getDependant(flags2, flag) { return import_lodash2.default.filter(flags2, (f) => hasFlag(f, flag)).map(isolateFlag); } function removeFlag(flags2, flag, allFlags = [flag]) { const dependant = getDependant(allFlags, flag); return import_lodash2.default.reduce(dependant, removeSingleFlag, flags2); } function toggleFlag(flags2, flag, enabled, allFlags = [flag]) { if (enabled) return addFlag(flags2, flag); return removeFlag(flags2, flag, allFlags); } // src/constants/saveModules.js var nextFlag = flagGenerator(); var Filter = nextFlag(); var SortOrder = nextFlag(); var Items = nextFlag(); var Pagination = nextFlag(); var Active = nextFlag() | Items | Filter | SortOrder; var Search = nextFlag() | Active; var Selection = nextFlag() | Items; var Pivot = nextFlag() | Active | Selection; // src/utils/dlMapUtils.js var dlMapUtils_exports = {}; __export(dlMapUtils_exports, { addUnlinkedItem: () => addUnlinkedItem, deleteItem: () => deleteItem, getItem: () => getItem, getItemMetadata: () => getItemMetadata, getItems: () => getItems, getKeyedItems: () => getKeyedItems, instance: () => instance, keyIterator: () => keyIterator, sortAndLinkItems: () => sortAndLinkItems, sortItems: () => sortItems }); var import_lodash3 = __toESM(require("lodash")); function instance() { return { headKey: null, tailKey: null, nodes: {} }; } var getItems = (map) => import_lodash3.default.map(map.nodes, (node) => node.value); var getKeyedItems = (map) => import_lodash3.default.mapValues(map.nodes, (node) => node.value); var getItem = (map, key) => { var _a; return (_a = map.nodes[key]) == null ? void 0 : _a.value; }; var getItemMetadata = (map, key) => { var _a; return (_a = map.nodes[key]) == null ? void 0 : _a.metadata; }; var getNextKey = (map, key) => key == null ? map.headKey : map.nodes[key].nextKey; var getPrevKey = (map, key) => key == null ? map.tailKey : map.nodes[key].prevKey; function* keyIterator(map, forward = true, key = null) { const _getNextKey = forward ? getNextKey : getPrevKey; while (true) { key = _getNextKey(map, key); if (key == null) return; yield key; } } function setNextItem(map, key, nextKey) { const { [nextKey]: nextNode, [key]: node } = map.nodes; if (nextNode) nextNode.prevKey = key; else map.tailKey = key; if (node) node.nextKey = nextKey; else map.headKey = nextKey; } function linkItem(map, prevKey, key, nextKey) { setNextItem(map, prevKey, key); setNextItem(map, key, nextKey); } function sortAndLinkItems(map, keys, keyComparator) { keys = keys.sort(keyComparator); const linkedKeys = keyIterator(map); let linkedKeyNext = linkedKeys.next(); let keyIndex = 0; while (!linkedKeyNext.done && keyIndex < keys.length) { const key = keys[keyIndex]; const linkedKey = linkedKeyNext.value; if (keyComparator(linkedKey, key) > 0) { const linkedNode = map.nodes[linkedKey]; linkItem(map, linkedNode.prevKey, key, linkedKey); keyIndex++; } else linkedKeyNext = linkedKeys.next(); } for (; keyIndex < keys.length; keyIndex++) linkItem(map, map.tailKey, keys[keyIndex], null); } function deleteItem(map, key) { const node = map.nodes[key]; if (!node) return; setNextItem(map, node.prevKey, node.nextKey); delete map.nodes[key]; return node.value; } function addUnlinkedItem(map, key, value, metadata) { const isReplacing = deleteItem(map, key) !== void 0; map.nodes[key] = { metadata, value, prevKey: null, nextKey: null }; return isReplacing; } function sortItems(map, keyComparator) { const keys = [...keyIterator(map)].sort(keyComparator); let prevKey = null; for (const key of keys) { setNextItem(map, prevKey, key); prevKey = key; } setNextItem(map, prevKey, null); } // src/utils/setUtils.js var setUtils_exports = {}; __export(setUtils_exports, { addItem: () => addItem, getItems: () => getItems2, hasItem: () => hasItem, instance: () => instance2, isEmpty: () => isEmpty, isEqual: () => isEqual, removeItem: () => removeItem, toggleItem: () => toggleItem }); var import_lodash4 = __toESM(require("lodash")); function instance2() { return {}; } function removeItem(set, value) { delete set[value]; } function addItem(set, value) { set[value] = true; } function toggleItem(set, value, exists) { const action = exists ? addItem : removeItem; action(set, value); } function hasItem(set, value) { return set[value] === true; } function getItems2(set) { return Object.keys(set); } function isEmpty(set) { return import_lodash4.default.isEmpty(set); } function isEqual(setA, setB) { return import_lodash4.default.isEqual(setA, setB); } // src/models/Selectors.js var moduleProperties = { [Items]: ["isLoading", "error", "items"], [Selection]: "selected", [Filter]: "filter", [SortOrder]: "sortAscending", [Pagination]: "pageSize", [Active]: "activeIndex", [Pivot]: "pivotIndex", [Search]: "searchPhrase" }; var Selectors = class { constructor(options) { bindPrototypeMethods(this); this.options = options; } getTableState(state) { return this.options.statePath ? import_lodash5.default.get(state, this.options.statePath) : state; } getPageSize(state) { return state.pageSize || state.visibleItemCount; } getPageCount(state) { return Math.ceil(state.visibleItemCount / this.getPageSize(state)); } getItemPageIndex(state, itemIndex) { return Math.floor(itemIndex / this.getPageSize(state)); } getPageIndex(state) { return this.getItemPageIndex(state, state.activeIndex); } getPageIndexOffset(state) { return this.getPageIndex(state) * state.pageSize; } getSaveState(state, modules) { const saveState = {}; for (const module2 in moduleProperties) { if (!hasFlag(modules, parseInt(module2))) continue; Object.assign(saveState, import_lodash5.default.pick(state, moduleProperties[module2])); } if (saveState.items) saveState.items = getItems(saveState.items); if (saveState.selected) saveState.selected = getItems2(saveState.selected); return saveState; } getActiveRowIndex(state) { return state.activeIndex % this.getPageSize(state); } getActiveKey(state) { return state.rowKeys[this.getActiveRowIndex(state)]; } getSelected(state, rowIndex) { return hasItem(state.selected, state.rowKeys[rowIndex]); } getIsStateNormal(state) { return !state.isLoading && !state.error; } getSelection(state) { return this.getIsStateNormal(state) ? state.selected : instance2(); } getSelectionArg(state) { var _a; const selectedKeys = getItems2(this.getSelection(state)); if (this.options.multiSelect) return new Set(selectedKeys); return (_a = selectedKeys[0]) != null ? _a : null; } getContextMenuArg(state, forceEmpty = false, forceSelection = false) { const { listBox, multiSelect } = this.options; const activeKey = this.getActiveKey(state); if (forceEmpty || activeKey == null) return multiSelect ? /* @__PURE__ */ new Set() : null; if (forceSelection || !listBox) return this.getSelectionArg(state); return multiSelect ? /* @__PURE__ */ new Set([activeKey]) : activeKey; } }; // src/utils/optionsUtils.js var import_lodash6 = __toESM(require("lodash")); var defaultOptions = { itemPredicate: import_lodash6.default.isMatch, itemComparator: () => { }, searchPhraseParser: (phrase) => phrase.normalize("NFD").toLowerCase(), searchProperty: "", multiSelect: true, listBox: false, minColumnWidth: 50, constantWidth: false, statePath: "", savedState: {}, context: void 0, keyBy: "_id", chunkSize: 10 }; function getOptions(options) { return Object.freeze(import_lodash6.default.defaults(options, defaultOptions)); } function setDefaultOptions(options) { Object.assign(defaultOptions, options); } // src/models/Utils.js var Utils = class { constructor(namespace, options) { this.options = getOptions(options); this.actions = new Actions(namespace); this.selectors = new Selectors(this.options); this.events = new Events(this.selectors); this.hooks = new Hooks(this.options, this.selectors, this.actions); } }; // src/utils/tableUtils.js var px = (n) => `${n}px`; var pc = (n) => `${n}%`; var negative = (n) => -Math.abs(n); var tableUtils = {}; function createTableUtils(namespace, options) { return tableUtils[namespace] = new Utils(namespace, options); } function getTableUtils(namespace) { return tableUtils[namespace]; } // src/components/Root.jsx var import_react23 = __toESM(require("react")); // src/components/ScrollingContainer.jsx var import_lodash16 = __toESM(require("lodash")); var import_react20 = __toESM(require("react")); // src/components/ResizingContainer.jsx var import_react16 = __toESM(require("react")); var import_lodash14 = __toESM(require("lodash")); // src/components/TableBody.jsx var import_react11 = __toESM(require("react")); // src/components/ColGroup.jsx var import_react4 = __toESM(require("react")); // src/context/ColumnGroup.js var import_react3 = __toESM(require("react")); var ColumnGroupContext = import_react3.default.createContext(null); ColumnGroupContext.displayName = "ColumnGroupContext"; var ColumnGroup_default = ColumnGroupContext; // src/components/ColGroup.jsx var import_lodash7 = __toESM(require("lodash")); var ColGroup = ({ name, columns }, ref) => { const { widths, widthUnit, containerWidth } = (0, import_react4.useContext)(ColumnGroup_default); const factor = containerWidth > 100 ? 100 / import_lodash7.default.min(import_lodash7.default.values(widths)) : 1; return /* @__PURE__ */ import_react4.default.createElement("colgroup", { ref }, columns.map( ({ key }) => /* @__PURE__ */ import_react4.default.createElement("col", { key: `col_${name}_${key}`, style: { width: widthUnit(widths[key] * factor) }, "data-col-key": key }) ), /* @__PURE__ */ import_react4.default.createElement("col", { className: "rst-endCap" }), /* @__PURE__ */ import_react4.default.createElement("col", { className: "rst-spacer" })); }; var ColGroup_default = import_react4.default.forwardRef(ColGroup); // src/components/TableBody.jsx var import_lodash12 = __toESM(require("lodash")); // src/components/ChunkObserver.jsx var import_react10 = __toESM(require("react")); // src/components/TableChunk.jsx var import_react9 = __toESM(require("react")); // src/components/TableRow.jsx var import_react8 = __toESM(require("react")); // src/components/TableCell.jsx var import_lodash8 = __toESM(require("lodash")); var import_react5 = __toESM(require("react")); var TableCell = ({ render, data, rowIndex, path, isHeader }) => { const options = { className: "" }; const defaultContent = path ? import_lodash8.default.get(data, path) : rowIndex + 1; const content = render(defaultContent, data, options); const CellType = isHeader ? "th" : "td"; return /* @__PURE__ */ import_react5.default.createElement(CellType, { className: "rst-cell " + options.className }, content); }; var TableCell_default = TableCell; // src/hoc/withGestures.jsx var import_react7 = __toESM(require("react")); // src/context/GestureTarget.js var import_react6 = __toESM(require("react")); var GestureContext = import_react6.default.createContext(null); GestureContext.displayName = "GestureContext"; var GestureTarget_default = GestureContext; // src/hoc/withGestures.jsx var import_lodash9 = __toESM(require("lodash")); function withGestures(Component) { return function WithGestures({ gestureTarget, onDualTap, onDualTapDirect, ...props }) { const gesture = (0, import_react7.useContext)(GestureTarget_default); props.handleGestureTouchStart = (0, import_react7.useCallback)((e) => { if (gesture.isDragging) return; if (e.touches.length !== 2) return; if (import_lodash9.default.every(e.touches, (t) => e.currentTarget === t.target) && (onDualTapDirect == null ? void 0 : onDualTapDirect(e)) === false || import_lodash9.default.every(e.touches, (t) => e.currentTarget.contains(t.target)) && (onDualTap == null ? void 0 : onDualTap(e)) === false) e.stopPropagation(); }, [gesture, onDualTap, onDualTapDirect]); props.handleGesturePointerDownCapture = (0, import_react7.useCallback)(() => { if (!gestureTarget) return; gesture.target = gestureTarget; }, [gesture, gestureTarget]); return /* @__PURE__ */ import_react7.default.createElement(Component, { ...props }); }; } // src/utils/dataAttributeUtils.js var import_lodash10 = __toESM(require("lodash")); var getFlagAttribute = (flagName) => "data-is-" + flagName; var getFlagAttributes = (flagNames) => import_lodash10.default.mapValues(flagNames, getFlagAttribute); function dataAttributeFlags(flags2) { const attributes = import_lodash10.default.mapKeys(flags2, (enabled, name) => getFlagAttribute(name)); return import_lodash10.default.mapValues(attributes, (enabled) => enabled ? "" : void 0); } // src/components/TableRow.jsx var flags = { Selected: "selected", Active: "active" }; var RowAttributes = getFlagAttributes(flags); function getRowBounds(row) { if (!row) return null; const { offsetHeight: height, offsetTop: top } = row; if (!height) return null; return { top, bottom: top + height }; } var TableRow = ({ handleGesturePointerDownCapture, handleGestureTouchStart, columns, name, getRowClassName, row: { index, key, selected, active, data, ref } }) => { const renderColumn = ({ key: colKey, ...column }) => /* @__PURE__ */ import_react8.default.createElement(TableCell_default, { ...column, data, rowIndex: index, key: `cell_${name}_${key}_${colKey}` }); return /* @__PURE__ */ import_react8.default.createElement("tr", { ref, className: "rst-row " + getRowClassName(data, key), onPointerDownCapture: handleGesturePointerDownCapture, onTouchStart: handleGestureTouchStart, ...dataAttributeFlags({ [flags.Active]: active, [flags.Selected]: selected }) }, columns.map(renderColumn), /* @__PURE__ */ import_react8.default.createElement("td", { className: "rst-endCap" }), /* @__PURE__ */ import_react8.default.createElement("td", { className: "rst-spacer" })); }; var TableRow_default = withGestures(TableRow); // src/models/GestureTarget.js function GestureTarget(type, index = -1) { return { type, index }; } // src/utils/memoUtils.js var import_lodash11 = __toESM(require("lodash")); function comparePropsDeep(prev, next) { return import_lodash11.default.isEqualWith(prev, next, (pv, nv, key, po) => { if (po === prev && key.endsWith("Ref")) return true; }); } // src/components/TableChunk.jsx function TableChunk(props, ref) { const { rows, contextMenu, refresh, ...rowCommonProps } = props; (0, import_react9.useLayoutEffect)(refresh); const renderRow = (row) => { const rowProps = { ...rowCommonProps, row, key: `row_${props.name}_${row.key}`, gestureTarget: GestureTarget(GestureTargetTypes.Row, row.index), onDualTap: contextMenu }; return /* @__PURE__ */ import_react9.default.createElement(TableRow_default, { ...rowProps }); }; return /* @__PURE__ */ import_react9.default.createElement("tbody", { className: "rst-chunk", ref }, rows.map(renderRow)); } var TableChunk_default = import_react9.default.memo(import_react9.default.forwardRef(TableChunk), comparePropsDeep); // src/components/ChunkObserver.jsx var HiddenAttribute = getFlagAttribute("hidden"); var LastWidthAttribute = "data-last-width"; function ChunkObserver(props) { const { chunkObserverRef, indexOffset, utils: { hooks, selectors }, ...chunkProps } = props; const activeRowIndex = hooks.useSelector(selectors.getActiveRowIndex); const chunkRef = (0, import_react10.useRef)(); const isRefreshingRef = (0, import_react10.useRef)(false); const { resizingIndex } = (0, import_react10.useContext)(ColumnGroup_default); const refreshChunk = (0, import_react10.useCallback)(() => { const observer = chunkObserverRef.current; if (!observer) return; const chunk = chunkRef.current; const isHidden = chunk.hasAttribute(HiddenAttribute); if (!isHidden) return; observer.unobserve(chunk); chunk.toggleAttribute(HiddenAttribute, false); isRefreshingRef.current = true; }, [chunkObserverRef]); (0, import_react10.useEffect)(() => { if (!isRefreshingRef.current) return; chunkObserverRef.current.observe(chunkRef.current); isRefreshingRef.current = false; }); (0, import_react10.useLayoutEffect)(() => { if (resizingIndex >= 0) return; refreshChunk(); }, [resizingIndex, refreshChunk]); (0, import_react10.useLayoutEffect)(() => { if (activeRowIndex <= indexOffset) return; const chunk = chunkRef.current; const lastWidth = chunk.getAttribute(LastWidthAttribute); const width = chunk.clientWidth.toString(); if (width === lastWidth) return; refreshChunk(); }, [activeRowIndex, indexOffset, refreshChunk]); (0, import_react10.useEffect)(() => { const observer = chunkObserverRef.current; if (!observer) return; const chunk = chunkRef.current; observer.observe(chunk); return () => observer.unobserve(chunk); }, [chunkObserverRef]); return /* @__PURE__ */ import_react10.default.createElement(TableChunk_default, { ref: chunkRef, refresh: refreshChunk, ...chunkProps }); } var ChunkObserver_default = ChunkObserver; // src/components/TableBody.jsx function TableBody(props) { const { showPlaceholder, tableBodyRef, ...chunkCommonProps } = props; const { columns, name, utils: { hooks, selectors, options } } = props; const rowKeys = hooks.useSelector((s) => s.rowKeys); const selected = hooks.useSelector((s) => s.selected); const items = hooks.useSelector((s) => s.items); const activeRowIndex = hooks.useSelector(selectors.getActiveRowIndex); const chunkSize = (0, import_react11.useMemo)(() => Math.ceil(options.chunkSize) * 2, [options]); const keyChunks = (0, import_react11.useMemo)( () => chunkSize > 0 ? import_lodash12.default.chunk(rowKeys, chunkSize) : [rowKeys], [rowKeys, chunkSize] ); const renderChunk = (keys, chunkIndex) => { const chunkIndexOffset = chunkIndex * chunkSize; const rows = keys.map((key, rowIndex) => { const index = chunkIndexOffset + rowIndex; return { key, index, data: getItem(items, key), selected: hasItem(selected, key), active: index === activeRowIndex }; }); return /* @__PURE__ */ import_react11.default.createElement(ChunkObserver_default, { indexOffset: chunkIndexOffset, rows, key: `chunk_${props.name}_${chunkIndex}`, ...chunkCommonProps }); }; return /* @__PURE__ */ import_react11.default.createElement("div", { className: "rst-body", tabIndex: 0 }, /* @__PURE__ */ import_react11.default.createElement("table", { ref: tableBodyRef }, /* @__PURE__ */ import_react11.default.createElement(ColGroup_default, { name, columns }), !showPlaceholder && keyChunks.map(renderChunk))); } var TableBody_default = TableBody; // src/components/TableHead.jsx var import_react15 = __toESM(require("react")); var import_lodash13 = __toESM(require("lodash")); // src/components/TableHeader.jsx var import_react14 = __toESM(require("react")); // src/components/AngleIcon.jsx var import_react12 = __toESM(require("react")); var angleRotation = Object.freeze({ Up: 0, Down: 180, Right: 90, Left: -90 }); function AngleIcon({ rotation }) { return /* @__PURE__ */ import_react12.default.createElement("svg", { className: "rst-icon", viewBox: "0 0 24 24", style: { transform: `rotate(${rotation}deg)` } }, /* @__PURE__ */ import_react12.default.createElement("path", { d: "M 23.514324,16.51929 11.995,4.5999889 0.47567595,16.51929 A 1.7007899,1.7007899 0 0 0 2.9255324,18.879152 L 11.995,9.4897022 21.074467,18.879152 a 1.7007901,1.7007901 0 0 0 2.449857,-2.359862 z" })); } AngleIcon.defaultProps = { rotation: angleRotation.Up }; var AngleIcon_default = AngleIcon; // src/components/HourGlassIcon.jsx var import_react13 = __toESM(require("react")); function HourGlassIcon({ rotation, ...rest }, ref) { return /* @__PURE__ */ import_react13.default.createElement("svg", { className: "rst-icon rst-loadingIcon", viewBox: "0 0 24 32", ref, ...rest }, /* @__PURE__ */ import_react13.default.createElement("path", { d: "m 23,30 h -3 v -7.09 a 6.67,6.67 0 0 0 -2.69,-5.33 l -1.28,-1 A 6.36,6.36 0 0 0 15,16 v 0 a 6.29,6.29 0 0 0 1,-0.62 l 1.28,-1 A 6.67,6.67 0 0 0 20,9.09 V 2 h 3 A 1,1 0 0 0 23,0 H 1 a 1,1 0 0 0 0,2 h 3 v 7.09 a 6.67,6.67 0 0 0 2.69,5.33 l 1.28,1 A 6.36,6.36 0 0 0 9,16 v 0 a 6.27,6.27 0 0 0 -1,0.62 l -1.28,1 A 6.67,6.67 0 0 0 4,22.91 V 30 H 1 a 1,1 0 0 0 0,2 h 22 a 1,1 0 0 0 0,-2 z M 6,22.91 a 4.66,4.66 0 0 1 1.88,-3.72 l 1.28,-1 a 4.66,4.66 0 0 1 1.18,-0.63 1,1 0 0 0 0.65,-0.94 V 15.33 A 1,1 0 0 0 10.34,14.39 4.67,4.67 0 0 1 9.15,13.76 l -1.28,-1 A 4.66,4.66 0 0 1 6,9.09 V 2 h 12 v 7.09 a 4.66,4.66 0 0 1 -1.88,3.72 l -1.28,1 v 0 a 4.66,4.66 0 0 1 -1.18,0.63 1,1 0 0 0 -0.65,0.94 v 1.34 a 1,1 0 0 0 0.65,0.94 4.67,4.67 0 0 1 1.19,0.63 l 1.28,1 A 4.66,4.66 0 0 1 18,22.91 V 30 H 6 Z" })); } var HourGlassIcon_default = import_react13.default.forwardRef(HourGlassIcon); // src/components/TableHeader.jsx var LoadingAttribute = getFlagAttribute("loading"); function TableHeader({ handleGesturePointerDownCapture, handleGestureTouchStart, path, title, columnResize, actions, sortAscending, sortPriority, showPriority, isResizing, isResizable, className }) { const gesture = (0, import_react14.useContext)(GestureTarget_default); const isSortable = !!path; const loadingIconRef = (0, import_react14.useRef)(); const sortColumn = (0, import_react14.useCallback)((addToPrev) => { if (!isSortable) return; requestAnimationFrame(() => { loadingIconRef.current.toggleAttribute(LoadingAttribute, true); setTimeout(() => actions.sortItems(path, addToPrev)); }); return true; }, [actions, path, isSortable]); const handleTitleMouseDown = (0, import_react14.useCallback)((e) => { if (e.button !== 0) return; sortColumn(e.shiftKey); }, [sortColumn]); const handleTitleKeyDown = (0, import_react14.useCallback)((e) => { if (e.keyCode !== 32) return; e.stopPropagation(); if (!sortColumn(e.shiftKey)) return; e.preventDefault(); }, [sortColumn]); const handleTitleContextMenu = (0, import_react14.useCallback)(() => { if (gesture.pointerType !== "touch") return; sortColumn(true); }, [sortColumn, gesture]); (0, import_react14.useLayoutEffect)(() => { loadingIconRef.current.toggleAttribute(LoadingAttribute, false); }, [sortAscending]); return /* @__PURE__ */ import_react14.default.createElement("th", { className, onPointerDownCapture: handleGesturePointerDownCapture, onTouchStart: handleGestureTouchStart, ...dataAttributeFlags({ sortable: isSortable, resizing: isResizing }) }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "rst-headerContent", onMouseDown: handleTitleMouseDown, onContextMenu: handleTitleContextMenu, onKeyDown: handleTitleKeyDown, tabIndex: isSortable ? 0 : -1, role: "none" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "rst-headerText" }, title), /* @__PURE__ */ import_react14.default.createElement(HourGlassIcon_default, { ref: loadingIconRef }), sortPriority >= 0 && /* @__PURE__ */ import_react14.default.createElement(import_react14.Fragment, null, /* @__PURE__ */ import_react14.default.createElement(AngleIcon_default, { rotation: sortAscending ? angleRotation.Up : angleRotation.Down }), showPriority && /* @__PURE__ */ import_react14.default.createElement("small", null, sortPriority))), isResizable && /* @__PURE__ */ import_react14.default.createElement("div", { className: "rst-columnResizer", onDragStart: (e) => e.preventDefault(), onPointerDown: columnResize })); } var TableHeader_default = withGestures(TableHeader); // src/components/TableHead.jsx function TableHead(props) { const { handleGesturePointerDownCapture, handleGestureTouchStart, columns, name, headColGroupRef, headRowRef, utils: { hooks, options }, ...commonHeaderProps } = props; const sortAscending = hooks.useSelector((s) => s.sortAscending); const sorting = (0, import_react15.useMemo)(() => { let priority = 0; return { orders: import_lodash13.default.mapValues(sortAscending, (ascending) => ({ ascending, priority: ++priority })), maxPriority: priority }; }, [sortAscending]); const { resizingIndex } = (0, import_react15.useContext)(ColumnGroup_default); const renderHeader = (column, index) => { const { path, title } = column; const sortOrder = sorting.orders[path]; return /* @__PURE__ */ import_react15.default.createElement(TableHeader_default, { ...commonHeaderProps, path, title, key: `header_${name}_${column.key}`, className: "rst-header", gestureTarget: GestureTarget(GestureTargetTypes.Header, index), isResizable: !!index, isResizing: resizingIndex === index, sortAscending: sortOrder == null ? void 0 : sortOrder.ascending, sortPriority: sortOrder == null ? void 0 : sortOrder.priority, showPriority: sorting.maxPriority > 1 }); }; return /* @__PURE__ */ import_react15.default.createElement("div", { className: "rst-head", onPointerDownCapture: handleGesturePointerDownCapture, onTouchStart: handleGestureTouchStart }, /* @__PURE__ */ import_react15.default.createElement("table", null, /* @__PURE__ */ import_react15.default.createElement(ColGroup_default, { name, columns, ref: headColGroupRef }), /* @__PURE__ */ import_react15.default.createElement("thead", null, /* @__PURE__ */ import_react15.default.createElement("tr", { className: "rst-row", ref: headRowRef }, columns.map(renderHeader), /* @__PURE__ */ import_react15.default.createElement("th", { className: "rst-endCap" }), /* @__PURE__ */ import_react15.default.createElement(TableHeader_default, { ...commonHeaderProps, path: "", title: "", gestureTarget: null, className: "rst-spacer", isResizable: !options.constantWidth, isResizing: resizingIndex === columns.length, sortAscending: true, sortPriority: -1, showPriority: false }))))); } var TableHead_default = withGestures(TableHead); // src/components/ResizingContainer.jsx function ResizingContainer(props) { const { handleGesturePointerDownCapture, handleGestureTouchStart, dragSelect, placeholder, selectionRectRef, dragMode, contextMenu, headColGroupRef, headRowRef, columnResize, actions, getRowClassName, tableBodyRef, chunkObserverRef, ...commonProps } = props; const { utils: { options, hooks, selectors, events }, columns } = props; const showPlaceholder = !!placeholder; const { containerWidth, widths, resizingIndex } = (0, import_react16.useContext)(ColumnGroup_default); const gesture = (0, import_react16.useContext)(GestureTarget_default); const rowCount = hooks.useSelector((s) => s.rowKeys.length); const indexOffset = hooks.useSelector(selectors.getPageIndexOffset); const handleMouseDown = (0, import_react16.useCallback)((e) => { if (showPlaceholder || e.button !== 0 || e.altKey) return; const { target } = gesture; switch (target.type) { case GestureTargetTypes.BelowRows: if (e.shiftKey) actions.select(indexOffset + rowCount - 1, e.shiftKey, e.ctrlKey); else if (!options.listBox && !e.ctrlKey) actions.clearSelection(); break; case GestureTargetTypes.Row: actions.select(indexOffset + target.index, e.shiftKey, e.ctrlKey); break; default: return; } if (gesture.pointerType === "mouse") { getSelection().removeAllRanges(); dragSelect(e); } }, [gesture, actions, options, indexOffset, rowCount, dragSelect, showPlaceholder]); const handleContextMenu = (0, import_react16.useCallback)((e) => { if (e.shiftKey) return; const { target } = gesture; if (gesture.pointerType !== "mouse") { if (showPlaceholder) return; if (target.type === GestureTargetTypes.Row) actions.select(indexOffset + target.index, false, true); else if (target.type !== GestureTargetTypes.BelowRows) return; return dragSelect(e); } if (events.hasListener("onContextMenu")) e.preventDefault(); contextMenu(e); }, [gesture, indexOffset, contextMenu, actions, events, dragSelect, showPlaceholder]); const gestureEventHandlers = { onMouseDown: handleMouseDown, onContextMenu: handleContextMenu, onPointerDownCapture: handleGesturePointerDownCapture, onTouchStart: handleGestureTouchStart }; const columnKeys = import_lodash14.default.map(columns, "key"); const clippingStoppers = /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-stoppers" }, import_lodash14.default.map(columnKeys, (referenceKey) => { const minWidthScale = options.minColumnWidth / widths[referenceKey]; return /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-clippingStopper", "data-col-key": referenceKey, key: `stoppers-${referenceKey}` }, import_lodash14.default.map(columnKeys, (key) => /* @__PURE__ */ import_react16.default.createElement("div", { "data-col-key": key, key: `stopper-${key}`, style: { width: widths[key] * minWidthScale } }))); })); const resizingStopperWidths = import_lodash14.default.map(columnKeys, (key) => containerWidth / widths[key] * options.minColumnWidth); const isOverflowing = containerWidth > 100; const isResizing = resizingIndex >= 0; const showClippingStoppers = !isResizing && !isOverflowing; const headProps = { ...commonProps, headColGroupRef, actions, headRowRef, columnResize }; const bodyProps = { ...commonProps, tableBodyRef, chunkObserverRef, showPlaceholder, getRowClassName, contextMenu }; return /* @__PURE__ */ import_react16.default.createElement(import_react16.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-clippingContainer", ...dataAttributeFlags({ clipping: showClippingStoppers }) }, showClippingStoppers && clippingStoppers, /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-resizingContainer", style: { width: pc(containerWidth), marginRight: showClippingStoppers ? -import_lodash14.default.max(resizingStopperWidths) : 0 }, ...gestureEventHandlers }, !isResizing && (isOverflowing ? clippingStoppers : /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-stoppers" }, import_lodash14.default.map(columnKeys, (key, index) => /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-resizingStopper", "data-col-key": key, key: `stopper-${key}`, style: { width: resizingStopperWidths[index] } })))), /* @__PURE__ */ import_react16.default.createElement(TableHead_default, { ...headProps, gestureTarget: GestureTarget(GestureTargetTypes.Header, columns.length), onDualTap: contextMenu }), /* @__PURE__ */ import_react16.default.createElement(TableBody_default, { ...bodyProps }), dragMode === DragModes.Select && /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-dragSelection", ref: selectionRectRef }))), showPlaceholder && /* @__PURE__ */ import_react16.default.createElement("div", { className: "rst-placeholder", ...gestureEventHandlers }, placeholder)); } var ResizingContainer_default = withGestures(ResizingContainer); // src/hooks/useDecoupledCallback.js var import_react17 = require("react"); function useDecoupledCallback(callback) { const callbackRef = (0, import_react17.useRef)(callback); (0, import_react17.useEffect)(() => { callbackRef.current = callback; }, [callback]); return (0, import_react17.useCallback)((...args) => { var _a; return (_a = callbackRef.current) == null ? void 0 : _a.call(callbackRef, ...args); }, [callbackRef]); } // src/hooks/useEventListener.js var import_react19 = require("react"); // src/hooks/useObjectMemo.js var import_react18 = require("react"); var import_lodash15 = __toESM(require("lodash")); function useObjectMemo(obj) { const objRef = (0, import_react18.useRef)(obj); if (!import_lodash15.default.isEqual(obj, objRef.current)) objRef.current = obj; return objRef.current; } // src/hooks/useEventListener.js var activeListenerOptions = { passive: false }; var defaultOptions2 = {}; function useEventListener(type, handler, options = defaultOptions2) { const decoupledHandler = useDecoupledCallback(handler); const add = (0, import_react19.useCallback)( (element) => element.addEventListener(type, decoupledHandler, options), [decoupledHandler, type, options] ); const remove = (0, import_react19.useCallback)( (element) => element.removeEventListener(type, decoupledHandler, options), [decoupledHandler, type, options] ); return useObjectMemo({ add, remove }); } // src/components/ScrollingContainer.jsx var isColumnVisible = (width) => width > 0; var Point = (x, y) => ({ x, y }); var getClientX = (element) => element.getBoundingClientRect().x; var getClientY = (element) => element.getBoundingClientRect().y; function getLine(pointA, pointB) { const min = pointA < pointB ? pointA : pointB; const max = pointA > pointB ? pointA : pointB; return { origin: min, size: max - min }; } function getRelativeOffset(absolute, origin, minVisible, maxVisible, scrollFactor) { const reference = import_lodash16.default.clamp(absolute, minVisible, maxVisible); const scrollOffset = (absolute - reference) * scrollFactor; return { scrollOffset, relToOrigin: reference - origin, relToMin: reference - minVisible, relToMax: maxVisible - reference }; } function ScrollingContainer(props) { const { dragSelectScrollFactor, columnResizeScrollFactor, columns, initColumnWidths, componentEvents, ...resizingProps } = props; const { utils: { options, hooks, selectors, events }, actions, placeholder } = props; const gesture = (0, import_react20.useContext)(GestureTarget_default); const [dragMode, setDragMode] = (0, import_react20.useState)(null); (0, import_react20.useLayoutEffect)(() => { gesture.isDragging = !!dragMode; }, [gesture, dragMode]); const rowCount = hooks.useSelector((s) => s.rowKeys.length); const rowKeys = hooks.useSelector((s) => s.rowKeys); const indexOffset = hooks.useSelector(selectors.getPageIndexOffset); const activeRowIndex = hooks.useSelector(selectors.getActiveRowIndex); const noSelection = hooks.useSelector((s) => isEmpty(s.selected)); const getState = hooks.useGetState(); const tableBodyRef = (0, import_react20.useRef)(); const headColGroupRef = (0, import_react20.useRef)(); const headRowRef = (0, import_react20.useRef)(); const selectionRectRef = (0, import_react20.useRef)(); const scrollingContainerRef = (0, import_react20.useRef)(); const getRow = (0, import_react20.useCallback)((index) => tableBodyRef.current.rows[index], []); const getCurrentHeaderWidths = (0, import_react20.useCallback)( () => import_lodash16.default.map(import_lodash16.default.take(headRowRef.current.children, columns.length), (h) => h.getBoundingClientRect().width), [columns] ); const [columnGroup, setColumnGroup] = (0, import_react20.useState)({ widths: initColumnWidths, resizingIndex: -1 }); const getRenderedColumnsWidthsPatch = (0, import_react20.useCallback)((widths) => import_lodash16.default.zipObject(import_lodash16.default.map(columns, "key"), widths), [columns]); const defaultWidths = (0, import_react20.useMemo)(() => { const defaultWidth = 100 / columns.length; const widths = import_lodash16.default.map(columns, (c) => +c.defaultWidth || defaultWidth); return getRenderedColumnsWidthsPatch(widths); }, [columns, getRenderedColumnsWidthsPatch]); const allWidths = (0, import_react20.useMemo)(() => { const validWidths = import_lodash16.default.mapValues( columnGroup.widths, (width, key) => width || negative(defaultWidths[key]) ); return { ...defaultWidths, ...validWidths }; }, [columnGroup, defaultWidths]); const fullColumnGroup = (0, import_react20.useMemo)(() => { const visibleWidths = columns.map((c) => allWidths[c.key]).filter((w) => w >= 0); const { resizingIndex } = columnGroup; const isResizing = resizingIndex >= 0; return { resizingIndex, widths: import_lodash16.default.mapValues(allWidths, Math.abs), containerWidth: isResizing ? 0 : Math.max(100, import_lodash16.default.sum(visibleWidths)), widthUnit: isResizing ? px : pc }; }, [columnGroup, columns, allWidths]); const setRenderedColumnWidths = (0, import_react20.useCallback)((widths, resizingIndex = -1) => { const renderedPatch = getRenderedColumnsWidthsPatch(widths); const visiblePatch = import_lodash16.default.pickBy(renderedPatch, isColumnVisible); const hiddenPatch = import_lodash16.default.mapValues(renderedPatch, (w, key) => negative(allWidths[key])); setColumnGroup({ widths: import_lodash16.default.defaults(visiblePatch, hiddenPatch, allWidths), resizingIndex }); if (resizingIndex >= 0) return; componentEvents.columnResize(visiblePatch); }, [getRenderedColumnsWidthsPatch, componentEvents, allWidths]); const drag = (0, import_react20.useRef)({ invertScroll: false, animationId: null, pointerPos: Point(), pointerId: null, movement: Point(0, 0), ctrlKey: false }).current; const columnResizing = (0, import_react20.useRef)({ prevVisibleIndex: -1, borderLeft: 0, header: null, distanceOfPrevToStart: 0, isResizingSpacer: false, minWidth: 0 }).current; const dragSelection = (0, import_react20.useRef)({ selection: {}, selectionBuffer: {}, originRel: Point(), activeIndex: null, pivotIndex: null, prevRowIndex: -1, prevRelY: 0 }).current; const columnResizeEnd = (0, import_react20.useCallback)(() => { const { offsetLeft: fullWidth, previousElementSibling: { offsetLeft: availableWidth } } = headRowRef.current.lastChild; const container = scrollingContainerRef.current; const { clientWidth, offsetWidth } = container; const visibleWidth = container.getBoundingClientRect().width - (offsetWidth - clientWidth); const scale = fullWidth > visibleWidth ? fullWidth / availableWidth : 1; const widths = getCurrentHeaderWidths().map((px2) => px2 / visibleWidth * scale * 100); setRenderedColumnWidths(widths); }, [getCurrentHeaderWidths, setRenderedColumnWidths]); const dragSelectEnd = (0, import_react20.useCallback)(() => { if (dragSelection.activeIndex == null