@sap-ux/ui-components
Version:
SAP UI Components Library
255 lines • 8.74 kB
JavaScript
import React from 'react';
import { Sticky } from '@fluentui/react';
import { UIIcon } from '../index.js';
/**
* Method to copy and sort.
*
* @param {T[]} items
* @param {string }columnKey
* @param {boolean} isSortedDescending
* @returns {T[]}
*/
export function _copyAndSort(items, columnKey, isSortedDescending) {
const key = columnKey;
return items.slice(0).sort((a, b) => {
const comparison = a[key] < b[key];
const shouldSwap = isSortedDescending ? !comparison : comparison;
return shouldSwap ? 1 : -1;
});
}
/**
* Focus edited cell.
*
* @param {EditedCell | undefined} editedCell
* @param {UITableProps} props
* @param {string} direction
* @returns {Promise<void>}
*/
export function focusEditedCell(editedCell, props, direction = '') {
const rowIndex = editedCell?.rowIndex || 0;
const colKey = editedCell?.column?.key || '';
let newRowIndex = rowIndex;
let newColKey = colKey;
if (!colKey) {
return Promise.resolve();
}
// go up/down/left/right
if (direction) {
const editableColumnKeys = props.columns.filter((c) => c.editable).map((c) => c.key);
const rowsLen = props.items.length;
const colIdx = editableColumnKeys.indexOf(colKey);
const moves = {
right: () => {
if (colIdx < editableColumnKeys.length - 1) {
newColKey = editableColumnKeys[colIdx + 1];
}
},
left: () => {
if (colIdx > 0) {
newColKey = editableColumnKeys[colIdx - 1];
}
},
down: () => {
if (rowIndex < rowsLen - 1) {
newRowIndex = rowIndex + 1;
}
},
up: () => {
if (rowIndex > 0) {
newRowIndex = rowIndex - 1;
}
}
};
moves[direction]?.();
}
return new Promise((resolve) => {
requestAnimationFrame(() => {
const cell = getCellFromCoords(newRowIndex, newColKey, props.columns, props.showRowNumbers);
if (cell && direction) {
cell.click();
}
cell?.focus();
requestAnimationFrame(() => resolve());
});
});
}
/**
* Get cell from coordinates.
*
* @param {number} rowIdx
* @param {string} columnKey
* @param {UIColumn} columns
* @param {boolean} addOneToColIndex
* @returns {NodeListOf<Element>}
*/
export function getCellFromCoords(rowIdx, columnKey, columns, addOneToColIndex = false) {
const selectedIdx = (columns.findIndex((col) => col.key === columnKey) || 0) + +addOneToColIndex;
const row = document.querySelector(`.ms-DetailsList .ms-DetailsList-contentWrapper .ms-List-page .ms-DetailsRow[data-item-index="${rowIdx || 0}"]`);
const cols = row?.querySelectorAll('.ms-DetailsRow-cell');
return cols?.length && cols[selectedIdx];
}
// manual workaround due to the lack of API for selecting columns
/**
* Scrolls to column.
*
* @param {string} columnKey
* @param {UIColumn[]} columns
* @param {number} selectedRow
* @param {boolean} addOneToColIndex
*/
export function scrollToColumn(columnKey, columns, selectedRow, addOneToColIndex = false) {
const sidebar = document.querySelector('.data-editor__sidebar');
const sidebarWidth = (sidebar?.getBoundingClientRect().width ?? 0) + (addOneToColIndex ? 20 : 0);
const scrollContainer = document.querySelector('.ms-ScrollablePane--contentContainer');
const cell = getCellFromCoords(selectedRow, columnKey, columns, addOneToColIndex);
const box = cell?.getBoundingClientRect();
if (scrollContainer && box) {
const left = scrollContainer.scrollLeft + Math.ceil(box.x) - sidebarWidth;
requestAnimationFrame(() => scrollContainer.scrollTo({ left, behavior: 'smooth' }));
}
}
/**
* Scrolls to row.
*
* @param {number} idx
* @param {IDetailsList | null} table
*/
export function scrollToRow(idx = 0, table = null) {
if (!table) {
return;
}
table.focusIndex(idx, false);
const slctr = `.ms-DetailsList-contentWrapper .ms-DetailsRow[data-selection-index="${idx}"]`;
waitFor(slctr)
.then((rowEl) => {
rowEl.setAttribute('tabIndex', '0');
rowEl.click();
rowEl.focus();
showFocus();
})
.catch((e) => {
throw e;
});
}
/**
* Wait for selector.
*
* @param {string} selector
* @param {number} count - number of tries, after which the element is considered not found
* (so that the function doesn't run forever)
* @returns {Promise<Element>}
*/
export async function waitFor(selector, count = 10) {
if (count === 0) {
throw new Error('Element for selector not found: ' + selector);
}
await sleep();
const el = document.querySelector(selector);
return el ? Promise.resolve(el) : waitFor(selector, count - 1);
}
/**
* Promisified setTimeout.
*
* @param ms
* @returns Promise
*/
export function sleep(ms = 200) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Adds row numbers.
*
* @param {any} columns
* @param {boolean} showRowNumbers
* @returns {any}
*/
export function addRowNumbers(columns, showRowNumbers = false) {
if (showRowNumbers && columns[0].key !== '__row_number__') {
columns.unshift({
key: '__row_number__',
name: '#',
fieldName: '__row_number__',
minWidth: 24,
maxWidth: 24,
isResizable: false
});
}
return columns;
}
export const _onHeaderRender = (props, defaultRender) => {
if (!props || !defaultRender) {
return null;
}
const customProps = {
...props,
onRenderColumnHeaderTooltip: (item, tooltipDefaultRender) => {
if (item?.column) {
const column = item.column;
const editable = (column.editable ? '' : 'not-') + 'editable-container';
const isRowNumber = column.key === '__row_number__';
const containerDiv = isRowNumber ? React.createElement("div", { className: editable }) : null;
// row number column header is focusable on the parent of this cell
const isFocusable = !isRowNumber;
return (React.createElement("div", { className: "data-editor__header-cell", "data-is-focusable": isFocusable },
column.iconName && (React.createElement(UIIcon, { className: "type-icon", iconName: column.iconName, title: column.iconTooltip || '' })),
React.createElement("span", { title: column?.headerTooltip || column.name }, column.name),
containerDiv));
}
const isCheckTooltip = item?.hostClassName === 'ms-DetailsHeader-checkTooltip';
if (props.selection && isCheckTooltip && tooltipDefaultRender) {
return tooltipDefaultRender(item);
}
return null;
}
};
return React.createElement(Sticky, null, defaultRender(customProps));
};
/**
* Gets styles for selected cell.
*
* @param state
* @returns {Partial<IDetailsListStyles>}
*/
export function getStylesForSelectedCell(state) {
let styles = {};
const editedRow = state.editedCell ? state.editedCell.rowIndex : undefined;
const editedColumn = state.editedCell ? state.editedCell.column : undefined;
if (editedRow !== undefined && editedColumn !== undefined) {
styles = {
root: {
['div.ms-List-cell']: {
position: 'relative',
zIndex: 0
},
[`div.ms-List-cell[data-list-index="${editedRow}"]`]: {
zIndex: 1
},
[`.ms-DetailsRow-cell`]: {
overflow: 'hidden'
},
[`div.ms-List-cell[data-list-index="${editedRow}"] .ms-DetailsRow-cell[data-automation-key="${editedColumn.key}"]`]: {
overflow: 'visible'
}
}
};
}
return styles;
}
export function showFocus() {
document.body.classList.remove('ms-Fabric--isFocusHidden');
document.body.classList.add('ms-Fabric--isFocusVisible');
}
export function hideFocus() {
document.body.classList.add('ms-Fabric--isFocusHidden');
document.body.classList.remove('ms-Fabric--isFocusVisible');
}
/**
* Gets ComboBox input.
*
* @param ref
* @returns {HTMLInputElement | undefined }
*/
export function getComboBoxInput(ref) {
return ref?.current?.querySelector('input');
}
//# sourceMappingURL=UITable-helper.js.map