UNPKG

@sap-ux/ui-components

Version:

SAP UI Components Library

256 lines 11 kB
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