diff --git a/packages/roosterjs-content-model-api/lib/publicApi/table/setTableCellShade.ts b/packages/roosterjs-content-model-api/lib/publicApi/table/setTableCellShade.ts index fc00545ece3..12f52e26381 100644 --- a/packages/roosterjs-content-model-api/lib/publicApi/table/setTableCellShade.ts +++ b/packages/roosterjs-content-model-api/lib/publicApi/table/setTableCellShade.ts @@ -1,7 +1,6 @@ import { hasSelectionInBlockGroup, getFirstSelectedTable, - normalizeTable, setTableCellBackgroundColor, } from 'roosterjs-content-model-dom'; import type { IEditor } from 'roosterjs-content-model-types'; @@ -19,8 +18,6 @@ export function setTableCellShade(editor: IEditor, color: string | null) { const [table] = getFirstSelectedTable(model); if (table) { - normalizeTable(table); - table.rows.forEach(row => row.cells.forEach(cell => { if (hasSelectionInBlockGroup(cell)) { diff --git a/packages/roosterjs-content-model-dom/lib/modelApi/editing/applyTableFormat.ts b/packages/roosterjs-content-model-dom/lib/modelApi/editing/applyTableFormat.ts index f7e9065a775..942a638fe91 100644 --- a/packages/roosterjs-content-model-dom/lib/modelApi/editing/applyTableFormat.ts +++ b/packages/roosterjs-content-model-dom/lib/modelApi/editing/applyTableFormat.ts @@ -208,7 +208,7 @@ function formatCells( // Format Background Color if (!metaOverrides.bgColorOverrides[rowIndex][colIndex]) { let color: string | null | undefined; - if (hasFirstColumn && colIndex == 0) { + if (hasFirstColumn && colIndex == 0 && rowIndex > 0) { color = null; } else { color = @@ -239,7 +239,7 @@ function formatCells( } /** - * Set the first column format borders for the table + * Set the first column format borders for the table as well as header property * @param rows The rows of the table * @param format The table metadata format */ @@ -261,13 +261,14 @@ export function setFirstColumnFormatBorders( switch (rowIndex) { case 0: - break; - case 1: - setBorderColor(cell.format, 'borderBottom'); + cell.isHeader = !!format.hasHeaderRow; break; case rows.length - 1: setBorderColor(cell.format, 'borderTop'); break; + case 1: + setBorderColor(cell.format, 'borderBottom'); + break; default: setBorderColor(cell.format, 'borderTop'); setBorderColor(cell.format, 'borderBottom'); diff --git a/packages/roosterjs-content-model-dom/lib/modelApi/editing/normalizeTable.ts b/packages/roosterjs-content-model-dom/lib/modelApi/editing/normalizeTable.ts index 76a57ab0bcf..1760a8c7d87 100644 --- a/packages/roosterjs-content-model-dom/lib/modelApi/editing/normalizeTable.ts +++ b/packages/roosterjs-content-model-dom/lib/modelApi/editing/normalizeTable.ts @@ -19,7 +19,7 @@ const MIN_HEIGHT = 22; /** * Normalize a Content Model table, make sure: * 1. Fist cells are not spanned - * 2. Inner cells are not header + * 2. Only first column and row can have headers * 3. All cells have content and width * 4. Table and table row have correct width/height * 5. Spanned cell has no child blocks @@ -64,7 +64,7 @@ export function normalizeTable( if (rowIndex == 0) { cell.spanAbove = false; - } else if (rowIndex > 0 && cell.isHeader) { + } else if (rowIndex > 0 && colIndex > 0 && cell.isHeader) { cell.isHeader = false; delete cell.cachedElement; } diff --git a/packages/roosterjs-content-model-dom/test/modelApi/editing/normalizeTableTest.ts b/packages/roosterjs-content-model-dom/test/modelApi/editing/normalizeTableTest.ts index 50187d7548b..3b5009f827a 100644 --- a/packages/roosterjs-content-model-dom/test/modelApi/editing/normalizeTableTest.ts +++ b/packages/roosterjs-content-model-dom/test/modelApi/editing/normalizeTableTest.ts @@ -159,7 +159,7 @@ describe('normalizeTable', () => { blockGroupType: 'TableCell', spanLeft: false, spanAbove: false, - isHeader: false, + isHeader: true, format: { useBorderBox: true }, blocks: [ { @@ -183,6 +183,133 @@ describe('normalizeTable', () => { }); }); + it('Normalize a table with only TH', () => { + const table = createTable(2); + + table.rows[0].cells.push(createTableCell(1, 1, true)); + table.rows[0].cells.push(createTableCell(1, 1, true)); + table.rows[1].cells.push(createTableCell(1, 1, true)); + table.rows[1].cells.push(createTableCell(1, 1, true)); + + table.widths = [100, 100]; + table.rows[0].height = 200; + table.rows[1].height = 200; + + normalizeTable(table); + + expect(table).toEqual({ + blockType: 'Table', + rows: [ + { + height: 200, + format: {}, + cells: [ + { + blockGroupType: 'TableCell', + blocks: [ + { + blockType: 'Paragraph', + segments: [ + { + segmentType: 'Br', + format: {}, + }, + ], + format: {}, + }, + ], + format: { + useBorderBox: true, + }, + spanLeft: false, + spanAbove: false, + isHeader: true, + dataset: {}, + }, + { + blockGroupType: 'TableCell', + blocks: [ + { + blockType: 'Paragraph', + segments: [ + { + segmentType: 'Br', + format: {}, + }, + ], + format: {}, + }, + ], + format: { + useBorderBox: true, + }, + spanLeft: false, + spanAbove: false, + isHeader: true, + dataset: {}, + }, + ], + }, + { + height: 200, + format: {}, + cells: [ + { + blockGroupType: 'TableCell', + blocks: [ + { + blockType: 'Paragraph', + segments: [ + { + segmentType: 'Br', + format: {}, + }, + ], + format: {}, + }, + ], + format: { + useBorderBox: true, + }, + spanLeft: false, + spanAbove: false, + isHeader: true, + dataset: {}, + }, + { + blockGroupType: 'TableCell', + blocks: [ + { + blockType: 'Paragraph', + segments: [ + { + segmentType: 'Br', + format: {}, + }, + ], + format: {}, + }, + ], + format: { + useBorderBox: true, + }, + spanLeft: false, + spanAbove: false, + isHeader: false, + dataset: {}, + }, + ], + }, + ], + format: { + borderCollapse: true, + useBorderBox: true, + }, + widths: [100, 100], + dataset: {}, + }); + }); + it('Normalize a table with left-spanned cells', () => { const table = createTable(1);