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

[visual] Manually calculate column widths in table generator

GitOrigin-RevId: ce42219098d56cca2fbdb1bef6ad33a11d79fb25
This commit is contained in:
Mathias Jakobsen 2023-09-04 09:03:01 +01:00 committed by Copybot
parent 2516f271b1
commit c8413c6cc6
2 changed files with 61 additions and 5 deletions

View file

@ -32,6 +32,9 @@ type NavigationMap = {
} }
const isMac = /Mac/.test(window.navigator?.platform) 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 = () => { export const Table: FC = () => {
const { selection, setSelection } = useSelectionContext() const { selection, setSelection } = useSelectionContext()
@ -46,6 +49,57 @@ export const Table: FC = () => {
const { table: tableData } = useTableContext() const { table: tableData } = useTableContext()
const tableRef = useRef<HTMLTableElement>(null) const tableRef = useRef<HTMLTableElement>(null)
const view = useCodeMirrorViewContext() 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( const navigation: NavigationMap = useMemo(
() => ({ () => ({
@ -267,13 +321,16 @@ export const Table: FC = () => {
ref={tableRef} ref={tableRef}
> >
<thead> <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 */} unless there is a row filled with cells without colspan */}
<tr className="table-generator-filler-row"> <tr className="table-generator-filler-row">
{/* A td for the row selector */} {/* A td for the row selector */}
<td /> <td />
{tableData.columns.map((_, columnIndex) => ( {tableData.columns.map((_, columnIndex) => (
<td key={columnIndex} /> <td
key={columnIndex}
style={{ width: `${cellWidths[columnIndex]}ch` }}
/>
))} ))}
</tr> </tr>
<tr> <tr>

View file

@ -119,7 +119,7 @@ export const tableGeneratorTheme = EditorView.baseTheme({
'.table-generator-table': { '.table-generator-table': {
'table-layout': 'fixed', 'table-layout': 'fixed',
'max-width': '80%', 'max-width': '95%',
margin: '0 auto', margin: '0 auto',
cursor: 'default', cursor: 'default',
@ -127,7 +127,6 @@ export const tableGeneratorTheme = EditorView.baseTheme({
'&:not(.editing)': { '&:not(.editing)': {
padding: '0 0.25em', padding: '0 0.25em',
}, },
'max-width': '200px',
'vertical-align': 'top', 'vertical-align': 'top',
'&.alignment-left': { '&.alignment-left': {
@ -281,9 +280,9 @@ export const tableGeneratorTheme = EditorView.baseTheme({
}, },
'.table-generator-cell-input': { '.table-generator-cell-input': {
'max-width': 'calc(200px - 0.5em)',
'background-color': 'transparent', 'background-color': 'transparent',
width: '100%', width: '100%',
'text-align': 'inherit',
height: '1.5em', height: '1.5em',
'min-height': '100%', 'min-height': '100%',
border: '1px solid var(--table-generator-toolbar-shadow-color)', border: '1px solid var(--table-generator-toolbar-shadow-color)',