terra-table
Version:
The Terra Table component provides user a way to display data in an accessible table format.
802 lines (765 loc) • 35.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.TableConstants = exports.RowSelectionModes = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _reactIntl = require("react-intl");
var _uuid = require("uuid");
var KeyCode = _interopRequireWildcard(require("keycode-js"));
var _bind = _interopRequireDefault(require("classnames/bind"));
var _resizeObserverPolyfill = _interopRequireDefault(require("resize-observer-polyfill"));
var _terraThemeContext = _interopRequireDefault(require("terra-theme-context"));
var _terraVisuallyHiddenText = _interopRequireDefault(require("terra-visually-hidden-text"));
var _Section = _interopRequireDefault(require("./subcomponents/Section"));
var _ColumnHeader = _interopRequireDefault(require("./subcomponents/ColumnHeader"));
var _ColumnContext = _interopRequireDefault(require("./utils/ColumnContext"));
var _columnShape = _interopRequireDefault(require("./proptypes/columnShape"));
var _GridContext = _interopRequireWildcard(require("./utils/GridContext"));
var _rowShape = _interopRequireDefault(require("./proptypes/rowShape"));
var _validators = require("./proptypes/validators");
var _TableModule = _interopRequireDefault(require("./Table.module.scss"));
var _sectionShape = _interopRequireDefault(require("./proptypes/sectionShape"));
var _focusManagement = _interopRequireDefault(require("./utils/focusManagement"));
var _actionsUtils = _interopRequireDefault(require("./utils/actionsUtils"));
var _tableUtils = _interopRequireDefault(require("./utils/tableUtils"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var cx = _bind.default.bind(_TableModule.default);
var RowSelectionModes = exports.RowSelectionModes = {
SINGLE: 'single',
MULTIPLE: 'multiple'
};
var TableConstants = exports.TableConstants = {
ROW_SELECTION_COLUMN_WIDTH: 40,
TABLE_MARGIN_RIGHT: 15
};
var ROW_SELECTION_COLUMN_ID = 'table-rowSelectionColumn';
var propTypes = {
/**
* An identifier to uniquely identify the table.
*/
id: _propTypes.default.string.isRequired,
/**
* The information for content in the body of the table when sections do not exist. Rows are rendered in the order given.
* The sections property has precedence over this property.
*/
rows: _propTypes.default.arrayOf(_rowShape.default),
/**
* The information for content in the body of the table. Sections are rendered in the order given.
*/
sections: _propTypes.default.arrayOf(_sectionShape.default),
/**
* A string that identifies the element (or elements) that labels the table.
*/
ariaLabelledBy: _propTypes.default.string,
/**
* A string that labels the table for accessibility. If the ariaLabelledBy property is specified, the ariaLabel property is not used.
*/
ariaLabel: _propTypes.default.string,
/**
* @private
* Column index for cell that can receive tab focus.
*/
activeColumnIndex: _propTypes.default.number,
/**
* @private
* Row index for cell that can receive tab focus.
*/
focusedRowIndex: _propTypes.default.number,
/**
* CallBack to trigger re-focusing when focused row or col didn't change, but focus update is needed
*/
triggerFocus: _propTypes.default.func,
/**
* @private
* Specifies if resize handle should be active.
*/
isActiveColumnResizing: _propTypes.default.bool,
/**
* A numeric increment in pixels to adjust column width when resizing with the keyboard.
*/
columnResizeIncrement: _propTypes.default.number,
/**
* The information for pinned columns. Pinned columns are the stickied leftmost columns of the table.
* Columns are presented in the order given.
*/
pinnedColumns: _propTypes.default.arrayOf(_columnShape.default),
/**
* The information for overflow columns. Overflow columns are rendered in the table's horizontal overflow.
* Columns are presented in the order given.
*/
overflowColumns: _propTypes.default.arrayOf(_columnShape.default),
/**
* A number indicating the default column width in pixels. This value is used if no overriding width value is provided on a per-column basis.
* This value is ignored if the isAutoLayout property is set to true.
*/
defaultColumnWidth: _propTypes.default.number,
/**
* A string that specifies the column height. Any valid CSS height value is accepted.
*/
columnHeaderHeight: _propTypes.default.string,
/**
* A string that specifies the height for the rows on the table. Any valid CSS value is accepted.
*/
rowHeight: _propTypes.default.string,
/**
* A string that specifies the Minimum height for the rows on the table. rowHeight takes precedence if valid CSS value is passed.
* With this property the height of the cell will grow to fit the cell content.
*/
rowMinimumHeight: _propTypes.default.string,
/**
* A number indicating the index of the column that represents the row header. The index is based on 0 and cannot exceed one less than the number of columns on the table.
* Index can be set to -1 if row headers are not required.
*/
rowHeaderIndex: _validators.validateRowHeaderIndex,
/**
* A function that is called when a resizable column is resized. Parameters:
* @param {string} columnId columnId
* @param {string} requestedWidth requestedWidth
*/
onColumnResize: _propTypes.default.func,
/**
* A callback function that is called when a selectable cell is selected. Parameters:
* @private
* @param {string} rowId rowId
* @param {string} columnId columnId
* @param {object} event event
*/
onCellSelect: _propTypes.default.func,
/**
* A callback function that is called when one or more rows are selected or cleared. Parameters:
* @param {string} rowId row id of the selected row
*/
onRowSelect: _propTypes.default.func,
/**
* A callback function that is called when a selectable column is selected. Parameters:
* @param {string} columnId columnId
*/
onColumnSelect: _propTypes.default.func,
/**
* A function that is called when a collapsible section is selected. Parameters: `onSectionSelect(sectionId)`
*/
onSectionSelect: _propTypes.default.func,
/*
* A callback function that is called when the row selection column header is selected. Parameters:
* @param {string} columnId columnId
*/
onRowSelectionHeaderSelect: _propTypes.default.func,
/**
* A mode that enables row selection capabilities for the table.
* Use 'single' for single row selection and 'multiple' for multi-row selection.
*/
rowSelectionMode: _propTypes.default.oneOf(Object.values(RowSelectionModes)),
/**
* A Boolean value indicating whether the table columns are displayed. Setting the value to **false** hides the columns,
* but a screen reader still reads the column header values for accessibility.
*/
hasVisibleColumnHeaders: _propTypes.default.bool,
/**
* A Boolean value specifying whether the table has zebra striping for rows.
*/
isStriped: _propTypes.default.bool,
/**
* A Boolean value specifying whether the auto table layout is used to render the table.
*/
isAutoLayout: _propTypes.default.bool,
/**
* @private
* The intl object containing translations. This is retrieved from the context automatically by injectIntl.
*/
intl: _propTypes.default.shape({
formatMessage: _propTypes.default.func
}).isRequired
};
var defaultProps = {
rowHeaderIndex: 0,
defaultColumnWidth: 200,
columnHeaderHeight: '2.5rem',
rowMinimumHeight: 'auto',
pinnedColumns: [],
overflowColumns: [],
rows: [],
hasVisibleColumnHeaders: true
};
var defaultColumnMinimumWidth = 60;
var defaultColumnMaximumWidth = 300;
function Table(props) {
var id = props.id,
ariaLabelledBy = props.ariaLabelledBy,
ariaLabel = props.ariaLabel,
activeColumnIndex = props.activeColumnIndex,
focusedRowIndex = props.focusedRowIndex,
triggerFocus = props.triggerFocus,
isActiveColumnResizing = props.isActiveColumnResizing,
columnResizeIncrement = props.columnResizeIncrement,
rows = props.rows,
sections = props.sections,
pinnedColumns = props.pinnedColumns,
overflowColumns = props.overflowColumns,
onColumnResize = props.onColumnResize,
defaultColumnWidth = props.defaultColumnWidth,
columnHeaderHeight = props.columnHeaderHeight,
rowHeight = props.rowHeight,
rowSelectionMode = props.rowSelectionMode,
onColumnSelect = props.onColumnSelect,
onCellSelect = props.onCellSelect,
onSectionSelect = props.onSectionSelect,
onRowSelect = props.onRowSelect,
onRowSelectionHeaderSelect = props.onRowSelectionHeaderSelect,
hasVisibleColumnHeaders = props.hasVisibleColumnHeaders,
isStriped = props.isStriped,
isAutoLayout = props.isAutoLayout,
rowHeaderIndex = props.rowHeaderIndex,
intl = props.intl,
rowMinimumHeight = props.rowMinimumHeight;
// Manage column resize
var _useState = (0, _react.useState)(0),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
tableHeight = _useState2[0],
setTableHeight = _useState2[1];
var _useState3 = (0, _react.useState)(null),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
activeIndex = _useState4[0],
setActiveIndex = _useState4[1];
// Set an initial width so that the component intially renders sticky behavior correctly. This gets modified later through screen resize events
var _useState5 = (0, _react.useState)(1000),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
boundedWidth = _useState6[0],
setBoundedWidth = _useState6[1];
var activeColumnPageX = (0, _react.useRef)(0);
var activeColumnWidth = (0, _react.useRef)(200);
var tableWidth = (0, _react.useRef)(0);
var resizingDelayTimer = (0, _react.useRef)(null);
var screenResizeTimer = (0, _react.useRef)(null);
var resizeTimer = 100;
var _useState7 = (0, _react.useState)([0]),
_useState8 = (0, _slicedToArray2.default)(_useState7, 2),
pinnedColumnOffsets = _useState8[0],
setPinnedColumnOffsets = _useState8[1];
var _useState9 = (0, _react.useState)([0]),
_useState10 = (0, _slicedToArray2.default)(_useState9, 2),
pinnedColumnHeaderOffsets = _useState10[0],
setPinnedColumnHeaderOffsets = _useState10[1];
var tableContainerRef = (0, _react.useRef)();
var tableRef = (0, _react.useRef)();
var _useState11 = (0, _react.useState)(false),
_useState12 = (0, _slicedToArray2.default)(_useState11, 2),
isTableScrollable = _useState12[0],
setTableScrollable = _useState12[1];
var theme = (0, _react.useContext)(_terraThemeContext.default);
var gridContext = (0, _react.useContext)(_GridContext.default);
var isGridContext = gridContext.role === _GridContext.GridConstants.GRID;
var rowSelectionEffectTriggered = (0, _react.useRef)(false);
var selectedRows = (0, _react.useRef)([]);
var _useState13 = (0, _react.useState)(null),
_useState14 = (0, _slicedToArray2.default)(_useState13, 2),
rowSelectionAriaLiveMessage = _useState14[0],
setRowSelectionAriaLiveMessage = _useState14[1];
var _useState15 = (0, _react.useState)(null),
_useState16 = (0, _slicedToArray2.default)(_useState15, 2),
rowSelectionModeAriaLiveMessage = _useState16[0],
setRowSelectionModeAriaLiveMessage = _useState16[1];
// Aria live region message management
var _useState17 = (0, _react.useState)(null),
_useState18 = (0, _slicedToArray2.default)(_useState17, 2),
columnHeaderAriaLiveMessage = _useState18[0],
setColumnHeaderAriaLiveMessage = _useState18[1];
var columnContextValue = (0, _react.useMemo)(function () {
return {
pinnedColumnOffsets: pinnedColumnOffsets,
pinnedColumnHeaderOffsets: pinnedColumnHeaderOffsets,
setColumnHeaderAriaLiveMessage: setColumnHeaderAriaLiveMessage
};
}, [pinnedColumnOffsets, pinnedColumnHeaderOffsets]);
// Initialize column width properties
var initializeColumn = function initializeColumn(column) {
var columnWidth = column.width || (!isAutoLayout ? defaultColumnWidth : undefined);
return _objectSpread(_objectSpread({}, column), {}, {
width: columnWidth,
// Default column width should only apply to a fixed table layout
minimumWidth: column.minimumWidth || defaultColumnMinimumWidth,
maximumWidth: column.maximumWidth || defaultColumnMaximumWidth,
isResizable: column.isResizable && typeof columnWidth === 'number' && !isAutoLayout
});
};
var hasSelectableRows = rowSelectionMode === RowSelectionModes.MULTIPLE;
var displayedColumns = (0, _react.useMemo)(function () {
// Create row selection column object
var tableRowSelectionColumn = {
id: ROW_SELECTION_COLUMN_ID,
width: TableConstants.ROW_SELECTION_COLUMN_WIDTH,
displayName: intl.formatMessage({
id: 'Terra.table.row-selection-header-display'
}),
isDisplayVisible: false,
isSelectable: !!onRowSelectionHeaderSelect,
isResizable: false
};
return (hasSelectableRows ? [tableRowSelectionColumn] : []).concat(pinnedColumns).concat(overflowColumns);
}, [hasSelectableRows, intl, onRowSelectionHeaderSelect, overflowColumns, pinnedColumns]);
var tableBodyColumns = (0, _react.useMemo)(function () {
var columnData = displayedColumns.reduce(function (columns, currentColumn, columnHeaderIndex) {
for (var columnSpanIndex = 0; columnSpanIndex < (currentColumn.columnSpan || 1); columnSpanIndex += 1) {
columns.push(_objectSpread(_objectSpread({}, currentColumn), {}, {
columnSpanIndex: columnSpanIndex,
columnHeaderIndex: columnHeaderIndex
}));
}
return columns;
}, []);
if (gridContext.tableBodyColumnsRef) {
gridContext.tableBodyColumnsRef.current = columnData;
}
return columnData;
}, [displayedColumns, gridContext.tableBodyColumnsRef]);
var _useState19 = (0, _react.useState)(displayedColumns.map(function (column) {
return initializeColumn(column);
})),
_useState20 = (0, _slicedToArray2.default)(_useState19, 2),
tableHeaderColumns = _useState20[0],
setTableHeaderColumns = _useState20[1];
var defaultSectionRef = (0, _react.useRef)((0, _uuid.v4)());
// Create section array from props
var tableSections = (0, _react.useMemo)(function () {
if (sections) {
return (0, _toConsumableArray2.default)(sections);
}
return [{
id: defaultSectionRef.current,
rows: rows
}];
}, [rows, sections]);
// check if at least one column has an action prop
// same check is done in DataGrid, but as Table can be a stand-alone component, it can't relay on passed prop.
var hasColumnHeaderActions = (0, _actionsUtils.default)(pinnedColumns) || (0, _actionsUtils.default)(overflowColumns);
// eslint-disable-next-line no-nested-ternary
var headerRowCount = hasVisibleColumnHeaders ? hasColumnHeaderActions ? 2 : 1 : 0;
// Calculate total table row count
var subSectionReducer = function subSectionReducer(rowCount, currentSubsection) {
// eslint-disable-next-line no-param-reassign
currentSubsection.subSectionRowIndex = rowCount + 1;
return rowCount + currentSubsection.rows.length + 1;
};
var tableSectionReducer = function tableSectionReducer(rowCount, currentSection) {
if (currentSection.id !== defaultSectionRef.current) {
// eslint-disable-next-line no-param-reassign
currentSection.sectionRowIndex = rowCount + 1;
if (currentSection.subsections) {
return currentSection.subsections.reduce(subSectionReducer, rowCount + 1);
}
return rowCount + currentSection.rows.length + 1;
}
// eslint-disable-next-line no-param-reassign
currentSection.sectionRowIndex = rowCount;
return rowCount + currentSection.rows.length;
};
var tableRowCount = tableSections.reduce(tableSectionReducer, headerRowCount);
// -------------------------------------
// functions
var handleCellSelection = (0, _react.useCallback)(function (selectionDetails, event) {
if (!isGridContext && onRowSelect) {
onRowSelect({
sectionId: selectionDetails.sectionId,
rowId: selectionDetails.rowId
});
return;
}
if (onCellSelect) {
onCellSelect(selectionDetails, event);
}
}, [isGridContext, onCellSelect, onRowSelect]);
// -------------------------------------
// useEffect Hooks
(0, _react.useEffect)(function () {
if (!rowSelectionEffectTriggered.current) {
rowSelectionEffectTriggered.current = true;
return;
}
// Since the row selection mode has changed, the row selection mode needs to be updated.
setRowSelectionModeAriaLiveMessage(intl.formatMessage({
id: rowSelectionMode === RowSelectionModes.MULTIPLE ? 'Terra.table.row-selection-mode-enabled' : 'Terra.table.row-selection-mode-disabled'
}));
setTableHeaderColumns(displayedColumns.map(function (column) {
return initializeColumn(column);
}));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rowSelectionMode]);
// useEffect for row updates
(0, _react.useEffect)(function () {
var previousSelectedRows = (0, _toConsumableArray2.default)(selectedRows.current);
var selectableRows = tableSections.flatMap(function (section) {
if (section.subsections) {
return section.subsections.flatMap(function (subsection) {
return subsection.rows.map(function (row) {
return row;
});
});
}
return section.rows.map(function (row) {
return row;
});
});
selectedRows.current = selectableRows.filter(function (row) {
return row.isSelected;
}).map(function (row) {
return row.id;
});
if (previousSelectedRows.length > 0 && selectedRows.current.length === 0) {
setRowSelectionAriaLiveMessage(intl.formatMessage({
id: 'Terra.table.all-rows-unselected'
}));
} else if (selectedRows.current.length === selectableRows.length) {
setRowSelectionAriaLiveMessage(intl.formatMessage({
id: 'Terra.table.all-rows-selected'
}));
} else {
var rowSelectionsAdded = selectedRows.current.filter(function (row) {
return !previousSelectedRows.includes(row);
});
var rowSelectionsRemoved = previousSelectedRows.filter(function (row) {
return !selectedRows.current.includes(row);
});
var selectionUpdateAriaMessage = '';
if (rowSelectionsAdded.length === 1) {
var selectedRowElement = tableRef.current.querySelector("tr[data-row-id='".concat(rowSelectionsAdded[0], "']"));
if (selectedRowElement) {
var selectedRowLabel = selectedRowElement.getAttribute('aria-rowindex');
selectionUpdateAriaMessage = intl.formatMessage({
id: 'Terra.table.row-selection-template'
}, {
row: selectedRowLabel
});
}
} else if (rowSelectionsAdded.length > 1) {
selectionUpdateAriaMessage = intl.formatMessage({
id: 'Terra.table.multiple-rows-selected'
}, {
rowCount: rowSelectionsAdded.length
});
}
if (rowSelectionsRemoved.length === 1) {
var unselectedRowElement = tableRef.current.querySelector("tr[data-row-id='".concat(rowSelectionsRemoved[0], "']"));
if (unselectedRowElement) {
var unselectedRowLabel = unselectedRowElement.getAttribute('aria-rowindex');
selectionUpdateAriaMessage += intl.formatMessage({
id: 'Terra.table.row-selection-cleared-template'
}, {
row: unselectedRowLabel
});
}
} else if (rowSelectionsRemoved.length > 1) {
selectionUpdateAriaMessage += intl.formatMessage({
id: 'Terra.table.multiple-rows-unselected'
}, {
rowCount: rowSelectionsRemoved.length
});
}
if (selectionUpdateAriaMessage) {
setRowSelectionAriaLiveMessage(selectionUpdateAriaMessage);
}
}
}, [intl, tableSections]);
// useEffect for row displayed columns
(0, _react.useEffect)(function () {
setTableHeaderColumns(displayedColumns.map(function (column) {
return initializeColumn(column);
}));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pinnedColumns, overflowColumns]);
// useEffect to calculate pinned column offsets
(0, _react.useEffect)(function () {
var headerOffsetArray = [];
var cellOffsetArray = [];
var cumulativeHeaderOffset = 0;
var cumulativeCellOffset = 0;
var lastPinnedColumnIndex;
// if table has selectable rows but no pinned columns, then set the offset of the first column to 0
if (hasSelectableRows && pinnedColumns.length === 0) {
lastPinnedColumnIndex = 0;
headerOffsetArray.push(cumulativeHeaderOffset);
setPinnedColumnOffsets(headerOffsetArray);
setPinnedColumnHeaderOffsets(headerOffsetArray);
return;
}
if (pinnedColumns.length > 0) {
lastPinnedColumnIndex = hasSelectableRows ? pinnedColumns.length : pinnedColumns.length - 1;
tableHeaderColumns.slice(0, lastPinnedColumnIndex + 1).forEach(function (pinnedColumn) {
headerOffsetArray.push(cumulativeHeaderOffset);
var currentColumnSpan = pinnedColumn.columnSpan || 1;
for (var columnSpanIndex = 0; columnSpanIndex < currentColumnSpan; columnSpanIndex += 1) {
cellOffsetArray.push(cumulativeCellOffset);
cumulativeCellOffset += pinnedColumn.width / currentColumnSpan;
}
cumulativeHeaderOffset += pinnedColumn.width;
});
}
setPinnedColumnHeaderOffsets(headerOffsetArray);
setPinnedColumnOffsets(cellOffsetArray);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [tableHeaderColumns]);
(0, _react.useEffect)(function () {
var resizeObserver = new _resizeObserverPolyfill.default(function () {
clearTimeout(resizingDelayTimer.current);
resizingDelayTimer.current = setTimeout(function () {
if (tableRef.current) {
var heightOffset = hasColumnHeaderActions ? 2 : 1; // needs 2 pixels if actions row exists in headers to avoid scroll
setTableHeight(tableRef.current.offsetHeight - heightOffset);
var tableContainer = tableContainerRef.current;
setTableScrollable(tableContainer.scrollWidth > tableContainer.clientWidth || tableContainer.scrollHeight > tableContainer.clientHeight);
}
}, resizeTimer);
});
resizeObserver.observe(tableRef.current);
return function () {
resizeObserver.disconnect();
};
}, [hasColumnHeaderActions, tableRef]);
(0, _react.useEffect)(function () {
// Resize handler to control the width of the sticky headers. This value needs to be responsive to window resizing.
var resizeObserver = new _resizeObserverPolyfill.default(function () {
clearTimeout(screenResizeTimer.current);
screenResizeTimer.current = setTimeout(function () {
var _tableContainerRef$cu, _tableRef$current;
var containerWidth = tableContainerRef === null || tableContainerRef === void 0 || (_tableContainerRef$cu = tableContainerRef.current) === null || _tableContainerRef$cu === void 0 ? void 0 : _tableContainerRef$cu.clientWidth;
// An offset is necessary in order to prevent the fixed width from being too large and bleeding outside the container.
setBoundedWidth(Math.min(containerWidth || 0, (tableRef === null || tableRef === void 0 || (_tableRef$current = tableRef.current) === null || _tableRef$current === void 0 ? void 0 : _tableRef$current.clientWidth) || 0) - 25);
}, resizeTimer);
});
resizeObserver.observe(tableContainerRef.current);
return function () {
resizeObserver.disconnect();
};
}, [tableContainerRef, tableRef]);
// -------------------------------------
var handleTableRef = (0, _react.useCallback)(function (node) {
if (gridContext.tableRef) {
gridContext.tableRef.current = node;
}
tableRef.current = node;
}, [gridContext.tableRef]);
var handleContainerRef = (0, _react.useCallback)(function (node) {
if (gridContext.tableContainerRef) {
gridContext.tableContainerRef.current = node;
}
tableContainerRef.current = node;
}, [gridContext.tableContainerRef]);
// -------------------------------------
// event handlers
var handleColumnSelect = (0, _react.useCallback)(function (columnId) {
if (columnId === ROW_SELECTION_COLUMN_ID) {
if (onRowSelectionHeaderSelect) {
onRowSelectionHeaderSelect();
}
} else if (onColumnSelect) {
onColumnSelect(columnId);
}
}, [onColumnSelect, onRowSelectionHeaderSelect]);
var onResizeMouseDown = (0, _react.useCallback)(function (event, index, resizeColumnWidth) {
// Store current table and column values for resize calculations
tableWidth.current = tableRef.current.offsetWidth;
activeColumnPageX.current = event.pageX;
activeColumnWidth.current = resizeColumnWidth;
// Set the active index to the selected column
setActiveIndex(index);
}, []);
var onMouseMove = function onMouseMove(event) {
if (activeIndex == null) {
return;
}
// Ensure the new column width falls within the range of the minimum and maximum values
var diffX = event.pageX - activeColumnPageX.current;
var _tableHeaderColumns$a = tableHeaderColumns[activeIndex],
minimumWidth = _tableHeaderColumns$a.minimumWidth,
maximumWidth = _tableHeaderColumns$a.maximumWidth;
var newColumnWidth = Math.min(Math.max(activeColumnWidth.current + diffX, minimumWidth), maximumWidth);
// Update the width for the column in the state variable
var newColumns = (0, _toConsumableArray2.default)(tableHeaderColumns);
newColumns[activeIndex].width = newColumnWidth;
setTableHeaderColumns(newColumns);
// Update the column and table width
tableRef.current.style.width = "".concat(tableWidth + (newColumnWidth - activeColumnWidth.current), "px");
};
var onMouseUp = function onMouseUp() {
if (onColumnResize) {
onColumnResize(tableHeaderColumns[activeIndex].id, tableHeaderColumns[activeIndex].width);
}
// Remove active index
setActiveIndex(null);
};
var onResizeHandleChange = (0, _react.useCallback)(function (columnIndex, increment) {
var _tableHeaderColumns$c = tableHeaderColumns[columnIndex],
minimumWidth = _tableHeaderColumns$c.minimumWidth,
maximumWidth = _tableHeaderColumns$c.maximumWidth,
width = _tableHeaderColumns$c.width;
var newColumnWidth = Math.min(Math.max(width + increment, minimumWidth), maximumWidth);
// Update the width for the column in the state variable
var newGridColumns = (0, _toConsumableArray2.default)(tableHeaderColumns);
newGridColumns[columnIndex].width = newColumnWidth;
setTableHeaderColumns(newGridColumns);
// Update the column and table width
tableRef.current.style.width = "".concat(tableRef.current.offsetWidth + (newColumnWidth - width), "px");
// Notify consumers of the new column width
if (onColumnResize) {
onColumnResize(tableHeaderColumns[columnIndex].id, tableHeaderColumns[columnIndex].width);
}
}, [tableHeaderColumns, onColumnResize]);
/**
*
* @param {HTMLElement} element - The element to check if it is a text input
* @returns True if the element is a text input. Otherwise, false.
*/
var isTextInput = function isTextInput(element) {
var tagName = element.tagName;
if (tagName.toLowerCase() === 'input') {
var validTypes = ['text', 'password', 'number', 'email', 'tel', 'url', 'search', 'date', 'datetime', 'datetime-local', 'time', 'month', 'week'];
var inputType = element.type;
return validTypes.indexOf(inputType) >= 0;
}
return false;
};
var onKeyDown = function onKeyDown(event) {
var targetElement = event.target;
// Allow default behavior if the event target is an editable field
if (event.keyCode !== KeyCode.KEY_TAB && (isTextInput(targetElement) || ['textarea', 'select'].indexOf(targetElement.tagName.toLowerCase()) >= 0 || targetElement.hasAttribute('contentEditable') && targetElement.getAttribute('contentEditable') !== false)) {
return;
}
// Handle home and end key navigation in table
var focusableTableElements;
if (event.keyCode === KeyCode.KEY_HOME) {
focusableTableElements = (0, _focusManagement.default)(tableRef.current);
if (focusableTableElements) {
focusableTableElements[0].focus();
}
} else if (event.keyCode === KeyCode.KEY_END) {
focusableTableElements = (0, _focusManagement.default)(tableRef.current);
if (focusableTableElements) {
focusableTableElements[focusableTableElements.length - 1].focus();
}
}
};
// Added margin to allow for resizing of last column.
var hasResizableCol = tableHeaderColumns[tableHeaderColumns.length - 1].isResizable;
var tableStyle = {
marginRight: hasResizableCol ? "".concat(TableConstants.TABLE_MARGIN_RIGHT, "px") : '0'
};
// Set first and last row Ids
var firstRowId;
var lastRowId;
if (rows && rows.length) {
firstRowId = rows[0].id;
lastRowId = rows[rows.length - 1].id;
} else if (sections) {
var rowData = _tableUtils.default.getFirstAndLastVisibleRowData(sections);
firstRowId = rowData.firstRowId;
lastRowId = rowData.lastRowId;
}
// -------------------------------------
return /*#__PURE__*/_react.default.createElement("div", {
ref: handleContainerRef,
className: cx('table-container', theme.className)
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
,
tabIndex: !isGridContext && isTableScrollable ? 0 : undefined
}, /*#__PURE__*/_react.default.createElement("table", (0, _extends2.default)({
ref: handleTableRef,
id: id,
role: gridContext.role,
"aria-labelledby": ariaLabelledBy,
"aria-label": ariaLabel,
"aria-rowcount": tableRowCount,
style: tableStyle // eslint-disable-line react/forbid-dom-props
,
className: cx('table', {
headerless: !hasVisibleColumnHeaders,
'auto-layout': isAutoLayout
}),
onKeyDown: !isGridContext ? onKeyDown : undefined
}, activeIndex != null && {
onMouseUp: onMouseUp,
onMouseMove: onMouseMove,
onMouseLeave: onMouseUp
}), /*#__PURE__*/_react.default.createElement(_ColumnContext.default.Provider, {
value: columnContextValue
}, /*#__PURE__*/_react.default.createElement("colgroup", null, tableHeaderColumns.map(function (column) {
var currentColumnWidth = column.width;
if (typeof column.width === 'number') {
currentColumnWidth = "".concat(column.width, "px");
}
if (column.columnSpan) {
currentColumnWidth = "calc(".concat(currentColumnWidth, " / ").concat(column.columnSpan, ")");
}
// eslint-disable-next-line react/forbid-dom-props
return /*#__PURE__*/_react.default.createElement("col", {
span: column.columnSpan,
key: column.id,
style: {
width: currentColumnWidth
}
});
})), /*#__PURE__*/_react.default.createElement(_ColumnHeader.default, {
tableId: id,
isActiveColumnResizing: isActiveColumnResizing,
activeColumnIndex: activeColumnIndex,
focusedRowIndex: focusedRowIndex,
triggerFocus: triggerFocus,
columns: tableHeaderColumns,
hasVisibleColumnHeaders: hasVisibleColumnHeaders,
headerHeight: columnHeaderHeight,
columnResizeIncrement: columnResizeIncrement,
tableHeight: tableHeight,
onResizeMouseDown: onResizeMouseDown,
onColumnSelect: handleColumnSelect,
onResizeHandleChange: onResizeHandleChange,
hasColumnHeaderActions: hasColumnHeaderActions
}), tableSections.map(function (section) {
return /*#__PURE__*/_react.default.createElement(_Section.default, {
id: section.id,
tableId: id,
key: section.id,
sectionRowIndex: section.sectionRowIndex,
isCollapsible: section.isCollapsible,
isCollapsed: section.isCollapsed,
isHidden: section.id === defaultSectionRef.current,
isTableStriped: isStriped,
text: section.text,
rows: section.rows,
subsections: section.subsections,
rowHeight: rowHeight,
rowSelectionMode: rowSelectionMode,
displayedColumns: tableBodyColumns,
rowHeaderIndex: rowHeaderIndex,
onCellSelect: isGridContext || rowSelectionMode ? handleCellSelection : undefined,
onSectionSelect: onSectionSelect,
rowMinimumHeight: rowMinimumHeight,
boundingWidth: boundedWidth,
firstRowId: firstRowId,
lastRowId: lastRowId
});
}))), /*#__PURE__*/_react.default.createElement(_terraVisuallyHiddenText.default, {
className: cx('row-selection-mode-region'),
"aria-live": "polite",
text: rowSelectionModeAriaLiveMessage
}), /*#__PURE__*/_react.default.createElement(_terraVisuallyHiddenText.default, {
className: cx('row-selection-region'),
"aria-live": "polite",
text: rowSelectionAriaLiveMessage
}), /*#__PURE__*/_react.default.createElement(_terraVisuallyHiddenText.default, {
className: cx('column-header-region'),
"aria-live": "polite",
"aria-atomic": "true",
text: columnHeaderAriaLiveMessage
}));
}
Table.propTypes = propTypes;
Table.defaultProps = defaultProps;
var _default = exports.default = /*#__PURE__*/_react.default.memo((0, _reactIntl.injectIntl)(Table));