mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 17:13:38 -05:00
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:
parent
2516f271b1
commit
c8413c6cc6
2 changed files with 61 additions and 5 deletions
|
@ -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>
|
||||||
|
|
|
@ -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)',
|
||||||
|
|
Loading…
Reference in a new issue