@sap-ux/ui-components
Version:
SAP UI Components Library
256 lines • 11 kB
JavaScript
import React from 'react';
import { UIFocusZone, UIFocusZoneDirection } from '../index.js';
import { UIFlexibleTableLayout } from './types.js';
import { composeClassNames } from './utils.js';
/**
* Render row title.
*
* @param {UIFlexibleTableProps<T>} props
* @param {UIFlexibleTableRowType<T>} row
* @param {number | undefined} rowIndex
* @param {React.ReactElement} rowActions
* @returns {React.ReactNode}
*/
function renderRowTitle(props, row, rowIndex, rowActions) {
return (React.createElement("div", { className: "flexible-table-content-table-row-header" },
React.createElement("div", { className: "flexible-table-content-table-row-header-text-content", title: row.tooltip }, row.title || React.createElement("span", null)),
props.layout === UIFlexibleTableLayout.Wrapping &&
getActionsContainer(false, rowIndex, rowActions, 'flexible-table-content-table-row-header-actions')));
}
/**
*
* @param {boolean} useFocusZone
* @param {number | undefined} rowIndex
* @param {React.ReactElement} rowActions
* @param {string} className
* @returns {JSX.Element}
*/
function getActionsContainer(useFocusZone, rowIndex, rowActions, className) {
return useFocusZone ? (React.createElement(UIFocusZone, { as: "div", key: `cell-actions-${rowIndex ?? 'unknown'}`, className: className, direction: UIFocusZoneDirection.horizontal, isCircularNavigation: true, shouldEnterInnerZone: (ev) => ev.key === 'Enter' }, rowActions)) : (React.createElement("div", { className: className }, rowActions));
}
/**
* Render the index column header cell for the title row.
*
* @param {UIFlexibleTableProps<T>} props
* @returns {React.ReactElement}
*/
function renderIndexColumnCell(props) {
if (props.onRenderTitleColumnCell) {
const { content, cellClassNames, tooltip } = props.onRenderTitleColumnCell({ isIndexColumn: true });
const className = composeClassNames('flexible-table-content-table-title-row-item-index', [cellClassNames]);
return (React.createElement("div", { key: "title-cell-index", className: className, title: tooltip }, content));
}
return (React.createElement("div", { key: "title-cell-index", className: "flexible-table-content-table-title-row-item-index" },
React.createElement("span", { className: "flexible-table-content-table-title-row-item-index-value" }, "#")));
}
/**
* Render a data column header cell for the title row.
*
* @param {UIFlexibleTableProps<T>} props
* @param column - column definition
* @param {number} i - column index
* @returns {React.ReactNode | null} rendered cell or null if a span break was encountered
*/
function renderColumnCell(props, column, i) {
const key = column.key;
const tableId = props.id;
if (props.onRenderTitleColumnCell) {
const { content, isSpan, cellClassNames, tooltip } = props.onRenderTitleColumnCell({
colIndex: i,
colKey: key
});
const className = composeClassNames('flexible-table-content-table-title-row-item-data-cells-value', [
cellClassNames,
column.className
]);
if (isSpan) {
return {
isSpan: true,
node: (React.createElement("div", { key: `title-cell-unknown`, className: className, title: tooltip || column.tooltip, id: `${tableId}-header-column-${key}` }, content))
};
}
return {
isSpan: false,
node: (React.createElement("div", { key: `cell-${key}-${i}`, className: className, title: tooltip || column.tooltip, id: `${tableId}-header-column-${key}` }, content))
};
}
const className = composeClassNames('flexible-table-content-table-title-row-item-data-cells-value', [
column.className
]);
return {
isSpan: false,
node: (React.createElement("div", { key: `title-cell-${key}-${i}`, className: className, title: column.tooltip, id: `${tableId}-header-column-${key}` }, column.title))
};
}
/**
* On render title row.
*
* @param {UIFlexibleTableProps<T>} props
* @param {number} paddingRight
* @returns {React.ReactNode}
*/
export function renderTitleRow(props, paddingRight) {
const rowCells = [];
if (props.showIndexColumn) {
rowCells.push(renderIndexColumnCell(props));
}
const rowCellsData = [];
for (let i = 0; i < props.columns.length; i++) {
const column = props.columns[i];
if (column.hidden) {
continue;
}
const { node, isSpan } = renderColumnCell(props, column, i);
rowCellsData.push(node);
if (isSpan) {
break;
}
}
// Add data cells titles
rowCells.push(React.createElement("div", { key: `flexible-table-content-table-title-row-item-data-cells}`, className: `flexible-table-content-table-title-row-item-data-cells in-row` }, rowCellsData));
// Add actions title
if (props.onRenderTitleColumnCell) {
const { content, cellClassNames, tooltip } = props.onRenderTitleColumnCell({
isActionsColumn: true
});
const className = composeClassNames('flexible-table-content-table-title-row-item-actions', [cellClassNames]);
rowCells.push(React.createElement("div", { key: "title-row", className: className, title: tooltip }, content));
}
else {
rowCells.push(React.createElement("div", { key: `title-cell-actions`, className: "flexible-table-content-table-title-row-item-actions" }));
}
return (React.createElement("div", { className: "flexible-table-content-table-title-row", key: "title-row", style: { paddingRight }, tabIndex: -1 },
React.createElement("div", { className: "flexible-table-content-table-title-row-wrapper" },
React.createElement("div", { className: "flexible-table-content-table-title-row-wrapper-cells" }, rowCells))));
}
/**
* Method checks if passed row is disabled for drag.
*
* @param value Row item value.
* @returns {boolean} Is row disabled for drag.
*/
function isRowDisabled(value) {
let disabled = false;
if (value && typeof value === 'object' && 'disabled' in value) {
disabled = !!value.disabled;
}
return disabled;
}
/**
* Method returns CSS styles for row item element.
*
* @param isDragDisabled Is row disabled for drag.
* @param isDragged True if row is currently dragging.
* @param isTouchDragDisabled Is drag disabled by touch events.
* @returns {string} CSS styles for row item element.
*/
function getRowStyles(isDragDisabled, isDragged, isTouchDragDisabled) {
const style = {
pointerEvents: 'all',
cursor: isDragged ? 'grabbing' : 'inherit',
touchAction: 'none'
};
if (isDragDisabled) {
style.cursor = 'default';
}
if (isDragDisabled || isTouchDragDisabled) {
style.touchAction = 'auto';
}
return style;
}
/**
* Method returns class name for row index parity.
*
* @param rowIndex Row index.
* @returns {string} Class name string.
*/
function getParityClassName(rowIndex) {
let className = '';
if (rowIndex !== undefined) {
// Index is zero based - odd/even opposite
className = rowIndex % 2 === 0 ? 'odd' : 'even';
}
return className;
}
/**
* Build the inline style for a row, including drag/loading state overrides.
*
* @param params - drag and drop params
* @param isDragDisabled - whether drag is disabled for this row
* @param isTouchDragDisabled - whether touch drag is disabled
* @param isContentLoading - whether table content is loading
* @returns CSSProperties
*/
function buildRowStyle(params, isDragDisabled, isTouchDragDisabled, isContentLoading) {
const style = {
...params.props.style,
...getRowStyles(isDragDisabled, params.isDragged, !!isTouchDragDisabled)
};
if (isContentLoading) {
style.pointerEvents = 'none';
style.cursor = 'none';
}
return style;
}
/**
* Build touch event handlers to disable drag via touch when configured.
*
* @param isDragDisabled - whether drag is disabled for this row
* @param isTouchDragDisabled - whether touch drag is disabled
* @returns object with optional onTouchStart and onTouchEnd handlers
*/
function buildTouchHandlers(isDragDisabled, isTouchDragDisabled) {
if (!isDragDisabled && isTouchDragDisabled) {
const stopPropagation = (event) => {
event.nativeEvent.stopImmediatePropagation();
};
return { onTouchStart: stopPropagation, onTouchEnd: stopPropagation };
}
return {};
}
/**
* UIFlexibleTableRow component.
*
* @exports
* @param {UIFlexibleTableRowProps} props
* @returns {JSX.Element}
*/
export function UIFlexibleTableRow(props) {
const { dragAndDropParams: params, rowData, rowActions, rowRef, tableProps, className: dynamicClassName } = props;
const row = params.value;
const rowIndex = params.index;
const rowCells = [];
const { isDragged, isSelected, isOutOfBounds, value } = params;
const isRow = row && rowIndex !== undefined;
const isDragDisabled = isRowDisabled(value);
if (isRow) {
rowCells.push(rowData);
if (tableProps.layout === UIFlexibleTableLayout.InlineFlex) {
// Add row actions
rowCells.push(getActionsContainer(true, rowIndex, rowActions, 'flexible-table-content-table-row-item-actions'));
}
}
const rowClassName = composeClassNames('flexible-table-content-table-row', [
tableProps.noRowBackground ? 'no-background' : '',
isDragged ? 'dragged' : '',
isSelected ? 'selected' : '',
isOutOfBounds ? 'out-of-bounds' : '',
row.className ?? '',
tableProps.lockVertically ? 'locked-axis' : 'unlocked-axis',
getParityClassName(rowIndex),
tableProps.reverseBackground && !tableProps.noRowBackground ? 'reverse-background' : '',
dynamicClassName
]);
const rowWrapperClassNames = [
'flexible-table-content-table-row-wrapper',
tableProps.layout === UIFlexibleTableLayout.InlineFlex ? 'inline-layout' : 'wrapping-layout'
].join(' ');
const showRowTitle = isRow && (tableProps.showRowTitles || tableProps.layout === UIFlexibleTableLayout.Wrapping);
const style = buildRowStyle(params, isDragDisabled, tableProps.isTouchDragDisabled, tableProps.isContentLoading);
const { onTouchStart, onTouchEnd } = buildTouchHandlers(isDragDisabled, tableProps.isTouchDragDisabled);
return (React.createElement("li", { ...params.props, className: rowClassName, "data-movable-handle": true, key: `row-${rowIndex}`, id: `row-${rowIndex}`, style: style, onTouchStart: onTouchStart, onTouchEnd: onTouchEnd },
React.createElement("div", { className: rowWrapperClassNames, ref: rowRef },
showRowTitle && renderRowTitle(tableProps, row, rowIndex, rowActions),
React.createElement("div", { className: "flexible-table-content-table-row-wrapper-cells" }, rowCells))));
}
//# sourceMappingURL=UIFlexibleTableRow.js.map