UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

359 lines (356 loc) 23.9 kB
import { __rest, __assign, __spreadArray } from '../../node_modules/tslib/tslib.es6.js'; import React, { forwardRef, useRef, useState, useMemo, useEffect } from 'react'; import PropTypes from 'prop-types'; import { CIcon } from '../../node_modules/@coreui/icons-react/dist/index.esm.js'; import { CElementCover } from '../element-cover/CElementCover.js'; import '../form/CForm.js'; import '../form/CFormCheck.js'; import '../form/CFormControlValidation.js'; import '../form/CFormControlWrapper.js'; import '../form/CFormFeedback.js'; import '../form/CFormFloating.js'; import { CFormInput } from '../form/CFormInput.js'; import { CFormLabel } from '../form/CFormLabel.js'; import '../form/CFormRange.js'; import { CFormSelect } from '../form/CFormSelect.js'; import '../form/CFormSwitch.js'; import '../form/CFormText.js'; import '../form/CFormTextarea.js'; import '../form/CInputGroup.js'; import '../form/CInputGroupText.js'; import { CSmartPagination } from '../smart-pagination/CSmartPagination.js'; import { CTable } from '../table/CTable.js'; import '../table/CTableBody.js'; import '../table/CTableCaption.js'; import { CTableDataCell } from '../table/CTableDataCell.js'; import { CTableFoot } from '../table/CTableFoot.js'; import '../table/CTableHead.js'; import '../table/CTableHeaderCell.js'; import { CTableRow } from '../table/CTableRow.js'; import { CSmartTableBody } from './CSmartTableBody.js'; import { CSmartTableHead } from './CSmartTableHead.js'; import isObjectInArray from '../../utils/isObjectInArray.js'; import { ITEM_INTERNAL_KEYS } from './consts.js'; import { getColumnNames, getColumnNamesFromItems, filterColumns, filterTable, sortItems, isSortable } from './utils.js'; import { cilSwapVertical } from '../../node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js'; import { cilArrowTop } from '../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js'; import { cilArrowBottom } from '../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js'; import { cilFilterX } from '../../node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js'; var CSmartTable = forwardRef(function (_a, ref) { var _b = _a.activePage, activePage = _b === void 0 ? 1 : _b, cleaner = _a.cleaner, clickableRows = _a.clickableRows, columnFilter = _a.columnFilter, columnFilterValue = _a.columnFilterValue, // TODO: consider to use only columnFilter prop columns = _a.columns, columnSorter = _a.columnSorter, elementCover = _a.elementCover, footer = _a.footer, _c = _a.header, header = _c === void 0 ? true : _c, _d = _a.items, items = _d === void 0 ? [] : _d, itemsNumber = _a.itemsNumber, _e = _a.itemsPerPage, itemsPerPage = _e === void 0 ? 10 : _e, _f = _a.itemsPerPageLabel, itemsPerPageLabel = _f === void 0 ? 'Items per page:' : _f, _g = _a.itemsPerPageOptions, itemsPerPageOptions = _g === void 0 ? [5, 10, 20, 50] : _g, itemsPerPageSelect = _a.itemsPerPageSelect, loading = _a.loading, _h = _a.noItemsLabel, noItemsLabel = _h === void 0 ? 'No items found' : _h, onActivePageChange = _a.onActivePageChange, onColumnFilterChange = _a.onColumnFilterChange, onFilteredItemsChange = _a.onFilteredItemsChange, onItemsPerPageChange = _a.onItemsPerPageChange, onRowClick = _a.onRowClick, onSelectAll = _a.onSelectAll, onSelectedItemsChange = _a.onSelectedItemsChange, onSorterChange = _a.onSorterChange, onTableFilterChange = _a.onTableFilterChange, pagination = _a.pagination, paginationProps = _a.paginationProps, scopedColumns = _a.scopedColumns, selected = _a.selected, selectable = _a.selectable, _j = _a.selectAll, selectAll = _j === void 0 ? true : _j, sorterValue = _a.sorterValue, _k = _a.sortingIcon, sortingIcon = _k === void 0 ? React.createElement(CIcon, { width: 18, icon: cilSwapVertical, key: "csv" }) : _k, _l = _a.sortingIconAscending, sortingIconAscending = _l === void 0 ? React.createElement(CIcon, { width: 18, icon: cilArrowTop, key: "cat" }) : _l, _m = _a.sortingIconDescending, sortingIconDescending = _m === void 0 ? React.createElement(CIcon, { width: 18, icon: cilArrowBottom, key: "cab" }) : _m, tableBodyProps = _a.tableBodyProps, tableFootProps = _a.tableFootProps, tableFilter = _a.tableFilter, _o = _a.tableFilterLabel, tableFilterLabel = _o === void 0 ? 'Filter:' : _o, _p = _a.tableFilterPlaceholder, tableFilterPlaceholder = _p === void 0 ? 'type string...' : _p, tableFilterValue = _a.tableFilterValue, tableHeadProps = _a.tableHeadProps, tableProps = _a.tableProps, rest = __rest(_a, ["activePage", "cleaner", "clickableRows", "columnFilter", "columnFilterValue", "columns", "columnSorter", "elementCover", "footer", "header", "items", "itemsNumber", "itemsPerPage", "itemsPerPageLabel", "itemsPerPageOptions", "itemsPerPageSelect", "loading", "noItemsLabel", "onActivePageChange", "onColumnFilterChange", "onFilteredItemsChange", "onItemsPerPageChange", "onRowClick", "onSelectAll", "onSelectedItemsChange", "onSorterChange", "onTableFilterChange", "pagination", "paginationProps", "scopedColumns", "selected", "selectable", "selectAll", "sorterValue", "sortingIcon", "sortingIconAscending", "sortingIconDescending", "tableBodyProps", "tableFootProps", "tableFilter", "tableFilterLabel", "tableFilterPlaceholder", "tableFilterValue", "tableHeadProps", "tableProps"]); var mountedRef = useRef(false); var _q = useState(activePage), _activePage = _q[0], setActivePage = _q[1]; var _r = useState([]), _items = _r[0], setItems = _r[1]; var _s = useState(itemsPerPage), _itemsPerPage = _s[0], setItemsPerPage = _s[1]; var _t = useState([]), _selected = _t[0], setSelected = _t[1]; var _u = useState({}), columnFilterState = _u[0], setColumnFilterState = _u[1]; var _v = useState(), selectedAll = _v[0], setSelectedAll = _v[1]; var _w = useState([]), sorterState = _w[0], setSorterState = _w[1]; var _x = useState(tableFilterValue !== null && tableFilterValue !== void 0 ? tableFilterValue : ''), tableFilterState = _x[0], setTableFilterState = _x[1]; var _itemsNumber = useMemo(function () { return itemsNumber !== null && itemsNumber !== void 0 ? itemsNumber : items.length; }, [itemsNumber, items.length]); useEffect(function () { setActivePage(activePage); }, [activePage]); useEffect(function () { if (items.length < _itemsPerPage * _activePage - _itemsPerPage) { setActivePage(1); } var selected = []; for (var _i = 0, items_1 = items; _i < items_1.length; _i++) { var item = items_1[_i]; if (item._selected) { var _item = __assign({}, item); for (var _a = 0, ITEM_INTERNAL_KEYS_1 = ITEM_INTERNAL_KEYS; _a < ITEM_INTERNAL_KEYS_1.length; _a++) { var key = ITEM_INTERNAL_KEYS_1[_a]; delete _item[key]; // Remove internal keys } selected.push(_item); // Add cleaned item to selected array } } if (selected.length > 0) { setSelected(__spreadArray(__spreadArray([], _selected, true), selected, true)); } if (Array.isArray(items)) { setItems(__spreadArray([], items, true)); } }, [JSON.stringify(items)]); useEffect(function () { Array.isArray(selected) && setSelected(selected); }, [JSON.stringify(selected)]); useEffect(function () { columnFilterValue && setColumnFilterState(columnFilterValue); }, [JSON.stringify(columnFilterValue)]); useEffect(function () { sorterValue && setSorterState(Array.isArray(sorterValue) ? sorterValue : [sorterValue]); }, [JSON.stringify(sorterValue)]); useEffect(function () { return setItemsPerPage(itemsPerPage); }, [itemsPerPage]); useEffect(function () { mountedRef.current && onActivePageChange && onActivePageChange(_activePage); }, [_activePage]); useEffect(function () { mountedRef.current && onItemsPerPageChange && onItemsPerPageChange(_itemsPerPage); itemsPerPage !== _itemsPerPage && setActivePage(1); // TODO: set proper page after _itemsPerPage update }, [_itemsPerPage]); useEffect(function () { var multiple = typeof columnSorter === 'object' && columnSorter.multiple; mountedRef.current && sorterState && onSorterChange && onSorterChange(multiple ? sorterState : sorterState[0]); }, [sorterState]); useEffect(function () { mountedRef.current && onColumnFilterChange && onColumnFilterChange(columnFilterState); }, [columnFilterState]); useEffect(function () { mountedRef.current && onTableFilterChange && onTableFilterChange(tableFilterState); }, [tableFilterState]); useEffect(function () { if (selectable) { onSelectedItemsChange && onSelectedItemsChange(_selected); if (_selected.length === _itemsNumber) { setSelectedAll(true); return; } if (_selected.length === 0) { setSelectedAll(false); return; } if (_selected.length > 0 && _selected.length !== _itemsNumber) { setSelectedAll('indeterminate'); } } }, [JSON.stringify(_selected), _itemsNumber]); var columnNames = useMemo(function () { return getColumnNames(columns, _items); }, [columns, _items]); var itemsDataColumns = useMemo(function () { return columnNames.filter(function (name) { return getColumnNamesFromItems(_items).includes(name); }); }, [columnNames, _items]); var filteredColumns = useMemo(function () { return filterColumns(_items, columnFilter, columnFilterState, itemsDataColumns); }, [columnFilterState, _items]); var filteredTable = useMemo(function () { return filterTable(filteredColumns, tableFilter, tableFilterState, itemsDataColumns); }, [tableFilterState, tableFilterValue, filteredColumns]); var sortedItems = useMemo(function () { return sortItems(columns, columnSorter, filteredTable, itemsDataColumns, sorterState); }, [columnSorter, sorterState, filteredTable]); var numberOfPages = _itemsPerPage ? Math.ceil(sortedItems.length / _itemsPerPage) : 1; var firstItemOnActivePageIndex = _activePage ? (_activePage - 1) * _itemsPerPage : 0; var currentItems = _activePage ? sortedItems.slice(firstItemOnActivePageIndex, firstItemOnActivePageIndex + _itemsPerPage) : sortedItems; useEffect(function () { mountedRef.current && onFilteredItemsChange && onFilteredItemsChange(sortedItems); }, [JSON.stringify(sortedItems)]); var handleClean = function () { setTableFilterState(''); setColumnFilterState({}); setSorterState([]); }; var handleColumnFilterChange = function (colName, value, type) { var isLazy = columnFilter && typeof columnFilter === 'object' && columnFilter.lazy === true; if ((isLazy && type === 'input') || (!isLazy && type === 'change')) { return; } setActivePage(1); setColumnFilterState(function (prevState) { var newState = __assign({}, prevState); if (value === '') { delete newState[colName]; } else { newState[colName] = value; } return newState; }); }; var handleItemsPerPageChange = function (event) { if (typeof itemsPerPageSelect !== 'object' || (typeof itemsPerPageSelect === 'object' && !itemsPerPageSelect.external)) { setItemsPerPage(Number(event.target.value)); } }; var handleRowChecked = function (item, value) { if (value && !isObjectInArray(_selected, item, ITEM_INTERNAL_KEYS)) { setSelected(function (prevSelected) { return __spreadArray(__spreadArray([], prevSelected, true), [item], false); }); return; } setSelected(function (prevSelected) { return prevSelected.filter(function (_item) { return !isObjectInArray([_item], item, ITEM_INTERNAL_KEYS); }); }); }; var handleSelectAllChecked = function () { if (selectedAll === true) { setSelected(_items.filter(function (item) { return item._selectable === false; })); return; } onSelectAll && onSelectAll(); if (selectAll && typeof selectAll === 'object' && selectAll.external) { return; } var selectable = _items.filter(function (item) { return item._selectable !== false || item._selected === true; }); if (selectable.length === _selected.length) { setSelected(_items.filter(function (item) { return item._selectable === false && item._selected === true; })); return; } var selected = selectable.map(function (item) { return __assign({}, item); }); setSelected(selected.map(function (item) { for (var _i = 0, ITEM_INTERNAL_KEYS_2 = ITEM_INTERNAL_KEYS; _i < ITEM_INTERNAL_KEYS_2.length; _i++) { var key = ITEM_INTERNAL_KEYS_2[_i]; delete item[key]; } return item; })); }; var handleSorterChange = function (column, index, order) { if (!isSortable(index, columns, columnSorter, itemsDataColumns, columnNames)) { return; } var existingColumnState = sorterState.find(function (x) { return x.column === column; }); var multiple = typeof columnSorter === 'object' && columnSorter.multiple; // If the column already has a sort state if (existingColumnState) { // No need to update if the order is already the same if (existingColumnState.state === order) { return; } // Remove the column from sorting if resetable and descending if (typeof columnSorter === 'object' && columnSorter.resetable && existingColumnState.state === 'desc' && order !== 'asc') { setSorterState(multiple ? sorterState.filter(function (x) { return x.column !== column; }) : []); } else { // Toggle between ascending and descending var newState_1 = { column: column, state: order || (existingColumnState.state === 'asc' ? 'desc' : 'asc'), }; setSorterState(multiple ? sorterState.map(function (item) { return (item.column === column ? newState_1 : item); }) : [newState_1]); } } else { // If the column is not yet sorted, add it with the default or provided order var newSorter = { column: column, state: order || 'asc' }; setSorterState(multiple ? __spreadArray(__spreadArray([], sorterState, true), [newSorter], false) : [newSorter]); } }; var handleTableFilterChange = function (value, type) { var isLazy = tableFilter && typeof tableFilter === 'object' && tableFilter.lazy === true; if ((isLazy && type === 'input') || (!isLazy && type === 'change')) { return; } setActivePage(1); setTableFilterState(value); }; useEffect(function () { mountedRef.current = true; }, []); return (React.createElement(React.Fragment, null, React.createElement("div", __assign({}, rest, { ref: ref }), (itemsPerPageSelect || tableFilter || cleaner) && (React.createElement("div", { className: "row my-2 mx-0" }, (tableFilter || cleaner) && (React.createElement(React.Fragment, null, React.createElement("div", { className: "col-auto p-0" }, tableFilter && (React.createElement("div", { className: "row mb-2" }, React.createElement(CFormLabel, { className: "col-sm-auto col-form-label" }, tableFilterLabel), React.createElement("div", { className: "col-sm-auto" }, React.createElement(CFormInput, { onInput: function (e) { handleTableFilterChange(e.target.value, 'input'); }, onChange: function (e) { handleTableFilterChange(e.target.value, 'change'); }, placeholder: tableFilterPlaceholder, value: tableFilterState || '' }))))), React.createElement("div", { className: "col-auto p-0" }, cleaner && (React.createElement("button", __assign({ type: "button", className: "btn btn-transparent" }, (!(tableFilterState || sorterState.length > 0 || Object.values(columnFilterState).join('')) && { disabled: true, tabIndex: -1, }), { onClick: function () { return handleClean(); }, onKeyDown: function (event) { if (event.key === 'Enter') handleClean(); } }), React.createElement(CIcon, { width: 18, icon: cilFilterX }))))))))), React.createElement("div", { className: "position-relative" }, React.createElement(CTable, __assign({}, tableProps), header && (React.createElement(CSmartTableHead, __assign({}, tableHeadProps, { columnFilter: columnFilter, columnFilterState: columnFilterState, columns: columns !== null && columns !== void 0 ? columns : columnNames, columnSorter: columnSorter, items: _items, selectable: selectable, selectAll: selectAll, selectedAll: selectedAll, sorterState: sorterState, sortingIcon: sortingIcon, sortingIconAscending: sortingIconAscending, sortingIconDescending: sortingIconDescending, handleFilterOnChange: function (key, event) { return handleColumnFilterChange(key, event, 'change'); }, handleFilterOnInput: function (key, event) { return handleColumnFilterChange(key, event, 'input'); }, handleOnCustomFilterChange: function (key, event) { return handleColumnFilterChange(key, event); }, handleSelectAllChecked: function () { return handleSelectAllChecked(); }, handleSort: function (key, index, order) { return handleSorterChange(key, index, order); } }))), React.createElement(CSmartTableBody, __assign({ clickableRows: clickableRows, columnNames: columnNames, columns: columns !== null && columns !== void 0 ? columns : columnNames, currentItems: currentItems, firstItemOnActivePageIndex: firstItemOnActivePageIndex, noItemsLabel: noItemsLabel, onRowClick: function (item, index, columnName, event) { return clickableRows && onRowClick && onRowClick(item, index, columnName, event); }, onRowChecked: function (item, value) { return handleRowChecked(item, value); }, scopedColumns: scopedColumns, selectable: selectable, selected: _selected }, tableBodyProps)), typeof footer === 'boolean' && footer && (React.createElement(CSmartTableHead, __assign({ as: CTableFoot }, tableFootProps, { columnFilter: false, columnSorter: false, columns: columns !== null && columns !== void 0 ? columns : columnNames, items: _items, handleSelectAllChecked: function () { return handleSelectAllChecked(); }, selectable: selectable, selectAll: selectAll, selectedAll: selectedAll, showGroups: false }))), Array.isArray(footer) && (React.createElement(CTableFoot, __assign({}, tableFootProps), React.createElement(CTableRow, null, footer.map(function (item, index) { return (React.createElement(CTableDataCell, __assign({}, (typeof item === 'object' && item._props && __assign({}, item._props)), { key: index }), typeof item === 'object' ? item.label : item)); }))))), loading && (React.createElement(CElementCover, { boundaries: [ { sides: ['top'], query: 'tbody' }, { sides: ['bottom'], query: 'tbody' }, ] }, elementCover))), (pagination || itemsPerPageSelect) && (React.createElement("div", { className: "row" }, React.createElement("div", { className: "col" }, ((pagination && numberOfPages > 1) || (paginationProps && paginationProps.pages > 1)) && (React.createElement(CSmartPagination, __assign({ activePage: _activePage, onActivePageChange: function (page) { pagination && typeof pagination === 'object' && pagination.external ? onActivePageChange && onActivePageChange(page) : setActivePage(page); }, pages: numberOfPages }, paginationProps)))), React.createElement("div", { className: "col-auto ms-auto" }, itemsPerPageSelect && (React.createElement("div", { className: "row" }, React.createElement(CFormLabel, { className: "col-auto col-form-label" }, itemsPerPageLabel), React.createElement("div", { className: "col-auto" }, React.createElement(CFormSelect, { defaultValue: _itemsPerPage, onChange: function (event) { return handleItemsPerPageChange(event); } }, itemsPerPageOptions && itemsPerPageOptions.map(function (number, index) { return (React.createElement("option", { value: number, key: index }, number)); })))))))))); }); CSmartTable.propTypes = { activePage: PropTypes.number, cleaner: PropTypes.bool, clickableRows: PropTypes.bool, columnFilter: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), columnFilterValue: PropTypes.object, columns: PropTypes.array, columnSorter: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), elementCover: PropTypes.node, footer: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]), header: PropTypes.bool, items: PropTypes.array, itemsNumber: PropTypes.number, itemsPerPage: PropTypes.number, itemsPerPageLabel: PropTypes.string, itemsPerPageOptions: PropTypes.array, itemsPerPageSelect: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), loading: PropTypes.bool, noItemsLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), onActivePageChange: PropTypes.func, onColumnFilterChange: PropTypes.func, onFilteredItemsChange: PropTypes.func, onItemsPerPageChange: PropTypes.func, onRowClick: PropTypes.func, onSelectAll: PropTypes.func, onSelectedItemsChange: PropTypes.func, onSorterChange: PropTypes.func, // TODO: change to `onColumnSorterChange` in v6 onTableFilterChange: PropTypes.func, pagination: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), paginationProps: PropTypes.any, // TODO: update scopedColumns: PropTypes.object, selectable: PropTypes.bool, selectAll: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), selected: PropTypes.array, sorterValue: PropTypes.oneOfType([ PropTypes.shape({ column: PropTypes.string.isRequired, state: PropTypes.oneOf(['asc', 'desc', 0]).isRequired, }), PropTypes.arrayOf(PropTypes.shape({ column: PropTypes.string.isRequired, state: PropTypes.oneOf(['asc', 'desc', 0]).isRequired, }).isRequired), ]), sortingIcon: PropTypes.node, sortingIconAscending: PropTypes.node, sortingIconDescending: PropTypes.node, tableBodyProps: PropTypes.object, tableFootProps: PropTypes.object, tableFilter: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), tableFilterLabel: PropTypes.string, tableFilterPlaceholder: PropTypes.string, tableFilterValue: PropTypes.string, tableHeadProps: PropTypes.object, tableProps: PropTypes.object, }; CSmartTable.displayName = 'CSmartTable'; export { CSmartTable }; //# sourceMappingURL=CSmartTable.js.map