suomifi-ui-components
Version:
Suomi.fi UI component library
326 lines (323 loc) • 16.1 kB
JavaScript
import { __rest, __assign, __makeTemplateObject, __spreadArray } from 'tslib';
import React, { useState, useEffect, forwardRef } from 'react';
import { styled } from 'styled-components';
import classnames from 'classnames';
import { SuomifiThemeConsumer } from '../theme/SuomifiThemeProvider/SuomifiThemeProvider.js';
import '../theme/SuomifiTheme/SuomifiTheme.js';
import { SpacingConsumer } from '../theme/SpacingProvider/SpacingProvider.js';
import { separateMarginProps } from '../theme/utils/spacing.js';
import { baseStyles } from './Table.baseStyles.js';
import { filterDuplicateKeys } from '../../utils/common/common.js';
import { AutoId } from '../utils/AutoId/AutoId.js';
import '../../reset/HtmlA/HtmlA.js';
import { HtmlButton } from '../../reset/HtmlButton/HtmlButton.js';
import { HtmlDivWithRef } from '../../reset/HtmlDiv/HtmlDiv.js';
import '../../reset/HtmlFieldSet/HtmlFieldSet.js';
import '../../reset/HtmlH/HtmlH.js';
import '../../reset/HtmlInput/HtmlInput.js';
import '../../reset/HtmlLabel/HtmlLabel.js';
import '../../reset/HtmlLegend/HtmlLegend.js';
import '../../reset/HtmlLi/HtmlLi.js';
import '../../reset/HtmlNav/HtmlNav.js';
import '../../reset/HtmlOl/HtmlOl.js';
import '../../reset/HtmlSpan/HtmlSpan.js';
import '../../reset/HtmlTextarea/HtmlTextarea.js';
import '../../reset/HtmlUl/HtmlUl.js';
import { HtmlTable } from '../../reset/HtmlTable/HtmlTable.js';
import { HtmlTableCaption } from '../../reset/HtmlTable/HtmlTableCaption.js';
import { HtmlTableHeader } from '../../reset/HtmlTable/HtmlTableHeader.js';
import { HtmlTableRow } from '../../reset/HtmlTable/HtmlTableRow.js';
import { HtmlTableBody } from '../../reset/HtmlTable/HtmlTableBody.js';
import { HtmlTableHeaderCell } from '../../reset/HtmlTable/HtmlTableHeaderCell.js';
import { HtmlTableCell } from '../../reset/HtmlTable/HtmlTableCell.js';
import { IconSort, IconSortDownAlph, IconSortUpAlph, IconSortDown, IconSortUp } from 'suomifi-icons';
import { getConditionalAriaProp } from '../../utils/aria/aria.js';
import { Checkbox } from '../Form/Checkbox/Checkbox.js';
import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden.js';
import { RadioButton } from '../Form/RadioButton/RadioButton.js';
import { Block } from '../Block/Block.js';
var baseClassName = 'fi-table';
var tableClassNames = {
table: "".concat(baseClassName, "_table"),
thead: "".concat(baseClassName, "_thead"),
tbody: "".concat(baseClassName, "_tbody"),
th: "".concat(baseClassName, "_th"),
tr: "".concat(baseClassName, "_tr"),
td: "".concat(baseClassName, "_td"),
selectionTd: "".concat(baseClassName, "_td--selection"),
tdAlignRight: "".concat(baseClassName, "_td--align-right"),
tdAlignCenter: "".concat(baseClassName, "_td--align-center"),
caption: "".concat(baseClassName, "_caption"),
alternativeCaption: "".concat(baseClassName, "_caption--alternative"),
toolbar: "".concat(baseClassName, "_toolbar"),
condenseButtons: "".concat(baseClassName, "_condense-buttons"),
condenseButton: "".concat(baseClassName, "_condense-button"),
condensed: "".concat(baseClassName, "--condensed"),
rowCountText: "".concat(baseClassName, "_row-count-text"),
sortIcons: "".concat(baseClassName, "_sort-icons"),
sortButton: "".concat(baseClassName, "_sort-button"),
skeleton: "".concat(baseClassName, "_skeleton"),
skeletonRow: "".concat(baseClassName, "_skeleton-row"),
skeletonCell: "".concat(baseClassName, "_skeleton-cell"),
skeletonContent: "".concat(baseClassName, "_skeleton-content"),
selectionCellSkeleton: "".concat(baseClassName, "_selection-cell-skeleton")
};
var BaseTable = function BaseTable(props) {
var _a;
var id = props.id,
columns = props.columns,
propData = props.data,
caption = props.caption,
condensed = props.condensed,
enableRowSelection = props.enableRowSelection,
enableSingleRowSelection = props.enableSingleRowSelection,
onSelectedRowsChange = props.onSelectedRowsChange,
tableSortedAriaLiveText = props.tableSortedAriaLiveText,
tableSortCallback = props.tableSortCallback,
defaultSort = props.defaultSort,
loading = props.loading,
_b = props.loadingRowAmount,
loadingRowAmount = _b === void 0 ? 5 : _b,
controlledSelectedRowIds = props.controlledSelectedRowIds,
className = props.className,
ariaLabelledBy = props["aria-labelledby"];
props.globalMargins;
var rest = __rest(props, ["id", "columns", "data", "caption", "condensed", "enableRowSelection", "enableSingleRowSelection", "onSelectedRowsChange", "tableSortedAriaLiveText", "tableSortCallback", "defaultSort", "loading", "loadingRowAmount", "controlledSelectedRowIds", "className", 'aria-labelledby', "globalMargins"]);
var _c = separateMarginProps(rest),
passProps = _c[1];
var _d = useState(propData),
data = _d[0],
setData = _d[1];
var _e = useState(''),
sortColumn = _e[0],
setSortColumn = _e[1];
var _f = useState(controlledSelectedRowIds || []),
selectedRowIds = _f[0],
setSelectedRowIds = _f[1];
var _g = useState(false),
hasHorizontalScrollbar = _g[0],
setHasHorizontalScrollbar = _g[1];
var wrapperRef = /*#__PURE__*/React.createRef();
useEffect(function () {
if (controlledSelectedRowIds !== undefined) {
setSelectedRowIds(controlledSelectedRowIds);
}
}, [controlledSelectedRowIds]);
useEffect(function () {
setData(propData);
}, [propData]);
useEffect(function () {
if (defaultSort && defaultSort.columnKey) {
var column = columns.find(function (col) {
return col.key === defaultSort.columnKey;
});
if (column && column.sortable) {
sortData(defaultSort.columnKey, defaultSort.direction);
}
}
}, [defaultSort === null || defaultSort === void 0 ? void 0 : defaultSort.columnKey, defaultSort === null || defaultSort === void 0 ? void 0 : defaultSort.direction]);
useEffect(function () {
var targetDiv = wrapperRef.current;
if (!targetDiv) return;
var observer = new ResizeObserver(function () {
var isScrollbarVisible = targetDiv.scrollWidth > targetDiv.clientWidth;
setHasHorizontalScrollbar(isScrollbarVisible);
});
observer.observe(targetDiv);
return function () {
return observer.disconnect();
};
}, []);
var sortData = function sortData(key, forceDirection) {
var newDirection = forceDirection || (!sortColumn.includes(key) || sortColumn === "".concat(key, "-desc") ? 'asc' : 'desc');
var sortedData = __spreadArray([], data, true).sort(function (a, b) {
var aValue = a[key];
var bValue = b[key];
var getTextContent = function getTextContent(element) {
if (typeof element === 'string' || typeof element === 'number') {
return element.toString();
}
if ( /*#__PURE__*/React.isValidElement(element)) {
var children = element.props.children;
if (Array.isArray(children)) {
return children.map(getTextContent).join('');
}
return getTextContent(children);
}
return '';
};
var aValueText = getTextContent(aValue);
var bValueText = getTextContent(bValue);
var isNumeric = !Number.isNaN(Number(aValueText)) && !Number.isNaN(Number(bValueText));
if (isNumeric) {
return newDirection === 'asc' ? Number(aValueText) - Number(bValueText) : Number(bValueText) - Number(aValueText);
}
return newDirection === 'asc' ? aValueText.localeCompare(bValueText) : bValueText.localeCompare(aValueText);
});
if (!!tableSortCallback) {
tableSortCallback(key, newDirection);
} else {
setData(sortedData);
}
setSortColumn("".concat(key, "-").concat(newDirection));
};
var handleRowSelection = function handleRowSelection(rowId, operation) {
var newSelectedRowIds = [];
if (enableSingleRowSelection) {
newSelectedRowIds = [rowId];
} else {
newSelectedRowIds = operation === 'add' ? __spreadArray(__spreadArray([], selectedRowIds, true), [rowId], false) : selectedRowIds.filter(function (rid) {
return rid !== rowId;
});
}
if (controlledSelectedRowIds === undefined) {
setSelectedRowIds(newSelectedRowIds);
}
if (onSelectedRowsChange) {
onSelectedRowsChange(newSelectedRowIds);
}
};
var getSortColumnLabel = function getSortColumnLabel() {
var _a;
return ((_a = columns.find(function (col) {
return sortColumn.includes(col.key);
})) === null || _a === void 0 ? void 0 : _a.labelText) || '';
};
var getSortDirection = function getSortDirection() {
return sortColumn.endsWith('-asc') ? 'asc' : 'desc';
};
var skeletonRows = [];
if (loading) {
for (var i = 0; i < loadingRowAmount; i += 1) {
skeletonRows.push(i);
}
}
var tableCaptionId = "".concat(id, "-caption");
var getTableCaptionId = function getTableCaptionId() {
return caption ? tableCaptionId : ariaLabelledBy;
};
return /*#__PURE__*/React.createElement(HtmlDivWithRef, {
className: classnames(baseClassName, className),
forwardedRef: wrapperRef,
tabIndex: hasHorizontalScrollbar ? 0 : undefined,
role: hasHorizontalScrollbar ? 'region' : undefined,
"aria-labelledby": hasHorizontalScrollbar ? getTableCaptionId() : undefined
}, /*#__PURE__*/React.createElement(VisuallyHidden, {
"aria-live": "polite"
}, sortColumn !== '' && tableSortedAriaLiveText && tableSortedAriaLiveText(getSortColumnLabel(), getSortDirection())), /*#__PURE__*/React.createElement(HtmlTable, __assign({
className: classnames(tableClassNames.table, (_a = {}, _a[tableClassNames.condensed] = condensed, _a)),
id: id
}, getConditionalAriaProp('aria-labelledby', [ariaLabelledBy]), {
"aria-busy": loading
}, passProps), caption && ( /*#__PURE__*/React.createElement(HtmlTableCaption, {
className: tableClassNames.caption,
id: tableCaptionId
}, caption)), /*#__PURE__*/React.createElement(HtmlTableHeader, {
className: tableClassNames.thead
}, /*#__PURE__*/React.createElement(HtmlTableRow, null, (enableRowSelection || enableSingleRowSelection) && ( /*#__PURE__*/React.createElement(HtmlTableCell, {
className: classnames(tableClassNames.th, tableClassNames.selectionTd)
})), columns.map(function (col) {
var _a;
return /*#__PURE__*/React.createElement(HtmlTableHeaderCell, {
scope: "col",
key: col.key,
className: classnames(tableClassNames.th, col.className, (_a = {}, _a[tableClassNames.tdAlignRight] = col.textAlign === 'right', _a[tableClassNames.tdAlignCenter] = col.textAlign === 'center', _a)),
"aria-sort": sortColumn === "".concat(col.key, "-asc") ? 'ascending' : sortColumn === "".concat(col.key, "-desc") ? 'descending' : undefined
}, col.sortable ? ( /*#__PURE__*/React.createElement(HtmlButton, {
onClick: function onClick() {
return sortData(col.key);
},
className: tableClassNames.sortButton
}, col.labelText, !sortColumn.includes(col.key) && /*#__PURE__*/React.createElement(IconSort, null), sortColumn === "".concat(col.key, "-asc") && col.sortIcon !== 'generic' && /*#__PURE__*/React.createElement(IconSortDownAlph, null), sortColumn === "".concat(col.key, "-desc") && col.sortIcon !== 'generic' && /*#__PURE__*/React.createElement(IconSortUpAlph, null), sortColumn === "".concat(col.key, "-asc") && col.sortIcon === 'generic' && /*#__PURE__*/React.createElement(IconSortDown, null), sortColumn === "".concat(col.key, "-desc") && col.sortIcon === 'generic' && /*#__PURE__*/React.createElement(IconSortUp, null))) : col.labelText);
}))), /*#__PURE__*/React.createElement(HtmlTableBody, {
className: tableClassNames.tbody
}, loading ? skeletonRows.map(function (val) {
return /*#__PURE__*/React.createElement(HtmlTableRow, {
key: "loading-row-".concat(val, "}"),
className: tableClassNames.skeletonRow,
"aria-hidden": "true"
}, (enableRowSelection || enableSingleRowSelection) && ( /*#__PURE__*/React.createElement(HtmlTableCell, {
className: classnames(tableClassNames.skeletonCell, tableClassNames.selectionCellSkeleton)
}, /*#__PURE__*/React.createElement(Block, {
className: classnames(tableClassNames.skeleton, tableClassNames.skeletonContent)
}))), columns.map(function (col) {
return /*#__PURE__*/React.createElement(HtmlTableCell, {
key: "loading-cell-".concat(col.key),
className: tableClassNames.skeletonCell
}, /*#__PURE__*/React.createElement(Block, {
className: classnames(tableClassNames.skeleton, tableClassNames.skeletonContent)
}));
}));
}) : data.map(function (row) {
return /*#__PURE__*/React.createElement(HtmlTableRow, {
key: row.id,
className: classnames(tableClassNames.tr, {
highlighted: selectedRowIds.includes(row.id)
})
}, (enableRowSelection || enableSingleRowSelection) && row.rowSelectionDisabled === true && ( /*#__PURE__*/React.createElement(HtmlTableCell, {
className: classnames(tableClassNames.td, tableClassNames.selectionTd)
})), enableRowSelection && row.rowSelectionDisabled !== true && ( /*#__PURE__*/React.createElement(HtmlTableCell, {
className: classnames(tableClassNames.td, tableClassNames.selectionTd)
}, /*#__PURE__*/React.createElement(Checkbox, {
checked: selectedRowIds.includes(row.id),
onClick: function onClick(checkedVal) {
return handleRowSelection(row.id, checkedVal.checkboxState ? 'add' : 'remove');
},
labelProps: row.rowSelectionLabelProps
}, /*#__PURE__*/React.createElement(VisuallyHidden, null, row.rowSelectionCheckboxLabel)))), enableSingleRowSelection && row.rowSelectionDisabled !== true && ( /*#__PURE__*/React.createElement(HtmlTableCell, {
className: classnames(tableClassNames.td, tableClassNames.selectionTd)
}, /*#__PURE__*/React.createElement(RadioButton, {
value: "radiobutton-".concat(row.id),
checked: selectedRowIds.includes(row.id),
onChange: function onChange(newValue) {
return handleRowSelection(row.id, newValue ? 'add' : 'remove');
},
labelProps: row.rowSelectionLabelProps
}, /*#__PURE__*/React.createElement(VisuallyHidden, null, row.rowSelectionCheckboxLabel)))), columns.map(function (col) {
var _a;
return /*#__PURE__*/React.createElement(HtmlTableCell, {
key: "".concat(row.id, "-").concat(col.key),
className: classnames(tableClassNames.td, col.className, (_a = {}, _a[tableClassNames.tdAlignRight] = col.textAlign === 'right', _a[tableClassNames.tdAlignCenter] = col.textAlign === 'center', _a))
}, row[col.key]);
}));
}))));
};
var StyledTable = styled(function (_a) {
_a.theme;
var passProps = __rest(_a, ["theme"]);
return /*#__PURE__*/React.createElement(BaseTable, __assign({}, passProps));
}).withConfig({
componentId: "sc-pno9ty-0"
})(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n ", "\n"], ["\n ", "\n"])), function (_a) {
var theme = _a.theme,
globalMargins = _a.globalMargins,
rest = __rest(_a, ["theme", "globalMargins"]);
var _b = separateMarginProps(rest),
marginProps = _b[0];
var cleanedGlobalMargins = filterDuplicateKeys(globalMargins.table, marginProps);
return baseStyles(theme, cleanedGlobalMargins, marginProps);
});
var Table = /*#__PURE__*/forwardRef(function (props, ref) {
var propId = props.id,
passProps = __rest(props, ["id"]);
return /*#__PURE__*/React.createElement(SpacingConsumer, null, function (_a) {
var margins = _a.margins;
return /*#__PURE__*/React.createElement(SuomifiThemeConsumer, null, function (_a) {
var suomifiTheme = _a.suomifiTheme;
return /*#__PURE__*/React.createElement(AutoId, {
id: propId
}, function (id) {
return /*#__PURE__*/React.createElement(StyledTable, __assign({
theme: suomifiTheme,
id: id,
forwardedRef: ref,
globalMargins: margins
}, passProps));
});
});
});
});
Table.displayName = 'Table';
var templateObject_1;
export { Table };
//# sourceMappingURL=Table.js.map