@appbuckets/react-ui
Version:
Just Another React UI Framework
283 lines (280 loc) • 8.04 kB
JavaScript
import { __read, __spreadArray } from 'tslib';
import * as React from 'react';
import invariant from 'tiny-invariant';
import areEqualStringArray from '../../utils/areEqualStringArray.js';
import 'clsx';
/* --------
* Main Hook Definition
* -------- */
function useDataSelector(config) {
var allData = config.allData,
filteredData = config.filteredData,
selectable = config.selectable,
defaultSelectedData = config.defaultSelectedData,
userDefinedGetRowKey = config.getRowKey,
onSelectedDataChange = config.onSelectedDataChange;
// ----
// Memoize the RowKey extractor
// ----
var getRowKey = React.useCallback(
function (row, index, array) {
if (typeof userDefinedGetRowKey === 'function') {
return userDefinedGetRowKey(row, index, array);
}
if (typeof userDefinedGetRowKey === 'string') {
return row[userDefinedGetRowKey];
}
return '';
},
[userDefinedGetRowKey]
);
// ----
// Invariant Check selectable and getRowKey
// ----
if (process.env.NODE_ENV === 'development' && selectable) {
invariant(
typeof getRowKey === 'function',
'To correctly use selectable table the getRowKey' +
'function must be declared'
);
}
// ----
// Build a Map with all data keys
// ----
var dataKeys = React.useMemo(
function () {
/** Build a new Map to save all data keys */
var keys = new Map();
/** Loop each row and get it's own key */
allData.forEach(function (row, index, array) {
keys.set(row, getRowKey(row, index, array));
});
return keys;
},
[allData, getRowKey]
);
var filteredDataKeys = React.useMemo(
function () {
/** Build a new Map to save all data keys */
var keys = new Map();
/** Loop filtered data only and save key */
filteredData.forEach(function (row) {
/** Get key from dataKeys */
var key = dataKeys.get(row);
/** If exists, push into keys */
if (key !== undefined) {
keys.set(row, key);
}
});
return keys;
},
[dataKeys, filteredData]
);
// ----
// Initialize Internal State to keep tracking of Selected Keys
// ----
var _a = __read(
React.useState(
defaultSelectedData && selectable
? defaultSelectedData
.filter(function (row) {
return dataKeys.has(row);
})
.map(function (row) {
return dataKeys.get(row);
})
: []
),
2
),
selectedKeys = _a[0],
setSelectedKeys = _a[1];
// ----
// Internal Helpers
// ----
var getSelectedData = React.useCallback(
function (currentSelected) {
if (currentSelected === void 0) {
currentSelected = selectedKeys;
}
return allData.filter(function (row) {
/** Get the row key */
var key = dataKeys.get(row);
/** Return key exists and is included into selectedKeys */
return key !== undefined && currentSelected.includes(key);
});
},
[allData, dataKeys, selectedKeys]
);
// ----
// Handlers
// ----
var handleSelectedDataChange = React.useCallback(
function (currentSelected) {
if (typeof onSelectedDataChange === 'function') {
onSelectedDataChange(getSelectedData(currentSelected));
}
},
[getSelectedData, onSelectedDataChange]
);
// ----
// Public Helpers
// ----
var isRowSelected = React.useCallback(
function (rowToCheck) {
/** Get the row key */
var key = dataKeys.get(rowToCheck);
/** Check if is selected */
return key !== undefined && selectedKeys.includes(key);
},
[dataKeys, selectedKeys]
);
var selectAllRows = React.useCallback(
function () {
/** Build an array of new Selected item using all keys */
var newSelected = __spreadArray(
[],
__read(
new Set(
__spreadArray(
__spreadArray([], __read(selectedKeys), false),
__read(Array.from(filteredDataKeys.values())),
false
)
)
),
false
);
/** Update the state */
setSelectedKeys(function () {
handleSelectedDataChange(newSelected);
return newSelected;
});
},
[filteredDataKeys, selectedKeys, handleSelectedDataChange]
);
var deselectAllRows = React.useCallback(
function () {
/** Build a new empty array of selected keys */
var newSelected = [];
/** Update the state */
setSelectedKeys(function () {
handleSelectedDataChange(newSelected);
return newSelected;
});
},
[handleSelectedDataChange]
);
var selectRow = React.useCallback(
function () {
var rows = [];
for (var _i = 0; _i < arguments.length; _i++) {
rows[_i] = arguments[_i];
}
/** Transform rows into a React.Key array */
var rowsKey = rows
.map(function (row) {
return dataKeys.get(row);
})
.filter(function (key) {
return key !== undefined && !selectedKeys.includes(key);
});
if (rowsKey.length) {
var newSelected_1 = __spreadArray(
__spreadArray([], __read(selectedKeys), false),
__read(rowsKey),
false
);
setSelectedKeys(function () {
handleSelectedDataChange(newSelected_1);
return newSelected_1;
});
}
},
[dataKeys, handleSelectedDataChange, selectedKeys]
);
var deselectRow = React.useCallback(
function () {
var rows = [];
for (var _i = 0; _i < arguments.length; _i++) {
rows[_i] = arguments[_i];
}
/** Transform rows into a React.Key array */
var rowsKey = rows
.map(function (row) {
return dataKeys.get(row);
})
.filter(function (key) {
return key !== undefined && selectedKeys.includes(key);
});
/** Remove found keys */
if (rowsKey.length) {
var newSelected_2 = __spreadArray(
[],
__read(selectedKeys),
false
).filter(function (key) {
return !rowsKey.includes(key);
});
setSelectedKeys(function () {
handleSelectedDataChange(newSelected_2);
return newSelected_2;
});
}
},
[dataKeys, handleSelectedDataChange, selectedKeys]
);
var toggleSelectRow = React.useCallback(
function (rowToToggle) {
if (isRowSelected(rowToToggle)) {
deselectRow(rowToToggle);
} else {
selectRow(rowToToggle);
}
},
[isRowSelected, deselectRow, selectRow]
);
// ----
// Assert selectedKeys validity on data change
// ----
React.useEffect(
function () {
/** Avoid is selecting is disabled */
if (!selectable) {
return;
}
/** Get all selected keys */
var dataIDs = Array.from(dataKeys.values());
/** Build a new array of selected keys */
var newSelected = __spreadArray([], __read(selectedKeys), false).filter(
function (key) {
return dataIDs.includes(key);
}
);
/** If selected data is different, update state */
if (!areEqualStringArray(newSelected, selectedKeys)) {
setSelectedKeys(function () {
handleSelectedDataChange(newSelected);
return newSelected;
});
}
},
[dataKeys, handleSelectedDataChange, selectable, selectedKeys]
);
// ----
// Return Controller
// ----
return {
areAllRowsSelected: selectedKeys.length === allData.length,
deselectAllRows: deselectAllRows,
deselectRow: deselectRow,
getRowKey: getRowKey,
isRowSelected: isRowSelected,
selectAllRows: selectAllRows,
selectedData: getSelectedData(),
selectedCount: selectedKeys.length,
selectRow: selectRow,
toggleSelectRow: toggleSelectRow,
};
}
export { useDataSelector as default };