Просмотр исходного кода

Merge pull request #14596 from overleaf/mj-manual-cell-widths

[visual] Manually calculate column widths in table generator

GitOrigin-RevId: ce42219098d56cca2fbdb1bef6ad33a11d79fb25
Mathias Jakobsen 2 лет назад
Родитель
Сommit
c8413c6cc6

+ 59 - 2
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<HTMLTableElement>(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}
     >
       <thead>
-        {/* 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 */}
         <tr className="table-generator-filler-row">
           {/* A td for the row selector */}
           <td />
           {tableData.columns.map((_, columnIndex) => (
-            <td key={columnIndex} />
+            <td
+              key={columnIndex}
+              style={{ width: `${cellWidths[columnIndex]}ch` }}
+            />
           ))}
         </tr>
         <tr>

+ 2 - 3
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)',