From eb2349975ebb9bed22b8878b738390bf2825c531 Mon Sep 17 00:00:00 2001 From: jocs Date: Thu, 24 Oct 2024 17:26:14 +0800 Subject: [PATCH 1/3] feat: set inline style at cursor --- .../data-model/text-x/__tests__/apply.spec.ts | 76 +++++++++++++++++-- .../data-model/text-x/apply-utils/common.ts | 32 ++++---- packages/docs-ui/src/basics/paragraph.ts | 17 +++-- .../commands/commands/ime-input.command.ts | 5 +- .../commands/inline-format.command.ts | 16 +++- packages/docs-ui/src/controllers/menu/menu.ts | 20 ++++- .../doc-input.controller.ts | 7 +- packages/docs-ui/src/docs-ui-plugin.ts | 2 + .../services/doc-ime-input-manager.service.ts | 2 +- .../src/services/doc-menu-style.service.ts | 68 +++++++++++++++++ 10 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 packages/docs-ui/src/services/doc-menu-style.service.ts diff --git a/packages/core/src/docs/data-model/text-x/__tests__/apply.spec.ts b/packages/core/src/docs/data-model/text-x/__tests__/apply.spec.ts index d87c0073f56..acc69d179a6 100644 --- a/packages/core/src/docs/data-model/text-x/__tests__/apply.spec.ts +++ b/packages/core/src/docs/data-model/text-x/__tests__/apply.spec.ts @@ -384,13 +384,6 @@ describe('apply method', () => { const resultC = TextX.apply(doc3, composedAction1); const resultD = TextX.apply(doc4, composedAction2); - // console.log(JSON.stringify(resultA, null, 2)); - // console.log(JSON.stringify(resultB, null, 2)); - - // console.log('composedAction1', JSON.stringify(composedAction1, null, 2)); - - // console.log(JSON.stringify(resultC, null, 2)); - expect(resultA).toEqual(resultB); expect(resultC).toEqual(resultD); expect(resultA).toEqual(resultC); @@ -478,4 +471,73 @@ describe('apply method', () => { expect(resultA).toEqual(resultC); expect(composedAction1).toEqual(composedAction2); }); + + it('should get the same result when set different style at 2 clients', () => { + const actionsA: TextXAction[] = [ + { + t: TextXActionType.RETAIN, + len: 1, + segmentId: '', + }, { + t: TextXActionType.RETAIN, + len: 1, + segmentId: '', + body: { + dataStream: '', + textRuns: [{ + st: 0, + ed: 1, + ts: { fs: 9 }, + }], + }, + }, + ]; + + const actionsB: TextXAction[] = [ + { + t: TextXActionType.RETAIN, + len: 2, + segmentId: '', + body: { + dataStream: '', + textRuns: [{ + st: 0, + ed: 2, + ts: { + cl: { + rgb: '#ee0000', + }, + }, + }], + }, + }, + ]; + + const doc1 = getDefaultDocWithLength2(); + const doc2 = getDefaultDocWithLength2(); + const doc3 = getDefaultDocWithLength2(); + const doc4 = getDefaultDocWithLength2(); + + const resultA = TextX.apply(TextX.apply(doc1, actionsA), TextX.transform(actionsB, actionsA, 'left')); + const resultB = TextX.apply(TextX.apply(doc2, actionsB), TextX.transform(actionsA, actionsB, 'right')); + + const composedAction1 = TextX.compose(actionsA, TextX.transform(actionsB, actionsA, 'left')); + const composedAction2 = TextX.compose(actionsB, TextX.transform(actionsA, actionsB, 'right')); + + const resultC = TextX.apply(doc3, composedAction1); + const resultD = TextX.apply(doc4, composedAction2); + + // console.log(JSON.stringify(resultA, null, 2)); + // console.log(JSON.stringify(resultB, null, 2)); + + // console.log('composedAction1', JSON.stringify(composedAction1, null, 2)); + // console.log('composedAction2', JSON.stringify(composedAction2, null, 2)); + + // console.log(JSON.stringify(resultC, null, 2)); + + expect(resultA).toEqual(resultB); + expect(resultC).toEqual(resultD); + expect(resultA).toEqual(resultC); + expect(composedAction1).toEqual(composedAction2); + }); }); diff --git a/packages/core/src/docs/data-model/text-x/apply-utils/common.ts b/packages/core/src/docs/data-model/text-x/apply-utils/common.ts index 8d63885fb6c..e9b014c7628 100644 --- a/packages/core/src/docs/data-model/text-x/apply-utils/common.ts +++ b/packages/core/src/docs/data-model/text-x/apply-utils/common.ts @@ -33,15 +33,15 @@ export function normalizeTextRuns(textRuns: ITextRun[]) { const results: ITextRun[] = []; for (const textRun of textRuns) { - const { ed, ts } = textRun; + const { st, ed, ts } = textRun; if (textRun.sId === undefined) { delete textRun.sId; } - // if (st === ed) { - // continue; - // } + if (st === ed) { + continue; + } // Delete textRun if it has no style(ts is empty or has no sId) if (Tools.isEmptyObject(ts) && textRun.sId == null) { @@ -473,18 +473,18 @@ export function deleteTextRuns(body: IDocumentBody, textLength: number, currentI const removeTextRuns: ITextRun[] = []; // Handles special case where repeated set inline format style by cursor. - if (startIndex === endIndex && textRuns?.find((t) => t.st === currentIndex && t.ed === currentIndex)) { - const textRun = textRuns.find((t) => t.st === currentIndex && t.ed === currentIndex)!; - removeTextRuns.push({ - ...textRun, - st: textRun.st - currentIndex, - ed: textRun.ed - currentIndex, - }); - - body.textRuns = body.textRuns?.filter((t) => t !== textRun); - - return removeTextRuns; - } + // if (startIndex === endIndex && textRuns?.find((t) => t.st === currentIndex && t.ed === currentIndex)) { + // const textRun = textRuns.find((t) => t.st === currentIndex && t.ed === currentIndex)!; + // removeTextRuns.push({ + // ...textRun, + // st: textRun.st - currentIndex, + // ed: textRun.ed - currentIndex, + // }); + + // body.textRuns = body.textRuns?.filter((t) => t !== textRun); + + // return removeTextRuns; + // } if (textRuns) { const newTextRuns = []; diff --git a/packages/docs-ui/src/basics/paragraph.ts b/packages/docs-ui/src/basics/paragraph.ts index b8b66c7a11f..f55c4328ad2 100644 --- a/packages/docs-ui/src/basics/paragraph.ts +++ b/packages/docs-ui/src/basics/paragraph.ts @@ -14,22 +14,27 @@ * limitations under the License. */ -import type { ICustomTable, IParagraph, ITextRun } from '@univerjs/core'; +import type { ICustomTable, IParagraph, ITextRun, ITextStyle, Nullable } from '@univerjs/core'; export function hasParagraphInTable(paragraph: IParagraph, tables: ICustomTable[]) { return tables.some((table) => paragraph.startIndex > table.startIndex && paragraph.startIndex < table.endIndex); } -export function getTextRunAtPosition(textRuns: ITextRun[], position: number) { +export function getTextRunAtPosition(textRuns: ITextRun[], position: number, cacheStyle?: Nullable) { for (let i = textRuns.length - 1; i >= 0; i--) { const textRun = textRuns[i]; const { st, ed } = textRun; - if (st === ed && position === st) { - return textRun; - } if (position > st && position <= ed) { - return textRun; + return { + ...textRun, + ts: { + ...textRun.ts, + ...cacheStyle, + }, + }; } } + + return cacheStyle ? { ts: cacheStyle } : null; } diff --git a/packages/docs-ui/src/commands/commands/ime-input.command.ts b/packages/docs-ui/src/commands/commands/ime-input.command.ts index e302eea2de7..7fae00ebc72 100644 --- a/packages/docs-ui/src/commands/commands/ime-input.command.ts +++ b/packages/docs-ui/src/commands/commands/ime-input.command.ts @@ -21,6 +21,7 @@ import { RichTextEditingMutation } from '@univerjs/docs'; import { IRenderManagerService, type ITextRangeWithStyle } from '@univerjs/engine-render'; import { getTextRunAtPosition } from '../../basics/paragraph'; import { DocIMEInputManagerService } from '../../services/doc-ime-input-manager.service'; +import { DocMenuStyleService } from '../../services/doc-menu-style.service'; import { getRichTextEditPath } from '../util'; export interface IIMEInputCommandParams { @@ -42,6 +43,7 @@ export const IMEInputCommand: ICommand = { const commandService = accessor.get(ICommandService); const renderManagerService = accessor.get(IRenderManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); + const docMenuStyleService = accessor.get(DocMenuStyleService); const imeInputManagerService = renderManagerService.getRenderById(unitId)?.with(DocIMEInputManagerService); const docDataModel = univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_DOC); @@ -86,7 +88,8 @@ export const IMEInputCommand: ICommand = { }, }; - const curTextRun = getTextRunAtPosition(body.textRuns ?? [], startOffset + oldTextLen); + const styleCache = docMenuStyleService.getStyleCache(); + const curTextRun = getTextRunAtPosition(body.textRuns ?? [], startOffset + oldTextLen, styleCache); const textX = new TextX(); const jsonX = JSONX.getInstance(); diff --git a/packages/docs-ui/src/commands/commands/inline-format.command.ts b/packages/docs-ui/src/commands/commands/inline-format.command.ts index 8f372479e89..0db35fab0e8 100644 --- a/packages/docs-ui/src/commands/commands/inline-format.command.ts +++ b/packages/docs-ui/src/commands/commands/inline-format.command.ts @@ -15,6 +15,7 @@ */ import type { + DocumentDataModel, ICommand, IDocumentBody, IMutationInfo, IStyleBase, ITextDecoration, ITextRun, } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; @@ -24,8 +25,10 @@ import { ICommandService, IUniverInstanceService, JSONX, MemoryCursor, TextX, TextXActionType, + UniverInstanceType, } from '@univerjs/core'; import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; +import { DocMenuStyleService } from '../../services/doc-menu-style.service'; import { getRichTextEditPath } from '../util'; function handleInlineFormat( @@ -233,6 +236,7 @@ export const SetInlineFormatCommand: ICommand = { const commandService = accessor.get(ICommandService); const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); + const docMenuStyleService = accessor.get(DocMenuStyleService); const docRanges = docSelectionManagerService.getDocRanges(); @@ -242,7 +246,7 @@ export const SetInlineFormatCommand: ICommand = { const segmentId = docRanges[0].segmentId; - const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); + const docDataModel = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); if (docDataModel == null) { return false; } @@ -315,6 +319,16 @@ export const SetInlineFormatCommand: ICommand = { continue; } + if (startOffset === endOffset) { + // Cache the menu style for next input. + docMenuStyleService.setStyleCache( + { + [COMMAND_ID_TO_FORMAT_KEY_MAP[preCommandId]]: formatValue, + } + ); + continue; + } + const body: IDocumentBody = { dataStream: '', textRuns: [ diff --git a/packages/docs-ui/src/controllers/menu/menu.ts b/packages/docs-ui/src/controllers/menu/menu.ts index 65f0aa113a8..b3c26a58629 100644 --- a/packages/docs-ui/src/controllers/menu/menu.ts +++ b/packages/docs-ui/src/controllers/menu/menu.ts @@ -54,6 +54,7 @@ import { COLOR_PICKER_COMPONENT } from '../../components/color-picker'; import { FONT_FAMILY_COMPONENT, FONT_FAMILY_ITEM_COMPONENT } from '../../components/font-family'; import { FONT_SIZE_COMPONENT } from '../../components/font-size'; import { BULLET_LIST_TYPE_COMPONENT, ORDER_LIST_TYPE_COMPONENT } from '../../components/list-type-picker'; +import { DocMenuStyleService } from '../../services/doc-menu-style.service'; function getInsertTableHiddenObservable( accessor: IAccessor @@ -913,11 +914,16 @@ export function BackgroundColorSelectorMenuItemFactory(accessor: IAccessor): IMe function getFontStyleAtCursor(accessor: IAccessor) { const univerInstanceService = accessor.get(IUniverInstanceService); const textSelectionService = accessor.get(DocSelectionManagerService); + const docMenuStyleService = accessor.get(DocMenuStyleService); + const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); const activeTextRange = textSelectionService.getActiveTextRange(); + const cacheStyle = docMenuStyleService.getStyleCache() ?? {}; if (docDataModel == null || activeTextRange == null) { - return; + return { + ts: cacheStyle, + }; } const { startOffset, segmentId } = activeTextRange; @@ -925,7 +931,9 @@ function getFontStyleAtCursor(accessor: IAccessor) { const textRuns = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.textRuns; if (textRuns == null) { - return; + return { + ts: cacheStyle, + }; } let textRun; @@ -939,7 +947,13 @@ function getFontStyleAtCursor(accessor: IAccessor) { } } - return textRun; + return { + ...textRun, + ts: { + ...textRun?.ts, + ...cacheStyle, + }, + }; } function getParagraphStyleAtCursor(accessor: IAccessor) { diff --git a/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts b/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts index f6da47c868f..9610dbd5cc4 100644 --- a/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts +++ b/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts @@ -22,6 +22,7 @@ import { DocSkeletonManagerService } from '@univerjs/docs'; import { getTextRunAtPosition } from '../../basics/paragraph'; import { AfterSpaceCommand } from '../../commands/commands/auto-format.command'; import { InsertCommand } from '../../commands/commands/core-editing.command'; +import { DocMenuStyleService } from '../../services/doc-menu-style.service'; import { DocSelectionRenderService } from '../../services/selection/doc-selection-render.service'; export class DocInputController extends Disposable implements IRenderModule { @@ -31,7 +32,8 @@ export class DocInputController extends Disposable implements IRenderModule { private readonly _context: IRenderContext, @Inject(DocSelectionRenderService) private readonly _docSelectionRenderService: DocSelectionRenderService, @Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService, - @ICommandService private readonly _commandService: ICommandService + @ICommandService private readonly _commandService: ICommandService, + @Inject(DocMenuStyleService) private readonly _docMenuStyleService: DocMenuStyleService ) { super(); @@ -72,7 +74,8 @@ export class DocInputController extends Disposable implements IRenderModule { const originBody = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody(); // Insert content's style should follow the text style of the current position. - const curTextRun = getTextRunAtPosition(originBody?.textRuns ?? [], activeRange.endOffset); + const cacheStyle = this._docMenuStyleService.getStyleCache(); + const curTextRun = getTextRunAtPosition(originBody?.textRuns ?? [], activeRange.endOffset, cacheStyle); await this._commandService.executeCommand(InsertCommand.id, { unitId, diff --git a/packages/docs-ui/src/docs-ui-plugin.ts b/packages/docs-ui/src/docs-ui-plugin.ts index 967b56c2953..a56be9ea7af 100644 --- a/packages/docs-ui/src/docs-ui-plugin.ts +++ b/packages/docs-ui/src/docs-ui-plugin.ts @@ -76,6 +76,7 @@ import { DocClipboardService, IDocClipboardService } from './services/clipboard/ import { DocAutoFormatService } from './services/doc-auto-format.service'; import { DocEventManagerService } from './services/doc-event-manager.service'; import { DocIMEInputManagerService } from './services/doc-ime-input-manager.service'; +import { DocMenuStyleService } from './services/doc-menu-style.service'; import { DocPageLayoutService } from './services/doc-page-layout.service'; import { DocCanvasPopManagerService } from './services/doc-popup-manager.service'; import { DocStateChangeManagerService } from './services/doc-state-change-manager.service'; @@ -258,6 +259,7 @@ export class UniverDocsUIPlugin extends Plugin { [DocsRenderService], [DocStateChangeManagerService], [DocAutoFormatService], + [DocMenuStyleService], ], this._config.override); dependencies.forEach((d) => injector.add(d)); } diff --git a/packages/docs-ui/src/services/doc-ime-input-manager.service.ts b/packages/docs-ui/src/services/doc-ime-input-manager.service.ts index 0da3d58ef52..fa88384ffff 100644 --- a/packages/docs-ui/src/services/doc-ime-input-manager.service.ts +++ b/packages/docs-ui/src/services/doc-ime-input-manager.service.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { JSONX, RxDisposable } from '@univerjs/core'; import type { DocumentDataModel, JSONXActions, Nullable } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import type { IRenderContext, IRenderModule, ITextRangeWithStyle } from '@univerjs/engine-render'; +import { JSONX, RxDisposable } from '@univerjs/core'; interface ICacheParams { undoCache: IRichTextEditingMutationParams[]; diff --git a/packages/docs-ui/src/services/doc-menu-style.service.ts b/packages/docs-ui/src/services/doc-menu-style.service.ts new file mode 100644 index 00000000000..72071f425a9 --- /dev/null +++ b/packages/docs-ui/src/services/doc-menu-style.service.ts @@ -0,0 +1,68 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ITextStyle, Nullable } from '@univerjs/core'; +import { Disposable, Inject } from '@univerjs/core'; +import { DocSelectionManagerService } from '@univerjs/docs'; +import { Subject } from 'rxjs'; + +// It is used to cache the styles in the doc menu, which is used for the next input, +// and is cleared when the doc range is changed. +export class DocMenuStyleService extends Disposable { + private _cacheStyle: Nullable = null; + + private readonly _styleCache$ = new Subject>(); + readonly styleCache$ = this._styleCache$.asObservable(); + + constructor( + @Inject(DocSelectionManagerService) private readonly _textSelectionManagerService: DocSelectionManagerService + ) { + super(); + + this._init(); + } + + private _init() { + this._listenDocRangeChange(); + } + + private _listenDocRangeChange() { + this.disposeWithMe( + this._textSelectionManagerService.textSelection$.subscribe(() => { + this._clearStyleCache(); + }) + ); + } + + getStyleCache(): Nullable { + return this._cacheStyle; + } + + setStyleCache(style: ITextStyle) { + this._cacheStyle = { + ...this._cacheStyle, + ...style, + }; + + this._styleCache$.next(this._cacheStyle); + } + + private _clearStyleCache() { + this._cacheStyle = null; + + this._styleCache$.next(null); + } +} From 3a49b5ed5b1559e7c3522ed254feffb3ba162694 Mon Sep 17 00:00:00 2001 From: jocs Date: Thu, 24 Oct 2024 17:28:59 +0800 Subject: [PATCH 2/3] fix: remove ununsed codes --- packages/docs-ui/src/services/doc-menu-style.service.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/docs-ui/src/services/doc-menu-style.service.ts b/packages/docs-ui/src/services/doc-menu-style.service.ts index 72071f425a9..ab670bf34c2 100644 --- a/packages/docs-ui/src/services/doc-menu-style.service.ts +++ b/packages/docs-ui/src/services/doc-menu-style.service.ts @@ -17,16 +17,12 @@ import type { ITextStyle, Nullable } from '@univerjs/core'; import { Disposable, Inject } from '@univerjs/core'; import { DocSelectionManagerService } from '@univerjs/docs'; -import { Subject } from 'rxjs'; // It is used to cache the styles in the doc menu, which is used for the next input, // and is cleared when the doc range is changed. export class DocMenuStyleService extends Disposable { private _cacheStyle: Nullable = null; - private readonly _styleCache$ = new Subject>(); - readonly styleCache$ = this._styleCache$.asObservable(); - constructor( @Inject(DocSelectionManagerService) private readonly _textSelectionManagerService: DocSelectionManagerService ) { @@ -56,13 +52,9 @@ export class DocMenuStyleService extends Disposable { ...this._cacheStyle, ...style, }; - - this._styleCache$.next(this._cacheStyle); } private _clearStyleCache() { this._cacheStyle = null; - - this._styleCache$.next(null); } } From 1cefa80cd8a045322aa9627847181a5c971d2193 Mon Sep 17 00:00:00 2001 From: jocs Date: Thu, 24 Oct 2024 17:42:39 +0800 Subject: [PATCH 3/3] fix: remove some failed test case --- .../text-x/__tests__/apply-utils.spec.ts | 48 ++----------------- .../text-x/__tests__/common.spec.ts | 13 ++--- .../__tests__/create-command-test-bed.ts | 2 + 3 files changed, 10 insertions(+), 53 deletions(-) diff --git a/packages/core/src/docs/data-model/text-x/__tests__/apply-utils.spec.ts b/packages/core/src/docs/data-model/text-x/__tests__/apply-utils.spec.ts index 09de1fbd93d..0aa1e67e505 100644 --- a/packages/core/src/docs/data-model/text-x/__tests__/apply-utils.spec.ts +++ b/packages/core/src/docs/data-model/text-x/__tests__/apply-utils.spec.ts @@ -148,7 +148,7 @@ describe('test case in apply utils', () => { expect(removeTextRuns).toEqual(expectedTextRuns); }); - it('Should return collapsed textRun when textLength is 0 and remove the collapsed textRun in body', () => { + it('Should return textRun when textLength is 5 and remove the textRun in body', () => { const body = { dataStream: 'hello\rworld hello\rworld hello\rworld he\r\n', textRuns: [ @@ -159,13 +159,6 @@ describe('test case in apply utils', () => { bl: BooleanNumber.FALSE, }, }, - { - st: 15, - ed: 15, - ts: { - it: BooleanNumber.TRUE, - }, - }, { st: 15, ed: 20, @@ -198,18 +191,19 @@ describe('test case in apply utils', () => { ], }; - const removeTextRuns = deleteTextRuns(body as IDocumentBody, 0, 15); + const removeTextRuns = deleteTextRuns(body as IDocumentBody, 5, 15); const expectedTextRuns = [{ st: 0, - ed: 0, + ed: 5, ts: { + bl: BooleanNumber.FALSE, it: BooleanNumber.TRUE, }, }]; expect(removeTextRuns).toEqual(expectedTextRuns); - expect(body?.textRuns?.length).toBe(3); + expect(body?.textRuns?.length).toBe(2); }); }); @@ -399,38 +393,6 @@ describe('test case in apply utils', () => { expect(needUpdateTextRuns[3]?.ts?.bl).toBe(BooleanNumber.TRUE); }); - it('it should be pass the test when the updateTextRuns and removeTextRuns are both collapsed', () => { - const updateTextRuns = [ - { - st: 0, - ed: 0, - ts: { - bl: BooleanNumber.TRUE, - }, - }, - ]; - - const removedTextRuns = [ - { - st: 0, - ed: 0, - ts: { - cl: { rgb: 'rgb(30, 30, 30)' }, - ff: 'Microsoft YaHei', - fs: 12, - }, - }, - ]; - - const needUpdateTextRuns = coverTextRuns(updateTextRuns, removedTextRuns, UpdateDocsAttributeType.COVER); - - expect(needUpdateTextRuns.length).toBe(1); - expect(needUpdateTextRuns[0]?.ts?.bl).toBe(BooleanNumber.TRUE); - expect(needUpdateTextRuns[0]?.ts?.cl?.rgb).toBe('rgb(30, 30, 30)'); - expect(needUpdateTextRuns[0]?.ts?.ff).toBe('Microsoft YaHei'); - expect(needUpdateTextRuns[0]?.ts?.fs).toBe(12); - }); - describe('test cases in function insertTextRuns', () => { it('it should pass the case when the insertTextRuns is at the beginning of one testRun', async () => { insertTextRuns( diff --git a/packages/core/src/docs/data-model/text-x/__tests__/common.spec.ts b/packages/core/src/docs/data-model/text-x/__tests__/common.spec.ts index 768076b050c..69361f4f04d 100644 --- a/packages/core/src/docs/data-model/text-x/__tests__/common.spec.ts +++ b/packages/core/src/docs/data-model/text-x/__tests__/common.spec.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { describe, expect, it } from 'vitest'; +import type { ITextRun } from '../../../../types/interfaces/i-document-data'; -import { normalizeTextRuns } from '../apply-utils/common'; +import { describe, expect, it } from 'vitest'; import { BooleanNumber } from '../../../../types/enum/text-style'; -import type { ITextRun } from '../../../../types/interfaces/i-document-data'; +import { normalizeTextRuns } from '../apply-utils/common'; describe('common utils test cases', () => { describe('normalizeTextRuns', () => { @@ -56,13 +56,6 @@ describe('common utils test cases', () => { ]; const expectedTextRuns: ITextRun[] = [ - { - st: 0, - ed: 0, - ts: { - bl: BooleanNumber.FALSE, - }, - }, { st: 15, ed: 35, diff --git a/packages/docs-ui/src/commands/commands/__tests__/create-command-test-bed.ts b/packages/docs-ui/src/commands/commands/__tests__/create-command-test-bed.ts index 753d70db1f6..2f51f921e27 100644 --- a/packages/docs-ui/src/commands/commands/__tests__/create-command-test-bed.ts +++ b/packages/docs-ui/src/commands/commands/__tests__/create-command-test-bed.ts @@ -37,6 +37,7 @@ import { DocSelectionManagerService, DocSkeletonManagerService, DocStateEmitServ import { DocumentViewModel, IRenderManagerService } from '@univerjs/engine-render'; import { BehaviorSubject, takeUntil } from 'rxjs'; import { DocIMEInputManagerService } from '../../../services/doc-ime-input-manager.service'; +import { DocMenuStyleService } from '../../../services/doc-menu-style.service'; import { DocStateChangeManagerService } from '../../../services/doc-state-change-manager.service'; import { DocSelectionRenderService } from '../../../services/selection/doc-selection-render.service'; @@ -117,6 +118,7 @@ export function createCommandTestBed(docData?: IDocumentData, dependencies?: Dep injector.add([IRenderManagerService, { useClass: MockRenderManagerService as unknown as Ctor }]); injector.add([DocSelectionManagerService]); + injector.add([DocMenuStyleService]); injector.add([DocStateEmitService]); injector.add([DocStateChangeManagerService]); injector.add([DocIMEInputManagerService]);