UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

352 lines (348 loc) 22 kB
'use strict'; var tslib_es6 = require('../../node_modules/tslib/tslib.es6.js'); var React = require('react'); var PropTypes = require('prop-types'); var index_esm = require('../../node_modules/@coreui/icons-react/dist/index.esm.js'); var CElementCover = require('../element-cover/CElementCover.js'); require('../form/CForm.js'); require('../form/CFormCheck.js'); require('../form/CFormControlValidation.js'); require('../form/CFormControlWrapper.js'); require('../form/CFormFeedback.js'); require('../form/CFormFloating.js'); var CFormInput = require('../form/CFormInput.js'); var CFormLabel = require('../form/CFormLabel.js'); require('../form/CFormRange.js'); var CFormSelect = require('../form/CFormSelect.js'); require('../form/CFormSwitch.js'); require('../form/CFormText.js'); require('../form/CFormTextarea.js'); require('../form/CInputGroup.js'); require('../form/CInputGroupText.js'); var CSmartPagination = require('../smart-pagination/CSmartPagination.js'); var CTable = require('../table/CTable.js'); require('../table/CTableBody.js'); require('../table/CTableCaption.js'); var CTableDataCell = require('../table/CTableDataCell.js'); var CTableFoot = require('../table/CTableFoot.js'); require('../table/CTableHead.js'); require('../table/CTableHeaderCell.js'); var CTableRow = require('../table/CTableRow.js'); var CSmartTableBody = require('./CSmartTableBody.js'); var CSmartTableHead = require('./CSmartTableHead.js'); var isObjectInArray = require('../../utils/isObjectInArray.js'); var consts = require('./consts.js'); var utils = require('./utils.js'); var cilSwapVertical = require('../../node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js'); var cilArrowTop = require('../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js'); var cilArrowBottom = require('../../node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js'); var cilFilterX = require('../../node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js'); const CSmartTable = React.forwardRef((_a, ref) => { var { activePage = 1, cleaner, clickableRows, columnFilter, columnFilterValue, // TODO: consider to use only columnFilter prop columns, columnSorter, elementCover, footer, header = true, items = [], itemsNumber, itemsPerPage = 10, itemsPerPageLabel = 'Items per page:', itemsPerPageOptions = [5, 10, 20, 50], itemsPerPageSelect, loading, noItemsLabel = 'No items found', onActivePageChange, onColumnFilterChange, onFilteredItemsChange, onItemsPerPageChange, onRowChecked, onRowClick, onSelectAll, onSelectedItemsChange, onSorterChange, onTableFilterChange, pagination, paginationProps, scopedColumns, selected, selectable, selectAll = true, sorterValue, sortingIcon = React.createElement(index_esm.CIcon, { width: 18, icon: cilSwapVertical.cilSwapVertical, key: "csv" }), sortingIconAscending = React.createElement(index_esm.CIcon, { width: 18, icon: cilArrowTop.cilArrowTop, key: "cat" }), sortingIconDescending = React.createElement(index_esm.CIcon, { width: 18, icon: cilArrowBottom.cilArrowBottom, key: "cab" }), tableBodyProps, tableFootProps, tableFilter, tableFilterLabel = 'Filter:', tableFilterPlaceholder = 'type string...', tableFilterValue, tableHeadProps, tableProps } = _a, rest = tslib_es6.__rest(_a, ["activePage", "cleaner", "clickableRows", "columnFilter", "columnFilterValue", "columns", "columnSorter", "elementCover", "footer", "header", "items", "itemsNumber", "itemsPerPage", "itemsPerPageLabel", "itemsPerPageOptions", "itemsPerPageSelect", "loading", "noItemsLabel", "onActivePageChange", "onColumnFilterChange", "onFilteredItemsChange", "onItemsPerPageChange", "onRowChecked", "onRowClick", "onSelectAll", "onSelectedItemsChange", "onSorterChange", "onTableFilterChange", "pagination", "paginationProps", "scopedColumns", "selected", "selectable", "selectAll", "sorterValue", "sortingIcon", "sortingIconAscending", "sortingIconDescending", "tableBodyProps", "tableFootProps", "tableFilter", "tableFilterLabel", "tableFilterPlaceholder", "tableFilterValue", "tableHeadProps", "tableProps"]); const mountedRef = React.useRef(false); const [_activePage, setActivePage] = React.useState(activePage); const [_items, setItems] = React.useState([]); const [_itemsPerPage, setItemsPerPage] = React.useState(itemsPerPage); const [_selected, setSelected] = React.useState([]); const [columnFilterState, setColumnFilterState] = React.useState({}); const [selectedAll, setSelectedAll] = React.useState(); const [sorterState, setSorterState] = React.useState([]); const [tableFilterState, setTableFilterState] = React.useState(tableFilterValue !== null && tableFilterValue !== void 0 ? tableFilterValue : ''); const _itemsNumber = React.useMemo(() => itemsNumber !== null && itemsNumber !== void 0 ? itemsNumber : items.length, [itemsNumber, items.length]); React.useEffect(() => { setActivePage(activePage); }, [activePage]); React.useEffect(() => { if (items.length < _itemsPerPage * _activePage - _itemsPerPage) { setActivePage(1); } const selected = []; for (const item of items) { if (item._selected) { const _item = Object.assign({}, item); for (const key of consts.ITEM_INTERNAL_KEYS) { delete _item[key]; // Remove internal keys } selected.push(_item); // Add cleaned item to selected array } } if (selected.length > 0) { setSelected([..._selected, ...selected]); } if (Array.isArray(items)) { setItems([...items]); } }, [JSON.stringify(items)]); React.useEffect(() => { Array.isArray(selected) && setSelected(selected); }, [JSON.stringify(selected)]); React.useEffect(() => { columnFilterValue && setColumnFilterState(columnFilterValue); }, [JSON.stringify(columnFilterValue)]); React.useEffect(() => { sorterValue && setSorterState(Array.isArray(sorterValue) ? sorterValue : [sorterValue]); }, [JSON.stringify(sorterValue)]); React.useEffect(() => setItemsPerPage(itemsPerPage), [itemsPerPage]); React.useEffect(() => { mountedRef.current && onActivePageChange && onActivePageChange(_activePage); }, [_activePage]); React.useEffect(() => { mountedRef.current && onItemsPerPageChange && onItemsPerPageChange(_itemsPerPage); itemsPerPage !== _itemsPerPage && setActivePage(1); // TODO: set proper page after _itemsPerPage update }, [_itemsPerPage]); React.useEffect(() => { const multiple = typeof columnSorter === 'object' && columnSorter.multiple; mountedRef.current && sorterState && onSorterChange && onSorterChange(multiple ? sorterState : sorterState[0]); }, [sorterState]); React.useEffect(() => { mountedRef.current && onColumnFilterChange && onColumnFilterChange(columnFilterState); }, [columnFilterState]); React.useEffect(() => { mountedRef.current && onTableFilterChange && onTableFilterChange(tableFilterState); }, [tableFilterState]); React.useEffect(() => { 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]); const columnNames = React.useMemo(() => utils.getColumnNames(columns, _items), [columns, _items]); const itemsDataColumns = React.useMemo(() => columnNames.filter((name) => utils.getColumnNamesFromItems(_items).includes(name)), [columnNames, _items]); const filteredColumns = React.useMemo(() => utils.filterColumns(_items, columnFilter, columnFilterState, itemsDataColumns), [columnFilterState, _items]); const filteredTable = React.useMemo(() => utils.filterTable(filteredColumns, tableFilter, tableFilterState, itemsDataColumns), [tableFilterState, tableFilterValue, filteredColumns]); const sortedItems = React.useMemo(() => utils.sortItems(columns, columnSorter, filteredTable, itemsDataColumns, sorterState), [columnSorter, sorterState, filteredTable]); const numberOfPages = _itemsPerPage ? Math.ceil(sortedItems.length / _itemsPerPage) : 1; const firstItemOnActivePageIndex = _activePage ? (_activePage - 1) * _itemsPerPage : 0; const currentItems = _activePage ? sortedItems.slice(firstItemOnActivePageIndex, firstItemOnActivePageIndex + _itemsPerPage) : sortedItems; React.useEffect(() => { mountedRef.current && onFilteredItemsChange && onFilteredItemsChange(sortedItems); }, [JSON.stringify(sortedItems)]); const handleClean = () => { setTableFilterState(''); setColumnFilterState({}); setSorterState([]); }; const handleColumnFilterChange = (colName, value, type) => { const isLazy = columnFilter && typeof columnFilter === 'object' && columnFilter.lazy === true; if ((isLazy && type === 'input') || (!isLazy && type === 'change')) { return; } setActivePage(1); setColumnFilterState((prevState) => { const newState = Object.assign({}, prevState); if (value === '') { delete newState[colName]; } else { newState[colName] = value; } return newState; }); }; const handleItemsPerPageChange = (event) => { if (typeof itemsPerPageSelect !== 'object' || (typeof itemsPerPageSelect === 'object' && !itemsPerPageSelect.external)) { setItemsPerPage(Number(event.target.value)); } }; const handleRowChecked = (item, value) => { onRowChecked === null || onRowChecked === void 0 ? void 0 : onRowChecked(item, value); if (value && !isObjectInArray.default(_selected, item, consts.ITEM_INTERNAL_KEYS)) { setSelected((prevSelected) => [...prevSelected, item]); return; } setSelected((prevSelected) => prevSelected.filter((_item) => !isObjectInArray.default([_item], item, consts.ITEM_INTERNAL_KEYS))); }; const handleSelectAllChecked = () => { onSelectAll === null || onSelectAll === void 0 ? void 0 : onSelectAll(); if (selectedAll === true) { setSelected(_items.filter((item) => item._selectable === false)); return; } if (selectAll && typeof selectAll === 'object' && selectAll.external) { return; } const selectable = _items.filter((item) => item._selectable !== false || item._selected === true); if (selectable.length === _selected.length) { setSelected(_items.filter((item) => item._selectable === false && item._selected === true)); return; } const selected = selectable.map((item) => { return Object.assign({}, item); }); setSelected(selected.map((item) => { for (const key of consts.ITEM_INTERNAL_KEYS) { delete item[key]; } return item; })); }; const handleSorterChange = (column, index, order) => { if (!utils.isSortable(index, columns, columnSorter, itemsDataColumns, columnNames)) { return; } const existingColumnState = sorterState.find((x) => x.column === column); const 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((x) => x.column !== column) : []); } else { // Toggle between ascending and descending const newState = { column, state: order || (existingColumnState.state === 'asc' ? 'desc' : 'asc'), }; setSorterState(multiple ? sorterState.map((item) => (item.column === column ? newState : item)) : [newState]); } } else { // If the column is not yet sorted, add it with the default or provided order const newSorter = { column, state: order || 'asc' }; setSorterState(multiple ? [...sorterState, newSorter] : [newSorter]); } }; const handleTableFilterChange = (value, type) => { const isLazy = tableFilter && typeof tableFilter === 'object' && tableFilter.lazy === true; if ((isLazy && type === 'input') || (!isLazy && type === 'change')) { return; } setActivePage(1); setTableFilterState(value); }; React.useEffect(() => { mountedRef.current = true; }, []); return (React.createElement(React.Fragment, null, React.createElement("div", Object.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.CFormLabel, { className: "col-sm-auto col-form-label" }, tableFilterLabel), React.createElement("div", { className: "col-sm-auto" }, React.createElement(CFormInput.CFormInput, { onInput: (e) => { handleTableFilterChange(e.target.value, 'input'); }, onChange: (e) => { handleTableFilterChange(e.target.value, 'change'); }, placeholder: tableFilterPlaceholder, value: tableFilterState || '' }))))), React.createElement("div", { className: "col-auto p-0" }, cleaner && (React.createElement("button", Object.assign({ type: "button", className: "btn btn-transparent" }, (!(tableFilterState || sorterState.length > 0 || Object.values(columnFilterState).join('')) && { disabled: true, tabIndex: -1, }), { onClick: () => handleClean(), onKeyDown: (event) => { if (event.key === 'Enter') handleClean(); } }), React.createElement(index_esm.CIcon, { width: 18, icon: cilFilterX.cilFilterX }))))))))), React.createElement("div", { className: "position-relative" }, React.createElement(CTable.CTable, Object.assign({}, tableProps), header && (React.createElement(CSmartTableHead.CSmartTableHead, Object.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: (key, event) => handleColumnFilterChange(key, event, 'change'), handleFilterOnInput: (key, event) => handleColumnFilterChange(key, event, 'input'), handleOnCustomFilterChange: (key, event) => handleColumnFilterChange(key, event), handleSelectAllChecked: () => handleSelectAllChecked(), handleSort: (key, index, order) => handleSorterChange(key, index, order) }))), React.createElement(CSmartTableBody.CSmartTableBody, Object.assign({ clickableRows: clickableRows, columnNames: columnNames, columns: columns !== null && columns !== void 0 ? columns : columnNames, currentItems: currentItems, firstItemOnActivePageIndex: firstItemOnActivePageIndex, noItemsLabel: noItemsLabel, onRowClick: (item, index, columnName, event) => clickableRows && onRowClick && onRowClick(item, index, columnName, event), onRowChecked: (item, value) => handleRowChecked(item, value), scopedColumns: scopedColumns, selectable: selectable, selected: _selected }, tableBodyProps)), typeof footer === 'boolean' && footer && (React.createElement(CSmartTableHead.CSmartTableHead, Object.assign({ as: CTableFoot.CTableFoot }, tableFootProps, { columnFilter: false, columnSorter: false, columns: columns !== null && columns !== void 0 ? columns : columnNames, items: _items, handleSelectAllChecked: () => handleSelectAllChecked(), selectable: selectable, selectAll: selectAll, selectedAll: selectedAll, showGroups: false }))), Array.isArray(footer) && (React.createElement(CTableFoot.CTableFoot, Object.assign({}, tableFootProps), React.createElement(CTableRow.CTableRow, null, footer.map((item, index) => (React.createElement(CTableDataCell.CTableDataCell, Object.assign({}, (typeof item === 'object' && item._props && Object.assign({}, item._props)), { key: index }), typeof item === 'object' ? item.label : item))))))), loading && (React.createElement(CElementCover.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.CSmartPagination, Object.assign({ activePage: _activePage, onActivePageChange: (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.CFormLabel, { className: "col-auto col-form-label" }, itemsPerPageLabel), React.createElement("div", { className: "col-auto" }, React.createElement(CFormSelect.CFormSelect, { defaultValue: _itemsPerPage, onChange: (event) => handleItemsPerPageChange(event) }, itemsPerPageOptions && itemsPerPageOptions.map((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, onRowChecked: 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'; exports.CSmartTable = CSmartTable; //# sourceMappingURL=CSmartTable.js.map