diff --git a/demo/scripts/controlsV2/mainPane/MainPane.tsx b/demo/scripts/controlsV2/mainPane/MainPane.tsx index 1527cd9a55d7..e8a3945195a0 100644 --- a/demo/scripts/controlsV2/mainPane/MainPane.tsx +++ b/demo/scripts/controlsV2/mainPane/MainPane.tsx @@ -630,6 +630,7 @@ const AnnounceStringMap: Record = { announceUnderlineOff: 'Underline Off', selected: '{0}, selected', unselected: '{0}, unselected', + newLineInserted: 'New line', }; function getAnnouncingString(key: KnownAnnounceStrings) { diff --git a/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnParagraph.ts b/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnParagraph.ts index be052bf1e2e4..9b56d93f7309 100644 --- a/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnParagraph.ts +++ b/packages/roosterjs-content-model-plugins/lib/edit/inputSteps/handleEnterOnParagraph.ts @@ -23,5 +23,10 @@ export const handleEnterOnParagraph: ( context.deleteResult = 'range'; context.lastParagraph = newPara; context.insertPoint.paragraph = newPara; + if (context.formatContext) { + context.formatContext.announceData = { + defaultStrings: 'newLineInserted', + }; + } } }; diff --git a/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnParagraphTest.ts b/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnParagraphTest.ts index a2952a391ef6..5cccad88730c 100644 --- a/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnParagraphTest.ts +++ b/packages/roosterjs-content-model-plugins/test/edit/inputSteps/handleEnterOnParagraphTest.ts @@ -1,5 +1,8 @@ import { handleEnterOnParagraph } from '../../../lib/edit/inputSteps/handleEnterOnParagraph'; -import { ValidDeleteSelectionContext } from 'roosterjs-content-model-types'; +import { + FormatContentModelContext, + ValidDeleteSelectionContext, +} from 'roosterjs-content-model-types'; import { createContentModelDocument, createParagraph, @@ -43,6 +46,11 @@ describe('handleEnterOnParagraph', () => { const mockedCache = {} as any; const text1 = createText('test1'); const text2 = createText('test1'); + const formatContext: FormatContentModelContext = { + newEntities: [], + deletedEntities: [], + newImages: [], + }; para.segments.push(text1, marker, text2); doc.blocks.push(para); @@ -55,6 +63,7 @@ describe('handleEnterOnParagraph', () => { marker: marker, path: [doc], }, + formatContext, }; handleEnterOnParagraph([])(context); @@ -98,6 +107,9 @@ describe('handleEnterOnParagraph', () => { marker: marker, path: [doc], }); + expect(formatContext.announceData).toEqual({ + defaultStrings: 'newLineInserted', + }); }); it('Not deleted, split current paragraph with id', () => { diff --git a/packages/roosterjs-content-model-types/lib/parameter/AnnounceData.ts b/packages/roosterjs-content-model-types/lib/parameter/AnnounceData.ts index abf1af172d35..8cfdf9c31207 100644 --- a/packages/roosterjs-content-model-types/lib/parameter/AnnounceData.ts +++ b/packages/roosterjs-content-model-types/lib/parameter/AnnounceData.ts @@ -65,7 +65,15 @@ export type KnownAnnounceStrings = * @example * {0}, unselected */ - | 'unselected'; + | 'unselected' + + /** + * String announced when a new line is inserted in the editor. + * Used when Enter is pressed and a new line is inserted in the editor. + * @example + * New line inserted + */ + | 'newLineInserted'; /** * Represents data, that can be used to announce text to screen reader. diff --git a/packages/roosterjs-editor-adapter/lib/editor/utils/eventConverter.ts b/packages/roosterjs-editor-adapter/lib/editor/utils/eventConverter.ts index 052d4808813f..03e91006f24f 100644 --- a/packages/roosterjs-editor-adapter/lib/editor/utils/eventConverter.ts +++ b/packages/roosterjs-editor-adapter/lib/editor/utils/eventConverter.ts @@ -61,6 +61,7 @@ const KnownAnnounceStringsNewToOld: Record< announceUnderlineOff: undefined, selected: undefined, unselected: undefined, + newLineInserted: undefined, }; const EntityOperationOldToNew: Record = { diff --git a/packages/roosterjs-editor-adapter/test/editor/utils/eventConverterTest.ts b/packages/roosterjs-editor-adapter/test/editor/utils/eventConverterTest.ts index 816e66cee395..9b921bfcf1c2 100644 --- a/packages/roosterjs-editor-adapter/test/editor/utils/eventConverterTest.ts +++ b/packages/roosterjs-editor-adapter/test/editor/utils/eventConverterTest.ts @@ -873,6 +873,34 @@ describe('newEventToOldEvent', () => { expect(result.additionalData!.getEntityState!()).toEqual(mockedEntityState); }); + it('ContentChanged with unsupported announce string', () => { + const mockedSource = 'SOURCE'; + const result = runTest( + { + eventType: 'contentChanged', + eventDataCache: mockedDataCache, + source: mockedSource, + announceData: { + defaultStrings: 'newLineInserted', + }, + }, + undefined, + { + eventType: PluginEventType.ContentChanged, + eventDataCache: mockedDataCache, + additionalData: { + formatApiName: undefined, + getAnnounceData: jasmine.anything() as any, + getEntityState: undefined, + }, + data: undefined, + source: mockedSource, + } + ) as ContentChangedEvent; + + expect(result.additionalData!.getAnnounceData!()).toBeUndefined(); + }); + it('ContextMenu', () => { const mockedItems = 'ITEMS' as any;