UNPKG

suomifi-ui-components

Version:
314 lines (311 loc) 15.4 kB
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, 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", "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 () { 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) { 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 !sortColumn.includes(key) || sortColumn === "".concat(key, "-desc") ? Number(aValueText) - Number(bValueText) : Number(bValueText) - Number(aValueText); } return !sortColumn.includes(key) || sortColumn === "".concat(key, "-desc") ? aValueText.localeCompare(bValueText) : bValueText.localeCompare(aValueText); }); if (!!tableSortCallback) { tableSortCallback(key, !sortColumn.includes(key) || sortColumn === "".concat(key, "-desc") ? 'asc' : 'desc'); } else { setData(sortedData); } if (!sortColumn.includes(key) || sortColumn === "".concat(key, "-desc")) { setSortColumn("".concat(key, "-asc")); } else { setSortColumn("".concat(key, "-desc")); } }; 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 && ( /*#__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'); } }, /*#__PURE__*/React.createElement(VisuallyHidden, null, row.rowSelectionCheckboxLabel)))), enableSingleRowSelection && ( /*#__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'); } }, /*#__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