UNPKG

@ui5/webcomponents-react

Version:

React Wrapper for UI5 Web Components and additional components

280 lines (271 loc) 7.95 kB
import { defaultColumn, emptyRenderer } from './publicUtils.js'; // Find the depth of the columns export function findMaxDepth(columns, depth = 0) { return columns.reduce((prev, curr) => { if (curr.columns) { return Math.max(prev, findMaxDepth(curr.columns, depth + 1)); } return depth; }, 0); } // Build the visible columns, headers and flat column list export function linkColumnStructure(columns, parent, depth = 0) { return columns.map(column => { column = { ...column, parent, depth }; assignColumnAccessor(column); if (column.columns) { column.columns = linkColumnStructure(column.columns, column, depth + 1); } return column; }); } export function flattenColumns(columns) { return flattenBy(columns, 'columns'); } export function assignColumnAccessor(column) { // First check for string accessor let { id, accessor } = column; const { Header } = column; if (typeof accessor === 'string') { id = id || accessor; const accessorPath = accessor.split('.'); accessor = row => getBy(row, accessorPath); } if (!id && typeof Header === 'string' && Header) { id = Header; } if (!id && column.columns) { console.error(column); throw new Error('A column ID (or unique "Header" value) is required!'); } if (!id) { console.error(column); throw new Error('A column ID (or string accessor) is required!'); } Object.assign(column, { id, accessor }); return column; } export function decorateColumn(column, userDefaultColumn) { if (!userDefaultColumn) { throw new Error(); } Object.assign(column, { // Make sure there is a fallback header, just in case Header: emptyRenderer, Footer: emptyRenderer, ...defaultColumn, ...userDefaultColumn, ...column }); Object.assign(column, { originalWidth: column.width }); return column; } // Build the header groups from the bottom up export function makeHeaderGroups(allColumns, defaultColumn, additionalHeaderProperties = () => ({})) { const headerGroups = []; let scanColumns = allColumns; let uid = 0; const getUID = () => uid++; while (scanColumns.length) { // The header group we are creating const headerGroup = { headers: [] }; // The parent columns we're going to scan next const parentColumns = []; const hasParents = scanColumns.some(d => d.parent); // Scan each column for parents scanColumns.forEach(column => { // What is the latest (last) parent column? const latestParentColumn = [...parentColumns].reverse()[0]; let newParent; if (hasParents) { // If the column has a parent, add it if necessary if (column.parent) { newParent = { ...column.parent, originalId: column.parent.id, id: `${column.parent.id}_${getUID()}`, headers: [column], ...additionalHeaderProperties(column) }; } else { // If other columns have parents, we'll need to add a place holder if necessary const originalId = `${column.id}_placeholder`; newParent = decorateColumn({ originalId, id: `${column.id}_placeholder_${getUID()}`, placeholderOf: column, headers: [column], ...additionalHeaderProperties(column) }, defaultColumn); } // If the resulting parent columns are the same, just add // the column and increment the header span if (latestParentColumn && latestParentColumn.originalId === newParent.originalId) { latestParentColumn.headers.push(column); } else { parentColumns.push(newParent); } } headerGroup.headers.push(column); }); headerGroups.push(headerGroup); // Start scanning the parent columns scanColumns = parentColumns; } return headerGroups.reverse(); } const pathObjCache = new Map(); export function getBy(obj, path, def) { if (!path) { return obj; } const cacheKey = typeof path === 'function' ? path : JSON.stringify(path); const pathObj = pathObjCache.get(cacheKey) || (() => { const pathObj = makePathArray(path); pathObjCache.set(cacheKey, pathObj); return pathObj; })(); let val; try { val = pathObj.reduce((cursor, pathPart) => cursor[pathPart], obj); } catch (_e) { // continue regardless of error } return typeof val !== 'undefined' ? val : def; } export function getFirstDefined(...args) { for (let i = 0; i < args.length; i += 1) { if (typeof args[i] !== 'undefined') { return args[i]; } } } export function getElementDimensions(element) { const rect = element.getBoundingClientRect(); const style = window.getComputedStyle(element); const margins = { left: parseInt(style.marginLeft), right: parseInt(style.marginRight) }; const padding = { left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight) }; return { left: Math.ceil(rect.left), width: Math.ceil(rect.width), outerWidth: Math.ceil(rect.width + margins.left + margins.right + padding.left + padding.right), marginLeft: margins.left, marginRight: margins.right, paddingLeft: padding.left, paddingRight: padding.right, scrollWidth: element.scrollWidth }; } export function isFunction(a) { if (typeof a === 'function') { return a; } } export function flattenBy(arr, key) { const flat = []; const recurse = arr => { arr.forEach(d => { if (!d[key]) { flat.push(d); } else { recurse(d[key]); } }); }; recurse(arr); return flat; } export function expandRows(rows, { manualExpandedKey, expanded, expandSubRows = true }) { const expandedRows = []; const handleRow = (row, addToExpandedRows = true) => { row.isExpanded = row.original && row.original[manualExpandedKey] || expanded[row.id]; row.canExpand = row.subRows && !!row.subRows.length; if (addToExpandedRows) { expandedRows.push(row); } if (row.subRows && row.subRows.length && row.isExpanded) { row.subRows.forEach(row => handleRow(row, expandSubRows)); } }; rows.forEach(row => handleRow(row)); return expandedRows; } export function getFilterMethod(filter, userFilterTypes, filterTypes) { return isFunction(filter) || userFilterTypes[filter] || filterTypes[filter] || filterTypes.text; } export function shouldAutoRemoveFilter(autoRemove, value, column) { return autoRemove ? autoRemove(value, column) : typeof value === 'undefined'; } export function unpreparedAccessWarning() { throw new Error('React-Table: You have not called prepareRow(row) one or more rows you are attempting to render.'); } let passiveSupported = null; export function passiveEventSupported() { // memoize support to avoid adding multiple test events if (typeof passiveSupported === 'boolean') return passiveSupported; let supported = false; try { const options = { get passive() { supported = true; return false; } }; window.addEventListener('test', null, options); window.removeEventListener('test', null, options); } catch (_err) { supported = false; } passiveSupported = supported; return passiveSupported; } // const reOpenBracket = /\[/g; const reCloseBracket = /\]/g; function makePathArray(obj) { return flattenDeep(obj) // remove all periods in parts .map(d => String(d).replace('.', '_')) // join parts using period .join('.') // replace brackets with periods .replace(reOpenBracket, '.').replace(reCloseBracket, '') // split it back out on periods .split('.'); } function flattenDeep(arr, newArr = []) { if (!Array.isArray(arr)) { newArr.push(arr); } else { for (let i = 0; i < arr.length; i += 1) { flattenDeep(arr[i], newArr); } } return newArr; }