use-table-tools
Version:
react hook for building powerful table components
493 lines (484 loc) • 20.1 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
var isClient = typeof window === 'object';
var useWindowSize = function (shouldDoCalculations) {
if (shouldDoCalculations === void 0) { shouldDoCalculations = 'yes'; }
var _a = React.useState({
width: isClient ? window.innerWidth : Infinity,
height: isClient ? window.innerHeight : Infinity,
}), state = _a[0], setState = _a[1];
React.useEffect(function () {
if (isClient && shouldDoCalculations === 'yes') {
var handler_1 = function () {
setState({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handler_1);
return function () { return window.removeEventListener('resize', handler_1); };
}
}, [shouldDoCalculations]);
return state;
};
var getObjectValueByString = function (obj, path) {
return path.split('.').reduce(function (acc, part) { return acc && acc[part]; }, obj);
};
var getOffsetColumns = function (visibleColumns, columns, includeVisible) {
if (includeVisible === void 0) { includeVisible = false; }
if (visibleColumns.length) {
var visible_1 = visibleColumns.map(function (_a) {
var sortKey = _a.sortKey;
return sortKey;
});
return columns
.filter(function (_a) {
var isLocked = _a.isLocked;
return !isLocked;
})
.map(function (column) {
if (visible_1.includes(column.sortKey)) {
return Object.assign(column, { visible: true });
}
else {
return Object.assign(column, { visible: false });
}
})
.filter(function (_a) {
var visible = _a.visible;
return (includeVisible ? true : !visible);
});
}
else {
return [];
}
};
var callAllEventHandlers = function () {
var fns = [];
for (var _i = 0; _i < arguments.length; _i++) {
fns[_i] = arguments[_i];
}
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return fns.some(function (fn) {
if (fn) {
fn.apply(void 0, args);
}
});
};
};
var __assign = (undefined && undefined.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (undefined && undefined.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArrays = (undefined && undefined.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var actionTypes = {
updateState: 'updateState',
switchColumns: 'switchColumns',
switchCurrentLayout: 'switchCurrentLayout',
deselectAll: 'deselectAll',
selectAll: 'selectAll',
checkboxToggle: 'checkboxToggle',
checkboxShiftToggle: 'checkboxShiftToggle',
changeSortDirection: 'changeSortDirection',
toggleSortDirection: 'toggleSortDirection',
toggleSortByKey: 'toggleSortByKey',
sortData: 'sortData',
};
var tableToolsReducer = function (state, action) {
switch (action.type) {
case actionTypes.updateState: {
return __assign(__assign({}, state), action.payload);
}
case actionTypes.switchColumns: {
var _a = action.payload, to_1 = _a.to, from_1 = _a.from;
var columns = state.visibleColumns;
var index = columns.findIndex(function (x) { return x.sortKey === from_1; });
var visibleColumns = columns.filter(function (col) { return col.sortKey !== from_1; });
var replacement = getOffsetColumns(state.visibleColumns, state.columns).find(function (_a) {
var sortKey = _a.sortKey;
return sortKey === to_1;
});
if (replacement) {
visibleColumns.splice(index, 0, replacement);
}
return __assign(__assign({}, state), { visibleColumns: visibleColumns });
}
case actionTypes.switchCurrentLayout: {
var currentLayout = action.payload.currentLayout;
var visibleSortFields_1 = state.visibleColumns
.map(function (_a) {
var sortField = _a.sortField;
return sortField;
})
.reverse();
return __assign(__assign({}, state), { currentLayout: currentLayout, visibleColumns: state.columns
.sort(function (a, b) {
return (visibleSortFields_1.indexOf(b.sortKey) -
visibleSortFields_1.indexOf(a.sortKey));
})
.slice(0, currentLayout.length) });
}
case actionTypes.deselectAll: {
return __assign(__assign({}, state), { selectAllCheckboxState: 'none', checkedItems: [] });
}
case actionTypes.selectAll: {
var items = action.payload.items;
return __assign(__assign({}, state), { checkedItems: items, selectAllCheckboxState: state.totalItems === items.length ? 'all' : 'some' });
}
case actionTypes.checkboxToggle: {
var _b = action.payload, id = _b.id, rowId_1 = _b.value;
var checkedItems = state.checkedItems;
if (!checkedItems.includes(rowId_1)) {
var allCheckedItems = __spreadArrays(state.checkedItems, [rowId_1]);
return __assign(__assign({}, state), { lastChecked: { id: id, value: rowId_1 }, checkedItems: allCheckedItems, selectAllCheckboxState: state.totalItems === allCheckedItems.length ? 'all' : 'some' });
}
else {
var allCheckedItems = checkedItems.filter(function (id) { return id !== rowId_1; });
return __assign(__assign({}, state), { lastChecked: { id: id, value: rowId_1 }, checkedItems: allCheckedItems, selectAllCheckboxState: allCheckedItems.length ? 'some' : 'none' });
}
}
case actionTypes.checkboxShiftToggle: {
var checkedItems = state.checkedItems, lastChecked = state.lastChecked;
var _c = action.payload, id = _c.id, value = _c.value, refs = _c.refs;
if (lastChecked) {
var rows = Array.from(refs);
var lastCheckedId = parseInt(lastChecked.id);
var currentCheckedId = parseInt(id);
var slicedInputs = void 0;
var checked = [];
if (lastCheckedId < currentCheckedId) {
slicedInputs = rows.slice(lastCheckedId, currentCheckedId + 1);
}
else {
slicedInputs = rows.slice(currentCheckedId, lastCheckedId + 1);
}
var rangeIds_1 = slicedInputs.map(function (ref) { return ref.value; });
if (checkedItems.includes(lastChecked.value) &&
!checkedItems.includes(value)) {
checked = checkedItems.concat(rangeIds_1);
}
else if (!checkedItems.includes(lastChecked.value) &&
!checkedItems.includes(value)) {
checked = checkedItems.concat(rangeIds_1);
}
else {
checked = checkedItems.filter(function (id) {
return rangeIds_1.includes(id) ? false : true;
});
}
return __assign(__assign({}, state), { lastChecked: { id: id, value: value }, checkedItems: checked, selectAllCheckboxState: checked.length
? state.totalItems === checked.length
? 'all'
: 'some'
: 'none' });
}
else {
return __assign(__assign({}, state), { lastChecked: { id: id, value: value } });
}
}
case actionTypes.changeSortDirection: {
return __assign(__assign({}, state), { currentSort: {
fieldKey: state.currentSort.fieldKey,
direction: action.payload.direction,
} });
}
case actionTypes.toggleSortDirection: {
var currentSort = state.currentSort;
return __assign(__assign({}, state), { currentSort: {
direction: currentSort.direction === 'asc' ? 'dsc' : 'asc',
fieldKey: currentSort.fieldKey,
} });
}
case actionTypes.toggleSortByKey: {
var currentSort = state.currentSort;
var fieldKey = action.payload.fieldKey;
return __assign(__assign({}, state), { currentSort: {
fieldKey: fieldKey,
direction: currentSort.direction === 'asc' ? 'desc' : 'asc',
} });
}
case actionTypes.sortData: {
var _d = action.payload, fieldKey = _d.fieldKey, direction = _d.direction;
return __assign(__assign({}, state), { currentSort: { fieldKey: fieldKey, direction: direction } });
}
default: {
throw new Error("Unhandled type: " + action.type);
}
}
};
var useTableTools = function (_a, reducer) {
var _b = _a.layout, layout = _b === void 0 ? ['0 0 25%', '1 1 35%', '0 0 20%', '0 0 20%'] : _b, _c = _a.totalItems, totalItems = _c === void 0 ? 0 : _c, _d = _a.clientSortBy, clientSortBy = _d === void 0 ? { direction: 'asc', fieldKey: '' } : _d, _e = _a.columns, columns = _e === void 0 ? [] : _e, _f = _a.checkedItems, checkedItems = _f === void 0 ? [] : _f;
if (reducer === void 0) { reducer = tableToolsReducer; }
var checkboxRefs = new Set();
var width = useWindowSize(Array.isArray(layout) ? 'no' : 'yes').width;
var _g = React.useReducer(reducer, {
currentLayout: [],
visibleColumns: [],
columns: columns,
totalItems: totalItems,
currentSort: clientSortBy,
checkedItems: checkedItems,
selectAllCheckboxState: 'none',
lastChecked: null,
}), state = _g[0], send = _g[1];
React.useLayoutEffect(function () {
if (Array.isArray(layout)) {
return send({
type: actionTypes.updateState,
payload: {
currentLayout: layout,
visibleColumns: columns.slice(0, layout.length),
},
});
}
Object.keys(layout).map(function (breakpoint) {
if (breakpoint < width) {
switchCurrentLayout(layout[breakpoint]);
}
return undefined;
});
}, [width]);
var switchColumns = function (from, to) {
send({ type: actionTypes.switchColumns, payload: { to: to, from: from } });
};
var switchCurrentLayout = function (nextLayout) {
send({
type: actionTypes.switchCurrentLayout,
payload: { currentLayout: nextLayout },
});
};
var offsetColumns = React.useCallback(function (_a) {
var includeVisible = (_a === void 0 ? {} : _a).includeVisible;
return getOffsetColumns(state.visibleColumns, state.columns, includeVisible);
}, [state.visibleColumns, state.columns]);
var onSelection = function (items) {
switch (state.selectAllCheckboxState) {
case 'all':
return deselectAll();
case 'some':
return deselectAll();
case 'none':
return selectAll(items);
default:
return deselectAll();
}
};
var deselectAll = function () {
send({ type: actionTypes.deselectAll });
};
var selectAll = function (items) {
send({
type: actionTypes.selectAll,
payload: { items: items.map(function (item) { return String(item); }) },
});
};
var checkboxToggle = function (evt) {
send({
type: actionTypes.checkboxToggle,
payload: { id: String(evt.target.id), value: String(evt.target.value) },
});
};
var checkboxShiftToggle = function (evt) {
if (evt.shiftKey && state.lastChecked) {
send({
type: actionTypes.checkboxShiftToggle,
payload: {
id: String(evt.target.id),
value: String(evt.target.value),
refs: checkboxRefs,
},
});
return;
}
send({
type: actionTypes.checkboxToggle,
payload: { id: String(evt.target.id), value: String(evt.target.value) },
});
};
var checkboxState = function (itemId) {
if (!state.checkedItems || state.checkedItems.length < 1) {
return false;
}
return state.checkedItems.includes(String(itemId));
};
var clientSortMethod = function (a, b) {
var _a = state.currentSort, fieldKey = _a.fieldKey, direction = _a.direction;
if (fieldKey && direction) {
var valueA = getObjectValueByString(a, fieldKey);
var valueB = getObjectValueByString(b, fieldKey);
valueA = valueA === null || valueA === undefined ? '' : valueA;
valueB = valueB === null || valueB === undefined ? '' : valueB;
valueA = typeof valueA === 'string' ? valueA.toLowerCase() : valueA;
valueB = typeof valueB === 'string' ? valueB.toLowerCase() : valueB;
if (direction.toLowerCase() === 'asc') {
if (valueA < valueB) {
return -1;
}
else if (valueA > valueB) {
return 1;
}
else {
return 0;
}
}
if (direction.toLowerCase() === 'desc') {
if (valueA > valueB) {
return -1;
}
else if (valueA < valueB) {
return 1;
}
else {
return 0;
}
}
return 0;
}
return 0;
};
var changeSortDirection = function (direction) {
send({ type: actionTypes.changeSortDirection, payload: { direction: direction } });
};
var toggleSortDirection = function () {
send({
type: actionTypes.toggleSortDirection,
});
};
var toggleSortByKey = function (fieldKey) {
send({
type: actionTypes.toggleSortByKey,
payload: { fieldKey: fieldKey },
});
};
var sortData = function (_a) {
var direction = _a.direction, fieldKey = _a.fieldKey;
send({ type: actionTypes.sortData, payload: { direction: direction, fieldKey: fieldKey } });
};
var activeSort = function (_a) {
var direction = _a.direction, fieldKey = _a.fieldKey;
var currentSort = state.currentSort;
var isActive = currentSort.fieldKey === fieldKey;
var isCurrentSortDir = currentSort.direction === direction;
return isActive && isCurrentSortDir;
};
var activeSortKey = function (fieldKey) {
var currentSort = state.currentSort;
return currentSort.fieldKey === fieldKey;
};
var getCheckboxProps = function (_a) {
if (_a === void 0) { _a = {}; }
var _b = _a.master, master = _b === void 0 ? false : _b, rest = __rest(_a, ["master"]);
if (master) {
return __assign({}, rest);
}
return __assign({ ref: function (ref) { return ref && checkboxRefs.add(ref); } }, rest);
};
return Object.assign(state, {
switchColumns: switchColumns,
switchCurrentLayout: switchCurrentLayout,
onSelection: onSelection,
deselectAll: deselectAll,
selectAll: selectAll,
offsetColumns: offsetColumns,
checkboxToggle: checkboxToggle,
checkboxShiftToggle: checkboxShiftToggle,
checkboxState: checkboxState,
clientSortMethod: clientSortMethod,
changeSortDirection: changeSortDirection,
toggleSortDirection: toggleSortDirection,
toggleSortByKey: toggleSortByKey,
sortData: sortData,
activeSort: activeSort,
activeSortKey: activeSortKey,
getCheckboxProps: getCheckboxProps,
});
};
var __rest$1 = (undefined && undefined.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var TableToolsContext = React.createContext({
currentLayout: [],
visibleColumns: [],
totalItems: 0,
columns: [],
checkedItems: [],
selectAllCheckboxState: 'none',
currentSort: { direction: 'asc', fieldKey: '' },
lastChecked: null,
switchColumns: function () { },
switchCurrentLayout: function () { },
offsetColumns: function () { return []; },
onSelection: function () { },
deselectAll: function () { },
selectAll: function () { },
checkboxToggle: function () { },
checkboxShiftToggle: function () { },
checkboxState: function () { return false; },
clientSortMethod: function () { return 0; },
changeSortDirection: function () { },
toggleSortDirection: function () { },
toggleSortByKey: function () { },
sortData: function () { },
activeSort: function () { return false; },
activeSortKey: function () { return false; },
getCheckboxProps: function () { },
});
var TableTools = function (_a) {
var children = _a.children, stateReducer = _a.stateReducer, rest = __rest$1(_a, ["children", "stateReducer"]);
var utils = useTableTools(rest, stateReducer);
var ui = typeof children === 'function' ? children(utils) : children;
return (React__default.createElement(TableToolsContext.Provider, { value: utils }, ui));
};
var useTableToolsContext = function () {
var utils = React.useContext(TableToolsContext);
return utils;
};
exports.TableTools = TableTools;
exports.actionTypes = actionTypes;
exports.callAllEventHandlers = callAllEventHandlers;
exports.default = useTableTools;
exports.getObjectValueByString = getObjectValueByString;
exports.getOffsetColumns = getOffsetColumns;
exports.tableToolsReducer = tableToolsReducer;
exports.useTableTools = useTableTools;
exports.useTableToolsContext = useTableToolsContext;
//# sourceMappingURL=index.cjs.js.map