Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@ export function retrieveModelFormatState(
);

if (formatState.fontSize) {
const fontSize = formatState.fontSize;

// If the font size is a relative value (e.g. 1.5em from an h2 default style), resolve it
// against the container's computed font size so that the format state always returns an
// absolute value that reflects the actual rendered size.
if (
(fontSize.endsWith('em') && !fontSize.endsWith('rem')) ||
fontSize.endsWith('%')
) {
if (!containerFormat) {
containerFormat =
domHelper?.getContainerFormat(isInDarkMode, colorHandler) ?? modelFormat;
}

const containerFontSizePx = parseValueWithUnit(containerFormat?.fontSize ?? '');

if (containerFontSizePx > 0) {
const resolvedPx = parseValueWithUnit(fontSize, containerFontSizePx);

if (resolvedPx > 0) {
formatState.fontSize = resolvedPx + 'px';
}
}
}

formatState.fontSize = px2Pt(formatState.fontSize);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,90 @@ describe('retrieveModelFormatState', () => {
});
});

it('Single selection with heading and em font size from decorator, with domHelper', () => {
const model = createContentModelDocument();
const result: ContentModelFormatState = {};
// Simulate h2 decorator format with a relative em-based font size (default browser style for h2)
const para = createParagraph(false, undefined, undefined, {
format: { fontSize: '1.5em', fontWeight: 'bold' },
tagName: 'h2',
});
// Segment has no explicit fontSize override
const marker = createSelectionMarker({
fontFamily: 'Arial',
textColor: 'green',
});

spyOn(iterateSelections, 'iterateSelections').and.callFake((path: any, callback) => {
callback([path], undefined, para, [marker]);
return false;
});

const domHelper: DOMHelper = {
getContainerFormat: () => ({ fontFamily: 'Arial', fontSize: '16px', textColor: 'green' }),
} as any;

retrieveModelFormatState(model, null, result, 'remove', domHelper);

// 1.5em * 16px = 24px = 18pt
expect(result.fontSize).toBe('18pt');
expect(result.headingLevel).toBe(2);
});

it('Single selection with heading and em font size from decorator, without domHelper', () => {
const model = createContentModelDocument();
const result: ContentModelFormatState = {};
// Simulate h2 decorator format with a relative em-based font size
const para = createParagraph(false, undefined, undefined, {
format: { fontSize: '1.5em', fontWeight: 'bold' },
tagName: 'h2',
});
// Segment has no explicit fontSize override
const marker = createSelectionMarker({
fontFamily: 'Arial',
textColor: 'green',
});

spyOn(iterateSelections, 'iterateSelections').and.callFake((path: any, callback) => {
callback([path], undefined, para, [marker]);
return false;
});

// No domHelper - relative font size cannot be resolved, should remain as-is
retrieveModelFormatState(model, null, result);

expect(result.fontSize).toBe('1.5em');
expect(result.headingLevel).toBe(2);
});

it('Single selection with heading and percentage font size from decorator, with domHelper', () => {
const model = createContentModelDocument();
const result: ContentModelFormatState = {};
const para = createParagraph(false, undefined, undefined, {
format: { fontSize: '150%', fontWeight: 'bold' },
tagName: 'h2',
});
const marker = createSelectionMarker({
fontFamily: 'Arial',
textColor: 'green',
});

spyOn(iterateSelections, 'iterateSelections').and.callFake((path: any, callback) => {
callback([path], undefined, para, [marker]);
return false;
});

const domHelper: DOMHelper = {
getContainerFormat: () => ({ fontFamily: 'Arial', fontSize: '16px', textColor: 'green' }),
} as any;

retrieveModelFormatState(model, null, result, 'remove', domHelper);

// 150% * 16px = 24px = 18pt
expect(result.fontSize).toBe('18pt');
expect(result.headingLevel).toBe(2);
});

it('Single selection with margin format', () => {
const model = createContentModelDocument();
const result: ContentModelFormatState = {};
Expand Down