Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions packages/layout-engine/style-engine/src/ooxml/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,92 @@ describe('ooxml - resolveTableCellProperties basedOn tblStylePr inheritance', ()
});
});

// ──────────────────────────────────────────────────────────────────────────────
// Style base-level tcPr as the wholeTable layer (ECMA-376 17.7.6, SD-3035)
// A table style's base-level <w:tcPr><w:shd/></w:tcPr> is stored on the style
// def's own tableCellProperties (sibling of tableStyleProperties) and IS the
// wholeTable conditional layer. Word paints it on every cell.
// ──────────────────────────────────────────────────────────────────────────────

describe('ooxml - style base-level tcPr surfaces as wholeTable (SD-3035)', () => {
const interiorCell = (styleId: string) => ({
tableProperties: { tableStyleId: styleId, tblLook: { noHBand: true, noVBand: true } },
rowIndex: 1,
cellIndex: 1,
numRows: 3,
numCells: 3,
});

it('resolves a base-level shading with no explicit wholeTable region', () => {
const styles = {
...emptyStyles,
styles: {
CondStyle: {
type: 'table',
tableProperties: {},
tableCellProperties: { shading: { val: 'clear', color: 'auto', fill: 'F2F2F2' } },
},
},
};
const result = resolveTableCellProperties(null, interiorCell('CondStyle'), styles);
expect(result.shading).toEqual({ val: 'clear', color: 'auto', fill: 'F2F2F2' });
});

it('leaf base-level shading beats an ancestor base-level shading via basedOn', () => {
const styles = {
...emptyStyles,
styles: {
BaseStyle: {
type: 'table',
tableProperties: {},
tableCellProperties: { shading: { fill: 'AAAAAA' } },
},
LeafStyle: {
type: 'table',
basedOn: 'BaseStyle',
tableProperties: {},
tableCellProperties: { shading: { fill: 'F2F2F2' } },
},
},
};
const result = resolveTableCellProperties(null, interiorCell('LeafStyle'), styles);
expect(result.shading).toEqual({ fill: 'F2F2F2' });
});

it('an explicit tableStyleProperties.wholeTable entry beats the base-level tcPr', () => {
const styles = {
...emptyStyles,
styles: {
CondStyle: {
type: 'table',
tableProperties: {},
tableCellProperties: { shading: { fill: 'BASE99' } },
tableStyleProperties: {
wholeTable: { tableCellProperties: { shading: { fill: 'EXPL77' } } },
},
},
},
};
const result = resolveTableCellProperties(null, interiorCell('CondStyle'), styles);
expect(result.shading).toEqual({ fill: 'EXPL77' });
});

it('inline cell shading still wins over the base-level wholeTable fill', () => {
const styles = {
...emptyStyles,
styles: {
CondStyle: {
type: 'table',
tableProperties: {},
tableCellProperties: { shading: { fill: 'F2F2F2' } },
},
},
};
const result = resolveTableCellProperties({ shading: { fill: '4472C4' } }, interiorCell('CondStyle'), styles);
expect(result.shading).toEqual({ fill: '4472C4' });
});
});

// ──────────────────────────────────────────────────────────────────────────────
// cnfStyle supplementing index-based conditional type detection
// ──────────────────────────────────────────────────────────────────────────────
Expand Down
9 changes: 9 additions & 0 deletions packages/layout-engine/style-engine/src/ooxml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,15 @@ function resolveConditionalProps<T extends PropertyObject>(
const def: StyleDefinition | undefined = translatedLinkedStyles.styles?.[currentId];
const props = def?.tableStyleProperties?.[styleType]?.[propertyType] as T | undefined;
if (props) chain.push(props);
// ECMA-376 17.7.6: a table style's BASE-LEVEL <w:tcPr> (stored on the def's own
// tableCellProperties, a sibling of tableStyleProperties) IS the wholeTable
// conditional layer; Word paints e.g. its w:shd on every cell. Pushed after the
// explicit wholeTable entry so, post-reverse, the explicit entry still wins within
// one def while a leaf's base props beat any ancestor's. (SD-3035)
if (styleType === 'wholeTable' && propertyType === 'tableCellProperties') {
const baseProps = def?.tableCellProperties as T | undefined;
if (baseProps) chain.push(baseProps);
}
currentId = def?.basedOn;
}
if (chain.length === 0) return undefined;
Expand Down
Loading