react-select-table
Version:
React table component with selectable items
1,510 lines (1,457 loc) • 95 kB
JavaScript
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/components/Table.jsx
import React21, { useEffect as useEffect5 } from "react";
// src/models/Hooks.js
import { useMemo, useCallback } from "react";
import {
createDispatchHook,
createSelectorHook,
createStoreHook
} from "react-redux";
import { bindActionCreators } from "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 = createSelectorHook(context);
this.useDispatch = createDispatchHook(context);
this.useStore = createStoreHook(context);
}
useSelector(selector, equalityFn) {
return this.useRootSelector((state) => selector(this.selectors.getTableState(state)), equalityFn);
}
useGetState() {
const store = this.useStore();
return useCallback(() => this.selectors.getTableState(store.getState()), [store]);
}
useActions(metadata = null) {
const dispatch = this.useDispatch();
return useMemo(() => {
const dispatchWithExtra = (action) => dispatch(Object.assign(action, metadata));
return 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
import PropTypes from "prop-types";
import React from "react";
var columnShape = {
title: PropTypes.string,
path: PropTypes.string,
key: PropTypes.string,
render: PropTypes.func,
isHeader: PropTypes.bool,
defaultWidth: PropTypes.number
};
var componentEventHandlersPropTypes = {
onColumnResizeEnd: PropTypes.func,
onKeyDown: PropTypes.func,
onItemsOpen: PropTypes.func
};
var reduxEventHandlersPropTypes = {
onContextMenu: PropTypes.func,
onSelectionChange: PropTypes.func,
onActionDispatched: PropTypes.func
};
var commonTablePropTypes = {
...componentEventHandlersPropTypes,
namespace: PropTypes.string.isRequired,
columns: PropTypes.arrayOf(PropTypes.shape(columnShape)).isRequired,
initColumnWidths: PropTypes.objectOf(PropTypes.number),
errorComponent: PropTypes.elementType,
paginationComponent: PropTypes.elementType,
loadingIndicator: PropTypes.node,
emptyPlaceholder: PropTypes.node,
id: PropTypes.string,
className: PropTypes.string,
autoFocus: PropTypes.bool,
dragSelectScrollFactor: PropTypes.number,
columnResizeScrollFactor: PropTypes.number,
getRowClassName: PropTypes.func
};
var tablePropTypes = {
...commonTablePropTypes,
...reduxEventHandlersPropTypes
};
var slaveTablePropTypes = {
...commonTablePropTypes,
name: PropTypes.string.isRequired
};
// src/models/Events.js
import _ from "lodash";
var handlersSymbol = Symbol("Event handlers");
var noopEventHandler = () => {
};
var getNoopHandlers = () => _.mapValues(reduxEventHandlersPropTypes, _.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
import _5 from "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
});
import _2 from "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 _2.filter(flags2, (f) => hasFlag(f, flag)).map(isolateFlag);
}
function removeFlag(flags2, flag, allFlags = [flag]) {
const dependant = getDependant(allFlags, flag);
return _2.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
});
import _3 from "lodash";
function instance() {
return {
headKey: null,
tailKey: null,
nodes: {}
};
}
var getItems = (map) => _3.map(map.nodes, (node) => node.value);
var getKeyedItems = (map) => _3.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
});
import _4 from "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 _4.isEmpty(set);
}
function isEqual(setA, setB) {
return _4.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 ? _5.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 module in moduleProperties) {
if (!hasFlag(modules, parseInt(module)))
continue;
Object.assign(saveState, _5.pick(state, moduleProperties[module]));
}
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
import _6 from "lodash";
var defaultOptions = {
itemPredicate: _6.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(_6.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
import React19, { useCallback as useCallback11, useEffect as useEffect4, useMemo as useMemo5, useRef as useRef6 } from "react";
// src/components/ScrollingContainer.jsx
import _16 from "lodash";
import React16, { useCallback as useCallback8, useContext as useContext7, useEffect as useEffect3, useLayoutEffect as useLayoutEffect4, useMemo as useMemo4, useRef as useRef5, useState } from "react";
// src/components/ResizingContainer.jsx
import React15, { Fragment as Fragment2, useContext as useContext6, useCallback as useCallback5 } from "react";
import _14 from "lodash";
// src/components/TableBody.jsx
import React10, { useMemo as useMemo2 } from "react";
// src/components/ColGroup.jsx
import React3, { useContext } from "react";
// src/context/ColumnGroup.js
import React2 from "react";
var ColumnGroupContext = React2.createContext(null);
ColumnGroupContext.displayName = "ColumnGroupContext";
var ColumnGroup_default = ColumnGroupContext;
// src/components/ColGroup.jsx
import _7 from "lodash";
var ColGroup = ({ name, columns }, ref) => {
const { widths, widthUnit, containerWidth } = useContext(ColumnGroup_default);
const factor = containerWidth > 100 ? 100 / _7.min(_7.values(widths)) : 1;
return /* @__PURE__ */ React3.createElement("colgroup", {
ref
}, columns.map(
({ key }) => /* @__PURE__ */ React3.createElement("col", {
key: `col_${name}_${key}`,
style: { width: widthUnit(widths[key] * factor) },
"data-col-key": key
})
), /* @__PURE__ */ React3.createElement("col", {
className: "rst-endCap"
}), /* @__PURE__ */ React3.createElement("col", {
className: "rst-spacer"
}));
};
var ColGroup_default = React3.forwardRef(ColGroup);
// src/components/TableBody.jsx
import _12 from "lodash";
// src/components/ChunkObserver.jsx
import React9, { useCallback as useCallback3, useRef, useEffect, useContext as useContext3, useLayoutEffect as useLayoutEffect2 } from "react";
// src/components/TableChunk.jsx
import React8, { useLayoutEffect } from "react";
// src/components/TableRow.jsx
import React7 from "react";
// src/components/TableCell.jsx
import _8 from "lodash";
import React4 from "react";
var TableCell = ({ render, data, rowIndex, path, isHeader }) => {
const options = {
className: ""
};
const defaultContent = path ? _8.get(data, path) : rowIndex + 1;
const content = render(defaultContent, data, options);
const CellType = isHeader ? "th" : "td";
return /* @__PURE__ */ React4.createElement(CellType, {
className: "rst-cell " + options.className
}, content);
};
var TableCell_default = TableCell;
// src/hoc/withGestures.jsx
import React6, { useCallback as useCallback2, useContext as useContext2 } from "react";
// src/context/GestureTarget.js
import React5 from "react";
var GestureContext = React5.createContext(null);
GestureContext.displayName = "GestureContext";
var GestureTarget_default = GestureContext;
// src/hoc/withGestures.jsx
import _9 from "lodash";
function withGestures(Component) {
return function WithGestures({
gestureTarget,
onDualTap,
onDualTapDirect,
...props
}) {
const gesture = useContext2(GestureTarget_default);
props.handleGestureTouchStart = useCallback2((e) => {
if (gesture.isDragging)
return;
if (e.touches.length !== 2)
return;
if (_9.every(e.touches, (t) => e.currentTarget === t.target) && (onDualTapDirect == null ? void 0 : onDualTapDirect(e)) === false || _9.every(e.touches, (t) => e.currentTarget.contains(t.target)) && (onDualTap == null ? void 0 : onDualTap(e)) === false)
e.stopPropagation();
}, [gesture, onDualTap, onDualTapDirect]);
props.handleGesturePointerDownCapture = useCallback2(() => {
if (!gestureTarget)
return;
gesture.target = gestureTarget;
}, [gesture, gestureTarget]);
return /* @__PURE__ */ React6.createElement(Component, {
...props
});
};
}
// src/utils/dataAttributeUtils.js
import _10 from "lodash";
var getFlagAttribute = (flagName) => "data-is-" + flagName;
var getFlagAttributes = (flagNames) => _10.mapValues(flagNames, getFlagAttribute);
function dataAttributeFlags(flags2) {
const attributes = _10.mapKeys(flags2, (enabled, name) => getFlagAttribute(name));
return _10.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__ */ React7.createElement(TableCell_default, {
...column,
data,
rowIndex: index,
key: `cell_${name}_${key}_${colKey}`
});
return /* @__PURE__ */ React7.createElement("tr", {
ref,
className: "rst-row " + getRowClassName(data, key),
onPointerDownCapture: handleGesturePointerDownCapture,
onTouchStart: handleGestureTouchStart,
...dataAttributeFlags({
[flags.Active]: active,
[flags.Selected]: selected
})
}, columns.map(renderColumn), /* @__PURE__ */ React7.createElement("td", {
className: "rst-endCap"
}), /* @__PURE__ */ React7.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
import _11 from "lodash";
function comparePropsDeep(prev, next) {
return _11.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;
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__ */ React8.createElement(TableRow_default, {
...rowProps
});
};
return /* @__PURE__ */ React8.createElement("tbody", {
className: "rst-chunk",
ref
}, rows.map(renderRow));
}
var TableChunk_default = React8.memo(React8.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 = useRef();
const isRefreshingRef = useRef(false);
const { resizingIndex } = useContext3(ColumnGroup_default);
const refreshChunk = useCallback3(() => {
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]);
useEffect(() => {
if (!isRefreshingRef.current)
return;
chunkObserverRef.current.observe(chunkRef.current);
isRefreshingRef.current = false;
});
useLayoutEffect2(() => {
if (resizingIndex >= 0)
return;
refreshChunk();
}, [resizingIndex, refreshChunk]);
useLayoutEffect2(() => {
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]);
useEffect(() => {
const observer = chunkObserverRef.current;
if (!observer)
return;
const chunk = chunkRef.current;
observer.observe(chunk);
return () => observer.unobserve(chunk);
}, [chunkObserverRef]);
return /* @__PURE__ */ React9.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 = useMemo2(() => Math.ceil(options.chunkSize) * 2, [options]);
const keyChunks = useMemo2(
() => chunkSize > 0 ? _12.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__ */ React10.createElement(ChunkObserver_default, {
indexOffset: chunkIndexOffset,
rows,
key: `chunk_${props.name}_${chunkIndex}`,
...chunkCommonProps
});
};
return /* @__PURE__ */ React10.createElement("div", {
className: "rst-body",
tabIndex: 0
}, /* @__PURE__ */ React10.createElement("table", {
ref: tableBodyRef
}, /* @__PURE__ */ React10.createElement(ColGroup_default, {
name,
columns
}), !showPlaceholder && keyChunks.map(renderChunk)));
}
var TableBody_default = TableBody;
// src/components/TableHead.jsx
import React14, { useMemo as useMemo3, useContext as useContext5 } from "react";
import _13 from "lodash";
// src/components/TableHeader.jsx
import React13, { Fragment, useCallback as useCallback4, useContext as useContext4, useLayoutEffect as useLayoutEffect3, useRef as useRef2 } from "react";
// src/components/AngleIcon.jsx
import React11 from "react";
var angleRotation = Object.freeze({
Up: 0,
Down: 180,
Right: 90,
Left: -90
});
function AngleIcon({ rotation }) {
return /* @__PURE__ */ React11.createElement("svg", {
className: "rst-icon",
viewBox: "0 0 24 24",
style: { transform: `rotate(${rotation}deg)` }
}, /* @__PURE__ */ React11.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
import React12 from "react";
function HourGlassIcon({ rotation, ...rest }, ref) {
return /* @__PURE__ */ React12.createElement("svg", {
className: "rst-icon rst-loadingIcon",
viewBox: "0 0 24 32",
ref,
...rest
}, /* @__PURE__ */ React12.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 = React12.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 = useContext4(GestureTarget_default);
const isSortable = !!path;
const loadingIconRef = useRef2();
const sortColumn = useCallback4((addToPrev) => {
if (!isSortable)
return;
requestAnimationFrame(() => {
loadingIconRef.current.toggleAttribute(LoadingAttribute, true);
setTimeout(() => actions.sortItems(path, addToPrev));
});
return true;
}, [actions, path, isSortable]);
const handleTitleMouseDown = useCallback4((e) => {
if (e.button !== 0)
return;
sortColumn(e.shiftKey);
}, [sortColumn]);
const handleTitleKeyDown = useCallback4((e) => {
if (e.keyCode !== 32)
return;
e.stopPropagation();
if (!sortColumn(e.shiftKey))
return;
e.preventDefault();
}, [sortColumn]);
const handleTitleContextMenu = useCallback4(() => {
if (gesture.pointerType !== "touch")
return;
sortColumn(true);
}, [sortColumn, gesture]);
useLayoutEffect3(() => {
loadingIconRef.current.toggleAttribute(LoadingAttribute, false);
}, [sortAscending]);
return /* @__PURE__ */ React13.createElement("th", {
className,
onPointerDownCapture: handleGesturePointerDownCapture,
onTouchStart: handleGestureTouchStart,
...dataAttributeFlags({ sortable: isSortable, resizing: isResizing })
}, /* @__PURE__ */ React13.createElement("div", {
className: "rst-headerContent",
onMouseDown: handleTitleMouseDown,
onContextMenu: handleTitleContextMenu,
onKeyDown: handleTitleKeyDown,
tabIndex: isSortable ? 0 : -1,
role: "none"
}, /* @__PURE__ */ React13.createElement("span", {
className: "rst-headerText"
}, title), /* @__PURE__ */ React13.createElement(HourGlassIcon_default, {
ref: loadingIconRef
}), sortPriority >= 0 && /* @__PURE__ */ React13.createElement(Fragment, null, /* @__PURE__ */ React13.createElement(AngleIcon_default, {
rotation: sortAscending ? angleRotation.Up : angleRotation.Down
}), showPriority && /* @__PURE__ */ React13.createElement("small", null, sortPriority))), isResizable && /* @__PURE__ */ React13.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 = useMemo3(() => {
let priority = 0;
return {
orders: _13.mapValues(sortAscending, (ascending) => ({ ascending, priority: ++priority })),
maxPriority: priority
};
}, [sortAscending]);
const { resizingIndex } = useContext5(ColumnGroup_default);
const renderHeader = (column, index) => {
const { path, title } = column;
const sortOrder = sorting.orders[path];
return /* @__PURE__ */ React14.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__ */ React14.createElement("div", {
className: "rst-head",
onPointerDownCapture: handleGesturePointerDownCapture,
onTouchStart: handleGestureTouchStart
}, /* @__PURE__ */ React14.createElement("table", null, /* @__PURE__ */ React14.createElement(ColGroup_default, {
name,
columns,
ref: headColGroupRef
}), /* @__PURE__ */ React14.createElement("thead", null, /* @__PURE__ */ React14.createElement("tr", {
className: "rst-row",
ref: headRowRef
}, columns.map(renderHeader), /* @__PURE__ */ React14.createElement("th", {
className: "rst-endCap"
}), /* @__PURE__ */ React14.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 } = useContext6(ColumnGroup_default);
const gesture = useContext6(GestureTarget_default);
const rowCount = hooks.useSelector((s) => s.rowKeys.length);
const indexOffset = hooks.useSelector(selectors.getPageIndexOffset);
const handleMouseDown = useCallback5((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 = useCallback5((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 = _14.map(columns, "key");
const clippingStoppers = /* @__PURE__ */ React15.createElement("div", {
className: "rst-stoppers"
}, _14.map(columnKeys, (referenceKey) => {
const minWidthScale = options.minColumnWidth / widths[referenceKey];
return /* @__PURE__ */ React15.createElement("div", {
className: "rst-clippingStopper",
"data-col-key": referenceKey,
key: `stoppers-${referenceKey}`
}, _14.map(columnKeys, (key) => /* @__PURE__ */ React15.createElement("div", {
"data-col-key": key,
key: `stopper-${key}`,
style: { width: widths[key] * minWidthScale }
})));
}));
const resizingStopperWidths = _14.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__ */ React15.createElement(Fragment2, null, /* @__PURE__ */ React15.createElement("div", {
className: "rst-clippingContainer",
...dataAttributeFlags({ clipping: showClippingStoppers })
}, showClippingStoppers && clippingStoppers, /* @__PURE__ */ React15.createElement("div", {
className: "rst-resizingContainer",
style: {
width: pc(containerWidth),
marginRight: showClippingStoppers ? -_14.max(resizingStopperWidths) : 0
},
...gestureEventHandlers
}, !isResizing && (isOverflowing ? clippingStoppers : /* @__PURE__ */ React15.createElement("div", {
className: "rst-stoppers"
}, _14.map(columnKeys, (key, index) => /* @__PURE__ */ React15.createElement("div", {
className: "rst-resizingStopper",
"data-col-key": key,
key: `stopper-${key}`,
style: { width: resizingStopperWidths[index] }
})))), /* @__PURE__ */ React15.createElement(TableHead_default, {
...headProps,
gestureTarget: GestureTarget(GestureTargetTypes.Header, columns.length),
onDualTap: contextMenu
}), /* @__PURE__ */ React15.createElement(TableBody_default, {
...bodyProps
}), dragMode === DragModes.Select && /* @__PURE__ */ React15.createElement("div", {
className: "rst-dragSelection",
ref: selectionRectRef
}))), showPlaceholder && /* @__PURE__ */ React15.createElement("div", {
className: "rst-placeholder",
...gestureEventHandlers
}, placeholder));
}
var ResizingContainer_default = withGestures(ResizingContainer);
// src/hooks/useDecoupledCallback.js
import { useRef as useRef3, useEffect as useEffect2, useCallback as useCallback6 } from "react";
function useDecoupledCallback(callback) {
const callbackRef = useRef3(callback);
useEffect2(() => {
callbackRef.current = callback;
}, [callback]);
return useCallback6((...args) => {
var _a;
return (_a = callbackRef.current) == null ? void 0 : _a.call(callbackRef, ...args);
}, [callbackRef]);
}
// src/hooks/useEventListener.js
import { useCallback as useCallback7 } from "react";
// src/hooks/useObjectMemo.js
import { useRef as useRef4 } from "react";
import _15 from "lodash";
function useObjectMemo(obj) {
const objRef = useRef4(obj);
if (!_15.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 = useCallback7(
(element) => element.addEventListener(type, decoupledHandler, options),
[decoupledHandler, type, options]
);
const remove = useCallback7(
(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 = _16.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 = useContext7(GestureTarget_default);
const [dragMode, setDragMode] = useState(null);
useLayoutEffect4(() => {
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 = useRef5();
const headColGroupRef = useRef5();
const headRowRef = useRef5();
const selectionRectRef = useRef5();
const scrollingContainerRef = useRef5();
const getRow = useCallback8((index) => tableBodyRef.current.rows[index], []);
const getCurrentHeaderWidths = useCallback8(
() => _16.map(_16.take(headRowRef.current.children, columns.length), (h) => h.getBoundingClientRect().width),
[columns]
);
const [columnGroup, setColumnGroup] = useState({
widths: initColumnWidths,
resizingIndex: -1
});
const getRenderedColumnsWidthsPatch = useCallback8((widths) => _16.zipObject(_16.map(columns, "key"), widths), [columns]);
const defaultWidths = useMemo4(() => {
const defaultWidth = 100 / columns.length;
const widths = _16.map(columns, (c) => +c.defaultWidth || defaultWidth);
return getRenderedColumnsWidthsPatch(widths);
}, [columns, getRenderedColumnsWidthsPatch]);
const allWidths = useMemo4(() => {
const validWidths = _16.mapValues(
columnGroup.widths,
(width, key) => width || negative(defaultWidths[key])
);
return { ...defaultWidths, ...validWidths };
}, [columnGroup, defaultWidths]);
const fullColumnGroup = useMemo4(() => {
const visibleWidths = columns.map((c) => allWidths[c.key]).filter((w) => w >= 0);
const { resizingIndex } = columnGroup;
const isResizing = resizingIndex >= 0;
return {
resizingIndex,
widths: _16.mapValues(allWidths, Math.abs),
containerWidth: isResizing ? 0 : Math.max(100, _16.sum(visibleWidths)),
widthUnit: isResizing ? px : pc
};
}, [columnGroup, columns, allWidths]);
const setRenderedColumnWidths = useCallback8((widths, resizingIndex = -1) => {
const renderedPatch = getRenderedColumnsWidthsPatch(widths);
const visiblePatch = _16.pickBy(renderedPatch, isColumnVisible);
const hiddenPatch = _16.mapValues(renderedPatch, (w, key) => negative(allWidths[key]));
setColumnGroup({
widths: _16.defaults(visiblePatch, hiddenPatch, allWidths),
resizingIndex
});
if (resizingIndex >= 0)
return;
componentEvents.columnResize(visiblePatch);
}, [getRenderedColumnsWidthsPatch, componentEvents, allWidths]);
const drag = useRef5({
invertScroll: false,
animationId: null,
pointerPos: Point(),
pointerId: null,
movement: Point(0, 0),
ctrlKey: false
}).current;
const columnResizing = useRef5({
prevVisibleIndex: -1,
borderLeft: 0,
header: null,
distanceOfPrevToStart: 0,
isResizingSpacer: false,
minWidth: 0
}).current;
const dragSelection = useRef5({
selection: {},
selectionBuffer: {},
originRel: Point(),
activeIndex: null,
pivotIndex: null,
prevRowIndex: -1,
prevRelY: 0
}).current;
const columnResizeEnd = useCallback8(() => {
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 = useCallback8(() => {
if (dragSelection.activeIndex == null)
return;
actions.setSelected(
_16.mapKeys(dragSelection.selection, (_23, rowIndex) => rowKeys[rowIndex]),
dragSelection.activeIndex + indexOffset,
dragSelection.pivotIndex + indexOffset
);
}, [dragSelection, actions, rowKeys, indexOffset]);
const dragEnd = useMemo4(() => ({
[DragModes.Resize]: columnResizeEnd,
[DragModes.Select]: dragSelectEnd
})[dragMode], [dragMode, columnResizeEnd, dragSelectEnd]);
const dragStop = useCallback8(() => {
if (drag.pointerId != null) {
scrollingContainerRef.current.releasePointerCapture(drag.pointerId);
drag.pointerId = null;
}
if (drag.animationId != null)
return;
dragEnd();
setDragMode(null);
}, [drag, dragEnd]);
const dragAnimate = useCallback8((callback) => {
cancelAnimationFrame(drag.animationId);
drag.animationId = requestAnimationFrame(() => {
callback();
drag.animationId = null;
drag.movement.x = 0;
drag.movement.y = 0;
if (drag.pointerId == null)
setTimeout(dragStop, 0);
});
}, [drag, dragStop]);
const columnResizeAnimation = useCallback8((changedWidths, newScroll) => {
const colGroup = headColGroupRef.current;
const container = scrollingContainerRef.current;
for (const index in changedWidths)
colGroup.children[index].style.width = px(changedWidths[index]);
container.scrollLeft = newScroll;
}, []);
const dragSelectAnimation = useCallback8((relX, relY, scrollLeftOffset, scrollTopOffset) => {
const container = scrollingContainerRef.current;
container.scrollLeft += scrollLeftOffset;
container.scrollTop += scrollTopOffset;
const { originRel } = dragSelection;
const lineX = getLine(relX, originRel.x);
const lineY = getLine(relY, originRel.y);
const body = tableBodyRef.current;
Object.assign(selectionRectRef.current.style, _16.mapValues({
left: lineX.origin,
width: lineX.size,
top: lineY.origin + body.offsetTop,
height: lineY.size
}, px));
_16.forEach(dragSelection.selectionBuffer, (selected, index) => {
getRow(index).toggleAttribute(RowAttributes.Selected, selected);
});
dragSelection.selectionBuffer = {};
if (dragSelection.activeIndex == null)
return;
const newActiveRow = getRow(dragSelection.activeIndex);
if (newActiveRow === dragSelection.activeRow)
return;
dragSelection.activeRow.toggleAttribute(RowAttributes.Active, false);
dragSelection.activeRow = newActiveRow;
dragSelection.activeRow.toggleAttribute(RowAttributes.Active, true);
}, [dragSelection, getRow]);
const columnResizeUpdate = useCallback8(() => {
const index = columnGroup.resizingIndex;
if (index < 0)
return;
const {
prevVisibleIndex,
header,
distanceOfPrevToStart,
isResizingSpacer,
minWidth,
borderLeft
} = columnResizing;
const constantWidth = options.constantWidth || drag.ctrlKey;
const container = scrollingContainerRef.current;
const containerX = getClientX(container);
const { clientWidth, scrollWidth, scrollLeft } = container;
const head = headRowRef.current;
const { lastChild: spacer } = head;
const shrinkThresholdColumn = scrollLeft && (isResizingSpacer || !constantWidth) ? clientWidth - spacer.offsetLeft + header.offsetLeft : -Infinity;
const shrinkThreshold = containerX + Math.max(0, shrinkThresholdColumn);
const expandThreshold = containerX + clientWidth;
const { relToOrigin: relX, scrollOffset } = getRelativeOffset(
drag.pointerPos.x,
getClientX(head),
shrinkThreshold,
expandThreshold,
columnResizeScrollFactor
);
let movementOffset = 0;
if (scrollWidth > clientWidth) {
const scrollRemaining = constantWidth ? scrollWidth - scrollLeft - clientWidth : Infinity;
movementOffset = _16.clamp(drag.movement.x, -scrollLeft, scrollRemaining);
}
const offsetSum = Math.floor(movementOffset + scrollOffset);
const offsetRight = isResizingSpacer ? head.offsetWidth : header.offsetLeft + header.offsetWidth;
const sharedWidth = constantWidth ? offsetRight - distanceOfPrevToStart : Infinity;
const minPrevWidth = options.minColumnWidth;
const targetWidth = Math.floor(relX - distanceOfPrevToStart) + offsetSum - borderLeft;
const newPrevWidth = _16.clamp(targetWidth, minPrevWidth, sharedWidth - minWidth);
const changedWidths = { [prevVisibleIndex]: newPrevWidth };
if (constantWidth && !isResizingSpacer)
changedWidths[index] = sharedWidth - newPrevWidth;
const newScroll = Math.ceil(scrollLeft) + offsetSum;
dragAnimate(() =