diff --git a/packages/roosterjs-content-model-dom/lib/config/defaultContentModelFormatMap.ts b/packages/roosterjs-content-model-dom/lib/config/defaultContentModelFormatMap.ts index 4576d1bc708..b686d5144cf 100644 --- a/packages/roosterjs-content-model-dom/lib/config/defaultContentModelFormatMap.ts +++ b/packages/roosterjs-content-model-dom/lib/config/defaultContentModelFormatMap.ts @@ -52,4 +52,7 @@ export const defaultContentModelFormatMap: DefaultImplicitFormatMap = { marginTop: '1em', marginBottom: '1em', }, + th: { + fontWeight: 'bold', + }, }; diff --git a/packages/roosterjs-content-model-dom/lib/config/defaultHTMLStyleMap.ts b/packages/roosterjs-content-model-dom/lib/config/defaultHTMLStyleMap.ts index 5ee760791ee..f8d911cf198 100644 --- a/packages/roosterjs-content-model-dom/lib/config/defaultHTMLStyleMap.ts +++ b/packages/roosterjs-content-model-dom/lib/config/defaultHTMLStyleMap.ts @@ -117,6 +117,7 @@ export const defaultHTMLStyleMap: DefaultStyleMap = { }, th: { display: 'table-cell', + fontWeight: 'bold', }, u: { textDecoration: 'underline', 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 942a638fe91..25d1ea35c3f 100644 --- a/packages/roosterjs-content-model-dom/lib/modelApi/editing/applyTableFormat.ts +++ b/packages/roosterjs-content-model-dom/lib/modelApi/editing/applyTableFormat.ts @@ -262,6 +262,10 @@ export function setFirstColumnFormatBorders( switch (rowIndex) { case 0: cell.isHeader = !!format.hasHeaderRow; + + if (cell.isHeader) { + cell.format.fontWeight = 'bold'; + } break; case rows.length - 1: setBorderColor(cell.format, 'borderTop'); @@ -295,6 +299,7 @@ function setHeaderRowFormat( const cell = mutateBlock(readonlyCell); cell.isHeader = true; + cell.format.fontWeight = 'bold'; if (format.headerRowColor) { if (!metaOverrides.bgColorOverrides[rowIndex][cellIndex]) { diff --git a/packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleTable.ts b/packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleTable.ts index 5f564971b79..2f183cf580b 100644 --- a/packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleTable.ts +++ b/packages/roosterjs-content-model-dom/lib/modelToDom/handlers/handleTable.ts @@ -3,6 +3,7 @@ import { hasMetadata } from '../../modelApi/metadata/updateMetadata'; import { isBlockEmpty } from '../../modelApi/common/isEmpty'; import { moveChildNodes } from '../../domUtils/moveChildNodes'; import { reuseCachedElement } from '../../domUtils/reuseCachedElement'; +import { stackFormat } from '../utils/stackFormat'; import type { ContentModelBlockHandler, ContentModelTable, @@ -96,9 +97,9 @@ export const handleTable: ContentModelBlockHandler = ( } if (!cell.spanAbove && !cell.spanLeft) { + const tag = cell.isHeader ? 'th' : 'td'; const td = - (context.allowCacheElement && cell.cachedElement) || - doc.createElement(cell.isHeader ? 'th' : 'td'); + (context.allowCacheElement && cell.cachedElement) || doc.createElement(tag); tr.appendChild(td); @@ -132,18 +133,25 @@ export const handleTable: ContentModelBlockHandler = ( } } - if (!cell.cachedElement) { - if (context.allowCacheElement) { - cell.cachedElement = td; + stackFormat(context, tag, () => { + if (!cell.cachedElement) { + if (context.allowCacheElement) { + cell.cachedElement = td; + } + + applyFormat(td, context.formatAppliers.block, cell.format, context); + applyFormat(td, context.formatAppliers.tableCell, cell.format, context); + applyFormat( + td, + context.formatAppliers.tableCellBorder, + cell.format, + context + ); + applyFormat(td, context.formatAppliers.dataset, cell.dataset, context); } - applyFormat(td, context.formatAppliers.block, cell.format, context); - applyFormat(td, context.formatAppliers.tableCell, cell.format, context); - applyFormat(td, context.formatAppliers.tableCellBorder, cell.format, context); - applyFormat(td, context.formatAppliers.dataset, cell.dataset, context); - } - - context.modelHandlers.blockGroupChildren(doc, td, cell, context); + context.modelHandlers.blockGroupChildren(doc, td, cell, context); + }); context.onNodeCreated?.(cell, td); } diff --git a/packages/roosterjs-content-model-dom/test/endToEndTest.ts b/packages/roosterjs-content-model-dom/test/endToEndTest.ts index 1313bb9918e..3d07f2a9972 100644 --- a/packages/roosterjs-content-model-dom/test/endToEndTest.ts +++ b/packages/roosterjs-content-model-dom/test/endToEndTest.ts @@ -2226,4 +2226,157 @@ describe('End to end test for DOM => Model => DOM/TEXT', () => { '
test
' ); }); + + it('TH without font-weight', () => { + runTest( + '
test
', + { + blockGroupType: 'Document', + blocks: [ + { + widths: [], + rows: [ + { + height: 0, + cells: [ + { + spanAbove: false, + spanLeft: false, + isHeader: true, + blockGroupType: 'TableCell', + blocks: [ + { + isImplicit: true, + segments: [ + { + text: 'test', + segmentType: 'Text', + format: { + fontWeight: 'bold', + }, + }, + ], + blockType: 'Paragraph', + format: {}, + }, + ], + format: {}, + dataset: {}, + }, + ], + format: {}, + }, + ], + blockType: 'Table', + format: {}, + dataset: {}, + }, + ], + }, + 'test', + '
test
' + ); + }); + + it('TH with font-weight: 400', () => { + runTest( + '
test
', + { + blockGroupType: 'Document', + blocks: [ + { + widths: [], + rows: [ + { + height: 0, + cells: [ + { + spanAbove: false, + spanLeft: false, + isHeader: true, + blockGroupType: 'TableCell', + blocks: [ + { + isImplicit: true, + segments: [ + { + text: 'test', + segmentType: 'Text', + format: { + fontWeight: '400', + }, + }, + ], + blockType: 'Paragraph', + format: {}, + }, + ], + format: {}, + dataset: {}, + }, + ], + format: {}, + }, + ], + blockType: 'Table', + format: {}, + dataset: {}, + }, + ], + }, + 'test', + '
test
' + ); + }); + + it('TH with font-weight: bold', () => { + runTest( + '
test
', + { + blockGroupType: 'Document', + blocks: [ + { + widths: [], + rows: [ + { + height: 0, + cells: [ + { + spanAbove: false, + spanLeft: false, + isHeader: true, + blockGroupType: 'TableCell', + blocks: [ + { + isImplicit: true, + segments: [ + { + text: 'test', + segmentType: 'Text', + format: { + fontWeight: 'bold', + }, + }, + ], + blockType: 'Paragraph', + format: {}, + }, + ], + format: {}, + dataset: {}, + }, + ], + format: {}, + }, + ], + blockType: 'Table', + format: {}, + dataset: {}, + }, + ], + }, + 'test', + '
test
' + ); + }); }); diff --git a/packages/roosterjs-content-model-types/lib/contentModel/format/ContentModelTableCellFormat.ts b/packages/roosterjs-content-model-types/lib/contentModel/format/ContentModelTableCellFormat.ts index 651535c95f0..3640a14efe0 100644 --- a/packages/roosterjs-content-model-types/lib/contentModel/format/ContentModelTableCellFormat.ts +++ b/packages/roosterjs-content-model-types/lib/contentModel/format/ContentModelTableCellFormat.ts @@ -1,3 +1,4 @@ +import type { BoldFormat } from './formatParts/BoldFormat'; import type { BorderBoxFormat } from './formatParts/BorderBoxFormat'; import type { ContentModelBlockFormat } from './ContentModelBlockFormat'; import type { SizeFormat } from './formatParts/SizeFormat'; @@ -13,4 +14,5 @@ export type ContentModelTableCellFormat = ContentModelBlockFormat & VerticalAlignFormat & WordBreakFormat & TextColorFormat & - SizeFormat; + SizeFormat & + BoldFormat;