From c8413c6cc67e77a7560bd2a28485cc92f45ff08c Mon Sep 17 00:00:00 2001 From: Mathias Jakobsen Date: Mon, 4 Sep 2023 09:03:01 +0100 Subject: [PATCH] Merge pull request #14596 from overleaf/mj-manual-cell-widths [visual] Manually calculate column widths in table generator GitOrigin-RevId: ce42219098d56cca2fbdb1bef6ad33a11d79fb25 --- .../components/table-generator/table.tsx | 61 ++++++++++++++++++- .../extensions/visual/table-generator.ts | 5 +- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/services/web/frontend/js/features/source-editor/components/table-generator/table.tsx b/services/web/frontend/js/features/source-editor/components/table-generator/table.tsx index e792e95521..d63ea2c843 100644 --- a/services/web/frontend/js/features/source-editor/components/table-generator/table.tsx +++ b/services/web/frontend/js/features/source-editor/components/table-generator/table.tsx @@ -32,6 +32,9 @@ type NavigationMap = { } const isMac = /Mac/.test(window.navigator?.platform) +const MINIMUM_CELL_WIDTH_CHARACTERS = 15 +const MINIMUM_EDITING_CELL_WIDTH_CHARACTERS = 20 +const CELL_WIDTH_BUFFER = 3 // characters export const Table: FC = () => { const { selection, setSelection } = useSelectionContext() @@ -46,6 +49,57 @@ export const Table: FC = () => { const { table: tableData } = useTableContext() const tableRef = useRef(null) const view = useCodeMirrorViewContext() + const cellWidths: number[] = useMemo(() => { + const columns = Array.from( + { length: tableData.columns.length }, + () => MINIMUM_CELL_WIDTH_CHARACTERS + ) + // First pass, calculate the optimal width of each column. For the cell + // we're editing, make sure there's space to write into as well + // (MINIMUM_EDITING_CELL_WIDTH_CHARACTERS) + for (let row = 0; row < tableData.rows.length; ++row) { + for ( + let i = 0; + i < tableData.columns.length; + i += tableData.getCell(row, i).multiColumn?.columnSpan ?? 1 + ) { + const columnSpan = + tableData.getCell(row, i).multiColumn?.columnSpan ?? 1 + let contentLength = + tableData.getCell(row, i).content.length + CELL_WIDTH_BUFFER + if (cellData?.rowIndex === row && cellData?.cellIndex === i) { + contentLength = Math.max( + contentLength, + Math.min( + cellData.content.length + CELL_WIDTH_BUFFER, + MINIMUM_EDITING_CELL_WIDTH_CHARACTERS + ) + ) + } + for (let j = 0; j < columnSpan; ++j) { + columns[i + j] = Math.max(columns[i + j], contentLength / columnSpan) + } + } + } + // Second pass, use a logarithmic scale to not drown out narrow columns + // completely + const total = columns.reduce((a, b) => a + b, 0) + for (let i = 0; i < columns.length; ++i) { + columns[i] = Math.log2(columns[i]) + } + + // Third pass, normalize the columns to the total width of the table + const totalLog = columns.reduce((a, b) => a + b, 0) + for (let i = 0; i < columns.length; ++i) { + columns[i] = Math.round((columns[i] / totalLog) * total) + } + return columns + }, [ + tableData, + cellData?.cellIndex, + cellData?.rowIndex, + cellData?.content.length, + ]) const navigation: NavigationMap = useMemo( () => ({ @@ -267,13 +321,16 @@ export const Table: FC = () => { ref={tableRef} > - {/* A workaround for a chrome bug where it will not respect colspan + {/* A workaround for a chrome bug where it will not respect colspan unless there is a row filled with cells without colspan */} {/* A td for the row selector */} {tableData.columns.map((_, columnIndex) => ( - + ))} diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/table-generator.ts b/services/web/frontend/js/features/source-editor/extensions/visual/table-generator.ts index d95eb0d767..b5ff305364 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/table-generator.ts +++ b/services/web/frontend/js/features/source-editor/extensions/visual/table-generator.ts @@ -119,7 +119,7 @@ export const tableGeneratorTheme = EditorView.baseTheme({ '.table-generator-table': { 'table-layout': 'fixed', - 'max-width': '80%', + 'max-width': '95%', margin: '0 auto', cursor: 'default', @@ -127,7 +127,6 @@ export const tableGeneratorTheme = EditorView.baseTheme({ '&:not(.editing)': { padding: '0 0.25em', }, - 'max-width': '200px', 'vertical-align': 'top', '&.alignment-left': { @@ -281,9 +280,9 @@ export const tableGeneratorTheme = EditorView.baseTheme({ }, '.table-generator-cell-input': { - 'max-width': 'calc(200px - 0.5em)', 'background-color': 'transparent', width: '100%', + 'text-align': 'inherit', height: '1.5em', 'min-height': '100%', border: '1px solid var(--table-generator-toolbar-shadow-color)',