diff --git a/examples/scripts/generate-locales.mjs b/examples/scripts/generate-locales.mjs index 95ca877c42..ac7c47f776 100644 --- a/examples/scripts/generate-locales.mjs +++ b/examples/scripts/generate-locales.mjs @@ -48,7 +48,7 @@ import { Tools } from '@univerjs/core'; return ` ${dep.replace(/(@univerjs\/|\-)/g, '')}${formattedLocale}`; }).join(',\n'); - acc += `export const ${formattedLocale} = Tools.deepMerge(\n${depStatements}\n);\n`; + acc += `export const ${formattedLocale} = Tools.deepMerge(\n {},\n${depStatements}\n);\n`; return acc; }, ''); diff --git a/examples/src/mobile-s/main.ts b/examples/src/mobile-s/main.ts index e1a39a3bb3..bd0f262752 100644 --- a/examples/src/mobile-s/main.ts +++ b/examples/src/mobile-s/main.ts @@ -48,9 +48,7 @@ const univer = new Univer({ univer.registerPlugin(UniverFormulaEnginePlugin); // core plugins -univer.registerPlugin(UniverDocsPlugin, { - hasScroll: false, -}); +univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverRenderEnginePlugin); univer.registerPlugin(UniverMobileUIPlugin, { container: 'app', contextMenu: true }); univer.registerPlugin(UniverRPCMainThreadPlugin, { diff --git a/examples/src/sheets-multi/main.tsx b/examples/src/sheets-multi/main.tsx index 05b2538cdc..39c844ef3d 100644 --- a/examples/src/sheets-multi/main.tsx +++ b/examples/src/sheets-multi/main.tsx @@ -51,9 +51,7 @@ function factory(id: string) { univer.registerPlugin(UniverUIPlugin, { container: id, }); - univer.registerPlugin(UniverDocsPlugin, { - hasScroll: false, - }); + univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverDocsUIPlugin); // sheets plugin diff --git a/examples/src/sheets-uniscript/main.ts b/examples/src/sheets-uniscript/main.ts index 5df1106ffe..d144dc376d 100644 --- a/examples/src/sheets-uniscript/main.ts +++ b/examples/src/sheets-uniscript/main.ts @@ -50,9 +50,7 @@ univer.registerPlugin(UniverUIPlugin, { container: 'app', }); -univer.registerPlugin(UniverDocsPlugin, { - hasScroll: false, -}); +univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverDocsUIPlugin); univer.registerPlugin(UniverSheetsPlugin); diff --git a/examples/src/sheets/main.ts b/examples/src/sheets/main.ts index f7094979fd..33780f313f 100644 --- a/examples/src/sheets/main.ts +++ b/examples/src/sheets/main.ts @@ -67,7 +67,7 @@ univer.registerPlugin(UniverRPCMainThreadPlugin, { workerURL: './worker.js', } as IUniverRPCMainThreadConfig); -univer.registerPlugin(UniverDocsPlugin, { hasScroll: false }); +univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverRenderEnginePlugin); univer.registerPlugin(UniverUIPlugin, { container: 'app' }); univer.registerPlugin(UniverDocsUIPlugin); @@ -91,7 +91,6 @@ univer.registerPlugin(UniverSheetsConditionalFormattingUIPlugin); // drawing univer.registerPlugin(UniverSheetsDrawingUIPlugin); -// univer.registerPlugin(UniverDocsDrawingUIPlugin); const mockUser = { userID: 'Owner_qxVnhPbQ', diff --git a/examples/src/slides/main.ts b/examples/src/slides/main.ts index 1b81141e1c..3fef5f5b12 100644 --- a/examples/src/slides/main.ts +++ b/examples/src/slides/main.ts @@ -42,7 +42,7 @@ const univer = new Univer({ // core plugins univer.registerPlugin(UniverRenderEnginePlugin); univer.registerPlugin(UniverUIPlugin, { container: 'app' }); -univer.registerPlugin(UniverDocsPlugin, { hasScroll: false }); +univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverDocsUIPlugin); // base-render univer.registerPlugin(UniverFormulaEnginePlugin); diff --git a/examples/src/uni/main.ts b/examples/src/uni/main.ts index 687e15e69f..4f7a2b4f11 100644 --- a/examples/src/uni/main.ts +++ b/examples/src/uni/main.ts @@ -130,9 +130,7 @@ window.univer = univer; window.univerAPI = FUniver.newAPI(univer); function registerBasicPlugins(univer: Univer) { - univer.registerPlugin(UniverDocsPlugin, { - hasScroll: false, - }); + univer.registerPlugin(UniverDocsPlugin); univer.registerPlugin(UniverFormulaEnginePlugin, { notExecuteFormula: true, }); diff --git a/packages-experimental/uni-docs-ui/src/controllers/menu.schema.ts b/packages-experimental/uni-docs-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..e99d5defee --- /dev/null +++ b/packages-experimental/uni-docs-ui/src/controllers/menu.schema.ts @@ -0,0 +1,52 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { FONT_GROUP_MENU_ID, UNI_MENU_POSITIONS } from '@univerjs/uniui'; +import { menuSchema as docsUIMenuSchema } from '@univerjs/docs-ui'; +import { + DOC_BOLD_MUTATION_ID, + DOC_ITALIC_MUTATION_ID, + DOC_STRIKE_MUTATION_ID, + DOC_UNDERLINE_MUTATION_ID, + DocBoldMenuItemFactory, + DocItalicMenuItemFactory, + DocStrikeThroughMenuItemFactory, + DocUnderlineMenuItemFactory, +} from './menu'; + +export const menuSchema: IMenu2Item = { + [UNI_MENU_POSITIONS.TOOLBAR_MAIN]: (docsUIMenuSchema as any)[RibbonStartGroup.FORMAT], + [FONT_GROUP_MENU_ID]: { + [DOC_BOLD_MUTATION_ID]: { + order: 0, + menuItemFactory: DocBoldMenuItemFactory, + }, + [DOC_ITALIC_MUTATION_ID]: { + order: 1, + menuItemFactory: DocItalicMenuItemFactory, + }, + [DOC_UNDERLINE_MUTATION_ID]: { + order: 2, + menuItemFactory: DocUnderlineMenuItemFactory, + }, + [DOC_STRIKE_MUTATION_ID]: { + order: 3, + menuItemFactory: DocStrikeThroughMenuItemFactory, + }, + }, +}; diff --git a/packages-experimental/uni-docs-ui/src/controllers/uni-docs-ui.controller.tsx b/packages-experimental/uni-docs-ui/src/controllers/uni-docs-ui.controller.tsx index 1b32f5f1fc..575077d55c 100644 --- a/packages-experimental/uni-docs-ui/src/controllers/uni-docs-ui.controller.tsx +++ b/packages-experimental/uni-docs-ui/src/controllers/uni-docs-ui.controller.tsx @@ -14,47 +14,47 @@ * limitations under the License. */ -import { ICommandService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; -import type { IMenuItemFactory } from '@univerjs/ui'; -import { ComponentManager, ILayoutService, IMenuService, IShortcutService, IUIPartsService } from '@univerjs/ui'; +import { ICommandService, IConfigService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; +import { ComponentManager, ILayoutService, IMenu2Service, IShortcutService, IUIPartsService } from '@univerjs/ui'; import { BuiltinUniToolbarItemId, generateCloneMutation, UniToolbarService } from '@univerjs/uniui'; -import type { IUniverDocsUIConfig } from '@univerjs/docs-ui'; import { DocCreateTableOperation, DocUIController } from '@univerjs/docs-ui'; import { BulletListCommand, OrderListCommand, SetInlineFormatBoldCommand, SetInlineFormatFontFamilyCommand, SetInlineFormatFontSizeCommand, SetInlineFormatItalicCommand, SetInlineFormatStrikethroughCommand, SetInlineFormatTextBackgroundColorCommand, SetInlineFormatTextColorCommand, SetInlineFormatUnderlineCommand } from '@univerjs/docs'; import { IMAGE_MENU_ID as DocsImageMenuId } from '@univerjs/docs-drawing-ui'; -import { DOC_BOLD_MUTATION_ID, DOC_ITALIC_MUTATION_ID, DOC_STRIKE_MUTATION_ID, DOC_TABLE_MUTATION_ID, DOC_UNDERLINE_MUTATION_ID, DocBoldMenuItemFactory, DocItalicMenuItemFactory, DocStrikeThroughMenuItemFactory, DocTableMenuFactory, DocUnderlineMenuItemFactory } from './menu'; +import { DOC_BOLD_MUTATION_ID, DOC_ITALIC_MUTATION_ID, DOC_STRIKE_MUTATION_ID, DOC_TABLE_MUTATION_ID, DOC_UNDERLINE_MUTATION_ID } from './menu'; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, UniDocsUIController) export class UniDocsUIController extends DocUIController { constructor( - config: Partial, @Inject(Injector) injector: Injector, @Inject(ComponentManager) componentManager: ComponentManager, @ICommandService commandService: ICommandService, @ILayoutService layoutService: ILayoutService, - @IMenuService menuService: IMenuService, + @IMenu2Service menu2Service: IMenu2Service, @IUIPartsService uiPartsService: IUIPartsService, @IUniverInstanceService univerInstanceService: IUniverInstanceService, @IShortcutService shortcutService: IShortcutService, + @IConfigService configService: IConfigService, @Inject(UniToolbarService) private readonly _toolbarService: UniToolbarService - ) { super( - config, injector, componentManager, commandService, layoutService, - menuService, + menu2Service, uiPartsService, univerInstanceService, - shortcutService + shortcutService, + configService ); this._initUniMenus(); this._initMutations(); } private _initUniMenus(): void { + this._menu2Service.appendRootMenu(menuSchema); + ([ [BuiltinUniToolbarItemId.FONT_FAMILY, SetInlineFormatFontFamilyCommand.id], [BuiltinUniToolbarItemId.FONT_SIZE, SetInlineFormatFontSizeCommand.id], @@ -67,18 +67,6 @@ export class UniDocsUIController extends DocUIController { ]).forEach(([id, menuId]) => { this.disposeWithMe(this._toolbarService.implementItem(id, { id: menuId, type: UniverInstanceType.UNIVER_DOC })); }); - - ( - [ - DocBoldMenuItemFactory, - DocItalicMenuItemFactory, - DocUnderlineMenuItemFactory, - DocStrikeThroughMenuItemFactory, - DocTableMenuFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), {})); - }); } private _initMutations() { diff --git a/packages-experimental/uni-sheets-ui/src/controllers/menu.schema.ts b/packages-experimental/uni-sheets-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..2a0de13e07 --- /dev/null +++ b/packages-experimental/uni-sheets-ui/src/controllers/menu.schema.ts @@ -0,0 +1,51 @@ +/** + * 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 IMenu2Item, RibbonStartGroup } from '@univerjs/ui'; +import { FONT_GROUP_MENU_ID, UNI_MENU_POSITIONS } from '@univerjs/uniui'; +import { menuSchema as sheetsUIMenuSchema } from '@univerjs/sheets-ui'; +import { + SHEET_BOLD_MUTATION_ID, + SHEET_ITALIC_MUTATION_ID, + SHEET_STRIKE_MUTATION_ID, + SHEET_UNDERLINE_MUTATION_ID, + SheetBoldMenuItemFactory, + SheetItalicMenuItemFactory, + SheetStrikeThroughMenuItemFactory, + SheetUnderlineMenuItemFactory, +} from './menu'; + +export const menuSchema: IMenu2Item = { + [UNI_MENU_POSITIONS.TOOLBAR_MAIN]: (sheetsUIMenuSchema as any)[RibbonStartGroup.FORMAT], + [FONT_GROUP_MENU_ID]: { + [SHEET_BOLD_MUTATION_ID]: { + order: 0, + menuItemFactory: SheetBoldMenuItemFactory, + }, + [SHEET_ITALIC_MUTATION_ID]: { + order: 1, + menuItemFactory: SheetItalicMenuItemFactory, + }, + [SHEET_UNDERLINE_MUTATION_ID]: { + order: 2, + menuItemFactory: SheetUnderlineMenuItemFactory, + }, + [SHEET_STRIKE_MUTATION_ID]: { + order: 3, + menuItemFactory: SheetStrikeThroughMenuItemFactory, + }, + }, +}; diff --git a/packages-experimental/uni-sheets-ui/src/controllers/uni-sheets-ui.controller.tsx b/packages-experimental/uni-sheets-ui/src/controllers/uni-sheets-ui.controller.tsx index f0ab6702c7..ab6a01be53 100644 --- a/packages-experimental/uni-sheets-ui/src/controllers/uni-sheets-ui.controller.tsx +++ b/packages-experimental/uni-sheets-ui/src/controllers/uni-sheets-ui.controller.tsx @@ -16,37 +16,35 @@ import type { Workbook } from '@univerjs/core'; import { connectInjector, ICommandService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, UniverInstanceType, useDependency } from '@univerjs/core'; -import { type IUniverSheetsUIConfig, RenderSheetContent, SetRangeBoldCommand, SetRangeFontFamilyCommand, SetRangeFontSizeCommand, SetRangeItalicCommand, SetRangeStrickThroughCommand, SetRangeTextColorCommand, SetRangeUnderlineCommand, SheetUIController } from '@univerjs/sheets-ui'; -import type { IMenuItemFactory } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, ILayoutService, IMenuService, IShortcutService, IUIPartsService, useObservable } from '@univerjs/ui'; +import { RenderSheetContent, SetRangeBoldCommand, SetRangeFontFamilyCommand, SetRangeFontSizeCommand, SetRangeItalicCommand, SetRangeStrickThroughCommand, SetRangeTextColorCommand, SetRangeUnderlineCommand, SheetUIController } from '@univerjs/sheets-ui'; +import { BuiltInUIPart, ComponentManager, ILayoutService, IMenu2Service, IShortcutService, IUIPartsService, useObservable } from '@univerjs/ui'; import { BuiltinUniToolbarItemId, generateCloneMutation, UniToolbarService, UniUIPart } from '@univerjs/uniui'; import React from 'react'; import { SetBackgroundColorCommand } from '@univerjs/sheets'; import { IMAGE_MENU_ID as SheetsImageMenuId } from '@univerjs/sheets-drawing-ui'; import { UniSheetBar } from '../views/uni-sheet-bar/UniSheetBar'; -import { SHEET_BOLD_MUTATION_ID, SHEET_ITALIC_MUTATION_ID, SHEET_STRIKE_MUTATION_ID, SHEET_UNDERLINE_MUTATION_ID, SheetBoldMenuItemFactory, SheetItalicMenuItemFactory, SheetStrikeThroughMenuItemFactory, SheetUnderlineMenuItemFactory } from './menu'; +import { SHEET_BOLD_MUTATION_ID, SHEET_ITALIC_MUTATION_ID, SHEET_STRIKE_MUTATION_ID, SHEET_UNDERLINE_MUTATION_ID } from './menu'; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, SheetUIController) export class UniSheetsUIController extends SheetUIController { constructor( - config: Partial, @Inject(Injector) injector: Injector, @Inject(ComponentManager) componentManager: ComponentManager, @ILayoutService layoutService: ILayoutService, @ICommandService commandService: ICommandService, @IShortcutService shortcutService: IShortcutService, - @IMenuService menuService: IMenuService, + @IMenu2Service menu2Service: IMenu2Service, @IUIPartsService uiPartsService: IUIPartsService, @Inject(UniToolbarService) private readonly _toolbarService: UniToolbarService ) { super( - config, injector, componentManager, layoutService, commandService, shortcutService, - menuService, + menu2Service, uiPartsService ); this._initUniMenus(); @@ -63,6 +61,8 @@ export class UniSheetsUIController extends SheetUIController { } private _initUniMenus(): void { + this._menu2Service.appendRootMenu(menuSchema); + ([ [BuiltinUniToolbarItemId.FONT_FAMILY, SetRangeFontFamilyCommand.id], [BuiltinUniToolbarItemId.FONT_SIZE, SetRangeFontSizeCommand.id], @@ -72,17 +72,6 @@ export class UniSheetsUIController extends SheetUIController { ]).forEach(([id, menuId]) => { this._toolbarService.implementItem(id, { id: menuId, type: UniverInstanceType.UNIVER_SHEET }); }); - - ( - [ - SheetBoldMenuItemFactory, - SheetItalicMenuItemFactory, - SheetUnderlineMenuItemFactory, - SheetStrikeThroughMenuItemFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), {})); - }); } private _initMutations() { @@ -107,4 +96,3 @@ function RenderOutline() { ); } - diff --git a/packages-experimental/uni-slides-ui/src/controllers/menu.schema.ts b/packages-experimental/uni-slides-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..5bcb237f70 --- /dev/null +++ b/packages-experimental/uni-slides-ui/src/controllers/menu.schema.ts @@ -0,0 +1,24 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { UNI_MENU_POSITIONS } from '@univerjs/uniui'; +import { menuSchema as slidesUIMenuSchema } from '@univerjs/slides-ui'; + +export const menuSchema: IMenu2Item = { + [UNI_MENU_POSITIONS.TOOLBAR_MAIN]: (slidesUIMenuSchema as any)[RibbonStartGroup.FORMAT], +}; diff --git a/packages-experimental/uni-slides-ui/src/controllers/uni-slides-ui.controller.tsx b/packages-experimental/uni-slides-ui/src/controllers/uni-slides-ui.controller.tsx index 0f31cdc0a1..ef71655d46 100644 --- a/packages-experimental/uni-slides-ui/src/controllers/uni-slides-ui.controller.tsx +++ b/packages-experimental/uni-slides-ui/src/controllers/uni-slides-ui.controller.tsx @@ -17,25 +17,24 @@ import React from 'react'; import type { SlideDataModel } from '@univerjs/core'; import { connectInjector, ICommandService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, UniverInstanceType, useDependency } from '@univerjs/core'; -import type { IUniverSlidesDrawingConfig } from '@univerjs/slides-ui'; import { IMAGE_MENU_ID, SHAPE_MENU_ID, SlideAddTextCommand, SlideEditorContainer, SlidesUIController } from '@univerjs/slides-ui'; -import { BuiltInUIPart, ComponentManager, IMenuService, IShortcutService, IUIPartsService, useObservable } from '@univerjs/ui'; +import { BuiltInUIPart, ComponentManager, IMenu2Service, IShortcutService, IUIPartsService, useObservable } from '@univerjs/ui'; import { BuiltinUniToolbarItemId, UniToolbarService, UniUIPart } from '@univerjs/uniui'; import { UniSlideSideBar } from '../views/UniSlideSideBar'; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, UniSlidesUIController) export class UniSlidesUIController extends SlidesUIController { constructor( - _config: Partial, @Inject(Injector) _injector: Injector, - @IMenuService _menuService: IMenuService, + @IMenu2Service _menu2Service: IMenu2Service, @Inject(ComponentManager) _componentManager: ComponentManager, @IUIPartsService _uiPartsService: IUIPartsService, @ICommandService _commandService: ICommandService, @IShortcutService _shortcutService: IShortcutService, @Inject(UniToolbarService) private readonly _toolbarService: UniToolbarService ) { - super(_config, _injector, _menuService, _componentManager, _uiPartsService, _commandService, _shortcutService); + super(_injector, _menu2Service, _componentManager, _uiPartsService, _commandService, _shortcutService); this._initUniMenus(); } @@ -48,6 +47,8 @@ export class UniSlidesUIController extends SlidesUIController { } private _initUniMenus(): void { + this._menu2Service.appendRootMenu(menuSchema); + ([ [BuiltinUniToolbarItemId.IMAGE, IMAGE_MENU_ID], [BuiltinUniToolbarItemId.FONT_GROUP, SHAPE_MENU_ID], diff --git a/packages-experimental/uniui/package.json b/packages-experimental/uniui/package.json index 8a2a6bb5f4..f9d5800be6 100644 --- a/packages-experimental/uniui/package.json +++ b/packages-experimental/uniui/package.json @@ -66,6 +66,7 @@ "@univerjs/sheets": "workspace:*", "@univerjs/sheets-ui": "workspace:*", "@univerjs/ui": "workspace:*", + "@univerjs/uniui": "workspace:*", "clsx": ">=2.0.0", "react": "^16.9.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.9.0 || ^17.0.0 || ^18.0.0", diff --git a/packages-experimental/uniui/src/controllers/menu.schema.ts b/packages-experimental/uniui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..32333d5416 --- /dev/null +++ b/packages-experimental/uniui/src/controllers/menu.schema.ts @@ -0,0 +1,75 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { FONT_GROUP_MENU_ID } from '@univerjs/uniui'; +import { + FAKE_BG_COLOR_MENU_ID, + FAKE_FONT_COLOR_MENU_ID, + FAKE_FONT_FAMILY_MENU_ID, + FAKE_FONT_GROUP_MENU_ID, + FAKE_FONT_SIZE_MENU_ID, + FAKE_IMAGE_MENU_ID, + FAKE_ORDER_LIST_MENU_ID, + FAKE_TABLE_MENU_ID, + FAKE_UNORDER_LIST_MENU_ID, + FakeBackgroundColorSelectorMenuItemFactory, + FakeFontFamilySelectorMenuItemFactory, + FakeFontGroupMenuItemFactory, + FakeFontSizeSelectorMenuItemFactory, + FakeImageMenuFactory, + FakeOrderListMenuItemFactory, + FakePivotTableMenuItemFactory, + FakeTextColorSelectorMenuItemFactory, + FakeUnorderListMenuItemFactory, + FontGroupMenuItemFactory, + UNI_MENU_POSITIONS, +} from './menu'; + +export const menuSchema: IMenu2Item = { + [UNI_MENU_POSITIONS.TOOLBAR_MAIN]: { + [FAKE_FONT_FAMILY_MENU_ID]: { + menuItemFactory: FakeFontFamilySelectorMenuItemFactory, + }, + [FAKE_FONT_SIZE_MENU_ID]: { + menuItemFactory: FakeFontSizeSelectorMenuItemFactory, + }, + [FAKE_FONT_COLOR_MENU_ID]: { + menuItemFactory: FakeTextColorSelectorMenuItemFactory, + }, + [FAKE_BG_COLOR_MENU_ID]: { + menuItemFactory: FakeBackgroundColorSelectorMenuItemFactory, + }, + [FAKE_IMAGE_MENU_ID]: { + menuItemFactory: FakeImageMenuFactory, + }, + [FAKE_UNORDER_LIST_MENU_ID]: { + menuItemFactory: FakeUnorderListMenuItemFactory, + }, + [FAKE_ORDER_LIST_MENU_ID]: { + menuItemFactory: FakeOrderListMenuItemFactory, + }, + [FONT_GROUP_MENU_ID]: { + menuItemFactory: FontGroupMenuItemFactory, + }, + [FAKE_FONT_GROUP_MENU_ID]: { + menuItemFactory: FakeFontGroupMenuItemFactory, + }, + [FAKE_TABLE_MENU_ID]: { + menuItemFactory: FakePivotTableMenuItemFactory, + }, + }, +}; diff --git a/packages-experimental/uniui/src/controllers/uniui-toolbar.controller.tsx b/packages-experimental/uniui/src/controllers/uniui-toolbar.controller.tsx index e4d1209207..1f2838c5e3 100644 --- a/packages-experimental/uniui/src/controllers/uniui-toolbar.controller.tsx +++ b/packages-experimental/uniui/src/controllers/uniui-toolbar.controller.tsx @@ -16,11 +16,29 @@ import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; import { DeleteSingle, DownloadSingle, LockSingle, PivotTableSingle, PrintSingle, ShareSingle, ZenSingle } from '@univerjs/icons'; -import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import type { MenuConfig } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service } from '@univerjs/ui'; import { DisposeUnitOperation } from '../commands/operations/uni.operation'; import { UniToolbarService } from '../services/toolbar/uni-toolbar-service'; -import { DeleteMenuItemFactory, DownloadMenuItemFactory, FakeBackgroundColorSelectorMenuItemFactory, FakeFontFamilySelectorMenuItemFactory, FakeFontGroupMenuItemFactory, FakeFontSizeSelectorMenuItemFactory, FakeImageMenuFactory, FakeOrderListMenuItemFactory, FakePivotTableMenuItemFactory, FakeTextColorSelectorMenuItemFactory, FakeUnorderListMenuItemFactory, FontGroupMenuItemFactory, LockMenuItemFactory, PrintMenuItemFactory, ShareMenuItemFactory, ZenMenuItemFactory } from './menu'; +// import { +// DeleteMenuItemFactory, +// DownloadMenuItemFactory, +// FakeBackgroundColorSelectorMenuItemFactory, +// FakeFontFamilySelectorMenuItemFactory, +// FakeFontGroupMenuItemFactory, +// FakeFontSizeSelectorMenuItemFactory, +// FakeImageMenuFactory, +// FakeOrderListMenuItemFactory, +// FakePivotTableMenuItemFactory, +// FakeTextColorSelectorMenuItemFactory, +// FakeUnorderListMenuItemFactory, +// FontGroupMenuItemFactory, +// LockMenuItemFactory, +// PrintMenuItemFactory, +// ShareMenuItemFactory, +// ZenMenuItemFactory, +// } from './menu'; +import { menuSchema } from './menu.schema'; export interface IUniuiToolbarConfig { menu: MenuConfig; @@ -31,7 +49,7 @@ export const DefaultUniuiToolbarConfig = {}; @OnLifecycle(LifecycleStages.Ready, UniuiToolbarController) export class UniuiToolbarController extends Disposable { constructor( - @IMenuService protected readonly _menuService: IMenuService, + @IMenu2Service protected readonly _menu2Service: IMenu2Service, @Inject(Injector) protected readonly _injector: Injector, @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, @ICommandService protected readonly _commandService: ICommandService, @@ -60,29 +78,31 @@ export class UniuiToolbarController extends Disposable { } private _initMenus(): void { + this._menu2Service.appendRootMenu(menuSchema); + // register menu factories - ( - [ - DownloadMenuItemFactory, - ShareMenuItemFactory, - LockMenuItemFactory, - PrintMenuItemFactory, - ZenMenuItemFactory, - DeleteMenuItemFactory, - FontGroupMenuItemFactory, - FakeFontFamilySelectorMenuItemFactory, - FakeTextColorSelectorMenuItemFactory, - FakeFontSizeSelectorMenuItemFactory, - FakeBackgroundColorSelectorMenuItemFactory, - FakeImageMenuFactory, - FakeFontGroupMenuItemFactory, - FakePivotTableMenuItemFactory, - FakeOrderListMenuItemFactory, - FakeUnorderListMenuItemFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), {})); - }); + // ( + // [ + // DownloadMenuItemFactory, + // ShareMenuItemFactory, + // LockMenuItemFactory, + // PrintMenuItemFactory, + // ZenMenuItemFactory, + // DeleteMenuItemFactory, + // FontGroupMenuItemFactory, + // FakeFontFamilySelectorMenuItemFactory, + // FakeTextColorSelectorMenuItemFactory, + // FakeFontSizeSelectorMenuItemFactory, + // FakeBackgroundColorSelectorMenuItemFactory, + // FakeImageMenuFactory, + // FakeFontGroupMenuItemFactory, + // FakePivotTableMenuItemFactory, + // FakeOrderListMenuItemFactory, + // FakeUnorderListMenuItemFactory, + // ] as IMenuItemFactory[] + // ).forEach((factory) => { + // this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), {})); + // }); } private _initCommands(): void { diff --git a/packages-experimental/uniui/src/plugin.ts b/packages-experimental/uniui/src/plugin.ts index cbd915d4ce..87d1ed0227 100644 --- a/packages-experimental/uniui/src/plugin.ts +++ b/packages-experimental/uniui/src/plugin.ts @@ -47,6 +47,7 @@ import { IGlobalZoneService, ILayoutService, ILeftSidebarService, + IMenu2Service, IMenuService, IMessageService, INotificationService, @@ -58,6 +59,7 @@ import { IUIController, IUIPartsService, IZenZoneService, + Menu2Service, MenuService, PlatformService, ProgressService, @@ -89,7 +91,7 @@ export class UniverUniUIPlugin extends Plugin { static override pluginName: string = UNIVER_UI_PLUGIN_NAME; constructor( - private _config: Partial = {}, + private readonly _config: Partial = {}, @Inject(Injector) protected readonly _injector: Injector, @IContextService private readonly _contextService: IContextService ) { @@ -114,6 +116,7 @@ export class UniverUniUIPlugin extends Plugin { [IShortcutService, { useClass: ShortcutService }], [IPlatformService, { useClass: PlatformService }], [IMenuService, { useClass: MenuService }], + [IMenu2Service, { useClass: Menu2Service }], [IContextMenuService, { useClass: ContextMenuService }], [IClipboardInterfaceService, { useClass: BrowserClipboardService, lazy: true }], [INotificationService, { useClass: DesktopNotificationService, lazy: true }], @@ -134,13 +137,9 @@ export class UniverUniUIPlugin extends Plugin { [IUIController, { useFactory: () => this._injector.createInstance(UniverUniUIController, this._config), }], - [SharedController, { - useFactory: () => this._injector.createInstance(SharedController, this._config), - }], + [SharedController], [ErrorController], - [ShortcutPanelController, { - useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config), - }], + [ShortcutPanelController], [UniuiLeftSidebarController], [UniuiToolbarController], [UniuiFlowController], diff --git a/packages-experimental/uniui/src/views/uni-toolbar/UniToolbar.tsx b/packages-experimental/uniui/src/views/uni-toolbar/UniToolbar.tsx index 2a8165ac0c..94963984a1 100644 --- a/packages-experimental/uniui/src/views/uni-toolbar/UniToolbar.tsx +++ b/packages-experimental/uniui/src/views/uni-toolbar/UniToolbar.tsx @@ -15,7 +15,7 @@ */ import { IUniverInstanceService, UniverInstanceType, useDependency, useObservable } from '@univerjs/core'; -import { MenuPosition, ToolbarItem, useToolbarGroups } from '@univerjs/ui'; +import { IMenu2Service, ToolbarItem } from '@univerjs/ui'; import type { ComponentType } from 'react'; import React from 'react'; import { useWorkbooks } from '@univerjs/sheets-ui'; @@ -24,15 +24,6 @@ import { UniToolbarService } from '../../services/toolbar/uni-toolbar-service'; import styles from './index.module.less'; import { UniFormulaBar } from './UniFormulaBar'; -const MENU_POSITIONS = [ - MenuPosition.TOOLBAR_START, - MenuPosition.TOOLBAR_INSERT, - MenuPosition.TOOLBAR_FORMULAS, - MenuPosition.TOOLBAR_DATA, - MenuPosition.TOOLBAR_VIEW, - UNI_MENU_POSITIONS.TOOLBAR_MAIN, -]; - export interface IToolbarProps { headerMenuComponents?: Set; } @@ -41,35 +32,38 @@ export function UniToolbar() { const uniToolbarService = useDependency(UniToolbarService); const instanceService = useDependency(IUniverInstanceService); const focusedUnit = useObservable(instanceService.focused$); + const menu2Service = useDependency(IMenu2Service); const type = focusedUnit ? (instanceService.getUnit(focusedUnit)?.type ?? UniverInstanceType.UNIVER_UNKNOWN) : UniverInstanceType.UNIVER_UNKNOWN; - const { visibleItems } = useToolbarGroups(MENU_POSITIONS); + const menus = menu2Service.getMenuByPositionKey(UNI_MENU_POSITIONS.TOOLBAR_MAIN); const toolbarItems = uniToolbarService.getItems(); const uniVisibleItems = toolbarItems.map((item) => { const { impl } = item; const typeImpl = impl.find((item) => item.type === type); - const visibleItem = visibleItems.find((item) => item.id === typeImpl?.id); + const visibleItem = menus.find((item) => item.key === typeImpl?.id)?.item; if (visibleItem) { return visibleItem; } const placeHolderImpl = impl.find((item) => item.type === UniverInstanceType.UNIVER_UNKNOWN); - const placeHolderItem = visibleItems.find((item) => item.id === placeHolderImpl?.id); + const placeHolderItem = menus.find((item) => item.key === placeHolderImpl?.id)?.item; if (placeHolderItem) { return placeHolderItem; } return null; - }).filter((item) => !!item); + }).filter((item) => { + return !!item && !item.id.startsWith('FAKE_'); + }); const hasWorkbooks = useWorkbooks().length > 0; return (
- { hasWorkbooks && } + {hasWorkbooks && }
- {uniVisibleItems.map((subItem) => )} + {uniVisibleItems.map((subItem) => subItem && )}
diff --git a/packages/core/src/services/config/config.service.ts b/packages/core/src/services/config/config.service.ts index d96f8089ff..2da5f76a26 100644 --- a/packages/core/src/services/config/config.service.ts +++ b/packages/core/src/services/config/config.service.ts @@ -15,6 +15,7 @@ */ import { createIdentifier } from '../../common/di'; +import { Tools } from '../../shared'; import type { Nullable } from '../../shared/types'; @@ -25,25 +26,49 @@ import type { Nullable } from '../../shared/types'; */ export const IConfigService = createIdentifier('univer.config-service'); +interface IConfigOptions { + /** + * Whether the configuration is read-only. + * Not implemented yet. + * @ignore + */ + readonly?: boolean; + + /** + * Whether to merge the configuration with the existing one. + * @default false + */ + merge?: boolean; +} + export interface IConfigService { - getConfig(id: string, defaultValue: T): T; getConfig(id: string): Nullable; - setConfig(id: string, value: unknown): void; - deleteConfig(id: string): void; + setConfig(id: string | symbol, value: unknown, options?: IConfigOptions): void; + deleteConfig(id: string): boolean; } export class ConfigService implements IConfigService { - private readonly _config: Map = new Map(); + private readonly _config: Map = new Map(); - getConfig(id: string): Nullable { + getConfig(id: string | symbol): Nullable { return this._config.get(id) as T; } - setConfig(id: string, value: unknown) { + setConfig(id: string, value: unknown, options?: IConfigOptions): void { + const { merge = false } = options || {}; + + const existingValue = this._config.get(id) ?? {}; + + if (merge) { + this._config.set(id, Tools.deepMerge(existingValue, value)); + + return; + } + this._config.set(id, value); } - deleteConfig(id: string): void { - this._config.delete(id); + deleteConfig(id: string | symbol): boolean { + return this._config.delete(id); } } diff --git a/packages/data-validation/src/controllers/config.schema.ts b/packages/data-validation/src/controllers/config.schema.ts new file mode 100644 index 0000000000..4647ac1451 --- /dev/null +++ b/packages/data-validation/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'data-validation.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDataValidationConfig { +} + +export const defaultPluginConfig: IUniverDataValidationConfig = {}; diff --git a/packages/data-validation/src/plugin.ts b/packages/data-validation/src/plugin.ts index 5e832fb6b4..769f9642b9 100644 --- a/packages/data-validation/src/plugin.ts +++ b/packages/data-validation/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ICommandService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { DataValidatorRegistryService } from './services/data-validator-registry.service'; import { DataValidationModel } from './models/data-validation-model'; @@ -22,6 +22,8 @@ import { AddDataValidationCommand, RemoveAllDataValidationCommand, RemoveDataVal import { AddDataValidationMutation, RemoveDataValidationMutation, UpdateDataValidationMutation } from './commands/mutations/data-validation.mutation'; import { DataValidationResourceController } from './controllers/dv-resource.controller'; import { DataValidationSheetController } from './controllers/dv-sheet.controller'; +import type { IUniverDataValidationConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'UNIVER_DATA_VALIDATION_PLUGIN'; @@ -30,11 +32,16 @@ export class UniverDataValidationPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - _config: unknown, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, - @ICommandService private _commandService: ICommandService + @ICommandService private _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/debugger/src/controllers/config.schema.ts b/packages/debugger/src/controllers/config.schema.ts new file mode 100644 index 0000000000..1ce283e6ab --- /dev/null +++ b/packages/debugger/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'debugger.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDebuggerConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverDebuggerConfig = {}; diff --git a/packages/debugger/src/controllers/debugger.controller.ts b/packages/debugger/src/controllers/debugger.controller.ts index 1d30f520d1..3cb901e9fd 100644 --- a/packages/debugger/src/controllers/debugger.controller.ts +++ b/packages/debugger/src/controllers/debugger.controller.ts @@ -15,8 +15,7 @@ */ import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service } from '@univerjs/ui'; import { ConfirmOperation } from '../commands/operations/confirm.operation'; import { DialogOperation } from '../commands/operations/dialog.operation'; @@ -38,46 +37,21 @@ import { CreateFloatDomCommand } from '../commands/commands/float-dom.command'; import { ImageDemo } from '../components/Image'; import { ChangeUserCommand } from '../commands/operations/change-user.operation'; import { ShowCellContentOperation } from '../commands/operations/cell.operation'; -import { - ChangeUserMenuItemFactory, - ConfirmMenuItemFactory, - CreateEmptySheetMenuItemFactory, - CreateFloatDOMMenuItemFactory, - DialogMenuItemFactory, - DisposeCurrentUnitMenuItemFactory, - DisposeUniverItemFactory, - FloatDomMenuItemFactory, - LocaleMenuItemFactory, - MessageMenuItemFactory, - NotificationMenuItemFactory, - SaveSnapshotSetEditableMenuItemFactory, - SetEditableMenuItemFactory, - ShowCellContentMenuItemFactory, - SidebarMenuItemFactory, - ThemeMenuItemFactory, - UnitMenuItemFactory, -} from './menu'; import { RecordController } from './local-save/record.controller'; import { ExportController } from './local-save/export.controller'; - -export interface IUniverDebuggerConfig { - menu: MenuConfig; -} - -export const DefaultDebuggerConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, DebuggerController) export class DebuggerController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) private readonly _injector: Injector, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService private readonly _commandService: ICommandService, @Inject(ComponentManager) private readonly _componentManager: ComponentManager ) { super(); - this._initializeContextMenu(); + this._initializeMenu(); this._initCustomComponents(); [ @@ -102,30 +76,8 @@ export class DebuggerController extends Disposable { this._injector.add([RecordController]); } - private _initializeContextMenu() { - const { menu = {} } = this._config; - - ([ - LocaleMenuItemFactory, - ThemeMenuItemFactory, - NotificationMenuItemFactory, - MessageMenuItemFactory, - DialogMenuItemFactory, - ConfirmMenuItemFactory, - SidebarMenuItemFactory, - SetEditableMenuItemFactory, - SaveSnapshotSetEditableMenuItemFactory, - UnitMenuItemFactory, - DisposeUniverItemFactory, - DisposeCurrentUnitMenuItemFactory, - CreateEmptySheetMenuItemFactory, - FloatDomMenuItemFactory, - CreateFloatDOMMenuItemFactory, - ChangeUserMenuItemFactory, - ShowCellContentMenuItemFactory, - ] as IMenuItemFactory[]).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); + private _initializeMenu() { + this._menu2Service.mergeMenu(menuSchema); } private _initCustomComponents(): void { diff --git a/packages/debugger/src/controllers/menu.schema.ts b/packages/debugger/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..c9038f3a8b --- /dev/null +++ b/packages/debugger/src/controllers/menu.schema.ts @@ -0,0 +1,124 @@ +/** + * 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 IMenu2Item, RibbonOthersGroup } from '@univerjs/ui'; +import { LocaleOperation } from '../commands/operations/locale.operation'; +import { + ChangeUserMenuItemFactory, + ConfirmMenuItemFactory, + CreateEmptySheetMenuItemFactory, + CreateFloatDOMMenuItemFactory, + DialogMenuItemFactory, + DisposeCurrentUnitMenuItemFactory, + DisposeUniverItemFactory, + FLOAT_DOM_ITEM_MENU_ID, + FloatDomMenuItemFactory, + LocaleMenuItemFactory, + MessageMenuItemFactory, + NotificationMenuItemFactory, + SaveSnapshotSetEditableMenuItemFactory, + SetEditableMenuItemFactory, + ShowCellContentMenuItemFactory, + SidebarMenuItemFactory, + ThemeMenuItemFactory, + UNIT_ITEM_MENU_ID, + UnitMenuItemFactory, +} from '../controllers/menu'; +import { ThemeOperation } from '../commands/operations/theme.operation'; +import { NotificationOperation } from '../commands/operations/notification.operation'; +import { ConfirmOperation } from '../commands/operations/confirm.operation'; +import { DialogOperation } from '../commands/operations/dialog.operation'; +import { MessageOperation } from '../commands/operations/message.operation'; +import { SaveSnapshotOptions } from '../commands/operations/save-snapshot.operations'; +import { SetEditable } from '../commands/operations/set.editable.operation'; +import { SidebarOperation } from '../commands/operations/sidebar.operation'; +import { CreateEmptySheetCommand, DisposeCurrentUnitCommand, DisposeUniverCommand } from '../commands/commands/unit.command'; +import { CreateFloatDomCommand } from '../commands/commands/float-dom.command'; +import { ChangeUserCommand } from '../commands/operations/change-user.operation'; +import { ShowCellContentOperation } from '../commands/operations/cell.operation'; + +export const menuSchema: IMenu2Item = { + [RibbonOthersGroup.OTHERS]: { + [LocaleOperation.id]: { + order: 0, + menuItemFactory: LocaleMenuItemFactory, + }, + [ThemeOperation.id]: { + order: 1, + menuItemFactory: ThemeMenuItemFactory, + }, + [NotificationOperation.id]: { + order: 2, + menuItemFactory: NotificationMenuItemFactory, + }, + [DialogOperation.id]: { + order: 3, + menuItemFactory: DialogMenuItemFactory, + }, + [ConfirmOperation.id]: { + order: 4, + menuItemFactory: ConfirmMenuItemFactory, + }, + [MessageOperation.id]: { + order: 5, + menuItemFactory: MessageMenuItemFactory, + }, + [SidebarOperation.id]: { + order: 6, + menuItemFactory: SidebarMenuItemFactory, + }, + [SetEditable.id]: { + order: 7, + menuItemFactory: SetEditableMenuItemFactory, + }, + [SaveSnapshotOptions.id]: { + order: 8, + menuItemFactory: SaveSnapshotSetEditableMenuItemFactory, + }, + [UNIT_ITEM_MENU_ID]: { + order: 9, + menuItemFactory: UnitMenuItemFactory, + [DisposeUniverCommand.id]: { + order: 0, + menuItemFactory: DisposeUniverItemFactory, + }, + [DisposeCurrentUnitCommand.id]: { + order: 1, + menuItemFactory: DisposeCurrentUnitMenuItemFactory, + }, + [CreateEmptySheetCommand.id]: { + order: 2, + menuItemFactory: CreateEmptySheetMenuItemFactory, + }, + }, + [FLOAT_DOM_ITEM_MENU_ID]: { + order: 10, + menuItemFactory: FloatDomMenuItemFactory, + [CreateFloatDomCommand.id]: { + order: 0, + menuItemFactory: CreateFloatDOMMenuItemFactory, + }, + [ShowCellContentOperation.id]: { + order: 1, + menuItemFactory: ShowCellContentMenuItemFactory, + }, + }, + [ChangeUserCommand.id]: { + order: 11, + menuItemFactory: ChangeUserMenuItemFactory, + }, + }, +}; diff --git a/packages/debugger/src/controllers/menu.ts b/packages/debugger/src/controllers/menu.ts index ee8ce5e0f8..e7788bf568 100644 --- a/packages/debugger/src/controllers/menu.ts +++ b/packages/debugger/src/controllers/menu.ts @@ -229,7 +229,7 @@ export function SaveSnapshotSetEditableMenuItemFactory(accessor: IAccessor): IMe }; } -const UNIT_ITEM_MENU_ID = 'debugger.unit-menu-item'; +export const UNIT_ITEM_MENU_ID = 'debugger.unit-menu-item'; export function UnitMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { @@ -274,7 +274,7 @@ export function CreateEmptySheetMenuItemFactory(accessor: IAccessor): IMenuButto }; } -const FLOAT_DOM_ITEM_MENU_ID = 'debugger.float-dom-menu-item'; +export const FLOAT_DOM_ITEM_MENU_ID = 'debugger.float-dom-menu-item'; export function FloatDomMenuItemFactory(): IMenuSelectorItem { return { diff --git a/packages/debugger/src/debugger-plugin.ts b/packages/debugger/src/debugger-plugin.ts index d28ce29dab..daade27fe0 100644 --- a/packages/debugger/src/debugger-plugin.ts +++ b/packages/debugger/src/debugger-plugin.ts @@ -14,13 +14,14 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, Tools } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; -import type { IUniverDebuggerConfig } from './controllers/debugger.controller'; -import { DebuggerController, DefaultDebuggerConfig } from './controllers/debugger.controller'; +import { DebuggerController } from './controllers/debugger.controller'; import { E2EMemoryController } from './controllers/e2e/e2e-memory.controller'; import { PerformanceMonitorController } from './controllers/performance-monitor.controller'; +import type { IUniverDebuggerConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverDebuggerPlugin extends Plugin { static override pluginName = 'DEBUGGER_PLUGIN'; @@ -28,12 +29,18 @@ export class UniverDebuggerPlugin extends Plugin { private _debuggerController!: DebuggerController; constructor( - private readonly _config: Partial = {}, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultDebuggerConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { @@ -42,12 +49,7 @@ export class UniverDebuggerPlugin extends Plugin { [E2EMemoryController], ] as Dependency[]).forEach((d) => this._injector.add(d)); - this._injector.add([ - DebuggerController, - { - useFactory: () => this._injector.createInstance(DebuggerController, this._config), - }, - ]); + this._injector.add([DebuggerController]); } getDebuggerController() { diff --git a/packages/design/src/components/tooltip/Tooltip.tsx b/packages/design/src/components/tooltip/Tooltip.tsx index 10e63640a4..e870c1db58 100644 --- a/packages/design/src/components/tooltip/Tooltip.tsx +++ b/packages/design/src/components/tooltip/Tooltip.tsx @@ -39,7 +39,7 @@ export interface ITooltipProps { style?: React.CSSProperties; } -type NullableTooltipRef = TooltipRef | null; +export type NullableTooltipRef = TooltipRef | null; export const Tooltip = forwardRef((props, ref) => { const { diff --git a/packages/design/src/components/tooltip/index.ts b/packages/design/src/components/tooltip/index.ts index 1ce735d2c8..a77961431c 100644 --- a/packages/design/src/components/tooltip/index.ts +++ b/packages/design/src/components/tooltip/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { type ITooltipProps, Tooltip } from './Tooltip'; +export { type ITooltipProps, type NullableTooltipRef, Tooltip } from './Tooltip'; export { resizeObserverCtor } from './hooks'; diff --git a/packages/design/src/index.ts b/packages/design/src/index.ts index 6d973320d0..16a76ebcbb 100644 --- a/packages/design/src/index.ts +++ b/packages/design/src/index.ts @@ -54,7 +54,7 @@ export { type ISelectProps, Select } from './components/select'; export { type ISelectListProps, SelectList } from './components/select-list'; export { type ISegmentedProps, Segmented } from './components/segmented'; export { type ISliderProps, Slider } from './components/slider'; -export { type ITooltipProps, Tooltip, resizeObserverCtor } from './components/tooltip'; +export { type ITooltipProps, Tooltip, resizeObserverCtor, type NullableTooltipRef } from './components/tooltip'; export { type ITreeNodeProps, type ITreeProps, Tree, TreeSelectionMode, mergeTreeSelected, findSubTreeFromPath, findNodePathFromTree, filterLeafNode } from './components/tree'; export { Switch } from './components/switch'; export { type ILocale } from './locale/interface'; diff --git a/packages/docs-drawing-ui/src/controllers/config.schema.ts b/packages/docs-drawing-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..99f75ff307 --- /dev/null +++ b/packages/docs-drawing-ui/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'docs-drawing-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsDrawingUIConfig { +} + +export const defaultPluginConfig: IUniverDocsDrawingUIConfig = {}; diff --git a/packages/docs-drawing-ui/src/controllers/doc-drawing.controller.ts b/packages/docs-drawing-ui/src/controllers/doc-drawing.controller.ts index b212f46f85..4ccd022106 100644 --- a/packages/docs-drawing-ui/src/controllers/doc-drawing.controller.ts +++ b/packages/docs-drawing-ui/src/controllers/doc-drawing.controller.ts @@ -15,13 +15,12 @@ */ import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { IMenuItemFactory } from '@univerjs/ui'; -import { ComponentManager, IMenuService, IShortcutService } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service, IShortcutService } from '@univerjs/ui'; import { AddImageSingle } from '@univerjs/icons'; import { UploadFileMenu } from '../views/upload-component/UploadFile'; import { COMPONENT_DOC_UPLOAD_FILE_MENU } from '../views/upload-component/component-name'; -import { ImageMenuFactory, ImageUploadIcon, UploadFloatImageMenuFactory } from '../views/menu/image.menu'; +import { ImageUploadIcon } from '../views/menu/image.menu'; import { InsertDocImageOperation } from '../commands/operations/insert-image.operation'; import { COMPONENT_DOC_DRAWING_PANEL } from '../views/doc-image-panel/component-name'; import { DocDrawingPanel } from '../views/doc-image-panel/DocDrawingPanel'; @@ -38,13 +37,14 @@ import { GroupDocDrawingCommand } from '../commands/commands/group-doc-drawing.c import { InsertDocDrawingCommand } from '../commands/commands/insert-doc-drawing.command'; import { IMoveInlineDrawingCommand, ITransformNonInlineDrawingCommand, UpdateDocDrawingDistanceCommand, UpdateDocDrawingWrappingStyleCommand, UpdateDocDrawingWrapTextCommand, UpdateDrawingDocTransformCommand } from '../commands/commands/update-doc-drawing.command'; import { DeleteDrawingsShortcutItem, MoveDrawingDownShortcutItem, MoveDrawingLeftShortcutItem, MoveDrawingRightShortcutItem, MoveDrawingUpShortcutItem } from './shortcuts/drawing.shortcut'; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, DocDrawingUIController) export class DocDrawingUIController extends Disposable { constructor( @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService private readonly _commandService: ICommandService, @IShortcutService private readonly _shortcutService: IShortcutService ) { @@ -61,15 +61,7 @@ export class DocDrawingUIController extends Disposable { } private _initMenus(): void { - // init menus - ( - [ - ImageMenuFactory, - UploadFloatImageMenuFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), {})); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initCommands() { diff --git a/packages/docs-drawing-ui/src/controllers/menu.schema.ts b/packages/docs-drawing-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..0a0abda8fd --- /dev/null +++ b/packages/docs-drawing-ui/src/controllers/menu.schema.ts @@ -0,0 +1,37 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { + IMAGE_MENU_ID, + IMAGE_MENU_UPLOAD_FLOAT_ID, + ImageMenuFactory, + UploadFloatImageMenuFactory, +} from '../views/menu/image.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.LAYOUT]: { + [IMAGE_MENU_ID]: { + order: 0, + menuItemFactory: ImageMenuFactory, + [IMAGE_MENU_UPLOAD_FLOAT_ID]: { + order: 0, + menuItemFactory: UploadFloatImageMenuFactory, + }, + }, + }, +}; diff --git a/packages/docs-drawing-ui/src/plugin.ts b/packages/docs-drawing-ui/src/plugin.ts index 051863ef18..97e58739c0 100644 --- a/packages/docs-drawing-ui/src/plugin.ts +++ b/packages/docs-drawing-ui/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverDrawingUIPlugin } from '@univerjs/drawing-ui'; import { UniverDrawingPlugin } from '@univerjs/drawing'; @@ -27,6 +27,8 @@ import { DocDrawingTransformUpdateController } from './controllers/render-contro import { DocDrawingAddRemoveController } from './controllers/doc-drawing-notification.controller'; import { DocDrawingTransformerController } from './controllers/doc-drawing-transformer-update.controller'; import { DocRefreshDrawingsService } from './services/doc-refresh-drawings.service'; +import type { IUniverDocsDrawingUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'DOCS_DRAWING_UI_PLUGIN'; @@ -36,11 +38,16 @@ export class UniverDocsDrawingUIPlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - _config: undefined, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, - @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService + @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/docs-drawing-ui/src/views/menu/image.menu.ts b/packages/docs-drawing-ui/src/views/menu/image.menu.ts index d914963d45..b60ada9284 100644 --- a/packages/docs-drawing-ui/src/views/menu/image.menu.ts +++ b/packages/docs-drawing-ui/src/views/menu/image.menu.ts @@ -24,7 +24,7 @@ import { COMPONENT_DOC_UPLOAD_FILE_MENU } from '../upload-component/component-na export const ImageUploadIcon = 'addition-and-subtraction-single'; export const IMAGE_MENU_ID = 'doc.menu.image'; -const IMAGE_MENU_UPLOAD_FLOAT_ID = 'doc.menu.image.upload.float'; +export const IMAGE_MENU_UPLOAD_FLOAT_ID = 'doc.menu.image.upload.float'; // TODO: @Jocs, remove this when cell support drawing. const getDisableWhenSelectionInTableObservable = (accessor: IAccessor) => { diff --git a/packages/docs-drawing/src/controllers/config.schema.ts b/packages/docs-drawing/src/controllers/config.schema.ts new file mode 100644 index 0000000000..6c4b1a27af --- /dev/null +++ b/packages/docs-drawing/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'docs-drawing.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsDrawingConfig { +} + +export const defaultPluginConfig: IUniverDocsDrawingConfig = {}; diff --git a/packages/docs-drawing/src/plugin.ts b/packages/docs-drawing/src/plugin.ts index 6406a3c1c6..cd44529636 100644 --- a/packages/docs-drawing/src/plugin.ts +++ b/packages/docs-drawing/src/plugin.ts @@ -14,20 +14,27 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { DocDrawingController, DocDrawingLoadController, DOCS_DRAWING_PLUGIN } from './controllers/doc-drawing.controller'; import { DocDrawingService, IDocDrawingService } from './services/doc-drawing.service'; +import type { IUniverDocsDrawingConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverDocsDrawingPlugin extends Plugin { static override pluginName = DOCS_DRAWING_PLUGIN; static override type = UniverInstanceType.UNIVER_DOC; constructor( - _config: undefined, - @Inject(Injector) override _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/docs-hyper-link-ui/src/controllers/config.schema.ts b/packages/docs-hyper-link-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..13e6715b85 --- /dev/null +++ b/packages/docs-hyper-link-ui/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'docs-hyper-link-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsHyperLinkUIConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverDocsHyperLinkUIConfig = {}; diff --git a/packages/docs-hyper-link-ui/src/controllers/menu.schema.ts b/packages/docs-hyper-link-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..ea6c9ad710 --- /dev/null +++ b/packages/docs-hyper-link-ui/src/controllers/menu.schema.ts @@ -0,0 +1,37 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; +import { ShowDocHyperLinkEditPopupOperation } from '../commands/operations/popup.operation'; +import { AddHyperLinkMenuItemFactory } from './menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.OTHERS]: { + [ShowDocHyperLinkEditPopupOperation.id]: { + order: 0, + menuItemFactory: AddHyperLinkMenuItemFactory, + }, + }, + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.DATA]: { + [ShowDocHyperLinkEditPopupOperation.id]: { + order: 0, + menuItemFactory: AddHyperLinkMenuItemFactory, + }, + }, + }, +}; diff --git a/packages/docs-hyper-link-ui/src/controllers/ui.controller.ts b/packages/docs-hyper-link-ui/src/controllers/ui.controller.ts index 7c0972f4f3..a58dbbe1d7 100644 --- a/packages/docs-hyper-link-ui/src/controllers/ui.controller.ts +++ b/packages/docs-hyper-link-ui/src/controllers/ui.controller.ts @@ -16,7 +16,7 @@ import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService, IShortcutService } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service, IShortcutService } from '@univerjs/ui'; import { LinkSingle } from '@univerjs/icons'; import { DocHyperLinkEdit } from '../views/hyper-link-edit'; import { AddDocHyperLinkCommand } from '../commands/commands/add-link.command'; @@ -24,7 +24,8 @@ import { UpdateDocHyperLinkCommand } from '../commands/commands/update-link.comm import { DeleteDocHyperLinkCommand } from '../commands/commands/delete-link.command'; import { ClickDocHyperLinkOperation, ShowDocHyperLinkEditPopupOperation, ToggleDocHyperLinkInfoPopupOperation } from '../commands/operations/popup.operation'; import { DocLinkPopup } from '../views/hyper-link-popup'; -import { AddHyperLinkMenuItemFactory, addLinkShortcut, DOC_LINK_ICON } from './menu'; +import { addLinkShortcut, DOC_LINK_ICON } from './menu'; +import { menuSchema } from './menu.schema'; export interface IDocHyperLinkUIConfig { menu: MenuConfig; @@ -33,10 +34,9 @@ export interface IDocHyperLinkUIConfig { @OnLifecycle(LifecycleStages.Starting, DocHyperLinkUIController) export class DocHyperLinkUIController extends Disposable { constructor( - protected _config: IDocHyperLinkUIConfig, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, @ICommandService private readonly _commandService: ICommandService, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @Inject(Injector) private readonly _injector: Injector, @IShortcutService private readonly _shortcutService: IShortcutService ) { @@ -78,8 +78,6 @@ export class DocHyperLinkUIController extends Disposable { } private _initMenus() { - [AddHyperLinkMenuItemFactory].forEach((menuFactory) => { - this.disposeWithMe(this._menuService.addMenuItem(menuFactory(this._injector), {})); - }); + this._menu2Service.mergeMenu(menuSchema); } } diff --git a/packages/docs-hyper-link-ui/src/plugin.ts b/packages/docs-hyper-link-ui/src/plugin.ts index a2c5f36cb7..00ec99022f 100644 --- a/packages/docs-hyper-link-ui/src/plugin.ts +++ b/packages/docs-hyper-link-ui/src/plugin.ts @@ -14,17 +14,18 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { UniverDocsHyperLinkPlugin } from '@univerjs/docs-hyper-link'; import { DOC_HYPER_LINK_UI_PLUGIN } from './types/const'; -import type { IDocHyperLinkUIConfig } from './controllers/ui.controller'; import { DocHyperLinkUIController } from './controllers/ui.controller'; import { DocHyperLinkPopupService } from './services/hyper-link-popup.service'; import { DocHyperLinkSelectionController } from './controllers/doc-hyper-link-selection.controller'; import { DocHyperLinkRenderController } from './controllers/render-controllers/render.controller'; import { DocHyperLinkEventRenderController } from './controllers/render-controllers/hyper-link-event.render-controller'; +import type { IUniverDocsHyperLinkUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverDocsHyperLinkPlugin) export class UniverDocsHyperLinkUIPlugin extends Plugin { @@ -32,21 +33,25 @@ export class UniverDocsHyperLinkUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_DOC; constructor( - private _config: IDocHyperLinkUIConfig = { menu: {} }, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected override _injector: Injector, - @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService + @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { const deps: Dependency[] = [ [DocHyperLinkPopupService], - [DocHyperLinkUIController, - { - useFactory: () => this._injector.createInstance(DocHyperLinkUIController, this._config), - }, - ], + [DocHyperLinkUIController], [DocHyperLinkSelectionController], ]; diff --git a/packages/docs-hyper-link/package.json b/packages/docs-hyper-link/package.json index 61a5a868b3..e5995f8e41 100644 --- a/packages/docs-hyper-link/package.json +++ b/packages/docs-hyper-link/package.json @@ -20,8 +20,7 @@ "keywords": [], "exports": { ".": "./src/index.ts", - "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./*": "./src/*" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", @@ -41,8 +40,7 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*", - "./locale/*": "./lib/locale/*.json" + "./lib/*": "./lib/*" } }, "directories": { @@ -59,9 +57,7 @@ "build": "tsc && vite build" }, "peerDependencies": { - "@univerjs/core": "workspace:*", - "@univerjs/docs": "workspace:*", - "rxjs": ">=7.0.0" + "@univerjs/core": "workspace:*" }, "dependencies": { "@univerjs/icons": "^0.1.74" @@ -85,7 +81,6 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*", - "./locale/*": "./lib/locale/*.json" + "./lib/*": "./lib/*" } } diff --git a/packages/docs-hyper-link/src/controllers/config.schema.ts b/packages/docs-hyper-link/src/controllers/config.schema.ts new file mode 100644 index 0000000000..718dd1020f --- /dev/null +++ b/packages/docs-hyper-link/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'docs-hyper-link.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsHyperLinkConfig { +} + +export const defaultPluginConfig: IUniverDocsHyperLinkConfig = {}; diff --git a/packages/docs-hyper-link/src/plugin.ts b/packages/docs-hyper-link/src/plugin.ts index 1a80edb864..f9b42092a5 100644 --- a/packages/docs-hyper-link/src/plugin.ts +++ b/packages/docs-hyper-link/src/plugin.ts @@ -14,19 +14,26 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { DOC_HYPER_LINK_PLUGIN, DocHyperLinkResourceController } from './controllers/resource.controller'; +import type { IUniverDocsHyperLinkConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverDocsHyperLinkPlugin extends Plugin { static override pluginName = DOC_HYPER_LINK_PLUGIN; static override type = UniverInstanceType.UNIVER_DOC; constructor( - private _config: unknown, - @Inject(Injector) protected override _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected override _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/docs-mention-ui/src/controllers/config.schema.ts b/packages/docs-mention-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..7332dfb26c --- /dev/null +++ b/packages/docs-mention-ui/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'docs-mention-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsMentionUIConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverDocsMentionUIConfig = {}; diff --git a/packages/docs-mention-ui/src/controllers/menu.schema.ts b/packages/docs-mention-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..cf732b1e13 --- /dev/null +++ b/packages/docs-mention-ui/src/controllers/menu.schema.ts @@ -0,0 +1,16 @@ +/** + * 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. + */ + diff --git a/packages/docs-mention-ui/src/plugin.ts b/packages/docs-mention-ui/src/plugin.ts index c4a0d0578f..2f7fb144a9 100644 --- a/packages/docs-mention-ui/src/plugin.ts +++ b/packages/docs-mention-ui/src/plugin.ts @@ -14,23 +14,33 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { DOC_MENTION_UI_PLUGIN } from './types/const/const'; import { DocMentionPopupService } from './services/doc-mention-popup.service'; import { DocMentionUIController } from './controllers/doc-mention-ui.controller'; import { DocMentionTriggerController } from './controllers/doc-mention-trigger.controller'; import { DocMentionService } from './services/doc-mention.service'; +import type { IUniverDocsMentionUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverDocsMentionUIPlugin extends Plugin { static override pluginName = DOC_MENTION_UI_PLUGIN; static override type = UniverInstanceType.UNIVER_DOC; constructor( - private _config: unknown, - @Inject(Injector) protected override _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected override _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/docs-mention/src/controllers/config.schema.ts b/packages/docs-mention/src/controllers/config.schema.ts new file mode 100644 index 0000000000..3744667653 --- /dev/null +++ b/packages/docs-mention/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'docs-mention.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsMentionConfig { +} + +export const defaultPluginConfig: IUniverDocsMentionConfig = {}; diff --git a/packages/docs-thread-comment-ui/src/controllers/config.schema.ts b/packages/docs-thread-comment-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..2a25b23d75 --- /dev/null +++ b/packages/docs-thread-comment-ui/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'docs-thread-comment-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsThreadCommentUIConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverDocsThreadCommentUIConfig = {}; diff --git a/packages/docs-thread-comment-ui/src/controllers/doc-thread-comment-ui.controller.ts b/packages/docs-thread-comment-ui/src/controllers/doc-thread-comment-ui.controller.ts index a812e7c58d..2488e27900 100644 --- a/packages/docs-thread-comment-ui/src/controllers/doc-thread-comment-ui.controller.ts +++ b/packages/docs-thread-comment-ui/src/controllers/doc-thread-comment-ui.controller.ts @@ -14,27 +14,20 @@ * limitations under the License. */ -import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { Disposable, ICommandService, Inject, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { ComponentManager, IMenu2Service } from '@univerjs/ui'; import { CommentSingle } from '@univerjs/icons'; import { AddDocCommentComment } from '../commands/commands/add-doc-comment.command'; import { DocThreadCommentPanel } from '../views/doc-thread-comment-panel'; import { ShowCommentPanelOperation, StartAddCommentOperation, ToggleCommentPanelOperation } from '../commands/operations/show-comment-panel.operation'; import { DeleteDocCommentComment } from '../commands/commands/delete-doc-comment.command'; -import { AddDocCommentMenuItemFactory, ToolbarDocCommentMenuItemFactory } from './menu'; - -export interface IDocThreadCommentUIConfig { - menu: MenuConfig; -} +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Rendered, DocThreadCommentUIController) export class DocThreadCommentUIController extends Disposable { constructor( - private _config: IDocThreadCommentUIConfig, @ICommandService private readonly _commandService: ICommandService, - @IMenuService private readonly _menuService: IMenuService, - @Inject(Injector) private readonly _injector: Injector, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @Inject(ComponentManager) private readonly _componentManager: ComponentManager ) { super(); @@ -56,12 +49,7 @@ export class DocThreadCommentUIController extends Disposable { } private _initMenus() { - [ - AddDocCommentMenuItemFactory, - ToolbarDocCommentMenuItemFactory, - ].forEach((menuFactory) => { - this.disposeWithMe(this._menuService.addMenuItem(menuFactory(this._injector), this._config.menu)); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initComponents() { diff --git a/packages/docs-thread-comment-ui/src/controllers/menu.schema.ts b/packages/docs-thread-comment-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..8c20049555 --- /dev/null +++ b/packages/docs-thread-comment-ui/src/controllers/menu.schema.ts @@ -0,0 +1,40 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; +import { + StartAddCommentOperation, + ToggleCommentPanelOperation, +} from '../commands/operations/show-comment-panel.operation'; +import { AddDocCommentMenuItemFactory, ToolbarDocCommentMenuItemFactory } from './menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.OTHERS]: { + [ToggleCommentPanelOperation.id]: { + order: 1, + menuItemFactory: ToolbarDocCommentMenuItemFactory, + }, + }, + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.DATA]: { + [StartAddCommentOperation.id]: { + order: 1, + menuItemFactory: AddDocCommentMenuItemFactory, + }, + }, + }, +}; diff --git a/packages/docs-thread-comment-ui/src/plugin.ts b/packages/docs-thread-comment-ui/src/plugin.ts index c8b5330a78..862d556610 100644 --- a/packages/docs-thread-comment-ui/src/plugin.ts +++ b/packages/docs-thread-comment-ui/src/plugin.ts @@ -14,16 +14,17 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; import { IRenderManagerService } from '@univerjs/engine-render'; import { PLUGIN_NAME } from './common/const'; -import type { IDocThreadCommentUIConfig } from './controllers/doc-thread-comment-ui.controller'; import { DocThreadCommentUIController } from './controllers/doc-thread-comment-ui.controller'; import { DocThreadCommentService } from './services/doc-thread-comment.service'; import { DocThreadCommentSelectionController } from './controllers/doc-thread-comment-selection.controller'; import { DocThreadCommentRenderController } from './controllers/render-controllers/render.controller'; +import type { IUniverDocsThreadCommentUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverThreadCommentUIPlugin) export class UniverDocsThreadCommentUIPlugin extends Plugin { @@ -31,21 +32,24 @@ export class UniverDocsThreadCommentUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_DOC; constructor( - private _config: IDocThreadCommentUIConfig = { menu: {} }, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, - @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService + @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { ([ - [ - DocThreadCommentUIController, - { - useFactory: () => this._injector.createInstance(DocThreadCommentUIController, this._config), - }, - ], + [DocThreadCommentUIController], [DocThreadCommentSelectionController], [DocThreadCommentService], diff --git a/packages/docs-ui/src/basics/const/default-univer-doc-config.ts b/packages/docs-ui/src/basics/const/default-univer-doc-config.ts index fb2b3fa5bd..d58a0b8969 100644 --- a/packages/docs-ui/src/basics/const/default-univer-doc-config.ts +++ b/packages/docs-ui/src/basics/const/default-univer-doc-config.ts @@ -45,10 +45,3 @@ export const DefaultDocContainerConfig = { infoBar: true, toolbar: true, }; - -export const DefaultDocUiConfig = { - layout: { - docContainerConfig: DefaultDocContainerConfig, - toolbarConfig: DefaultToolbarConfig, - }, -}; diff --git a/packages/docs-ui/src/basics/interfaces/component-config/i-doc-ui-plugin-config.ts b/packages/docs-ui/src/basics/interfaces/component-config/i-doc-ui-plugin-config.ts index 529c239030..f8dafd77e9 100644 --- a/packages/docs-ui/src/basics/interfaces/component-config/i-doc-ui-plugin-config.ts +++ b/packages/docs-ui/src/basics/interfaces/component-config/i-doc-ui-plugin-config.ts @@ -14,21 +14,11 @@ * limitations under the License. */ -import type { DependencyOverride } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; - export interface ILayout { docContainerConfig?: DocContainerConfig; toolbarConfig?: DocToolbarConfig; } -export interface IUniverDocsUIConfig { - menu?: MenuConfig; - container?: HTMLElement | string; - layout?: ILayout; - override?: DependencyOverride; -} - export interface DocContainerConfig { outerLeft?: boolean; diff --git a/packages/docs-ui/src/controllers/app-ui-controller.ts b/packages/docs-ui/src/controllers/app-ui-controller.ts index 5a4b7c89df..dd37e8e385 100644 --- a/packages/docs-ui/src/controllers/app-ui-controller.ts +++ b/packages/docs-ui/src/controllers/app-ui-controller.ts @@ -14,26 +14,23 @@ * limitations under the License. */ -import type { LocaleType } from '@univerjs/core'; -import { Inject, Injector, LocaleService, Optional, RxDisposable } from '@univerjs/core'; +import { Inject, Injector, Optional, RxDisposable } from '@univerjs/core'; import { ILayoutService } from '@univerjs/ui'; import { ITextSelectionRenderManager } from '@univerjs/engine-render'; -import type { IUniverDocsUIConfig } from '../basics'; import { DocContainerUIController } from './doc-container-ui-controller'; export class AppUIController extends RxDisposable { private _docContainerController: DocContainerUIController; constructor( - _config: IUniverDocsUIConfig, - @Inject(LocaleService) private readonly _localeService: LocaleService, @Inject(Injector) private readonly _injector: Injector, @ITextSelectionRenderManager private readonly _textSelectionRenderManager: ITextSelectionRenderManager, @Optional(ILayoutService) private readonly _layoutService?: ILayoutService ) { super(); - this._docContainerController = this._injector.createInstance(DocContainerUIController, _config); + + this._docContainerController = this._injector.createInstance(DocContainerUIController); this._registerContainer(); } @@ -45,19 +42,4 @@ export class AppUIController extends RxDisposable { ); } } - - /** - * Change language - * @param {string} locale new language - * - * e: {target: HTMLSelectElement } reference from https://stackoverflow.com/a/48443771 - * - */ - changeLocale = (locale: string) => { - this._localeService.setLocale(locale as LocaleType); - }; - - getDocContainerController() { - return this._docContainerController; - } } diff --git a/packages/docs-ui/src/controllers/config.schema.ts b/packages/docs-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..e446683162 --- /dev/null +++ b/packages/docs-ui/src/controllers/config.schema.ts @@ -0,0 +1,38 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; +import type { DependencyOverride } from '@univerjs/core'; +import type { ILayout } from '../basics'; +import { DefaultDocContainerConfig, DefaultToolbarConfig } from '../basics'; + +export const PLUGIN_CONFIG_KEY = 'docs-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsUIConfig { + menu?: MenuConfig; + container?: HTMLElement | string; + layout?: ILayout; + override?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverDocsUIConfig = { + layout: { + docContainerConfig: DefaultDocContainerConfig, + toolbarConfig: DefaultToolbarConfig, + }, +}; diff --git a/packages/docs-ui/src/controllers/doc-container-ui-controller.ts b/packages/docs-ui/src/controllers/doc-container-ui-controller.ts index 33c84429de..899142f511 100644 --- a/packages/docs-ui/src/controllers/doc-container-ui-controller.ts +++ b/packages/docs-ui/src/controllers/doc-container-ui-controller.ts @@ -15,18 +15,19 @@ */ import type { LocaleType } from '@univerjs/core'; -import { Inject, Injector, LocaleService } from '@univerjs/core'; +import { IConfigService, Inject, Injector, LocaleService } from '@univerjs/core'; -import type { IUniverDocsUIConfig } from '../basics'; import type { DocContainer } from '../views/doc-container/DocContainer'; +import type { IUniverDocsUIConfig } from './config.schema'; +import { PLUGIN_CONFIG_KEY } from './config.schema'; export class DocContainerUIController { private _docContainer?: DocContainer; constructor( - private readonly _config: IUniverDocsUIConfig, @Inject(LocaleService) private readonly _localeService: LocaleService, - @Inject(Injector) private readonly _injector: Injector + @Inject(Injector) private readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { // empty } @@ -34,7 +35,7 @@ export class DocContainerUIController { getUIConfig() { const config = { injector: this._injector, - config: this._config, + config: this._configService.getConfig(PLUGIN_CONFIG_KEY), changeLocale: this.changeLocale, getComponent: this.getComponent, }; diff --git a/packages/docs-ui/src/controllers/doc-ui.controller.ts b/packages/docs-ui/src/controllers/doc-ui.controller.ts index 586320a7f4..1fcd1e22bd 100644 --- a/packages/docs-ui/src/controllers/doc-ui.controller.ts +++ b/packages/docs-ui/src/controllers/doc-ui.controller.ts @@ -14,9 +14,19 @@ * limitations under the License. */ -import { connectInjector, Disposable, ICommandService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; -import type { IMenuItemFactory } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, ILayoutService, IMenuService, IShortcutService, IUIPartsService } from '@univerjs/ui'; +import { + connectInjector, + Disposable, + ICommandService, + IConfigService, + Inject, + Injector, + IUniverInstanceService, + LifecycleStages, + OnLifecycle, + UniverInstanceType, +} from '@univerjs/core'; +import { BuiltInUIPart, ComponentManager, ILayoutService, IMenu2Service, IShortcutService, IUIPartsService } from '@univerjs/ui'; import { ITextSelectionRenderManager } from '@univerjs/engine-render'; import { TodoList } from '@univerjs/icons'; @@ -28,7 +38,6 @@ import { FontFamilyItem, } from '../components/font-family'; import { FONT_SIZE_COMPONENT, FontSize } from '../components/font-size'; -import type { IUniverDocsUIConfig } from '../basics'; import { CoreHeaderFooterCommand, OpenHeaderFooterPanelCommand } from '../commands/commands/doc-header-footer.command'; import { SidebarDocHeaderFooterPanelOperation } from '../commands/operations/doc-header-footer-panel.operation'; import { DocFooter } from '../views/doc-footer'; @@ -48,44 +57,23 @@ import { } from '../shortcuts/toolbar.shortcut'; import { TabShortCut } from '../shortcuts/format.shortcut'; import { BULLET_LIST_TYPE_COMPONENT, BulletListTypePicker, ORDER_LIST_TYPE_COMPONENT, OrderListTypePicker } from '../components/list-type-picker'; -import { - AlignCenterMenuItemFactory, - AlignJustifyMenuItemFactory, - AlignLeftMenuItemFactory, - AlignRightMenuItemFactory, - BackgroundColorSelectorMenuItemFactory, - BoldMenuItemFactory, - BulletListMenuItemFactory, - CheckListMenuItemFactory, - FontFamilySelectorMenuItemFactory, - FontSizeSelectorMenuItemFactory, - HeaderFooterMenuItemFactory, - InsertTableMenuFactory, - ItalicMenuItemFactory, - OrderListMenuItemFactory, - ResetBackgroundColorMenuItemFactory, - StrikeThroughMenuItemFactory, - SubscriptMenuItemFactory, - SuperscriptMenuItemFactory, - TableMenuFactory, - TextColorSelectorMenuItemFactory, - UnderlineMenuItemFactory, -} from './menu/menu'; -import { CopyMenuFactory, CutMenuFactory, DeleteColumnsMenuItemFactory, DeleteMenuFactory, DeleteRowsMenuItemFactory, DeleteTableMenuItemFactory, InsertColumnLeftMenuItemFactory, InsertColumnRightMenuItemFactory, InsertRowAfterMenuItemFactory, InsertRowBeforeMenuItemFactory, ParagraphSettingMenuFactory, PasteMenuFactory, TableDeleteMenuItemFactory, TableInsertMenuItemFactory } from './menu/context-menu'; +import { menuSchema } from './menu.schema'; +import type { IUniverDocsUIConfig } from './config.schema'; +import { PLUGIN_CONFIG_KEY } from './config.schema'; // FIXME: LifecycleStages.Rendered must be used, otherwise the menu cannot be added to the DOM, but the sheet ui plug-in can be added in LifecycleStages.Ready @OnLifecycle(LifecycleStages.Rendered, DocUIController) export class DocUIController extends Disposable { constructor( - protected readonly _config: Partial, @Inject(Injector) protected readonly _injector: Injector, @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, @ICommandService protected readonly _commandService: ICommandService, @ILayoutService protected readonly _layoutService: ILayoutService, - @IMenuService protected readonly _menuService: IMenuService, + @IMenu2Service protected readonly _menu2Service: IMenu2Service, @IUIPartsService protected readonly _uiPartsService: IUIPartsService, @IUniverInstanceService protected readonly _univerInstanceService: IUniverInstanceService, - @IShortcutService protected readonly _shortcutService: IShortcutService + @IShortcutService protected readonly _shortcutService: IShortcutService, + @IConfigService protected readonly _configService: IConfigService ) { super(); @@ -106,65 +94,14 @@ export class DocUIController extends Disposable { private _initUiParts() { const workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); - if (this._config.layout?.docContainerConfig?.footer && !workbook) { + const config = this._configService.getConfig(PLUGIN_CONFIG_KEY); + if (config?.layout?.docContainerConfig?.footer && !workbook) { this.disposeWithMe(this._uiPartsService.registerComponent(BuiltInUIPart.FOOTER, () => connectInjector(DocFooter, this._injector))); } } private _initMenus(): void { - const { menu = {} } = this._config; - - // init menus - ( - [ - BoldMenuItemFactory, - ItalicMenuItemFactory, - UnderlineMenuItemFactory, - StrikeThroughMenuItemFactory, - SubscriptMenuItemFactory, - SuperscriptMenuItemFactory, - FontSizeSelectorMenuItemFactory, - FontFamilySelectorMenuItemFactory, - TextColorSelectorMenuItemFactory, - HeaderFooterMenuItemFactory, - TableMenuFactory, - InsertTableMenuFactory, - AlignLeftMenuItemFactory, - AlignCenterMenuItemFactory, - AlignRightMenuItemFactory, - AlignJustifyMenuItemFactory, - OrderListMenuItemFactory, - BulletListMenuItemFactory, - CheckListMenuItemFactory, - ResetBackgroundColorMenuItemFactory, - BackgroundColorSelectorMenuItemFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); - - ([ - CopyMenuFactory, - CutMenuFactory, - PasteMenuFactory, - DeleteMenuFactory, - ParagraphSettingMenuFactory, - TableInsertMenuItemFactory, - InsertRowBeforeMenuItemFactory, - InsertRowAfterMenuItemFactory, - InsertColumnLeftMenuItemFactory, - InsertColumnRightMenuItemFactory, - TableDeleteMenuItemFactory, - DeleteRowsMenuItemFactory, - DeleteColumnsMenuItemFactory, - DeleteTableMenuItemFactory, - ] as IMenuItemFactory[]).forEach((factory) => { - try { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - } catch (error) { - - } - }); + this._menu2Service.mergeMenu(menuSchema); } private _initShortCut() { diff --git a/packages/docs-ui/src/controllers/menu.schema.ts b/packages/docs-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..9abf14c5f8 --- /dev/null +++ b/packages/docs-ui/src/controllers/menu.schema.ts @@ -0,0 +1,245 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; +import { + AlignCenterCommand, + AlignJustifyCommand, + AlignLeftCommand, + AlignRightCommand, + BulletListCommand, + CheckListCommand, + DeleteLeftCommand, + DocTableDeleteColumnsCommand, + DocTableDeleteRowsCommand, + DocTableDeleteTableCommand, + DocTableInsertColumnLeftCommand, + DocTableInsertColumnRightCommand, + DocTableInsertRowAboveCommand, + DocTableInsertRowBellowCommand, + OrderListCommand, + ResetInlineFormatTextBackgroundColorCommand, + SetInlineFormatBoldCommand, + SetInlineFormatFontFamilyCommand, + SetInlineFormatFontSizeCommand, + SetInlineFormatItalicCommand, + SetInlineFormatStrikethroughCommand, + SetInlineFormatSubscriptCommand, + SetInlineFormatSuperscriptCommand, + SetInlineFormatTextBackgroundColorCommand, + SetInlineFormatTextColorCommand, + SetInlineFormatUnderlineCommand, +} from '@univerjs/docs'; +import { DocCreateTableOperation } from '../commands/operations/doc-create-table.operation'; +import { OpenHeaderFooterPanelCommand } from '../commands/commands/doc-header-footer.command'; +import { DocCopyCommand, DocCutCommand, DocPasteCommand } from '../commands/commands/clipboard.command'; +import { DocParagraphSettingPanelOperation } from '../commands/operations/doc-paragraph-setting-panel.operation'; +import { + AlignCenterMenuItemFactory, + AlignJustifyMenuItemFactory, + AlignLeftMenuItemFactory, + AlignRightMenuItemFactory, + BackgroundColorSelectorMenuItemFactory, + BoldMenuItemFactory, + BulletListMenuItemFactory, + CheckListMenuItemFactory, + FontFamilySelectorMenuItemFactory, + FontSizeSelectorMenuItemFactory, + HeaderFooterMenuItemFactory, + InsertTableMenuFactory, + ItalicMenuItemFactory, + OrderListMenuItemFactory, + ResetBackgroundColorMenuItemFactory, + StrikeThroughMenuItemFactory, + SubscriptMenuItemFactory, + SuperscriptMenuItemFactory, + TABLE_MENU_ID, + TableMenuFactory, + TextColorSelectorMenuItemFactory, + UnderlineMenuItemFactory, +} from './menu/menu'; +import { + CopyMenuFactory, + CutMenuFactory, + DeleteColumnsMenuItemFactory, + DeleteMenuFactory, + DeleteRowsMenuItemFactory, + DeleteTableMenuItemFactory, + InsertColumnLeftMenuItemFactory, + InsertColumnRightMenuItemFactory, + InsertRowAfterMenuItemFactory, + InsertRowBeforeMenuItemFactory, + ParagraphSettingMenuFactory, + PasteMenuFactory, + TABLE_DELETE_MENU_ID, + TABLE_INSERT_MENU_ID, + TableDeleteMenuItemFactory, + TableInsertMenuItemFactory, +} from './menu/context-menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMAT]: { + [SetInlineFormatBoldCommand.id]: { + order: 0, + menuItemFactory: BoldMenuItemFactory, + }, + [SetInlineFormatItalicCommand.id]: { + order: 1, + menuItemFactory: ItalicMenuItemFactory, + }, + [SetInlineFormatUnderlineCommand.id]: { + order: 2, + menuItemFactory: UnderlineMenuItemFactory, + }, + [SetInlineFormatStrikethroughCommand.id]: { + order: 3, + menuItemFactory: StrikeThroughMenuItemFactory, + }, + [SetInlineFormatSubscriptCommand.id]: { + order: 4, + menuItemFactory: SubscriptMenuItemFactory, + }, + [SetInlineFormatSuperscriptCommand.id]: { + order: 5, + menuItemFactory: SuperscriptMenuItemFactory, + }, + [SetInlineFormatFontSizeCommand.id]: { + order: 6, + menuItemFactory: FontSizeSelectorMenuItemFactory, + }, + [SetInlineFormatFontFamilyCommand.id]: { + order: 7, + menuItemFactory: FontFamilySelectorMenuItemFactory, + }, + [SetInlineFormatTextColorCommand.id]: { + order: 8, + menuItemFactory: TextColorSelectorMenuItemFactory, + }, + [SetInlineFormatTextBackgroundColorCommand.id]: { + order: 9, + menuItemFactory: BackgroundColorSelectorMenuItemFactory, + [ResetInlineFormatTextBackgroundColorCommand.id]: { + order: 0, + menuItemFactory: ResetBackgroundColorMenuItemFactory, + }, + }, + }, + [RibbonStartGroup.LAYOUT]: { + [TABLE_MENU_ID]: { + order: 1, + menuItemFactory: TableMenuFactory, + [DocCreateTableOperation.id]: { + order: 0, + menuItemFactory: InsertTableMenuFactory, + }, + }, + [AlignLeftCommand.id]: { + order: 2, + menuItemFactory: AlignLeftMenuItemFactory, + }, + [AlignCenterCommand.id]: { + order: 3, + menuItemFactory: AlignCenterMenuItemFactory, + }, + [AlignRightCommand.id]: { + order: 4, + menuItemFactory: AlignRightMenuItemFactory, + }, + [AlignJustifyCommand.id]: { + order: 5, + menuItemFactory: AlignJustifyMenuItemFactory, + }, + [OrderListCommand.id]: { + order: 6, + menuItemFactory: OrderListMenuItemFactory, + }, + [BulletListCommand.id]: { + order: 7, + menuItemFactory: BulletListMenuItemFactory, + }, + [CheckListCommand.id]: { + order: 8, + menuItemFactory: CheckListMenuItemFactory, + }, + [OpenHeaderFooterPanelCommand.id]: { + order: 9, + menuItemFactory: HeaderFooterMenuItemFactory, + }, + }, + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.FORMAT]: { + [DocCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuFactory, + }, + [DocCutCommand.id]: { + order: 1, + menuItemFactory: CutMenuFactory, + }, + [DocPasteCommand.id]: { + order: 2, + menuItemFactory: PasteMenuFactory, + }, + [DeleteLeftCommand.id]: { + order: 3, + menuItemFactory: DeleteMenuFactory, + }, + }, + [ContextMenuGroup.LAYOUT]: { + [DocParagraphSettingPanelOperation.id]: { + order: 0, + menuItemFactory: ParagraphSettingMenuFactory, + }, + [TABLE_INSERT_MENU_ID]: { + order: 1, + menuItemFactory: TableInsertMenuItemFactory, + [DocTableInsertRowAboveCommand.id]: { + order: 1, + menuItemFactory: InsertRowBeforeMenuItemFactory, + }, + [DocTableInsertRowBellowCommand.id]: { + order: 2, + menuItemFactory: InsertRowAfterMenuItemFactory, + }, + [DocTableInsertColumnLeftCommand.id]: { + order: 3, + menuItemFactory: InsertColumnLeftMenuItemFactory, + }, + [DocTableInsertColumnRightCommand.id]: { + order: 4, + menuItemFactory: InsertColumnRightMenuItemFactory, + }, + }, + [TABLE_DELETE_MENU_ID]: { + order: 2, + menuItemFactory: TableDeleteMenuItemFactory, + [DocTableDeleteRowsCommand.id]: { + order: 1, + menuItemFactory: DeleteRowsMenuItemFactory, + }, + [DocTableDeleteColumnsCommand.id]: { + order: 2, + menuItemFactory: DeleteColumnsMenuItemFactory, + }, + [DocTableDeleteTableCommand.id]: { + order: 3, + menuItemFactory: DeleteTableMenuItemFactory, + }, + }, + }, + }, +}; diff --git a/packages/docs-ui/src/controllers/menu/context-menu.ts b/packages/docs-ui/src/controllers/menu/context-menu.ts index 88f6f07b93..5e4bd2acbc 100644 --- a/packages/docs-ui/src/controllers/menu/context-menu.ts +++ b/packages/docs-ui/src/controllers/menu/context-menu.ts @@ -148,7 +148,7 @@ export const DeleteMenuFactory = (accessor: IAccessor): IMenuButtonItem => { }; }; -const TABLE_INSERT_MENU_ID = 'doc.menu.table-insert'; +export const TABLE_INSERT_MENU_ID = 'doc.menu.table-insert'; export function TableInsertMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: TABLE_INSERT_MENU_ID, @@ -211,7 +211,7 @@ export function InsertColumnRightMenuItemFactory(accessor: IAccessor): IMenuButt }; } -const TABLE_DELETE_MENU_ID = 'doc.menu.table-delete'; +export const TABLE_DELETE_MENU_ID = 'doc.menu.table-delete'; export function TableDeleteMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: TABLE_DELETE_MENU_ID, diff --git a/packages/docs-ui/src/controllers/render-controllers/contextmenu.render-controller.ts b/packages/docs-ui/src/controllers/render-controllers/contextmenu.render-controller.ts index 7c40812bf0..8e0d9d0540 100644 --- a/packages/docs-ui/src/controllers/render-controllers/contextmenu.render-controller.ts +++ b/packages/docs-ui/src/controllers/render-controllers/contextmenu.render-controller.ts @@ -26,7 +26,7 @@ import { } from '@univerjs/core'; import { RichTextEditingMutation, TextSelectionManagerService } from '@univerjs/docs'; import type { Documents, IRenderContext, IRenderModule } from '@univerjs/engine-render'; -import { IContextMenuService, MenuPosition } from '@univerjs/ui'; +import { ContextMenuPosition, IContextMenuService } from '@univerjs/ui'; const SKIP_UNIT_IDS = [ DEFAULT_EMPTY_DOCUMENT_VALUE, @@ -59,7 +59,7 @@ export class DocContextMenuRenderController extends Disposable implements IRende // Content range context menu const documentsSubscription = documentsPointerDownObserver.subscribeEvent((event) => { if (event.button === 2) { - this._contextMenuService.triggerContextMenu(event, MenuPosition.CONTEXT_MENU); + this._contextMenuService.triggerContextMenu(event, ContextMenuPosition.MAIN_AREA); } }); this.disposeWithMe(documentsSubscription); diff --git a/packages/docs-ui/src/controllers/render-controllers/doc.render-controller.ts b/packages/docs-ui/src/controllers/render-controllers/doc.render-controller.ts index 3893971825..7b1e890b0c 100644 --- a/packages/docs-ui/src/controllers/render-controllers/doc.render-controller.ts +++ b/packages/docs-ui/src/controllers/render-controllers/doc.render-controller.ts @@ -108,11 +108,12 @@ export class DocRenderController extends RxDisposable implements IRenderModule { }); // TODO@wzhudev: this shouldn't be a config, because we may render different units at the same time. - const hasScroll = this._configService.getConfig('hasScroll') as Nullable; - if (hasScroll !== false) { - // eslint-disable-next-line no-new - new ScrollBar(viewMain); - } + // @jikkai: hasScroll has never been set before, so I commented it out. + // const hasScroll = this._configService.getConfig('hasScroll') as Nullable; + // if (hasScroll !== false) { + // eslint-disable-next-line no-new + new ScrollBar(viewMain); + // } scene.addLayer( new Layer(scene, [], DOCS_COMPONENT_MAIN_LAYER_INDEX), diff --git a/packages/docs-ui/src/docs-ui-plugin.ts b/packages/docs-ui/src/docs-ui-plugin.ts index 56133b84b2..fe05f2f048 100644 --- a/packages/docs-ui/src/docs-ui-plugin.ts +++ b/packages/docs-ui/src/docs-ui-plugin.ts @@ -16,15 +16,15 @@ import type { Dependency } from '@univerjs/core'; -import { - ICommandService, +import { ICommandService, + + IConfigService, ILogService, Inject, Injector, IUniverInstanceService, mergeOverrideWithDependencies, - Plugin, - Tools, UniverInstanceType } from '@univerjs/core'; + Plugin, UniverInstanceType } from '@univerjs/core'; import { IEditorService, IShortcutService } from '@univerjs/ui'; import { IRenderManagerService } from '@univerjs/engine-render'; import { DocInterceptorService, DocSkeletonManagerService } from '@univerjs/docs'; @@ -39,8 +39,6 @@ import { MoveSelectionUpShortcut, SelectAllShortcut, } from './shortcuts/cursor.shortcut'; -import type { IUniverDocsUIConfig } from './basics'; -import { DefaultDocUiConfig } from './basics'; import { DOC_UI_PLUGIN_NAME } from './basics/const/plugin-name'; import { AppUIController } from './controllers'; import { DocUIController } from './controllers/doc-ui.controller'; @@ -67,21 +65,30 @@ import { DocParagraphSettingController } from './controllers/doc-paragraph-setti import { DocParagraphSettingPanelOperation } from './commands/operations/doc-paragraph-setting-panel.operation'; import { DocParagraphSettingCommand } from './commands/commands/doc-paragraph-setting.command'; import { DocTableController } from './controllers/doc-table.controller'; +import type { IUniverDocsUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverDocsUIPlugin extends Plugin { static override pluginName = DOC_UI_PLUGIN_NAME; static override type = UniverInstanceType.UNIVER_DOC; constructor( - private readonly _config: IUniverDocsUIConfig, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override _injector: Injector, @IRenderManagerService private readonly _renderManagerSrv: IRenderManagerService, @ICommandService private _commandService: ICommandService, - @ILogService private _logService: ILogService + @ILogService private _logService: ILogService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultDocUiConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + this._initDependencies(_injector); this._initializeShortcut(); this._initCommand(); @@ -127,14 +134,14 @@ export class UniverDocsUIPlugin extends Plugin { private _initDependencies(injector: Injector) { const dependencies: Dependency[] = [ - [DocUIController, { useFactory: () => this._injector.createInstance(DocUIController, this._config) }], + [DocUIController], [DocClipboardController], [DocEditorBridgeController], [DocAutoFormatController], [DocTableController], [DocsRenderService], - [AppUIController, { useFactory: () => this._injector.createInstance(AppUIController, this._config) }], + [AppUIController], [IDocClipboardService, { useClass: DocClipboardService }], [DocCanvasPopManagerService], [DocParagraphSettingController], diff --git a/packages/docs-ui/src/index.ts b/packages/docs-ui/src/index.ts index a44dace3c9..2b24f91fc7 100644 --- a/packages/docs-ui/src/index.ts +++ b/packages/docs-ui/src/index.ts @@ -26,8 +26,10 @@ export { DocCanvasPopManagerService } from './services/doc-popup-manager.service export { docDrawingPositionToTransform, transformToDocDrawingPosition } from './basics/transform-position'; export { DocEventManagerService } from './services/doc-event-manager.service'; export { DocUIController } from './controllers/doc-ui.controller'; -// #region - all commands +export { menuSchema } from './controllers/menu.schema'; + +// #region - all commands export { DocCopyCommand, DocCutCommand, DocPasteCommand } from './commands/commands/clipboard.command'; export { DocCreateTableOperation } from './commands/operations/doc-create-table.operation'; // #endregion diff --git a/packages/docs-ui/src/views/doc-container/DocContainer.tsx b/packages/docs-ui/src/views/doc-container/DocContainer.tsx index 789dd6bb7a..fe0211b04d 100644 --- a/packages/docs-ui/src/views/doc-container/DocContainer.tsx +++ b/packages/docs-ui/src/views/doc-container/DocContainer.tsx @@ -16,7 +16,7 @@ import React, { Component, createRef } from 'react'; -import type { IUniverDocsUIConfig } from '../../basics'; +import type { IUniverDocsUIConfig } from '../../controllers/config.schema'; import style from './index.module.less'; interface IBaseDocContainerProps { @@ -43,6 +43,7 @@ export class DocContainer extends Component { constructor(props: IBaseDocContainerProps) { super(props); + this.changeSkin(props.config.container as string, 'default'); } diff --git a/packages/docs/src/controllers/config.schema.ts b/packages/docs/src/controllers/config.schema.ts new file mode 100644 index 0000000000..ab2be48d5b --- /dev/null +++ b/packages/docs/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'docs.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDocsConfig { +} + +export const defaultPluginConfig: IUniverDocsConfig = {}; diff --git a/packages/docs/src/doc-plugin.ts b/packages/docs/src/doc-plugin.ts index b308143694..7cc0abac39 100644 --- a/packages/docs/src/doc-plugin.ts +++ b/packages/docs/src/doc-plugin.ts @@ -17,6 +17,7 @@ import type { Dependency, ICommand } from '@univerjs/core'; import { ICommandService, + IConfigService, Inject, Injector, Plugin, @@ -64,10 +65,8 @@ import { CreateDocTableCommand } from './commands/commands/table/doc-table-creat import { DocTableDeleteColumnsCommand, DocTableDeleteRowsCommand, DocTableDeleteTableCommand } from './commands/commands/table/doc-table-delete.command'; import { DocTableInsertColumnCommand, DocTableInsertColumnLeftCommand, DocTableInsertColumnRightCommand, DocTableInsertRowAboveCommand, DocTableInsertRowBellowCommand, DocTableInsertRowCommand } from './commands/commands/table/doc-table-insert.command'; import { DocTableTabCommand } from './commands/commands/table/doc-table-tab.command'; - -export interface IUniverDocsConfig { - hasScroll?: boolean; -} +import type { IUniverDocsConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'DOCS_PLUGIN'; @@ -76,10 +75,16 @@ export class UniverDocsPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_DOC; constructor( - _config: Partial = {}, - @Inject(Injector) override _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + this._initializeDependencies(_injector); this._initializeCommands(); diff --git a/packages/docs/src/index.ts b/packages/docs/src/index.ts index dd09cb99ff..6934083342 100644 --- a/packages/docs/src/index.ts +++ b/packages/docs/src/index.ts @@ -22,7 +22,7 @@ export type { IDocObjectParam } from './basics/component-tools'; export { getDocObject, neoGetDocObject, getDocObjectById } from './basics/component-tools'; export * from './basics/docs-view-key'; -export { type IUniverDocsConfig, UniverDocsPlugin } from './doc-plugin'; +export { UniverDocsPlugin } from './doc-plugin'; export { DocSkeletonManagerService } from './services/doc-skeleton-manager.service'; export { TextSelectionManagerService, serializeDocRange } from './services/text-selection-manager.service'; export { DocStateChangeManagerService, type IDocStateChangeParams } from './services/doc-state-change-manager.service'; diff --git a/packages/drawing-ui/src/controllers/config.schema.ts b/packages/drawing-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..e4440f0434 --- /dev/null +++ b/packages/drawing-ui/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'drawing-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDrawingUIConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverDrawingUIConfig = {}; diff --git a/packages/drawing-ui/src/controllers/drawing-ui.controller.ts b/packages/drawing-ui/src/controllers/drawing-ui.controller.ts index 7d399a04a7..577e77e2bf 100644 --- a/packages/drawing-ui/src/controllers/drawing-ui.controller.ts +++ b/packages/drawing-ui/src/controllers/drawing-ui.controller.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Disposable, ICommandService, Inject, Injector, LifecycleStages, LocaleService, OnLifecycle } from '@univerjs/core'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { Disposable, ICommandService, Inject, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { ComponentManager } from '@univerjs/ui'; import { COMPONENT_IMAGE_POPUP_MENU } from '../views/image-popup-menu/component-name'; import { ImagePopupMenu } from '../views/image-popup-menu/ImagePopupMenu'; import { AutoImageCropOperation, CloseImageCropOperation, OpenImageCropOperation } from '../commands/operations/image-crop.operation'; @@ -27,11 +27,8 @@ import { SetDrawingAlignOperation } from '../commands/operations/drawing-align.o @OnLifecycle(LifecycleStages.Rendered, DrawingUIController) export class DrawingUIController extends Disposable { constructor( - @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, - @IMenuService private readonly _menuService: IMenuService, - @ICommandService private readonly _commandService: ICommandService, - @Inject(LocaleService) private readonly _localeService: LocaleService + @ICommandService private readonly _commandService: ICommandService ) { super(); @@ -44,17 +41,6 @@ export class DrawingUIController extends Disposable { this.disposeWithMe(componentManager.register(COMPONENT_IMAGE_VIEWER, ImageViewer)); } - private _initMenus(): void { - // init menus - // ( - // [ - - // ] as IMenuItemFactory[] - // ).forEach((factory) => { - // this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory))); - // }); - } - private _initCommands() { [ OpenImageCropOperation, @@ -68,6 +54,5 @@ export class DrawingUIController extends Disposable { private _init(): void { this._initCommands(); this._initCustomComponents(); - this._initMenus(); } } diff --git a/packages/drawing-ui/src/plugin.ts b/packages/drawing-ui/src/plugin.ts index 807991b5a3..e3115babf5 100644 --- a/packages/drawing-ui/src/plugin.ts +++ b/packages/drawing-ui/src/plugin.ts @@ -14,13 +14,15 @@ * limitations under the License. */ -import { Inject, Injector, LocaleService, Plugin } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { DrawingUpdateController } from './controllers/drawing-update.controller'; import { DrawingUIController } from './controllers/drawing-ui.controller'; import { ImageCropperController } from './controllers/image-cropper.controller'; import { ImageUpdateController } from './controllers/image-update.controller'; import { DrawingRenderService } from './services/drawing-render.service'; +import type { IUniverDrawingUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'DRAWING_UI_PLUGIN'; @@ -28,11 +30,18 @@ export class UniverDrawingUIPlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - config: undefined, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/drawing/src/controllers/config.schema.ts b/packages/drawing/src/controllers/config.schema.ts new file mode 100644 index 0000000000..09fd3c2e67 --- /dev/null +++ b/packages/drawing/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { DependencyOverride } from '@univerjs/core'; + +export const PLUGIN_CONFIG_KEY = 'drawing.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverDrawingConfig { + override?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverDrawingConfig = {}; diff --git a/packages/drawing/src/plugin.ts b/packages/drawing/src/plugin.ts index 9c5bfa2d6e..0cf8062c82 100644 --- a/packages/drawing/src/plugin.ts +++ b/packages/drawing/src/plugin.ts @@ -14,13 +14,15 @@ * limitations under the License. */ -import type { Dependency, DependencyOverride } from '@univerjs/core'; -import { Inject, Injector, mergeOverrideWithDependencies, Plugin } from '@univerjs/core'; +import type { Dependency } from '@univerjs/core'; +import { IConfigService, Inject, Injector, mergeOverrideWithDependencies, Plugin } from '@univerjs/core'; import { ImageIoService } from './services/image-io-impl.service'; import { DrawingManagerService } from './services/drawing-manager-impl.service'; import { IImageIoService } from './services/image-io.service'; import { IDrawingManagerService } from './services/drawing-manager.service'; +import type { IUniverDrawingConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'DRAWING_PLUGIN'; @@ -28,10 +30,15 @@ export class UniverDrawingPlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - private _config: { override?: DependencyOverride }, - @Inject(Injector) protected _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/engine-formula/src/controller/config.schema.ts b/packages/engine-formula/src/controller/config.schema.ts new file mode 100644 index 0000000000..804a84348b --- /dev/null +++ b/packages/engine-formula/src/controller/config.schema.ts @@ -0,0 +1,30 @@ +/** + * 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 { Ctor } from '@univerjs/core'; +import type { BaseFunction } from '../functions/base-function'; +import type { IFunctionNames } from '../basics/function'; + +export const PLUGIN_CONFIG_KEY = 'engine-formula.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverEngineFormulaConfig { + notExecuteFormula?: boolean; + function?: Array<[Ctor, IFunctionNames]>; +} + +export const defaultPluginConfig: IUniverEngineFormulaConfig = {}; diff --git a/packages/engine-formula/src/controller/formula.controller.ts b/packages/engine-formula/src/controller/formula.controller.ts index 7f1e35f866..cdea2e4cd0 100644 --- a/packages/engine-formula/src/controller/formula.controller.ts +++ b/packages/engine-formula/src/controller/formula.controller.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Disposable, ICommandService, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { Disposable, ICommandService, IConfigService, LifecycleStages, OnLifecycle } from '@univerjs/core'; import { type Ctor, Optional } from '@univerjs/core'; import { DataSyncPrimaryController } from '@univerjs/rpc'; @@ -57,13 +57,15 @@ import { functionText } from '../functions/text/function-map'; import { functionUniver } from '../functions/univer/function-map'; import { functionWeb } from '../functions/web/function-map'; import { IFunctionService } from '../services/function.service'; +import type { IUniverEngineFormulaConfig } from './config.schema'; +import { PLUGIN_CONFIG_KEY } from './config.schema'; @OnLifecycle(LifecycleStages.Ready, FormulaController) export class FormulaController extends Disposable { constructor( - private _function: Array<[Ctor, IFunctionNames]> = [], @ICommandService private readonly _commandService: ICommandService, @IFunctionService private readonly _functionService: IFunctionService, + @IConfigService private readonly _configService: IConfigService, @Optional(DataSyncPrimaryController) private readonly _dataSyncPrimaryController?: DataSyncPrimaryController ) { super(); @@ -103,6 +105,8 @@ export class FormulaController extends Disposable { } private _registerFunctions() { + const config = this._configService.getConfig(PLUGIN_CONFIG_KEY); + const functions: BaseFunction[] = ( [ ...functionArray, @@ -123,7 +127,7 @@ export class FormulaController extends Disposable { ...functionWeb, ] as Array<[Ctor, IFunctionNames]> ) - .concat(this._function) + .concat(config?.function ?? []) .map((registerObject) => { const Func = registerObject[0] as Ctor; const name = registerObject[1] as IFunctionNames; diff --git a/packages/engine-formula/src/plugin.ts b/packages/engine-formula/src/plugin.ts index 478d420f2d..bc6ee43fd9 100644 --- a/packages/engine-formula/src/plugin.ts +++ b/packages/engine-formula/src/plugin.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { Inject, Injector, Plugin } from '@univerjs/core'; -import type { Ctor, Dependency } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; +import type { Dependency } from '@univerjs/core'; -import type { IFunctionNames } from './basics/function'; import { CalculateController } from './controller/calculate.controller'; import { FormulaController } from './controller/formula.controller'; import { SetDefinedNameController } from './controller/set-defined-name.controller'; @@ -39,7 +38,6 @@ import { UnionNodeFactory } from './engine/ast-node/union-node'; import { ValueNodeFactory } from './engine/ast-node/value-node'; import { FormulaDependencyGenerator } from './engine/dependency/formula-dependency'; import { Interpreter } from './engine/interpreter/interpreter'; -import type { BaseFunction } from './functions/base-function'; import { FormulaDataModel } from './models/formula-data.model'; import { CalculateFormulaService } from './services/calculate-formula.service'; import { FormulaCurrentConfigService, IFormulaCurrentConfigService } from './services/current-data.service'; @@ -55,22 +53,24 @@ import { ISuperTableService, SuperTableService } from './services/super-table.se import { ActiveDirtyManagerService, IActiveDirtyManagerService } from './services/active-dirty-manager.service'; import { DependencyManagerService, IDependencyManagerService } from './services/dependency-manager.service'; import { SetDependencyController } from './controller/set-dependency.controller'; +import type { IUniverEngineFormulaConfig } from './controller/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controller/config.schema'; const PLUGIN_NAME = 'base-formula-engine'; -interface IUniverFormulaEngine { - notExecuteFormula?: boolean; - function?: Array<[Ctor, IFunctionNames]>; -} - export class UniverFormulaEnginePlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - private _config: IUniverFormulaEngine, - @Inject(Injector) protected override _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected override _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { @@ -93,12 +93,7 @@ export class UniverFormulaEnginePlugin extends Plugin { [LexerTreeBuilder], //Controllers - [ - FormulaController, - { - useFactory: () => this._injector.createInstance(FormulaController, this._config?.function), - }, - ], + [FormulaController], [SetDefinedNameController], [SetSuperTableController], ]; diff --git a/packages/engine-render/src/components/sheets/extensions/row-header-layout.ts b/packages/engine-render/src/components/sheets/extensions/row-header-layout.ts index 1aeb40d466..b27c77d1d0 100644 --- a/packages/engine-render/src/components/sheets/extensions/row-header-layout.ts +++ b/packages/engine-render/src/components/sheets/extensions/row-header-layout.ts @@ -21,7 +21,7 @@ import { getColor } from '../../../basics/tools'; import type { UniverRenderingContext } from '../../../context'; import { SheetRowHeaderExtensionRegistry } from '../../extension'; import type { SpreadsheetSkeleton } from '../sheet-skeleton'; -import type { IARowCfg, IARowCfgObj, IColumnStyleCfg, IRowStyleCfg } from '../interfaces.ts'; +import type { IARowCfg, IARowCfgObj, IColumnStyleCfg, IRowStyleCfg } from '../interfaces'; import { SheetExtension } from './sheet-extension'; const UNIQUE_KEY = 'DefaultRowHeaderLayoutExtension'; diff --git a/packages/engine-render/src/controllers/config.schema.ts b/packages/engine-render/src/controllers/config.schema.ts new file mode 100644 index 0000000000..862829e60d --- /dev/null +++ b/packages/engine-render/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'engine-render.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverEngineRenderConfig { +} + +export const defaultPluginConfig: IUniverEngineRenderConfig = {}; diff --git a/packages/engine-render/src/render-engine.ts b/packages/engine-render/src/render-engine.ts index 0c561f9601..bd6c9d6d41 100644 --- a/packages/engine-render/src/render-engine.ts +++ b/packages/engine-render/src/render-engine.ts @@ -14,10 +14,12 @@ * limitations under the License. */ -import { createIdentifier, Inject, Injector, Plugin } from '@univerjs/core'; +import { createIdentifier, IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; import { Engine } from './engine'; import { IRenderManagerService, RenderManagerService } from './render-manager/render-manager.service'; +import type { IUniverEngineRenderConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; /** * The global rendering engine. @@ -30,11 +32,16 @@ export class UniverRenderEnginePlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - _config: undefined, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + this._injector.add([IRenderingEngine, { useFactory: () => new Engine() }]); this._injector.add([ diff --git a/packages/facade/src/apis/__tests__/create-test-bed.ts b/packages/facade/src/apis/__tests__/create-test-bed.ts index dd08bc0032..afd00b1089 100644 --- a/packages/facade/src/apis/__tests__/create-test-bed.ts +++ b/packages/facade/src/apis/__tests__/create-test-bed.ts @@ -143,7 +143,7 @@ export function createFacadeTestBed(workbookData?: IWorkbookData, dependencies?: injector.add([ IDescriptionService, { - useFactory: () => this._injector.createInstance(DescriptionService, undefined), + useFactory: () => this._injector.createInstance(DescriptionService), }, ]); diff --git a/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts b/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts index 9e18c4869f..b3b00f3696 100644 --- a/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts +++ b/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts @@ -144,7 +144,7 @@ function registerFormulaDependencies(injector: Injector) { injector.add([ IDescriptionService, { - useFactory: () => injector.createInstance(DescriptionService, undefined), + useFactory: () => injector.createInstance(DescriptionService), }, ]); diff --git a/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts b/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts index 9ec209cedd..3a55fb0908 100644 --- a/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts +++ b/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts @@ -139,7 +139,7 @@ export function createWorksheetTestBed(workbookData?: IWorkbookData, dependencie injector.add([ IDescriptionService, { - useFactory: () => this._injector.createInstance(DescriptionService, undefined), + useFactory: () => this._injector.createInstance(DescriptionService), }, ]); diff --git a/packages/find-replace/src/controllers/config.schema.ts b/packages/find-replace/src/controllers/config.schema.ts new file mode 100644 index 0000000000..a25a4e75c2 --- /dev/null +++ b/packages/find-replace/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'find-replace.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverFindReplaceConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverFindReplaceConfig = {}; diff --git a/packages/find-replace/src/controllers/find-replace.controller.ts b/packages/find-replace/src/controllers/find-replace.controller.ts index e6c6ddedfb..f2fe7c41a5 100644 --- a/packages/find-replace/src/controllers/find-replace.controller.ts +++ b/packages/find-replace/src/controllers/find-replace.controller.ts @@ -29,12 +29,10 @@ import { toDisposable, } from '@univerjs/core'; import { SearchSingle16 } from '@univerjs/icons'; -import type { MenuConfig } from '@univerjs/ui'; -import { - ComponentManager, +import { ComponentManager, IDialogService, ILayoutService, - IMenuService, + IMenu2Service, IShortcutService, } from '@univerjs/ui'; import { takeUntil } from 'rxjs'; @@ -55,13 +53,7 @@ import { OpenFindDialogShortcutItem, OpenReplaceDialogShortcutItem, } from './find-replace.shortcut'; -import { FindReplaceMenuItemFactory } from './find-replace.menu'; - -export interface IUniverFindReplaceConfig { - menu: MenuConfig; -} - -export const DefaultFindReplaceConfig = {}; +import { menuSchema } from './menu.schema'; const FIND_REPLACE_DIALOG_ID = 'DESKTOP_FIND_REPLACE_DIALOG'; @@ -72,9 +64,8 @@ const FIND_REPLACE_PANEL_TOP_PADDING = -90; @OnLifecycle(LifecycleStages.Rendered, FindReplaceController) export class FindReplaceController extends RxDisposable { constructor( - private readonly _config: Partial, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @IShortcutService private readonly _shortcutService: IShortcutService, @ICommandService private readonly _commandService: ICommandService, @IFindReplaceService private readonly _findReplaceService: IFindReplaceService, @@ -122,12 +113,11 @@ export class FindReplaceController extends RxDisposable { } private _initUI(): void { - const { menu = {} } = this._config; - - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(FindReplaceMenuItemFactory), menu)); this.disposeWithMe(this._componentManager.register('FindReplaceDialog', FindReplaceDialog)); this.disposeWithMe(this._componentManager.register('SearchIcon', SearchSingle16)); + this._menu2Service.mergeMenu(menuSchema); + // this controller is also responsible for toggling the FindReplaceDialog this._findReplaceService.stateUpdates$.pipe(takeUntil(this.dispose$)).subscribe((newState) => { if (newState.revealed === true) { diff --git a/packages/find-replace/src/controllers/menu.schema.ts b/packages/find-replace/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..ce76437f53 --- /dev/null +++ b/packages/find-replace/src/controllers/menu.schema.ts @@ -0,0 +1,29 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { OpenFindDialogOperation } from '../commands/operations/find-replace.operation'; +import { FindReplaceMenuItemFactory } from './find-replace.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.OTHERS]: { + [OpenFindDialogOperation.id]: { + order: 2, + menuItemFactory: FindReplaceMenuItemFactory, + }, + }, +}; diff --git a/packages/find-replace/src/plugin.ts b/packages/find-replace/src/plugin.ts index f8b7a8f5c1..42ff81d7d3 100644 --- a/packages/find-replace/src/plugin.ts +++ b/packages/find-replace/src/plugin.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { LocaleService, Plugin, Tools } from '@univerjs/core'; +import { IConfigService, Plugin } from '@univerjs/core'; import { type Dependency, Inject, Injector } from '@univerjs/core'; -import type { IUniverFindReplaceConfig } from './controllers/find-replace.controller'; -import { DefaultFindReplaceConfig, FindReplaceController } from './controllers/find-replace.controller'; +import { FindReplaceController } from './controllers/find-replace.controller'; import { FindReplaceService, IFindReplaceService } from './services/find-replace.service'; +import type { IUniverFindReplaceConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'FIND_REPLACE_PLUGIN'; @@ -27,23 +28,20 @@ export class UniverFindReplacePlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultFindReplaceConfig, this._config); + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { ([ - [ - FindReplaceController, - { - useFactory: () => this._injector.createInstance(FindReplaceController, this._config), - }, - ], + [FindReplaceController], [IFindReplaceService, { useClass: FindReplaceService }], ] as Dependency[]).forEach( (d) => { diff --git a/packages/rpc/src/controllers/config.schema.ts b/packages/rpc/src/controllers/config.schema.ts new file mode 100644 index 0000000000..f239cfd6cd --- /dev/null +++ b/packages/rpc/src/controllers/config.schema.ts @@ -0,0 +1,34 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY_MAIN_THREAD = 'rpc.main-thread.config'; + +export const configSymbolMainThread = Symbol(PLUGIN_CONFIG_KEY_MAIN_THREAD); + +export interface IUniverRPCMainThreadConfig { + workerURL?: string | URL | Worker; +} + +export const defaultPluginMainThreadConfig: IUniverRPCMainThreadConfig = {}; + +export const PLUGIN_CONFIG_KEY_WORKER_THREAD = 'rpc.worker-thread.config'; + +export const configSymbolWorkerThread = Symbol(PLUGIN_CONFIG_KEY_WORKER_THREAD); + +export interface IUniverRPCWorkerThreadConfig { +} + +export const defaultPluginWorkerThreadConfig: IUniverRPCWorkerThreadConfig = {}; diff --git a/packages/rpc/src/index.ts b/packages/rpc/src/index.ts index 095c516ce4..82084c7a64 100644 --- a/packages/rpc/src/index.ts +++ b/packages/rpc/src/index.ts @@ -15,7 +15,6 @@ */ export { - type IUniverRPCMainThreadConfig, UniverRPCMainThreadPlugin, UniverRPCWorkerThreadPlugin, } from './plugin'; @@ -31,3 +30,5 @@ export { export { ChannelService, IRPCChannelService } from './services/rpc/channel.service'; export { ChannelClient, ChannelServer, type IMessageProtocol, fromModule, toModule } from './services/rpc/rpc.service'; export { IRemoteSyncService } from './services/remote-instance/remote-instance.service'; + +export type { IUniverRPCMainThreadConfig, IUniverRPCWorkerThreadConfig } from './controllers/config.schema'; diff --git a/packages/rpc/src/plugin.ts b/packages/rpc/src/plugin.ts index 7e32178ed2..41969d4d1f 100644 --- a/packages/rpc/src/plugin.ts +++ b/packages/rpc/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Inject, Injector, Plugin } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { DataSyncPrimaryController } from './controllers/data-sync/data-sync-primary.controller'; @@ -30,10 +30,14 @@ import { createWebWorkerMessagePortOnMain, createWebWorkerMessagePortOnWorker, } from './services/rpc/implementations/web-worker-rpc.service'; - -export interface IUniverRPCMainThreadConfig { - workerURL: string | URL | Worker; -} +import type { + IUniverRPCMainThreadConfig, + IUniverRPCWorkerThreadConfig } from './controllers/config.schema'; +import { + defaultPluginMainThreadConfig, + defaultPluginWorkerThreadConfig, + PLUGIN_CONFIG_KEY_MAIN_THREAD, PLUGIN_CONFIG_KEY_WORKER_THREAD, +} from './controllers/config.schema'; /** * This plugin is used to register the RPC services on the main thread. It @@ -45,10 +49,15 @@ export class UniverRPCMainThreadPlugin extends Plugin { private _internalWorker: Worker | null = null; constructor( - private readonly _config: IUniverRPCMainThreadConfig, - @Inject(Injector) protected readonly _injector: Injector + private readonly _config: Partial = defaultPluginMainThreadConfig, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY_MAIN_THREAD, rest); } override dispose(): void { @@ -62,6 +71,10 @@ export class UniverRPCMainThreadPlugin extends Plugin { override onStarting(): void { const { workerURL } = this._config; + if (!workerURL) { + throw new Error('[UniverRPCMainThreadPlugin]: The workerURL is required for the RPC main thread plugin.'); + } + const worker = workerURL instanceof Worker ? workerURL : new Worker(workerURL); this._internalWorker = workerURL instanceof Worker ? null : worker; @@ -91,10 +104,15 @@ export class UniverRPCWorkerThreadPlugin extends Plugin { static override pluginName = 'UNIVER_RPC_WORKER_THREAD_PLUGIN'; constructor( - private readonly _config: unknown, - @Inject(Injector) protected readonly _injector: Injector + private readonly _config: Partial = defaultPluginWorkerThreadConfig, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY_WORKER_THREAD, rest); } override onStarting(): void { diff --git a/packages/sheets-conditional-formatting-ui/src/commands/operations/open-conditional-formatting-panel.ts b/packages/sheets-conditional-formatting-ui/src/commands/operations/open-conditional-formatting-panel.ts index 57bb3420af..7c3b079a97 100644 --- a/packages/sheets-conditional-formatting-ui/src/commands/operations/open-conditional-formatting-panel.ts +++ b/packages/sheets-conditional-formatting-ui/src/commands/operations/open-conditional-formatting-panel.ts @@ -19,7 +19,7 @@ import { CommandType, ICommandService } from '@univerjs/core'; import { SheetsSelectionsService } from '@univerjs/sheets'; import { CFRuleType, CFSubRuleType, createDefaultRule } from '@univerjs/sheets-conditional-formatting'; import type { IColorScale, IConditionFormattingRule, IDataBar, IFormulaHighlightCell, IIconSet, IRankHighlightCell } from '@univerjs/sheets-conditional-formatting'; -import { ConditionalFormattingMenuController } from '../../controllers/cf.menu.controller'; +import { ConditionalFormattingPanelController } from '../../controllers/cf.panel.controller'; import type { IClearRangeCfParams } from '../commands/clear-range-cf.command'; import { ClearRangeCfCommand } from '../commands/clear-range-cf.command'; import { ClearWorksheetCfCommand } from '../commands/clear-worksheet-cf.command'; @@ -40,11 +40,12 @@ export enum CF_MENU_OPERATION { clearRangeRules, clearWorkSheetRules, } + export const OpenConditionalFormattingOperator: ICommand = { id: 'sheet.operation.open.conditional.formatting.panel', type: CommandType.OPERATION, handler: (accessor: IAccessor, params: IOpenConditionalFormattingOperatorParams) => { - const conditionalFormattingMenuController = accessor.get(ConditionalFormattingMenuController); + const conditionalFormattingMenuController = accessor.get(ConditionalFormattingPanelController); const selectionManagerService = accessor.get(SheetsSelectionsService); const commandService = accessor.get(ICommandService); diff --git a/packages/sheets-conditional-formatting-ui/src/controllers/cf.menu.controller.ts b/packages/sheets-conditional-formatting-ui/src/controllers/cf.menu.controller.ts index 60686f52b6..4151d877bd 100644 --- a/packages/sheets-conditional-formatting-ui/src/controllers/cf.menu.controller.ts +++ b/packages/sheets-conditional-formatting-ui/src/controllers/cf.menu.controller.ts @@ -15,66 +15,20 @@ */ import type { IDisposable } from '@univerjs/core'; -import { Disposable, Inject, Injector, IUniverInstanceService, LifecycleStages, LocaleService, OnLifecycle, Tools, UniverInstanceType } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService, ISidebarService } from '@univerjs/ui'; -import type { IConditionFormattingRule } from '@univerjs/sheets-conditional-formatting'; -import { FactoryManageConditionalFormattingRule } from '../menu/manage-rule'; -import { ConditionFormattingPanel } from '../components/panel'; +import { Disposable, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { IMenu2Service } from '@univerjs/ui'; +import { menuSchema } from './menu.schema'; -export interface IUniverSheetsConditionalFormattingUIConfig { - menu: MenuConfig; -} - -export const DefaultSheetConditionalFormattingUiConfig = {}; - -const CF_PANEL_KEY = 'sheet.conditional.formatting.panel'; @OnLifecycle(LifecycleStages.Ready, ConditionalFormattingMenuController) export class ConditionalFormattingMenuController extends Disposable { private _sidebarDisposable: IDisposable | null = null; constructor( - private readonly _config: Partial, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, @Inject(Injector) private _injector: Injector, - @Inject(ComponentManager) private _componentManager: ComponentManager, - @Inject(IMenuService) private _menuService: IMenuService, - @Inject(ISidebarService) private _sidebarService: ISidebarService, - @Inject(LocaleService) private _localeService: LocaleService + @IMenu2Service private readonly _menu2Service: IMenu2Service ) { super(); - this._initMenu(); - this._initPanel(); - - this.disposeWithMe( - this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).subscribe((sheet) => { - if (!sheet) this._sidebarDisposable?.dispose(); - }) - ); - } - - openPanel(rule?: IConditionFormattingRule) { - const props = { - header: { title: this._localeService.t('sheet.cf.title') }, - children: { - label: CF_PANEL_KEY, - rule, - key: Tools.generateRandomId(4), - }, - onClose: () => this._sidebarDisposable = null, - }; - - this._sidebarDisposable = this._sidebarService.open(props); - } - - private _initMenu() { - const { menu = {} } = this._config; - - this._menuService.addMenuItem(FactoryManageConditionalFormattingRule(this._injector), menu); - } - - private _initPanel() { - this._componentManager.register(CF_PANEL_KEY, ConditionFormattingPanel); + this._menu2Service.mergeMenu(menuSchema); } } diff --git a/packages/sheets-conditional-formatting-ui/src/controllers/cf.panel.controller.ts b/packages/sheets-conditional-formatting-ui/src/controllers/cf.panel.controller.ts new file mode 100644 index 0000000000..40a9b479d9 --- /dev/null +++ b/packages/sheets-conditional-formatting-ui/src/controllers/cf.panel.controller.ts @@ -0,0 +1,63 @@ +/** + * 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 { IDisposable } from '@univerjs/core'; +import { Disposable, generateRandomId, Inject, Injector, IUniverInstanceService, LifecycleStages, LocaleService, OnLifecycle, UniverInstanceType } from '@univerjs/core'; +import { ComponentManager, ISidebarService } from '@univerjs/ui'; +import type { IConditionFormattingRule } from '@univerjs/sheets-conditional-formatting'; +import { ConditionFormattingPanel } from '../components/panel'; + +const CF_PANEL_KEY = 'sheet.conditional.formatting.panel'; +@OnLifecycle(LifecycleStages.Ready, ConditionalFormattingPanelController) +export class ConditionalFormattingPanelController extends Disposable { + private _sidebarDisposable: IDisposable | null = null; + + constructor( + @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, + @Inject(Injector) private _injector: Injector, + @Inject(ComponentManager) private _componentManager: ComponentManager, + @Inject(ISidebarService) private _sidebarService: ISidebarService, + @Inject(LocaleService) private _localeService: LocaleService + ) { + super(); + + this._initPanel(); + + this.disposeWithMe( + this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).subscribe((sheet) => { + if (!sheet) this._sidebarDisposable?.dispose(); + }) + ); + } + + openPanel(rule?: IConditionFormattingRule) { + const props = { + header: { title: this._localeService.t('sheet.cf.title') }, + children: { + label: CF_PANEL_KEY, + rule, + key: generateRandomId(4), + }, + onClose: () => this._sidebarDisposable = null, + }; + + this._sidebarDisposable = this._sidebarService.open(props); + } + + private _initPanel() { + this._componentManager.register(CF_PANEL_KEY, ConditionFormattingPanel); + } +} diff --git a/packages/sheets-conditional-formatting-ui/src/controllers/config.schema.ts b/packages/sheets-conditional-formatting-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..707bc70768 --- /dev/null +++ b/packages/sheets-conditional-formatting-ui/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-conditional-formatting-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsConditionalFormattingUIConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSheetsConditionalFormattingUIConfig = {}; diff --git a/packages/sheets-conditional-formatting-ui/src/controllers/menu.schema.ts b/packages/sheets-conditional-formatting-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..bf009bd827 --- /dev/null +++ b/packages/sheets-conditional-formatting-ui/src/controllers/menu.schema.ts @@ -0,0 +1,29 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { OpenConditionalFormattingOperator } from '../commands/operations/open-conditional-formatting-panel'; +import { FactoryManageConditionalFormattingRule } from '../menu/manage-rule'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [OpenConditionalFormattingOperator.id]: { + order: 0, + menuItemFactory: FactoryManageConditionalFormattingRule, + }, + }, +}; diff --git a/packages/sheets-conditional-formatting-ui/src/menu/manage-rule.ts b/packages/sheets-conditional-formatting-ui/src/menu/manage-rule.ts index 2f6fdf921e..dec952750d 100644 --- a/packages/sheets-conditional-formatting-ui/src/menu/manage-rule.ts +++ b/packages/sheets-conditional-formatting-ui/src/menu/manage-rule.ts @@ -27,52 +27,57 @@ import { AddConditionalRuleMutation, ConditionalFormattingRuleModel, DeleteCondi import { getCurrentRangeDisable$ } from '@univerjs/sheets-ui'; import { CF_MENU_OPERATION, OpenConditionalFormattingOperator } from '../commands/operations/open-conditional-formatting-panel'; -const commandList = [SetWorksheetActiveOperation.id, AddConditionalRuleMutation.id, SetConditionalRuleMutation.id, DeleteConditionalRuleMutation.id, MoveConditionalRuleMutation.id]; +const commandList = [ + SetWorksheetActiveOperation.id, + AddConditionalRuleMutation.id, + SetConditionalRuleMutation.id, + DeleteConditionalRuleMutation.id, + MoveConditionalRuleMutation.id, +]; + +const commonSelections = [ + { + label: 'sheet.cf.ruleType.highlightCell', + value: CF_MENU_OPERATION.highlightCell, + }, + { + label: 'sheet.cf.panel.rankAndAverage', + value: CF_MENU_OPERATION.rank, + }, + { + label: 'sheet.cf.ruleType.formula', + value: CF_MENU_OPERATION.formula, + }, + { + label: 'sheet.cf.ruleType.colorScale', + value: CF_MENU_OPERATION.colorScale, + }, + { + label: 'sheet.cf.ruleType.dataBar', + value: CF_MENU_OPERATION.dataBar, + }, { + label: 'sheet.cf.ruleType.iconSet', + value: CF_MENU_OPERATION.icon, + }, + { + label: 'sheet.cf.menu.manageConditionalFormatting', + value: CF_MENU_OPERATION.viewRule, + }, { + label: 'sheet.cf.menu.createConditionalFormatting', + value: CF_MENU_OPERATION.createRule, + }, + { + label: 'sheet.cf.menu.clearRangeRules', + value: CF_MENU_OPERATION.clearRangeRules, + disabled: false, + }, + { + label: 'sheet.cf.menu.clearWorkSheetRules', + value: CF_MENU_OPERATION.clearWorkSheetRules, + }, +]; -// eslint-disable-next-line max-lines-per-function export const FactoryManageConditionalFormattingRule = (accessor: IAccessor): IMenuSelectorItem => { - const commonSelections = [ - { - label: 'sheet.cf.ruleType.highlightCell', - value: CF_MENU_OPERATION.highlightCell, - }, - { - label: 'sheet.cf.panel.rankAndAverage', - value: CF_MENU_OPERATION.rank, - }, - { - label: 'sheet.cf.ruleType.formula', - value: CF_MENU_OPERATION.formula, - }, - { - label: 'sheet.cf.ruleType.colorScale', - value: CF_MENU_OPERATION.colorScale, - }, - { - label: 'sheet.cf.ruleType.dataBar', - value: CF_MENU_OPERATION.dataBar, - }, { - label: 'sheet.cf.ruleType.iconSet', - value: CF_MENU_OPERATION.icon, - }, - { - label: 'sheet.cf.menu.manageConditionalFormatting', - value: CF_MENU_OPERATION.viewRule, - }, { - label: 'sheet.cf.menu.createConditionalFormatting', - value: CF_MENU_OPERATION.createRule, - }, - { - label: 'sheet.cf.menu.clearRangeRules', - value: CF_MENU_OPERATION.clearRangeRules, - disabled: false, - }, - { - label: 'sheet.cf.menu.clearWorkSheetRules', - value: CF_MENU_OPERATION.clearWorkSheetRules, - }, - ]; - const selectionManagerService = accessor.get(SheetsSelectionsService); const commandService = accessor.get(ICommandService); const univerInstanceService = accessor.get(IUniverInstanceService); diff --git a/packages/sheets-conditional-formatting-ui/src/mobile-plugin.ts b/packages/sheets-conditional-formatting-ui/src/mobile-plugin.ts index aa82851903..9a5ab9c0cb 100644 --- a/packages/sheets-conditional-formatting-ui/src/mobile-plugin.ts +++ b/packages/sheets-conditional-formatting-ui/src/mobile-plugin.ts @@ -14,7 +14,15 @@ * limitations under the License. */ -import { DependentOn, ICommandService, Inject, Injector, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + ICommandService, + IConfigService, + Inject, + Injector, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import { SHEET_CONDITIONAL_FORMATTING_PLUGIN, UniverSheetsConditionalFormattingPlugin } from '@univerjs/sheets-conditional-formatting'; import { AddAverageCfCommand } from './commands/commands/add-average-cf.command'; import { AddColorScaleConditionalRuleCommand } from './commands/commands/add-color-scale-cf.command'; @@ -35,11 +43,11 @@ import { AddCfCommand } from './commands/commands/add-cf.command'; import { SheetsCfRenderController } from './controllers/cf.render.controller'; import { ConditionalFormattingCopyPasteController } from './controllers/cf.copy-paste.controller'; -import type { IUniverSheetsConditionalFormattingUIConfig } from './controllers/cf.menu.controller'; -import { DefaultSheetConditionalFormattingUiConfig } from './controllers/cf.menu.controller'; import { ConditionalFormattingI18nController } from './controllers/cf.i18n.controller'; import { SheetsCfRefRangeController } from './controllers/cf.ref-range.controller'; import { ConditionalFormattingPermissionController } from './controllers/cf.permission.controller'; +import type { IUniverSheetsConditionalFormattingUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverSheetsConditionalFormattingPlugin) export class UniverSheetsConditionalFormattingMobileUIPlugin extends Plugin { @@ -47,12 +55,19 @@ export class UniverSheetsConditionalFormattingMobileUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, - @Inject(ICommandService) private _commandService: ICommandService + @Inject(ICommandService) private _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetConditionalFormattingUiConfig, this._config); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); this._initCommand(); diff --git a/packages/sheets-conditional-formatting-ui/src/plugin.ts b/packages/sheets-conditional-formatting-ui/src/plugin.ts index 446580c6ef..b03572f5cb 100644 --- a/packages/sheets-conditional-formatting-ui/src/plugin.ts +++ b/packages/sheets-conditional-formatting-ui/src/plugin.ts @@ -14,7 +14,15 @@ * limitations under the License. */ -import { DependentOn, ICommandService, Inject, Injector, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + ICommandService, + IConfigService, + Inject, + Injector, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import { SHEET_CONDITIONAL_FORMATTING_PLUGIN, UniverSheetsConditionalFormattingPlugin } from '@univerjs/sheets-conditional-formatting'; import { AddAverageCfCommand } from './commands/commands/add-average-cf.command'; import { AddColorScaleConditionalRuleCommand } from './commands/commands/add-color-scale-cf.command'; @@ -36,13 +44,15 @@ import { AddCfCommand } from './commands/commands/add-cf.command'; import { SheetsCfRenderController } from './controllers/cf.render.controller'; import { ConditionalFormattingCopyPasteController } from './controllers/cf.copy-paste.controller'; import { ConditionalFormattingAutoFillController } from './controllers/cf.auto-fill.controller'; -import type { IUniverSheetsConditionalFormattingUIConfig } from './controllers/cf.menu.controller'; -import { ConditionalFormattingMenuController, DefaultSheetConditionalFormattingUiConfig } from './controllers/cf.menu.controller'; +import { ConditionalFormattingMenuController } from './controllers/cf.menu.controller'; +import { ConditionalFormattingPanelController } from './controllers/cf.panel.controller'; import { ConditionalFormattingI18nController } from './controllers/cf.i18n.controller'; import { SheetsCfRefRangeController } from './controllers/cf.ref-range.controller'; import { ConditionalFormattingEditorController } from './controllers/cf.editor.controller'; import { ConditionalFormattingClearController } from './controllers/cf.clear.controller'; import { ConditionalFormattingPermissionController } from './controllers/cf.permission.controller'; +import type { IUniverSheetsConditionalFormattingUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverSheetsConditionalFormattingPlugin) export class UniverSheetsConditionalFormattingUIPlugin extends Plugin { @@ -50,13 +60,19 @@ export class UniverSheetsConditionalFormattingUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, - @Inject(ICommandService) private _commandService: ICommandService + @Inject(ICommandService) private _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetConditionalFormattingUiConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); this._initCommand(); @@ -65,12 +81,8 @@ export class UniverSheetsConditionalFormattingUIPlugin extends Plugin { this._injector.add([ConditionalFormattingCopyPasteController]); this._injector.add([ConditionalFormattingAutoFillController]); this._injector.add([ConditionalFormattingPermissionController]); - this._injector.add([ - ConditionalFormattingMenuController, - { - useFactory: () => this._injector.createInstance(ConditionalFormattingMenuController, this._config), - }, - ]); + this._injector.add([ConditionalFormattingPanelController]); + this._injector.add([ConditionalFormattingMenuController]); this._injector.add([ConditionalFormattingI18nController]); this._injector.add([ConditionalFormattingEditorController]); this._injector.add([ConditionalFormattingClearController]); diff --git a/packages/sheets-conditional-formatting/src/controllers/config.schema.ts b/packages/sheets-conditional-formatting/src/controllers/config.schema.ts new file mode 100644 index 0000000000..75cfd8e1e8 --- /dev/null +++ b/packages/sheets-conditional-formatting/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'ssheets-conditional-formatting.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsConditionalFormattingConfig { +} + +export const defaultPluginConfig: IUniverSheetsConditionalFormattingConfig = {}; diff --git a/packages/sheets-conditional-formatting/src/plugin.ts b/packages/sheets-conditional-formatting/src/plugin.ts index 5695002d99..2c203a3fce 100644 --- a/packages/sheets-conditional-formatting/src/plugin.ts +++ b/packages/sheets-conditional-formatting/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ICommandService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { SHEET_CONDITIONAL_FORMATTING_PLUGIN } from './base/const'; import { ConditionalFormattingService } from './services/conditional-formatting.service'; @@ -27,17 +27,28 @@ import { SetConditionalRuleMutation } from './commands/mutations/set-conditional import { MoveConditionalRuleMutation } from './commands/mutations/move-conditional-rule.mutation'; import { ConditionalFormattingFormulaService } from './services/conditional-formatting-formula.service'; import { ConditionalFormattingFormulaMarkDirty } from './commands/mutations/formula-mark-dirty.mutation'; +import type { IUniverSheetsConditionalFormattingConfig } from './controllers/config.schema'; +import { + defaultPluginConfig, + PLUGIN_CONFIG_KEY, +} from './controllers/config.schema'; export class UniverSheetsConditionalFormattingPlugin extends Plugin { static override pluginName = SHEET_CONDITIONAL_FORMATTING_PLUGIN; static override type = UniverInstanceType.UNIVER_SHEET; constructor( - _config: unknown, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, - @Inject(ICommandService) private _commandService: ICommandService + @Inject(ICommandService) private _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + ([ [ConditionalFormattingService], [ConditionalFormattingFormulaService], diff --git a/packages/sheets-crosshair-highlight/src/controllers/config.schema.ts b/packages/sheets-crosshair-highlight/src/controllers/config.schema.ts new file mode 100644 index 0000000000..b548db8c26 --- /dev/null +++ b/packages/sheets-crosshair-highlight/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-crosshair-highlight.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsCrosshairHighlightConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSheetsCrosshairHighlightConfig = {}; diff --git a/packages/sheets-crosshair-highlight/src/controllers/crosshair.controller.tsx b/packages/sheets-crosshair-highlight/src/controllers/crosshair.controller.tsx index aeeb77fe4b..b9981d46e0 100644 --- a/packages/sheets-crosshair-highlight/src/controllers/crosshair.controller.tsx +++ b/packages/sheets-crosshair-highlight/src/controllers/crosshair.controller.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Disposable, ICommandService, Inject, Injector } from '@univerjs/core'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { Disposable, ICommandService, Inject } from '@univerjs/core'; +import { ComponentManager, IMenu2Service } from '@univerjs/ui'; import { CrossHighlightingSingle } from '@univerjs/icons'; import { DisableCrosshairHighlightOperation, @@ -24,13 +24,13 @@ import { ToggleCrosshairHighlightOperation, } from '../commands/operations/operation'; import { CrosshairOverlay } from '../views/components/CrosshairHighlight'; -import { CROSSHAIR_HIGHLIGHT_OVERLAY_COMPONENT, CrosshairHighlightMenuItemFactory } from './crosshair.menu'; +import { CROSSHAIR_HIGHLIGHT_OVERLAY_COMPONENT } from './crosshair.menu'; +import { menuSchema } from './menu.schema'; export class SheetsCrosshairHighlightController extends Disposable { constructor( - @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentMgr: ComponentManager, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService private readonly _cmdSrv: ICommandService ) { super(); @@ -50,7 +50,7 @@ export class SheetsCrosshairHighlightController extends Disposable { } private _initMenus(): void { - this._menuService.addMenuItem(this._injector.invoke(CrosshairHighlightMenuItemFactory), {}); + this._menu2Service.mergeMenu(menuSchema); } private _initComponents(): void { diff --git a/packages/sheets-crosshair-highlight/src/controllers/menu.schema.ts b/packages/sheets-crosshair-highlight/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..6c3790b2ca --- /dev/null +++ b/packages/sheets-crosshair-highlight/src/controllers/menu.schema.ts @@ -0,0 +1,30 @@ +/** + * 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 { ContextMenuGroup, ContextMenuPosition, type IMenu2Item } from '@univerjs/ui'; +import { ToggleCrosshairHighlightOperation } from '../commands/operations/operation'; +import { CrosshairHighlightMenuItemFactory } from './crosshair.menu'; + +export const menuSchema: IMenu2Item = { + [ContextMenuPosition.FOOTER_MENU]: { + [ContextMenuGroup.OTHERS]: { + [ToggleCrosshairHighlightOperation.id]: { + order: 0, + menuItemFactory: CrosshairHighlightMenuItemFactory, + }, + }, + }, +}; diff --git a/packages/sheets-crosshair-highlight/src/plugin.ts b/packages/sheets-crosshair-highlight/src/plugin.ts index b87f1beee5..df790400a1 100644 --- a/packages/sheets-crosshair-highlight/src/plugin.ts +++ b/packages/sheets-crosshair-highlight/src/plugin.ts @@ -15,18 +15,26 @@ */ import type { Dependency } from '@univerjs/core'; -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { SheetsCrosshairHighlightController } from './controllers/crosshair.controller'; import { SheetsCrosshairHighlightService } from './services/crosshair.service'; import { SheetCrosshairHighlightRenderController } from './views/widgets/crosshair-highlight.render-controller'; +import type { IUniverSheetsCrosshairHighlightConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverSheetsCrosshairHighlightPlugin extends Plugin { constructor( + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected readonly _injector: Injector, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-data-validation/src/controllers/config.schema.ts b/packages/sheets-data-validation/src/controllers/config.schema.ts new file mode 100644 index 0000000000..62373733d6 --- /dev/null +++ b/packages/sheets-data-validation/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-data-validation.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsDataValidationConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSheetsDataValidationConfig = {}; diff --git a/packages/sheets-data-validation/src/controllers/dv-render.controller.ts b/packages/sheets-data-validation/src/controllers/dv-render.controller.ts index 705faaea63..f59f8d36be 100644 --- a/packages/sheets-data-validation/src/controllers/dv-render.controller.ts +++ b/packages/sheets-data-validation/src/controllers/dv-render.controller.ts @@ -15,10 +15,9 @@ */ import type { ICellDataForSheetInterceptor, ICellRenderContext, IRange, Workbook } from '@univerjs/core'; -import { DataValidationRenderMode, DataValidationStatus, DataValidationType, ICommandService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, Optional, RxDisposable, sequenceExecute, UniverInstanceType, WrapStrategy } from '@univerjs/core'; +import { DataValidationRenderMode, DataValidationStatus, DataValidationType, ICommandService, Inject, IUniverInstanceService, LifecycleStages, OnLifecycle, Optional, RxDisposable, sequenceExecute, UniverInstanceType, WrapStrategy } from '@univerjs/core'; import { DataValidationModel, DataValidatorRegistryService } from '@univerjs/data-validation'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { IMenu2Service } from '@univerjs/ui'; import { AutoHeightController, IEditorBridgeService, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; import type { Spreadsheet } from '@univerjs/engine-render'; import { IRenderManagerService } from '@univerjs/engine-render'; @@ -28,14 +27,7 @@ import { getCellValueOrigin } from '../utils/get-cell-data-origin'; import type { ListValidator } from '../validators'; import type { SheetDataValidationManager } from '../models/sheet-data-validation-manager'; import { DataValidationDropdownManagerService } from '../services/dropdown-manager.service'; -import { addDataValidationMenuFactory, dataValidationMenuFactory, openDataValidationMenuFactory } from './dv.menu'; - -export interface IUniverSheetsDataValidation { - menu?: MenuConfig; -} - -export const DefaultSheetsDataValidation = { -}; +import { menuSchema } from './menu.schema'; const INVALID_MARK = { tr: { @@ -47,17 +39,14 @@ const INVALID_MARK = { @OnLifecycle(LifecycleStages.Rendered, SheetsDataValidationRenderController) export class SheetsDataValidationRenderController extends RxDisposable { constructor( - private readonly _config: Partial, @ICommandService private readonly _commandService: ICommandService, - @IMenuService private _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, @Inject(AutoHeightController) private readonly _autoHeightController: AutoHeightController, - @Inject(ComponentManager) private _componentManager: ComponentManager, @Inject(DataValidationDropdownManagerService) private readonly _dropdownManagerService: DataValidationDropdownManagerService, @Inject(DataValidationModel) private readonly _dataValidationModel: DataValidationModel, @Inject(DataValidatorRegistryService) private readonly _dataValidatorRegistryService: DataValidatorRegistryService, - @Inject(Injector) private readonly _injector: Injector, @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, @Optional(IEditorBridgeService) private readonly _editorBridgeService?: IEditorBridgeService ) { @@ -71,17 +60,7 @@ export class SheetsDataValidationRenderController extends RxDisposable { } private _initMenu() { - const { menu = {} } = this._config; - - [ - dataValidationMenuFactory, - openDataValidationMenuFactory, - addDataValidationMenuFactory, - ].forEach((factory) => { - this.disposeWithMe( - this._menuService.addMenuItem(factory(this._injector), menu) - ); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initDropdown() { @@ -342,7 +321,6 @@ export class SheetsDataValidationRenderController extends RxDisposable { @OnLifecycle(LifecycleStages.Rendered, SheetsDataValidationMobileRenderController) export class SheetsDataValidationMobileRenderController extends RxDisposable { constructor( - private readonly _config: Partial, @ICommandService private readonly _commandService: ICommandService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, diff --git a/packages/sheets-data-validation/src/controllers/dv.menu.ts b/packages/sheets-data-validation/src/controllers/dv.menu.ts index 1b63a2357a..2384e0a8f3 100644 --- a/packages/sheets-data-validation/src/controllers/dv.menu.ts +++ b/packages/sheets-data-validation/src/controllers/dv.menu.ts @@ -23,7 +23,7 @@ import { AddSheetDataValidationAndOpenCommand } from '../commands/commands/data- import { OpenValidationPanelOperation } from '../commands/operations/data-validation.operation'; export const DataValidationIcon = 'data-validation-single'; -const DATA_VALIDATION_MENU_ID = 'sheet.menu.data-validation'; +export const DATA_VALIDATION_MENU_ID = 'sheet.menu.data-validation'; export function dataValidationMenuFactory(accessor: IAccessor): IMenuItem { return { diff --git a/packages/sheets-data-validation/src/controllers/menu.schema.ts b/packages/sheets-data-validation/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..4d76ab531c --- /dev/null +++ b/packages/sheets-data-validation/src/controllers/menu.schema.ts @@ -0,0 +1,43 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { OpenValidationPanelOperation } from '../commands/operations/data-validation.operation'; +import { AddSheetDataValidationAndOpenCommand } from '../commands/commands/data-validation.command'; +import { + addDataValidationMenuFactory, + DATA_VALIDATION_MENU_ID, + dataValidationMenuFactory, + openDataValidationMenuFactory, +} from './dv.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [DATA_VALIDATION_MENU_ID]: { + order: 9, + menuItemFactory: dataValidationMenuFactory, + [OpenValidationPanelOperation.id]: { + order: 0, + menuItemFactory: openDataValidationMenuFactory, + }, + [AddSheetDataValidationAndOpenCommand.id]: { + order: 1, + menuItemFactory: addDataValidationMenuFactory, + }, + }, + }, +}; diff --git a/packages/sheets-data-validation/src/mobile-plugin.ts b/packages/sheets-data-validation/src/mobile-plugin.ts index bc1316f497..09ccba6e74 100644 --- a/packages/sheets-data-validation/src/mobile-plugin.ts +++ b/packages/sheets-data-validation/src/mobile-plugin.ts @@ -14,13 +14,18 @@ * limitations under the License. */ -import { DependentOn, ICommandService, LocaleService, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + ICommandService, + IConfigService, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import { type Dependency, Inject, Injector } from '@univerjs/core'; import { UniverDataValidationPlugin } from '@univerjs/data-validation'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; -import type { IUniverSheetsDataValidation } from './controllers/dv-render.controller'; -import { DefaultSheetsDataValidation, SheetsDataValidationMobileRenderController } from './controllers/dv-render.controller'; +import { SheetsDataValidationMobileRenderController } from './controllers/dv-render.controller'; import { DataValidationController } from './controllers/dv.controller'; import { DataValidationAlertController } from './controllers/dv-alert.controller'; import { AddSheetDataValidationAndOpenCommand, AddSheetDataValidationCommand, UpdateSheetDataValidationRangeCommand } from './commands/commands/data-validation.command'; @@ -37,6 +42,11 @@ import { DataValidationPanelService } from './services/data-validation-panel.ser import { DataValidationFormulaController } from './controllers/dv-formula.controller'; import { DataValidationPermissionController } from './controllers/dv-permission.controller'; import { SheetsDataValidationValidatorService } from './services/dv-validator-service'; +import { + defaultPluginConfig, + type IUniverSheetsDataValidationConfig, + PLUGIN_CONFIG_KEY, +} from './controllers/config.schema'; @DependentOn(UniverDataValidationPlugin, UniverSheetsPlugin, UniverSheetsUIPlugin) export class UniverSheetsDataValidationMobilePlugin extends Plugin { @@ -44,14 +54,19 @@ export class UniverSheetsDataValidationMobilePlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, @ICommandService private readonly _commandService: ICommandService, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetsDataValidation, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting() { @@ -66,12 +81,7 @@ export class UniverSheetsDataValidationMobilePlugin extends Plugin { // controller [DataValidationModelController], [DataValidationController], - [ - SheetsDataValidationMobileRenderController, - { - useFactory: () => this._injector.createInstance(SheetsDataValidationMobileRenderController, this._config), - }, - ], + [SheetsDataValidationMobileRenderController], [DataValidationAlertController], [DataValidationRefRangeController], [DataValidationPermissionController], diff --git a/packages/sheets-data-validation/src/plugin.ts b/packages/sheets-data-validation/src/plugin.ts index 21ff50c057..84a5cc1c6e 100644 --- a/packages/sheets-data-validation/src/plugin.ts +++ b/packages/sheets-data-validation/src/plugin.ts @@ -14,13 +14,18 @@ * limitations under the License. */ -import { DependentOn, ICommandService, LocaleService, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + ICommandService, + IConfigService, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import { type Dependency, Inject, Injector } from '@univerjs/core'; import { UniverDataValidationPlugin } from '@univerjs/data-validation'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; -import type { IUniverSheetsDataValidation } from './controllers/dv-render.controller'; -import { DefaultSheetsDataValidation, SheetsDataValidationRenderController } from './controllers/dv-render.controller'; +import { SheetsDataValidationRenderController } from './controllers/dv-render.controller'; import { DataValidationController } from './controllers/dv.controller'; import { DataValidationAlertController } from './controllers/dv-alert.controller'; import { AddSheetDataValidationAndOpenCommand, AddSheetDataValidationCommand, UpdateSheetDataValidationOptionsCommand, UpdateSheetDataValidationRangeCommand, UpdateSheetDataValidationSettingCommand } from './commands/commands/data-validation.command'; @@ -39,6 +44,8 @@ import { DataValidationPanelService } from './services/data-validation-panel.ser import { DataValidationFormulaController } from './controllers/dv-formula.controller'; import { DataValidationPermissionController } from './controllers/dv-permission.controller'; import { SheetsDataValidationValidatorService } from './services/dv-validator-service'; +import type { IUniverSheetsDataValidationConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverDataValidationPlugin, UniverSheetsPlugin, UniverSheetsUIPlugin) export class UniverSheetsDataValidationPlugin extends Plugin { @@ -46,14 +53,19 @@ export class UniverSheetsDataValidationPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, @ICommandService private readonly _commandService: ICommandService, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetsDataValidation, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting() { @@ -68,12 +80,7 @@ export class UniverSheetsDataValidationPlugin extends Plugin { // controller [DataValidationModelController], [DataValidationController], - [ - SheetsDataValidationRenderController, - { - useFactory: () => this._injector.createInstance(SheetsDataValidationRenderController, this._config), - }, - ], + [SheetsDataValidationRenderController], [DataValidationAlertController], [DataValidationRefRangeController], [DataValidationPermissionController], diff --git a/packages/sheets-drawing-ui/src/controllers/config.schema.ts b/packages/sheets-drawing-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..7f1d3e00f2 --- /dev/null +++ b/packages/sheets-drawing-ui/src/controllers/config.schema.ts @@ -0,0 +1,29 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; +import type { DependencyOverride } from '@univerjs/core'; + +export const PLUGIN_CONFIG_KEY = 'sheets-drawing-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsDrawingUIConfig { + menu?: MenuConfig; + overrides?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverSheetsDrawingUIConfig = {}; diff --git a/packages/sheets-drawing-ui/src/controllers/menu.schema.ts b/packages/sheets-drawing-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..86b65f201e --- /dev/null +++ b/packages/sheets-drawing-ui/src/controllers/menu.schema.ts @@ -0,0 +1,33 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { IMAGE_MENU_ID, ImageMenuFactory, UploadFloatImageMenuFactory } from '../views/menu/image.menu'; +import { InsertFloatImageOperation } from '../commands/operations/insert-image.operation'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [IMAGE_MENU_ID]: { + order: 3, + menuItemFactory: ImageMenuFactory, + [InsertFloatImageOperation.id]: { + order: 0, + menuItemFactory: UploadFloatImageMenuFactory, + }, + }, + }, +}; diff --git a/packages/sheets-drawing-ui/src/controllers/sheet-drawing.controller.ts b/packages/sheets-drawing-ui/src/controllers/sheet-drawing.controller.ts index 7f36e63301..ce15d00bd1 100644 --- a/packages/sheets-drawing-ui/src/controllers/sheet-drawing.controller.ts +++ b/packages/sheets-drawing-ui/src/controllers/sheet-drawing.controller.ts @@ -14,15 +14,13 @@ * limitations under the License. */ -import type { DependencyOverride } from '@univerjs/core'; import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService, IShortcutService } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service, IShortcutService } from '@univerjs/ui'; import { AddImageSingle } from '@univerjs/icons'; import { UploadFileMenu } from '../views/upload-component/UploadFile'; import { COMPONENT_UPLOAD_FILE_MENU } from '../views/upload-component/component-name'; -import { IMAGE_UPLOAD_ICON, ImageMenuFactory, UploadFloatImageMenuFactory } from '../views/menu/image.menu'; +import { IMAGE_UPLOAD_ICON } from '../views/menu/image.menu'; import { InsertCellImageOperation, InsertFloatImageOperation } from '../commands/operations/insert-image.operation'; import { InsertSheetDrawingCommand } from '../commands/commands/insert-sheet-drawing.command'; import { RemoveSheetDrawingCommand } from '../commands/commands/remove-sheet-drawing.command'; @@ -39,23 +37,14 @@ import { MoveDrawingsCommand } from '../commands/commands/move-drawings.command' import { DeleteDrawingsCommand } from '../commands/commands/delete-drawings.command'; import { SetDrawingArrangeCommand } from '../commands/commands/set-drawing-arrange.command'; import { DeleteDrawingsShortcutItem, MoveDrawingDownShortcutItem, MoveDrawingLeftShortcutItem, MoveDrawingRightShortcutItem, MoveDrawingUpShortcutItem } from './shortcuts/drawing.shortcut'; - -export interface IUniverSheetsDrawingConfig { - menu?: MenuConfig; - overrides?: DependencyOverride; -} - -export const DefaultSheetsDrawingConfig: IUniverSheetsDrawingConfig = { - -}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Rendered, SheetDrawingUIController) export class SheetDrawingUIController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService private readonly _commandService: ICommandService, @IShortcutService private readonly _shortcutService: IShortcutService ) { @@ -72,15 +61,7 @@ export class SheetDrawingUIController extends Disposable { } private _initMenus(): void { - const { menu = {} } = this._config; - // init menus - [ - ImageMenuFactory, - UploadFloatImageMenuFactory, - // UploadCellImageMenuFactory, - ].forEach((menuFactory) => { - this._menuService.addMenuItem(menuFactory(this._injector), menu); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initCommands() { diff --git a/packages/sheets-drawing-ui/src/plugin.ts b/packages/sheets-drawing-ui/src/plugin.ts index 687b3aea75..535b3d1132 100644 --- a/packages/sheets-drawing-ui/src/plugin.ts +++ b/packages/sheets-drawing-ui/src/plugin.ts @@ -14,7 +14,14 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, LocaleService, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + IConfigService, + Inject, + Injector, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverDrawingUIPlugin } from '@univerjs/drawing-ui'; import { UniverSheetsDrawingPlugin } from '@univerjs/sheets-drawing'; @@ -22,14 +29,15 @@ import { UniverDrawingPlugin } from '@univerjs/drawing'; import { IRenderManagerService } from '@univerjs/engine-render'; import { DrawingPopupMenuController } from './controllers/drawing-popup-menu.controller'; import { SheetDrawingUpdateController } from './controllers/sheet-drawing-update.controller'; -import type { IUniverSheetsDrawingConfig } from './controllers/sheet-drawing.controller'; -import { DefaultSheetsDrawingConfig, SheetDrawingUIController } from './controllers/sheet-drawing.controller'; +import { SheetDrawingUIController } from './controllers/sheet-drawing.controller'; import { SheetDrawingTransformAffectedController } from './controllers/sheet-drawing-transform-affected.controller'; import { SheetCanvasFloatDomManagerService } from './services/canvas-float-dom-manager.service'; import { SheetDrawingPrintingController } from './controllers/sheet-drawing-printing.controller'; import { SheetDrawingPermissionController } from './controllers/sheet-drawing-permission.controller'; import { SheetsDrawingCopyPasteController } from './controllers/sheet-drawing-copy-paste.controller'; import { SheetsDrawingRenderController } from './controllers/render-controllers/sheet-drawing.render-controller'; +import type { IUniverSheetsDrawingUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'SHEET_IMAGE_UI_PLUGIN'; @@ -38,17 +46,20 @@ export class UniverSheetsDrawingUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; static override pluginName = PLUGIN_NAME; - private _pluginConfig: IUniverSheetsDrawingConfig; - constructor( - config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, - @Inject(LocaleService) private readonly _localeService: LocaleService, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._pluginConfig = Tools.deepMerge({}, DefaultSheetsDrawingConfig, config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { @@ -62,9 +73,7 @@ export class UniverSheetsDrawingUIPlugin extends Plugin { private _initDependencies(): void { const dependencies: Dependency[] = [ [SheetCanvasFloatDomManagerService], - [SheetDrawingUIController, { - useFactory: () => this._injector.createInstance(SheetDrawingUIController, this._pluginConfig), - }], + [SheetDrawingUIController], [DrawingPopupMenuController], [SheetDrawingPrintingController], [SheetDrawingPermissionController], diff --git a/packages/sheets-drawing/src/controllers/config.schema.ts b/packages/sheets-drawing/src/controllers/config.schema.ts new file mode 100644 index 0000000000..1451f6957b --- /dev/null +++ b/packages/sheets-drawing/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'sheets-drawing.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsDrawingConfig { +} + +export const defaultPluginConfig: IUniverSheetsDrawingConfig = {}; diff --git a/packages/sheets-drawing/src/plugin.ts b/packages/sheets-drawing/src/plugin.ts index e4b2201c33..0d166dc8ce 100644 --- a/packages/sheets-drawing/src/plugin.ts +++ b/packages/sheets-drawing/src/plugin.ts @@ -14,20 +14,27 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { SHEET_DRAWING_PLUGIN, SheetsDrawingLoadController } from './controllers/sheet-drawing.controller'; import { ISheetDrawingService, SheetDrawingService } from './services/sheet-drawing.service'; +import type { IUniverSheetsDrawingConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverSheetsDrawingPlugin extends Plugin { static override pluginName = SHEET_DRAWING_PLUGIN; static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: unknown, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts b/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts index 6d1968266b..cc4ca59f32 100644 --- a/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts +++ b/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts @@ -19,7 +19,7 @@ import { AuthzIoLocalService, DisposableCollection, IAuthzIoService, ICommandSer import { ExclusiveRangeService, IExclusiveRangeService, RangeProtectionRuleModel, RefRangeService, SetWorksheetActiveOperation, SheetInterceptorService, SheetsSelectionsService, WorkbookPermissionService, WorksheetPermissionService, WorksheetProtectionPointModel, WorksheetProtectionRuleModel } from '@univerjs/sheets'; import type { ISetSheetsFilterCriteriaMutationParams, ISetSheetsFilterRangeMutationParams } from '@univerjs/sheets-filter'; import { RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation, UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; -import { IMenuService, IPlatformService, IShortcutService, MenuService, PlatformService, ShortcutService } from '@univerjs/ui'; +import { IMenu2Service, IPlatformService, IShortcutService, Menu2Service, PlatformService, ShortcutService } from '@univerjs/ui'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SmartToggleSheetsFilterCommand } from '../../commands/commands/sheets-filter.command'; import { CloseFilterPanelOperation, OpenFilterPanelOperation } from '../../commands/operations/sheets-filter.operation'; @@ -68,7 +68,7 @@ function createSheetsFilterMenuTestBed() { injector.add([RefRangeService]); injector.add([SheetsSelectionsService]); injector.add([IShortcutService, { useClass: ShortcutService }]); - injector.add([IMenuService, { useClass: MenuService }]); + injector.add([IMenu2Service, { useClass: Menu2Service }]); injector.add([WorksheetPermissionService]); injector.add([WorksheetProtectionPointModel]); injector.add([WorkbookPermissionService]); diff --git a/packages/sheets-filter-ui/src/controllers/config.schema.ts b/packages/sheets-filter-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..430256033b --- /dev/null +++ b/packages/sheets-filter-ui/src/controllers/config.schema.ts @@ -0,0 +1,28 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-filter-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsFilterUIConfig { + menu?: MenuConfig; + useRemoteFilterValuesGenerator?: boolean; +} + +export const defaultPluginConfig: IUniverSheetsFilterUIConfig = {}; diff --git a/packages/sheets-filter-ui/src/controllers/menu.schema.ts b/packages/sheets-filter-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..be6b021bb4 --- /dev/null +++ b/packages/sheets-filter-ui/src/controllers/menu.schema.ts @@ -0,0 +1,44 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { + ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, + SmartToggleSheetsFilterCommand, +} from '../commands/commands/sheets-filter.command'; +import { + ClearFilterCriteriaMenuItemFactory, + ReCalcFilterMenuItemFactory, + SmartToggleFilterMenuItemFactory, +} from './sheets-filter.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [SmartToggleSheetsFilterCommand.id]: { + order: 10, + menuItemFactory: SmartToggleFilterMenuItemFactory, + [ClearSheetsFilterCriteriaCommand.id]: { + order: 0, + menuItemFactory: ClearFilterCriteriaMenuItemFactory, + }, + [ReCalcSheetsFilterCommand.id]: { + order: 1, + menuItemFactory: ReCalcFilterMenuItemFactory, + }, + }, + }, +}; diff --git a/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts b/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts index 6be9d62306..10a6b63d43 100644 --- a/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts +++ b/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts @@ -16,8 +16,7 @@ import type { IDisposable, Nullable } from '@univerjs/core'; import { ICommandService, IContextService, Inject, Injector, LocaleService } from '@univerjs/core'; -import { ComponentManager, IMenuService, IMessageService, IShortcutService } from '@univerjs/ui'; -import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service, IMessageService, IShortcutService } from '@univerjs/ui'; import { distinctUntilChanged } from 'rxjs'; import { SheetCanvasPopManagerService, SheetsRenderService } from '@univerjs/sheets-ui'; @@ -31,16 +30,8 @@ import { FilterPanel } from '../views/components/SheetsFilterPanel'; import { ChangeFilterByOperation, CloseFilterPanelOperation, FILTER_PANEL_OPENED_KEY, OpenFilterPanelOperation } from '../commands/operations/sheets-filter.operation'; import { SheetsFilterPanelService } from '../services/sheets-filter-panel.service'; import { SmartToggleFilterShortcut } from './sheets-filter.shortcut'; -import { ClearFilterCriteriaMenuItemFactory, ReCalcFilterMenuItemFactory, SmartToggleFilterMenuItemFactory } from './sheets-filter.menu'; import { SheetsFilterUIMobileController } from './sheets-filter-ui-mobile.controller'; - -export interface IUniverSheetsFilterUIConfig { - menu: MenuConfig; - - useRemoteFilterValuesGenerator?: boolean; -} - -export const DefaultSheetFilterUiConfig = {}; +import { menuSchema } from './menu.schema'; export const FILTER_PANEL_POPUP_KEY = 'FILTER_PANEL_POPUP'; @@ -49,7 +40,6 @@ export const FILTER_PANEL_POPUP_KEY = 'FILTER_PANEL_POPUP'; */ export class SheetsFilterUIDesktopController extends SheetsFilterUIMobileController { constructor( - private readonly _config: Partial, @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, @Inject(SheetsFilterPanelService) private readonly _sheetsFilterPanelService: SheetsFilterPanelService, @@ -58,7 +48,7 @@ export class SheetsFilterUIDesktopController extends SheetsFilterUIMobileControl @Inject(LocaleService) private _localeService: LocaleService, @IShortcutService private readonly _shortcutService: IShortcutService, @ICommandService private readonly _commandService: ICommandService, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @IContextService private readonly _contextService: IContextService, @IMessageService private readonly _messageService: IMessageService, @Inject(SheetsRenderService) sheetsRenderService: SheetsRenderService, @@ -103,15 +93,7 @@ export class SheetsFilterUIDesktopController extends SheetsFilterUIMobileControl } private _initMenuItems(): void { - const { menu = {} } = this._config; - - ([ - SmartToggleFilterMenuItemFactory, - ClearFilterCriteriaMenuItemFactory, - ReCalcFilterMenuItemFactory, - ] as IMenuItemFactory[]).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initUI(): void { diff --git a/packages/sheets-filter-ui/src/filter-ui-desktop.plugin.ts b/packages/sheets-filter-ui/src/filter-ui-desktop.plugin.ts index 2a92b50abf..b34598e9df 100644 --- a/packages/sheets-filter-ui/src/filter-ui-desktop.plugin.ts +++ b/packages/sheets-filter-ui/src/filter-ui-desktop.plugin.ts @@ -14,15 +14,24 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Optional, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + IConfigService, + Inject, + Injector, + Optional, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; import { IRPCChannelService, toModule } from '@univerjs/rpc'; -import type { IUniverSheetsFilterUIConfig } from './controllers/sheets-filter-ui-desktop.controller'; -import { DefaultSheetFilterUiConfig, SheetsFilterUIDesktopController } from './controllers/sheets-filter-ui-desktop.controller'; +import { SheetsFilterUIDesktopController } from './controllers/sheets-filter-ui-desktop.controller'; import { SheetsFilterPanelService } from './services/sheets-filter-panel.service'; import { SheetsFilterPermissionController } from './controllers/sheets-filter-permission.controller'; import { ISheetsGenerateFilterValuesService, SHEETS_GENERATE_FILTER_VALUES_SERVICE_NAME } from './worker/generate-filter-values.service'; +import type { IUniverSheetsFilterUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const NAME = 'SHEET_FILTER_UI_PLUGIN'; @@ -35,23 +44,26 @@ export class UniverSheetsFilterUIPlugin extends Plugin { static override pluginName = NAME; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService, @Optional(IRPCChannelService) private readonly _rpcChannelService?: IRPCChannelService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetFilterUiConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { ([ [SheetsFilterPanelService], [SheetsFilterPermissionController], - [SheetsFilterUIDesktopController, { - useFactory: (): SheetsFilterUIDesktopController => - this._injector.createInstance(SheetsFilterUIDesktopController, this._config), - }], + [SheetsFilterUIDesktopController], ] as Dependency[]).forEach((d) => this._injector.add(d)); if (this._config.useRemoteFilterValuesGenerator && this._rpcChannelService) { diff --git a/packages/sheets-filter-ui/src/filter-ui-mobile.plugin.ts b/packages/sheets-filter-ui/src/filter-ui-mobile.plugin.ts index 1c3fb512e0..0f525f7483 100644 --- a/packages/sheets-filter-ui/src/filter-ui-mobile.plugin.ts +++ b/packages/sheets-filter-ui/src/filter-ui-mobile.plugin.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; -import type { IUniverSheetsFilterUIConfig } from './controllers/sheets-filter-ui-desktop.controller'; -import { DefaultSheetFilterUiConfig } from './controllers/sheets-filter-ui-desktop.controller'; import { SheetsFilterPermissionController } from './controllers/sheets-filter-permission.controller'; import { SheetsFilterUIMobileController } from './controllers/sheets-filter-ui-mobile.controller'; +import type { IUniverSheetsFilterUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const NAME = 'SHEET_FILTER_UI_PLUGIN'; @@ -31,12 +31,18 @@ export class UniverSheetsFilterMobileUIPlugin extends Plugin { static override pluginName = NAME; constructor( - private readonly _config: Partial = {}, - @Inject(Injector) protected readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetFilterUiConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-filter/src/controllers/config.schema.ts b/packages/sheets-filter/src/controllers/config.schema.ts new file mode 100644 index 0000000000..ee86f80f5f --- /dev/null +++ b/packages/sheets-filter/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'sheets-filter.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsFilterConfig { +} + +export const defaultPluginConfig: IUniverSheetsFilterConfig = {}; diff --git a/packages/sheets-filter/src/plugin.ts b/packages/sheets-filter/src/plugin.ts index 826c2440cf..a898bdfdb2 100644 --- a/packages/sheets-filter/src/plugin.ts +++ b/packages/sheets-filter/src/plugin.ts @@ -14,18 +14,28 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { SHEET_FILTER_SNAPSHOT_ID, SheetsFilterService } from './services/sheet-filter.service'; import { SheetsFilterController } from './controllers/sheets-filter.controller'; +import type { IUniverSheetsFilterConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverSheetsFilterPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; static override pluginName = SHEET_FILTER_SNAPSHOT_ID; - constructor(_config: unknown, @Inject(Injector) protected readonly _injector: Injector) { + constructor( + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService + ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-find-replace/src/controllers/config.schema.ts b/packages/sheets-find-replace/src/controllers/config.schema.ts new file mode 100644 index 0000000000..98a7c1019d --- /dev/null +++ b/packages/sheets-find-replace/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'sheets-find-replace.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsFindReplaceConfig { +} + +export const defaultPluginConfig: IUniverSheetsFindReplaceConfig = {}; diff --git a/packages/sheets-find-replace/src/plugin.ts b/packages/sheets-find-replace/src/plugin.ts index 8a643f2744..2de442c915 100644 --- a/packages/sheets-find-replace/src/plugin.ts +++ b/packages/sheets-find-replace/src/plugin.ts @@ -14,11 +14,13 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverFindReplacePlugin } from '@univerjs/find-replace'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { SheetsFindReplaceController } from './controllers/sheet-find-replace.controller'; +import type { IUniverSheetsFindReplaceConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const NAME = 'SHEET_FIND_REPLACE_PLUGIN'; @@ -28,10 +30,15 @@ export class UniverSheetsFindReplacePlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - _config: unknown, - @Inject(Injector) protected readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-formula/src/controllers/config.schema.ts b/packages/sheets-formula/src/controllers/config.schema.ts new file mode 100644 index 0000000000..be09b61b17 --- /dev/null +++ b/packages/sheets-formula/src/controllers/config.schema.ts @@ -0,0 +1,60 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; +import type { BaseFunction, IFunctionInfo, IFunctionNames } from '@univerjs/engine-formula'; +import type { Ctor } from '@univerjs/core'; + +/** + * Base configuration for the plugin. + */ +export const PLUGIN_CONFIG_KEY_BASE = 'sheets-formula.base.config'; + +export const configSymbolBase = Symbol(PLUGIN_CONFIG_KEY_BASE); + +export interface IUniverSheetsFormulaBaseConfig { + menu?: MenuConfig; + notExecuteFormula?: boolean; + description?: IFunctionInfo[]; + function?: Array<[Ctor, IFunctionNames]>; +} + +export const defaultPluginBaseConfig: IUniverSheetsFormulaBaseConfig = {}; + +/** + * Remote configuration for the plugin. + */ +export const PLUGIN_CONFIG_KEY_REMOTE = 'sheets-formula.remote.config'; + +export const configSymbolRemote = Symbol(PLUGIN_CONFIG_KEY_REMOTE); + +export interface IUniverSheetsFormulaRemoteConfig { +} + +export const defaultPluginRemoteConfig: IUniverSheetsFormulaRemoteConfig = {}; + +/** + * Mobile configuration for the plugin. + */ +export const PLUGIN_CONFIG_KEY_MOBILE = 'sheets-formula.mobile.config'; + +export const configSymbolMobile = Symbol(PLUGIN_CONFIG_KEY_MOBILE); + +export interface IUniverSheetsFormulaMobileConfig { + menu?: MenuConfig; +} + +export const defaultPluginMobileConfig: IUniverSheetsFormulaMobileConfig = {}; diff --git a/packages/sheets-formula/src/controllers/formula-ui.controller.ts b/packages/sheets-formula/src/controllers/formula-ui.controller.ts index e45f07c7b3..1b5898db55 100644 --- a/packages/sheets-formula/src/controllers/formula-ui.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-ui.controller.ts @@ -15,12 +15,10 @@ */ import { connectInjector, Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, IMenuService, IShortcutService, IUIPartsService } from '@univerjs/ui'; -import type { Ctor, Dependency } from '@univerjs/core'; +import { BuiltInUIPart, ComponentManager, IMenu2Service, IShortcutService, IUIPartsService } from '@univerjs/ui'; +import type { Dependency } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; -import type { BaseFunction, IFunctionInfo, IFunctionNames } from '@univerjs/engine-formula'; import { SheetOnlyPasteFormulaCommand } from '../commands/commands/formula-clipboard.command'; import { InsertFunctionCommand } from '../commands/commands/insert-function.command'; import { SelectEditorFormulaOperation } from '../commands/operations/editor-formula.operation'; @@ -33,7 +31,6 @@ import { RenderFormulaPromptContent } from '../views/FormulaPromptContainer'; import { MORE_FUNCTIONS_COMPONENT } from '../views/more-functions/interface'; import { MoreFunctions } from '../views/more-functions/MoreFunctions'; import { OtherFormulaMarkDirty } from '../commands/mutations/formula.mutation'; -import { InsertFunctionMenuItemFactory, MoreFunctionsMenuItemFactory, PasteFormulaMenuItemFactory } from './menu'; import { ChangeRefToAbsoluteShortcut, promptSelectionShortcutItem, @@ -43,22 +40,13 @@ import { singleEditorPromptSelectionShortcutItem, } from './shortcuts/prompt.shortcut'; import { FormulaEditorShowController } from './formula-editor-show.controller'; - -export interface IUniverSheetsFormulaConfig { - menu: MenuConfig; - notExecuteFormula?: boolean; - description: IFunctionInfo[]; - function: Array<[Ctor, IFunctionNames]>; -} - -export const DefaultSheetFormulaConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, FormulaUIController) export class FormulaUIController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) private readonly _injector: Injector, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService private readonly _commandService: ICommandService, @IShortcutService private readonly _shortcutService: IShortcutService, @IUIPartsService private readonly _uiPartsService: IUIPartsService, @@ -79,13 +67,7 @@ export class FormulaUIController extends Disposable { } private _registerMenus(): void { - const { menu = {} } = this._config; - - [InsertFunctionMenuItemFactory, MoreFunctionsMenuItemFactory, PasteFormulaMenuItemFactory].forEach( - (factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - } - ); + this._menu2Service.mergeMenu(menuSchema); } private _registerCommands(): void { diff --git a/packages/sheets-formula/src/controllers/menu.schema.ts b/packages/sheets-formula/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..de6ab6cecf --- /dev/null +++ b/packages/sheets-formula/src/controllers/menu.schema.ts @@ -0,0 +1,42 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { PASTE_SPECIAL_MENU_ID } from '@univerjs/sheets-ui'; +import { InsertFunctionOperation } from '../commands/operations/insert-function.operation'; +import { MoreFunctionsOperation } from '../commands/operations/more-functions.operation'; +import { SheetOnlyPasteFormulaCommand } from '../commands/commands/formula-clipboard.command'; +import { InsertFunctionMenuItemFactory, MoreFunctionsMenuItemFactory, PasteFormulaMenuItemFactory } from './menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [InsertFunctionOperation.id]: { + order: 1, + menuItemFactory: InsertFunctionMenuItemFactory, + [MoreFunctionsOperation.id]: { + order: 1, + menuItemFactory: MoreFunctionsMenuItemFactory, + }, + }, + }, + [PASTE_SPECIAL_MENU_ID]: { + [SheetOnlyPasteFormulaCommand.id]: { + order: 4, + menuItemFactory: PasteFormulaMenuItemFactory, + }, + }, +}; diff --git a/packages/sheets-formula/src/formula-ui-plugin.ts b/packages/sheets-formula/src/formula-ui-plugin.ts index e2196b71ae..10fcd854c3 100644 --- a/packages/sheets-formula/src/formula-ui-plugin.ts +++ b/packages/sheets-formula/src/formula-ui-plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { fromModule, IRPCChannelService, toModule } from '@univerjs/rpc'; import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; @@ -27,8 +27,7 @@ import { ArrayFormulaDisplayController } from './controllers/array-formula-displ import { FormulaAutoFillController } from './controllers/formula-auto-fill.controller'; import { FormulaClipboardController } from './controllers/formula-clipboard.controller'; import { FormulaEditorShowController } from './controllers/formula-editor-show.controller'; -import type { IUniverSheetsFormulaConfig } from './controllers/formula-ui.controller'; -import { DefaultSheetFormulaConfig, FormulaUIController } from './controllers/formula-ui.controller'; +import { FormulaUIController } from './controllers/formula-ui.controller'; import { TriggerCalculationController } from './controllers/trigger-calculation.controller'; import { UpdateFormulaController } from './controllers/update-formula.controller'; import { DescriptionService, IDescriptionService } from './services/description.service'; @@ -42,6 +41,17 @@ import { FormulaRenderManagerController } from './controllers/formula-render.con import { RefSelectionsRenderService } from './services/render-services/ref-selections.render-service'; import { PromptController } from './controllers/prompt.controller'; import { IRemoteRegisterFunctionService, RemoteRegisterFunctionService, RemoteRegisterFunctionServiceName } from './services/remote/remote-register-function.service'; +import type { + IUniverSheetsFormulaBaseConfig, IUniverSheetsFormulaMobileConfig, + IUniverSheetsFormulaRemoteConfig } from './controllers/config.schema'; +import { + defaultPluginBaseConfig, defaultPluginMobileConfig, + + defaultPluginRemoteConfig + , PLUGIN_CONFIG_KEY_BASE, + + PLUGIN_CONFIG_KEY_MOBILE, + PLUGIN_CONFIG_KEY_REMOTE } from './controllers/config.schema'; @DependentOn(UniverFormulaEnginePlugin) export class UniverRemoteSheetsFormulaPlugin extends Plugin { @@ -49,10 +59,15 @@ export class UniverRemoteSheetsFormulaPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config = {}, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginRemoteConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY_REMOTE, rest); } override onStarting(): void { @@ -73,13 +88,19 @@ export class UniverSheetsFormulaPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginBaseConfig, @Inject(Injector) override readonly _injector: Injector, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetFormulaConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY_BASE, rest); } override onStarting(): void { @@ -87,11 +108,11 @@ export class UniverSheetsFormulaPlugin extends Plugin { const dependencies: Dependency[] = [ [IFormulaPromptService, { useClass: FormulaPromptService }], [IRefSelectionsService, { useClass: RefSelectionsService }], - [IDescriptionService, { useFactory: () => j.createInstance(DescriptionService, this._config?.description) }], + [IDescriptionService, { useClass: DescriptionService }], [IRegisterFunctionService, { useClass: RegisterFunctionService }], [FormulaRefRangeService], [RegisterOtherFormulaService], - [FormulaUIController, { useFactory: () => j.createInstance(FormulaUIController, this._config) }], + [FormulaUIController], [FormulaAutoFillController], [FormulaClipboardController], [ArrayFormulaDisplayController], @@ -131,12 +152,18 @@ export class UniverSheetsFormulaMobilePlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginMobileConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetFormulaConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY_MOBILE, rest); } override onStarting(): void { @@ -147,12 +174,7 @@ export class UniverSheetsFormulaMobilePlugin extends Plugin { const dependencies: Dependency[] = [ // services [IFormulaPromptService, { useClass: FormulaPromptService }], - [ - IDescriptionService, - { - useFactory: () => this._injector.createInstance(DescriptionService, this._config?.description), - }, - ], + [IDescriptionService, { useClass: DescriptionService }], [IRegisterFunctionService, { useClass: RegisterFunctionService }], [FormulaRefRangeService], [RegisterOtherFormulaService], diff --git a/packages/sheets-formula/src/services/description.service.ts b/packages/sheets-formula/src/services/description.service.ts index b0b4c20b5c..ff2f9dffab 100644 --- a/packages/sheets-formula/src/services/description.service.ts +++ b/packages/sheets-formula/src/services/description.service.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createIdentifier, Inject, LocaleService, toDisposable } from '@univerjs/core'; +import { createIdentifier, IConfigService, Inject, LocaleService, toDisposable } from '@univerjs/core'; import type { IFunctionInfo, IFunctionNames } from '@univerjs/engine-formula'; import { functionArray, @@ -39,6 +39,8 @@ import { } from '@univerjs/engine-formula'; import type { IDisposable } from '@univerjs/core'; +import type { IUniverSheetsFormulaBaseConfig } from '../controllers/config.schema'; +import { PLUGIN_CONFIG_KEY_BASE } from '../controllers/config.schema'; import { FUNCTION_LIST } from './function-list/function-list'; import { getFunctionName } from './utils'; @@ -119,9 +121,9 @@ export class DescriptionService implements IDescriptionService, IDisposable { private _descriptions: IFunctionInfo[] = []; constructor( - private _description: IFunctionInfo[] = [], @IFunctionService private readonly _functionService: IFunctionService, - @Inject(LocaleService) private readonly _localeService: LocaleService + @Inject(LocaleService) private readonly _localeService: LocaleService, + @IConfigService private readonly _configService: IConfigService ) { this._initialize(); } @@ -255,7 +257,10 @@ export class DescriptionService implements IDescriptionService, IDisposable { return functions.includes(item.functionName as IFunctionNames); }); - this._descriptions = filterFunctionList.concat(this._description); + const config = this._configService.getConfig(PLUGIN_CONFIG_KEY_BASE); + if (config?.description) { + this._descriptions = filterFunctionList.concat(config.description); + } } private _registerDescriptions() { diff --git a/packages/sheets-hyper-link-ui/src/types/interfaces/i-config.ts b/packages/sheets-hyper-link-ui/src/controllers/config.schema.ts similarity index 81% rename from packages/sheets-hyper-link-ui/src/types/interfaces/i-config.ts rename to packages/sheets-hyper-link-ui/src/controllers/config.schema.ts index 24f816ee4d..1152f44c62 100644 --- a/packages/sheets-hyper-link-ui/src/types/interfaces/i-config.ts +++ b/packages/sheets-hyper-link-ui/src/controllers/config.schema.ts @@ -16,11 +16,16 @@ import type { MenuConfig } from '@univerjs/ui'; +export const PLUGIN_CONFIG_KEY = 'sheets-hyper-link-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + export interface IUrlHandler { navigateToOtherWebsite?: (url: string) => void; } - export interface IUniverSheetsHyperLinkUIConfig { menu?: MenuConfig; urlHandler?: IUrlHandler; } + +export const defaultPluginConfig: IUniverSheetsHyperLinkUIConfig = {}; diff --git a/packages/sheets-hyper-link-ui/src/controllers/menu.schema.ts b/packages/sheets-hyper-link-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..1bbf08bdd2 --- /dev/null +++ b/packages/sheets-hyper-link-ui/src/controllers/menu.schema.ts @@ -0,0 +1,38 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; +import { InsertHyperLinkToolbarOperation } from '../commands/operations/sidebar.operations'; +import { insertLinkMenuFactory, insertLinkMenuToolbarFactory } from './menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.OTHERS]: { + [InsertHyperLinkToolbarOperation.id]: { + order: 2, + menuItemFactory: insertLinkMenuToolbarFactory, + }, + }, + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.OTHERS]: { + order: 1, + [InsertHyperLinkToolbarOperation.id]: { + order: 0, + menuItemFactory: insertLinkMenuFactory, + }, + }, + }, +}; diff --git a/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts b/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts index fc7c6a0def..64d4ab02e6 100644 --- a/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts +++ b/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts @@ -14,27 +14,24 @@ * limitations under the License. */ -import type { Nullable } from '@univerjs/core'; -import { Disposable, ICommandService, Inject, Injector, LifecycleStages, LocaleService, OnLifecycle } from '@univerjs/core'; -import { ComponentManager, IMenuService, IShortcutService } from '@univerjs/ui'; +import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { ComponentManager, IMenu2Service, IShortcutService } from '@univerjs/ui'; import { LinkSingle } from '@univerjs/icons'; import { CellLinkPopup } from '../views/CellLinkPopup'; import { CellLinkEdit } from '../views/CellLinkEdit'; import { CloseHyperLinkSidebarOperation, InsertHyperLinkOperation, InsertHyperLinkToolbarOperation, OpenHyperLinkSidebarOperation } from '../commands/operations/sidebar.operations'; -import type { IUniverSheetsHyperLinkUIConfig } from '../types/interfaces/i-config'; import { AddHyperLinkCommand } from '../commands/commands/add-hyper-link.command'; import { UpdateHyperLinkCommand } from '../commands/commands/update-hyper-link.command'; import { CancelHyperLinkCommand, RemoveHyperLinkCommand } from '../commands/commands/remove-hyper-link.command'; -import { insertLinkMenuFactory, insertLinkMenuToolbarFactory, InsertLinkShortcut } from './menu'; +import { InsertLinkShortcut } from './menu'; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, SheetsHyperLinkUIController) export class SheetsHyperLinkUIController extends Disposable { constructor( - private _config: Nullable, @Inject(ComponentManager) private _componentManager: ComponentManager, @ICommandService private _commandService: ICommandService, - @Inject(LocaleService) private _localeService: LocaleService, - @IMenuService private _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @Inject(Injector) private _injector: Injector, @Inject(IShortcutService) private _shortcutService: IShortcutService ) { @@ -73,8 +70,7 @@ export class SheetsHyperLinkUIController extends Disposable { } private _initMenus() { - this._menuService.addMenuItem(insertLinkMenuFactory(this._injector), this._config?.menu ?? {}); - this._menuService.addMenuItem(insertLinkMenuToolbarFactory(this._injector), this._config?.menu ?? {}); + this._menu2Service.mergeMenu(menuSchema); } private _initShortCut() { diff --git a/packages/sheets-hyper-link-ui/src/index.ts b/packages/sheets-hyper-link-ui/src/index.ts index 3dd23d9a0a..bb3b2c4da5 100644 --- a/packages/sheets-hyper-link-ui/src/index.ts +++ b/packages/sheets-hyper-link-ui/src/index.ts @@ -20,7 +20,6 @@ export { SheetsHyperLinkResolverService } from './services/resolver.service'; export { SheetsHyperLinkCopyPasteController } from './controllers/copy-paste.controller'; export { UniverSheetsHyperLinkUIPlugin } from './plugin'; export { InsertLinkShortcut } from './controllers/menu'; -export type { IUrlHandler, IUniverSheetsHyperLinkUIConfig } from './types/interfaces/i-config'; // #region - all commands export { diff --git a/packages/sheets-hyper-link-ui/src/plugin.ts b/packages/sheets-hyper-link-ui/src/plugin.ts index 0875042a16..e46126f240 100644 --- a/packages/sheets-hyper-link-ui/src/plugin.ts +++ b/packages/sheets-hyper-link-ui/src/plugin.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import type { Dependency, Nullable } from '@univerjs/core'; -import { DependentOn, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import type { Dependency } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link'; import { IRenderManagerService } from '@univerjs/engine-render'; import { SheetsHyperLinkRemoveSheetController } from './controllers/remove-sheet.controller'; @@ -31,7 +31,8 @@ import { SheetsHyperLinkCopyPasteController } from './controllers/copy-paste.con import { SheetHyperLinkUrlController } from './controllers/url.controller'; import { SheetsHyperLinkPermissionController } from './controllers/hyper-link-permission.controller'; import { SheetsHyperLinkSidePanelService } from './services/side-panel.service'; -import type { IUniverSheetsHyperLinkUIConfig } from './types/interfaces/i-config'; +import type { IUniverSheetsHyperLinkUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverSheetsHyperLinkPlugin) export class UniverSheetsHyperLinkUIPlugin extends Plugin { @@ -39,21 +40,24 @@ export class UniverSheetsHyperLinkUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private _config: Nullable, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected override _injector: Injector, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { const dependencies: Dependency[] = [ - [ - SheetsHyperLinkResolverService, - { - useFactory: () => this._injector.createInstance(SheetsHyperLinkResolverService, this._config?.urlHandler), - }, - ], + [SheetsHyperLinkResolverService], [SheetsHyperLinkPopupService], [SheetsHyperLinkSidePanelService], @@ -61,12 +65,7 @@ export class UniverSheetsHyperLinkUIPlugin extends Plugin { [SheetsHyperLinkRenderManagerController], [SheetHyperLinkSetRangeController], [SheetsHyperLinkPopupController], - [ - SheetsHyperLinkUIController, - { - useFactory: () => this._injector.createInstance(SheetsHyperLinkUIController, this._config), - }, - ], + [SheetsHyperLinkUIController], [SheetsHyperLinkAutoFillController], [SheetsHyperLinkCopyPasteController], [SheetsHyperLinkPermissionController], diff --git a/packages/sheets-hyper-link-ui/src/services/resolver.service.ts b/packages/sheets-hyper-link-ui/src/services/resolver.service.ts index d91a12e0cc..d51a57ffa2 100644 --- a/packages/sheets-hyper-link-ui/src/services/resolver.service.ts +++ b/packages/sheets-hyper-link-ui/src/services/resolver.service.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import type { IRange, Nullable, Workbook, Worksheet } from '@univerjs/core'; -import { ICommandService, Inject, isValidRange, IUniverInstanceService, LocaleService, RANGE_TYPE, Rectangle, UniverInstanceType } from '@univerjs/core'; +import type { IRange, Workbook, Worksheet } from '@univerjs/core'; +import { ICommandService, IConfigService, Inject, isValidRange, IUniverInstanceService, LocaleService, RANGE_TYPE, Rectangle, UniverInstanceType } from '@univerjs/core'; import { MessageType } from '@univerjs/design'; import { deserializeRangeWithSheet, IDefinedNamesService, serializeRangeWithSheet } from '@univerjs/engine-formula'; import type { ISetSelectionsOperationParams } from '@univerjs/sheets'; @@ -23,7 +23,8 @@ import { SetSelectionsOperation, SetWorksheetActiveOperation } from '@univerjs/s import { ERROR_RANGE } from '@univerjs/sheets-hyper-link'; import { ScrollToRangeOperation } from '@univerjs/sheets-ui'; import { IMessageService } from '@univerjs/ui'; -import type { IUrlHandler } from '../types/interfaces/i-config'; +import type { IUniverSheetsHyperLinkUIConfig } from '../controllers/config.schema'; +import { PLUGIN_CONFIG_KEY } from '../controllers/config.schema'; interface ISheetUrlParams { gid?: string; @@ -66,12 +67,12 @@ export interface IHyperLinkInfo { export class SheetsHyperLinkResolverService { constructor( - private _urlHandler: Nullable, @IUniverInstanceService private _univerInstanceService: IUniverInstanceService, @ICommandService private _commandService: ICommandService, @IDefinedNamesService private _definedNamesService: IDefinedNamesService, @IMessageService private _messageService: IMessageService, - @Inject(LocaleService) private _localeService: LocaleService + @Inject(LocaleService) private _localeService: LocaleService, + @IConfigService private _configService: IConfigService ) { } private _getURLName(params: ISheetUrlParams) { @@ -285,8 +286,10 @@ export class SheetsHyperLinkResolverService { } async navigateToOtherWebsite(url: string) { - if (this._urlHandler?.navigateToOtherWebsite) { - return this._urlHandler.navigateToOtherWebsite(url); + const config = this._configService.getConfig(PLUGIN_CONFIG_KEY); + + if (config?.urlHandler?.navigateToOtherWebsite) { + return config.urlHandler.navigateToOtherWebsite(url); } window.open(url, '_blank', 'noopener noreferrer'); diff --git a/packages/sheets-hyper-link/src/controllers/config.schema.ts b/packages/sheets-hyper-link/src/controllers/config.schema.ts new file mode 100644 index 0000000000..f804606cf6 --- /dev/null +++ b/packages/sheets-hyper-link/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'sheets-hyper-link.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsHyperLinkConfig { +} + +export const defaultPluginConfig: IUniverSheetsHyperLinkConfig = {}; diff --git a/packages/sheets-hyper-link/src/plugin.ts b/packages/sheets-hyper-link/src/plugin.ts index 4c5cfb0dd7..e3d6ec1607 100644 --- a/packages/sheets-hyper-link/src/plugin.ts +++ b/packages/sheets-hyper-link/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { SheetsHyperLinkController } from './controllers/sheet-hyper-link.controller'; @@ -22,6 +22,8 @@ import { HyperLinkModel } from './models/hyper-link.model'; import { SHEET_HYPER_LINK_PLUGIN } from './types/const'; import { SheetsHyperLinkResourceController } from './controllers/sheet-hyper-link-resource.controller'; import { SheetsHyperLinkRefRangeController } from './controllers/ref-range.controller'; +import type { IUniverSheetsHyperLinkConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverSheetsPlugin) export class UniverSheetsHyperLinkPlugin extends Plugin { @@ -29,10 +31,15 @@ export class UniverSheetsHyperLinkPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - config: unknown, - @Inject(Injector) protected _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-numfmt/src/controllers/config.schema.ts b/packages/sheets-numfmt/src/controllers/config.schema.ts new file mode 100644 index 0000000000..a8145359a5 --- /dev/null +++ b/packages/sheets-numfmt/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-numfmt.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsNumfmtConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSheetsNumfmtConfig = {}; diff --git a/packages/sheets-numfmt/src/controllers/menu.schema.ts b/packages/sheets-numfmt/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..8259d3c60b --- /dev/null +++ b/packages/sheets-numfmt/src/controllers/menu.schema.ts @@ -0,0 +1,49 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { SetCurrencyCommand } from '../commands/commands/set-currency.command'; +import { AddDecimalMenuItem, CurrencyMenuItem, FactoryOtherMenuItem, PercentMenuItem, SubtractDecimalMenuItem } from '../menu/menu'; +import { SubtractDecimalCommand } from '../commands/commands/subtract-decimal.command'; +import { SetPercentCommand } from '../commands/commands/set-percent.command'; +import { OpenNumfmtPanelOperator } from '../commands/operations/open.numfmt.panel.operation'; +import { AddDecimalCommand } from '../commands/commands/add-decimal.command'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [SetCurrencyCommand.id]: { + order: 4, + menuItemFactory: CurrencyMenuItem, + }, + [AddDecimalCommand.id]: { + order: 5, + menuItemFactory: AddDecimalMenuItem, + }, + [SubtractDecimalCommand.id]: { + order: 6, + menuItemFactory: SubtractDecimalMenuItem, + }, + [SetPercentCommand.id]: { + order: 7, + menuItemFactory: PercentMenuItem, + }, + [OpenNumfmtPanelOperator.id]: { + order: 8, + menuItemFactory: FactoryOtherMenuItem, + }, + }, +}; diff --git a/packages/sheets-numfmt/src/controllers/numfmt.currency.controller.ts b/packages/sheets-numfmt/src/controllers/numfmt.currency.controller.ts new file mode 100644 index 0000000000..fde35b6afd --- /dev/null +++ b/packages/sheets-numfmt/src/controllers/numfmt.currency.controller.ts @@ -0,0 +1,43 @@ +/** + * 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 { Disposable, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; + +import { BehaviorSubject } from 'rxjs'; +import type { countryCurrencyMap } from '../base/const/CURRENCY-SYMBOLS'; + +@OnLifecycle(LifecycleStages.Rendered, NumfmtCurrencyController) +export class NumfmtCurrencyController extends Disposable { + private _currencySymbol$ = new BehaviorSubject('US'); + public readonly currencySymbol$ = this._currencySymbol$.asObservable(); + + constructor( + @Inject(Injector) private _injector: Injector + ) { + super(); + } + + /** + * Set the currency symbol by setting the country code. + */ + public setCurrencySymbolByCountryCode(symbol: keyof typeof countryCurrencyMap) { + this._currencySymbol$.next(symbol); + } + + public getCurrencySymbol() { + return this._currencySymbol$.getValue(); + } +} diff --git a/packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts b/packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts index 075022e7df..ab7897ed58 100644 --- a/packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts +++ b/packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts @@ -15,43 +15,24 @@ */ import { Disposable, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service } from '@univerjs/ui'; -import { BehaviorSubject } from 'rxjs'; -import { AddDecimalMenuItem, CurrencyMenuItem, FactoryOtherMenuItem, PercentMenuItem, SubtractDecimalMenuItem } from '../menu/menu'; import { MORE_NUMFMT_TYPE_KEY, MoreNumfmtType, Options, OPTIONS_KEY } from '../components/more-numfmt-type/MoreNumfmtType'; -import type { countryCurrencyMap } from '../base/const/CURRENCY-SYMBOLS'; - -export interface IUniverSheetsNumfmtConfig { - menu: MenuConfig; -} - -export const DefaultSheetNumfmtConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Rendered, NumfmtMenuController) export class NumfmtMenuController extends Disposable { - private _currencySymbol$ = new BehaviorSubject('US'); - public readonly currencySymbol$ = this._currencySymbol$.asObservable(); - constructor( - private readonly _config: Partial, @Inject(Injector) private _injector: Injector, @Inject(ComponentManager) private _componentManager: ComponentManager, - @Inject(IMenuService) private _menuService: IMenuService - + @IMenu2Service private readonly _menu2Service: IMenu2Service ) { super(); this._initMenu(); } private _initMenu() { - const { menu = {} } = this._config; - - [PercentMenuItem, AddDecimalMenuItem, SubtractDecimalMenuItem, CurrencyMenuItem, FactoryOtherMenuItem] - .forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(factory(this._injector), menu)); - }); + this._menu2Service.mergeMenu(menuSchema); this.disposeWithMe((this._componentManager.register(MORE_NUMFMT_TYPE_KEY, MoreNumfmtType))); this.disposeWithMe((this._componentManager.register(OPTIONS_KEY, Options))); diff --git a/packages/sheets-numfmt/src/numfmt-plugin.ts b/packages/sheets-numfmt/src/numfmt-plugin.ts index bdcf8b2e51..b9b1ed98aa 100644 --- a/packages/sheets-numfmt/src/numfmt-plugin.ts +++ b/packages/sheets-numfmt/src/numfmt-plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; @@ -23,11 +23,13 @@ import { SheetsNumfmtCellContentController } from './controllers/numfmt.cell-con import { NumfmtController } from './controllers/numfmt.controller'; import { NumfmtEditorController } from './controllers/numfmt.editor.controller'; import { NumfmtI18nController } from './controllers/numfmt.i18n.controller'; -import type { IUniverSheetsNumfmtConfig } from './controllers/numfmt.menu.controller'; -import { DefaultSheetNumfmtConfig, NumfmtMenuController } from './controllers/numfmt.menu.controller'; +import { NumfmtMenuController } from './controllers/numfmt.menu.controller'; +import { NumfmtCurrencyController } from './controllers/numfmt.currency.controller'; import { INumfmtController } from './controllers/type'; import { UserHabitController } from './controllers/user-habit.controller'; import { MenuCurrencyService } from './service/menu.currency.service'; +import type { IUniverSheetsNumfmtConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverSheetsPlugin, UniverSheetsUIPlugin) export class UniverSheetsNumfmtPlugin extends Plugin { @@ -35,23 +37,28 @@ export class UniverSheetsNumfmtPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetNumfmtConfig, this._config); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + } + + override onStarting(): void { this._injector.add([INumfmtController, { useClass: NumfmtController, lazy: false }]); this._injector.add([NumfmtEditorController]); this._injector.add([UserHabitController]); this._injector.add([SheetsNumfmtCellContentController]); this._injector.add([NumfmtI18nController]); this._injector.add([MenuCurrencyService]); - this._injector.add( - [ - NumfmtMenuController, - { - useFactory: () => this._injector.createInstance(NumfmtMenuController, this._config), - }, - ]); + this._injector.add([NumfmtCurrencyController]); + this._injector.add([NumfmtMenuController]); } } diff --git a/packages/sheets-sort-ui/src/controllers/config.schema.ts b/packages/sheets-sort-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..b78cb969d4 --- /dev/null +++ b/packages/sheets-sort-ui/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-sort-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsSortUIConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSheetsSortUIConfig = {}; diff --git a/packages/sheets-sort-ui/src/controllers/menu.schema.ts b/packages/sheets-sort-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..cb5d4a37d5 --- /dev/null +++ b/packages/sheets-sort-ui/src/controllers/menu.schema.ts @@ -0,0 +1,99 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, RibbonStartGroup } from '@univerjs/ui'; +import { + SortRangeAscCommand, + SortRangeAscExtCommand, + SortRangeAscExtInCtxMenuCommand, + SortRangeAscInCtxMenuCommand, + SortRangeCustomCommand, + SortRangeCustomInCtxMenuCommand, + SortRangeDescCommand, + SortRangeDescExtCommand, + SortRangeDescExtInCtxMenuCommand, + SortRangeDescInCtxMenuCommand, +} from '../commands/commands/sheets-sort.command'; +import { + SHEETS_SORT_CTX_MENU_ID, + SHEETS_SORT_MENU_ID, + sortRangeAscCtxMenuFactory, + sortRangeAscExtCtxMenuFactory, + sortRangeAscExtMenuFactory, + sortRangeAscMenuFactory, + sortRangeCtxMenuFactory, sortRangeCustomCtxMenuFactory, + sortRangeCustomMenuFactory, + sortRangeDescCtxMenuFactory, sortRangeDescExtCtxMenuFactory, + sortRangeDescExtMenuFactory, + sortRangeDescMenuFactory, + sortRangeMenuFactory, +} from './sheets-sort.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMULAS_INSERT]: { + [SHEETS_SORT_MENU_ID]: { + order: 2, + menuItemFactory: sortRangeMenuFactory, + [SortRangeAscCommand.id]: { + order: 0, + menuItemFactory: sortRangeAscMenuFactory, + }, + [SortRangeAscExtCommand.id]: { + order: 1, + menuItemFactory: sortRangeAscExtMenuFactory, + }, + [SortRangeDescCommand.id]: { + order: 2, + menuItemFactory: sortRangeDescMenuFactory, + }, + [SortRangeDescExtCommand.id]: { + order: 3, + menuItemFactory: sortRangeDescExtMenuFactory, + }, + [SortRangeCustomCommand.id]: { + order: 4, + menuItemFactory: sortRangeCustomMenuFactory, + }, + }, + }, + [ContextMenuGroup.DATA]: { + [SHEETS_SORT_CTX_MENU_ID]: { + order: 0, + menuItemFactory: sortRangeCtxMenuFactory, + [SortRangeAscInCtxMenuCommand.id]: { + order: 0, + menuItemFactory: sortRangeAscCtxMenuFactory, + }, + [SortRangeAscExtInCtxMenuCommand.id]: { + order: 1, + menuItemFactory: sortRangeAscExtCtxMenuFactory, + }, + [SortRangeDescInCtxMenuCommand.id]: { + order: 2, + menuItemFactory: sortRangeDescCtxMenuFactory, + }, + [SortRangeDescExtInCtxMenuCommand.id]: { + order: 3, + menuItemFactory: sortRangeDescExtCtxMenuFactory, + }, + [SortRangeCustomInCtxMenuCommand.id]: { + order: 4, + menuItemFactory: sortRangeCustomCtxMenuFactory, + }, + }, + }, +}; diff --git a/packages/sheets-sort-ui/src/controllers/sheets-sort-ui.controller.ts b/packages/sheets-sort-ui/src/controllers/sheets-sort-ui.controller.ts index 028191cb45..11bc115a97 100644 --- a/packages/sheets-sort-ui/src/controllers/sheets-sort-ui.controller.ts +++ b/packages/sheets-sort-ui/src/controllers/sheets-sort-ui.controller.ts @@ -16,8 +16,8 @@ import { connectInjector, ICommandService, Inject, Injector, LifecycleStages, LocaleService, OnLifecycle, RxDisposable } from '@univerjs/core'; -import type { MenuConfig, UIPartsService } from '@univerjs/ui'; -import { ComponentManager, IDialogService, ILayoutService, IMenuService, IUIPartsService } from '@univerjs/ui'; +import type { UIPartsService } from '@univerjs/ui'; +import { ComponentManager, IDialogService, ILayoutService, IMenu2Service, IUIPartsService } from '@univerjs/ui'; import { takeUntil } from 'rxjs'; import { serializeRange } from '@univerjs/engine-formula'; import { AscendingSingle, CustomSortSingle, DescendingSingle, ExpandAscendingSingle, ExpandDescendingSingle } from '@univerjs/icons'; @@ -28,14 +28,8 @@ import { CustomSortPanel } from '../views/CustomSortPanel'; import type { ISheetSortLocation } from '../services/sheets-sort-ui.service'; import { SheetsSortUIService } from '../services/sheets-sort-ui.service'; import EmbedSortBtn from '../views/EmbedSortBtn'; -import { SHEETS_SORT_ASC_EXT_ICON, SHEETS_SORT_ASC_ICON, SHEETS_SORT_CUSTOM_ICON, SHEETS_SORT_DESC_EXT_ICON, SHEETS_SORT_DESC_ICON, sortRangeAscCtxMenuFactory, sortRangeAscExtCtxMenuFactory, sortRangeAscExtMenuFactory, sortRangeAscMenuFactory, sortRangeCtxMenuFactory, sortRangeCustomCtxMenuFactory, sortRangeCustomMenuFactory, sortRangeDescCtxMenuFactory, sortRangeDescExtCtxMenuFactory, sortRangeDescExtMenuFactory, sortRangeDescMenuFactory, sortRangeMenuFactory } from './sheets-sort.menu'; - -export interface IUniverSheetsSortUIConfig { - menu: MenuConfig; -} -export const DefaultSheetsSortUIConfig = { - menu: {}, -}; +import { menuSchema } from './menu.schema'; +import { SHEETS_SORT_ASC_EXT_ICON, SHEETS_SORT_ASC_ICON, SHEETS_SORT_CUSTOM_ICON, SHEETS_SORT_DESC_EXT_ICON, SHEETS_SORT_DESC_ICON } from './sheets-sort.menu'; const CUSTOM_SORT_DIALOG_ID = 'custom-sort-dialog'; const CUSTOM_SORT_PANEL_WIDTH = 560; @@ -43,9 +37,8 @@ const CUSTOM_SORT_PANEL_WIDTH = 560; @OnLifecycle(LifecycleStages.Ready, SheetsSortUIController) export class SheetsSortUIController extends RxDisposable { constructor( - private readonly _config: Partial, @ICommandService private readonly _commandService: ICommandService, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @IDialogService private readonly _dialogService: IDialogService, @ILayoutService private readonly _layoutService: ILayoutService, @IUIPartsService private readonly _uiPartsService: UIPartsService, @@ -62,27 +55,7 @@ export class SheetsSortUIController extends RxDisposable { } private _initMenu() { - const { menu = {} } = this._config; - [ - sortRangeMenuFactory, - sortRangeAscMenuFactory, - sortRangeDescMenuFactory, - sortRangeAscExtMenuFactory, - sortRangeDescExtMenuFactory, - sortRangeCustomMenuFactory, - sortRangeCtxMenuFactory, - sortRangeAscCtxMenuFactory, - sortRangeDescCtxMenuFactory, - sortRangeAscExtCtxMenuFactory, - sortRangeDescExtCtxMenuFactory, - sortRangeCustomCtxMenuFactory, - ].forEach((factory) => { - this.disposeWithMe( - this._menuService.addMenuItem( - this._injector.invoke(factory), menu - ) - ); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initCommands(): void { diff --git a/packages/sheets-sort-ui/src/controllers/sheets-sort.menu.ts b/packages/sheets-sort-ui/src/controllers/sheets-sort.menu.ts index 0592232134..9253b574a0 100644 --- a/packages/sheets-sort-ui/src/controllers/sheets-sort.menu.ts +++ b/packages/sheets-sort-ui/src/controllers/sheets-sort.menu.ts @@ -21,8 +21,8 @@ import { getCurrentRangeDisable$, SheetMenuPosition } from '@univerjs/sheets-ui' import { RangeProtectionPermissionEditPoint, WorkbookEditablePermission, WorksheetEditPermission, WorksheetSortPermission } from '@univerjs/sheets'; import { SortRangeAscCommand, SortRangeAscExtCommand, SortRangeAscExtInCtxMenuCommand, SortRangeAscInCtxMenuCommand, SortRangeCustomCommand, SortRangeCustomInCtxMenuCommand, SortRangeDescCommand, SortRangeDescExtCommand, SortRangeDescExtInCtxMenuCommand, SortRangeDescInCtxMenuCommand } from '../commands/commands/sheets-sort.command'; -const SHEETS_SORT_MENU_ID = 'sheet.menu.sheets-sort'; -const SHEETS_SORT_CTX_MENU_ID = 'sheet.menu.sheets-sort-ctx'; +export const SHEETS_SORT_MENU_ID = 'sheet.menu.sheets-sort'; +export const SHEETS_SORT_CTX_MENU_ID = 'sheet.menu.sheets-sort-ctx'; export const SHEETS_SORT_ASC_ICON = 'AscendingSingle'; export const SHEETS_SORT_ASC_EXT_ICON = 'ExpandAscendingSingle'; diff --git a/packages/sheets-sort-ui/src/plugin.ts b/packages/sheets-sort-ui/src/plugin.ts index 529def64b3..6a9b1649c6 100644 --- a/packages/sheets-sort-ui/src/plugin.ts +++ b/packages/sheets-sort-ui/src/plugin.ts @@ -14,13 +14,21 @@ * limitations under the License. */ -import { DependentOn, Inject, Injector, LocaleService, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { + DependentOn, + IConfigService, + Inject, + Injector, + Plugin, + UniverInstanceType, +} from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort'; import { SheetsSortUIService } from './services/sheets-sort-ui.service'; -import type { IUniverSheetsSortUIConfig } from './controllers/sheets-sort-ui.controller'; -import { DefaultSheetsSortUIConfig, SheetsSortUIController } from './controllers/sheets-sort-ui.controller'; +import { SheetsSortUIController } from './controllers/sheets-sort-ui.controller'; +import type { IUniverSheetsSortUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const NAME = 'UNIVER_SHEETS_SORT_UI_PLUGIN'; @DependentOn(UniverSheetsSortPlugin) @@ -29,21 +37,21 @@ export class UniverSheetsSortUIPlugin extends Plugin { static override pluginName = NAME; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected readonly _injector: Injector, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetsSortUIConfig, this._config); + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { ([ [SheetsSortUIService], - [SheetsSortUIController, { - useFactory: () => this._injector.createInstance(SheetsSortUIController, this._config), - }], + [SheetsSortUIController], ] as Dependency[]).forEach((d) => this._injector.add(d)); } } diff --git a/packages/sheets-sort/src/controllers/config.schema.ts b/packages/sheets-sort/src/controllers/config.schema.ts new file mode 100644 index 0000000000..8cec3eb70f --- /dev/null +++ b/packages/sheets-sort/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'sheets-sort.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsSortConfig { +} + +export const defaultPluginConfig: IUniverSheetsSortConfig = {}; diff --git a/packages/sheets-sort/src/plugin.ts b/packages/sheets-sort/src/plugin.ts index 1eec295fda..2815b6e115 100644 --- a/packages/sheets-sort/src/plugin.ts +++ b/packages/sheets-sort/src/plugin.ts @@ -14,11 +14,13 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { SheetsSortController } from './controllers/sheets-sort.controller'; import { SheetsSortService } from './services/sheets-sort.service'; +import type { IUniverSheetsSortConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const NAME = 'UNIVER_SHEETS_SORT_PLUGIN'; @@ -27,10 +29,15 @@ export class UniverSheetsSortPlugin extends Plugin { static override pluginName = NAME; constructor( - _config: unknown, - @Inject(Injector) protected readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/sheets-thread-comment-base/src/controllers/config.schema.ts b/packages/sheets-thread-comment-base/src/controllers/config.schema.ts new file mode 100644 index 0000000000..f224283b80 --- /dev/null +++ b/packages/sheets-thread-comment-base/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'sheets-thread-comment-base.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsThreadCommentBaseConfig { +} + +export const defaultPluginConfig: IUniverSheetsThreadCommentBaseConfig = {}; diff --git a/packages/sheets-thread-comment/src/controllers/config.schema.ts b/packages/sheets-thread-comment/src/controllers/config.schema.ts new file mode 100644 index 0000000000..f1d5b86d30 --- /dev/null +++ b/packages/sheets-thread-comment/src/controllers/config.schema.ts @@ -0,0 +1,29 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; +import type { DependencyOverride } from '@univerjs/core'; + +export const PLUGIN_CONFIG_KEY = 'sheets-thread-comment.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsThreadCommentConfig { + menu?: MenuConfig; + overrides?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverSheetsThreadCommentConfig = {}; diff --git a/packages/sheets-thread-comment/src/controllers/menu.schema.ts b/packages/sheets-thread-comment/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..ad72195cd3 --- /dev/null +++ b/packages/sheets-thread-comment/src/controllers/menu.schema.ts @@ -0,0 +1,38 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; +import { ToggleSheetCommentPanelOperation } from '@univerjs/thread-comment-ui'; +import { ShowAddSheetCommentModalOperation } from '../commands/operations/comment.operation'; +import { threadCommentMenuFactory, threadPanelMenuFactory } from './menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.OTHERS]: { + [ToggleSheetCommentPanelOperation.id]: { + order: 1, + menuItemFactory: threadPanelMenuFactory, + }, + }, + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.OTHERS]: { + [ShowAddSheetCommentModalOperation.id]: { + order: 0, + menuItemFactory: threadCommentMenuFactory, + }, + }, + }, +}; diff --git a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment.controller.ts b/packages/sheets-thread-comment/src/controllers/sheets-thread-comment.controller.ts index cf7d4fe481..6a2995812e 100644 --- a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment.controller.ts +++ b/packages/sheets-thread-comment/src/controllers/sheets-thread-comment.controller.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import type { DependencyOverride, Nullable, Workbook } from '@univerjs/core'; +import type { Nullable, Workbook } from '@univerjs/core'; import { Disposable, ICommandService, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, RANGE_TYPE, UniverInstanceType } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService, IShortcutService } from '@univerjs/ui'; +import { ComponentManager, IMenu2Service, IShortcutService } from '@univerjs/ui'; import { CommentSingle } from '@univerjs/icons'; import { SetActiveCommentOperation, THREAD_COMMENT_PANEL, ThreadCommentPanelService } from '@univerjs/thread-comment-ui'; import type { ISelectionWithStyle } from '@univerjs/sheets'; @@ -32,16 +31,8 @@ import { SheetsThreadCommentCell } from '../views/sheets-thread-comment-cell'; import { COMMENT_SINGLE_ICON, SHEETS_THREAD_COMMENT_MODAL } from '../types/const'; import { SheetsThreadCommentPanel } from '../views/sheets-thread-comment-panel'; import { SheetsThreadCommentPopupService } from '../services/sheets-thread-comment-popup.service'; -import { AddCommentShortcut, threadCommentMenuFactory, threadPanelMenuFactory } from './menu'; - -export interface IUniverSheetsThreadCommentConfig { - menu?: MenuConfig; - overrides?: DependencyOverride; -} - -export const DefaultSheetsThreadCommentConfig: IUniverSheetsThreadCommentConfig = { - -}; +import { AddCommentShortcut } from './menu'; +import { menuSchema } from './menu.schema'; interface ISelectionShapeInfo { shapeId: string; @@ -56,8 +47,7 @@ export class SheetsThreadCommentController extends Disposable { private _selectionShapeInfo: Nullable = null; constructor( - private readonly _config: Partial, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, @ICommandService private readonly _commandService: ICommandService, @@ -148,14 +138,7 @@ export class SheetsThreadCommentController extends Disposable { } private _initMenu() { - const { menu = {} } = this._config; - - [ - threadCommentMenuFactory, - threadPanelMenuFactory, - ].forEach((menuFactory) => { - this._menuService.addMenuItem(menuFactory(this._injector), menu); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initComponent() { diff --git a/packages/sheets-thread-comment/src/plugin.ts b/packages/sheets-thread-comment/src/plugin.ts index 21f7c0718c..66408c14bb 100644 --- a/packages/sheets-thread-comment/src/plugin.ts +++ b/packages/sheets-thread-comment/src/plugin.ts @@ -15,11 +15,10 @@ */ import type { Dependency } from '@univerjs/core'; -import { DependentOn, ICommandService, Inject, Injector, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; import { UniverSheetsThreadCommentBasePlugin } from '@univerjs/sheets-thread-comment-base'; -import type { IUniverSheetsThreadCommentConfig } from './controllers/sheets-thread-comment.controller'; -import { DefaultSheetsThreadCommentConfig, SheetsThreadCommentController } from './controllers/sheets-thread-comment.controller'; +import { SheetsThreadCommentController } from './controllers/sheets-thread-comment.controller'; import { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service'; import { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation'; import { SheetsThreadCommentRenderController } from './controllers/render-controllers/render.controller'; @@ -27,32 +26,33 @@ import { SHEETS_THREAD_COMMENT } from './types/const'; import { SheetsThreadCommentCopyPasteController } from './controllers/sheets-thread-comment-copy-paste.controller'; import { SheetsThreadCommentHoverController } from './controllers/sheets-thread-comment-hover.controller'; import { ThreadCommentRemoveSheetsController } from './controllers/sheets-thread-comment-remove.controller'; +import type { IUniverSheetsThreadCommentConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverThreadCommentUIPlugin, UniverSheetsThreadCommentBasePlugin) export class UniverSheetsThreadCommentPlugin extends Plugin { static override pluginName = SHEETS_THREAD_COMMENT; static override type = UniverInstanceType.UNIVER_SHEET; - private _pluginConfig: IUniverSheetsThreadCommentConfig; - constructor( - config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected override _injector: Injector, - @Inject(ICommandService) protected _commandService: ICommandService + @Inject(ICommandService) protected _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._pluginConfig = Tools.deepMerge({}, DefaultSheetsThreadCommentConfig, config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { ([ - [ - SheetsThreadCommentController, - { - useFactory: () => this._injector.createInstance(SheetsThreadCommentController, this._pluginConfig), - }, - ], + [SheetsThreadCommentController], [SheetsThreadCommentRenderController], [SheetsThreadCommentCopyPasteController], [SheetsThreadCommentHoverController], diff --git a/packages/sheets-ui/src/controllers/config.schema.ts b/packages/sheets-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..5acb5c94aa --- /dev/null +++ b/packages/sheets-ui/src/controllers/config.schema.ts @@ -0,0 +1,30 @@ +/** + * 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 { DependencyOverride } from '@univerjs/core'; +import type { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsUIConfig { + menu?: MenuConfig; + disableAutoFocus?: true; + override?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverSheetsUIConfig = {}; diff --git a/packages/sheets-ui/src/controllers/menu.schema.ts b/packages/sheets-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..eb23d0982d --- /dev/null +++ b/packages/sheets-ui/src/controllers/menu.schema.ts @@ -0,0 +1,701 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; +import { + AddWorksheetMergeAllCommand, + AddWorksheetMergeCommand, + AddWorksheetMergeHorizontalCommand, + AddWorksheetMergeVerticalCommand, + ClearSelectionAllCommand, + ClearSelectionContentCommand, + ClearSelectionFormatCommand, CopySheetCommand, + InsertColAfterCommand, + InsertColBeforeCommand, + InsertRowAfterCommand, + InsertRowBeforeCommand, + RemoveWorksheetMergeCommand, + ResetBackgroundColorCommand, + ResetTextColorCommand, + SetBackgroundColorCommand, + SetBorderBasicCommand, + SetColWidthCommand, + SetHorizontalTextAlignCommand, + SetRowHeightCommand, + SetSelectedColsVisibleCommand, + SetSelectedRowsVisibleCommand, SetTabColorCommand, + SetTextRotationCommand, + SetTextWrapCommand, + SetVerticalTextAlignCommand, SetWorksheetHideCommand, + SetWorksheetRowIsAutoHeightCommand, SetWorksheetShowCommand, +} from '@univerjs/sheets'; +import { SetOnceFormatPainterCommand } from '../commands/commands/set-format-painter.command'; +import { + SetRangeBoldCommand, + SetRangeFontFamilyCommand, + SetRangeFontSizeCommand, + SetRangeItalicCommand, + SetRangeStrickThroughCommand, + SetRangeTextColorCommand, + SetRangeUnderlineCommand, +} from '../commands/commands/inline-format.command'; +import { + SheetCopyCommand, + // SheetCutCommand, + SheetPasteBesidesBorderCommand, + SheetPasteColWidthCommand, + SheetPasteCommand, + SheetPasteFormatCommand, + SheetPasteValueCommand, +} from '../commands/commands/clipboard.command'; +import { InsertRangeMoveRightConfirmCommand } from '../commands/commands/insert-range-move-right-confirm.command'; +import { InsertRangeMoveDownConfirmCommand } from '../commands/commands/insert-range-move-down-confirm.command'; +import { RemoveColConfirmCommand, RemoveRowConfirmCommand } from '../commands/commands/remove-row-col-confirm.command'; +import { DeleteRangeMoveLeftConfirmCommand } from '../commands/commands/delete-range-move-left-confirm.command'; +import { DeleteRangeMoveUpConfirmCommand } from '../commands/commands/delete-range-move-up-confirm.command'; +import { CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand } from '../commands/commands/set-frozen.command'; +import { + AddRangeProtectionFromContextMenuCommand, + AddRangeProtectionFromSheetBarCommand, + AddRangeProtectionFromToolbarCommand, + DeleteRangeProtectionFromContextMenuCommand, + SetRangeProtectionFromContextMenuCommand, + ViewSheetPermissionFromContextMenuCommand, + ViewSheetPermissionFromSheetBarCommand, +} from '../commands/commands/range-protection.command'; +import { HideColConfirmCommand, HideRowConfirmCommand } from '../commands/commands/hide-row-col-confirm.command'; +import { RemoveSheetConfirmCommand } from '../commands/commands/remove-sheet-confirm.command'; +import { RenameSheetOperation } from '../commands/operations/rename-sheet.operation'; +import { ShowMenuListCommand } from '../commands/commands/unhide.command'; +import { + ChangeSheetProtectionFromSheetBarCommand, + DeleteWorksheetProtectionFormSheetBarCommand, +} from '../commands/commands/worksheet-protection.command'; +import { + BackgroundColorSelectorMenuItemFactory, + BoldMenuItemFactory, + CancelFrozenMenuItemFactory, + CopyMenuItemFactory, + // CutMenuItemFactory, + FitContentMenuItemFactory, + FontFamilySelectorMenuItemFactory, + FontSizeSelectorMenuItemFactory, + FormatPainterMenuItemFactory, + FrozenColMenuItemFactory, + FrozenMenuItemFactory, + FrozenRowMenuItemFactory, + HideColMenuItemFactory, + HideRowMenuItemFactory, + HorizontalAlignMenuItemFactory, + ItalicMenuItemFactory, + PASTE_SPECIAL_MENU_ID, + PasteBesidesBorderMenuItemFactory, + PasteColWidthMenuItemFactory, + // PasteColWidthMenuItemFactory, + PasteFormatMenuItemFactory, + PasteMenuItemFactory, + PasteSpacialMenuItemFactory, + PasteValueMenuItemFactory, + ResetBackgroundColorMenuItemFactory, + ResetTextColorMenuItemFactory, + SetColWidthMenuItemFactory, + SetRowHeightMenuItemFactory, + SHEET_FROZEN_HEADER_MENU_ID, + SHEET_FROZEN_MENU_ID, + SheetFrozenHeaderMenuItemFactory, + SheetFrozenMenuItemFactory, + ShowColMenuItemFactory, + ShowRowMenuItemFactory, + StrikeThroughMenuItemFactory, + TextColorSelectorMenuItemFactory, + TextRotateMenuItemFactory, + UnderlineMenuItemFactory, + VerticalAlignMenuItemFactory, + WrapTextMenuItemFactory, +} from './menu/menu'; +import { CellMergeAllMenuItemFactory, CellMergeCancelMenuItemFactory, CellMergeHorizontalMenuItemFactory, CellMergeMenuItemFactory, CellMergeVerticalMenuItemFactory } from './menu/merge.menu'; +import { CellBorderSelectorMenuItemFactory } from './menu/border.menu'; +import { CLEAR_SELECTION_MENU_ID, ClearSelectionAllMenuItemFactory, ClearSelectionContentMenuItemFactory, ClearSelectionFormatMenuItemFactory, ClearSelectionMenuItemFactory } from './menu/clear.menu'; +import { + CELL_INSERT_MENU_ID, + CellInsertMenuItemFactory, + COL_INSERT_MENU_ID, + ColInsertMenuItemFactory, + InsertColAfterMenuItemFactory, + InsertColBeforeMenuItemFactory, + InsertRangeMoveDownMenuItemFactory, + InsertRangeMoveRightMenuItemFactory, + InsertRowAfterMenuItemFactory, + InsertRowBeforeMenuItemFactory, + ROW_INSERT_MENU_ID, RowInsertMenuItemFactory, +} from './menu/insert.menu'; +import { DELETE_RANGE_MENU_ID, DeleteRangeMenuItemFactory, DeleteRangeMoveLeftMenuItemFactory, DeleteRangeMoveUpMenuItemFactory, RemoveColMenuItemFactory, RemoveRowMenuItemFactory } from './menu/delete.menu'; +import { + SHEET_PERMISSION_CONTEXT_MENU_ID, + sheetPermissionAddProtectContextMenuFactory, + sheetPermissionChangeSheetPermissionSheetBarMenuFactory, + sheetPermissionContextMenuFactory, + sheetPermissionEditProtectContextMenuFactory, + sheetPermissionProtectSheetInSheetBarMenuFactory, + sheetPermissionRemoveProtectContextMenuFactory, + sheetPermissionRemoveProtectionSheetBarMenuFactory, + sheetPermissionToolbarMenuFactory, + sheetPermissionViewAllProtectRuleContextMenuFactory, + sheetPermissionViewAllProtectRuleSheetBarMenuFactory, +} from './menu/permission.menu'; +import { + ChangeColorSheetMenuItemFactory, + CopySheetMenuItemFactory, + DeleteSheetMenuItemFactory, + HideSheetMenuItemFactory, + RenameSheetMenuItemFactory, + ShowMenuItemFactory, + UnHideSheetMenuItemFactory, +} from './menu/sheet.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMAT]: { + [SetOnceFormatPainterCommand.id]: { + order: 0, + menuItemFactory: FormatPainterMenuItemFactory, + }, + [SetRangeBoldCommand.id]: { + order: 1, + menuItemFactory: BoldMenuItemFactory, + }, + [SetRangeItalicCommand.id]: { + order: 2, + menuItemFactory: ItalicMenuItemFactory, + }, + [SetRangeUnderlineCommand.id]: { + order: 3, + menuItemFactory: UnderlineMenuItemFactory, + }, + [SetRangeStrickThroughCommand.id]: { + order: 4, + menuItemFactory: StrikeThroughMenuItemFactory, + }, + [SetRangeFontFamilyCommand.id]: { + order: 5, + menuItemFactory: FontFamilySelectorMenuItemFactory, + }, + [SetRangeFontSizeCommand.id]: { + order: 6, + menuItemFactory: FontSizeSelectorMenuItemFactory, + }, + [SetRangeTextColorCommand.id]: { + order: 7, + menuItemFactory: TextColorSelectorMenuItemFactory, + [ResetTextColorCommand.id]: { + order: 0, + menuItemFactory: ResetTextColorMenuItemFactory, + }, + }, + [SetBackgroundColorCommand.id]: { + order: 9, + menuItemFactory: BackgroundColorSelectorMenuItemFactory, + [ResetBackgroundColorCommand.id]: { + order: 0, + menuItemFactory: ResetBackgroundColorMenuItemFactory, + }, + }, + [SetBorderBasicCommand.id]: { + order: 10, + menuItemFactory: CellBorderSelectorMenuItemFactory, + }, + }, + [RibbonStartGroup.LAYOUT]: { + [AddWorksheetMergeCommand.id]: { + order: 0, + menuItemFactory: CellMergeMenuItemFactory, + [AddWorksheetMergeAllCommand.id]: { + order: 0, + menuItemFactory: CellMergeAllMenuItemFactory, + }, + [AddWorksheetMergeVerticalCommand.id]: { + order: 1, + menuItemFactory: CellMergeVerticalMenuItemFactory, + }, + [AddWorksheetMergeHorizontalCommand.id]: { + order: 2, + menuItemFactory: CellMergeHorizontalMenuItemFactory, + }, + [RemoveWorksheetMergeCommand.id]: { + order: 3, + menuItemFactory: CellMergeCancelMenuItemFactory, + }, + }, + [SetHorizontalTextAlignCommand.id]: { + order: 1, + menuItemFactory: HorizontalAlignMenuItemFactory, + }, + [SetVerticalTextAlignCommand.id]: { + order: 1, + menuItemFactory: VerticalAlignMenuItemFactory, + }, + [SetTextWrapCommand.id]: { + order: 2, + menuItemFactory: WrapTextMenuItemFactory, + }, + [SetTextRotationCommand.id]: { + order: 3, + menuItemFactory: TextRotateMenuItemFactory, + }, + }, + [RibbonStartGroup.OTHERS]: { + [AddRangeProtectionFromToolbarCommand.id]: { + order: 0, + menuItemFactory: sheetPermissionToolbarMenuFactory, + }, + }, + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.FORMAT]: { + [SheetCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuItemFactory, + }, + // [SheetCutCommand.name]: { + // order: 1, + // menuItemFactory: CutMenuItemFactory, + // }, + [SheetPasteCommand.name]: { + order: 2, + menuItemFactory: PasteMenuItemFactory, + }, + [PASTE_SPECIAL_MENU_ID]: { + order: 3, + menuItemFactory: PasteSpacialMenuItemFactory, + [SheetPasteValueCommand.id]: { + order: 0, + menuItemFactory: PasteValueMenuItemFactory, + }, + [SheetPasteFormatCommand.id]: { + order: 1, + menuItemFactory: PasteFormatMenuItemFactory, + }, + [SheetPasteColWidthCommand.id]: { + order: 2, + menuItemFactory: PasteColWidthMenuItemFactory, + }, + [SheetPasteBesidesBorderCommand.id]: { + order: 3, + menuItemFactory: PasteBesidesBorderMenuItemFactory, + }, + }, + [CLEAR_SELECTION_MENU_ID]: { + order: 4, + menuItemFactory: ClearSelectionMenuItemFactory, + [ClearSelectionContentCommand.id]: { + order: 0, + menuItemFactory: ClearSelectionContentMenuItemFactory, + }, + [ClearSelectionFormatCommand.id]: { + order: 1, + menuItemFactory: ClearSelectionFormatMenuItemFactory, + }, + [ClearSelectionAllCommand.id]: { + order: 2, + menuItemFactory: ClearSelectionAllMenuItemFactory, + }, + }, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + [CELL_INSERT_MENU_ID]: { + order: 0, + menuItemFactory: CellInsertMenuItemFactory, + [InsertRowBeforeCommand.id]: { + order: 0, + menuItemFactory: InsertRowBeforeMenuItemFactory, + }, + [InsertColBeforeCommand.id]: { + order: 1, + menuItemFactory: InsertColBeforeMenuItemFactory, + }, + [InsertRangeMoveRightConfirmCommand.id]: { + order: 2, + menuItemFactory: InsertRangeMoveRightMenuItemFactory, + }, + [InsertRangeMoveDownConfirmCommand.id]: { + order: 3, + menuItemFactory: InsertRangeMoveDownMenuItemFactory, + }, + }, + [DELETE_RANGE_MENU_ID]: { + order: 0, + menuItemFactory: DeleteRangeMenuItemFactory, + [RemoveColConfirmCommand.id]: { + order: 0, + menuItemFactory: RemoveColMenuItemFactory, + }, + [RemoveRowConfirmCommand.id]: { + order: 1, + menuItemFactory: RemoveRowMenuItemFactory, + }, + [DeleteRangeMoveLeftConfirmCommand.id]: { + order: 2, + menuItemFactory: DeleteRangeMoveLeftMenuItemFactory, + }, + [DeleteRangeMoveUpConfirmCommand.id]: { + order: 3, + menuItemFactory: DeleteRangeMoveUpMenuItemFactory, + }, + }, + [SHEET_FROZEN_MENU_ID]: { + order: 2, + menuItemFactory: SheetFrozenMenuItemFactory, + [SetSelectionFrozenCommand.id]: { + order: 0, + menuItemFactory: FrozenMenuItemFactory, + }, + [SetRowFrozenCommand.id]: { + order: 1, + menuItemFactory: FrozenRowMenuItemFactory, + }, + [SetColumnFrozenCommand.id]: { + order: 2, + menuItemFactory: FrozenColMenuItemFactory, + }, + [CancelFrozenCommand.id]: { + order: 3, + menuItemFactory: CancelFrozenMenuItemFactory, + }, + }, + [SHEET_PERMISSION_CONTEXT_MENU_ID]: { + order: 3, + menuItemFactory: sheetPermissionContextMenuFactory, + [AddRangeProtectionFromContextMenuCommand.id]: { + order: 0, + menuItemFactory: sheetPermissionAddProtectContextMenuFactory, + }, + [SetRangeProtectionFromContextMenuCommand.id]: { + order: 1, + menuItemFactory: sheetPermissionEditProtectContextMenuFactory, + }, + [DeleteRangeProtectionFromContextMenuCommand.id]: { + order: 2, + menuItemFactory: sheetPermissionRemoveProtectContextMenuFactory, + }, + [ViewSheetPermissionFromContextMenuCommand.id]: { + order: 3, + menuItemFactory: sheetPermissionViewAllProtectRuleContextMenuFactory, + }, + }, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.COL_HEADER]: { + [ContextMenuGroup.FORMAT]: { + [SheetCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuItemFactory, + }, + // [SheetCutCommand.name]: { + // order: 1, + // menuItemFactory: CutMenuItemFactory, + // }, + [SheetPasteCommand.name]: { + order: 2, + menuItemFactory: PasteMenuItemFactory, + }, + [PASTE_SPECIAL_MENU_ID]: { + order: 3, + menuItemFactory: PasteSpacialMenuItemFactory, + [SheetPasteValueCommand.id]: { + order: 0, + menuItemFactory: PasteValueMenuItemFactory, + }, + [SheetPasteFormatCommand.id]: { + order: 1, + menuItemFactory: PasteFormatMenuItemFactory, + }, + [SheetPasteColWidthCommand.id]: { + order: 2, + menuItemFactory: PasteColWidthMenuItemFactory, + }, + [SheetPasteBesidesBorderCommand.id]: { + order: 3, + menuItemFactory: PasteBesidesBorderMenuItemFactory, + }, + }, + [CLEAR_SELECTION_MENU_ID]: { + order: 4, + menuItemFactory: ClearSelectionMenuItemFactory, + [ClearSelectionContentCommand.id]: { + order: 0, + menuItemFactory: ClearSelectionContentMenuItemFactory, + }, + [ClearSelectionFormatCommand.id]: { + order: 1, + menuItemFactory: ClearSelectionFormatMenuItemFactory, + }, + [ClearSelectionAllCommand.id]: { + order: 2, + menuItemFactory: ClearSelectionAllMenuItemFactory, + }, + }, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + [COL_INSERT_MENU_ID]: { + order: 0, + menuItemFactory: ColInsertMenuItemFactory, + [InsertColBeforeCommand.id]: { + order: 0, + menuItemFactory: InsertColBeforeMenuItemFactory, + }, + [InsertColAfterCommand.id]: { + order: 1, + menuItemFactory: InsertColAfterMenuItemFactory, + }, + }, + [HideColConfirmCommand.id]: { + order: 1, + menuItemFactory: HideColMenuItemFactory, + }, + [SetSelectedColsVisibleCommand.id]: { + order: 2, + menuItemFactory: ShowColMenuItemFactory, + }, + [RemoveColConfirmCommand.id]: { + order: 2, + menuItemFactory: RemoveColMenuItemFactory, + }, + [SetColWidthCommand.id]: { + order: 3, + menuItemFactory: SetColWidthMenuItemFactory, + }, + [SHEET_FROZEN_HEADER_MENU_ID]: { + order: 4, + menuItemFactory: SheetFrozenHeaderMenuItemFactory, + [SetSelectionFrozenCommand.id]: { + order: 0, + menuItemFactory: FrozenMenuItemFactory, + }, + [CancelFrozenCommand.id]: { + order: 3, + menuItemFactory: CancelFrozenMenuItemFactory, + }, + }, + [SHEET_PERMISSION_CONTEXT_MENU_ID]: { + order: 5, + menuItemFactory: sheetPermissionContextMenuFactory, + [AddRangeProtectionFromContextMenuCommand.id]: { + order: 0, + menuItemFactory: sheetPermissionAddProtectContextMenuFactory, + }, + [SetRangeProtectionFromContextMenuCommand.id]: { + order: 1, + menuItemFactory: sheetPermissionEditProtectContextMenuFactory, + }, + [DeleteRangeProtectionFromContextMenuCommand.id]: { + order: 2, + menuItemFactory: sheetPermissionRemoveProtectContextMenuFactory, + }, + [ViewSheetPermissionFromContextMenuCommand.id]: { + order: 3, + menuItemFactory: sheetPermissionViewAllProtectRuleContextMenuFactory, + }, + }, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.ROW_HEADER]: { + [ContextMenuGroup.FORMAT]: { + [SheetCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuItemFactory, + }, + // [SheetCutCommand.name]: { + // order: 1, + // menuItemFactory: CutMenuItemFactory, + // }, + [SheetPasteCommand.name]: { + order: 2, + menuItemFactory: PasteMenuItemFactory, + }, + [PASTE_SPECIAL_MENU_ID]: { + order: 3, + menuItemFactory: PasteSpacialMenuItemFactory, + [SheetPasteValueCommand.id]: { + order: 0, + menuItemFactory: PasteValueMenuItemFactory, + }, + [SheetPasteFormatCommand.id]: { + order: 1, + menuItemFactory: PasteFormatMenuItemFactory, + }, + [SheetPasteColWidthCommand.id]: { + order: 2, + menuItemFactory: PasteColWidthMenuItemFactory, + }, + [SheetPasteBesidesBorderCommand.id]: { + order: 3, + menuItemFactory: PasteBesidesBorderMenuItemFactory, + }, + }, + [CLEAR_SELECTION_MENU_ID]: { + order: 4, + menuItemFactory: ClearSelectionMenuItemFactory, + [ClearSelectionContentCommand.id]: { + order: 0, + menuItemFactory: ClearSelectionContentMenuItemFactory, + }, + [ClearSelectionFormatCommand.id]: { + order: 1, + menuItemFactory: ClearSelectionFormatMenuItemFactory, + }, + [ClearSelectionAllCommand.id]: { + order: 2, + menuItemFactory: ClearSelectionAllMenuItemFactory, + }, + }, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + [ROW_INSERT_MENU_ID]: { + order: 0, + menuItemFactory: RowInsertMenuItemFactory, + [InsertRowBeforeCommand.id]: { + order: 0, + menuItemFactory: InsertRowBeforeMenuItemFactory, + }, + [InsertRowAfterCommand.id]: { + order: 1, + menuItemFactory: InsertRowAfterMenuItemFactory, + }, + }, + [RemoveRowConfirmCommand.id]: { + order: 1, + menuItemFactory: RemoveRowMenuItemFactory, + }, + [HideRowConfirmCommand.id]: { + order: 2, + menuItemFactory: HideRowMenuItemFactory, + }, + [SetSelectedRowsVisibleCommand.id]: { + order: 2, + menuItemFactory: ShowRowMenuItemFactory, + }, + [SetRowHeightCommand.id]: { + order: 3, + menuItemFactory: SetRowHeightMenuItemFactory, + }, + [SetWorksheetRowIsAutoHeightCommand.id]: { + order: 4, + menuItemFactory: FitContentMenuItemFactory, + }, + [SHEET_FROZEN_HEADER_MENU_ID]: { + order: 5, + menuItemFactory: SheetFrozenHeaderMenuItemFactory, + [SetSelectionFrozenCommand.id]: { + order: 0, + menuItemFactory: FrozenMenuItemFactory, + }, + [CancelFrozenCommand.id]: { + order: 3, + menuItemFactory: CancelFrozenMenuItemFactory, + }, + }, + [SHEET_PERMISSION_CONTEXT_MENU_ID]: { + order: 6, + menuItemFactory: sheetPermissionContextMenuFactory, + [AddRangeProtectionFromContextMenuCommand.id]: { + order: 0, + menuItemFactory: sheetPermissionAddProtectContextMenuFactory, + }, + [SetRangeProtectionFromContextMenuCommand.id]: { + order: 1, + menuItemFactory: sheetPermissionEditProtectContextMenuFactory, + }, + [DeleteRangeProtectionFromContextMenuCommand.id]: { + order: 2, + menuItemFactory: sheetPermissionRemoveProtectContextMenuFactory, + }, + [ViewSheetPermissionFromContextMenuCommand.id]: { + order: 3, + menuItemFactory: sheetPermissionViewAllProtectRuleContextMenuFactory, + }, + }, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.FOOTER_TABS]: { + [ContextMenuGroup.OTHERS]: { + order: 0, + [RemoveSheetConfirmCommand.id]: { + order: 0, + menuItemFactory: DeleteSheetMenuItemFactory, + }, + [CopySheetCommand.id]: { + order: 1, + menuItemFactory: CopySheetMenuItemFactory, + }, + [RenameSheetOperation.id]: { + order: 2, + menuItemFactory: RenameSheetMenuItemFactory, + }, + [SetTabColorCommand.id]: { + order: 3, + menuItemFactory: ChangeColorSheetMenuItemFactory, + }, + [SetWorksheetHideCommand.id]: { + order: 4, + menuItemFactory: HideSheetMenuItemFactory, + }, + [SetWorksheetShowCommand.id]: { + order: 5, + menuItemFactory: UnHideSheetMenuItemFactory, + }, + [ShowMenuListCommand.id]: { + order: 6, + menuItemFactory: ShowMenuItemFactory, + }, + [AddRangeProtectionFromSheetBarCommand.id]: { + order: 7, + menuItemFactory: sheetPermissionProtectSheetInSheetBarMenuFactory, + }, + [DeleteWorksheetProtectionFormSheetBarCommand.id]: { + order: 8, + menuItemFactory: sheetPermissionRemoveProtectionSheetBarMenuFactory, + }, + [ChangeSheetProtectionFromSheetBarCommand.id]: { + order: 9, + menuItemFactory: sheetPermissionChangeSheetPermissionSheetBarMenuFactory, + }, + [ViewSheetPermissionFromSheetBarCommand.id]: { + order: 10, + menuItemFactory: sheetPermissionViewAllProtectRuleSheetBarMenuFactory, + }, + }, + }, +}; diff --git a/packages/sheets-ui/src/controllers/menu/__tests__/create-menu-test-bed.ts b/packages/sheets-ui/src/controllers/menu/__tests__/create-menu-test-bed.ts index f6c093205c..79f620fb6a 100644 --- a/packages/sheets-ui/src/controllers/menu/__tests__/create-menu-test-bed.ts +++ b/packages/sheets-ui/src/controllers/menu/__tests__/create-menu-test-bed.ts @@ -23,7 +23,7 @@ import { RangeProtectionRefRangeService, RangeProtectionRenderModel, RangeProtec WorksheetProtectionPointModel, WorksheetProtectionRuleModel, } from '@univerjs/sheets'; -import { IMenuService, IPlatformService, IShortcutService, MenuService, PlatformService, ShortcutService } from '@univerjs/ui'; +import { IMenu2Service, IPlatformService, IShortcutService, Menu2Service, PlatformService, ShortcutService } from '@univerjs/ui'; import { IRenderManagerService, RenderManagerService } from '@univerjs/engine-render'; const TEST_WORKBOOK_DATA_DEMO: IWorkbookData = { @@ -66,7 +66,7 @@ export function createMenuTestBed() { injector.add([IPlatformService, { useClass: PlatformService }]); injector.add([SheetsSelectionsService]); injector.add([IShortcutService, { useClass: ShortcutService }]); - injector.add([IMenuService, { useClass: MenuService }]); + injector.add([IMenu2Service, { useClass: Menu2Service }]); injector.add([WorkbookPermissionService]); injector.add([WorksheetPermissionService]); injector.add([WorksheetProtectionPointModel]); diff --git a/packages/sheets-ui/src/controllers/menu/clear.menu.ts b/packages/sheets-ui/src/controllers/menu/clear.menu.ts index b90f7c83bb..81533f7a70 100644 --- a/packages/sheets-ui/src/controllers/menu/clear.menu.ts +++ b/packages/sheets-ui/src/controllers/menu/clear.menu.ts @@ -23,7 +23,7 @@ import { UniverInstanceType } from '@univerjs/core'; import { SheetMenuPosition } from './menu'; import { getCurrentRangeDisable$, getObservableWithExclusiveRange$ } from './menu-util'; -const CLEAR_SELECTION_MENU_ID = 'sheet.menu.clear-selection'; +export const CLEAR_SELECTION_MENU_ID = 'sheet.menu.clear-selection'; export function ClearSelectionMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: CLEAR_SELECTION_MENU_ID, diff --git a/packages/sheets-ui/src/controllers/menu/delete.menu.ts b/packages/sheets-ui/src/controllers/menu/delete.menu.ts index d0a71f7470..2f22d5a365 100644 --- a/packages/sheets-ui/src/controllers/menu/delete.menu.ts +++ b/packages/sheets-ui/src/controllers/menu/delete.menu.ts @@ -28,7 +28,7 @@ import { import { SheetMenuPosition } from './menu'; import { getBaseRangeMenuHidden$, getCellMenuHidden$, getCurrentRangeDisable$, getDeleteMenuHidden$, getObservableWithExclusiveRange$ } from './menu-util'; -const DELETE_RANGE_MENU_ID = 'sheet.menu.delete'; +export const DELETE_RANGE_MENU_ID = 'sheet.menu.delete'; export function DeleteRangeMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: DELETE_RANGE_MENU_ID, diff --git a/packages/sheets-ui/src/controllers/menu/insert.menu.ts b/packages/sheets-ui/src/controllers/menu/insert.menu.ts index 827cb68aad..3cf3fdbff2 100644 --- a/packages/sheets-ui/src/controllers/menu/insert.menu.ts +++ b/packages/sheets-ui/src/controllers/menu/insert.menu.ts @@ -34,7 +34,7 @@ import { InsertRangeMoveRightConfirmCommand } from '../../commands/commands/inse import { SheetMenuPosition } from './menu'; import { getBaseRangeMenuHidden$, getCellMenuHidden$, getCurrentRangeDisable$, getInsertAfterMenuHidden$, getInsertBeforeMenuHidden$, getObservableWithExclusiveRange$ } from './menu-util'; -const COL_INSERT_MENU_ID = 'sheet.menu.col-insert'; +export const COL_INSERT_MENU_ID = 'sheet.menu.col-insert'; export function ColInsertMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: COL_INSERT_MENU_ID, @@ -48,7 +48,7 @@ export function ColInsertMenuItemFactory(accessor: IAccessor): IMenuSelectorItem }; } -const ROW_INSERT_MENU_ID = 'sheet.menu.row-insert'; +export const ROW_INSERT_MENU_ID = 'sheet.menu.row-insert'; export function RowInsertMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: ROW_INSERT_MENU_ID, @@ -62,7 +62,7 @@ export function RowInsertMenuItemFactory(accessor: IAccessor): IMenuSelectorItem }; } -const CELL_INSERT_MENU_ID = 'sheet.menu.cell-insert'; +export const CELL_INSERT_MENU_ID = 'sheet.menu.cell-insert'; export function CellInsertMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { return { id: CELL_INSERT_MENU_ID, diff --git a/packages/sheets-ui/src/controllers/menu/permission.menu.ts b/packages/sheets-ui/src/controllers/menu/permission.menu.ts index 30ebf9222f..17455a7fae 100644 --- a/packages/sheets-ui/src/controllers/menu/permission.menu.ts +++ b/packages/sheets-ui/src/controllers/menu/permission.menu.ts @@ -25,8 +25,7 @@ import { ChangeSheetProtectionFromSheetBarCommand, DeleteWorksheetProtectionForm import { getAddPermissionDisableBase$, getAddPermissionFromSheetBarDisable$, getAddPermissionHidden$, getEditPermissionHidden$, getPermissionDisableBase$, getRemovePermissionDisable$, getRemovePermissionFromSheetBarDisable$, getSetPermissionFromSheetBarDisable$, getViewPermissionDisable$ } from './permission-menu-util'; import { SheetMenuPosition } from './menu'; -export const tmpIcon = 'data-validation-single'; -const SHEET_PERMISSION_CONTEXT_MENU_ID = 'sheet.contextMenu.permission'; +export const SHEET_PERMISSION_CONTEXT_MENU_ID = 'sheet.contextMenu.permission'; export function sheetPermissionToolbarMenuFactory(accessor: IAccessor): IMenuItem { return { diff --git a/packages/sheets-ui/src/controllers/mobile/menu.schema.ts b/packages/sheets-ui/src/controllers/mobile/menu.schema.ts new file mode 100644 index 0000000000..6920e191e9 --- /dev/null +++ b/packages/sheets-ui/src/controllers/mobile/menu.schema.ts @@ -0,0 +1,73 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition } from '@univerjs/ui'; +import { + SheetCopyCommand, +} from '../../commands/commands/clipboard.command'; +import { CopyMenuItemFactory } from '../menu/menu'; + +export const menuSchema: IMenu2Item = { + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.FORMAT]: { + [SheetCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuItemFactory, + }, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.COL_HEADER]: { + [ContextMenuGroup.FORMAT]: { + [SheetCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuItemFactory, + }, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.ROW_HEADER]: { + [ContextMenuGroup.FORMAT]: { + [SheetCopyCommand.name]: { + order: 0, + menuItemFactory: CopyMenuItemFactory, + }, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, +}; diff --git a/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts b/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts index b2e1fb3d5e..0957102770 100644 --- a/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts +++ b/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts @@ -23,8 +23,7 @@ import { SetStrikeThroughCommand, SetUnderlineCommand, } from '@univerjs/sheets'; -import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, ILayoutService, IMenuService, IShortcutService, IUIPartsService } from '@univerjs/ui'; +import { BuiltInUIPart, ComponentManager, ILayoutService, IMenu2Service, IShortcutService, IUIPartsService } from '@univerjs/ui'; import { AddWorksheetMergeAllCommand, @@ -102,10 +101,6 @@ import { SheetPermissionOpenDialogOperation } from '../../commands/operations/sh import { AddRangeProtectionFromContextMenuCommand, AddRangeProtectionFromSheetBarCommand, AddRangeProtectionFromToolbarCommand, DeleteRangeProtectionFromContextMenuCommand, SetProtectionCommand, SetRangeProtectionFromContextMenuCommand, ViewSheetPermissionFromContextMenuCommand, ViewSheetPermissionFromSheetBarCommand } from '../../commands/commands/range-protection.command'; import { AddWorksheetProtectionCommand, ChangeSheetProtectionFromSheetBarCommand, DeleteWorksheetProtectionCommand, DeleteWorksheetProtectionFormSheetBarCommand, SetWorksheetProtectionCommand } from '../../commands/commands/worksheet-protection.command'; -import { - CopyMenuItemFactory, -} from '../menu/menu'; - import { EditorBreakLineShortcut, EditorCursorEnterShortcut, @@ -157,23 +152,17 @@ import { ZoomOutShortcutItem, } from '../shortcuts/view.shortcut'; import { MobileSheetBar } from '../../views/mobile/sheet-bar/MobileSheetBar'; - -export interface IUniverSheetsUIConfig { - menu: MenuConfig; -} - -export const DefaultSheetUiConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, SheetUIMobileController) export class SheetUIMobileController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, @ILayoutService private readonly _layoutService: ILayoutService, @ICommandService private readonly _commandService: ICommandService, @IShortcutService private readonly _shortcutService: IShortcutService, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service protected readonly _menu2Service: IMenu2Service, @IUIPartsService private readonly _uiPartsService: IUIPartsService ) { super(); @@ -283,84 +272,7 @@ export class SheetUIMobileController extends Disposable { } private _initMenus(): void { - const { menu = {} } = this._config; - - ( - [ - // context menu - CopyMenuItemFactory, - // PasteMenuItemFactory, - // PasteSpacialMenuItemFactory, - // PasteValueMenuItemFactory, - // PasteFormatMenuItemFactory, - // PasteColWidthMenuItemFactory, - // PasteBesidesBorderMenuItemFactory, - // ClearSelectionContentMenuItemFactory, - // ClearSelectionFormatMenuItemFactory, - // ClearSelectionAllMenuItemFactory, - // ClearSelectionMenuItemFactory, - // ColInsertMenuItemFactory, - // RowInsertMenuItemFactory, - // CellInsertMenuItemFactory, - // InsertRowBeforeMenuItemFactory, - // InsertRowAfterMenuItemFactory, - // InsertColBeforeMenuItemFactory, - // InsertColAfterMenuItemFactory, - // RemoveRowMenuItemFactory, - // HideRowMenuItemFactory, - // ShowRowMenuItemFactory, - // HideColMenuItemFactory, - // ShowColMenuItemFactory, - // RemoveColMenuItemFactory, - // SetRowHeightMenuItemFactory, - // FitContentMenuItemFactory, - // SetColWidthMenuItemFactory, - // DeleteRangeMenuItemFactory, - // DeleteRangeMoveLeftMenuItemFactory, - // DeleteRangeMoveUpMenuItemFactory, - // InsertRangeMoveRightMenuItemFactory, - // InsertRangeMoveDownMenuItemFactory, - // FrozenMenuItemFactory, - // FrozenRowMenuItemFactory, - // FrozenColMenuItemFactory, - // CancelFrozenMenuItemFactory, - // SheetFrozenMenuItemFactory, - // SheetFrozenHeaderMenuItemFactory, - - // toolbar - // FormatPainterMenuItemFactory, - // BoldMenuItemFactory, - // ItalicMenuItemFactory, - // UnderlineMenuItemFactory, - // StrikeThroughMenuItemFactory, - // FontFamilySelectorMenuItemFactory, - // FontSizeSelectorMenuItemFactory, - // ResetTextColorMenuItemFactory, - // TextColorSelectorMenuItemFactory, - // ResetBackgroundColorMenuItemFactory, - // BackgroundColorSelectorMenuItemFactory, - // CellBorderSelectorMenuItemFactory, - // CellMergeMenuItemFactory, - // CellMergeAllMenuItemFactory, - // CellMergeVerticalMenuItemFactory, - // CellMergeHorizontalMenuItemFactory, - // CellMergeCancelMenuItemFactory, - // HorizontalAlignMenuItemFactory, - // VerticalAlignMenuItemFactory, - // WrapTextMenuItemFactory, - // TextRotateMenuItemFactory, - - // sheetbar - // DeleteSheetMenuItemFactory, - // CopySheetMenuItemFactory, - // RenameSheetMenuItemFactory, - // ChangeColorSheetMenuItemFactory, - // HideSheetMenuItemFactory, - // ShowMenuItemFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initShortcuts(): void { diff --git a/packages/sheets-ui/src/controllers/render-controllers/contextmenu.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/contextmenu.render-controller.ts index 573bc034e9..b66d2a2de7 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/contextmenu.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/contextmenu.render-controller.ts @@ -22,9 +22,8 @@ import { } from '@univerjs/core'; import type { IRenderContext, IRenderModule, Spreadsheet, SpreadsheetColumnHeader, SpreadsheetHeader } from '@univerjs/engine-render'; import { SheetsSelectionsService } from '@univerjs/sheets'; -import { IContextMenuService, MenuPosition } from '@univerjs/ui'; +import { ContextMenuPosition, IContextMenuService } from '@univerjs/ui'; -import { SheetMenuPosition } from '../menu/menu'; import { SHEET_VIEW_KEY } from '../../common/keys'; import { ISheetSelectionRenderService } from '../../services/selection/base-selection-render.service'; import { attachSelectionWithCoord } from '../../services/selection/util'; @@ -80,13 +79,13 @@ export class SheetContextMenuRenderController extends Disposable implements IRen this._contextMenuService.triggerContextMenu(event, position); }; if (!isPointerInRange()) { - triggerMenu(MenuPosition.CONTEXT_MENU); + triggerMenu(ContextMenuPosition.MAIN_AREA); } else if (rangeType === RANGE_TYPE.COLUMN) { - triggerMenu(SheetMenuPosition.COL_HEADER_CONTEXT_MENU); + triggerMenu(ContextMenuPosition.COL_HEADER); } else if (rangeType === RANGE_TYPE.ROW) { - triggerMenu(SheetMenuPosition.ROW_HEADER_CONTEXT_MENU); + triggerMenu(ContextMenuPosition.ROW_HEADER); } else { - triggerMenu(MenuPosition.CONTEXT_MENU); + triggerMenu(ContextMenuPosition.MAIN_AREA); } } }); @@ -97,7 +96,7 @@ export class SheetContextMenuRenderController extends Disposable implements IRen const spreadsheetRowHeader = this._context.components.get(SHEET_VIEW_KEY.ROW) as SpreadsheetHeader; const rowHeaderSub = spreadsheetRowHeader.onPointerDown$.subscribeEvent((event) => { if (event.button === 2) { - this._contextMenuService.triggerContextMenu(event, SheetMenuPosition.ROW_HEADER_CONTEXT_MENU); + this._contextMenuService.triggerContextMenu(event, ContextMenuPosition.ROW_HEADER); } }); this.disposeWithMe(rowHeaderSub); @@ -106,7 +105,7 @@ export class SheetContextMenuRenderController extends Disposable implements IRen const colHeaderPointerDownObserver = spreadsheetColumnHeader.onPointerDown$; const colHeaderObserver = colHeaderPointerDownObserver.subscribeEvent((event) => { if (event.button === 2) { - this._contextMenuService.triggerContextMenu(event, SheetMenuPosition.COL_HEADER_CONTEXT_MENU); + this._contextMenuService.triggerContextMenu(event, ContextMenuPosition.COL_HEADER); } }); this.disposeWithMe(colHeaderObserver); diff --git a/packages/sheets-ui/src/controllers/render-controllers/header-menu.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/header-menu.render-controller.ts index d4f6c93867..7c7be03d7e 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/header-menu.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/header-menu.render-controller.ts @@ -25,13 +25,12 @@ import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, Spreads import { CURSOR_TYPE, Rect } from '@univerjs/engine-render'; import type { ISetSelectionsOperationParams } from '@univerjs/sheets'; import { SetSelectionsOperation, SheetsSelectionsService } from '@univerjs/sheets'; -import { IContextMenuService } from '@univerjs/ui'; +import { ContextMenuPosition, IContextMenuService } from '@univerjs/ui'; import { Subscription } from 'rxjs'; import { SHEET_COMPONENT_HEADER_LAYER_INDEX, SHEET_VIEW_KEY } from '../../common/keys'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { HEADER_MENU_SHAPE_TYPE, HeaderMenuShape } from '../../views/header-menu-shape'; -import { SheetMenuPosition } from '../menu/menu'; import { getCoordByOffset } from '../utils/component-tools'; const HEADER_MENU_CONTROLLER_SHAPE = '__SpreadsheetHeaderMenuSHAPEControllerShape__'; @@ -260,7 +259,7 @@ export class HeaderMenuRenderController extends Disposable implements IRenderMod evt.stopPropagation(); evt.preventDefault(); - this._contextMenuService.triggerContextMenu(evt, SheetMenuPosition.COL_HEADER_CONTEXT_MENU); + this._contextMenuService.triggerContextMenu(evt, ContextMenuPosition.COL_HEADER); }); } diff --git a/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-contextmenu.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-contextmenu.render-controller.ts index 14c2e8b518..9829719dd0 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-contextmenu.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-contextmenu.render-controller.ts @@ -18,7 +18,7 @@ import type { Workbook } from '@univerjs/core'; import { Disposable, Inject, RANGE_TYPE, Tools } from '@univerjs/core'; import { type IPointerEvent, type IRenderContext, type IRenderModule, SHEET_VIEWPORT_KEY } from '@univerjs/engine-render'; import { type ISelectionWithStyle, SheetsSelectionsService } from '@univerjs/sheets'; -import { IContextMenuService, ILayoutService, MenuPosition } from '@univerjs/ui'; +import { ContextMenuPosition, IContextMenuService, ILayoutService } from '@univerjs/ui'; import { ISheetSelectionRenderService } from '../../../services/selection/base-selection-render.service'; import { SheetSkeletonManagerService } from '../../../services/sheet-skeleton-manager.service'; @@ -108,7 +108,7 @@ export class SheetContextMenuMobileRenderController extends Disposable implement clientY, preventDefault: () => {}, stopPropagation: () => {}, - } as unknown as IPointerEvent, MenuPosition.CONTEXT_MENU); + } as unknown as IPointerEvent, ContextMenuPosition.MAIN_AREA); })); } } diff --git a/packages/sheets-ui/src/controllers/sheet-ui.controller.ts b/packages/sheets-ui/src/controllers/sheet-ui.controller.ts index 083ae67488..47b94d6a99 100644 --- a/packages/sheets-ui/src/controllers/sheet-ui.controller.ts +++ b/packages/sheets-ui/src/controllers/sheet-ui.controller.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import type { DependencyOverride } from '@univerjs/core'; import { connectInjector, Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; import { @@ -25,8 +24,7 @@ import { SetStrikeThroughCommand, SetUnderlineCommand, } from '@univerjs/sheets'; -import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, ILayoutService, IMenuService, IShortcutService, IUIPartsService } from '@univerjs/ui'; +import { BuiltInUIPart, ComponentManager, ILayoutService, IMenu2Service, IShortcutService, IUIPartsService } from '@univerjs/ui'; import { ITextSelectionRenderManager } from '@univerjs/engine-render'; import { @@ -106,76 +104,6 @@ import { SheetPermissionOpenDialogOperation } from '../commands/operations/sheet import { AddRangeProtectionFromContextMenuCommand, AddRangeProtectionFromSheetBarCommand, AddRangeProtectionFromToolbarCommand, DeleteRangeProtectionFromContextMenuCommand, SetProtectionCommand, SetRangeProtectionFromContextMenuCommand, ViewSheetPermissionFromContextMenuCommand, ViewSheetPermissionFromSheetBarCommand } from '../commands/commands/range-protection.command'; import { AddWorksheetProtectionCommand, ChangeSheetProtectionFromSheetBarCommand, DeleteWorksheetProtectionCommand, DeleteWorksheetProtectionFormSheetBarCommand, SetWorksheetProtectionCommand } from '../commands/commands/worksheet-protection.command'; import { ScrollToRangeOperation } from '../commands/operations/scroll-to-range.operation'; -import { - ClearSelectionAllMenuItemFactory, - ClearSelectionContentMenuItemFactory, - ClearSelectionFormatMenuItemFactory, - ClearSelectionMenuItemFactory, -} from './menu/clear.menu'; -import { - DeleteRangeMenuItemFactory, - DeleteRangeMoveLeftMenuItemFactory, - DeleteRangeMoveUpMenuItemFactory, - RemoveColMenuItemFactory, - RemoveRowMenuItemFactory, -} from './menu/delete.menu'; -import { - CellInsertMenuItemFactory, - ColInsertMenuItemFactory, - InsertColAfterMenuItemFactory, - InsertColBeforeMenuItemFactory, - InsertRangeMoveDownMenuItemFactory, - InsertRangeMoveRightMenuItemFactory, - InsertRowAfterMenuItemFactory, - InsertRowBeforeMenuItemFactory, - RowInsertMenuItemFactory, -} from './menu/insert.menu'; -import { - BackgroundColorSelectorMenuItemFactory, - BoldMenuItemFactory, - CancelFrozenMenuItemFactory, - CopyMenuItemFactory, - FitContentMenuItemFactory, - FontFamilySelectorMenuItemFactory, - FontSizeSelectorMenuItemFactory, - FormatPainterMenuItemFactory, - FrozenColMenuItemFactory, - FrozenMenuItemFactory, - FrozenRowMenuItemFactory, - HideColMenuItemFactory, - HideRowMenuItemFactory, - HorizontalAlignMenuItemFactory, - ItalicMenuItemFactory, - PasteBesidesBorderMenuItemFactory, - PasteColWidthMenuItemFactory, - PasteFormatMenuItemFactory, - PasteMenuItemFactory, - PasteSpacialMenuItemFactory, - PasteValueMenuItemFactory, - ResetBackgroundColorMenuItemFactory, - ResetTextColorMenuItemFactory, - SetColWidthMenuItemFactory, - SetRowHeightMenuItemFactory, - SheetFrozenHeaderMenuItemFactory, - SheetFrozenMenuItemFactory, - ShowColMenuItemFactory, - ShowRowMenuItemFactory, - StrikeThroughMenuItemFactory, - TextColorSelectorMenuItemFactory, - TextRotateMenuItemFactory, - UnderlineMenuItemFactory, - VerticalAlignMenuItemFactory, - WrapTextMenuItemFactory, -} from './menu/menu'; - -import { - ChangeColorSheetMenuItemFactory, - CopySheetMenuItemFactory, - DeleteSheetMenuItemFactory, - HideSheetMenuItemFactory, - RenameSheetMenuItemFactory, - ShowMenuItemFactory, -} from './menu/sheet.menu'; import { EditorBreakLineShortcut, EditorCursorEnterShortcut, @@ -226,28 +154,17 @@ import { ZoomInShortcutItem, ZoomOutShortcutItem, } from './shortcuts/view.shortcut'; -import { CellBorderSelectorMenuItemFactory } from './menu/border.menu'; -import { CellMergeAllMenuItemFactory, CellMergeCancelMenuItemFactory, CellMergeHorizontalMenuItemFactory, CellMergeMenuItemFactory, CellMergeVerticalMenuItemFactory } from './menu/merge.menu'; -import { sheetPermissionAddProtectContextMenuFactory, sheetPermissionChangeSheetPermissionSheetBarMenuFactory, sheetPermissionContextMenuFactory, sheetPermissionEditProtectContextMenuFactory, sheetPermissionProtectSheetInSheetBarMenuFactory, sheetPermissionRemoveProtectContextMenuFactory, sheetPermissionRemoveProtectionSheetBarMenuFactory, sheetPermissionToolbarMenuFactory, sheetPermissionViewAllProtectRuleContextMenuFactory, sheetPermissionViewAllProtectRuleSheetBarMenuFactory } from './menu/permission.menu'; - -export interface IUniverSheetsUIConfig { - menu: MenuConfig; - disableAutoFocus?: true; - override?: DependencyOverride; -} - -export const DefaultSheetUiConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Ready, SheetUIController) export class SheetUIController extends Disposable { constructor( - protected readonly _config: Partial, @Inject(Injector) protected readonly _injector: Injector, @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, @ILayoutService protected readonly _layoutService: ILayoutService, @ICommandService protected readonly _commandService: ICommandService, @IShortcutService protected readonly _shortcutService: IShortcutService, - @IMenuService protected readonly _menuService: IMenuService, + @IMenu2Service protected readonly _menu2Service: IMenu2Service, @IUIPartsService protected readonly _uiPartsService: IUIPartsService ) { super(); @@ -358,98 +275,8 @@ export class SheetUIController extends Disposable { }); } - // eslint-disable-next-line max-lines-per-function private _initMenus(): void { - const { menu = {} } = this._config; - - ( - [ - // context menu - CopyMenuItemFactory, - PasteMenuItemFactory, - PasteSpacialMenuItemFactory, - PasteValueMenuItemFactory, - PasteFormatMenuItemFactory, - PasteColWidthMenuItemFactory, - PasteBesidesBorderMenuItemFactory, - ClearSelectionContentMenuItemFactory, - ClearSelectionFormatMenuItemFactory, - ClearSelectionAllMenuItemFactory, - ClearSelectionMenuItemFactory, - ColInsertMenuItemFactory, - RowInsertMenuItemFactory, - CellInsertMenuItemFactory, - InsertRowBeforeMenuItemFactory, - InsertRowAfterMenuItemFactory, - InsertColBeforeMenuItemFactory, - InsertColAfterMenuItemFactory, - RemoveRowMenuItemFactory, - HideRowMenuItemFactory, - ShowRowMenuItemFactory, - HideColMenuItemFactory, - ShowColMenuItemFactory, - RemoveColMenuItemFactory, - SetRowHeightMenuItemFactory, - FitContentMenuItemFactory, - SetColWidthMenuItemFactory, - DeleteRangeMenuItemFactory, - DeleteRangeMoveLeftMenuItemFactory, - DeleteRangeMoveUpMenuItemFactory, - InsertRangeMoveRightMenuItemFactory, - InsertRangeMoveDownMenuItemFactory, - FrozenMenuItemFactory, - FrozenRowMenuItemFactory, - FrozenColMenuItemFactory, - CancelFrozenMenuItemFactory, - SheetFrozenMenuItemFactory, - SheetFrozenHeaderMenuItemFactory, - - // toolbar - FormatPainterMenuItemFactory, - BoldMenuItemFactory, - ItalicMenuItemFactory, - UnderlineMenuItemFactory, - StrikeThroughMenuItemFactory, - FontFamilySelectorMenuItemFactory, - FontSizeSelectorMenuItemFactory, - ResetTextColorMenuItemFactory, - TextColorSelectorMenuItemFactory, - ResetBackgroundColorMenuItemFactory, - BackgroundColorSelectorMenuItemFactory, - CellBorderSelectorMenuItemFactory, - CellMergeMenuItemFactory, - CellMergeAllMenuItemFactory, - CellMergeVerticalMenuItemFactory, - CellMergeHorizontalMenuItemFactory, - CellMergeCancelMenuItemFactory, - HorizontalAlignMenuItemFactory, - VerticalAlignMenuItemFactory, - WrapTextMenuItemFactory, - TextRotateMenuItemFactory, - - // sheetbar - DeleteSheetMenuItemFactory, - CopySheetMenuItemFactory, - RenameSheetMenuItemFactory, - ChangeColorSheetMenuItemFactory, - HideSheetMenuItemFactory, - ShowMenuItemFactory, - - // sheet protection - sheetPermissionContextMenuFactory, - sheetPermissionAddProtectContextMenuFactory, - sheetPermissionEditProtectContextMenuFactory, - sheetPermissionRemoveProtectContextMenuFactory, - sheetPermissionViewAllProtectRuleContextMenuFactory, - sheetPermissionProtectSheetInSheetBarMenuFactory, - sheetPermissionRemoveProtectionSheetBarMenuFactory, - sheetPermissionChangeSheetPermissionSheetBarMenuFactory, - sheetPermissionViewAllProtectRuleSheetBarMenuFactory, - sheetPermissionToolbarMenuFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initShortcuts(): void { diff --git a/packages/sheets-ui/src/index.ts b/packages/sheets-ui/src/index.ts index db1acf8764..7e0510fcfa 100644 --- a/packages/sheets-ui/src/index.ts +++ b/packages/sheets-ui/src/index.ts @@ -24,7 +24,7 @@ export { SheetsRenderService } from './services/sheets-render.service'; export { SHEET_VIEWPORT_KEY as VIEWPORT_KEY } from './common/keys'; export { AutoFillController } from './controllers/auto-fill.controller'; export { CellCustomRenderController } from './controllers/cell-custom-render.controller'; -export { SheetUIController, type IUniverSheetsUIConfig } from './controllers/sheet-ui.controller'; +export { SheetUIController } from './controllers/sheet-ui.controller'; export { PASTE_SPECIAL_MENU_ID } from './controllers/menu/menu'; export { whenFormulaEditorActivated } from './controllers/shortcuts/utils'; export { @@ -100,6 +100,8 @@ export { SheetPermissionInitController } from './controllers/permission/sheet-pe export { IFormatPainterService } from './services/format-painter/format-painter.service'; export type { IFormatPainterBeforeApplyHookParams, IFormatPainterHook } from './services/format-painter/format-painter.service'; +export { menuSchema } from './controllers/menu.schema'; + // #region - all commands export { AddWorksheetMergeCommand, AddWorksheetMergeAllCommand, AddWorksheetMergeVerticalCommand, AddWorksheetMergeHorizontalCommand } from './commands/commands/add-worksheet-merge.command'; diff --git a/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts b/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts index b11aa1280f..9ed89b02bf 100644 --- a/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts @@ -15,7 +15,7 @@ */ import type { Dependency, Workbook } from '@univerjs/core'; -import { DependentOn, Inject, Injector, IUniverInstanceService, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, Inject, Injector, IUniverInstanceService, Plugin, UniverInstanceType } from '@univerjs/core'; import { filter } from 'rxjs/operators'; import { IRenderManagerService } from '@univerjs/engine-render'; @@ -29,8 +29,6 @@ import { HeaderFreezeRenderController } from './controllers/render-controllers/f import { HeaderMoveRenderController } from './controllers/render-controllers/header-move.render-controller'; import { MarkSelectionRenderController } from './controllers/mark-selection.controller'; import { SheetsRenderService } from './services/sheets-render.service'; -import type { IUniverSheetsUIConfig } from './controllers/sheet-ui.controller'; -import { DefaultSheetUiConfig } from './controllers/sheet-ui.controller'; import { StatusBarController } from './controllers/status-bar.controller'; import { AutoFillService, IAutoFillService } from './services/auto-fill/auto-fill.service'; import { ISheetClipboardService, SheetClipboardService } from './services/clipboard/clipboard.service'; @@ -70,6 +68,8 @@ import { SheetRenderController } from './controllers/render-controllers/sheet.re import { MobileSheetsSelectionRenderService } from './services/selection/mobile-selection-render.service'; import { ISheetSelectionRenderService } from './services/selection/base-selection-render.service'; import { SelectAllService } from './services/select-all/select-all.service'; +import type { IUniverSheetsUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig } from './controllers/config.schema'; /** * @ignore @@ -80,14 +80,12 @@ export class UniverSheetsMobileUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService ) { super(); - - this._config = Tools.deepMerge({}, DefaultSheetUiConfig, this._config); } override onStarting(): void { @@ -112,9 +110,7 @@ export class UniverSheetsMobileUIPlugin extends Plugin { [AutoHeightController], [SheetClipboardController], [SheetsRenderService], - [SheetUIMobileController, { - useFactory: (): SheetUIMobileController => this._injector.createInstance(SheetUIMobileController, this._config), - }], + [SheetUIMobileController], [StatusBarController], // permission diff --git a/packages/sheets-ui/src/sheets-ui-plugin.ts b/packages/sheets-ui/src/sheets-ui-plugin.ts index b0f67f405e..19574e917b 100644 --- a/packages/sheets-ui/src/sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/sheets-ui-plugin.ts @@ -15,7 +15,7 @@ */ import type { Dependency, Workbook } from '@univerjs/core'; -import { DependentOn, Inject, Injector, IUniverInstanceService, mergeOverrideWithDependencies, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, IUniverInstanceService, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; import { filter } from 'rxjs/operators'; import { IRenderManagerService } from '@univerjs/engine-render'; @@ -33,8 +33,7 @@ import { HeaderResizeRenderController } from './controllers/render-controllers/h import { HeaderUnhideRenderController } from './controllers/render-controllers/header-unhide.render-controller'; import { MarkSelectionRenderController } from './controllers/mark-selection.controller'; import { SheetsRenderService } from './services/sheets-render.service'; -import type { IUniverSheetsUIConfig } from './controllers/sheet-ui.controller'; -import { DefaultSheetUiConfig, SheetUIController } from './controllers/sheet-ui.controller'; +import { SheetUIController } from './controllers/sheet-ui.controller'; import { StatusBarController } from './controllers/status-bar.controller'; import { AutoFillService, IAutoFillService } from './services/auto-fill/auto-fill.service'; import { ISheetClipboardService, SheetClipboardService } from './services/clipboard/clipboard.service'; @@ -83,6 +82,8 @@ import { MoveRangeRenderController } from './controllers/move-range.controller'; import { ISheetSelectionRenderService } from './services/selection/base-selection-render.service'; import { SheetScrollManagerService } from './services/scroll-manager.service'; import { SelectAllService } from './services/select-all/select-all.service'; +import type { IUniverSheetsUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverSheetsPlugin) export class UniverSheetsUIPlugin extends Plugin { @@ -91,14 +92,21 @@ export class UniverSheetsUIPlugin extends Plugin { /** @ignore */ constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService ) { super(); - this._config = Tools.deepMerge({}, DefaultSheetUiConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { @@ -126,9 +134,7 @@ export class UniverSheetsUIPlugin extends Plugin { [FormulaEditorController], [SheetClipboardController], [SheetsRenderService], - [SheetUIController, { - useFactory: (): SheetUIController => this._injector.createInstance(SheetUIController, this._config), - }], + [SheetUIController], [StatusBarController], [AutoFillController], [FormatPainterController], diff --git a/packages/sheets-ui/src/views/sheet-bar/sheet-bar-tabs/SheetBarTabs.tsx b/packages/sheets-ui/src/views/sheet-bar/sheet-bar-tabs/SheetBarTabs.tsx index 8f944f64da..a274e30a8c 100644 --- a/packages/sheets-ui/src/views/sheet-bar/sheet-bar-tabs/SheetBarTabs.tsx +++ b/packages/sheets-ui/src/views/sheet-bar/sheet-bar-tabs/SheetBarTabs.tsx @@ -32,12 +32,11 @@ import { WorkbookRenameSheetPermission, WorksheetProtectionRuleModel, } from '@univerjs/sheets'; -import { IConfirmService, Menu, useObservable } from '@univerjs/ui'; +import { ContextMenuPosition, IConfirmService, Menu, useObservable } from '@univerjs/ui'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { LockSingle } from '@univerjs/icons'; import { merge } from 'rxjs'; -import { SheetMenuPosition } from '../../../controllers/menu/menu'; import { ISheetBarService } from '../../../services/sheet-bar/sheet-bar.service'; import { IEditorBridgeService } from '../../../services/editor-bridge.service'; import { useActiveWorkbook } from '../../../components/hook'; @@ -409,7 +408,7 @@ export function SheetBarTabs() { trigger={['contextMenu']} overlay={( { const { label: id, value, commandId } = params; commandService.executeCommand(commandId ?? id as string, { value, subUnitId: activeKey }); diff --git a/packages/sheets-ui/src/views/sheet-container/SheetContainer.tsx b/packages/sheets-ui/src/views/sheet-container/SheetContainer.tsx index 3420c318e5..bf8d3afaa5 100644 --- a/packages/sheets-ui/src/views/sheet-container/SheetContainer.tsx +++ b/packages/sheets-ui/src/views/sheet-container/SheetContainer.tsx @@ -17,7 +17,7 @@ import { IUniverInstanceService, UniverInstanceType, useDependency } from '@univerjs/core'; import type { Workbook } from '@univerjs/core'; import React, { useMemo } from 'react'; -import { ToolbarItem, useObservable, useSimpleToolbarGroups } from '@univerjs/ui'; +import { ContextMenuPosition, IMenu2Service, ToolbarItem, useObservable } from '@univerjs/ui'; import { CountBar } from '../count-bar/CountBar'; import { EditorContainer } from '../editor-container/EditorContainer'; @@ -26,19 +26,29 @@ import { OperateContainer } from '../operate-container/OperateContainer'; import { SheetBar } from '../sheet-bar/SheetBar'; import { StatusBar } from '../status-bar/StatusBar'; import { useActiveWorkbook } from '../../components/hook'; -import { SheetMenuPosition } from '../../controllers/menu/menu'; import styles from './index.module.less'; export function RenderSheetFooter() { + const menu2Service = useDependency(IMenu2Service); const workbook = useActiveWorkbook(); - const footerMenus = useSimpleToolbarGroups(SheetMenuPosition.SHEET_FOOTER); + const footerMenus = menu2Service.getMenuByPositionKey(ContextMenuPosition.FOOTER_MENU); if (!workbook) return null; return (
- {footerMenus.map((item) => )} + {footerMenus.map((item) => item.children?.map((child) => ( + child?.item && ( + + ) + )))}
); diff --git a/packages/sheets-zen-editor/src/controllers/config.schema.ts b/packages/sheets-zen-editor/src/controllers/config.schema.ts new file mode 100644 index 0000000000..af105db3dd --- /dev/null +++ b/packages/sheets-zen-editor/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-zen-editor.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsZenEditorConfig { + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSheetsZenEditorConfig = {}; diff --git a/packages/sheets-zen-editor/src/controllers/menu.schema.ts b/packages/sheets-zen-editor/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..b2238b6ac6 --- /dev/null +++ b/packages/sheets-zen-editor/src/controllers/menu.schema.ts @@ -0,0 +1,31 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { ContextMenuGroup, ContextMenuPosition } from '@univerjs/ui'; +import { OpenZenEditorOperation } from '../commands/operations/zen-editor.operation'; +import { ZenEditorMenuItemFactory } from '../views/menu'; + +export const menuSchema: IMenu2Item = { + [ContextMenuPosition.MAIN_AREA]: { + [ContextMenuGroup.OTHERS]: { + [OpenZenEditorOperation.id]: { + order: 2, + menuItemFactory: ZenEditorMenuItemFactory, + }, + }, + }, +}; diff --git a/packages/sheets-zen-editor/src/controllers/zen-editor-ui.controller.ts b/packages/sheets-zen-editor/src/controllers/zen-editor-ui.controller.ts index 709790ce73..6dace2f387 100644 --- a/packages/sheets-zen-editor/src/controllers/zen-editor-ui.controller.ts +++ b/packages/sheets-zen-editor/src/controllers/zen-editor-ui.controller.ts @@ -15,29 +15,21 @@ */ import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { IMenuItemFactory, MenuConfig } from '@univerjs/ui'; -import { IMenuService, IShortcutService, IZenZoneService } from '@univerjs/ui'; +import { IMenu2Service, IShortcutService, IZenZoneService } from '@univerjs/ui'; import { CancelZenEditCommand, ConfirmZenEditCommand } from '../commands/commands/zen-editor.command'; import { OpenZenEditorOperation } from '../commands/operations/zen-editor.operation'; -import { ZenEditorMenuItemFactory } from '../views/menu'; import { ZEN_EDITOR_COMPONENT, ZenEditor } from '../views/zen-editor'; import { ZenEditorCancelShortcut, ZenEditorConfirmShortcut } from './shortcuts/zen-editor.shortcut'; - -export interface IUniverSheetsZenEditorUIConfig { - menu: MenuConfig; -} - -export const DefaultSheetZenEditorUiConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Rendered, ZenEditorUIController) export class ZenEditorUIController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) private readonly _injector: Injector, @IZenZoneService private readonly _zenZoneService: IZenZoneService, @ICommandService private readonly _commandService: ICommandService, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @IShortcutService private readonly _shortcutService: IShortcutService ) { super(); @@ -63,16 +55,7 @@ export class ZenEditorUIController extends Disposable { } private _initMenus(): void { - const { menu = {} } = this._config; - - ( - [ - // context menu - ZenEditorMenuItemFactory, - ] as IMenuItemFactory[] - ).forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initShortcuts(): void { diff --git a/packages/sheets-zen-editor/src/plugin.ts b/packages/sheets-zen-editor/src/plugin.ts index ef68823faf..2af9b8ef25 100644 --- a/packages/sheets-zen-editor/src/plugin.ts +++ b/packages/sheets-zen-editor/src/plugin.ts @@ -14,37 +14,39 @@ * limitations under the License. */ -import { Inject, Injector, LocaleService, Plugin, Tools, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { ZenEditorController } from './controllers/zen-editor.controller'; -import type { IUniverSheetsZenEditorUIConfig } from './controllers/zen-editor-ui.controller'; -import { DefaultSheetZenEditorUiConfig, ZenEditorUIController } from './controllers/zen-editor-ui.controller'; +import { ZenEditorUIController } from './controllers/zen-editor-ui.controller'; import { IZenEditorManagerService, ZenEditorManagerService } from './services/zen-editor.service'; +import type { IUniverSheetsZenEditorConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverSheetsZenEditorPlugin extends Plugin { static override pluginName = 'zen-editor'; static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + this._initializeDependencies(this._injector); - this._config = Tools.deepMerge({}, DefaultSheetZenEditorUiConfig, this._config); } private _initializeDependencies(injector: Injector) { const dependencies: Dependency[] = [ - [ - ZenEditorUIController, - { - useFactory: () => this._injector.createInstance(ZenEditorUIController, this._config), - }, - ], + [ZenEditorUIController], [ZenEditorController], [IZenEditorManagerService, { useClass: ZenEditorManagerService }], ]; diff --git a/packages/sheets/src/controllers/config.schema.ts b/packages/sheets/src/controllers/config.schema.ts new file mode 100644 index 0000000000..9b5dba26fb --- /dev/null +++ b/packages/sheets/src/controllers/config.schema.ts @@ -0,0 +1,33 @@ +/** + * 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 { DependencyOverride } from '@univerjs/core'; + +export const PLUGIN_CONFIG_KEY = 'sheets.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsConfig { + notExecuteFormula?: boolean; + override?: DependencyOverride; + /** + * Only register the mutations related to the formula calculation. Especially useful for the + * web worker environment or server-side-calculation. + */ + onlyRegisterFormulaRelatedMutations?: true; +} + +export const defaultPluginConfig: IUniverSheetsConfig = {}; diff --git a/packages/sheets/src/index.ts b/packages/sheets/src/index.ts index 6780c7284e..ed3cd7adb1 100644 --- a/packages/sheets/src/index.ts +++ b/packages/sheets/src/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { type IUniverSheetsConfig, UniverSheetsPlugin } from './sheets-plugin'; +export { UniverSheetsPlugin } from './sheets-plugin'; // #region services export { COMMAND_LISTENER_SKELETON_CHANGE, COMMAND_LISTENER_VALUE_CHANGE } from './basics/const/command-listener-const'; diff --git a/packages/sheets/src/sheets-plugin.ts b/packages/sheets/src/sheets-plugin.ts index c3c59fc4bc..6fa3d890df 100644 --- a/packages/sheets/src/sheets-plugin.ts +++ b/packages/sheets/src/sheets-plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Dependency, DependencyOverride } from '@univerjs/core'; +import type { Dependency } from '@univerjs/core'; import { DependentOn, IConfigService, Inject, Injector, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; @@ -39,32 +39,27 @@ import { ONLY_REGISTER_FORMULA_RELATED_MUTATIONS_KEY } from './controllers/confi import { NumberCellDisplayController } from './controllers/number-cell.controller'; import { SheetsSelectionsService } from './services/selections/selection-manager.service'; import { ExclusiveRangeService, IExclusiveRangeService } from './services/exclusive-range/exclusive-range-service'; +import type { IUniverSheetsConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'SHEET_PLUGIN'; -export interface IUniverSheetsConfig { - notExecuteFormula?: boolean; - override?: DependencyOverride; - - /** - * Only register the mutations related to the formula calculation. Especially useful for the - * web worker environment or server-side-calculation. - */ - onlyRegisterFormulaRelatedMutations?: true; -} - @DependentOn(UniverFormulaEnginePlugin) export class UniverSheetsPlugin extends Plugin { static override pluginName = PLUGIN_NAME; static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private _config: IUniverSheetsConfig | undefined, - @IConfigService private readonly _configService: IConfigService, - @Inject(Injector) override readonly _injector: Injector + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + this._initConfig(); this._initDependencies(_injector); } diff --git a/packages/slides-ui/src/controllers/config.schema.ts b/packages/slides-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..77343f007c --- /dev/null +++ b/packages/slides-ui/src/controllers/config.schema.ts @@ -0,0 +1,29 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; +import type { DependencyOverride } from '@univerjs/core'; + +export const PLUGIN_CONFIG_KEY = 'slides-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSlidesUIConfig { + override?: DependencyOverride; + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverSlidesUIConfig = {}; diff --git a/packages/slides-ui/src/controllers/menu.schema.ts b/packages/slides-ui/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..c222249362 --- /dev/null +++ b/packages/slides-ui/src/controllers/menu.schema.ts @@ -0,0 +1,49 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { SlideAddTextCommand } from '../commands/operations/insert-text.operation'; +import { InsertSlideFloatImageOperation } from '../commands/operations/insert-image.operation'; +import { InsertSlideShapeRectangleCommand } from '../commands/operations/insert-shape.operation'; +import { SlideAddTextMenuItemFactory } from './text.menu'; +import { IMAGE_MENU_ID, SlideImageMenuFactory, UploadSlideFloatImageMenuFactory } from './image.menu'; +import { SHAPE_MENU_ID, SlideShapeMenuFactory, UploadSlideFloatShapeMenuFactory } from './shape.menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.FORMAT]: { + [SlideAddTextCommand.id]: { + order: 0, + menuItemFactory: SlideAddTextMenuItemFactory, + }, + [IMAGE_MENU_ID]: { + order: 0, + menuItemFactory: SlideImageMenuFactory, + [InsertSlideFloatImageOperation.id]: { + order: 0, + menuItemFactory: UploadSlideFloatImageMenuFactory, + }, + }, + [SHAPE_MENU_ID]: { + order: 0, + menuItemFactory: SlideShapeMenuFactory, + [InsertSlideShapeRectangleCommand.id]: { + order: 0, + menuItemFactory: UploadSlideFloatShapeMenuFactory, + }, + }, + }, +}; diff --git a/packages/slides-ui/src/controllers/slide-ui.controller.ts b/packages/slides-ui/src/controllers/slide-ui.controller.ts index 7c1f97e3bb..5bd57e505a 100644 --- a/packages/slides-ui/src/controllers/slide-ui.controller.ts +++ b/packages/slides-ui/src/controllers/slide-ui.controller.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import type { DependencyOverride } from '@univerjs/core'; import { connectInjector, Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; import { AddImageSingle, GraphSingle, TextSingle } from '@univerjs/icons'; -import type { MenuConfig } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, IMenuService, IShortcutService, IUIPartsService } from '@univerjs/ui'; +import { BuiltInUIPart, ComponentManager, IMenu2Service, IShortcutService, IUIPartsService } from '@univerjs/ui'; import { ActivateSlidePageOperation } from '../commands/operations/activate.operation'; import { DeleteSlideElementOperation } from '../commands/operations/delete-element.operation'; import { InsertSlideFloatImageOperation } from '../commands/operations/insert-image.operation'; @@ -35,18 +33,11 @@ import { SlideSideBar } from '../components/slide-bar/SlideBar'; import Sidebar, { COMPONENT_SLIDE_SIDEBAR } from '../components/sidebar/Sidebar'; import { AppendSlideOperation } from '../commands/operations/append-slide.operation'; import { UpdateSlideElementOperation } from '../commands/operations/update-element.operation'; -import { IMAGE_UPLOAD_ICON, SlideImageMenuFactory, UploadSlideFloatImageMenuFactory } from './image.menu'; -import { GRAPH_SINGLE_ICON, SlideShapeMenuFactory, UploadSlideFloatShapeMenuFactory } from './shape.menu'; +import { IMAGE_UPLOAD_ICON } from './image.menu'; +import { GRAPH_SINGLE_ICON } from './shape.menu'; import { EditorDeleteLeftShortcut, generateArrowSelectionShortCutItem } from './shortcuts/editor.shortcuts'; -import { SlideAddTextMenuItemFactory, TEXT_ICON_ID } from './text.menu'; - -export interface IUniverSlidesDrawingConfig { - menu?: MenuConfig; - override?: DependencyOverride; -} - -export const DefaultSlidesDrawingConfig: IUniverSlidesDrawingConfig = { -}; +import { TEXT_ICON_ID } from './text.menu'; +import { menuSchema } from './menu.schema'; /** * This controller registers UI parts of slide workbench to the base-ui workbench. @@ -54,9 +45,8 @@ export const DefaultSlidesDrawingConfig: IUniverSlidesDrawingConfig = { @OnLifecycle(LifecycleStages.Ready, SlidesUIController) export class SlidesUIController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) protected readonly _injector: Injector, - @IMenuService protected readonly _menuService: IMenuService, + @IMenu2Service protected readonly _menu2Service: IMenu2Service, @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, @IUIPartsService protected readonly _uiPartsService: IUIPartsService, @ICommandService protected readonly _commandService: ICommandService, @@ -72,17 +62,7 @@ export class SlidesUIController extends Disposable { } private _initMenus(): void { - const { menu = {} } = this._config || {}; - - [ - SlideAddTextMenuItemFactory, - SlideImageMenuFactory, - UploadSlideFloatImageMenuFactory, - SlideShapeMenuFactory, - UploadSlideFloatShapeMenuFactory, - ].forEach((menuFactory) => { - this._menuService.addMenuItem(menuFactory(this._injector), menu); - }); + this._menu2Service.mergeMenu(menuSchema); } private _initCustomComponents(): void { diff --git a/packages/slides-ui/src/index.ts b/packages/slides-ui/src/index.ts index e9bad3001f..cbe2997b6a 100644 --- a/packages/slides-ui/src/index.ts +++ b/packages/slides-ui/src/index.ts @@ -20,13 +20,13 @@ export { SlideSideBar } from './components/slide-bar/SlideBar'; export { ISlideEditorBridgeService } from './services/slide-editor-bridge.service'; export { SlideCanvasPopMangerService } from './services/slide-popup-manager.service'; -export type { IUniverSlidesDrawingConfig } from './controllers/slide-ui.controller'; export { IMAGE_MENU_ID } from './controllers/image.menu'; export { SHAPE_MENU_ID } from './controllers/shape.menu'; -// #region - all commands +export { menuSchema } from './controllers/menu.schema'; +// #region - all commands export { ActivateSlidePageOperation } from './commands/operations/activate.operation'; export { DeleteSlideElementOperation } from './commands/operations/delete-element.operation'; export { InsertSlideFloatImageOperation } from './commands/operations/insert-image.operation'; diff --git a/packages/slides-ui/src/locale/ru-RU.ts b/packages/slides-ui/src/locale/ru-RU.ts index 1a9815b8c9..2c3186a9ed 100644 --- a/packages/slides-ui/src/locale/ru-RU.ts +++ b/packages/slides-ui/src/locale/ru-RU.ts @@ -15,7 +15,7 @@ */ import type zhCN from './zh-CN'; -import enUS from './en-US.ts'; +import enUS from './en-US'; const locale: typeof zhCN = enUS; diff --git a/packages/slides-ui/src/locale/vi-VN.ts b/packages/slides-ui/src/locale/vi-VN.ts index 1a9815b8c9..2c3186a9ed 100644 --- a/packages/slides-ui/src/locale/vi-VN.ts +++ b/packages/slides-ui/src/locale/vi-VN.ts @@ -15,7 +15,7 @@ */ import type zhCN from './zh-CN'; -import enUS from './en-US.ts'; +import enUS from './en-US'; const locale: typeof zhCN = enUS; diff --git a/packages/slides-ui/src/locale/zh-TW.ts b/packages/slides-ui/src/locale/zh-TW.ts index 1a9815b8c9..2c3186a9ed 100644 --- a/packages/slides-ui/src/locale/zh-TW.ts +++ b/packages/slides-ui/src/locale/zh-TW.ts @@ -15,7 +15,7 @@ */ import type zhCN from './zh-CN'; -import enUS from './en-US.ts'; +import enUS from './en-US'; const locale: typeof zhCN = enUS; diff --git a/packages/slides-ui/src/slides-ui-plugin.ts b/packages/slides-ui/src/slides-ui-plugin.ts index a50c087262..a795d6984d 100644 --- a/packages/slides-ui/src/slides-ui-plugin.ts +++ b/packages/slides-ui/src/slides-ui-plugin.ts @@ -15,11 +15,10 @@ */ import type { Dependency, SlideDataModel } from '@univerjs/core'; -import { Inject, Injector, IUniverInstanceService, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, IUniverInstanceService, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; -import type { IUniverSlidesDrawingConfig } from './controllers/slide-ui.controller'; import { SlidesUIController } from './controllers/slide-ui.controller'; import { SlideRenderController } from './controllers/slide.render-controller'; import { SlidePopupMenuController } from './controllers/popup-menu.controller'; @@ -30,6 +29,8 @@ import { ISlideEditorManagerService, SlideEditorManagerService } from './service import { SlideEditingRenderController } from './controllers/slide-editing.render-controller'; import { SlideRenderService } from './services/slide-render.service'; import { CanvasView } from './controllers/canvas-view'; +import type { IUniverSlidesUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export const SLIDE_UI_PLUGIN_NAME = 'SLIDE_UI'; @@ -38,12 +39,20 @@ export class UniverSlidesUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_SLIDE; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService + @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { @@ -74,9 +83,7 @@ export class UniverSlidesUIPlugin extends Plugin { // SlidesUIController controller should be registered in Ready stage. // SlidesUIController controller would add a new RenderUnit (__INTERNAL_EDITOR__DOCS_NORMAL) - [SlidesUIController, { - useFactory: () => this._injector.createInstance(SlidesUIController, this._config), - }], // editor service was create in renderManagerService + [SlidesUIController], // editor service was create in renderManagerService [SlideRenderController], [SlidePopupMenuController], ] as Dependency[], this._config.override).forEach((m) => { diff --git a/packages/slides/src/controllers/config.schema.ts b/packages/slides/src/controllers/config.schema.ts new file mode 100644 index 0000000000..f0e757b263 --- /dev/null +++ b/packages/slides/src/controllers/config.schema.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export const PLUGIN_CONFIG_KEY = 'slides.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSlidesConfig { +} + +export const defaultPluginConfig: IUniverSlidesConfig = {}; diff --git a/packages/slides/src/slides-plugin.ts b/packages/slides/src/slides-plugin.ts index 358f341ec5..e07717f258 100644 --- a/packages/slides/src/slides-plugin.ts +++ b/packages/slides/src/slides-plugin.ts @@ -14,16 +14,12 @@ * limitations under the License. */ -import { Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; import type { Engine } from '@univerjs/engine-render'; import { IRenderingEngine, IRenderManagerService } from '@univerjs/engine-render'; import type { Dependency } from '@univerjs/core'; -// import { TextSelectionManagerService } from '@univerjs/docs'; -// import { CanvasView } from './views/render'; - -export interface IUniverSlidesConfig {} - -const DEFAULT_SLIDE_PLUGIN_DATA = {}; +import type { IUniverSlidesConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'slides'; @@ -31,20 +27,22 @@ export class UniverSlidesPlugin extends Plugin { static override pluginName = PLUGIN_NAME; static override type = UniverInstanceType.UNIVER_SLIDE; - private _config: IUniverSlidesConfig; - private _canvasEngine: Engine | null = null; // private _canvasView: CanvasView | null = null; constructor( - config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) override readonly _injector: Injector, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Object.assign(DEFAULT_SLIDE_PLUGIN_DATA, config); + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + this._initializeDependencies(this._injector); } diff --git a/packages/thread-comment-ui/src/controllers/config.schema.ts b/packages/thread-comment-ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..e43883ca64 --- /dev/null +++ b/packages/thread-comment-ui/src/controllers/config.schema.ts @@ -0,0 +1,29 @@ +/** + * 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 { DependencyOverride } from '@univerjs/core'; +import type { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'thread-comment-ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverThreadCommentUIConfig { + overrides?: DependencyOverride; + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverThreadCommentUIConfig = {}; diff --git a/packages/thread-comment-ui/src/plugin.ts b/packages/thread-comment-ui/src/plugin.ts index 98afb7b585..4b9bd89e81 100644 --- a/packages/thread-comment-ui/src/plugin.ts +++ b/packages/thread-comment-ui/src/plugin.ts @@ -15,16 +15,14 @@ */ import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'; -import type { Dependency, DependencyOverride } from '@univerjs/core'; -import { DependentOn, ICommandService, Inject, Injector, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; +import type { Dependency } from '@univerjs/core'; +import { DependentOn, ICommandService, IConfigService, Inject, Injector, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; import { PLUGIN_NAME } from './types/const'; import { ThreadCommentPanelService } from './services/thread-comment-panel.service'; import { SetActiveCommentOperation, ToggleSheetCommentPanelOperation } from './commands/operations/comment.operations'; import { IThreadCommentMentionDataService, ThreadCommentMentionDataService } from './services/thread-comment-mention-data.service'; - -export interface IUniverThreadCommentUIConfig { - overrides?: DependencyOverride; -} +import type { IUniverThreadCommentUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; @DependentOn(UniverThreadCommentPlugin) export class UniverThreadCommentUIPlugin extends Plugin { @@ -32,11 +30,19 @@ export class UniverThreadCommentUIPlugin extends Plugin { static override type = UniverInstanceType.UNIVER_UNKNOWN; constructor( - private readonly _config: IUniverThreadCommentUIConfig | undefined, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected override _injector: Injector, - @ICommandService protected _commandService: ICommandService + @ICommandService protected _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/thread-comment/src/controllers/config.schema.ts b/packages/thread-comment/src/controllers/config.schema.ts new file mode 100644 index 0000000000..1988436dbc --- /dev/null +++ b/packages/thread-comment/src/controllers/config.schema.ts @@ -0,0 +1,27 @@ +/** + * 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 { DependencyOverride } from '@univerjs/core'; + +export const PLUGIN_CONFIG_KEY = 'thread-comment.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverThreadCommentConfig { + overrides?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverThreadCommentConfig = {}; diff --git a/packages/thread-comment/src/plugin.ts b/packages/thread-comment/src/plugin.ts index f753b79add..1be7104d4c 100644 --- a/packages/thread-comment/src/plugin.ts +++ b/packages/thread-comment/src/plugin.ts @@ -14,31 +14,32 @@ * limitations under the License. */ -import type { Dependency, DependencyOverride } from '@univerjs/core'; -import { ICommandService, Inject, Injector, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; +import type { Dependency } from '@univerjs/core'; +import { ICommandService, IConfigService, Inject, Injector, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core'; import { ThreadCommentModel } from './models/thread-comment.model'; import { ThreadCommentResourceController } from './controllers/tc-resource.controller'; import { TC_PLUGIN_NAME } from './types/const'; import { AddCommentMutation, DeleteCommentMutation, ResolveCommentMutation, UpdateCommentMutation, UpdateCommentRefMutation } from './commands/mutations/comment.mutation'; import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, ResolveCommentCommand, UpdateCommentCommand } from './commands/commands/comment.command'; import { IThreadCommentDataSourceService, ThreadCommentDataSourceService } from './services/tc-datasource.service'; - -export interface IUniverThreadCommentConfig { - overrides?: DependencyOverride; -} +import type { IUniverThreadCommentConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export class UniverThreadCommentPlugin extends Plugin { static override pluginName = TC_PLUGIN_NAME; static override type = UniverInstanceType.UNIVER_UNKNOWN; - private _config: IUniverThreadCommentConfig; constructor( - config: IUniverThreadCommentConfig, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected _injector: Injector, - @ICommandService protected _commandService: ICommandService + @ICommandService protected _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = config; + + // Manage the plugin configuration. + const { ...rest } = this._config; + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { diff --git a/packages/ui/src/common/menu-merge-configs.ts b/packages/ui/src/common/menu-merge-configs.ts index c2dfb0f42a..3b1b7b960b 100644 --- a/packages/ui/src/common/menu-merge-configs.ts +++ b/packages/ui/src/common/menu-merge-configs.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { BehaviorSubject, switchMap } from 'rxjs'; +import { BehaviorSubject, Observable, switchMap } from 'rxjs'; import type { MenuConfig, MenuItemConfig } from '../services/menu/menu'; export function mergeMenuConfigs(baseConfig: T, additionalConfig: MenuItemConfig | null): T { @@ -43,10 +43,16 @@ export function mergeMenuConfigs(baseConfig: T, additionalConfig // Helper function to update reactive properties function updateReactiveProperty(baseConfig: T, key: K, value: any): void { - if (value !== undefined && baseConfig[key]) { - const subject$ = (baseConfig[key] as any).pipe( - switchMap(() => new BehaviorSubject(value)) - ); - baseConfig[key] = subject$; + if (value !== undefined) { + if (baseConfig[key]) { + const subject$ = (baseConfig[key] as any).pipe( + switchMap(() => new BehaviorSubject(value)) + ); + baseConfig[key] = subject$; + } else { + baseConfig[key] = new Observable((subscriber) => { + subscriber.next(value); + }) as any; + } } } diff --git a/packages/ui/src/components/menu/desktop/Menu.tsx b/packages/ui/src/components/menu/desktop/Menu.tsx index e80cd819db..06877483c2 100644 --- a/packages/ui/src/components/menu/desktop/Menu.tsx +++ b/packages/ui/src/components/menu/desktop/Menu.tsx @@ -24,8 +24,8 @@ import { } from '@univerjs/design'; import { CheckMarkSingle, MoreSingle } from '@univerjs/icons'; import clsx from 'clsx'; -import React, { useMemo, useState } from 'react'; -import { combineLatest, isObservable, map, Observable } from 'rxjs'; +import React, { useState } from 'react'; +import { isObservable } from 'rxjs'; import type { IDisplayMenuItem, @@ -34,20 +34,20 @@ import type { IMenuSelectorItem, IValueOption, MenuItemDefaultValueType, -} from '../../../services/menu/menu.ts'; -import { MenuGroup, MenuItemType } from '../../../services/menu/menu.ts'; -import { IMenuService } from '../../../services/menu/menu.service.ts'; -import { CustomLabel } from '../../custom-label/CustomLabel.tsx'; -import { useObservable } from '../../hooks/observable.ts'; -import { useScrollYOverContainer } from '../../hooks/layout.ts'; -import { ILayoutService } from '../../../services/layout/layout.service.ts'; +} from '../../../services/menu/menu'; +import { MenuItemType } from '../../../services/menu/menu'; +import { CustomLabel } from '../../custom-label/CustomLabel'; +import { useObservable } from '../../hooks/observable'; +import { useScrollYOverContainer } from '../../hooks/layout'; +import { ILayoutService } from '../../../services/layout/layout.service'; +import { IMenu2Service } from '../../../services/menu/menu2.service'; import styles from './index.module.less'; // TODO: @jikkai disabled and hidden are not working export interface IBaseMenuProps { parentKey?: string | number; - menuType?: string | string[]; + menuType?: string; value?: string | number; options?: IValueOption[]; @@ -61,139 +61,90 @@ export interface IBaseMenuProps { function MenuWrapper(props: IBaseMenuProps) { const { menuType, onOptionSelect } = props; - const menuService = useDependency(IMenuService); + + const menu2Service = useDependency(IMenu2Service); if (!menuType) { return null; }; + const menuItems = menu2Service.getMenuByPositionKey(menuType); - if (Array.isArray(menuType)) { - const menuTypes = menuType.map((type) => menuService.getMenuItems(type)); - - const group = menuTypes.map((menuItems) => - menuItems.reduce( - (acc, item: IDisplayMenuItem) => { - if (item.group) { - acc[item.group] = acc[item.group] ?? []; - acc[item.group].push(item); - } else { - acc[MenuGroup.CONTEXT_MENU_OTHERS] = acc[MenuGroup.CONTEXT_MENU_OTHERS] ?? []; - acc[MenuGroup.CONTEXT_MENU_OTHERS].push(item); - } - return acc; - }, - {} as Record>> - ) - ); - - function filterData(data: Record[]>[]) { - return data.map((group) => { - const filteredGroup: Record[]> = {}; - - Object.entries(group).forEach(([key, items]) => { - const hiddenObservables = items.map((item) => item.hidden$ ?? new Observable((subscriber) => subscriber.next(false))); - - combineLatest(hiddenObservables) - .pipe( - map((hiddenValues) => hiddenValues.every((hidden) => hidden === true)) + return menuItems && menuItems.map((item) => item.item + ? ( + ) => { + onOptionSelect?.({ value: '', label: item.key, ...object }); + }} + /> + ) + : item.children?.length + ? ( + + {item.children.map((child) => ( + child.item && ( + ) => { + onOptionSelect?.({ value: '', label: child.key, ...object }); + }} + /> ) - .subscribe((allHidden) => { - if (!allHidden) { - filteredGroup[key] = items; - } - }) - .unsubscribe(); - }); - - return filteredGroup; - }).filter((group) => Object.keys(group).length > 0); - }; - - const filteredGroup = useMemo(() => filterData(group), [group]); - - return ( - <> - {filteredGroup.map((groupItem) => - Object.keys(groupItem).map((groupKey: string) => ( - - {groupItem[groupKey as unknown as MenuGroup].map((item: IDisplayMenuItem) => ( - ) => { - onOptionSelect?.({ value: '', label: item.id, ...object }); - }} - /> - ))} - - )) - )} - - ); - } - - const menuItems = menuService.getMenuItems(menuType); - - return menuItems.map((item: IDisplayMenuItem) => ( - ) => { - onOptionSelect?.({ value: '', label: item.id, ...object }); - }} - /> - )); + ))} + + ) + : null); } function MenuOptionsWrapper(props: IBaseMenuProps) { const { options, value, onOptionSelect, parentKey } = props; - return ( - options?.map((option: IValueOption, index: number) => { - const key = `${parentKey}-${option.label ?? option.id}-${index}`; + return options?.map((option: IValueOption, index: number) => { + const key = `${parentKey}-${option.label ?? option.id}-${index}`; - const onChange = (v: string | number) => { - onOptionSelect?.({ value: v, label: option?.label, commandId: option?.commandId }); - }; + const onChange = (v: string | number) => { + onOptionSelect?.({ value: v, label: option?.label, commandId: option?.commandId }); + }; - const handleClick = () => { - if (typeof option.value === 'undefined') return; + const handleClick = () => { + if (typeof option.value === 'undefined') return; - onOptionSelect?.({ - ...option, - }); - }; - - const _className = clsx({ - [styles.menuItemNoHover]: typeof option.label !== 'string' && !option.label?.hoverable, + onOptionSelect?.({ + ...option, }); + }; - return ( - - - {typeof value !== 'undefined' && String(value) === String(option.value) && ( - - - - )} - - - - ); - }) ?? null - ); + const _className = clsx({ + [styles.menuItemNoHover]: typeof option.label !== 'string' && !option.label?.hoverable, + }); + + return ( + + + {typeof value !== 'undefined' && String(value) === String(option.value) && ( + + + + )} + + + + ); + }) ?? null; } export const Menu = (props: IBaseMenuProps) => { @@ -220,7 +171,7 @@ interface IMenuItemProps { } function MenuItem({ menuItem, onClick }: IMenuItemProps) { - const menuService = useDependency(IMenuService); + const menu2Service = useDependency(IMenu2Service); const disabled = useObservable(menuItem.disabled$, false); const activated = useObservable(menuItem.activated$, false); @@ -320,7 +271,8 @@ function MenuItem({ menuItem, onClick }: IMenuItemProps) { ); }; - const subMenuItems = menuItem.id ? menuService.getMenuItems(menuItem.id) : []; + const subMenuItems = menuItem.id ? menu2Service.getMenuByPositionKey(menuItem.id) : []; + const renderSubItemsType = () => { const item = menuItem as IDisplayMenuItem; diff --git a/packages/ui/src/components/menu/mobile/MobileMenu.stories.tsx b/packages/ui/src/components/menu/mobile/MobileMenu.stories.tsx index 723ed60865..9f13f37fe0 100644 --- a/packages/ui/src/components/menu/mobile/MobileMenu.stories.tsx +++ b/packages/ui/src/components/menu/mobile/MobileMenu.stories.tsx @@ -25,6 +25,7 @@ import { IPlatformService, PlatformService } from '../../../services/platform/pl import type { IMenuButtonItem } from '../../../services/menu/menu'; import { MenuItemType, MenuPosition } from '../../../services/menu/menu'; import { ComponentManager } from '../../../common'; +import { ContextMenuPosition } from '../../../services/menu/types'; import { MobileMenu } from './MobileMenu'; const meta: Meta = { @@ -121,7 +122,7 @@ export const Playground = { return ( - + ); }, diff --git a/packages/ui/src/components/menu/mobile/MobileMenu.tsx b/packages/ui/src/components/menu/mobile/MobileMenu.tsx index 55b6bffae4..870076ab7f 100644 --- a/packages/ui/src/components/menu/mobile/MobileMenu.tsx +++ b/packages/ui/src/components/menu/mobile/MobileMenu.tsx @@ -14,15 +14,16 @@ * limitations under the License. */ -import React from 'react'; -import { makeArray, useDependency, useObservable } from '@univerjs/core'; +import React, { useMemo } from 'react'; +import { useDependency, useObservable } from '@univerjs/core'; import { clsx } from 'clsx'; import type { IBaseMenuProps } from '../desktop/Menu'; -import { IMenuService } from '../../../services/menu/menu.service'; import type { IDisplayMenuItem, IMenuItem, IValueOption, MenuItemDefaultValueType } from '../../../services/menu/menu'; import { MenuItemType } from '../../../services/menu/menu'; import { CustomLabel } from '../../custom-label'; +import type { IMenu2Schema } from '../../../services/menu/menu2.service'; +import { IMenu2Service } from '../../../services/menu/menu2.service'; import styles from './index.module.less'; /** @@ -30,14 +31,29 @@ import styles from './index.module.less'; */ export function MobileMenu(props: IBaseMenuProps) { const { menuType, onOptionSelect } = props; - const menuService = useDependency(IMenuService); + const menu2Service = useDependency(IMenu2Service); if (!menuType) { return null; } // There is no submenu on mobile devices, so if there are sub menu items, we should flat them. - const flattedMenuItems = makeArray(menuType).map(menuService.getMenuItems.bind(menuService)).flat(); + const flattedMenuItems = useMemo(() => { + const menuItems = menu2Service.getMenuByPositionKey(menuType); + // 递归把所有的子菜单项都展开 + + function flatMenuItems(items: IMenu2Schema[]): IMenu2Schema[] { + return items.reduce((acc, item) => { + if (item.children) { + return [...acc, ...flatMenuItems(item.children)]; + } + return [...acc, item]; + }, [] as IMenu2Schema[]); + } + + return flatMenuItems(menuItems); + }, [menuType]); + return (
- {flattedMenuItems.map((item) => ( + {flattedMenuItems.map((item) => item.item && ( ) => onOptionSelect?.({ value: '', label: item.id, ...object })} + key={item.key} + menuItem={item.item} + onClick={(object: Partial) => onOptionSelect?.({ value: '', label: item.key, ...object })} /> ))}
diff --git a/packages/ui/src/controllers/config.schema.ts b/packages/ui/src/controllers/config.schema.ts new file mode 100644 index 0000000000..6c20cf7620 --- /dev/null +++ b/packages/ui/src/controllers/config.schema.ts @@ -0,0 +1,34 @@ +/** + * 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 { DependencyOverride } from '@univerjs/core'; +import type { MenuConfig } from '../services/menu/menu'; +import type { IWorkbenchOptions } from './ui/ui.controller'; + +export const PLUGIN_CONFIG_KEY = 'ui.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverUIConfig extends IWorkbenchOptions { + /** Disable auto focus when Univer bootstraps. */ + disableAutoFocus?: true; + + override?: DependencyOverride; + + menu?: MenuConfig; +} + +export const defaultPluginConfig: IUniverUIConfig = {}; diff --git a/packages/ui/src/controllers/menus/menu.schema.ts b/packages/ui/src/controllers/menus/menu.schema.ts new file mode 100644 index 0000000000..d74e34a44e --- /dev/null +++ b/packages/ui/src/controllers/menus/menu.schema.ts @@ -0,0 +1,41 @@ +/** + * 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 { RedoCommand, UndoCommand } from '@univerjs/core'; +import type { IMenu2Item } from '../../services/menu/menu2.service'; +import { RibbonStartGroup } from '../../services/menu/types'; +import { ToggleShortcutPanelOperation } from '../../commands/operations/toggle-shortcut-panel.operation'; +import { ShortcutPanelMenuItemFactory } from '../shortcut-display/menu'; +import { RedoMenuItemFactory, UndoMenuItemFactory } from './menus'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.HISTORY]: { + [UndoCommand.id]: { + order: 0, + menuItemFactory: UndoMenuItemFactory, + }, + [RedoCommand.id]: { + order: 1, + menuItemFactory: RedoMenuItemFactory, + }, + }, + [RibbonStartGroup.OTHERS]: { + [ToggleShortcutPanelOperation.id]: { + order: 99, + menuItemFactory: ShortcutPanelMenuItemFactory, + }, + }, +}; diff --git a/packages/ui/src/controllers/shared-shortcut.controller.ts b/packages/ui/src/controllers/shared-shortcut.controller.ts index 660fad27c6..2c19c49570 100644 --- a/packages/ui/src/controllers/shared-shortcut.controller.ts +++ b/packages/ui/src/controllers/shared-shortcut.controller.ts @@ -15,16 +15,13 @@ */ import type { IContextService } from '@univerjs/core'; -import { Disposable, FOCUSING_UNIVER_EDITOR, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle, RedoCommand, UndoCommand } from '@univerjs/core'; +import { Disposable, FOCUSING_UNIVER_EDITOR, ICommandService, LifecycleStages, OnLifecycle, RedoCommand, UndoCommand } from '@univerjs/core'; import { CopyCommand, CutCommand, PasteCommand } from '../services/clipboard/clipboard.command'; -import { IMenuService } from '../services/menu/menu.service'; import { KeyCode, MetaKeys } from '../services/shortcut/keycode'; import type { IShortcutItem } from '../services/shortcut/shortcut.service'; import { IShortcutService } from '../services/shortcut/shortcut.service'; import { SetEditorResizeOperation } from '../commands/operations/editor/set-editor-resize.operation'; -import { RedoMenuItemFactory, UndoMenuItemFactory } from './menus/menus'; -import type { IUniverUIConfig } from './ui/ui.controller'; // Not that the clipboard shortcut items would only be invoked when the browser fully supports clipboard API. // If not, the corresponding shortcut would not be triggered and we will perform clipboard operations @@ -93,9 +90,6 @@ export const RedoShortcutItem: IShortcutItem = { @OnLifecycle(LifecycleStages.Ready, SharedController) export class SharedController extends Disposable { constructor( - private readonly _config: Pick | undefined, - @Inject(Injector) private readonly _injector: Injector, - @IMenuService private readonly _menuService: IMenuService, @IShortcutService private readonly _shortcutService: IShortcutService, @ICommandService private readonly _commandService: ICommandService ) { @@ -107,15 +101,6 @@ export class SharedController extends Disposable { initialize(): void { this._registerCommands(); this._registerShortcuts(); - this._registerMenus(); - } - - private _registerMenus(): void { - const menu = this._config?.menu ?? {}; - - [UndoMenuItemFactory, RedoMenuItemFactory].forEach((factory) => { - this.disposeWithMe(this._menuService.addMenuItem(this._injector.invoke(factory), menu)); - }); } private _registerCommands(): void { diff --git a/packages/ui/src/controllers/shortcut-display/shortcut-panel.controller.ts b/packages/ui/src/controllers/shortcut-display/shortcut-panel.controller.ts index 39f940a193..c71e7b0b1e 100644 --- a/packages/ui/src/controllers/shortcut-display/shortcut-panel.controller.ts +++ b/packages/ui/src/controllers/shortcut-display/shortcut-panel.controller.ts @@ -21,13 +21,11 @@ import { ToggleShortcutPanelOperation, } from '../../commands/operations/toggle-shortcut-panel.operation'; import { ComponentManager } from '../../common/component-manager'; -import { IMenuService } from '../../services/menu/menu.service'; import { ShortcutPanel } from '../../views/components/shortcut-panel/ShortcutPanel'; import type { IShortcutItem } from '../../services/shortcut/shortcut.service'; import { IShortcutService } from '../../services/shortcut/shortcut.service'; import { KeyCode, MetaKeys } from '../../services/shortcut/keycode'; -import type { IUniverUIConfig } from '../ui/ui.controller'; -import { ShortcutPanelMenuItemFactory } from './menu'; +import { IMenu2Service } from '../../services/menu/menu2.service'; const ToggleShortcutPanelShortcut: IShortcutItem = { id: ToggleShortcutPanelOperation.id, @@ -42,20 +40,14 @@ const ToggleShortcutPanelShortcut: IShortcutItem = { @OnLifecycle(LifecycleStages.Steady, ShortcutPanelController) export class ShortcutPanelController extends Disposable { constructor( - private readonly _config: Partial, @Inject(Injector) injector: Injector, @Inject(ComponentManager) componentManager: ComponentManager, @IShortcutService shortcutService: IShortcutService, - @IMenuService menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService commandService: ICommandService ) { super(); - const { menu = {} } = this._config; - - // register the menu item - this.disposeWithMe(menuService.addMenuItem(injector.invoke(ShortcutPanelMenuItemFactory), menu)); - // register the panel this.disposeWithMe(componentManager.register(ShortcutPanelComponentName, ShortcutPanel)); this.disposeWithMe(commandService.registerCommand(ToggleShortcutPanelOperation)); diff --git a/packages/ui/src/controllers/ui/ui-desktop.controller.tsx b/packages/ui/src/controllers/ui/ui-desktop.controller.tsx index 7c20559c9b..48886e0a22 100644 --- a/packages/ui/src/controllers/ui/ui-desktop.controller.tsx +++ b/packages/ui/src/controllers/ui/ui-desktop.controller.tsx @@ -15,7 +15,7 @@ */ import type { IDisposable } from '@univerjs/core'; -import { connectInjector, Disposable, IConfigService, Inject, Injector, isInternalEditorID, IUniverInstanceService, LifecycleService, LifecycleStages, OnLifecycle, Optional, toDisposable } from '@univerjs/core'; +import { connectInjector, Disposable, Inject, Injector, isInternalEditorID, IUniverInstanceService, LifecycleService, LifecycleStages, OnLifecycle, Optional, toDisposable } from '@univerjs/core'; import type { RenderUnit } from '@univerjs/engine-render'; import { IRenderManagerService } from '@univerjs/engine-render'; import { render as createRoot, unmount } from 'rc-util/lib/React/render'; @@ -26,7 +26,10 @@ import { BuiltInUIPart, IUIPartsService } from '../../services/parts/parts.servi import { CanvasPopup } from '../../views/components/popup/CanvasPopup'; import { FloatDom } from '../../views/components/dom/FloatDom'; import { DesktopWorkbench } from '../../views/workbench/Workbench'; -import { type IUniverUIConfig, type IWorkbenchOptions, UI_CONFIG_KEY } from './ui.controller'; +import type { IUniverUIConfig } from '../config.schema'; +import { IMenu2Service } from '../../services/menu/menu2.service'; +import { menuSchema } from '../menus/menu.schema'; +import type { IWorkbenchOptions } from './ui.controller'; const STEADY_TIMEOUT = 3000; @@ -40,17 +43,21 @@ export class DesktopUIController extends Disposable { @Inject(Injector) private readonly _injector: Injector, @Inject(LifecycleService) private readonly _lifecycleService: LifecycleService, @IUIPartsService private readonly _uiPartsService: IUIPartsService, - @IConfigService private readonly _configService: IConfigService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @Optional(ILayoutService) private readonly _layoutService?: ILayoutService ) { super(); - this._configService.setConfig(UI_CONFIG_KEY, this._config); this._initBuiltinComponents(); + this._initMenus(); Promise.resolve().then(() => this._bootstrapWorkbench()); } + private _initMenus(): void { + this._menu2Service.mergeMenu(menuSchema); + } + private _bootstrapWorkbench(): void { this.disposeWithMe(this._instanceSrv.unitDisposed$.subscribe(() => { clearTimeout(this._steadyTimeout); diff --git a/packages/ui/src/controllers/ui/ui-mobile.controller.tsx b/packages/ui/src/controllers/ui/ui-mobile.controller.tsx index 748f50ac4e..05b9c283a9 100644 --- a/packages/ui/src/controllers/ui/ui-mobile.controller.tsx +++ b/packages/ui/src/controllers/ui/ui-mobile.controller.tsx @@ -25,7 +25,10 @@ import { BuiltInUIPart, IUIPartsService } from '../../services/parts/parts.servi import { CanvasPopup } from '../../views/components/popup/CanvasPopup'; import { FloatDom } from '../../views/components/dom/FloatDom'; import { MobileApp } from '../../views/MobileApp'; -import type { IUIController, IUniverUIConfig, IWorkbenchOptions } from './ui.controller'; +import type { IUniverUIConfig } from '../config.schema'; +import { IMenu2Service } from '../../services/menu/menu2.service'; +import { menuSchema } from '../menus/menu.schema'; +import type { IUIController, IWorkbenchOptions } from './ui.controller'; const STEADY_TIMEOUT = 3000; @@ -37,6 +40,7 @@ export class MobileUIController extends Disposable implements IUIController { @Inject(Injector) private readonly _injector: Injector, @Inject(LifecycleService) private readonly _lifecycleService: LifecycleService, @IUIPartsService private readonly _uiPartsService: IUIPartsService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @Optional(ILayoutService) private readonly _layoutService?: ILayoutService ) { super(); @@ -46,6 +50,10 @@ export class MobileUIController extends Disposable implements IUIController { Promise.resolve().then(() => this._bootstrapWorkbench()); } + private _initMenus(): void { + this._menu2Service.mergeMenu(menuSchema); + } + private _bootstrapWorkbench(): void { this.disposeWithMe( bootstrap(this._injector, this._config, (canvasElement, containerElement) => { diff --git a/packages/ui/src/controllers/ui/ui.controller.ts b/packages/ui/src/controllers/ui/ui.controller.ts index 1bb53fd3b7..6a8ca4c9d6 100644 --- a/packages/ui/src/controllers/ui/ui.controller.ts +++ b/packages/ui/src/controllers/ui/ui.controller.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { type DependencyOverride, LifecycleStages, runOnLifecycle } from '@univerjs/core'; -import { createIdentifier } from '@univerjs/core'; -import type { MenuConfig } from '../../services/menu/menu'; +import { createIdentifier, LifecycleStages, runOnLifecycle } from '@univerjs/core'; export interface IWorkbenchOptions { container?: string | HTMLElement; @@ -30,14 +28,3 @@ export interface IWorkbenchOptions { export interface IUIController {} export const IUIController = createIdentifier('univer.ui.ui-controller'); runOnLifecycle(LifecycleStages.Ready, IUIController); - -export interface IUniverUIConfig extends IWorkbenchOptions { - /** Disable auto focus when Univer bootstraps. */ - disableAutoFocus?: true; - - override?: DependencyOverride; - - menu?: MenuConfig; -} - -export const UI_CONFIG_KEY = 'UNIVER_UI_CONFIG_KEY'; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index ca761d93bc..7f4c31cb8f 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -28,7 +28,8 @@ export { SharedController, UndoShortcutItem, } from './controllers/shared-shortcut.controller'; -export { UI_CONFIG_KEY, IUIController, type IWorkbenchOptions, type IUniverUIConfig } from './controllers/ui/ui.controller'; +export { IUIController, type IWorkbenchOptions } from './controllers/ui/ui.controller'; +export { type IUniverUIConfig } from './controllers/config.schema'; export { DesktopUIController } from './controllers/ui/ui-desktop.controller'; export { IUIPartsService, BuiltInUIPart, UIPartsService } from './services/parts/parts.service'; export { DesktopBeforeCloseService, IBeforeCloseService } from './services/before-close/before-close.service'; @@ -88,7 +89,7 @@ export { IEditorService, EditorService, Editor } from './services/editor/editor. export { TextEditor } from './components/editor/TextEditor'; export { RangeSelector } from './components/range-selector/RangeSelector'; export { ProgressBar } from './components/progress-bar/ProgressBar'; -export { type IMenuGroup, useSimpleToolbarGroups, useToolbarGroups, useToolbarItemStatus, useToolbarCollapseObserver } from './views/components/doc-bars/hook'; +export { type IMenuGroup, useSimpleToolbarGroups, useToolbarGroups, useToolbarItemStatus } from './views/components/ribbon/hook'; export { mergeMenuConfigs } from './common/menu-merge-configs'; export { ShortcutPanelController } from './controllers/shortcut-display/shortcut-panel.controller'; export { ShortcutPanelService } from './services/shortcut/shortcut-panel.service'; @@ -101,6 +102,21 @@ export { DesktopZenZoneService } from './services/zen-zone/desktop-zen-zone.serv export { DesktopLocalStorageService } from './services/local-storage/local-storage.service'; export { UNI_DISABLE_CHANGING_FOCUS_KEY } from './const'; +export { IMenu2Service, type IMenu2Item, Menu2Service } from './services/menu/menu2.service'; +export { + + Menu2Position, + RibbonPosition, + RibbonStartGroup, + RibbonInsertGroup, + RibbonFormulasGroup, + RibbonDataGroup, + RibbonViewGroup, + RibbonOthersGroup, + ContextMenuGroup, + ContextMenuPosition, +} from './services/menu/types'; + // #region - workbench components export { GlobalZone } from './views/components/global-zone/GlobalZone'; @@ -113,9 +129,9 @@ export { CanvasPopup } from './views/components/popup/CanvasPopup'; export { CanvasFloatDomService, type IFloatDomLayout } from './services/dom/canvas-dom-layer.service'; export { FloatDom } from './views/components/dom/FloatDom'; export { MobileContextMenu } from './views/components/context-menu/MobileContextMenu'; -export { Toolbar } from './views/components/doc-bars/Toolbar'; -export { ToolbarItem } from './views/components/doc-bars/ToolbarItem'; -export { ToolbarButton } from './views/components/doc-bars/Button/ToolbarButton'; +export { Ribbon } from './views/components/ribbon/Ribbon'; +export { ToolbarItem } from './views/components/ribbon/ToolbarItem'; +export { ToolbarButton } from './views/components/ribbon/Button/ToolbarButton'; // #endregion // #region - all commands diff --git a/packages/ui/src/locale/en-US.ts b/packages/ui/src/locale/en-US.ts index 888df95266..ed83806f5f 100644 --- a/packages/ui/src/locale/en-US.ts +++ b/packages/ui/src/locale/en-US.ts @@ -17,15 +17,15 @@ import type zhCN from './zh-CN'; const locale: typeof zhCN = { - uiToolbar: { + ribbon: { start: 'Start', insert: 'Insert', formulas: 'Formulas', data: 'Data', view: 'View', others: 'Others', + more: 'More', }, - more: 'More', fontFamily: { TimesNewRoman: 'Times New Roman', Arial: 'Arial', diff --git a/packages/ui/src/locale/ru-RU.ts b/packages/ui/src/locale/ru-RU.ts index ec844807c6..86918fb56d 100644 --- a/packages/ui/src/locale/ru-RU.ts +++ b/packages/ui/src/locale/ru-RU.ts @@ -17,15 +17,15 @@ import type zhCN from './zh-CN'; const locale: typeof zhCN = { - uiToolbar: { + ribbon: { start: 'Начало', insert: 'Вставка', formulas: 'Формулы', data: 'Данные', view: 'Вид', others: 'Другие', + more: 'Больше', }, - more: 'Больше', fontFamily: { TimesNewRoman: 'Times New Roman', Arial: 'Arial', diff --git a/packages/ui/src/locale/vi-VN.ts b/packages/ui/src/locale/vi-VN.ts index 7bffc38d94..5b138448d6 100644 --- a/packages/ui/src/locale/vi-VN.ts +++ b/packages/ui/src/locale/vi-VN.ts @@ -17,15 +17,15 @@ import type zhCN from './zh-CN'; const locale: typeof zhCN = { - uiToolbar: { + ribbon: { start: 'Bắt đầu', insert: 'Chèn', formulas: 'Công thức', data: 'Dữ liệu', view: 'Xem', others: 'Khác', + more: 'Thêm', }, - more: 'Thêm', fontFamily: { TimesNewRoman: 'Times New Roman', Arial: 'Arial', diff --git a/packages/ui/src/locale/zh-CN.ts b/packages/ui/src/locale/zh-CN.ts index d87e5208f2..c41acbde3c 100644 --- a/packages/ui/src/locale/zh-CN.ts +++ b/packages/ui/src/locale/zh-CN.ts @@ -15,15 +15,15 @@ */ const locale = { - uiToolbar: { + ribbon: { start: '开始', insert: '插入', formulas: '公式', data: '数据', view: '视图', others: '其他', + more: '更多', }, - more: '更多', fontFamily: { TimesNewRoman: 'Times New Roman', Arial: 'Arial', diff --git a/packages/ui/src/locale/zh-TW.ts b/packages/ui/src/locale/zh-TW.ts index c6c213e2f5..9d9434ecaf 100644 --- a/packages/ui/src/locale/zh-TW.ts +++ b/packages/ui/src/locale/zh-TW.ts @@ -17,15 +17,15 @@ import type zhCN from './zh-CN'; const locale: typeof zhCN = { - uiToolbar: { + ribbon: { start: '開始', insert: '插入', formulas: '公式', data: '資料', view: '視圖', others: '其他', + more: '更多', }, - more: '更多', fontFamily: { TimesNewRoman: 'Times New Roman', Arial: 'Arial', diff --git a/packages/ui/src/mobile-ui-plugin.ts b/packages/ui/src/mobile-ui-plugin.ts index 0be879d811..15342d2446 100644 --- a/packages/ui/src/mobile-ui-plugin.ts +++ b/packages/ui/src/mobile-ui-plugin.ts @@ -24,7 +24,7 @@ import { ComponentManager } from './common/component-manager'; import { ZIndexManager } from './common/z-index-manager'; import { ErrorController } from './controllers/error/error.controller'; import { SharedController } from './controllers/shared-shortcut.controller'; -import type { IUniverUIConfig } from './controllers/ui/ui.controller'; +import type { IUniverUIConfig } from './controllers/config.schema'; import { IUIController } from './controllers/ui/ui.controller'; import { DesktopBeforeCloseService, IBeforeCloseService } from './services/before-close/before-close.service'; import { BrowserClipboardService, IClipboardInterfaceService } from './services/clipboard/clipboard-interface.service'; @@ -53,6 +53,7 @@ import { IProgressService, ProgressService } from './services/progress/progress. import { IUIPartsService, UIPartsService } from './services/parts/parts.service'; import { CanvasFloatDomService } from './services/dom/canvas-dom-layer.service'; import { MobileUIController } from './controllers/ui/ui-mobile.controller'; +import { IMenu2Service, Menu2Service } from './services/menu/menu2.service'; export const UNIVER_MOBILE_UI_PLUGIN_NAME = 'UNIVER_MOBILE_UI_PLUGIN'; @@ -64,7 +65,7 @@ export class UniverMobileUIPlugin extends Plugin { static override pluginName = UNIVER_MOBILE_UI_PLUGIN_NAME; constructor( - private _config: IUniverUIConfig, + private readonly _config: IUniverUIConfig, @Inject(Injector) protected readonly _injector: Injector ) { super(); @@ -82,6 +83,7 @@ export class UniverMobileUIPlugin extends Plugin { [IShortcutService, { useClass: ShortcutService }], [IPlatformService, { useClass: PlatformService }], [IMenuService, { useClass: MenuService }], + [IMenu2Service, { useClass: Menu2Service }], [IContextMenuService, { useClass: ContextMenuService }], [IClipboardInterfaceService, { useClass: BrowserClipboardService, lazy: true }], [INotificationService, { useClass: DesktopNotificationService, lazy: true }], @@ -106,12 +108,7 @@ export class UniverMobileUIPlugin extends Plugin { deps: [Injector], }, ], - [ - SharedController, - { - useFactory: () => this._injector.createInstance(SharedController, this._config), - }, - ], + [SharedController], [ErrorController], ], this._config.override); diff --git a/packages/ui/src/services/menu/menu.service.ts b/packages/ui/src/services/menu/menu.service.ts index 0ea063495b..2835ddd5a4 100644 --- a/packages/ui/src/services/menu/menu.service.ts +++ b/packages/ui/src/services/menu/menu.service.ts @@ -21,12 +21,17 @@ import { BehaviorSubject } from 'rxjs'; import { IShortcutService } from '../shortcut/shortcut.service'; import { mergeMenuConfigs } from '../../common/menu-merge-configs'; -import type { IDisplayMenuItem, IMenuItem, MenuConfig, MenuPosition } from './menu'; +import type { IDisplayMenuItem, IMenuItem, MenuConfig } from './menu'; +import { MenuPosition } from './menu'; +import { IMenu2Service } from './menu2.service'; +import { ContextMenuGroup, RibbonOthersGroup } from './types'; +/** @deprecated */ export const IMenuService = createIdentifier('univer.menu-service'); /** * Breaking changes to IMenuService are expected in the next version. Use with caution. by @jikkai + * @deprecated */ export interface IMenuService { menuChanged$: Observable; @@ -44,6 +49,7 @@ export interface IMenuService { getMenuItem(id: string): IMenuItem | null; } +/** @deprecated */ export class MenuService extends Disposable implements IMenuService { /** @deprecated */ private readonly _menuItemMap = new Map(); @@ -58,7 +64,10 @@ export class MenuService extends Disposable implements IMenuService { menuChanged$: Observable = this._menuChanged$.asObservable(); - constructor(@IShortcutService private readonly _shortcutService: IShortcutService) { + constructor( + @IShortcutService private readonly _shortcutService: IShortcutService, + @IMenu2Service private readonly _menu2Service: IMenu2Service + ) { super(); } @@ -83,6 +92,45 @@ export class MenuService extends Disposable implements IMenuService { this._appendMenuToPosition(item, item.positions); } + // TODO: Compatible with old menu service + [ + MenuPosition.TOOLBAR_START, + MenuPosition.TOOLBAR_INSERT, + MenuPosition.TOOLBAR_FORMULAS, + MenuPosition.TOOLBAR_DATA, + MenuPosition.TOOLBAR_VIEW, + MenuPosition.TOOLBAR_OTHERS, + MenuPosition.CONTEXT_MENU, + ].forEach((position) => { + if (position !== MenuPosition.CONTEXT_MENU) { + const menus = this.getMenuItems(position); + menus.forEach((menu) => { + this._menu2Service.mergeMenu({ + [position]: { + [menu.group ?? RibbonOthersGroup.OTHERS]: { + [menu.id]: { + menuItemFactory: () => menu, + }, + }, + }, + }); + }); + } else { + const menus = this.getMenuItems(position); + menus.forEach((menu) => { + this._menu2Service.mergeMenu({ + [position]: { + [menu.group ?? ContextMenuGroup.OTHERS]: { + [menu.id]: { + menuItemFactory: () => menu, + }, + }, + }, + }); + }); + } + }); + this._menuChanged$.next(); return toDisposable(() => { diff --git a/packages/ui/src/services/menu/menu.ts b/packages/ui/src/services/menu/menu.ts index d76065fc89..5b6b67b110 100644 --- a/packages/ui/src/services/menu/menu.ts +++ b/packages/ui/src/services/menu/menu.ts @@ -16,21 +16,31 @@ import type { IAccessor } from '@univerjs/core'; import type { Observable } from 'rxjs'; +import { ContextMenuPosition, RibbonPosition } from './types'; export type OneOrMany = T | T[]; +/** @deprecated */ export enum MenuPosition { VOID = 'void', - TOOLBAR_START = 'uiToolbar.start', - TOOLBAR_INSERT = 'uiToolbar.insert', - TOOLBAR_FORMULAS = 'uiToolbar.formulas', - TOOLBAR_DATA = 'uiToolbar.data', - TOOLBAR_VIEW = 'uiToolbar.view', - TOOLBAR_OTHERS = 'uiToolbar.others', - CONTEXT_MENU = 'contextMenu', + // TOOLBAR_START = 'uiToolbar.start', + // TOOLBAR_INSERT = 'uiToolbar.insert', + // TOOLBAR_FORMULAS = 'uiToolbar.formulas', + // TOOLBAR_DATA = 'uiToolbar.data', + // TOOLBAR_VIEW = 'uiToolbar.view', + // TOOLBAR_OTHERS = 'uiToolbar.others', + // CONTEXT_MENU = 'contextMenu', + TOOLBAR_START = RibbonPosition.START, + TOOLBAR_INSERT = RibbonPosition.INSERT, + TOOLBAR_FORMULAS = RibbonPosition.FORMULAS, + TOOLBAR_DATA = RibbonPosition.DATA, + TOOLBAR_VIEW = RibbonPosition.VIEW, + TOOLBAR_OTHERS = RibbonPosition.OTHERS, + CONTEXT_MENU = ContextMenuPosition.MAIN_AREA, FOOTER = 'footer', } +/** @deprecated */ export enum MenuGroup { TOOLBAR_HISTORY, TOOLBAR_FORMAT, @@ -156,7 +166,7 @@ export function isMenuSelectorItem(v: IMenuI export type MenuItemDefaultValueType = string | number | undefined; -export type IMenuItem = IMenuButtonItem | IMenuSelectorItem; +export type IMenuItem = IMenuButtonItem | IMenuSelectorItem; export type IDisplayMenuItem = T & { shortcut?: string; diff --git a/packages/ui/src/services/menu/menu2.service.ts b/packages/ui/src/services/menu/menu2.service.ts new file mode 100644 index 0000000000..00797138a4 --- /dev/null +++ b/packages/ui/src/services/menu/menu2.service.ts @@ -0,0 +1,280 @@ +/** + * 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 { IAccessor, Nullable } from '@univerjs/core'; +import { createIdentifier, Disposable, IConfigService, Inject, Injector, Tools } from '@univerjs/core'; +import type { Observable } from 'rxjs'; +import { Subject } from 'rxjs'; +import type { IMenuItem } from '../menu/menu'; +import { mergeMenuConfigs } from '../../common/menu-merge-configs'; +import { ContextMenuGroup, ContextMenuPosition, Menu2Position, RibbonDataGroup, RibbonFormulasGroup, RibbonInsertGroup, RibbonOthersGroup, RibbonPosition, RibbonStartGroup, RibbonViewGroup } from './types'; + +export const IMenu2Service = createIdentifier('univer.menu2-service'); + +export interface IMenu2Schema { + key: string; + order: number; + item?: IMenuItem; + children?: IMenu2Schema[]; +} + +export interface IMenu2Service { + readonly menuChanged$: Observable; + + mergeMenu(source: IMenu2Item, target?: IMenu2Item): void; + + appendRootMenu(source: IMenu2Item): void; + + getMenuByPositionKey(position: string): IMenu2Schema[]; +} + +export type IMenu2Item = { + order?: number; + menuItemFactory?: (accessor: IAccessor) => IMenuItem; +} | { + [key: string]: IMenu2Item; +}; + +export class Menu2Service extends Disposable implements IMenu2Service { + readonly menuChanged$ = new Subject(); + + private _menu: IMenu2Item = { + [Menu2Position.RIBBON]: { + [RibbonPosition.START]: { + order: 0, + [RibbonStartGroup.HISTORY]: { + order: 0, + }, + [RibbonStartGroup.FORMAT]: { + order: 1, + }, + [RibbonStartGroup.LAYOUT]: { + order: 2, + }, + [RibbonStartGroup.FORMULAS_INSERT]: { + order: 3, + }, + [RibbonStartGroup.FORMULAS_VIEW]: { + order: 4, + }, + [RibbonStartGroup.FILE]: { + order: 5, + }, + [RibbonStartGroup.OTHERS]: { + order: 6, + }, + }, + [RibbonPosition.INSERT]: { + order: 1, + [RibbonInsertGroup.OTHERS]: { + order: 0, + }, + }, + [RibbonPosition.FORMULAS]: { + order: 2, + [RibbonFormulasGroup.OTHERS]: { + order: 0, + }, + }, + [RibbonPosition.DATA]: { + order: 3, + [RibbonDataGroup.OTHERS]: { + order: 0, + }, + }, + [RibbonPosition.VIEW]: { + order: 4, + [RibbonViewGroup.OTHERS]: { + order: 0, + }, + }, + [RibbonPosition.OTHERS]: { + order: 5, + [RibbonOthersGroup.OTHERS]: { + order: 0, + }, + }, + }, + [Menu2Position.CONTEXT_MENU]: { + [ContextMenuPosition.MAIN_AREA]: { + order: 0, + [ContextMenuGroup.FORMAT]: { + order: 0, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.COL_HEADER]: { + order: 1, + [ContextMenuGroup.FORMAT]: { + order: 0, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.ROW_HEADER]: { + order: 2, + [ContextMenuGroup.FORMAT]: { + order: 0, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.FOOTER_TABS]: { + order: 3, + [ContextMenuGroup.FORMAT]: { + order: 0, + }, + [ContextMenuGroup.LAYOUT]: { + order: 1, + }, + [ContextMenuGroup.DATA]: { + order: 2, + }, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + [ContextMenuPosition.FOOTER_MENU]: { + order: 4, + [ContextMenuGroup.OTHERS]: { + order: 3, + }, + }, + }, + }; + + constructor( + @Inject(Injector) private readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService + ) { + super(); + } + + override dispose(): void { + this.menuChanged$.complete(); + } + + /** + * Merge source menu to target menu recursively + * @param source + * @param target default is root menu + */ + mergeMenu(source: IMenu2Item, target?: IMenu2Item): void { + const _target = target ?? this._menu; + + for (const [key, value] of Object.entries(_target)) { + if (key in source) { + const _key = key as keyof IMenu2Item; + Tools.deepMerge(_target[_key], source[_key]); + + this.menuChanged$.next(); + } else { + this.mergeMenu(source, value); + } + } + } + + appendRootMenu(source: IMenu2Item): void { + Tools.deepMerge(this._menu, source); + this.menuChanged$.next(); + } + + private _buildMenuSchema(data: IMenu2Item): IMenu2Schema[] { + const result: IMenu2Schema[] = []; + + for (const [key, value] of Object.entries(data)) { + const menuItem: Partial = { + key, + order: value.order, + }; + + if (value.menuItemFactory) { + const item: IMenuItem = this._injector.invoke(value.menuItemFactory); + + if (item) { + const menuItemConfig: Nullable = this._configService.getConfig('menu'); + + if (menuItemConfig && item.id in menuItemConfig) { + const _key = item.id as keyof IMenuItem; + menuItem.item = mergeMenuConfigs(item, menuItemConfig[_key] as any); + } else { + menuItem.item = item; + } + } + } + + const children = this._buildMenuSchema(value); + if (children.length > 0) { + menuItem.children = children.sort((a, b) => a.order - b.order); + } + + if (menuItem.item || menuItem.children) { + result.push(menuItem as IMenu2Schema); // 使用类型断言补充缺失字段 + } + } + + return result; + } + + /** + * Get menu schema by position key + * @param key + * @returns Menu schema array or empty array if not found + */ + getMenuByPositionKey(key: string): IMenu2Schema[] { + const findKey = (obj: any): any => { + if (key in obj) { + return this._buildMenuSchema(obj[key]); + } + + for (const k in obj) { + if (k === key) { + return this._buildMenuSchema(obj[k]); + } + if (typeof obj[k] === 'object') { + const result = findKey(obj[k]); + if (result) { + return result; + } + } + } + }; + + return findKey(this._menu); + } +} diff --git a/packages/ui/src/services/menu/types.ts b/packages/ui/src/services/menu/types.ts new file mode 100644 index 0000000000..8507802a1b --- /dev/null +++ b/packages/ui/src/services/menu/types.ts @@ -0,0 +1,74 @@ +/** + * 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. + */ + +export enum Menu2Position { + RIBBON = 'ribbon', + CONTEXT_MENU = 'contextMenu', +} + +export enum RibbonPosition { + START = 'ribbon.start', + INSERT = 'ribbon.insert', + FORMULAS = 'ribbon.formulas', + DATA = 'ribbon.data', + VIEW = 'ribbon.view', + OTHERS = 'ribbon.others', +} + +export enum RibbonStartGroup { + HISTORY = 'ribbon.start.history', + FORMAT = 'ribbon.start.format', + LAYOUT = 'ribbon.start.layout', + FORMULAS_INSERT = 'ribbon.start.insert', + FORMULAS_VIEW = 'ribbon.start.view', + FILE = 'ribbon.start.file', + OTHERS = 'ribbon.start.others', +} + +export enum RibbonInsertGroup { + OTHERS = 'ribbon.insert.others', +} + +export enum RibbonFormulasGroup { + OTHERS = 'ribbon.formulas.others', +} + +export enum RibbonDataGroup { + OTHERS = 'ribbon.data.others', +} + +export enum RibbonViewGroup { + OTHERS = 'ribbon.view.others', +} + +export enum RibbonOthersGroup { + OTHERS = 'ribbon.others.others', +} + +export enum ContextMenuPosition { + MAIN_AREA = 'contextMenu.mainArea', + COL_HEADER = 'contextMenu.colHeader', + ROW_HEADER = 'contextMenu.rowHeader', + FOOTER_TABS = 'contextMenu.footerTabs', + FOOTER_MENU = 'contextMenu.footerMenu', +} + +export enum ContextMenuGroup { + FORMAT = 'contextMenu.format', + LAYOUT = 'contextMenu.layout', + DATA = 'contextMenu.data', + OTHERS = 'contextMenu.others', +} diff --git a/packages/ui/src/ui-plugin.ts b/packages/ui/src/ui-plugin.ts index e37aa6f126..3c80eeb0ba 100644 --- a/packages/ui/src/ui-plugin.ts +++ b/packages/ui/src/ui-plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DependentOn, IContextService, ILocalStorageService, Inject, Injector, mergeOverrideWithDependencies, Plugin, Tools } from '@univerjs/core'; +import { DependentOn, IConfigService, IContextService, ILocalStorageService, Inject, Injector, mergeOverrideWithDependencies, Plugin } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; @@ -26,7 +26,6 @@ import { ZIndexManager } from './common/z-index-manager'; import { ErrorController } from './controllers/error/error.controller'; import { SharedController } from './controllers/shared-shortcut.controller'; import { ShortcutPanelController } from './controllers/shortcut-display/shortcut-panel.controller'; -import type { IUniverUIConfig } from './controllers/ui/ui.controller'; import { IUIController } from './controllers/ui/ui.controller'; import { DesktopUIController } from './controllers/ui/ui-desktop.controller'; import { DesktopBeforeCloseService, IBeforeCloseService } from './services/before-close/before-close.service'; @@ -55,6 +54,9 @@ import { IRangeSelectorService, RangeSelectorService } from './services/range-se import { IProgressService, ProgressService } from './services/progress/progress.service'; import { IUIPartsService, UIPartsService } from './services/parts/parts.service'; import { CanvasFloatDomService } from './services/dom/canvas-dom-layer.service'; +import { IMenu2Service, Menu2Service } from './services/menu/menu2.service'; +import type { IUniverUIConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; export const UNIVER_UI_PLUGIN_NAME = 'UNIVER_UI_PLUGIN'; @@ -68,16 +70,22 @@ export class UniverUIPlugin extends Plugin { static override pluginName = UNIVER_UI_PLUGIN_NAME; constructor( - private _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @IContextService private readonly _contextService: IContextService, - @Inject(Injector) protected readonly _injector: Injector + @Inject(Injector) protected readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, this._config); - if (this._config.disableAutoFocus) { + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (rest.disableAutoFocus) { this._contextService.setContextValue(DISABLE_AUTO_FOCUS_KEY, true); } + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { @@ -91,6 +99,7 @@ export class UniverUIPlugin extends Plugin { [IShortcutService, { useClass: ShortcutService }], [IPlatformService, { useClass: PlatformService }], [IMenuService, { useClass: MenuService }], + [IMenu2Service, { useClass: Menu2Service }], [IContextMenuService, { useClass: ContextMenuService }], [IClipboardInterfaceService, { useClass: BrowserClipboardService, lazy: true }], [INotificationService, { useClass: DesktopNotificationService, lazy: true }], @@ -112,13 +121,9 @@ export class UniverUIPlugin extends Plugin { deps: [Injector], }, ], - [SharedController, { - useFactory: () => this._injector.createInstance(SharedController, this._config), - }], + [SharedController], [ErrorController], - [ShortcutPanelController, { - useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config), - }], + [ShortcutPanelController], ], this._config.override); dependencies.forEach((dependency) => this._injector.add(dependency)); } diff --git a/packages/ui/src/views/components/context-menu/ContextMenu.tsx b/packages/ui/src/views/components/context-menu/ContextMenu.tsx index 9da0fc0806..a7376acbe4 100644 --- a/packages/ui/src/views/components/context-menu/ContextMenu.tsx +++ b/packages/ui/src/views/components/context-menu/ContextMenu.tsx @@ -76,7 +76,7 @@ export function DesktopContextMenu() {
{menuType && ( { const { label: id, commandId, value } = params; commandService && commandService.executeCommand(commandId ?? id as string, { value }); diff --git a/packages/ui/src/views/components/context-menu/MobileContextMenu.tsx b/packages/ui/src/views/components/context-menu/MobileContextMenu.tsx index 537bed0a29..bafdeaccae 100644 --- a/packages/ui/src/views/components/context-menu/MobileContextMenu.tsx +++ b/packages/ui/src/views/components/context-menu/MobileContextMenu.tsx @@ -68,7 +68,7 @@ export function MobileContextMenu() { {menuType && ( // TODO@wzhudev: change to mobile menu { const { label: id, value, commandId } = params; commandService && commandService.executeCommand(commandId ?? id as string, { value }); diff --git a/packages/ui/src/views/components/doc-bars/Toolbar.tsx b/packages/ui/src/views/components/doc-bars/Toolbar.tsx deleted file mode 100644 index 2c6940fca0..0000000000 --- a/packages/ui/src/views/components/doc-bars/Toolbar.tsx +++ /dev/null @@ -1,166 +0,0 @@ -/** - * 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 { LocaleService, useDependency } from '@univerjs/core'; -import { Dropdown, Tooltip } from '@univerjs/design'; -import { MoreFunctionSingle } from '@univerjs/icons'; -import clsx from 'clsx'; -import type { ComponentType } from 'react'; -import React, { useMemo } from 'react'; - -import { MenuPosition } from '../../../services/menu/menu'; -import { ComponentContainer } from '../ComponentContainer'; -import { ToolbarButton } from './Button/ToolbarButton'; -import styles from './index.module.less'; -import { ToolbarItem } from './ToolbarItem'; -import { useToolbarCollapseObserver, useToolbarGroups } from './hook'; - -const MENU_POSITIONS = [ - MenuPosition.TOOLBAR_START, - MenuPosition.TOOLBAR_INSERT, - MenuPosition.TOOLBAR_FORMULAS, - MenuPosition.TOOLBAR_DATA, - MenuPosition.TOOLBAR_VIEW, - MenuPosition.TOOLBAR_OTHERS, -]; - -export interface IToolbarProps { - headerMenuComponents?: Set; -} - -/** - * Univer's built in toolbar component. - */ -export function Toolbar(props: IToolbarProps) { - const { headerMenuComponents } = props; - const localeService = useDependency(LocaleService); - - const { setCategory, visibleItems, groups, category, groupsByKey } = useToolbarGroups(MENU_POSITIONS); - const { toolbarItemRefs, toolbarRef, collapsedId } = useToolbarCollapseObserver(visibleItems); - - // Should the header when there is at least one header menu components or menu groups. - const hasHeaderMenu = useMemo(() => (headerMenuComponents && headerMenuComponents.size > 0) || groups.length > 1, [headerMenuComponents, groups]); - - return ( - <> - {hasHeaderMenu - ? ( -
-
- {groups.length > 1 && - groups.map((item, index) => ( - { - setCategory(item.name); - }} - > - {localeService.t(item.name)} - - ))} -
-
- -
-
- ) - : null} - -
-
- {Object.entries(groupsByKey) - .filter(([_, item]) => { - const count = item.filter((subItem) => !collapsedId.includes(subItem.id)).length; - return count; - }) - .map(([key, item]) => ( -
- {item.map( - (subItem) => - !collapsedId.includes(subItem.id) && ( - - ) - )} -
- ))} - - {collapsedId.length > 0 && ( - -
- - {Object.entries(groupsByKey).map(([key, item]) => ( -
- {item.map( - (subItem) => - collapsedId.includes(subItem.id) && ( - - ) - )} -
- ))} -
- )} - > - - - - - - -
- - )} -
- - - {/* fake toolbar for calculating overflow width */} -
- {Object.entries(groupsByKey).map(([key, item]) => ( -
- {item.map((subItem) => ( - // TODO@jikkai: use fake ToolbarItem (no business logic) to improve performance. - { - toolbarItemRefs.current[subItem.id] = { - el: ref?.nativeElement as HTMLDivElement, - key: subItem.id, - }; - }} - {...subItem} - /> - ))} -
- ))} -
- - ); -} diff --git a/packages/ui/src/views/components/doc-bars/Button/ToolbarButton.tsx b/packages/ui/src/views/components/ribbon/Button/ToolbarButton.tsx similarity index 100% rename from packages/ui/src/views/components/doc-bars/Button/ToolbarButton.tsx rename to packages/ui/src/views/components/ribbon/Button/ToolbarButton.tsx diff --git a/packages/ui/src/views/components/doc-bars/Button/index.module.less b/packages/ui/src/views/components/ribbon/Button/index.module.less similarity index 100% rename from packages/ui/src/views/components/doc-bars/Button/index.module.less rename to packages/ui/src/views/components/ribbon/Button/index.module.less diff --git a/packages/ui/src/views/components/ribbon/Ribbon.tsx b/packages/ui/src/views/components/ribbon/Ribbon.tsx new file mode 100644 index 0000000000..ed77517ec5 --- /dev/null +++ b/packages/ui/src/views/components/ribbon/Ribbon.tsx @@ -0,0 +1,225 @@ +/** + * 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 { LocaleService, useDependency } from '@univerjs/core'; +import type { ComponentType } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import clsx from 'clsx'; +import { MoreFunctionSingle } from '@univerjs/icons'; + +import type { IMenu2Schema } from '../../../services/menu/menu2.service'; +import { IMenu2Service } from '../../../services/menu/menu2.service'; +import { ComponentContainer } from '../ComponentContainer'; +import { ToolbarButton } from '../ribbon/Button/ToolbarButton'; +import { Menu2Position, RibbonPosition } from '../../../services/menu/types'; +import { ToolbarItem } from './ToolbarItem'; +import { DropdownWrapper, TooltipWrapper } from './TooltipButtonWrapper'; +import styles from './index.module.less'; + +interface IRibbonProps { + headerMenuComponents?: Set; +} + +export function Ribbon(props: IRibbonProps) { + const { headerMenuComponents } = props; + + const menu2Service = useDependency(IMenu2Service); + const localeService = useDependency(LocaleService); + + const toolbarRef = useRef(null); + const toolbarItemRefs = useRef>({}); + + const [ribbon, setRibbon] = useState([]); + const [category, setCategory] = useState(RibbonPosition.START); + const [collapsedIds, setCollapsedIds] = useState([]); + + // subscribe to menu changes + useEffect(() => { + function getRibbon(): void { + const ribbon = menu2Service.getMenuByPositionKey(Menu2Position.RIBBON); + setRibbon(ribbon); + } + getRibbon(); + + const subscription = menu2Service.menuChanged$.subscribe(getRibbon); + + return () => { + subscription.unsubscribe(); + }; + }, [menu2Service]); + + // resize observer + useEffect(() => { + const observer = new ResizeObserver((entries) => { + const toolbar = entries[0].target; + const toolbarWidth = toolbar.clientWidth; + const toolbarItems = Object.values(toolbarItemRefs.current); + const collapsedIds: string[] = []; + let totalWidth = 58; + + for (const { el, key } of toolbarItems) { + if (!el) continue; + + totalWidth += el.clientWidth + 8; + if (totalWidth > toolbarWidth) { + collapsedIds.push(key); + } + } + + setCollapsedIds(collapsedIds); + }); + + if (toolbarRef.current) { + observer.observe(toolbarRef.current); + } + + return () => { + observer.disconnect(); + }; + }, [ribbon]); + + // Should the header when there is at least one header menu components or menu groups. + const hasHeaderMenu = useMemo(() => (headerMenuComponents && headerMenuComponents.size > 0) || ribbon.length > 1, [headerMenuComponents, ribbon]); + + const activeGroup = useMemo(() => { + const allGroups = ribbon.find((group) => group.key === category)?.children ?? []; + const visibleGroups: IMenu2Schema[] = []; + const hiddenGroups: IMenu2Schema[] = []; + + for (const item of allGroups) { + if (item.children) { + const visibleChildren = item.children.filter((child) => !collapsedIds.includes(child.key)); + visibleGroups.push({ ...item, children: visibleChildren }); + + if (visibleChildren.length < item.children.length) { + hiddenGroups.push({ ...item, children: item.children.filter((child) => collapsedIds.includes(child.key)) }); + } + } + } + + return { + allGroups, + visibleGroups, + hiddenGroups, + }; + }, [ribbon, category, collapsedIds]); + + return ( + <> + {/* header */} + {hasHeaderMenu && ( +
+
+ {ribbon.length > 1 && ribbon.map((group) => ( + { + setCategory(group.key); + }} + > + {localeService.t(group.key)} + + ))} +
+
+ +
+
+ )} + +
+
+ {activeGroup.visibleGroups.map((groupItem) => (groupItem.children?.length || groupItem.item) && ( +
+ {groupItem.children + ? groupItem.children?.map((child) => ( + child.item && + )) + : ( + groupItem.item && + )} +
+ ))} + + {/* overflow menu items */} + {collapsedIds.length > 0 && ( + + + {activeGroup.hiddenGroups.map((groupItem) => ( +
+ {groupItem.children + ? groupItem.children?.map((child) => ( + child.item && + )) + : ( + groupItem.item && + )} +
+ ))} +
+ )} + > + + + + + + )} + +
+ + {/* fake toolbar for calculating overflow width */} +
+ {activeGroup.allGroups.map((groupItem) => ( +
+ {groupItem.children?.map((child) => ( + child.item && ( + { + toolbarItemRefs.current[child.key] = { + el: ref?.nativeElement as HTMLDivElement, + key: child.key, + }; + }} + {...child.item} + /> + ) + ))} +
+ ))} +
+ + ); +} diff --git a/packages/ui/src/views/components/doc-bars/ToolbarItem.tsx b/packages/ui/src/views/components/ribbon/ToolbarItem.tsx similarity index 73% rename from packages/ui/src/views/components/doc-bars/ToolbarItem.tsx rename to packages/ui/src/views/components/ribbon/ToolbarItem.tsx index 53555d117e..9499436475 100644 --- a/packages/ui/src/views/components/doc-bars/ToolbarItem.tsx +++ b/packages/ui/src/views/components/ribbon/ToolbarItem.tsx @@ -15,13 +15,13 @@ */ import { ICommandService, LocaleService, useDependency } from '@univerjs/core'; -import { Dropdown, Tooltip } from '@univerjs/design'; import { MoreDownSingle } from '@univerjs/icons'; +import type { IDropdownProps } from '@univerjs/design'; import type { Ref } from 'react'; -import React, { forwardRef, useMemo, useState } from 'react'; +import React, { forwardRef, useMemo } from 'react'; import { isObservable, Observable } from 'rxjs'; - import clsx from 'clsx'; + import { ComponentManager } from '../../../common/component-manager'; import { CustomLabel } from '../../../components/custom-label/CustomLabel'; import { useObservable } from '../../../components/hooks/observable'; @@ -30,37 +30,25 @@ import type { IDisplayMenuItem, IMenuItem, IMenuSelectorItem, IValueOption } fro import { MenuItemType } from '../../../services/menu/menu'; import { ILayoutService } from '../../../services/layout/layout.service'; import { ToolbarButton } from './Button/ToolbarButton'; -import styles from './index.module.less'; import { useToolbarItemStatus } from './hook'; +import { DropdownWrapper, TooltipWrapper } from './TooltipButtonWrapper'; +import styles from './index.module.less'; + +export const ToolbarItem = forwardRef((props: IDisplayMenuItem & { align?: IDropdownProps['align'] }, ref: Ref) => { + const { align } = props; -export const ToolbarItem = forwardRef((props: IDisplayMenuItem, ref: Ref) => { const localeService = useDependency(LocaleService); const commandService = useDependency(ICommandService); const layoutService = useDependency(ILayoutService); const componentManager = useDependency(ComponentManager); - const [tooltipVisible, setTooltipVisible] = useState(false); - const [dropdownVisible, setDropdownVisible] = useState(false); - const { value, hidden, disabled, activated } = useToolbarItemStatus(props); - const executeCommand = (commandId: string, params?: Record) => { + const executeCommand = (commandId: string, params?: Record) => { layoutService.focus(); commandService.executeCommand(commandId, params); }; - function handleVisibleChange(visible: boolean) { - setTooltipVisible(visible); - } - - function handleDropdownVisibleChange(visible: boolean) { - setDropdownVisible(visible); - - if (!visible) { - setTooltipVisible(false); - } - } - const { tooltip, shortcut, icon, title, label, id, commandId } = props; const tooltipTitle = localeService.t(tooltip ?? '') + (shortcut ? ` (${shortcut})` : ''); @@ -119,9 +107,8 @@ export const ToolbarItem = forwardRef((props: IDisplayMenuItem, ref: } } - return menuType === MenuItemType.BUTTON_SELECTOR - ? ( - // Button Selector + if (menuType === MenuItemType.BUTTON_SELECTOR) { + return (
, ref: onChange={handleSelectionsValueChange} />
- + )} - onVisibleChange={handleDropdownVisibleChange} - disabled={disabled} >
, ref: [styles.toolbarItemSelectButtonArrowActivated]: activated, })} data-disabled={disabled} - onClick={(e) => e.stopPropagation()} > - +
- - + - ) - : ( - // Selector - + )} - onVisibleChange={handleDropdownVisibleChange} - disabled={disabled} >
e.stopPropagation()} > , ref:
- + ); + } } function renderButtonType() { const isCustomComponent = componentManager.get(typeof label === 'string' ? label : label?.name ?? ''); return ( - executeCommand(props.commandId ?? props.id)} - onDoubleClick={() => props.subId && executeCommand(props.subId)} - > - {isCustomComponent - ? ( - - ) - : ( - - )} - + + executeCommand(props.commandId ?? props.id)} + onDoubleClick={() => props.subId && executeCommand(props.subId)} + > + {isCustomComponent + ? ( + + ) + : ( + + )} + + ); } @@ -228,20 +226,9 @@ export const ToolbarItem = forwardRef((props: IDisplayMenuItem, ref: } } - // ref component - return hidden - ? null - : ( - -
- {renderItem()} -
-
- ); + return !hidden && ( + + {renderItem()} + + ); }); diff --git a/packages/ui/src/views/components/ribbon/TooltipButtonWrapper.tsx b/packages/ui/src/views/components/ribbon/TooltipButtonWrapper.tsx new file mode 100644 index 0000000000..a163a3d11d --- /dev/null +++ b/packages/ui/src/views/components/ribbon/TooltipButtonWrapper.tsx @@ -0,0 +1,86 @@ +/** + * 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 { IDropdownProps, ITooltipProps, NullableTooltipRef } from '@univerjs/design'; +import { Dropdown, Tooltip } from '@univerjs/design'; +import React, { createContext, forwardRef, useContext, useMemo, useState } from 'react'; + +const TooltipWrapperContext = createContext({ + dropdownVisible: false, + setDropdownVisible: (_visible: boolean) => {}, +}); + +export const TooltipWrapper = forwardRef((props, ref) => { + const { children, ...tooltipProps } = props; + + const [tooltipVisible, setTooltipVisible] = useState(false); + const [dropdownVisible, setDropdownVisible] = useState(false); + + function handleChangeTooltipVisible(visible: boolean) { + if (dropdownVisible) { + setTooltipVisible(false); + } else { + setTooltipVisible(visible); + } + } + + function handleChangeDropdownVisible(visible: boolean) { + setDropdownVisible(visible); + + setTooltipVisible(false); + } + + const contextValue = useMemo(() => ({ + dropdownVisible, + setDropdownVisible: handleChangeDropdownVisible, + }), [dropdownVisible]); + + return ( + + + + {children} + + + + ); +}); + +export function DropdownWrapper(props: IDropdownProps) { + const { children, ...dropdownProps } = props; + + const { setDropdownVisible } = useContext(TooltipWrapperContext); + + function handleVisibleChange(visible: boolean) { + setDropdownVisible(visible); + } + + return ( + +
e.stopPropagation()}> + {children} +
+
+ ); +} diff --git a/packages/ui/src/views/components/doc-bars/hook.ts b/packages/ui/src/views/components/ribbon/hook.ts similarity index 75% rename from packages/ui/src/views/components/doc-bars/hook.ts rename to packages/ui/src/views/components/ribbon/hook.ts index a332d4ef25..a3d1396ece 100644 --- a/packages/ui/src/views/components/doc-bars/hook.ts +++ b/packages/ui/src/views/components/ribbon/hook.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import type { Subscription } from 'rxjs'; import { combineLatest, map, Observable } from 'rxjs'; import { useDependency } from '@univerjs/core'; @@ -160,62 +160,3 @@ export function useToolbarItemStatus(menuItem: IDisplayMenuItem): ITo return { disabled, value, activated, hidden }; } - -export function useToolbarCollapseObserver(visibleItems: IToolbarRenderHookHandler['visibleItems']) { - const toolbarItemRefs = useRef>({}); - - const toolbarRef = useRef(null); - const [collapsedId, setCollapsedId] = useState([]); - - // Deal with toolbar collapsing. - useEffect(() => { - function resize() { - const wrapperWidth = toolbarRef.current?.clientWidth ?? 0; - let GAP = 0; - if (toolbarRef.current) { - // firstElementChild is toolbar container - const gapValue = Number.parseInt(getComputedStyle(toolbarRef.current.firstElementChild!).gap, 10); - GAP = Number.isNaN(gapValue) ? 0 : gapValue; - } - - const itemWidths = Object.entries(toolbarItemRefs.current) - .filter(([_, ref]) => ref.el && ref.key && visibleItems.find((item) => item.id === ref.key)) - .map(([_, ref]) => ({ - key: ref.key, - width: ref.el?.clientWidth + GAP, - })); - - const collapsedId: string[] = []; - - let currentWidth = 182; - for (const item of itemWidths) { - currentWidth += item.width; - - if (currentWidth > wrapperWidth) { - collapsedId.push(item.key); - } - } - - setCollapsedId(collapsedId); - } - - resize(); - const observer = new ResizeObserver(() => resize()); - - const toolbarDom = toolbarRef.current; - toolbarDom && observer.observe(toolbarDom); - - return () => { - toolbarDom && observer.unobserve(toolbarDom); - }; - }, [visibleItems]); - - return { - toolbarRef, - toolbarItemRefs, - collapsedId, - }; -} diff --git a/packages/ui/src/views/components/doc-bars/index.module.less b/packages/ui/src/views/components/ribbon/index.module.less similarity index 100% rename from packages/ui/src/views/components/doc-bars/index.module.less rename to packages/ui/src/views/components/ribbon/index.module.less diff --git a/packages/ui/src/views/workbench/Workbench.tsx b/packages/ui/src/views/workbench/Workbench.tsx index e404f09cb4..037b1b229a 100644 --- a/packages/ui/src/views/workbench/Workbench.tsx +++ b/packages/ui/src/views/workbench/Workbench.tsx @@ -25,7 +25,7 @@ import { IMessageService } from '../../services/message/message.service'; import { BuiltInUIPart } from '../../services/parts/parts.service'; import { ComponentContainer, useComponentsOfPart } from '../components/ComponentContainer'; import { DesktopContextMenu } from '../components/context-menu/ContextMenu'; -import { Toolbar } from '../components/doc-bars/Toolbar'; +import { Ribbon } from '../components/ribbon/Ribbon'; import { Sidebar } from '../components/sidebar/Sidebar'; import { ZenZone } from '../components/zen-zone/ZenZone'; import { builtInGlobalComponents } from '../parts'; @@ -112,7 +112,7 @@ export function DesktopWorkbench(props: IUniverWorkbenchProps) { {/* header */} {header && toolbar && (
- +
)} diff --git a/packages/uniscript/src/controllers/config.schema.ts b/packages/uniscript/src/controllers/config.schema.ts new file mode 100644 index 0000000000..e61ae99ebc --- /dev/null +++ b/packages/uniscript/src/controllers/config.schema.ts @@ -0,0 +1,28 @@ +/** + * 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 { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'uniscript.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverUniscriptConfig { + menu?: MenuConfig; + getWorkerUrl?: (moduleID: string, label: string) => string; +} + +export const defaultPluginConfig: IUniverUniscriptConfig = {}; diff --git a/packages/uniscript/src/controllers/menu.schema.ts b/packages/uniscript/src/controllers/menu.schema.ts new file mode 100644 index 0000000000..a7c776966f --- /dev/null +++ b/packages/uniscript/src/controllers/menu.schema.ts @@ -0,0 +1,30 @@ +/** + * 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 { IMenu2Item } from '@univerjs/ui'; +import { RibbonStartGroup } from '@univerjs/ui'; +import { ToggleScriptPanelOperation } from '../commands/operations/panel.operation'; +import { UniscriptMenuItemFactory } from './menu'; + +export const menuSchema: IMenu2Item = { + [RibbonStartGroup.OTHERS]: { + [ToggleScriptPanelOperation.id]: { + order: 5, + menuItemFactory: UniscriptMenuItemFactory, + }, + }, +}; + diff --git a/packages/uniscript/src/controllers/uniscript.controller.ts b/packages/uniscript/src/controllers/uniscript.controller.ts index c6589f2ac4..6801518af1 100644 --- a/packages/uniscript/src/controllers/uniscript.controller.ts +++ b/packages/uniscript/src/controllers/uniscript.controller.ts @@ -14,35 +14,23 @@ * limitations under the License. */ -import { Disposable, ICommandService, Inject, Injector, LifecycleStages, OnLifecycle } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { ComponentManager, IMenuService } from '@univerjs/ui'; +import { Disposable, ICommandService, Inject, LifecycleStages, OnLifecycle } from '@univerjs/core'; +import { ComponentManager, IMenu2Service } from '@univerjs/ui'; import { ScriptPanelComponentName, ToggleScriptPanelOperation } from '../commands/operations/panel.operation'; import { ScriptEditorPanel } from '../views/components/ScriptEditorPanel'; -import { UniscriptMenuItemFactory } from './menu'; - -export interface IUniverUniscriptConfig { - getWorkerUrl(moduleID: string, label: string): string; - menu: MenuConfig; -} - -export const DefaultUniscriptConfig = {}; +import { menuSchema } from './menu.schema'; @OnLifecycle(LifecycleStages.Steady, UniscriptController) export class UniscriptController extends Disposable { constructor( - private readonly _config: Partial, - @Inject(Injector) private readonly _injector: Injector, - @IMenuService private readonly _menuService: IMenuService, + @IMenu2Service private readonly _menu2Service: IMenu2Service, @ICommandService commandService: ICommandService, @Inject(ComponentManager) componentManager: ComponentManager ) { super(); - const { menu = {} } = this._config; - - this.disposeWithMe(_menuService.addMenuItem(this._injector.invoke(UniscriptMenuItemFactory), menu)); + this._menu2Service.mergeMenu(menuSchema); this.disposeWithMe(componentManager.register(ScriptPanelComponentName, ScriptEditorPanel)); this.disposeWithMe(commandService.registerCommand(ToggleScriptPanelOperation)); } diff --git a/packages/uniscript/src/plugin.ts b/packages/uniscript/src/plugin.ts index 43d7f2759f..60289ee20a 100644 --- a/packages/uniscript/src/plugin.ts +++ b/packages/uniscript/src/plugin.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { Inject, Injector, LocaleService, Plugin, Tools } from '@univerjs/core'; +import { IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; -import type { IUniverUniscriptConfig } from './controllers/uniscript.controller'; -import { DefaultUniscriptConfig, UniscriptController } from './controllers/uniscript.controller'; +import { UniscriptController } from './controllers/uniscript.controller'; import { ScriptEditorService } from './services/script-editor.service'; import { IUniscriptExecutionService, UniscriptExecutionService } from './services/script-execution.service'; import { ScriptPanelService } from './services/script-panel.service'; +import type { IUniverUniscriptConfig } from './controllers/config.schema'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; const PLUGIN_NAME = 'uniscript'; @@ -29,20 +30,25 @@ export class UniverUniscriptPlugin extends Plugin { static override pluginName = PLUGIN_NAME; constructor( - private readonly _config: Partial = {}, + private readonly _config: Partial = defaultPluginConfig, @Inject(Injector) protected override _injector: Injector, - @Inject(LocaleService) private readonly _localeService: LocaleService + @IConfigService private readonly _configService: IConfigService ) { super(); - this._config = Tools.deepMerge({}, DefaultUniscriptConfig, this._config); + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { const injector = this._injector; const dependencies: Dependency[] = [ - [UniscriptController, { useFactory: () => injector.createInstance(UniscriptController, this._config) }], - [ScriptEditorService, { useFactory: () => injector.createInstance(ScriptEditorService, this._config) }], + [UniscriptController], + [ScriptEditorService], [ScriptPanelService], ]; diff --git a/packages/uniscript/src/services/script-editor.service.ts b/packages/uniscript/src/services/script-editor.service.ts index 5b8636b1d4..c467f158fd 100644 --- a/packages/uniscript/src/services/script-editor.service.ts +++ b/packages/uniscript/src/services/script-editor.service.ts @@ -14,10 +14,11 @@ * limitations under the License. */ -import { Disposable, toDisposable } from '@univerjs/core'; +import { Disposable, IConfigService, toDisposable } from '@univerjs/core'; import type { IDisposable } from '@univerjs/core'; import type { editor } from 'monaco-editor'; -import type { IUniverUniscriptConfig } from '../controllers/uniscript.controller'; +import type { IUniverUniscriptConfig } from '../controllers/config.schema'; +import { PLUGIN_CONFIG_KEY } from '../controllers/config.schema'; /** * This service is for loading monaco editor and its resources. It also holds the @@ -26,7 +27,7 @@ import type { IUniverUniscriptConfig } from '../controllers/uniscript.controller export class ScriptEditorService extends Disposable { private _editorInstance: editor.IStandaloneCodeEditor | null = null; - constructor(private readonly _config: Partial) { + constructor(@IConfigService private readonly _configService: IConfigService) { super(); } @@ -41,8 +42,10 @@ export class ScriptEditorService extends Disposable { requireVscodeEditor(): void { if (!window.MonacoEnvironment) { + const config = this._configService.getConfig(PLUGIN_CONFIG_KEY); + window.MonacoEnvironment = { - getWorkerUrl: this._config.getWorkerUrl, + getWorkerUrl: config?.getWorkerUrl, }; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68f4563042..0003aa8dd7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -663,6 +663,9 @@ importers: '@univerjs/sheets': specifier: workspace:* version: link:../../packages/sheets + '@univerjs/uniui': + specifier: workspace:* + version: 'link:' '@xyflow/react': specifier: ^12.2.0 version: 12.2.0(@types/react@18.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1765,7 +1768,7 @@ importers: version: link:../engine-render '@univerjs/icons-svg': specifier: ^0.1.74 - version: 0.1.74 + version: 0.1.76 '@univerjs/shared': specifier: workspace:* version: link:../../common/shared @@ -5495,6 +5498,9 @@ packages: '@univerjs/icons-svg@0.1.74': resolution: {integrity: sha512-XLvM4AnZpHXMC9yNj2EJMea3fZ2PhuHq4cIsxmIgW4kWdCCGHlVTu/Xj3fAxYpvb4PgyPKA8KoRbKM+xh4WfGw==} + '@univerjs/icons-svg@0.1.76': + resolution: {integrity: sha512-bEHVTcfH1ucyWzOZC5wWAWcWX22ymrLz/NRK6IHzcUVW7I68N4v4MGd7pBX0AvtIwfH4cdu6h78NBB+W2ArIKw==} + '@univerjs/icons@0.1.77': resolution: {integrity: sha512-ADkX1PkXG+rptU+OJzrPX+asVawRVKF6v+Ce3DYq/pVKOnKm8qPbKsbVmCMyxPOCq9N5Cd0TAkjJavyft+XsEw==} peerDependencies: @@ -13683,7 +13689,7 @@ snapshots: '@types/lodash.get@4.4.9': dependencies: - '@types/lodash': 4.17.5 + '@types/lodash': 4.17.7 '@types/lodash.mergewith@4.6.9': dependencies: @@ -13691,7 +13697,7 @@ snapshots: '@types/lodash.set@4.3.9': dependencies: - '@types/lodash': 4.17.5 + '@types/lodash': 4.17.7 '@types/lodash@4.17.5': {} @@ -13868,6 +13874,8 @@ snapshots: '@univerjs/icons-svg@0.1.74': {} + '@univerjs/icons-svg@0.1.76': {} + '@univerjs/icons@0.1.77(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1