@@ -34,7 +34,7 @@ import type {
3434 NestedConverters ,
3535 TableNodeToBlockParams ,
3636} from '../types.js' ;
37- import { extractTableBorders , extractCellPadding , convertBorderSpec } from '../attributes/index.js' ;
37+ import { extractTableBorders , extractCellPadding , convertBorderSpec , normalizeShadingColor } from '../attributes/index.js' ;
3838import { pickNumber , twipsToPx } from '../utilities.js' ;
3939import { hydrateTableStyleAttrs } from './table-styles.js' ;
4040import { collectTrackedChangeFromMarks } from '../marks/index.js' ;
@@ -48,7 +48,9 @@ import {
4848 TableProperties ,
4949 resolveTableCellProperties ,
5050 resolveExistingTableEffectiveStyleId ,
51+ type TableInfo ,
5152} from '@superdoc/style-engine/ooxml' ;
53+ import { resolveThemeColorValue } from '../marks/theme-color.js' ;
5254
5355/**
5456 * Normalizes tableCellSpacing from PM node to CellSpacing object format.
@@ -119,6 +121,7 @@ type ParseTableCellArgs = {
119121 context : TableParserDependencies ;
120122 defaultCellPadding ?: BoxSpacing ;
121123 tableProperties ?: TableProperties ;
124+ rowCnfStyle ?: Record < string , unknown > | null ;
122125} ;
123126
124127type ParseTableRowArgs = {
@@ -240,17 +243,23 @@ const parseTableCell = (args: ParseTableCellArgs): TableCell | null => {
240243 // Table cells can contain paragraphs, images/drawings, structured content blocks, and nested tables.
241244 const blocks : ( ParagraphBlock | ImageBlock | DrawingBlock | TableBlock ) [ ] = [ ] ;
242245
246+ // Build tableInfo once with cnfStyle flags and reuse for both cascade and context.
247+ const rowCnfStyle = args . rowCnfStyle ?? null ;
248+ const cellCnfStyle = ( cellNode . attrs ?. tableCellProperties as Record < string , unknown > | undefined ) ?. cnfStyle ?? null ;
249+ const tableInfo : TableInfo | undefined = tableProperties
250+ ? { tableProperties, rowIndex, cellIndex, numCells, numRows, rowCnfStyle, cellCnfStyle }
251+ : undefined ;
252+
243253 // Resolve table cell properties from the style cascade (wholeTable → bands → conditional → inline)
244254 const inlineTcProps = cellNode . attrs ?. tableCellProperties as Record < string , unknown > | undefined ;
245- const tableInfo = tableProperties ? { tableProperties, rowIndex, cellIndex, numCells, numRows } : undefined ;
246255 const resolvedTcProps = resolveTableCellProperties (
247256 inlineTcProps as Parameters < typeof resolveTableCellProperties > [ 0 ] ,
248257 tableInfo ,
249258 context . converterContext ?. translatedLinkedStyles ,
250259 ) ;
251260
252261 // Extract cell background color for auto text color resolution
253- // Priority: inline background attr > resolved style shading
262+ // Priority: inline background attr > literal fill > theme fill
254263 const cellBackground = cellNode . attrs ?. background as { color ?: string } | undefined ;
255264 let cellBackgroundColor : string | undefined ;
256265 if ( cellBackground && typeof cellBackground . color === 'string' ) {
@@ -264,21 +273,28 @@ const parseTableCell = (args: ParseTableCellArgs): TableCell | null => {
264273 }
265274 }
266275 // Fall back to resolved style shading if no inline background
267- if ( ! cellBackgroundColor && resolvedTcProps ?. shading ?. fill ) {
268- const fill = resolvedTcProps . shading . fill ;
269- if ( fill !== 'auto' ) {
270- cellBackgroundColor = fill . startsWith ( '#' ) ? fill : `#${ fill } ` ;
276+ if ( ! cellBackgroundColor && resolvedTcProps ?. shading ) {
277+ const { fill, themeFill, themeFillTint, themeFillShade } = resolvedTcProps . shading ;
278+ const normalizedFill = normalizeShadingColor ( fill ) ;
279+ if ( normalizedFill ) {
280+ cellBackgroundColor = normalizedFill ;
281+ } else if ( themeFill && context . themeColors ) {
282+ const resolved = resolveThemeColorValue ( themeFill , themeFillTint , themeFillShade , context . themeColors ) ;
283+ const normalizedTheme = normalizeShadingColor ( resolved ) ;
284+ if ( normalizedTheme ) {
285+ cellBackgroundColor = normalizedTheme ;
286+ }
271287 }
272288 }
273289
274290 // Create enhanced converter context with table style paragraph props for the style cascade
275291 // This allows paragraphs inside table cells to inherit table style's pPr
276292 // Also includes backgroundColor for auto text color resolution
277293 const cellConverterContext : ConverterContext =
278- tableProperties || cellBackgroundColor
294+ tableInfo || cellBackgroundColor
279295 ? ( {
280296 ...context . converterContext ,
281- ...( tableProperties && { tableInfo : { tableProperties , rowIndex , cellIndex , numCells , numRows } } ) ,
297+ ...( tableInfo && { tableInfo } ) ,
282298 ...( cellBackgroundColor && { backgroundColor : cellBackgroundColor } ) ,
283299 } as ConverterContext )
284300 : context . converterContext ;
@@ -585,6 +601,9 @@ const parseTableRow = (args: ParseTableRowArgs): TableRow | null => {
585601 }
586602
587603 const cells : TableCell [ ] = [ ] ;
604+ const rowCnfStyle = ( rowNode . attrs ?. tableRowProperties as Record < string , unknown > | undefined ) ?. cnfStyle as
605+ | Record < string , unknown >
606+ | undefined ;
588607 rowNode . content . forEach ( ( cellNode , cellIndex ) => {
589608 const parsedCell = parseTableCell ( {
590609 cellNode,
@@ -595,6 +614,7 @@ const parseTableRow = (args: ParseTableRowArgs): TableRow | null => {
595614 tableProperties,
596615 numCells : rowNode ?. content ?. length || 1 ,
597616 numRows,
617+ rowCnfStyle,
598618 } ) ;
599619 if ( parsedCell ) {
600620 cells . push ( parsedCell ) ;
0 commit comments