diff --git a/mockdata/src/sheets/demo/default-workbook-data-demo.ts b/mockdata/src/sheets/demo/default-workbook-data-demo.ts index 0ef643cb62a..1b451590852 100644 --- a/mockdata/src/sheets/demo/default-workbook-data-demo.ts +++ b/mockdata/src/sheets/demo/default-workbook-data-demo.ts @@ -14287,6 +14287,114 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = { t: 1, }, }, + 25: { + 10: { + p: { + id: '__INTERNAL_EDITOR__ZEN_EDITOR', + documentStyle: { + pageSize: { + width: 37.2261962890625, + height: undefined, + }, + documentFlavor: 1, + marginTop: 0, + marginBottom: 2, + marginRight: 2, + marginLeft: 2, + renderConfig: { + horizontalAlign: 2, + verticalAlign: 0, + centerAngle: 0, + vertexAngle: 0, + wrapStrategy: 0, + }, + }, + drawings: {}, + drawingsOrder: [], + body: { + dataStream: '1\r\n', + textRuns: [], + paragraphs: [ + { + startIndex: 1, + paragraphStyle: { + horizontalAlign: 2, + }, + bullet: { + nestingLevel: 0, + textStyle: { + fs: 20, + }, + listType: 'CHECK_LIST_CHECKED', + listId: 'w6THUh', + }, + }, + ], + sectionBreaks: [ + { + startIndex: 2, + }, + ], + customRanges: [], + customDecorations: [], + }, + }, + s: 'idtqdi', + }, + 11: { + p: { + id: '__INTERNAL_EDITOR__ZEN_EDITOR', + documentStyle: { + pageSize: { + width: 37.2261962890625, + height: undefined, + }, + documentFlavor: 1, + marginTop: 0, + marginBottom: 2, + marginRight: 2, + marginLeft: 2, + renderConfig: { + horizontalAlign: 2, + verticalAlign: 0, + centerAngle: 0, + vertexAngle: 0, + wrapStrategy: 0, + }, + }, + drawings: {}, + drawingsOrder: [], + body: { + dataStream: '1\r\n', + textRuns: [], + paragraphs: [ + { + startIndex: 1, + paragraphStyle: { + horizontalAlign: 2, + }, + bullet: { + nestingLevel: 0, + textStyle: { + fs: 20, + }, + listType: 'CHECK_LIST', + listId: 'w6THUh', + }, + }, + ], + sectionBreaks: [ + { + startIndex: 2, + }, + ], + customRanges: [], + customDecorations: [], + }, + }, + s: 'idtqdi', + }, + }, }, freeze: { diff --git a/packages/core/src/docs/data-model/text-x/apply-utils/update-apply.ts b/packages/core/src/docs/data-model/text-x/apply-utils/update-apply.ts index 203ce512a28..f38c90715c2 100644 --- a/packages/core/src/docs/data-model/text-x/apply-utils/update-apply.ts +++ b/packages/core/src/docs/data-model/text-x/apply-utils/update-apply.ts @@ -15,7 +15,6 @@ */ import type { Nullable } from '../../../../shared'; -import { Tools, UpdateDocsAttributeType } from '../../../../shared'; import type { ICustomBlock, ICustomDecoration, @@ -26,6 +25,7 @@ import type { ISectionBreak, ITextRun, } from '../../../../types/interfaces'; +import { Tools, UpdateDocsAttributeType } from '../../../../shared'; import { PresetListType } from '../../preset-list-type'; import { deleteCustomBlocks, @@ -39,6 +39,7 @@ import { insertCustomDecorations, insertCustomRanges, insertParagraphs, + insertSectionBreaks, insertTables, insertTextRuns, normalizeTextRuns, @@ -229,7 +230,6 @@ function updateParagraphs( } const removeParagraphs = deleteParagraphs(body, textLength, currentIndex); - if (coverType !== UpdateDocsAttributeType.REPLACE) { const newUpdateParagraphs: IParagraph[] = []; for (const updateParagraph of updateDataParagraphs) { @@ -336,7 +336,7 @@ function updateSectionBreaks( } updateBody.sectionBreaks = newUpdateSectionBreaks; } - insertParagraphs(body, updateBody, textLength, currentIndex); + insertSectionBreaks(body, updateBody, textLength, currentIndex); return removeSectionBreaks; } diff --git a/packages/core/src/docs/data-model/text-x/build-utils/index.ts b/packages/core/src/docs/data-model/text-x/build-utils/index.ts index a586cbc36c3..0ed66b57fe0 100644 --- a/packages/core/src/docs/data-model/text-x/build-utils/index.ts +++ b/packages/core/src/docs/data-model/text-x/build-utils/index.ts @@ -15,6 +15,7 @@ */ import { copyCustomRange, getCustomRangesInterestsWithRange, isIntersecting, shouldDeleteCustomRange } from './custom-range'; +import { changeParagraphBulletNestLevel, setParagraphBullet, switchParagraphBullet, toggleChecklistParagraph } from './paragraph'; import { fromPlainText, getPlainText, isEmptyDocument } from './parse'; import { getDeleteSelection, getInsertSelection, getRetainAndDeleteFromReplace, isSegmentIntersects, makeSelection, normalizeSelection } from './selection'; import { addCustomRangeTextX, deleteCustomRangeTextX, getRetainAndDeleteAndExcludeLineBreak, replaceSelectionTextX } from './text-x-utils'; @@ -52,6 +53,15 @@ export class BuildTextUtils { fromPlainText, isEmptyDocument, }; + + static paragraph = { + bullet: { + set: setParagraphBullet, + switch: switchParagraphBullet, + toggleChecklist: toggleChecklistParagraph, + changeNestLevel: changeParagraphBulletNestLevel, + }, + }; } export type { IAddCustomRangeTextXParam, IDeleteCustomRangeParam, IReplaceSelectionTextXParams } from './text-x-utils'; diff --git a/packages/core/src/docs/data-model/text-x/build-utils/paragraph.ts b/packages/core/src/docs/data-model/text-x/build-utils/paragraph.ts new file mode 100644 index 00000000000..754135277bf --- /dev/null +++ b/packages/core/src/docs/data-model/text-x/build-utils/paragraph.ts @@ -0,0 +1,315 @@ +/** + * 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 { ICustomTable, IParagraph } from '../../../../types/interfaces'; +import type { DocumentDataModel } from '../../document-data-model'; +import { MemoryCursor } from '../../../../common/memory-cursor'; +import { Tools, UpdateDocsAttributeType } from '../../../../shared'; +import { PRESET_LIST_TYPE, PresetListType } from '../../preset-list-type'; +import { TextXActionType } from '../action-types'; +import { TextX } from '../text-x'; + +export interface ISwitchParagraphBulletParams { + paragraphs: IParagraph[]; + listType: string; + segmentId?: string; + document: DocumentDataModel; +} + +export const switchParagraphBullet = (params: ISwitchParagraphBulletParams) => { + const { paragraphs: currentParagraphs, segmentId, document: docDataModel } = params; + let listType = params.listType; + const paragraphs = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.paragraphs ?? []; + const isAlreadyList = currentParagraphs.every((paragraph) => paragraph.bullet?.listType.indexOf(listType) === 0); + + const ID_LENGTH = 6; + + let listId = Tools.generateRandomId(ID_LENGTH); + + if (currentParagraphs.length === 1) { + const curIndex = paragraphs.indexOf(currentParagraphs[0]); + const prevParagraph = paragraphs[curIndex - 1]; + const nextParagraph = paragraphs[curIndex + 1]; + + if (prevParagraph && prevParagraph.bullet && prevParagraph.bullet.listType.indexOf(listType) === 0) { + listId = prevParagraph.bullet.listId; + if (listType !== PresetListType.CHECK_LIST) { + listType = prevParagraph.bullet.listType; + } + } else if (nextParagraph && nextParagraph.bullet && nextParagraph.bullet.listType.indexOf(listType) === 0) { + listId = nextParagraph.bullet.listId; + if (listType !== PresetListType.CHECK_LIST) { + listType = nextParagraph.bullet.listType; + } + } + } + + const memoryCursor = new MemoryCursor(); + + memoryCursor.reset(); + + const textX = new TextX(); + + for (const paragraph of currentParagraphs) { + const { startIndex, paragraphStyle = {}, bullet } = paragraph; + + textX.push({ + t: TextXActionType.RETAIN, + len: startIndex - memoryCursor.cursor, + segmentId, + }); + + textX.push({ + t: TextXActionType.RETAIN, + len: 1, + body: { + dataStream: '', + paragraphs: [ + isAlreadyList + ? { + paragraphStyle, + startIndex: 0, + } + : { + startIndex: 0, + paragraphStyle: { + ...paragraphStyle, + }, + bullet: { + nestingLevel: bullet?.nestingLevel ?? 0, + textStyle: { + fs: 20, + }, + listType, + listId, + }, + }, + ], + }, + segmentId, + coverType: UpdateDocsAttributeType.REPLACE, + }); + + memoryCursor.moveCursorTo(startIndex + 1); + } + + return textX; +}; + +export interface IToggleChecklistParagraphParams { + paragraphIndex: number; + segmentId?: string; + document: DocumentDataModel; +} + +export const toggleChecklistParagraph = (params: IToggleChecklistParagraphParams) => { + const { paragraphIndex, segmentId, document: docDataModel } = params; + const paragraphs = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.paragraphs; + if (paragraphs == null) { + return false; + } + + const currentParagraph = paragraphs.find((p) => p.startIndex === paragraphIndex); + if (!currentParagraph?.bullet || currentParagraph.bullet.listType.indexOf(PresetListType.CHECK_LIST) === -1) { + return false; + } + + const memoryCursor = new MemoryCursor(); + memoryCursor.reset(); + + const textX = new TextX(); + + const { startIndex, paragraphStyle = {} } = currentParagraph; + const listType = currentParagraph.bullet.listType === PresetListType.CHECK_LIST ? + PresetListType.CHECK_LIST_CHECKED + : PresetListType.CHECK_LIST; + + textX.push({ + t: TextXActionType.RETAIN, + len: startIndex - memoryCursor.cursor, + segmentId, + }); + + textX.push({ + t: TextXActionType.RETAIN, + len: 1, + body: { + dataStream: '', + paragraphs: [ + { + ...currentParagraph, + paragraphStyle, + startIndex: 0, + bullet: { + ...currentParagraph.bullet, + listType, + }, + }, + ], + }, + coverType: UpdateDocsAttributeType.REPLACE, + segmentId, + }); + + memoryCursor.moveCursorTo(startIndex + 1); + + return textX; +}; + +export interface ISetParagraphBulletParams { + paragraphs: IParagraph[]; + listType: string; + segmentId?: string; + document: DocumentDataModel; +} + +export const setParagraphBullet = (params: ISetParagraphBulletParams) => { + const { paragraphs: currentParagraphs, listType, segmentId, document: docDataModel } = params; + const paragraphs = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.paragraphs; + + if (paragraphs == null) { + return false; + } + + const ID_LENGTH = 6; + const listId = Tools.generateRandomId(ID_LENGTH); + + const memoryCursor = new MemoryCursor(); + + memoryCursor.reset(); + + const textX = new TextX(); + + for (const paragraph of currentParagraphs) { + const { startIndex, paragraphStyle = {}, bullet } = paragraph; + + textX.push({ + t: TextXActionType.RETAIN, + len: startIndex - memoryCursor.cursor, + segmentId, + }); + + textX.push({ + t: TextXActionType.RETAIN, + len: 1, + body: { + dataStream: '', + paragraphs: [ + { + startIndex: 0, + paragraphStyle, + bullet: { + nestingLevel: bullet?.nestingLevel ?? 0, + textStyle: bullet?.listType === listType + ? bullet.textStyle + : { + fs: 20, + }, + listType, + listId, + }, + }, + ], + }, + segmentId, + coverType: UpdateDocsAttributeType.REPLACE, + }); + + memoryCursor.moveCursorTo(startIndex + 1); + } + + return textX; +}; + +export interface IChangeParagraphBulletNestLevelParams { + paragraphs: IParagraph[]; + segmentId?: string; + document: DocumentDataModel; + type: 1 | -1; +} + +export function hasParagraphInTable(paragraph: IParagraph, tables: ICustomTable[]) { + return tables.some((table) => paragraph.startIndex > table.startIndex && paragraph.startIndex < table.endIndex); +} + +export const changeParagraphBulletNestLevel = (params: IChangeParagraphBulletNestLevelParams) => { + const { paragraphs: currentParagraphs, segmentId, document: docDataModel, type } = params; + const memoryCursor = new MemoryCursor(); + + memoryCursor.reset(); + + const textX = new TextX(); + + const customLists = docDataModel.getSnapshot().lists ?? {}; + const tables = docDataModel.getBody()?.tables ?? []; + + const lists = { + ...PRESET_LIST_TYPE, + ...customLists, + }; + + for (const paragraph of currentParagraphs) { + const { startIndex, paragraphStyle = {}, bullet } = paragraph; + const isInTable = hasParagraphInTable(paragraph, tables); + + textX.push({ + t: TextXActionType.RETAIN, + len: startIndex - memoryCursor.cursor, + segmentId, + }); + + if (bullet) { + const listType = bullet.listType as keyof typeof lists; + let maxLevel = lists[listType].nestingLevel.length - 1; + if (isInTable) { + maxLevel = Math.min(maxLevel, 2); + } + + textX.push({ + t: TextXActionType.RETAIN, + len: 1, + body: { + dataStream: '', + paragraphs: [ + { + startIndex: 0, + paragraphStyle: { + ...paragraphStyle, + }, + bullet: { + ...bullet, + nestingLevel: Math.max(Math.min(bullet.nestingLevel + type, maxLevel), 0), + }, + }, + ], + }, + segmentId, + coverType: UpdateDocsAttributeType.REPLACE, + }); + } else { + // TODO: in this case, should set indent to paragraph + textX.push({ + t: TextXActionType.RETAIN, + len: 1, + }); + } + + memoryCursor.moveCursorTo(startIndex + 1); + } + + return textX; +}; + diff --git a/packages/core/src/docs/data-model/text-x/build-utils/text-x-utils.ts b/packages/core/src/docs/data-model/text-x/build-utils/text-x-utils.ts index dee68c37d57..bbbc158257d 100644 --- a/packages/core/src/docs/data-model/text-x/build-utils/text-x-utils.ts +++ b/packages/core/src/docs/data-model/text-x/build-utils/text-x-utils.ts @@ -15,11 +15,11 @@ */ import type { IAccessor } from '@wendellhu/redi'; -import type { Nullable } from '../../../../shared'; import type { ITextRange, ITextRangeParam } from '../../../../sheets/typedef'; import type { CustomRangeType, IDocumentBody } from '../../../../types/interfaces'; import type { DocumentDataModel } from '../../document-data-model'; import type { IDeleteAction, IRetainAction } from '../action-types'; +import { type Nullable, UpdateDocsAttributeType } from '../../../../shared'; import { DataStreamTreeTokenType } from '../../types'; import { TextXActionType } from '../action-types'; import { TextX } from '../text-x'; @@ -247,7 +247,6 @@ export function getRetainAndDeleteAndExcludeLineBreak( ): Array { const { startOffset, endOffset } = getDeleteSelection(selection, body); const dos: Array = []; - const { paragraphs = [], dataStream } = body; const textStart = startOffset - memoryCursor; @@ -320,7 +319,40 @@ export function getRetainAndDeleteAndExcludeLineBreak( line: 0, segmentId, }); + cursor = textEnd; + } + + if (!preserveLineBreak) { + const nextParagraph = paragraphs.find((p) => p.startIndex - memoryCursor >= textEnd); + if (nextParagraph) { + if (nextParagraph.startIndex > cursor) { + dos.push({ + t: TextXActionType.RETAIN, + len: nextParagraph.startIndex - cursor, + segmentId, + }); + cursor = nextParagraph.startIndex; + } + + dos.push({ + t: TextXActionType.RETAIN, + len: 1, + segmentId, + body: { + dataStream: '', + paragraphs: [ + { + ...nextParagraph, + startIndex: 0, + bullet: paragraphInRange?.bullet, + }, + ], + }, + coverType: UpdateDocsAttributeType.REPLACE, + }); + } } + return dos; } diff --git a/packages/core/src/docs/data-model/text-x/utils.ts b/packages/core/src/docs/data-model/text-x/utils.ts index f1e75e0647c..af934a19777 100644 --- a/packages/core/src/docs/data-model/text-x/utils.ts +++ b/packages/core/src/docs/data-model/text-x/utils.ts @@ -108,7 +108,7 @@ export function getBodySlice( for (const paragraph of paragraphs) { const { startIndex } = paragraph; - if (startIndex >= startOffset && startIndex <= endOffset) { + if (startIndex >= startOffset && startIndex < endOffset) { newParagraphs.push(Tools.deepClone(paragraph)); } } diff --git a/packages/docs-ui/src/commands/commands/break-line.command.ts b/packages/docs-ui/src/commands/commands/break-line.command.ts index 77907baad3f..c4617fd53de 100644 --- a/packages/docs-ui/src/commands/commands/break-line.command.ts +++ b/packages/docs-ui/src/commands/commands/break-line.command.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { BooleanNumber, BuildTextUtils, CommandType, DataStreamTreeTokenType, getBodySlice, ICommandService, IUniverInstanceService, normalizeBody, PresetListType, Tools, updateAttributeByInsert } from '@univerjs/core'; -import { DocSelectionManagerService } from '@univerjs/docs'; import type { ICommand, IParagraph } from '@univerjs/core'; +import { BuildTextUtils, CommandType, DataStreamTreeTokenType, getBodySlice, ICommandService, IUniverInstanceService, normalizeBody, PresetListType, Tools, updateAttributeByInsert } from '@univerjs/core'; +import { DocSelectionManagerService } from '@univerjs/docs'; import { InsertCommand } from './core-editing.command'; export function generateParagraphs(dataStream: string, prevParagraph?: IParagraph): IParagraph[] { @@ -38,20 +38,10 @@ export function generateParagraphs(dataStream: string, prevParagraph?: IParagrap for (const paragraph of paragraphs) { if (prevParagraph.bullet) { paragraph.bullet = Tools.deepClone(prevParagraph.bullet); - if (paragraph.bullet.listType === PresetListType.CHECK_LIST_CHECKED) { - paragraph.bullet.listType = PresetListType.CHECK_LIST; - } } if (prevParagraph.paragraphStyle) { paragraph.paragraphStyle = Tools.deepClone(prevParagraph.paragraphStyle); - if (prevParagraph.bullet?.listType === PresetListType.CHECK_LIST_CHECKED) { - if (paragraph.paragraphStyle?.textStyle) { - paragraph.paragraphStyle.textStyle.st = { - s: BooleanNumber.FALSE, - }; - } - } } } } @@ -97,49 +87,41 @@ export const BreakLineCommand: ICommand = { const paragraphs = body.paragraphs ?? []; const prevParagraph = paragraphs.find((p) => p.startIndex >= startOffset); + if (!prevParagraph) { + return false; + } // line breaks to 2 - if (prevParagraph && prevParagraph.startIndex > endOffset) { - const bodyAfter = normalizeBody(getBodySlice(body, endOffset, prevParagraph.startIndex + 1)); - bodyAfter.customRanges = bodyAfter.customRanges?.map(BuildTextUtils.customRange.copyCustomRange); + const bodyAfter = normalizeBody(getBodySlice(body, endOffset, prevParagraph.startIndex + 1)); + bodyAfter.customRanges = bodyAfter.customRanges?.map(BuildTextUtils.customRange.copyCustomRange); + const deleteRange = { + startOffset, + endOffset: prevParagraph.startIndex + 1, + collapsed: false, + }; + + if (bodyAfter.paragraphs?.[0].bullet?.listType === PresetListType.CHECK_LIST_CHECKED) { + bodyAfter.paragraphs[0].bullet.listType = PresetListType.CHECK_LIST; + }; + + updateAttributeByInsert( + bodyAfter, + { + dataStream: DataStreamTreeTokenType.PARAGRAPH, + paragraphs: generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, prevParagraph), + }, + 1, + 0 + ); + + const result = await commandService.executeCommand(InsertCommand.id, { + unitId, + body: bodyAfter, + range: deleteRange, + segmentId, + cursorOffset: 1, + }); - const deleteRange = { - startOffset, - endOffset: prevParagraph.startIndex + 1, - collapsed: false, - }; - updateAttributeByInsert( - bodyAfter, - { - dataStream: DataStreamTreeTokenType.PARAGRAPH, - paragraphs: generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, prevParagraph), - }, - 1, - 0 - ); - - const result = await commandService.executeCommand(InsertCommand.id, { - unitId, - body: bodyAfter, - range: deleteRange, - segmentId, - cursorOffset: 1, - }); - - return result; - } else { - // split paragraph into two. - const result = await commandService.executeCommand(InsertCommand.id, { - unitId, - body: { - dataStream: DataStreamTreeTokenType.PARAGRAPH, - paragraphs: generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, prevParagraph), - }, - range: activeTextRange, - segmentId, - }); - - return result; - } + return result; }, }; diff --git a/packages/docs-ui/src/commands/commands/core-editing.command.ts b/packages/docs-ui/src/commands/commands/core-editing.command.ts index 2e5cdc9f21f..38ff20f9aec 100644 --- a/packages/docs-ui/src/commands/commands/core-editing.command.ts +++ b/packages/docs-ui/src/commands/commands/core-editing.command.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { BuildTextUtils, CommandType, ICommandService, IUniverInstanceService, JSONX, TextX, TextXActionType, UniverInstanceType } from '@univerjs/core'; -import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; import type { DocumentDataModel, ICommand, @@ -27,6 +25,8 @@ import type { } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import type { ITextRangeWithStyle } from '@univerjs/engine-render'; +import { BuildTextUtils, CommandType, ICommandService, IUniverInstanceService, JSONX, TextX, TextXActionType, UniverInstanceType } from '@univerjs/core'; +import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; import { DeleteDirection } from '../../types/delete-direction'; import { getRichTextEditPath } from '../util'; diff --git a/packages/docs-ui/src/commands/commands/list.command.ts b/packages/docs-ui/src/commands/commands/list.command.ts index 69202f1dbd1..b2bcea59d04 100644 --- a/packages/docs-ui/src/commands/commands/list.command.ts +++ b/packages/docs-ui/src/commands/commands/list.command.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import type { DocumentDataModel, ICommand, IMutationInfo, IParagraph, IParagraphRange, ISectionBreak } from '@univerjs/core'; +import type { IRichTextEditingMutationParams } from '@univerjs/docs'; +import type { ITextRangeWithStyle } from '@univerjs/engine-render'; import { + BuildTextUtils, CommandType, GridType, ICommandService, @@ -27,14 +31,10 @@ import { TextX, TextXActionType, Tools, - UpdateDocsAttributeType, + UniverInstanceType, } from '@univerjs/core'; import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; import { getCharSpaceApply, getNumberUnitValue } from '@univerjs/engine-render'; -import type { ICommand, IListData, IMutationInfo, IParagraph, IParagraphRange, ISectionBreak } from '@univerjs/core'; -import type { IRichTextEditingMutationParams } from '@univerjs/docs'; -import type { ITextRangeWithStyle } from '@univerjs/engine-render'; -import { hasParagraphInTable } from '../../basics/paragraph'; import { getRichTextEditPath } from '../util'; interface IListOperationCommandParams { @@ -44,15 +44,15 @@ interface IListOperationCommandParams { export const ListOperationCommand: ICommand = { id: 'doc.command.list-operation', type: CommandType.COMMAND, - // eslint-disable-next-line max-lines-per-function, complexity + handler: (accessor, params: IListOperationCommandParams) => { const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const commandService = accessor.get(ICommandService); - let listType: string = params.listType; + const listType: string = params.listType; - const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); + const docDataModel = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); const docRanges = docSelectionManagerService.getDocRanges() ?? []; if (docDataModel == null || docRanges.length === 0) { @@ -67,36 +67,10 @@ export const ListOperationCommand: ICommand = { return false; } - const sectionBreaks = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.sectionBreaks ?? []; - const currentParagraphs = getParagraphsInRanges(docRanges, paragraphs); const unitId = docDataModel.getUnitId(); - const isAlreadyList = currentParagraphs.every((paragraph) => paragraph.bullet?.listType.indexOf(listType) === 0); - - const ID_LENGTH = 6; - - let listId = Tools.generateRandomId(ID_LENGTH); - - if (currentParagraphs.length === 1) { - const curIndex = paragraphs.indexOf(currentParagraphs[0]); - const prevParagraph = paragraphs[curIndex - 1]; - const nextParagraph = paragraphs[curIndex + 1]; - - if (prevParagraph && prevParagraph.bullet && prevParagraph.bullet.listType.indexOf(listType) === 0) { - listId = prevParagraph.bullet.listId; - if (listType !== PresetListType.CHECK_LIST) { - listType = prevParagraph.bullet.listType; - } - } else if (nextParagraph && nextParagraph.bullet && nextParagraph.bullet.listType.indexOf(listType) === 0) { - listId = nextParagraph.bullet.listId; - if (listType !== PresetListType.CHECK_LIST) { - listType = nextParagraph.bullet.listType; - } - } - } - const doMutation: IMutationInfo = { id: RichTextEditingMutation.id, params: { @@ -110,80 +84,18 @@ export const ListOperationCommand: ICommand = { memoryCursor.reset(); - const textX = new TextX(); + const textX = BuildTextUtils.paragraph.bullet.switch({ + paragraphs: currentParagraphs, + listType, + document: docDataModel, + segmentId, + }); const jsonX = JSONX.getInstance(); - const customLists = docDataModel.getSnapshot().lists ?? {}; - - const lists: Record = { - ...PRESET_LIST_TYPE, - ...customLists, - }; - - const { defaultTabStop = 36 } = docDataModel.getSnapshot().documentStyle; - - for (const paragraph of currentParagraphs) { - const { startIndex, paragraphStyle = {}, bullet } = paragraph; - const { indentFirstLine, snapToGrid, indentStart } = paragraphStyle; - const paragraphProperties = lists[listType].nestingLevel[0].paragraphProperties || {}; - const { hanging: listHanging, indentStart: listIndentStart } = paragraphProperties; - const { charSpace, gridType } = findNearestSectionBreak(startIndex, sectionBreaks) || { charSpace: 0, gridType: GridType.LINES }; - const charSpaceApply = getCharSpaceApply(charSpace, defaultTabStop, gridType, snapToGrid); - - textX.push({ - t: TextXActionType.RETAIN, - len: startIndex - memoryCursor.cursor, - segmentId, - }); - - textX.push({ - t: TextXActionType.RETAIN, - len: 1, - body: { - dataStream: '', - paragraphs: [ - isAlreadyList - ? { - paragraphStyle: { - ...paragraphStyle, - // hanging: undefined, - // indentStart: indentStart ? { v: Math.max(0, getNumberUnitValue(indentStart, charSpaceApply) + getNumberUnitValue(listHanging, charSpaceApply) - getNumberUnitValue(listIndentStart, charSpaceApply)) } : undefined, - }, - startIndex: 0, - } - : { - startIndex: 0, - paragraphStyle: { - ...paragraphStyle, - // indentFirstLine: undefined, - // hanging: listHanging, - // indentStart: { v: getNumberUnitValue(listIndentStart, charSpaceApply) - getNumberUnitValue(listHanging, charSpaceApply) + getNumberUnitValue(indentFirstLine, charSpaceApply) + getNumberUnitValue(indentStart, charSpaceApply) }, - }, - bullet: { - nestingLevel: bullet?.nestingLevel ?? 0, - textStyle: { - fs: 20, - }, - listType, - listId, - }, - }, - ], - }, - segmentId, - coverType: UpdateDocsAttributeType.REPLACE, - }); - - memoryCursor.moveCursorTo(startIndex + 1); - } - const path = getRichTextEditPath(docDataModel, segmentId); doMutation.params.actions = jsonX.editOp(textX.serialize(), path); - const result = commandService.syncExecuteCommand< - IRichTextEditingMutationParams, - IRichTextEditingMutationParams - >(doMutation.id, doMutation.params); + const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); }, @@ -196,13 +108,13 @@ interface IChangeListTypeCommandParams { export const ChangeListTypeCommand: ICommand = { id: 'doc.command.change-list-type', type: CommandType.COMMAND, - // eslint-disable-next-line max-lines-per-function + handler: (accessor, params: IChangeListTypeCommandParams) => { const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const commandService = accessor.get(ICommandService); const { listType } = params; - const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); + const docDataModel = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); const activeRanges = docSelectionManagerService.getDocRanges(); if (docDataModel == null || activeRanges == null || !activeRanges.length) { return false; @@ -216,12 +128,21 @@ export const ChangeListTypeCommand: ICommand = { return false; } - const sectionBreaks = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.sectionBreaks ?? []; - const currentParagraphs = getParagraphsRelative(activeRanges, paragraphs); + const currentParagraphs = getParagraphsInRanges(selections, paragraphs); + const unitId = docDataModel.getUnitId(); - const ID_LENGTH = 6; - const listId = Tools.generateRandomId(ID_LENGTH); + const textX = BuildTextUtils.paragraph.bullet.set({ + paragraphs: currentParagraphs, + listType, + segmentId, + document: docDataModel, + }); + + if (!textX) { + return false; + } + const jsonX = JSONX.getInstance(); const doMutation: IMutationInfo = { id: RichTextEditingMutation.id, params: { @@ -231,79 +152,10 @@ export const ChangeListTypeCommand: ICommand = { }, }; - const memoryCursor = new MemoryCursor(); - - memoryCursor.reset(); - - const textX = new TextX(); - const jsonX = JSONX.getInstance(); - - // const customLists = docDataModel.getSnapshot().lists ?? {}; - - // const lists = { - // ...PRESET_LIST_TYPE, - // ...customLists, - // }; - - // const { defaultTabStop = 36 } = docDataModel.getSnapshot().documentStyle; - - for (const paragraph of currentParagraphs) { - const { startIndex, paragraphStyle = {}, bullet } = paragraph; - // const { indentFirstLine, snapToGrid, indentStart } = paragraphStyle; - // const paragraphProperties = lists[listType].nestingLevel[0].paragraphProperties || {}; - // const bulletParagraphTextStyle = paragraphProperties.textStyle; - // const { hanging: listHanging, indentStart: listIndentStart } = paragraphProperties; - // const { charSpace, gridType } = findNearestSectionBreak(startIndex, sectionBreaks) || { charSpace: 0, gridType: GridType.LINES }; - - // const charSpaceApply = getCharSpaceApply(charSpace, defaultTabStop, gridType, snapToGrid); - - textX.push({ - t: TextXActionType.RETAIN, - len: startIndex - memoryCursor.cursor, - segmentId, - }); - - textX.push({ - t: TextXActionType.RETAIN, - len: 1, - body: { - dataStream: '', - paragraphs: [ - { - startIndex: 0, - paragraphStyle: { - ...paragraphStyle, - // indentFirstLine: undefined, - // hanging: listHanging, - // indentStart: { v: getNumberUnitValue(listIndentStart, charSpaceApply) - getNumberUnitValue(listHanging, charSpaceApply) + getNumberUnitValue(indentFirstLine, charSpaceApply) + getNumberUnitValue(indentStart, charSpaceApply) }, - }, - bullet: { - nestingLevel: bullet?.nestingLevel ?? 0, - textStyle: bullet?.listType === listType - ? bullet.textStyle - : { - fs: 20, - }, - listType, - listId, - }, - }, - ], - }, - segmentId, - coverType: UpdateDocsAttributeType.REPLACE, - }); - - memoryCursor.moveCursorTo(startIndex + 1); - } - const path = getRichTextEditPath(docDataModel, segmentId); doMutation.params.actions = jsonX.editOp(textX.serialize(), path); - const result = commandService.syncExecuteCommand< - IRichTextEditingMutationParams, - IRichTextEditingMutationParams - >(doMutation.id, doMutation.params); + const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); }, @@ -323,7 +175,6 @@ export const ChangeListNestingLevelCommand: ICommand { if (!params) { return false; @@ -332,14 +183,13 @@ export const ChangeListNestingLevelCommand: ICommand(UniverInstanceType.UNIVER_DOC); const activeRange = docSelectionManagerService.getActiveTextRange(); if (docDataModel == null || activeRange == null) { return false; } const { segmentId } = activeRange; - const tables = docDataModel.getBody()?.tables ?? []; const selections = docSelectionManagerService.getDocRanges() ?? []; const paragraphs = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody()?.paragraphs; @@ -350,6 +200,13 @@ export const ChangeListNestingLevelCommand: ICommand = { id: RichTextEditingMutation.id, @@ -360,76 +217,10 @@ export const ChangeListNestingLevelCommand: ICommand(doMutation.id, doMutation.params); + const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); }, @@ -487,7 +278,6 @@ export const ToggleCheckListCommand: ICommand = { id: 'doc.command.toggle-check-list', type: CommandType.COMMAND, - // eslint-disable-next-line max-lines-per-function handler: (accessor, params) => { if (!params) { return false; @@ -496,7 +286,7 @@ export const ToggleCheckListCommand: ICommand = { const commandService = accessor.get(ICommandService); const { index, segmentId, textRanges } = params; - const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); + const docDataModel = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); if (docDataModel == null) { return false; } @@ -506,11 +296,8 @@ export const ToggleCheckListCommand: ICommand = { return false; } - const currentParagraph = paragraphs.find((p) => p.startIndex === index); const unitId = docDataModel.getUnitId(); - if (!currentParagraph?.bullet || currentParagraph.bullet.listType.indexOf(PresetListType.CHECK_LIST) === -1) { - return false; - } + const doMutation: IMutationInfo = { id: RichTextEditingMutation.id, params: { @@ -521,52 +308,20 @@ export const ToggleCheckListCommand: ICommand = { }, }; - const memoryCursor = new MemoryCursor(); - memoryCursor.reset(); - - const textX = new TextX(); - const jsonX = JSONX.getInstance(); - - const { startIndex, paragraphStyle = {} } = currentParagraph; - const listType = currentParagraph.bullet.listType === PresetListType.CHECK_LIST ? - PresetListType.CHECK_LIST_CHECKED - : PresetListType.CHECK_LIST; - - textX.push({ - t: TextXActionType.RETAIN, - len: startIndex - memoryCursor.cursor, - segmentId, - }); - - textX.push({ - t: TextXActionType.RETAIN, - len: 1, - body: { - dataStream: '', - paragraphs: [ - { - ...currentParagraph, - paragraphStyle, - startIndex: 0, - bullet: { - ...currentParagraph.bullet, - listType, - }, - }, - ], - }, - coverType: UpdateDocsAttributeType.REPLACE, + const textX = BuildTextUtils.paragraph.bullet.toggleChecklist({ + document: docDataModel, + paragraphIndex: index, segmentId, }); - memoryCursor.moveCursorTo(startIndex + 1); + if (!textX) { + return false; + } + const jsonX = JSONX.getInstance(); const path = getRichTextEditPath(docDataModel, segmentId); doMutation.params.actions = jsonX.editOp(textX.serialize(), path); - const result = commandService.syncExecuteCommand< - IRichTextEditingMutationParams, - IRichTextEditingMutationParams - >(doMutation.id, doMutation.params); + const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); }, @@ -611,7 +366,7 @@ export const QuickListCommand: ICommand = { const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const commandService = accessor.get(ICommandService); - const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); + const docDataModel = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); const activeRange = docSelectionManagerService.getActiveTextRange(); if (docDataModel == null || activeRange == null) { return false; @@ -706,10 +461,7 @@ export const QuickListCommand: ICommand = { const path = getRichTextEditPath(docDataModel, segmentId); doMutation.params.actions = jsonX.editOp(textX.serialize(), path); - const result = commandService.syncExecuteCommand< - IRichTextEditingMutationParams, - IRichTextEditingMutationParams - >(doMutation.id, doMutation.params); + const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params); return Boolean(result); }, diff --git a/packages/docs-ui/src/controllers/render-controllers/doc-selection-render.controller.ts b/packages/docs-ui/src/controllers/render-controllers/doc-selection-render.controller.ts index 4d33dd1a30a..d8810c1b4be 100644 --- a/packages/docs-ui/src/controllers/render-controllers/doc-selection-render.controller.ts +++ b/packages/docs-ui/src/controllers/render-controllers/doc-selection-render.controller.ts @@ -14,17 +14,17 @@ * limitations under the License. */ +import type { DocumentDataModel, ICommandInfo } from '@univerjs/core'; +import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, RenderComponentType } from '@univerjs/engine-render'; +import type { ISetDocZoomRatioOperationParams } from '../../commands/operations/set-doc-zoom-ratio.operation'; + import { Disposable, ICommandService, Inject, isInternalEditorID, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { DocSelectionManagerService, DocSkeletonManagerService } from '@univerjs/docs'; import { CURSOR_TYPE, DocumentEditArea, PageLayoutType, Vector2 } from '@univerjs/engine-render'; - -import type { DocumentDataModel, ICommandInfo } from '@univerjs/core'; -import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, RenderComponentType } from '@univerjs/engine-render'; import { neoGetDocObject } from '../../basics/component-tools'; import { SetDocZoomRatioOperation } from '../../commands/operations/set-doc-zoom-ratio.operation'; import { IEditorService } from '../../services/editor/editor-manager.service'; import { DocSelectionRenderService } from '../../services/selection/doc-selection-render.service'; -import type { ISetDocZoomRatioOperationParams } from '../../commands/operations/set-doc-zoom-ratio.operation'; export class DocSelectionRenderController extends Disposable implements IRenderModule { private _loadedMap = new WeakSet(); @@ -76,7 +76,6 @@ export class DocSelectionRenderController extends Disposable implements IRenderM if (unitId !== this._context.unitId) { return; } - this._docSelectionRenderService.removeAllRanges(); if (docRanges.length) { this._docSelectionRenderService.addDocRanges(docRanges, isEditing, options); diff --git a/packages/docs/src/commands/mutations/core-editing.mutation.ts b/packages/docs/src/commands/mutations/core-editing.mutation.ts index 1c6304600d9..28123802a3d 100644 --- a/packages/docs/src/commands/mutations/core-editing.mutation.ts +++ b/packages/docs/src/commands/mutations/core-editing.mutation.ts @@ -14,13 +14,13 @@ * limitations under the License. */ +import type { IMutation, IMutationCommonParams, JSONXActions, Nullable } from '@univerjs/core'; +import type { IDocStateChangeInfo } from '../../services/doc-state-emit.service'; import { CommandType, IUniverInstanceService, JSONX } from '@univerjs/core'; import { IRenderManagerService, type ITextRangeWithStyle } from '@univerjs/engine-render'; -import type { IMutation, IMutationCommonParams, JSONXActions, Nullable } from '@univerjs/core'; import { DocSelectionManagerService } from '../../services/doc-selection-manager.service'; import { DocSkeletonManagerService } from '../../services/doc-skeleton-manager.service'; import { DocStateEmitService } from '../../services/doc-state-emit.service'; -import type { IDocStateChangeInfo } from '../../services/doc-state-emit.service'; export interface IRichTextEditingMutationParams extends IMutationCommonParams { unitId: string; @@ -60,6 +60,7 @@ export const RichTextEditingMutation: IMutation { + if (richText?.bullet) { + if (!this._isPointer) { + this._mainComponent?.setCursor(CURSOR_TYPE.POINTER); + } + this._isPointer = true; + } else { + if (this._isPointer) { + this._mainComponent?.setCursor(CURSOR_TYPE.AUTO); + } + this._isPointer = false; + } + })); + } + + private _initPointerEvent() { + this.disposeWithMe(this._hoverManagerService.currentClickedCell$.subscribe((cell) => { + const { location, bullet } = cell; + if (!bullet) { + return; + } + this._commandService.executeCommand(ToggleCellCheckboxCommand.id, { + unitId: location.unitId, + subUnitId: location.subUnitId, + row: location.row, + col: location.col, + paragraphIndex: bullet.startIndex, + }); + })); + } +} diff --git a/packages/sheets-ui/src/services/hover-manager.service.ts b/packages/sheets-ui/src/services/hover-manager.service.ts index ccefb120743..93fee7313e3 100644 --- a/packages/sheets-ui/src/services/hover-manager.service.ts +++ b/packages/sheets-ui/src/services/hover-manager.service.ts @@ -51,7 +51,7 @@ export interface IHoverRichTextPosition extends IHoverCellPosition { export class HoverManagerService extends Disposable { private _currentCell$ = new BehaviorSubject>(null); private _currentRichText$ = new BehaviorSubject>(null); - private _currentClickedCell$ = new Subject(); + private _currentClickedCell$ = new Subject(); // Notify when hovering over different cells currentCell$ = this._currentCell$.asObservable().pipe( @@ -163,6 +163,7 @@ export class HoverManagerService extends Disposable { if (font) { const { paddingLeft, paddingTop } = calcPadding(cell, font); const rects = calculateDocSkeletonRects(font.documentSkeleton, paddingLeft, paddingTop); + const innerX = offsetX - position.startX - leftOffset; const innerY = offsetY - position.startY - topOffset; customRange = rects.links.find((link) => link.rects.some((rect) => rect.left <= innerX && innerX <= rect.right && (rect.top) <= innerY && innerY <= (rect.bottom))); diff --git a/packages/sheets-ui/src/services/utils/doc-skeleton-util.ts b/packages/sheets-ui/src/services/utils/doc-skeleton-util.ts index dd7fb907373..a1e4aded74e 100644 --- a/packages/sheets-ui/src/services/utils/doc-skeleton-util.ts +++ b/packages/sheets-ui/src/services/utils/doc-skeleton-util.ts @@ -79,7 +79,7 @@ const calcDocGlyphPosition = (glyph: IDocumentSkeletonGlyph, skeleton: DocumentS top: rect.top, bottom: rect.bottom, left: rect.left, - right: rect.left, + right: rect.right, }; }; diff --git a/packages/sheets-ui/src/sheets-ui-plugin.ts b/packages/sheets-ui/src/sheets-ui-plugin.ts index 4b9f3af3806..03dacaf02d1 100644 --- a/packages/sheets-ui/src/sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/sheets-ui-plugin.ts @@ -27,6 +27,7 @@ import { AutoFillController } from './controllers/auto-fill.controller'; import { AutoHeightController } from './controllers/auto-height.controller'; import { CellAlertRenderController } from './controllers/cell-alert.controller'; import { CellCustomRenderController } from './controllers/cell-custom-render.controller'; +import { SheetCheckboxController } from './controllers/checkbox.controller'; import { SheetClipboardController } from './controllers/clipboard/clipboard.controller'; import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; import { SheetsDefinedNameController } from './controllers/defined-name/defined-name.controller'; @@ -140,6 +141,7 @@ export class UniverSheetsUIPlugin extends Plugin { [AutoFillController], [FormatPainterController], [SheetsDefinedNameController], + [SheetCheckboxController], // permission [SheetPermissionPanelModel], @@ -181,6 +183,7 @@ export class UniverSheetsUIPlugin extends Plugin { [SheetsDefinedNameController], [StatusBarController], [AutoHeightController], + [SheetCheckboxController], ]); } diff --git a/packages/sheets/src/commands/commands/toggle-checkbox.command.ts b/packages/sheets/src/commands/commands/toggle-checkbox.command.ts new file mode 100644 index 00000000000..7517636313f --- /dev/null +++ b/packages/sheets/src/commands/commands/toggle-checkbox.command.ts @@ -0,0 +1,93 @@ +/** + * 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 { ICommand, IMutationInfo, Workbook } from '@univerjs/core'; +import { BuildTextUtils, CellValueType, CommandType, DocumentDataModel, ICommandService, IUndoRedoService, IUniverInstanceService, TextX, Tools, UniverInstanceType } from '@univerjs/core'; +import { type ISetRangeValuesMutationParams, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '../mutations/set-range-values.mutation'; + +export interface IToggleCellCheckboxCommandParams { + unitId: string; + subUnitId: string; + row: number; + col: number; + paragraphIndex: number; +} + +export const ToggleCellCheckboxCommand: ICommand = { + id: 'sheet.command.toggle-cell-checkbox', + type: CommandType.COMMAND, + handler: (accessor, params) => { + if (!params) { + return false; + } + const { unitId, subUnitId, row, col, paragraphIndex } = params; + const univerInstanceService = accessor.get(IUniverInstanceService); + const workbook = univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); + const sheet = workbook?.getSheetBySheetId(subUnitId); + const undoRedoService = accessor.get(IUndoRedoService); + const commandService = accessor.get(ICommandService); + if (!sheet) { + return false; + } + const cell = sheet.getCell(row, col); + if (!cell?.p) { + return false; + } + const p = Tools.deepClone(cell.p); + const documentDataModel = new DocumentDataModel(p); + const textX = BuildTextUtils.paragraph.bullet.toggleChecklist({ + document: documentDataModel, + paragraphIndex, + }); + if (!textX) { + return false; + } + TextX.apply(documentDataModel.getBody()!, textX.serialize()); + const redoParams: ISetRangeValuesMutationParams = { + unitId, + subUnitId, + cellValue: { + [row]: { + [col]: { + p, + t: CellValueType.STRING, + }, + }, + }, + }; + + const redo: IMutationInfo = { + id: SetRangeValuesMutation.id, + params: redoParams, + }; + const undoParams = SetRangeValuesUndoMutationFactory(accessor, redoParams); + + const undo: IMutationInfo = { + id: SetRangeValuesMutation.id, + params: undoParams, + }; + const redos = [redo]; + const undos = [undo]; + + undoRedoService.pushUndoRedo({ + redoMutations: redos, + undoMutations: undos, + unitID: unitId, + }); + + return commandService.syncExecuteCommand(redo.id, redo.params); + }, +}; diff --git a/packages/sheets/src/controllers/basic-worksheet.controller.ts b/packages/sheets/src/controllers/basic-worksheet.controller.ts index f6d14a4b2ec..cd2ba9548a7 100644 --- a/packages/sheets/src/controllers/basic-worksheet.controller.ts +++ b/packages/sheets/src/controllers/basic-worksheet.controller.ts @@ -92,6 +92,7 @@ import { SetWorksheetRowIsAutoHeightCommand, } from '../commands/commands/set-worksheet-row-height.command'; import { SetWorksheetShowCommand } from '../commands/commands/set-worksheet-show.command'; +import { ToggleCellCheckboxCommand } from '../commands/commands/toggle-checkbox.command'; import { AddRangeProtectionMutation } from '../commands/mutations/add-range-protection.mutation'; import { AddWorksheetMergeMutation } from '../commands/mutations/add-worksheet-merge.mutation'; import { AddWorksheetProtectionMutation } from '../commands/mutations/add-worksheet-protection.mutation'; @@ -266,6 +267,8 @@ export class BasicWorksheetController extends Disposable implements IDisposable AddRangeProtectionMutation, DeleteRangeProtectionMutation, SetRangeProtectionMutation, + + ToggleCellCheckboxCommand, ].forEach((command) => this.disposeWithMe(this._commandService.registerCommand(command))); } diff --git a/packages/sheets/src/index.ts b/packages/sheets/src/index.ts index 1c82a9fae9b..3be4a88de1f 100644 --- a/packages/sheets/src/index.ts +++ b/packages/sheets/src/index.ts @@ -391,5 +391,5 @@ export { export { ScrollToCellOperation } from './commands/operations/scroll-to-cell.operation'; export { type ISetSelectionsOperationParams, SetSelectionsOperation } from './commands/operations/selection.operation'; export { type ISetWorksheetActiveOperationParams, SetWorksheetActiveOperation } from './commands/operations/set-worksheet-active.operation'; - +export { type IToggleCellCheckboxCommandParams, ToggleCellCheckboxCommand } from './commands/commands/toggle-checkbox.command'; // #endregion