UNPKG

@native-html/heuristic-table-plugin

Version:

🔠 A 100% native component using heuristics to render tables in react-native-render-html

123 lines (114 loc) • 3.27 kB
import { TableCell, Display, DisplayCell, TableFlexColumnContainer, TableFlexRowContainer, TableRoot } from '../shared-types'; import pipe from 'ramda/src/pipe'; import prop from 'ramda/src/prop'; import slice from 'ramda/src/slice'; import sum from 'ramda/src/sum'; import map from 'ramda/src/map'; import max from 'ramda/src/max'; import reduce from 'ramda/src/reduce'; import partial from 'ramda/src/partial'; import flatten from 'ramda/src/flatten'; import sort from 'ramda/src/sort'; import filter from 'ramda/src/filter'; import makeRows from './makeRows'; const getRowGroupHeight = pipe( map<TableCell, number>(prop('lenY')), reduce<number, number>(max, 0) ); function groupCellsByVGroup(cellsByRow: TableCell[][]) { const cellsByVGroup: TableCell[][][] = []; let rowHeight = 1; for (let i = 0; i < cellsByRow.length; i += Math.max(rowHeight, 1)) { const row = cellsByRow[i]; rowHeight = getRowGroupHeight(row); cellsByVGroup.push(slice(i, i + rowHeight)(cellsByRow)); } return cellsByVGroup; } function makeRowContainer(cells: TableCell[]): TableFlexRowContainer { return { type: 'row-container', children: cells }; } function makeColContainer(cells: TableCell[]): TableFlexColumnContainer { return { type: 'col-container', children: makeRows(cells).map(makeRowContainer) }; } const splitToColumnContainers = pipe< TableCell[][], TableCell[], TableFlexColumnContainer[] >(flatten, function (cells: TableCell[]): TableFlexColumnContainer[] { let breakpointsX: number[] = pipe<TableCell[], TableCell[], number[]>( filter((cell: TableCell) => cell.lenY > 1), map(prop('x')) )(cells); let breakpointIndex = 0; const cellsByRow = sort((a: TableCell, b: TableCell) => a.x - b.x)(cells); let containers: TableCell[][] = []; let colGroup: TableCell[] = []; for (const cell of cellsByRow) { if (cell.x < (breakpointsX[breakpointIndex] ?? Infinity)) { colGroup.push(cell); } else { colGroup.length && containers.push(colGroup); containers.push([cell]); colGroup = []; breakpointIndex += 1; } } colGroup.length && containers.push(colGroup); return containers.map(makeColContainer); }); function translateVGroups( virtualRowGroups: TableCell[][][] ): TableFlexRowContainer[] { const flattenRows: TableFlexRowContainer[] = []; for (const rowGroup of virtualRowGroups) { if (rowGroup.length === 1) { flattenRows.push({ type: 'row-container', children: rowGroup[0] }); } else { const container: TableFlexRowContainer = { type: 'row-container', children: splitToColumnContainers(rowGroup) }; flattenRows.push(container); } } return flattenRows; } function makeCell(columnWidths: number[], cell: DisplayCell): TableCell { return { ...cell, type: 'cell', width: pipe(slice(cell.x, cell.x + cell.lenX), sum)(columnWidths) }; } export default function createRenderTree( display: Display, columnWidths: number[] ): TableRoot { const children = pipe( map(partial(makeCell, [columnWidths])), makeRows, groupCellsByVGroup, translateVGroups )(display.cells); return { type: 'root', children: children }; }