diff --git a/packages/roosterjs-content-model/lib/formatHandlers/common/widthFormatHandler.ts b/packages/roosterjs-content-model/lib/formatHandlers/common/widthFormatHandler.ts new file mode 100644 index 00000000000..4d0528bf8ff --- /dev/null +++ b/packages/roosterjs-content-model/lib/formatHandlers/common/widthFormatHandler.ts @@ -0,0 +1,20 @@ +import { FormatHandler } from '../FormatHandler'; +import { WidthFormat } from '../../publicTypes/format/formatParts/WidthFormat'; + +/** + * @internal + */ +export const widthFormatHandler: FormatHandler = { + parse: (format, element, _, defaultStyle) => { + const width = element.style.width || defaultStyle.width; + + if (width) { + format.width = width; + } + }, + apply: (format, element) => { + if (format.width) { + element.style.width = format.width; + } + }, +}; diff --git a/packages/roosterjs-content-model/lib/formatHandlers/defaultFormatHandlers.ts b/packages/roosterjs-content-model/lib/formatHandlers/defaultFormatHandlers.ts index 718b7f342c1..3a170037d02 100644 --- a/packages/roosterjs-content-model/lib/formatHandlers/defaultFormatHandlers.ts +++ b/packages/roosterjs-content-model/lib/formatHandlers/defaultFormatHandlers.ts @@ -36,6 +36,7 @@ import { textColorOnTableCellFormatHandler } from './table/textColorOnTableCellF import { underlineFormatHandler } from './segment/underlineFormatHandler'; import { verticalAlignFormatHandler } from './common/verticalAlignFormatHandler'; import { whiteSpaceFormatHandler } from './block/whiteSpaceFormatHandler'; +import { widthFormatHandler } from './common/widthFormatHandler'; import { wordBreakFormatHandler } from './common/wordBreakFormatHandler'; import { FormatApplier, @@ -88,6 +89,7 @@ const defaultFormatHandlerMap: FormatHandlers = { verticalAlign: verticalAlignFormatHandler, whiteSpace: whiteSpaceFormatHandler, wordBreak: wordBreakFormatHandler, + width: widthFormatHandler, }; const sharedSegmentFormats: (keyof FormatHandlerTypeMap)[] = [ @@ -142,7 +144,7 @@ const defaultFormatKeysPerCategory: { 'htmlAlign', ], tableRow: ['backgroundColor'], - table: ['id', 'border', 'backgroundColor', 'display', 'htmlAlign', 'margin'], + table: ['id', 'border', 'backgroundColor', 'display', 'htmlAlign', 'margin', 'width'], tableBorder: ['borderBox', 'tableSpacing'], tableCellBorder: ['borderBox'], image: ['id', 'size', 'margin', 'padding', 'borderBox', 'border', 'boxShadow', 'display'], diff --git a/packages/roosterjs-content-model/lib/publicTypes/format/ContentModelTableFormat.ts b/packages/roosterjs-content-model/lib/publicTypes/format/ContentModelTableFormat.ts index cf39c042149..173efff5d9a 100644 --- a/packages/roosterjs-content-model/lib/publicTypes/format/ContentModelTableFormat.ts +++ b/packages/roosterjs-content-model/lib/publicTypes/format/ContentModelTableFormat.ts @@ -5,6 +5,7 @@ import { DisplayFormat } from './formatParts/DisplayFormat'; import { IdFormat } from './formatParts/IdFormat'; import { MarginFormat } from './formatParts/MarginFormat'; import { SpacingFormat } from './formatParts/SpacingFormat'; +import { WidthFormat } from './formatParts/WidthFormat'; /** * Format of Table @@ -15,4 +16,5 @@ export type ContentModelTableFormat = ContentModelBlockFormat & BorderBoxFormat & SpacingFormat & MarginFormat & - DisplayFormat; + DisplayFormat & + WidthFormat; diff --git a/packages/roosterjs-content-model/lib/publicTypes/format/FormatHandlerTypeMap.ts b/packages/roosterjs-content-model/lib/publicTypes/format/FormatHandlerTypeMap.ts index 5a17d98f578..0cac151bf27 100644 --- a/packages/roosterjs-content-model/lib/publicTypes/format/FormatHandlerTypeMap.ts +++ b/packages/roosterjs-content-model/lib/publicTypes/format/FormatHandlerTypeMap.ts @@ -29,6 +29,7 @@ import { TextColorFormat } from './formatParts/TextColorFormat'; import { UnderlineFormat } from './formatParts/UnderlineFormat'; import { VerticalAlignFormat } from './formatParts/VerticalAlignFormat'; import { WhiteSpaceFormat } from './formatParts/WhiteSpaceFormat'; +import { WidthFormat } from './formatParts/WidthFormat'; import { WordBreakFormat } from './formatParts/WordBreakFormat'; /** @@ -209,6 +210,11 @@ export interface FormatHandlerTypeMap { * Format for WordBreakFormat */ wordBreak: WordBreakFormat; + + /** + * Format for Width + */ + width: WidthFormat; } /** diff --git a/packages/roosterjs-content-model/lib/publicTypes/format/formatParts/WidthFormat.ts b/packages/roosterjs-content-model/lib/publicTypes/format/formatParts/WidthFormat.ts new file mode 100644 index 00000000000..7d92e1d86dc --- /dev/null +++ b/packages/roosterjs-content-model/lib/publicTypes/format/formatParts/WidthFormat.ts @@ -0,0 +1,9 @@ +/** + * Format of width + */ +export type WidthFormat = { + /** + * Width CSS value + */ + width?: string; +}; diff --git a/packages/roosterjs-content-model/test/formatHandlers/common/widthFormatHandlerTest.ts b/packages/roosterjs-content-model/test/formatHandlers/common/widthFormatHandlerTest.ts new file mode 100644 index 00000000000..b89980d7f91 --- /dev/null +++ b/packages/roosterjs-content-model/test/formatHandlers/common/widthFormatHandlerTest.ts @@ -0,0 +1,52 @@ +import { createDomToModelContext } from '../../../lib/domToModel/context/createDomToModelContext'; +import { createModelToDomContext } from '../../../lib/modelToDom/context/createModelToDomContext'; +import { DomToModelContext } from '../../../lib/publicTypes/context/DomToModelContext'; +import { ModelToDomContext } from '../../../lib/publicTypes/context/ModelToDomContext'; +import { WidthFormat } from '../../../lib/publicTypes/format/formatParts/WidthFormat'; +import { widthFormatHandler } from '../../../lib/formatHandlers/common/widthFormatHandler'; + +describe('widthFormatHandler.parse', () => { + let div: HTMLElement; + let format: WidthFormat; + let context: DomToModelContext; + + beforeEach(() => { + div = document.createElement('div'); + format = {}; + context = createDomToModelContext(); + }); + + it('No word break', () => { + widthFormatHandler.parse(format, div, context, {}); + expect(format).toEqual({}); + }); + + it('Has word break', () => { + div.style.width = '100pt'; + widthFormatHandler.parse(format, div, context, {}); + expect(format).toEqual({ width: '100pt' }); + }); +}); + +describe('wordBreakFormatHandler.apply', () => { + let div: HTMLElement; + let format: WidthFormat; + let context: ModelToDomContext; + + beforeEach(() => { + div = document.createElement('div'); + format = {}; + context = createModelToDomContext(); + }); + + it('No word break', () => { + widthFormatHandler.apply(format, div, context); + expect(div.outerHTML).toBe('
'); + }); + + it('Has word-break', () => { + format.width = '100pt'; + widthFormatHandler.apply(format, div, context); + expect(div.outerHTML).toBe('
'); + }); +});