import * as React from 'react'; import { Text, View } from '@react-pdf/renderer'; import type { DatasheetVoltageTable } from '../../model/types'; import { styles } from '../styles'; function clamp(n: number, min: number, max: number): number { return Math.max(min, Math.min(max, n)); } export function DenseTable(props: { table: Pick; firstColLabel: string; }): React.ReactElement { const cols = props.table.columns; const rows = props.table.rows; const noWrapHeader = (label: string): string => { const raw = String(label || '').trim(); if (!raw) return ''; // Ensure the header never wraps into a second line. // - Remove whitespace break opportunities (NBSP) // NOTE: Avoid inserting zero-width joiners between letters. // Some PDF viewers render them with spacing/odd glyph behavior. // This is intentionally aggressive because broken headers destroy scanability. return raw.replace(/\s+/g, '\u00A0'); }; // Column widths: use explicit percentages (no rounding gaps) so the table always // consumes the full content width. // Goal: // - keep the designation column *not too wide* // - guarantee enough width for data headers when there is available space const cfgMin = 0.18; const cfgMax = 0.30; let cfgPct = cols.length >= 14 ? 0.22 : cols.length >= 12 ? 0.24 : cols.length >= 10 ? 0.26 : 0.30; cfgPct = clamp(cfgPct, cfgMin, cfgMax); const minDataPct = cols.length >= 14 ? 0.045 : cols.length >= 12 ? 0.05 : cols.length >= 10 ? 0.055 : 0.06; // If the initial cfgPct leaves too little width per data column, reduce cfgPct. const cfgPctMaxForMinData = 1 - cols.length * minDataPct; if (Number.isFinite(cfgPctMaxForMinData)) { cfgPct = Math.min(cfgPct, cfgPctMaxForMinData); cfgPct = clamp(cfgPct, cfgMin, cfgMax); } const cfgW = `${(cfgPct * 100).toFixed(4)}%`; const dataTotal = 1 - cfgPct; const each = cols.length ? dataTotal / cols.length : dataTotal; const dataWs = cols.map((_, idx) => { // Keep the last column as the remainder so percentages sum to exactly 100%. if (idx === cols.length - 1) { const used = each * Math.max(0, cols.length - 1); const remainder = Math.max(0, dataTotal - used); return `${(remainder * 100).toFixed(4)}%`; } return `${(each * 100).toFixed(4)}%`; }); return ( {noWrapHeader(props.firstColLabel)} {cols.map((c, idx) => { const isLast = idx === cols.length - 1; return ( {noWrapHeader(c.label)} ); })} {rows.map((r, ri) => ( {r.configuration} {r.cells.map((cell, ci) => { const isLast = ci === r.cells.length - 1; return ( {cell} ); })} ))} ); }