From a97d859f996d5ead77b3bc677ca357be64c3daed Mon Sep 17 00:00:00 2001 From: Wenzhao Hu <12122021+wzhudev@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:50:00 +0800 Subject: [PATCH 1/4] refactor: rename basic files refactor(docs-ui): refactor doc rendering to render unit fix: fix error emitted refactor: refactor zoom controller refactor: refactor back scroll render controller refactor: move doc skeleton manager into render unit refactor: refactor doc drawing refactor: refactor editor related modules fix: fix type error WIP refactor: refactor doc view model test: fix docs test fix: fix import error test: fix facade test fix: fix e2e test chore: change editor unit name chore: update code style fix: fix formula editor cannot be activated fix: fix render blinking fix: fix sheet editor cannot be updated fix: button style (#2541) * fix(sheet): style issue * chore: range modal delete button style chore: update dependencies & limit maximum concurrency for turbo execution (#2543) fix(sheets-ui): fix unhide render controller RENDER_COMMANDS (#2516) fix(sheets): hide rows cols should skip over already hidden ranges (#2517) fix: use @univerjs/ui useObservable (#2456) fix(design): fix popup position (#2510) fix(sheets-drawing-ui): error delete cache when float-dom hide (#2540) feat: everything feels very lag when there is a long range dashrect(cliparea) (#2472) * fix: moving getCell lower * fix: try to draw dashrect in visible area * chore: rm useless * fix: do not use startXY as IRect props to get viewport pos fix(sheets): fix some bugs (#2545) * fix(sheets): fix some bugs * chore: change test * fix: bugfix chore(ci): fix sync:cnpm (#2525) feat: init uni mode ui layout fix: fix scroll problems fix: fix sheet bar tabs feat: add focus style fix: all workbooks need to initialized fix: fix zoom slider chore: clean code fix: fix editor position --- examples/package.json | 1 + .../demo/default-workbook-data-demo1.ts | 2 +- examples/src/uni/lazy.ts | 24 +- examples/src/uni/main.ts | 9 +- packages-experimental/README.md | 3 + packages-experimental/uniui/README.md | 16 ++ packages-experimental/uniui/package.json | 91 +++++++ .../controllers/uniui-desktop.controller.tsx | 107 ++++++++ .../uniui/src/index.ts | 13 +- packages-experimental/uniui/src/plugin.ts | 137 +++++++++++ .../services/unit-grid/unit-grid.service.ts | 79 ++++++ .../src/views/workbench/UniWorkbench.tsx | 230 ++++++++++++++++++ .../src/views/workbench/workbench.module.less | 76 ++++++ packages-experimental/uniui/src/vite-env.d.ts | 1 + packages-experimental/uniui/tsconfig.json | 9 + .../uniui/tsconfig.node.json | 4 + packages-experimental/uniui/vite.config.ts | 12 + .../src/controllers/doc-ui.controller.ts | 27 +- packages/docs-ui/src/docs-ui-plugin.ts | 4 +- .../views/doc-background/index.module.less | 11 - .../src/commands/commands/delete.command.ts | 1 - .../services/doc-skeleton-manager.service.ts | 2 +- packages/engine-render/src/engine.ts | 4 + .../render-manager/render-manager.service.ts | 22 +- .../src/render-manager/render-unit.ts | 10 +- packages/facade/package.json | 1 + .../create-selection-command-test-bed.ts | 4 +- .../__tests__/set-frozen.command.spec.ts | 6 +- .../commands/commands/set-frozen.command.ts | 4 +- .../commands/commands/set-scroll.command.ts | 10 +- .../commands/operations/scroll.operation.ts | 26 +- .../editor/editing.render-controller.ts | 10 +- .../controllers/hover-render.controller.ts | 4 +- .../sheet-permission-init.controller.ts | 46 ++-- .../freeze.render-controller.ts | 4 +- .../mobile/mobile-scroll.render-controller.ts | 4 +- .../scroll.render-controller.ts | 4 +- .../sheet.render-controller.ts | 2 - .../sheets-ui/src/mobile-sheets-ui-plugin.ts | 5 +- .../src/services/drag-manager.service.ts | 10 +- .../src/services/hover-manager.service.ts | 7 +- .../src/services/scroll-manager.service.ts | 31 +-- .../mobile-selection-render.service.ts | 4 +- .../src/services/sheets-render.service.ts | 2 +- packages/sheets-ui/src/sheets-ui-plugin.ts | 11 +- .../src/views/count-bar/ZoomSlider.tsx | 11 +- .../src/views/sheet-bar/SheetBar.tsx | 8 +- .../sheet-bar/sheet-bar-tabs/SheetBarTabs.tsx | 10 +- .../commands/set-col-visible.command.ts | 2 +- .../commands/set-row-visible.command.ts | 1 - .../operations/selection.operation.ts | 2 +- packages/sheets/src/sheets-plugin.ts | 2 +- .../controllers/ui/ui-desktop.controller.tsx | 4 +- packages/ui/src/index.ts | 17 +- packages/ui/src/ui-plugin.ts | 12 +- .../Workbench.tsx} | 48 ++-- .../workbench.module.less} | 2 +- pnpm-lock.yaml | 52 ++++ pnpm-workspace.yaml | 1 + 59 files changed, 1029 insertions(+), 233 deletions(-) create mode 100644 packages-experimental/README.md create mode 100644 packages-experimental/uniui/README.md create mode 100644 packages-experimental/uniui/package.json create mode 100644 packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx rename packages/docs-ui/src/views/doc-background/DocBackground.tsx => packages-experimental/uniui/src/index.ts (72%) create mode 100644 packages-experimental/uniui/src/plugin.ts create mode 100644 packages-experimental/uniui/src/services/unit-grid/unit-grid.service.ts create mode 100644 packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx create mode 100644 packages-experimental/uniui/src/views/workbench/workbench.module.less create mode 100644 packages-experimental/uniui/src/vite-env.d.ts create mode 100644 packages-experimental/uniui/tsconfig.json create mode 100644 packages-experimental/uniui/tsconfig.node.json create mode 100644 packages-experimental/uniui/vite.config.ts delete mode 100644 packages/docs-ui/src/views/doc-background/index.module.less rename packages/ui/src/views/{DesktopApp.tsx => workbench/Workbench.tsx} (79%) rename packages/ui/src/views/{app.module.less => workbench/workbench.module.less} (98%) diff --git a/examples/package.json b/examples/package.json index 50d804aaf69..61b2376dea2 100644 --- a/examples/package.json +++ b/examples/package.json @@ -55,6 +55,7 @@ "@univerjs/thread-comment-ui": "workspace:*", "@univerjs/ui": "workspace:*", "@univerjs/uniscript": "workspace:*", + "@univerjs/uniui": "workspace:*", "@wendellhu/redi": "0.15.5", "clsx": "^2.1.1", "monaco-editor": "0.50.0", diff --git a/examples/src/data/sheets/demo/default-workbook-data-demo1.ts b/examples/src/data/sheets/demo/default-workbook-data-demo1.ts index ac7a98ee862..dedf64bac1b 100644 --- a/examples/src/data/sheets/demo/default-workbook-data-demo1.ts +++ b/examples/src/data/sheets/demo/default-workbook-data-demo1.ts @@ -18,7 +18,7 @@ import type { IWorkbookData } from '@univerjs/core'; import { BooleanNumber, BorderStyleTypes, LocaleType } from '@univerjs/core'; export const DEFAULT_WORKBOOK_DATA_DEMO1: IWorkbookData = { - id: 'workbook-01', + id: 'workbook-001', locale: LocaleType.ZH_CN, name: 'universheet', sheetOrder: ['sheet-0003'], diff --git a/examples/src/uni/lazy.ts b/examples/src/uni/lazy.ts index f642604d63c..f609227f1be 100644 --- a/examples/src/uni/lazy.ts +++ b/examples/src/uni/lazy.ts @@ -16,22 +16,22 @@ import type { Plugin, PluginCtor } from '@univerjs/core'; import { UniverSheetsFilterUIPlugin } from '@univerjs/sheets-filter-ui'; -import { UniverUniscriptPlugin } from '@univerjs/uniscript'; +// import { UniverUniscriptPlugin } from '@univerjs/uniscript'; export default function getLazyPlugins(): Array<[PluginCtor] | [PluginCtor, unknown]> { return [ - [ - UniverUniscriptPlugin, - { - getWorkerUrl(moduleID: string, label: string) { - if (label === 'typescript' || label === 'javascript') { - return './vs/language/typescript/ts.worker.js'; - } + // [ + // UniverUniscriptPlugin, + // { + // getWorkerUrl(moduleID: string, label: string) { + // if (label === 'typescript' || label === 'javascript') { + // return './vs/language/typescript/ts.worker.js'; + // } - return './vs/editor/editor.worker.js'; - }, - }, - ], + // return './vs/editor/editor.worker.js'; + // }, + // }, + // ], [UniverSheetsFilterUIPlugin], ]; } diff --git a/examples/src/uni/main.ts b/examples/src/uni/main.ts index 05ddd25a71b..d429f74dbdf 100644 --- a/examples/src/uni/main.ts +++ b/examples/src/uni/main.ts @@ -24,13 +24,13 @@ import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; -import { UniverSheetsZenEditorPlugin } from '@univerjs/sheets-zen-editor'; -import { UniverUIPlugin } from '@univerjs/ui'; +import { UniverUniUIPlugin } from '@univerjs/uniui'; import { UniverDebuggerPlugin } from '@univerjs/debugger'; import { FUniver } from '@univerjs/facade'; import { UniverDrawingPlugin } from '@univerjs/drawing'; import { DEFAULT_WORKBOOK_DATA_DEMO } from '../data/sheets/demo/default-workbook-data-demo'; import { enUS } from '../locales'; +import { DEFAULT_WORKBOOK_DATA_DEMO1 } from '../data'; /* eslint-disable-next-line node/prefer-global/process */ const IS_E2E: boolean = !!process.env.IS_E2E; @@ -52,7 +52,7 @@ univer.registerPlugin(UniverDocsPlugin, { }); univer.registerPlugin(UniverFormulaEnginePlugin); univer.registerPlugin(UniverRenderEnginePlugin); -univer.registerPlugin(UniverUIPlugin, { +univer.registerPlugin(UniverUniUIPlugin, { container: 'app', }); @@ -64,12 +64,13 @@ univer.registerPlugin(UniverSheetsPlugin); univer.registerPlugin(UniverSheetsUIPlugin); univer.registerPlugin(UniverSheetsNumfmtPlugin); -univer.registerPlugin(UniverSheetsZenEditorPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); // create univer sheet instance if (!IS_E2E) { univer.createUnit(UniverInstanceType.UNIVER_SHEET, DEFAULT_WORKBOOK_DATA_DEMO); + univer.createUnit(UniverInstanceType.UNIVER_SHEET, DEFAULT_WORKBOOK_DATA_DEMO1); + // univer.createUnit(UniverInstanceType.UNIVER_DOC, DEFAULT_DOCUMENT_DATA_CN); } // debugger plugin diff --git a/packages-experimental/README.md b/packages-experimental/README.md new file mode 100644 index 00000000000..269364b78e5 --- /dev/null +++ b/packages-experimental/README.md @@ -0,0 +1,3 @@ +# Experimental Packages + +Experimental packages in development. These packages are not meant to be published to npm or used in production. diff --git a/packages-experimental/uniui/README.md b/packages-experimental/uniui/README.md new file mode 100644 index 00000000000..fb7f05dcb93 --- /dev/null +++ b/packages-experimental/uniui/README.md @@ -0,0 +1,16 @@ +# @univerjs/uniui + +[![npm version](https://img.shields.io/npm/v/@univerjs/uniui)](https://npmjs.org/packages/@univerjs/uniui) +[![license](https://img.shields.io/npm/l/@univerjs/uniui)](https://img.shields.io/npm/l/@univerjs/uniui) + +## Introduction + +> TODO: Introduction + +## Usage + +### Installation + +```shell +npm i @univerjs/uniui +``` diff --git a/packages-experimental/uniui/package.json b/packages-experimental/uniui/package.json new file mode 100644 index 00000000000..b69552c2e17 --- /dev/null +++ b/packages-experimental/uniui/package.json @@ -0,0 +1,91 @@ +{ + "name": "@univerjs/uniui", + "version": "0.0.1", + "private": true, + "description": "", + "author": "DreamNum ", + "license": "Apache-2.0", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/univer" + }, + "homepage": "https://univer.ai", + "repository": { + "type": "git", + "url": "https://github.com/dream-num/univer" + }, + "bugs": { + "url": "https://github.com/dream-num/univer/issues" + }, + "keywords": [], + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": "./src/index.ts", + "./*": "./src/*" + }, + "main": "./lib/cjs/index.js", + "module": "./lib/es/index.js", + "types": "./lib/types/index.d.ts", + "publishConfig": { + "access": "public", + "main": "./lib/cjs/index.js", + "module": "./lib/es/index.js", + "exports": { + ".": { + "import": "./lib/es/index.js", + "require": "./lib/cjs/index.js", + "types": "./lib/types/index.d.ts" + }, + "./*": { + "import": "./lib/es/*", + "require": "./lib/cjs/*", + "types": "./lib/types/index.d.ts" + }, + "./lib/*": "./lib/*" + } + }, + "directories": { + "lib": "lib" + }, + "files": [ + "lib" + ], + "scripts": { + "test": "vitest run", + "test:watch": "vitest", + "coverage": "vitest run --coverage", + "lint:types": "tsc --noEmit", + "build": "tsc && vite build" + }, + "peerDependencies": { + "@univerjs/core": "workspace:*", + "@univerjs/design": "workspace:*", + "@univerjs/engine-render": "workspace:*", + "@univerjs/ui": "workspace:*", + "@wendellhu/redi": ">=0.12.13", + "clsx": ">=2.0.0", + "react": ">=16.9.0", + "rxjs": ">=7.0.0" + }, + "dependencies": { + "@univerjs/icons": "^0.1.46", + "rc-util": "^5.43.0" + }, + "devDependencies": { + "@univerjs/core": "workspace:*", + "@univerjs/design": "workspace:*", + "@univerjs/engine-render": "workspace:*", + "@univerjs/shared": "workspace:*", + "@univerjs/ui": "workspace:*", + "@wendellhu/redi": "^0.15.2", + "clsx": "^2.1.1", + "less": "^4.2.0", + "react": "18.3.1", + "rxjs": "^7.8.1", + "typescript": "^5.4.5", + "vite": "^5.2.11", + "vitest": "^1.6.0" + } +} diff --git a/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx b/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx new file mode 100644 index 00000000000..1930e2ffb15 --- /dev/null +++ b/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx @@ -0,0 +1,107 @@ +/** + * 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, LifecycleService, LifecycleStages, toDisposable } from '@univerjs/core'; +import type { IWorkbenchOptions } from '@univerjs/ui'; +import { BuiltInUIPart, CanvasPopup, FloatDom, IUIPartsService } from '@univerjs/ui'; +import type { IDisposable } from '@wendellhu/redi'; +import { Inject, Injector } from '@wendellhu/redi'; +import { connectInjector } from '@wendellhu/redi/react-bindings'; +import React from 'react'; +import { delay, filter, take } from 'rxjs'; +import { render as createRoot, unmount } from 'rc-util/lib/React/render'; + +import { UniWorkbench } from '../views/workbench/UniWorkbench'; + +const STEADY_TIMEOUT = 3000; + +export class UniverUniUIController extends Disposable { + constructor( + @Inject(Injector) private readonly _injector: Injector, + @Inject(LifecycleService) private readonly _lifecycleService: LifecycleService, + @IUIPartsService private readonly _uiPartsService: IUIPartsService + ) { + super(); + this._initBuiltinComponents(); + } + + bootstrapWorkbench(options: IWorkbenchOptions): void { + this.disposeWithMe( + bootstrap(this._injector, options, () => { + this._lifecycleService.lifecycle$.pipe( + filter((lifecycle) => lifecycle === LifecycleStages.Ready), + delay(300), + take(1) + ).subscribe(() => { + this._lifecycleService.stage = LifecycleStages.Rendered; + setTimeout(() => this._lifecycleService.stage = LifecycleStages.Steady, STEADY_TIMEOUT); + }); + }) + ); + } + + private _initBuiltinComponents() { + this.disposeWithMe(this._uiPartsService.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(CanvasPopup, this._injector))); + this.disposeWithMe(this._uiPartsService.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(FloatDom, this._injector))); + } +} + +function bootstrap( + injector: Injector, + options: IWorkbenchOptions, + callback: () => void +): IDisposable { + let mountContainer: HTMLElement; + + const container = options.container; + if (typeof container === 'string') { + const containerElement = document.getElementById(container); + if (!containerElement) { + mountContainer = createContainer(container); + } else { + mountContainer = containerElement; + } + } else if (container instanceof HTMLElement) { + mountContainer = container; + } else { + mountContainer = createContainer('univer'); + } + + const ConnectedApp = connectInjector(UniWorkbench, injector); + function render() { + createRoot( + , + mountContainer + ); + } + + render(); + + return toDisposable(() => { + unmount(mountContainer); + }); +} + +function createContainer(id: string): HTMLElement { + const element = document.createElement('div'); + element.id = id; + // FIXME: the element is not append to the DOM tree. So it won't be rendered. + return element; +} diff --git a/packages/docs-ui/src/views/doc-background/DocBackground.tsx b/packages-experimental/uniui/src/index.ts similarity index 72% rename from packages/docs-ui/src/views/doc-background/DocBackground.tsx rename to packages-experimental/uniui/src/index.ts index 411817dd765..30056d30d9d 100644 --- a/packages/docs-ui/src/views/doc-background/DocBackground.tsx +++ b/packages-experimental/uniui/src/index.ts @@ -14,15 +14,4 @@ * limitations under the License. */ -import React from 'react'; - -import styles from './index.module.less'; - -/** - * Doc standalone background - */ -export const DocBackground = () => { - return ( -
- ); -}; +export { UniverUniUIPlugin } from './plugin'; diff --git a/packages-experimental/uniui/src/plugin.ts b/packages-experimental/uniui/src/plugin.ts new file mode 100644 index 00000000000..d353ec5de15 --- /dev/null +++ b/packages-experimental/uniui/src/plugin.ts @@ -0,0 +1,137 @@ +/** + * 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 { DependentOn, IContextService, ILocalStorageService, mergeOverrideWithDependencies, Plugin, Tools } from '@univerjs/core'; +import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; +import type { Dependency } from '@wendellhu/redi'; +import { Inject, Injector } from '@wendellhu/redi'; +import type { IUniverUIConfig } from '@univerjs/ui'; +import { + BrowserClipboardService, + CanvasFloatDomService, + CanvasPopupService, + ComponentManager, + ContextMenuService, + DesktopBeforeCloseService, + DesktopConfirmService, + DesktopDialogService, + DesktopGlobalZoneService, + DesktopLayoutService, + DesktopLocalStorageService, + DesktopMessageService, + DesktopNotificationService, + DesktopSidebarService, + DesktopZenZoneService, + DISABLE_AUTO_FOCUS_KEY, + EditorService, + ErrorController, + IBeforeCloseService, + ICanvasPopupService, + IClipboardInterfaceService, + IConfirmService, + IContextMenuService, + IDialogService, + IEditorService, + IGlobalZoneService, + ILayoutService, + IMenuService, + IMessageService, + INotificationService, + IPlatformService, + IProgressService, + IRangeSelectorService, + IShortcutService, + ISidebarService, + IUIController, + IUIPartsService, + IZenZoneService, + MenuService, + PlatformService, + ProgressService, + RangeSelectorService, + SharedController, + ShortcutPanelController, + ShortcutPanelService, + ShortcutService, + UIPartsService, + UNIVER_UI_PLUGIN_NAME, + ZIndexManager, +} from '@univerjs/ui'; +import { UniverUniUIController } from './controllers/uniui-desktop.controller'; +import { UnitGridService } from './services/unit-grid/unit-grid.service'; + +const UI_BOOTSTRAP_DELAY = 16; + +/** + * This plugin enables the Uni Mode of Univer. It should replace + * `UniverUIPlugin` when registered. + */ +@DependentOn(UniverRenderEnginePlugin) +export class UniverUniUIPlugin extends Plugin { + static override pluginName: string = UNIVER_UI_PLUGIN_NAME; + + constructor( + private _config: Partial = {}, + @Inject(Injector) protected readonly _injector: Injector, + @IContextService private readonly _contextService: IContextService + ) { + super(); + + this._config = Tools.deepMerge({}, this._config); + if (this._config.disableAutoFocus) { + this._contextService.setContextValue(DISABLE_AUTO_FOCUS_KEY, true); + } + } + + override onStarting(injector: Injector): void { + const dependencies: Dependency[] = mergeOverrideWithDependencies([ + [ComponentManager], + [ZIndexManager], + + [ShortcutPanelService], + [UnitGridService], + [IUIPartsService, { useClass: UIPartsService }], + [ILayoutService, { useClass: DesktopLayoutService }], + [IShortcutService, { useClass: ShortcutService }], + [IPlatformService, { useClass: PlatformService }], + [IMenuService, { useClass: MenuService }], + [IContextMenuService, { useClass: ContextMenuService }], + [IClipboardInterfaceService, { useClass: BrowserClipboardService, lazy: true }], + [INotificationService, { useClass: DesktopNotificationService, lazy: true }], + [IDialogService, { useClass: DesktopDialogService, lazy: true }], + [IConfirmService, { useClass: DesktopConfirmService, lazy: true }], + [ISidebarService, { useClass: DesktopSidebarService, lazy: true }], + [IZenZoneService, { useClass: DesktopZenZoneService, lazy: true }], + [IGlobalZoneService, { useClass: DesktopGlobalZoneService, lazy: true }], + [IMessageService, { useClass: DesktopMessageService, lazy: true }], + [ILocalStorageService, { useClass: DesktopLocalStorageService, lazy: true }], + [IBeforeCloseService, { useClass: DesktopBeforeCloseService }], + [IEditorService, { useClass: EditorService }], + [IRangeSelectorService, { useClass: RangeSelectorService }], + [ICanvasPopupService, { useClass: CanvasPopupService }], + [IProgressService, { useClass: ProgressService }], + [CanvasFloatDomService], + + // This line is different from the original UI plugin. + [IUIController, { useClass: UniverUniUIController }], + + [SharedController, { useFactory: () => this._injector.createInstance(SharedController, this._config) }], + [ErrorController], + [ShortcutPanelController, { useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config) }], + ], this._config.override); + dependencies.forEach((dependency) => injector.add(dependency)); + } +} diff --git a/packages-experimental/uniui/src/services/unit-grid/unit-grid.service.ts b/packages-experimental/uniui/src/services/unit-grid/unit-grid.service.ts new file mode 100644 index 00000000000..f234c123965 --- /dev/null +++ b/packages-experimental/uniui/src/services/unit-grid/unit-grid.service.ts @@ -0,0 +1,79 @@ +/** + * 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, isInternalEditorID } from '@univerjs/core'; +import type { IRender } from '@univerjs/engine-render'; +import { IRenderManagerService } from '@univerjs/engine-render'; +import { BehaviorSubject } from 'rxjs'; + +export type IUnitGrid = string[]; + +/** + * This services decides which (now at maximum two) units are going to be rendered in the browser. + */ +export class UnitGridService extends Disposable { + // TODO@wzhudev: currently we only support at maximum 2 units rendered side by side. + // In the future we would introduce a grid system (very much like vscode's) to support more + // units and more complex layout. + private _unitGrid: IUnitGrid = []; + private readonly _unitGrid$ = new BehaviorSubject(this._unitGrid); + readonly unitGrid$ = this._unitGrid$.asObservable(); + + constructor( + @IRenderManagerService private readonly _renderSrv: IRenderManagerService + ) { + super(); + + this._init(); + } + + setContainerForRender(unitId: string, element: HTMLElement) { + this._renderSrv.getRenderById(unitId)?.engine.setContainer(element); + } + + override dispose(): void { + super.dispose(); + + this._unitGrid$.complete(); + } + + private _init(): void { + this._renderSrv.getRenderAll().forEach((renderer) => this._onRendererCreated(renderer)); + this.disposeWithMe(this._renderSrv.created$.subscribe((renderer) => this._onRendererCreated(renderer))); + this.disposeWithMe(this._renderSrv.disposed$.subscribe((unitId) => this._onRenderedDisposed(unitId))); + } + + private _onRendererCreated(renderer: IRender): void { + if (isInternalEditorID(renderer.unitId)) { + return; + } + + this._unitGrid.push(renderer.unitId); + this._emitLayoutChange(); + } + + private _onRenderedDisposed(unitId: string): void { + const idx = this._unitGrid.indexOf(unitId); + if (idx !== -1) { + this._unitGrid.splice(idx, 1); + this._emitLayoutChange(); + } + } + + private _emitLayoutChange(): void { + this._unitGrid$.next(this._unitGrid); + } +} diff --git a/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx b/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx new file mode 100644 index 00000000000..9fef22eb0f0 --- /dev/null +++ b/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx @@ -0,0 +1,230 @@ +/** + * 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. + */ + +// Refer to packages/ui/src/views/App.tsx + +import { IUniverInstanceService, LocaleService, ThemeService } from '@univerjs/core'; +import { ConfigProvider, defaultTheme, themeInstance } from '@univerjs/design'; +import type { ILocale } from '@univerjs/design'; +import { + builtInGlobalComponents, + BuiltInUIPart, + ComponentContainer, + ContextMenu, + IMessageService, + type IWorkbenchOptions, + Sidebar, + Toolbar, + useComponentsOfPart, + useObservable, + ZenZone, +} from '@univerjs/ui'; +import { useDependency } from '@wendellhu/redi/react-bindings'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import clsx from 'clsx'; +import { UnitGridService } from '../../services/unit-grid/unit-grid.service'; +import styles from './workbench.module.less'; + +// Refer to packages/ui/src/views/workbench/Workbench.tsx + +export interface IUniWorkbenchProps extends IWorkbenchOptions { + mountContainer: HTMLElement; + + onRendered: () => void; +} + +export function UniWorkbench(props: IUniWorkbenchProps) { + const { + header = true, + footer = true, + contextMenu = true, + mountContainer, + onRendered, + } = props; + + const localeService = useDependency(LocaleService); + const themeService = useDependency(ThemeService); + const messageService = useDependency(IMessageService); + const unitGridService = useDependency(UnitGridService); + const instanceService = useDependency(IUniverInstanceService); + + const contentRef = useRef(null); + + const footerComponents = useComponentsOfPart(BuiltInUIPart.FOOTER); + const headerComponents = useComponentsOfPart(BuiltInUIPart.HEADER); + const headerMenuComponents = useComponentsOfPart(BuiltInUIPart.HEADER_MENU); + const contentComponents = useComponentsOfPart(BuiltInUIPart.CONTENT); + const leftSidebarComponents = useComponentsOfPart(BuiltInUIPart.LEFT_SIDEBAR); + const globalComponents = useComponentsOfPart(BuiltInUIPart.GLOBAL); + + const unitGrid = useObservable(unitGridService.unitGrid$, undefined, true); + const focused = useObservable(instanceService.focused$); + + const focusUnit = useCallback((unitId: string) => { + instanceService.focusUnit(unitId); + instanceService.setCurrentUnitForType(unitId); + }, [instanceService]); + + useEffect(() => { + if (!themeService.getCurrentTheme()) { + themeService.setTheme(defaultTheme); + } + + onRendered(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const [locale, setLocale] = useState(localeService.getLocales() as unknown as ILocale); + + // Create a portal container for injecting global component themes. + const portalContainer = useMemo(() => document.createElement('div'), []); + + useEffect(() => { + document.body.appendChild(portalContainer); + messageService.setContainer(portalContainer); + + const subscriptions = [ + localeService.localeChanged$.subscribe(() => { + setLocale(localeService.getLocales() as unknown as ILocale); + }), + themeService.currentTheme$.subscribe((theme) => { + themeInstance.setTheme(mountContainer, theme); + portalContainer && themeInstance.setTheme(portalContainer, theme); + }), + ]; + + return () => { + // batch unsubscribe + subscriptions.forEach((subscription) => subscription.unsubscribe()); + + // cleanup + document.body.removeChild(portalContainer); + }; + }, [localeService, messageService, mountContainer, portalContainer, themeService.currentTheme$]); + + return ( + + {/** + * IMPORTANT! This `tabIndex` should not be moved. This attribute allows the element to catch + * all focusin event merged from its descendants. The DesktopLayoutService would listen to focusin events + * bubbled to this element and refocus the input element. + */} +
e.stopPropagation()}> + {/* header */} + {header && ( +
+ +
+ )} + + {/* content */} +
+
+ + +
+
+ {header && } +
+ +
e.preventDefault()} + > + {/* Render units. */} + {unitGrid?.map((unitId) => ( + + ))} + +
+
+ + +
+ + {/* footer */} + {footer && ( +
+ +
+ )} + + +
+
+ + + {contextMenu && } +
+ ); +} + +interface IUnitRendererProps { + unitId: string; + focused: boolean; + + gridService: UnitGridService; + instanceService: IUniverInstanceService; + + onFocus?: (unitId: string) => void; +} + +function UnitRenderer(props: IUnitRendererProps) { + const { unitId, gridService, focused, onFocus } = props; + const mountRef = useRef(null); + + const focus = useCallback(() => { + !focused && onFocus?.(unitId); + }, [focused, onFocus, unitId]); + + useEffect(() => { + if (mountRef.current) { + gridService.setContainerForRender(unitId, mountRef.current); + } + }, [gridService, unitId]); + + return ( +
+
+ ); +} + +function FloatingContainer() { + const { mountContainer } = useContext(ConfigContext); + const floatingComponents = useComponentsOfPart(BuiltInUIPart.FLOATING); + + return createPortal(, mountContainer!); +} diff --git a/packages-experimental/uniui/src/views/workbench/workbench.module.less b/packages-experimental/uniui/src/views/workbench/workbench.module.less new file mode 100644 index 00000000000..033a761ab2a --- /dev/null +++ b/packages-experimental/uniui/src/views/workbench/workbench.module.less @@ -0,0 +1,76 @@ +.workbench { + &-layout { + display: flex; + flex-direction: column; + height: 100%; + background-color: rgb(var(--bg-color)); + min-height: 0; + position: relative; + } + + &-header { + // height: 32px; + } + + &-container { + position: relative; + display: flex; + flex: 1; + flex-direction: column; + min-height: 0; + + &-header { + position: relative; + z-index: 10; + width: 100%; + } + + &-wrapper { + display: grid; + grid-template-columns: auto 1fr auto; + grid-template-rows: 100%; + height: 100%; + overflow: hidden; + } + + &-content { + position: relative; + + overflow: hidden; + display: grid; + grid-template-rows: auto 1fr; + flex: 1; + + background-color: rgb(var(--bg-color-secondary)); + border-bottom: 1px solid rgb(var(--border-color)); + } + + &-canvas-container { + position: relative; + display: flex; + } + + &-canvas { + flex: 1; + position: relative; + overflow: hidden; + border: 1px solid transparent; + + &-focused { + border: 1px solid rgb(var(--primary-color)); + } + } + + &-left-sidebar { + height: 100%; + } + + &-sidebar { + height: 100%; + } + } + + &-footer { + // height: 36px; + } +} diff --git a/packages-experimental/uniui/src/vite-env.d.ts b/packages-experimental/uniui/src/vite-env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/packages-experimental/uniui/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages-experimental/uniui/tsconfig.json b/packages-experimental/uniui/tsconfig.json new file mode 100644 index 00000000000..d676ad2a20d --- /dev/null +++ b/packages-experimental/uniui/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@univerjs/shared/tsconfigs/base", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types" + }, + "references": [{ "path": "./tsconfig.node.json" }], + "include": ["src"] +} diff --git a/packages-experimental/uniui/tsconfig.node.json b/packages-experimental/uniui/tsconfig.node.json new file mode 100644 index 00000000000..e53dac88688 --- /dev/null +++ b/packages-experimental/uniui/tsconfig.node.json @@ -0,0 +1,4 @@ +{ + "extends": "@univerjs/shared/tsconfigs/node", + "include": ["vite.config.ts"] +} diff --git a/packages-experimental/uniui/vite.config.ts b/packages-experimental/uniui/vite.config.ts new file mode 100644 index 00000000000..925b530b4d5 --- /dev/null +++ b/packages-experimental/uniui/vite.config.ts @@ -0,0 +1,12 @@ +import createViteConfig from '@univerjs/shared/vite'; +import pkg from './package.json'; + +export default ({ mode }) => createViteConfig({}, { + mode, + pkg, + features: { + react: false, + css: true, + dom: true, + }, +}); diff --git a/packages/docs-ui/src/controllers/doc-ui.controller.ts b/packages/docs-ui/src/controllers/doc-ui.controller.ts index 42bce879852..99501db49b6 100644 --- a/packages/docs-ui/src/controllers/doc-ui.controller.ts +++ b/packages/docs-ui/src/controllers/doc-ui.controller.ts @@ -14,13 +14,11 @@ * limitations under the License. */ -import type { DocumentDataModel } from '@univerjs/core'; -import { Disposable, IUniverInstanceService, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; +import { Disposable, LifecycleStages, OnLifecycle, UniverInstanceType } from '@univerjs/core'; import type { IMenuItemFactory } from '@univerjs/ui'; -import { BuiltInUIPart, ComponentManager, IEditorService, ILayoutService, IMenuService, IUIPartsService } from '@univerjs/ui'; +import { ComponentManager, ILayoutService, IMenuService } from '@univerjs/ui'; import { Inject, Injector } from '@wendellhu/redi'; -import { connectInjector } from '@wendellhu/redi/react-bindings'; import { ITextSelectionRenderManager } from '@univerjs/engine-render'; import { COLOR_PICKER_COMPONENT, ColorPicker } from '../components/color-picker'; import { @@ -30,7 +28,6 @@ import { FontFamilyItem, } from '../components/font-family'; import { FONT_SIZE_COMPONENT, FontSize } from '../components/font-size'; -import { DocBackground } from '../views/doc-background/DocBackground'; import type { IUniverDocsUIConfig } from '../basics'; import { AlignCenterMenuItemFactory, @@ -61,10 +58,7 @@ export class DocUIController extends Disposable { @Inject(Injector) private readonly _injector: Injector, @Inject(ComponentManager) private readonly _componentManager: ComponentManager, @ILayoutService private readonly _layoutService: ILayoutService, - @IEditorService private readonly _editorService: IEditorService, - @IMenuService private readonly _menuService: IMenuService, - @IUIPartsService private readonly _uiPartsService: IUIPartsService, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService + @IMenuService private readonly _menuService: IMenuService ) { super(); @@ -112,24 +106,9 @@ export class DocUIController extends Disposable { private _init(): void { this._initCustomComponents(); this._initMenus(); - this._initDocBackground(); this._initFocusHandler(); } - private _initDocBackground() { - const firstDocUnitId = this._univerInstanceService.getAllUnitsForType(UniverInstanceType.UNIVER_DOC)[0].getUnitId(); - if (firstDocUnitId == null) { - return; - } - - const embedded = this._editorService.isEditor(firstDocUnitId); - if (!embedded) { - this.disposeWithMe( - this._uiPartsService.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(DocBackground, this._injector)) - ); - } - } - private _initFocusHandler(): void { this.disposeWithMe( this._layoutService.registerFocusHandler(UniverInstanceType.UNIVER_DOC, () => { diff --git a/packages/docs-ui/src/docs-ui-plugin.ts b/packages/docs-ui/src/docs-ui-plugin.ts index a1ad0bad3da..d69b7012638 100644 --- a/packages/docs-ui/src/docs-ui-plugin.ts +++ b/packages/docs-ui/src/docs-ui-plugin.ts @@ -23,11 +23,10 @@ import { } from '@univerjs/core'; import type { Dependency } from '@wendellhu/redi'; import { Inject, Injector } from '@wendellhu/redi'; - import { IEditorService, IShortcutService } from '@univerjs/ui'; - import { IRenderManagerService } from '@univerjs/engine-render'; import { DocSkeletonManagerService } from '@univerjs/docs'; + import { MoveCursorDownShortcut, MoveCursorLeftShortcut, @@ -44,7 +43,6 @@ 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'; - import { BreakLineShortcut, DeleteLeftShortcut, DeleteRightShortcut } from './shortcuts/core-editing.shortcut'; import { DocClipboardService, IDocClipboardService } from './services/clipboard/clipboard.service'; import { DocClipboardController } from './controllers/clipboard.controller'; diff --git a/packages/docs-ui/src/views/doc-background/index.module.less b/packages/docs-ui/src/views/doc-background/index.module.less deleted file mode 100644 index f9d6c502944..00000000000 --- a/packages/docs-ui/src/views/doc-background/index.module.less +++ /dev/null @@ -1,11 +0,0 @@ -@size: 100%; - -.docs-ui-canvas-background { - position: relative; - width: @size; - height: @size; - background: rgb(var(--grey-50)); //rgb(233,238,242) - z-index: 1; - user-select: none; - pointer-events: none; -} diff --git a/packages/docs/src/commands/commands/delete.command.ts b/packages/docs/src/commands/commands/delete.command.ts index 42cb9f23371..a30264a22b2 100644 --- a/packages/docs/src/commands/commands/delete.command.ts +++ b/packages/docs/src/commands/commands/delete.command.ts @@ -47,7 +47,6 @@ export const MergeTwoParagraphCommand: ICommand = { id: 'doc.command.merge-two-paragraph', type: CommandType.COMMAND, - // eslint-disable-next-line max-lines-per-function handler: async (accessor, params: IMergeTwoParagraphParams) => { const textSelectionManagerService = accessor.get(TextSelectionManagerService); diff --git a/packages/docs/src/services/doc-skeleton-manager.service.ts b/packages/docs/src/services/doc-skeleton-manager.service.ts index 134e86d72ff..21fb4e18c33 100644 --- a/packages/docs/src/services/doc-skeleton-manager.service.ts +++ b/packages/docs/src/services/doc-skeleton-manager.service.ts @@ -51,7 +51,7 @@ export class DocSkeletonManagerService extends RxDisposable implements IRenderMo this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_DOC) .pipe(takeUntil(this.dispose$)) .subscribe((documentModel) => { - if (documentModel?.getUnitId() === this._context.unitId) { + if (documentModel && documentModel.getUnitId() === this._context.unitId) { this._update(documentModel); } }); diff --git a/packages/engine-render/src/engine.ts b/packages/engine-render/src/engine.ts index b33d4f950c4..595bbc2e8b1 100644 --- a/packages/engine-render/src/engine.ts +++ b/packages/engine-render/src/engine.ts @@ -189,6 +189,10 @@ export class Engine extends ThinEngine { } setContainer(elem: HTMLElement, resize = true) { + if (this._container === elem) { + return; + } + this._container = elem; this._container.appendChild(this.getCanvasElement()); diff --git a/packages/engine-render/src/render-manager/render-manager.service.ts b/packages/engine-render/src/render-manager/render-manager.service.ts index 490e32e734c..fe5ffa1e2e6 100644 --- a/packages/engine-render/src/render-manager/render-manager.service.ts +++ b/packages/engine-render/src/render-manager/render-manager.service.ts @@ -34,6 +34,7 @@ export type RenderComponentType = SheetComponent | DocComponent | Slide | BaseOb export interface IRenderManagerService extends IDisposable { /** @deprecated */ currentRender$: Observable>; + addRender(unitId: string, renderer: IRender): void; createRender(unitId: string): IRender; removeRender(unitId: string): void; @@ -53,6 +54,9 @@ export interface IRenderManagerService extends IDisposable { /** @deprecated this design is very very weird! Remove it. */ create(unitId: string): void; + created$: Observable; + disposed$: Observable; + /** @deprecated There will be multi units to render at the same time, so there is no *current*. */ getCurrent(): Nullable; /** @deprecated There will be multi units to render at the same time, so there is no *first*. */ @@ -60,6 +64,7 @@ export interface IRenderManagerService extends IDisposable { has(unitId: string): boolean; withCurrentTypeOfUnit(type: UniverInstanceType, id: DependencyIdentifier): Nullable; + registerRenderModule(type: UnitType, dep: Dependency): IDisposable; } @@ -81,6 +86,12 @@ export class RenderManagerService extends Disposable implements IRenderManagerSe /** @deprecated */ readonly createRender$ = this._createRender$.asObservable(); + private readonly _renderCreated$ = new Subject(); + readonly created$ = this._renderCreated$.asObservable(); + + private readonly _renderDisposed$ = new Subject(); + readonly disposed$ = this._renderDisposed$.asObservable(); + get defaultEngine() { if (!this._defaultEngine) { this._defaultEngine = new Engine(); @@ -104,6 +115,9 @@ export class RenderManagerService extends Disposable implements IRenderManagerSe this._renderDependencies.clear(); this._renderMap.clear(); this._currentRender$.complete(); + + this._renderCreated$.complete(); + this._renderDisposed$.complete(); } registerRenderModules(type: UnitType, deps: Dependency[]): IDisposable { @@ -153,7 +167,9 @@ export class RenderManagerService extends Disposable implements IRenderManagerSe } createRender(unitId: string): IRender { - return this._createRender(unitId, new Engine()); + const renderer = this._createRender(unitId, new Engine()); + this._renderCreated$.next(renderer); + return renderer; } getCurrentTypeOfRenderer(type: UniverInstanceType): Nullable { @@ -196,7 +212,7 @@ export class RenderManagerService extends Disposable implements IRenderManagerSe if (unit) { const type = this._univerInstanceService.getUnitType(unitId); const ctors = this._getRenderControllersForType(type); - renderUnit = new RenderUnit(this._injector, { + renderUnit = this._injector.createInstance(RenderUnit, { unit, engine, scene, @@ -285,6 +301,8 @@ export class RenderManagerService extends Disposable implements IRenderManagerSe if (shouldDestroyEngine) { engine.dispose(); } + + this._renderDisposed$.next(item.unitId); } } diff --git a/packages/engine-render/src/render-manager/render-unit.ts b/packages/engine-render/src/render-manager/render-unit.ts index d4b60e15e72..1612a9d7f93 100644 --- a/packages/engine-render/src/render-manager/render-unit.ts +++ b/packages/engine-render/src/render-manager/render-unit.ts @@ -16,7 +16,7 @@ import type { Nullable, UnitModel, UnitType } from '@univerjs/core'; import { Disposable } from '@univerjs/core'; -import { type Dependency, type DependencyIdentifier, type IDisposable, type Injector, isClassDependencyItem } from '@wendellhu/redi'; +import { type Dependency, type DependencyIdentifier, type IDisposable, Inject, Injector, isClassDependencyItem } from '@wendellhu/redi'; import type { Engine } from '../engine'; import type { Scene } from '../scene'; import type { RenderComponentType } from './render-manager.service'; @@ -66,15 +66,14 @@ export class RenderUnit extends Disposable implements IRender { get components() { return this._renderContext.components; } constructor( - parentInjector: Injector, - init: Pick + init: Pick, + @Inject(Injector) parentInjector: Injector ) { super(); this._injector = parentInjector.createChild(); - this._renderContext = { - unit: init.unit, // model + unit: init.unit, unitId: init.unit.getUnitId(), type: init.unit.type, components: new Map(), @@ -87,7 +86,6 @@ export class RenderUnit extends Disposable implements IRender { override dispose() { this._injector.dispose(); - super.dispose(); } diff --git a/packages/facade/package.json b/packages/facade/package.json index f28903ae20b..6b47ba2dd57 100644 --- a/packages/facade/package.json +++ b/packages/facade/package.json @@ -62,6 +62,7 @@ "peerDependencies": { "@univerjs/core": "workspace:*", "@univerjs/docs": "workspace:*", + "@univerjs/docs-ui": "workspace:*", "@univerjs/engine-formula": "workspace:*", "@univerjs/engine-render": "workspace:*", "@univerjs/network": "workspace:*", diff --git a/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts b/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts index 9ce2c1a4bcc..fd328a7d1a8 100644 --- a/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts +++ b/packages/sheets-ui/src/commands/commands/__tests__/create-selection-command-test-bed.ts @@ -20,7 +20,7 @@ import { SetFrozenMutation, SetSelectionsOperation } from '@univerjs/sheets'; // FIXME: should not import from the inside of the package import { IRenderManagerService, RenderManagerService } from '@univerjs/engine-render'; -import { ScrollManagerService } from '../../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../../services/scroll-manager.service'; import { ShortcutExperienceService } from '../../../services/shortcut-experience.service'; import { CancelFrozenCommand, @@ -51,7 +51,7 @@ export function createSelectionCommandTestBed(workbookData?: IWorkbookData) { export function createFrozenCommandTestBed(workbookData?: IWorkbookData) { const { univer, get, sheet } = createCommandTestBed(workbookData || SIMPLE_SELECTION_WORKBOOK_DATA, [ [ShortcutExperienceService], - [ScrollManagerService], + [SheetScrollManagerService], [IRenderManagerService, { useClass: RenderManagerService }], ]); diff --git a/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts b/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts index cf65c84813a..a5b7fb2fbda 100644 --- a/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts +++ b/packages/sheets-ui/src/commands/commands/__tests__/set-frozen.command.spec.ts @@ -20,7 +20,7 @@ import { SheetsSelectionsService } from '@univerjs/sheets'; import type { Injector } from '@wendellhu/redi'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { ScrollManagerService } from '../../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../../services/scroll-manager.service'; import { CancelFrozenCommand, SetColumnFrozenCommand, @@ -34,7 +34,7 @@ describe('Test commands used for change selections', () => { let get: Injector['get']; let commandService: ICommandService; let selectionManagerService: SheetsSelectionsService; - let scrollManagerService: ScrollManagerService; + let scrollManagerService: SheetScrollManagerService; const currentInfo = { unitId: 'test', @@ -98,7 +98,7 @@ describe('Test commands used for change selections', () => { commandService = get(ICommandService); selectionManagerService = get(SheetsSelectionsService); - scrollManagerService = get(ScrollManagerService); + scrollManagerService = get(SheetScrollManagerService); scrollManagerService.setSearchParamAndRefresh({ ...currentInfo, }); diff --git a/packages/sheets-ui/src/commands/commands/set-frozen.command.ts b/packages/sheets-ui/src/commands/commands/set-frozen.command.ts index 2c190a7e9ba..0ecc8c6baff 100644 --- a/packages/sheets-ui/src/commands/commands/set-frozen.command.ts +++ b/packages/sheets-ui/src/commands/commands/set-frozen.command.ts @@ -19,7 +19,7 @@ import { CommandType, ICommandService, IUndoRedoService, IUniverInstanceService, import type { ISetFrozenMutationParams } from '@univerjs/sheets'; import { getSheetCommandTarget, SetFrozenMutation, SetFrozenMutationFactory, SheetsSelectionsService } from '@univerjs/sheets'; -import { ScrollManagerService } from '../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../services/scroll-manager.service'; export enum SetSelectionFrozenType { RowColumn = 0, @@ -50,7 +50,7 @@ export const SetSelectionFrozenCommand: ICommand // this._commandService.executeCommand(SetScrollRelativeCommand.id, { offsetY }); handler: async (accessor, params: ISetScrollRelativeCommandParams) => { const commandService = accessor.get(ICommandService); - const scrollManagerService = accessor.get(ScrollManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); + const renderManagerSrv = accessor.get(IRenderManagerService); const target = getSheetCommandTarget(univerInstanceService); if (!target) return false; const { unitId, subUnitId, worksheet } = target; const { xSplit, ySplit } = worksheet.getConfig().freeze; + const scrollManagerService = renderManagerSrv.getRenderById(unitId)!.with(SheetScrollManagerService); const currentScroll = scrollManagerService.getCurrentScrollInfo(); const { offsetX = 0, offsetY = 0 } = params || {}; const { @@ -89,12 +90,13 @@ export const ScrollCommand: ICommand = { } const univerInstanceService = accessor.get(IUniverInstanceService); - const scrollManagerService = accessor.get(ScrollManagerService); + const renderManagerSrv = accessor.get(IRenderManagerService); const target = getSheetCommandTarget(univerInstanceService); if (!target) return false; - const { workbook, worksheet } = target; + const { workbook, worksheet, unitId } = target; + const scrollManagerService = renderManagerSrv.getRenderById(unitId)!.with(SheetScrollManagerService); const currentScroll: Readonly> = scrollManagerService.getCurrentScrollInfo(); if (!worksheet) { diff --git a/packages/sheets-ui/src/commands/operations/scroll.operation.ts b/packages/sheets-ui/src/commands/operations/scroll.operation.ts index 17ad9ff61b9..16f336a54f3 100644 --- a/packages/sheets-ui/src/commands/operations/scroll.operation.ts +++ b/packages/sheets-ui/src/commands/operations/scroll.operation.ts @@ -17,32 +17,36 @@ import type { IOperation } from '@univerjs/core'; import { CommandType, IUniverInstanceService } from '@univerjs/core'; +import { IRenderManagerService } from '@univerjs/engine-render'; import type { IScrollManagerWithSearchParam } from '../../services/scroll-manager.service'; -import { ScrollManagerService } from '../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../services/scroll-manager.service'; export const SetScrollOperation: IOperation = { id: 'sheet.operation.set-scroll', type: CommandType.OPERATION, handler: (accessor, params: IScrollManagerWithSearchParam) => { - if (params == null) { + if (!params) { return false; } - const scrollManagerService = accessor.get(ScrollManagerService); // freeze is handled by set-scroll.command.ts + + const { unitId, sheetId, offsetX, offsetY, sheetViewStartColumn, sheetViewStartRow } = params; const currentService = accessor.get(IUniverInstanceService); - const workbook = currentService.getUniverSheetInstance(params!.unitId); - const worksheet = workbook!.getSheetBySheetId(params!.sheetId); + const renderManagerService = accessor.get(IRenderManagerService); + const workbook = currentService.getUniverSheetInstance(unitId); + const worksheet = workbook!.getSheetBySheetId(sheetId); + const scrollManagerService = renderManagerService.getRenderById(unitId)!.with(SheetScrollManagerService); const { xSplit, ySplit } = worksheet!.getConfig().freeze; scrollManagerService.setScrollInfoAndEmitEvent({ - unitId: params.unitId, - sheetId: params.sheetId, - offsetX: params.offsetX, - offsetY: params.offsetY, - sheetViewStartRow: params.sheetViewStartRow - ySplit, - sheetViewStartColumn: params.sheetViewStartColumn - xSplit, + unitId, + sheetId, + offsetX, + offsetY, + sheetViewStartRow: sheetViewStartRow - ySplit, + sheetViewStartColumn: sheetViewStartColumn - xSplit, }); return true; diff --git a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts index b822f90cf62..d3029c7e315 100644 --- a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts +++ b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts @@ -378,7 +378,7 @@ export class EditingRenderController extends Disposable implements IRenderModule let { startX, startY } = actualRangeWithCoord; - const { document: documentComponent, scene, engine } = editorObject; + const { document: documentComponent, scene, engine: docEngine } = editorObject; const viewportMain = scene.getViewport(DOC_VIEWPORT_KEY.VIEW_MAIN); @@ -438,12 +438,17 @@ export class EditingRenderController extends Disposable implements IRenderModule * When modifying the selection area for a formula, it is necessary to add a setTimeout to ensure successful updating. */ requestIdleCallback(() => { - engine.resizeBySize( + docEngine.resizeBySize( fixLineWidthByScale(editorWidth, precisionScaleX), fixLineWidthByScale(physicHeight, precisionScaleY) ); }); + const canvasElement = this._context.engine.getCanvasElement(); + const canvasBoundingRect = canvasElement.getBoundingClientRect(); + startX += canvasBoundingRect.left; + // startY += canvasBoundingRect.top; + // Update cell editor container position and size. this._cellEditorManagerService.setState({ startX, @@ -1041,3 +1046,4 @@ function isRichText(body: IDocumentBody) { paragraphs.length >= 2 ); } + diff --git a/packages/sheets-ui/src/controllers/hover-render.controller.ts b/packages/sheets-ui/src/controllers/hover-render.controller.ts index 1b632a373a0..573598bb5d9 100644 --- a/packages/sheets-ui/src/controllers/hover-render.controller.ts +++ b/packages/sheets-ui/src/controllers/hover-render.controller.ts @@ -21,14 +21,14 @@ import { Inject } from '@wendellhu/redi'; import { HoverManagerService } from '../services/hover-manager.service'; import type { ISheetSkeletonManagerParam } from '../services/sheet-skeleton-manager.service'; import { SheetSkeletonManagerService } from '../services/sheet-skeleton-manager.service'; -import { ScrollManagerService } from '../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../services/scroll-manager.service'; export class HoverRenderController extends Disposable implements IRenderModule { constructor( private readonly _context: IRenderContext, @Inject(HoverManagerService) private _hoverManagerService: HoverManagerService, @Inject(SheetSkeletonManagerService) private _sheetSkeletonManagerService: SheetSkeletonManagerService, - @Inject(ScrollManagerService) private _scrollManagerService: ScrollManagerService + @Inject(SheetScrollManagerService) private _scrollManagerService: SheetScrollManagerService ) { super(); diff --git a/packages/sheets-ui/src/controllers/permission/sheet-permission-init.controller.ts b/packages/sheets-ui/src/controllers/permission/sheet-permission-init.controller.ts index 6ca80ca4e52..6fe2809760e 100644 --- a/packages/sheets-ui/src/controllers/permission/sheet-permission-init.controller.ts +++ b/packages/sheets-ui/src/controllers/permission/sheet-permission-init.controller.ts @@ -278,42 +278,44 @@ export class SheetPermissionInitController extends Disposable { this._worksheetProtectionRuleModel.changeRuleInitState(false); - const workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!; - const unitId = workbook.getUnitId(); + const workbooks = this._univerInstanceService.getAllUnitsForType(UniverInstanceType.UNIVER_SHEET); + workbooks.forEach((workbook) => { + const unitId = workbook.getUnitId(); - getAllWorkbookPermissionPoint().forEach((F) => { - let instance = new F(unitId); - if (_map.has(instance.id)) { - instance = _map.get(instance.id) as any; - } - this._permissionService.addPermissionPoint(instance); - }); - - workbook.getSheets().forEach((sheet) => { - const subUnitId = sheet.getSheetId(); - [...getAllWorksheetPermissionPoint(), ...getAllWorksheetPermissionPointByPointPanel()].forEach((F) => { - let instance = new F(unitId, subUnitId); + getAllWorkbookPermissionPoint().forEach((F) => { + let instance = new F(unitId); if (_map.has(instance.id)) { instance = _map.get(instance.id) as any; } this._permissionService.addPermissionPoint(instance); }); - const ruleList = this._rangeProtectionRuleModel.getSubunitRuleList(unitId, subUnitId); - ruleList.forEach((rule) => { - getAllRangePermissionPoint().forEach((F) => { - let instance = new F(unitId, subUnitId, rule.permissionId); + workbook.getSheets().forEach((sheet) => { + const subUnitId = sheet.getSheetId(); + [...getAllWorksheetPermissionPoint(), ...getAllWorksheetPermissionPointByPointPanel()].forEach((F) => { + let instance = new F(unitId, subUnitId); if (_map.has(instance.id)) { instance = _map.get(instance.id) as any; } this._permissionService.addPermissionPoint(instance); }); + + const ruleList = this._rangeProtectionRuleModel.getSubunitRuleList(unitId, subUnitId); + ruleList.forEach((rule) => { + getAllRangePermissionPoint().forEach((F) => { + let instance = new F(unitId, subUnitId, rule.permissionId); + if (_map.has(instance.id)) { + instance = _map.get(instance.id) as any; + } + this._permissionService.addPermissionPoint(instance); + }); + }); }); - }); - this._initWorkbookPermissionChange(); - this._initWorksheetPermissionFromSnapshot(); - this._initRangePermissionFromSnapshot(); + this._initWorkbookPermissionChange(); + this._initWorksheetPermissionFromSnapshot(); + this._initRangePermissionFromSnapshot(); + }); }) ); } diff --git a/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts index 87f4f5f8934..0142cd419a0 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/freeze.render-controller.ts @@ -71,7 +71,7 @@ import { ScrollCommand } from '../../commands/commands/set-scroll.command'; import { SetZoomRatioOperation } from '../../commands/operations/set-zoom-ratio.operation'; import { SHEET_COMPONENT_HEADER_LAYER_INDEX } from '../../common/keys'; -import { ScrollManagerService } from '../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../services/scroll-manager.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { getCoordByOffset, getSheetObject } from '../utils/component-tools'; @@ -149,7 +149,7 @@ export class HeaderFreezeRenderController extends Disposable implements IRenderM @ICommandService private readonly _commandService: ICommandService, // @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @Inject(SheetsSelectionsService) private readonly _selectionManagerService: SheetsSelectionsService, - @Inject(ScrollManagerService) private readonly _scrollManagerService: ScrollManagerService, + @Inject(SheetScrollManagerService) private readonly _scrollManagerService: SheetScrollManagerService, @Inject(ThemeService) private readonly _themeService: ThemeService, @Inject(SheetInterceptorService) private _sheetInterceptorService: SheetInterceptorService, @Inject(Injector) private _injector: Injector diff --git a/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-scroll.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-scroll.render-controller.ts index 95a261cb056..f4744575ccd 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-scroll.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/mobile/mobile-scroll.render-controller.ts @@ -33,7 +33,7 @@ import { ScrollCommand, SetScrollRelativeCommand } from '../../../commands/comma import type { IExpandSelectionCommandParams } from '../../../commands/commands/set-selection.command'; import { ExpandSelectionCommand, MoveSelectionCommand, MoveSelectionEnterAndTabCommand } from '../../../commands/commands/set-selection.command'; import type { IScrollManagerParam, IScrollManagerSearchParam } from '../../../services/scroll-manager.service'; -import { ScrollManagerService } from '../../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../../services/scroll-manager.service'; import type { ISheetSkeletonManagerParam } from '../../../services/sheet-skeleton-manager.service'; import { SheetSkeletonManagerService } from '../../../services/sheet-skeleton-manager.service'; import { getSheetObject } from '../../utils/component-tools'; @@ -50,7 +50,7 @@ export class MobileSheetsScrollRenderController extends Disposable implements IR @ICommandService private readonly _commandService: ICommandService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @Inject(SheetsSelectionsService) private readonly _selectionManagerService: SheetsSelectionsService, - @Inject(ScrollManagerService) private readonly _scrollManagerService: ScrollManagerService, + @Inject(SheetScrollManagerService) private readonly _scrollManagerService: SheetScrollManagerService, @IUniverInstanceService protected readonly _univerInstanceService: IUniverInstanceService ) { super(); diff --git a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts index e70373e1ce1..8bd7a1b2737 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/scroll.render-controller.ts @@ -32,7 +32,7 @@ import { ScrollCommand } from '../../commands/commands/set-scroll.command'; import type { IExpandSelectionCommandParams } from '../../commands/commands/set-selection.command'; import { ExpandSelectionCommand, MoveSelectionCommand, MoveSelectionEnterAndTabCommand } from '../../commands/commands/set-selection.command'; import type { IScrollManagerParam, IScrollManagerSearchParam } from '../../services/scroll-manager.service'; -import { ScrollManagerService } from '../../services/scroll-manager.service'; +import { SheetScrollManagerService } from '../../services/scroll-manager.service'; import type { ISheetSkeletonManagerParam } from '../../services/sheet-skeleton-manager.service'; import { SheetSkeletonManagerService } from '../../services/sheet-skeleton-manager.service'; import { getSheetObject } from '../utils/component-tools'; @@ -49,7 +49,7 @@ export class SheetsScrollRenderController extends Disposable implements IRenderM @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService, @ICommandService private readonly _commandService: ICommandService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @Inject(ScrollManagerService) private readonly _scrollManagerService: ScrollManagerService + @Inject(SheetScrollManagerService) private readonly _scrollManagerService: SheetScrollManagerService ) { super(); diff --git a/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts index e9566ea8d46..2369ed46872 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/sheet.render-controller.ts @@ -123,8 +123,6 @@ export class SheetRenderController extends RxDisposable implements IRenderModule const bufferEdgeX = 100; const bufferEdgeY = 100; - // TODO @lumixraku test - // (window as any).sc = scene; const viewMain = new Viewport(SHEET_VIEWPORT_KEY.VIEW_MAIN, scene, { left: rowHeader.width, top: columnHeader.height, diff --git a/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts b/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts index 593cfcdfc28..2a2593c3800 100644 --- a/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/mobile-sheets-ui-plugin.ts @@ -38,7 +38,7 @@ import { AutoFillService, IAutoFillService } from './services/auto-fill/auto-fil import { ISheetClipboardService, SheetClipboardService } from './services/clipboard/clipboard.service'; import { FormatPainterService, IFormatPainterService } from './services/format-painter/format-painter.service'; import { IMarkSelectionService, MarkSelectionService } from './services/mark-selection/mark-selection.service'; -import { ScrollManagerService } from './services/scroll-manager.service'; +import { SheetScrollManagerService } from './services/scroll-manager.service'; import { ISheetBarService, SheetBarService } from './services/sheet-bar/sheet-bar.service'; import { SheetSkeletonManagerService } from './services/sheet-skeleton-manager.service'; import { ShortcutExperienceService } from './services/shortcut-experience.service'; @@ -102,7 +102,7 @@ export class UniverSheetsMobileUIPlugin extends Plugin { [IAutoFillService, { useClass: AutoFillService }], [SheetPrintInterceptorService], - [ScrollManagerService], + [SheetScrollManagerService], // This would be removed from global injector and moved into RenderUnit provider. // [SheetSkeletonManagerService], [ISheetSelectionRenderService, { useClass: MobileSheetsSelectionRenderService }], @@ -116,7 +116,6 @@ export class UniverSheetsMobileUIPlugin extends Plugin { // controllers [ActiveWorksheetController], [AutoHeightController], - [HeaderFreezeRenderController], [SheetClipboardController], [SheetsRenderService], [ diff --git a/packages/sheets-ui/src/services/drag-manager.service.ts b/packages/sheets-ui/src/services/drag-manager.service.ts index de5720a8f89..5399b8fd0b3 100644 --- a/packages/sheets-ui/src/services/drag-manager.service.ts +++ b/packages/sheets-ui/src/services/drag-manager.service.ts @@ -16,12 +16,11 @@ import type { Nullable, Workbook } from '@univerjs/core'; import { Disposable, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; -import { Inject } from '@wendellhu/redi'; import { distinctUntilChanged, Subject } from 'rxjs'; import type { IDragEvent } from '@univerjs/engine-render'; import { IRenderManagerService } from '@univerjs/engine-render'; import { getHoverCellPosition } from '../common/utils'; -import { ScrollManagerService } from './scroll-manager.service'; +import { SheetScrollManagerService } from './scroll-manager.service'; import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service'; import type { IHoverCellPosition } from './hover-manager.service'; @@ -45,7 +44,6 @@ export class DragManagerService extends Disposable { constructor( @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(ScrollManagerService) private readonly _scrollManagerService: ScrollManagerService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService ) { super(); @@ -78,9 +76,11 @@ export class DragManagerService extends Disposable { if (!worksheet) return; // const skeletonParam = this._sheetSkeletonManagerService.getCurrent(); const currentRender = this._renderManagerService.getRenderById(workbook.getUnitId()); - const skeletonParam = currentRender?.with(SheetSkeletonManagerService)?.getCurrent(); + if (!currentRender) return; - const scrollInfo = this._scrollManagerService.getCurrentScrollInfo(); + const skeletonParam = currentRender.with(SheetSkeletonManagerService).getCurrent(); + const scrollManagerService = currentRender.with(SheetScrollManagerService); + const scrollInfo = scrollManagerService.getCurrentScrollInfo(); if (!skeletonParam || !scrollInfo || !currentRender) return; diff --git a/packages/sheets-ui/src/services/hover-manager.service.ts b/packages/sheets-ui/src/services/hover-manager.service.ts index 7111dec89db..85f699b08bd 100644 --- a/packages/sheets-ui/src/services/hover-manager.service.ts +++ b/packages/sheets-ui/src/services/hover-manager.service.ts @@ -17,12 +17,11 @@ import type { IPosition, Nullable, Workbook } from '@univerjs/core'; import { Disposable, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import type { ISheetLocation } from '@univerjs/sheets'; -import { Inject } from '@wendellhu/redi'; import { distinctUntilChanged, Subject } from 'rxjs'; import { IRenderManagerService } from '@univerjs/engine-render'; import { getHoverCellPosition } from '../common/utils'; -import { ScrollManagerService } from './scroll-manager.service'; import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service'; +import { SheetScrollManagerService } from './scroll-manager.service'; export interface IHoverCellPosition { position: IPosition; @@ -49,7 +48,6 @@ export class HoverManagerService extends Disposable { constructor( @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(ScrollManagerService) private readonly _scrollManagerService: ScrollManagerService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService ) { super(); @@ -87,7 +85,8 @@ export class HoverManagerService extends Disposable { const currentRender = this._renderManagerService.getRenderById(workbook.getUnitId()); const skeletonParam = currentRender?.with(SheetSkeletonManagerService).getWorksheetSkeleton(worksheet.getSheetId()); - const scrollInfo = this._scrollManagerService.getCurrentScrollInfo(); + const scrollManagerService = currentRender?.with(SheetScrollManagerService); + const scrollInfo = scrollManagerService?.getCurrentScrollInfo(); if (!skeletonParam || !scrollInfo || !currentRender) return; diff --git a/packages/sheets-ui/src/services/scroll-manager.service.ts b/packages/sheets-ui/src/services/scroll-manager.service.ts index 66f9c0711d5..f8ae44602fa 100644 --- a/packages/sheets-ui/src/services/scroll-manager.service.ts +++ b/packages/sheets-ui/src/services/scroll-manager.service.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import { IUniverInstanceService, type Nullable, UniverInstanceType } from '@univerjs/core'; +import type { Nullable, Workbook } from '@univerjs/core'; import { BehaviorSubject } from 'rxjs'; -import { IRenderManagerService } from '@univerjs/engine-render'; +import type { IRenderContext, IRenderModule } from '@univerjs/engine-render'; +import { Inject } from '@wendellhu/redi'; import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service'; export interface IViewportScrollState { @@ -71,7 +72,7 @@ export type IScrollInfo = Map>; * * ScrollController subscribes to the changes in service data to refresh the view scrolling. */ -export class ScrollManagerService { +export class SheetScrollManagerService implements IRenderModule { /** * a map holds all scroll info for each sheet */ @@ -97,10 +98,10 @@ export class ScrollManagerService { private _searchParamForScroll: Nullable = null; constructor( - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService + private readonly _context: IRenderContext, + @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService ) { - // init + // empty } dispose(): void { @@ -128,8 +129,9 @@ export class ScrollManagerService { if (this._searchParamForScroll == null) { return; } - const { unitId, sheetId } = this._searchParamForScroll; - const workbook = this._univerInstanceService.getUniverSheetInstance(unitId); + + const { sheetId } = this._searchParamForScroll; + const workbook = this._context.unit; const worksheet = workbook?.getSheetBySheetId(sheetId); const snapshot = worksheet?.getConfig(); if (snapshot) { @@ -189,16 +191,6 @@ export class ScrollManagerService { this._clearByParam(this._searchParamForScroll); } - // scrollToCell(startRow: number, startColumn: number) { - // const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; - // const scene = this._renderManagerService.getCurrent()?.scene; - // if (skeleton == null || scene == null) { - // return; - // } - - // const {} = skeleton.getCellByIndex(startRow, startColumn); - // } - calcViewportScrollFromRowColOffset(scrollInfo: IScrollManagerWithSearchParam) { const { unitId } = scrollInfo; const workbookScrollInfo = this._scrollInfoMap.get(unitId); @@ -213,8 +205,7 @@ export class ScrollManagerService { sheetViewStartRow = sheetViewStartRow || 0; offsetY = offsetY || 0; - // const skeleton = this._sheetSkeletonManagerService.getCurrent()?.skeleton; - const skeleton = this._renderManagerService.withCurrentTypeOfUnit(UniverInstanceType.UNIVER_SHEET, SheetSkeletonManagerService)?.getCurrentSkeleton(); + const skeleton = this._sheetSkeletonManagerService.getCurrentSkeleton(); const rowAcc = skeleton?.rowHeightAccumulation[sheetViewStartRow - 1] || 0; const colAcc = skeleton?.columnWidthAccumulation[sheetViewStartColumn - 1] || 0; const overallScrollX = colAcc + offsetX; diff --git a/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts b/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts index bfcba572364..a97570665f5 100644 --- a/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts @@ -41,7 +41,7 @@ import { distinctUntilChanged, startWith } from 'rxjs'; import type { ISheetObjectParam } from '../../controllers/utils/component-tools'; import { getCoordByOffset, getSheetObject } from '../../controllers/utils/component-tools'; import { checkInHeaderRanges } from '../../controllers/utils/selections-tools'; -import { ScrollManagerService } from '../scroll-manager.service'; +import { SheetScrollManagerService } from '../scroll-manager.service'; import { SheetSkeletonManagerService } from '../sheet-skeleton-manager.service'; import { BaseSelectionRenderService, getAllSelection, getTopLeftSelection } from './base-selection-render.service'; import { MobileSelectionControl } from './mobile-selection-shape'; @@ -76,7 +76,7 @@ export class MobileSheetsSelectionRenderService extends BaseSelectionRenderServi @ICommandService private readonly _commandService: ICommandService, @IContextService private readonly _contextService: IContextService, @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService, - @Inject(ScrollManagerService) private readonly _scrollManagerService: ScrollManagerService + @Inject(SheetScrollManagerService) private readonly _scrollManagerService: SheetScrollManagerService ) { super( injector, diff --git a/packages/sheets-ui/src/services/sheets-render.service.ts b/packages/sheets-ui/src/services/sheets-render.service.ts index 047273405fb..4adbbbb1817 100644 --- a/packages/sheets-ui/src/services/sheets-render.service.ts +++ b/packages/sheets-ui/src/services/sheets-render.service.ts @@ -54,7 +54,7 @@ export class SheetsRenderService extends RxDisposable { */ registerSkeletonChangingMutations(mutationId: string): IDisposable { if (this._skeletonChangeMutations.has(mutationId)) { - throw new Error(`[SheetsRenderService]: the mutationId ${mutationId} has already been registered!`); + return toDisposable(() => {}); } this._skeletonChangeMutations.add(mutationId); diff --git a/packages/sheets-ui/src/sheets-ui-plugin.ts b/packages/sheets-ui/src/sheets-ui-plugin.ts index 82415217bd9..8a7ce618eb2 100644 --- a/packages/sheets-ui/src/sheets-ui-plugin.ts +++ b/packages/sheets-ui/src/sheets-ui-plugin.ts @@ -48,7 +48,6 @@ import { import { EditorBridgeService, IEditorBridgeService } from './services/editor-bridge.service'; import { FormatPainterService, IFormatPainterService } from './services/format-painter/format-painter.service'; import { IMarkSelectionService, MarkSelectionService } from './services/mark-selection/mark-selection.service'; -import { ScrollManagerService } from './services/scroll-manager.service'; import { SheetSelectionRenderService } from './services/selection/selection-render.service'; import { ISheetBarService, SheetBarService } from './services/sheet-bar/sheet-bar.service'; import { SheetSkeletonManagerService } from './services/sheet-skeleton-manager.service'; @@ -84,6 +83,7 @@ import { SheetPrintInterceptorService } from './services/print-interceptor.servi import { SheetsDefinedNameController } from './controllers/defined-name/defined-name.controller'; import { MoveRangeRenderController } from './controllers/move-range.controller'; import { ISheetSelectionRenderService } from './services/selection/base-selection-render.service'; +import { SheetScrollManagerService } from './services/scroll-manager.service'; @DependentOn(UniverSheetsPlugin) export class UniverSheetsUIPlugin extends Plugin { @@ -114,7 +114,6 @@ export class UniverSheetsUIPlugin extends Plugin { [IAutoFillService, { useClass: AutoFillService }], [SheetPrintInterceptorService], - [ScrollManagerService], // This would be removed from global injector and moved into RenderUnit provider. // [SheetSkeletonManagerService], [IStatusBarService, { useClass: StatusBarService }], @@ -128,7 +127,6 @@ export class UniverSheetsUIPlugin extends Plugin { [ActiveWorksheetController], [AutoHeightController], [FormulaEditorController], - [HeaderFreezeRenderController], [SheetClipboardController], [SheetsRenderService], [ @@ -150,8 +148,7 @@ export class UniverSheetsUIPlugin extends Plugin { [SheetPermissionInterceptorBaseController], [SheetPermissionInitController], // [MoveRangeController], - ] as Dependency[] - ).forEach((d) => injector.add(d)); + ] as Dependency[]).forEach((d) => injector.add(d)); this._injector.add( [ @@ -188,13 +185,13 @@ export class UniverSheetsUIPlugin extends Plugin { private _registerRenderModules(): void { ([ [HeaderMoveRenderController], - [HeaderFreezeRenderController], [HeaderUnhideRenderController], [HeaderResizeRenderController], - // Caution: ScrollRenderController should placed before ZoomRenderController // because ZoomRenderController ---> viewport.resize --> setScrollInfo, but ScrollRenderController needs scrollInfo + [SheetScrollManagerService], [SheetsScrollRenderController], + [HeaderFreezeRenderController], [SheetsZoomRenderController], [FormatPainterRenderController], diff --git a/packages/sheets-ui/src/views/count-bar/ZoomSlider.tsx b/packages/sheets-ui/src/views/count-bar/ZoomSlider.tsx index 553c798c9a6..8b4dc318e1e 100644 --- a/packages/sheets-ui/src/views/count-bar/ZoomSlider.tsx +++ b/packages/sheets-ui/src/views/count-bar/ZoomSlider.tsx @@ -28,28 +28,35 @@ import React, { useCallback, useEffect, useState } from 'react'; import { SetZoomRatioCommand } from '../../commands/commands/set-zoom-ratio.command'; import { SetZoomRatioOperation } from '../../commands/operations/set-zoom-ratio.operation'; import { SHEET_ZOOM_RANGE } from '../../common/keys'; +import { useActiveWorkbook } from '../../components/hook'; const ZOOM_MAP = [50, 80, 100, 130, 150, 170, 200, 400]; export function ZoomSlider() { const commandService = useDependency(ICommandService); const univerInstanceService = useDependency(IUniverInstanceService); + const workbook = useActiveWorkbook(); const getCurrentZoom = useCallback(() => { - const worksheet = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getActiveSheet(); + if (!workbook) return 100; + + const worksheet = workbook.getActiveSheet(); const currentZoom = (worksheet && (worksheet.getZoomRatio() * 100)) || 100; return Math.round(currentZoom); - }, [univerInstanceService]); + }, [workbook]); const [zoom, setZoom] = useState(() => getCurrentZoom()); useEffect(() => { + setZoom(getCurrentZoom()); + const disposable = commandService.onCommandExecuted((commandInfo) => { if (commandInfo.id === SetZoomRatioOperation.id || commandInfo.id === SetWorksheetActiveOperation.id) { const currentZoom = getCurrentZoom(); setZoom(currentZoom); } }); + return disposable.dispose; }, [commandService, getCurrentZoom]); diff --git a/packages/sheets-ui/src/views/sheet-bar/SheetBar.tsx b/packages/sheets-ui/src/views/sheet-bar/SheetBar.tsx index 75cc4ce9ebf..e5beb1137d2 100644 --- a/packages/sheets-ui/src/views/sheet-bar/SheetBar.tsx +++ b/packages/sheets-ui/src/views/sheet-bar/SheetBar.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ -import type { Workbook } from '@univerjs/core'; -import { ICommandService, IPermissionService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { ICommandService, IPermissionService } from '@univerjs/core'; import { IncreaseSingle, MoreSingle } from '@univerjs/icons'; import { InsertSheetCommand, WorkbookCreateSheetPermission, WorkbookEditablePermission } from '@univerjs/sheets'; import { useDependency } from '@wendellhu/redi/react-bindings'; @@ -23,6 +22,7 @@ import React, { useEffect, useState } from 'react'; import { useObservable } from '@univerjs/ui'; import { ISheetBarService } from '../../services/sheet-bar/sheet-bar.service'; +import { useActiveWorkbook } from '../../components/hook'; import styles from './index.module.less'; import { SheetBarButton } from './sheet-bar-button/SheetBarButton'; import { SheetBarMenu } from './sheet-bar-menu/SheetBarMenu'; @@ -37,11 +37,9 @@ export const SheetBar = () => { const commandService = useDependency(ICommandService); const sheetBarService = useDependency(ISheetBarService); - const permissionService = useDependency(IPermissionService); - const univerInstanceService = useDependency(IUniverInstanceService); - const workbook = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!; + const workbook = useActiveWorkbook()!; const unitId = workbook.getUnitId(); const workbookEditablePermission = useObservable(permissionService.getPermissionPoint$(new WorkbookEditablePermission(unitId)?.id)); 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 896081ba963..caacfe48edf 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 @@ -14,8 +14,8 @@ * limitations under the License. */ -import type { ICommandInfo, Workbook } from '@univerjs/core'; -import { ICommandService, IPermissionService, IUniverInstanceService, LocaleService, nameCharacterCheck, UniverInstanceType } from '@univerjs/core'; +import type { ICommandInfo } from '@univerjs/core'; +import { ICommandService, IPermissionService, LocaleService, nameCharacterCheck } from '@univerjs/core'; import { Dropdown } from '@univerjs/design'; import { InsertSheetMutation, @@ -58,7 +58,6 @@ export function SheetBarTabs() { const slideTabBarRef = useRef<{ slideTabBar: SlideTabBar | null }>({ slideTabBar: null }); const slideTabBarContainerRef = useRef(null); - const univerInstanceService = useDependency(IUniverInstanceService); const commandService = useDependency(ICommandService); const sheetBarService = useDependency(ISheetBarService); const localeService = useDependency(LocaleService); @@ -121,7 +120,7 @@ export function SheetBarTabs() { slideTabBar.destroy(); subscribeList.forEach((subscribe) => subscribe.unsubscribe()); }; - }, [resetOrder]); + }, [resetOrder, workbook]); useEffect(() => { if (sheetList.length > 0) { @@ -206,6 +205,8 @@ export function SheetBarTabs() { return slideTabBar; }; + // TODO@Dushusir: the following callback functions should be wrapped by `useCallback`. + const nameEmptyCheck = (name: string) => { if (name.trim() === '') { const id = 'sheetNameEmptyAlert'; @@ -255,7 +256,6 @@ export function SheetBarTabs() { }; const nameRepeatCheck = (name: string) => { - const workbook = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!; const worksheet = workbook.getActiveSheet(); const currenSheetName = worksheet?.getName(); // TODO@Dushusir: no need trigger save diff --git a/packages/sheets/src/commands/commands/set-col-visible.command.ts b/packages/sheets/src/commands/commands/set-col-visible.command.ts index 25544768624..3633cbdcb52 100644 --- a/packages/sheets/src/commands/commands/set-col-visible.command.ts +++ b/packages/sheets/src/commands/commands/set-col-visible.command.ts @@ -26,7 +26,6 @@ import { } from '@univerjs/core'; import type { IAccessor } from '@wendellhu/redi'; -import { SheetsSelectionsService } from '../../services/selections/selection-manager.service'; import type { ISetColHiddenMutationParams, ISetColVisibleMutationParams } from '../mutations/set-col-visible.mutation'; import { SetColHiddenMutation, @@ -37,6 +36,7 @@ import { import type { ISetSelectionsOperationParams } from '../operations/selection.operation'; import { SetSelectionsOperation } from '../operations/selection.operation'; import { SheetInterceptorService } from '../../services/sheet-interceptor/sheet-interceptor.service'; +import { SheetsSelectionsService } from '../../services/selections/selection-manager.service'; import { getPrimaryForRange } from './utils/selection-utils'; import { getSheetCommandTarget } from './utils/target-util'; diff --git a/packages/sheets/src/commands/commands/set-row-visible.command.ts b/packages/sheets/src/commands/commands/set-row-visible.command.ts index 502f7242437..d61010c5fc8 100644 --- a/packages/sheets/src/commands/commands/set-row-visible.command.ts +++ b/packages/sheets/src/commands/commands/set-row-visible.command.ts @@ -166,7 +166,6 @@ export const SetRowHiddenCommand: ICommand = { const setSelectionOperationParams: ISetSelectionsOperationParams = { unitId, subUnitId, - selections: getSelectionsAfterHiding(ranges).map((range) => ({ range, primary: getPrimaryForRange(range, worksheet), diff --git a/packages/sheets/src/commands/operations/selection.operation.ts b/packages/sheets/src/commands/operations/selection.operation.ts index a02ac6c0dcf..a5f0963a4c2 100644 --- a/packages/sheets/src/commands/operations/selection.operation.ts +++ b/packages/sheets/src/commands/operations/selection.operation.ts @@ -18,8 +18,8 @@ import type { IOperation } from '@univerjs/core'; import { CommandType } from '@univerjs/core'; import type { ISelectionWithStyle } from '../../basics/selection'; -import type { SelectionMoveType } from '../../services/selections/selection-manager.service'; import { getSelectionsService } from '../utils/selection-command-util'; +import type { SelectionMoveType } from '../../services/selections/selection-manager.service'; export interface ISetSelectionsOperationParams { unitId: string; diff --git a/packages/sheets/src/sheets-plugin.ts b/packages/sheets/src/sheets-plugin.ts index de0bc871f20..bf9310fd448 100644 --- a/packages/sheets/src/sheets-plugin.ts +++ b/packages/sheets/src/sheets-plugin.ts @@ -29,7 +29,6 @@ import { INumfmtService } from './services/numfmt/type'; import { WorkbookPermissionService } from './services/permission/workbook-permission/workbook-permission.service'; import { RefRangeService } from './services/ref-range/ref-range.service'; -import { SheetsSelectionsService } from './services/selections/selection-manager.service'; import { SheetInterceptorService } from './services/sheet-interceptor/sheet-interceptor.service'; import { DefinedNameDataController } from './controllers/defined-name-data.controller'; import { WorksheetPermissionService, WorksheetProtectionPointModel, WorksheetProtectionRuleModel } from './services/permission/worksheet-permission'; @@ -40,6 +39,7 @@ import { RangeProtectionRefRangeService } from './services/permission/range-perm import { RangeProtectionService } from './services/permission/range-permission/range-protection.service'; import { ONLY_REGISTER_FORMULA_RELATED_MUTATIONS_KEY } from './controllers/config'; import { NumberCellDisplayController } from './controllers/number-cell.controller'; +import { SheetsSelectionsService } from './services/selections/selection-manager.service'; const PLUGIN_NAME = 'SHEET_PLUGIN'; diff --git a/packages/ui/src/controllers/ui/ui-desktop.controller.tsx b/packages/ui/src/controllers/ui/ui-desktop.controller.tsx index 246687f3eb8..9cd87edeeec 100644 --- a/packages/ui/src/controllers/ui/ui-desktop.controller.tsx +++ b/packages/ui/src/controllers/ui/ui-desktop.controller.tsx @@ -24,10 +24,10 @@ import { render as createRoot, unmount } from 'rc-util/lib/React/render'; import React from 'react'; import { ILayoutService } from '../../services/layout/layout.service'; -import { DesktopApp } from '../../views/DesktopApp'; import { BuiltInUIPart, IUIPartsService } from '../../services/parts/parts.service'; 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'; const STEADY_TIMEOUT = 3000; @@ -113,7 +113,7 @@ function bootstrap( mountContainer = createContainer('univer'); } - const ConnectedApp = connectInjector(DesktopApp, injector); + const ConnectedApp = connectInjector(DesktopWorkbench, injector); const onRendered = (canvasElement: HTMLElement) => callback(canvasElement, mountContainer); function render() { diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index dcbd93972e2..eb0814cadea 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -27,7 +27,7 @@ export { SharedController, UndoShortcutItem, } from './controllers/shared-shortcut.controller'; -export { UI_CONFIG_KEY, IUIController, type IWorkbenchOptions } from './controllers/ui/ui.controller'; +export { UI_CONFIG_KEY, IUIController, type IWorkbenchOptions, type IUniverUIConfig } from './controllers/ui/ui.controller'; 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'; @@ -86,14 +86,18 @@ export { ComponentContainer, useComponentsOfPart, type IComponentContainerProps export { IEditorService, EditorService } from './services/editor/editor.service'; export { TextEditor } from './components/editor/TextEditor'; export { RangeSelector } from './components/range-selector/RangeSelector'; -export { IRangeSelectorService } from './services/range-selector/range-selector.service'; -export { DesktopLocalStorageService } from './services/local-storage/local-storage.service'; -export { CanvasPopupService, ICanvasPopupService, type IPopup } from './services/popup/canvas-popup.service'; export { ProgressBar } from './components/progress-bar/ProgressBar'; export { type IMenuGroup, useToolbarGroups, useToolbarItemStatus, useToolbarCollapseObserver } from './views/components/doc-bars/hook'; export { mergeMenuConfigs } from './common/menu-merge-configs'; -export { IProgressService, ProgressService } from './services/progress/progress.service'; -export type { IProgressStep } from './services/progress/progress.service'; +export { ShortcutPanelController } from './controllers/shortcut-display/shortcut-panel.controller'; +export { ShortcutPanelService } from './services/shortcut/shortcut-panel.service'; +export { IProgressService, type IProgressCount, type IProgressStep, ProgressService } from './services/progress/progress.service'; +export { type IRangeSelectorRange, IRangeSelectorService, RangeSelectorService } from './services/range-selector/range-selector.service'; +export { CanvasPopupService, ICanvasPopupService, type IPopup } from './services/popup/canvas-popup.service'; +export { UNIVER_UI_PLUGIN_NAME } from './ui-plugin'; +export { ErrorController } from './controllers/error/error.controller'; +export { DesktopZenZoneService } from './services/zen-zone/desktop-zen-zone.service'; +export { DesktopLocalStorageService } from './services/local-storage/local-storage.service'; // #region - workbench components @@ -106,6 +110,7 @@ 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'; // #endregion diff --git a/packages/ui/src/ui-plugin.ts b/packages/ui/src/ui-plugin.ts index 755f7714ae4..0306885c4cf 100644 --- a/packages/ui/src/ui-plugin.ts +++ b/packages/ui/src/ui-plugin.ts @@ -57,10 +57,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'; -const PLUGIN_NAME = 'ui'; - -export const DefaultUiConfig = {}; - +export const UNIVER_UI_PLUGIN_NAME = 'UNIVER_UI_PLUGIN'; export const DISABLE_AUTO_FOCUS_KEY = 'DISABLE_AUTO_FOCUS'; /** @@ -68,7 +65,7 @@ export const DISABLE_AUTO_FOCUS_KEY = 'DISABLE_AUTO_FOCUS'; */ @DependentOn(UniverRenderEnginePlugin) export class UniverUIPlugin extends Plugin { - static override pluginName = PLUGIN_NAME; + static override pluginName = UNIVER_UI_PLUGIN_NAME; constructor( private _config: Partial = {}, @@ -77,8 +74,7 @@ export class UniverUIPlugin extends Plugin { ) { super(); - this._config = Tools.deepMerge({}, DefaultUiConfig, this._config); - + this._config = Tools.deepMerge({}, this._config); if (this._config.disableAutoFocus) { this._contextService.setContextValue(DISABLE_AUTO_FOCUS_KEY, true); } @@ -89,7 +85,6 @@ export class UniverUIPlugin extends Plugin { [ComponentManager], [ZIndexManager], - // services [ShortcutPanelService], [IUIPartsService, { useClass: UIPartsService }], [ILayoutService, { useClass: DesktopLayoutService }], @@ -134,7 +129,6 @@ export class UniverUIPlugin extends Plugin { }, ], ], this._config.override); - dependencies.forEach((dependency) => injector.add(dependency)); } } diff --git a/packages/ui/src/views/DesktopApp.tsx b/packages/ui/src/views/workbench/Workbench.tsx similarity index 79% rename from packages/ui/src/views/DesktopApp.tsx rename to packages/ui/src/views/workbench/Workbench.tsx index 124b158b2ae..e08558d331e 100644 --- a/packages/ui/src/views/DesktopApp.tsx +++ b/packages/ui/src/views/workbench/Workbench.tsx @@ -19,26 +19,27 @@ import type { ILocale } from '@univerjs/design'; import { ConfigContext, ConfigProvider, defaultTheme, themeInstance } from '@univerjs/design'; import { useDependency } from '@wendellhu/redi/react-bindings'; import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; -import { createPortal } from 'react-dom'; -import type { IWorkbenchOptions } from '../controllers/ui/ui.controller'; -import { IMessageService } from '../services/message/message.service'; -import { BuiltInUIPart } from '../services/parts/parts.service'; -import styles from './app.module.less'; -import { ComponentContainer, useComponentsOfPart } from './components/ComponentContainer'; -import { Toolbar } from './components/doc-bars/Toolbar'; -import { Sidebar } from './components/sidebar/Sidebar'; -import { ZenZone } from './components/zen-zone/ZenZone'; -import { builtInGlobalComponents } from './parts'; -import { DesktopContextMenu } from './components/context-menu/ContextMenu'; - -export interface IUniverAppProps extends IWorkbenchOptions { +import { createPortal } from 'react-dom'; +import type { IWorkbenchOptions } from '../../controllers/ui/ui.controller'; +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 { Sidebar } from '../components/sidebar/Sidebar'; +import { ZenZone } from '../components/zen-zone/ZenZone'; +import { builtInGlobalComponents } from '../parts'; + +import styles from './workbench.module.less'; + +export interface IUniverWorkbenchProps extends IWorkbenchOptions { mountContainer: HTMLElement; onRendered?: (container: HTMLElement) => void; } -export function DesktopApp(props: IUniverAppProps) { +export function DesktopWorkbench(props: IUniverWorkbenchProps) { const { header = true, toolbar = true, @@ -108,28 +109,28 @@ export function DesktopApp(props: IUniverAppProps) { * all focusin event merged from its descendants. The DesktopLayoutService would listen to focusin events * bubbled to this element and refocus the input element. */} -
e.stopPropagation()}> +
e.stopPropagation()}> {/* header */} {header && toolbar && ( -
+
)} {/* content */} -
-
-
diff --git a/packages/ui/src/views/app.module.less b/packages/ui/src/views/workbench/workbench.module.less similarity index 98% rename from packages/ui/src/views/app.module.less rename to packages/ui/src/views/workbench/workbench.module.less index b71c767e9f3..b2055ca40f0 100644 --- a/packages/ui/src/views/app.module.less +++ b/packages/ui/src/views/workbench/workbench.module.less @@ -1,4 +1,4 @@ -.app { +.workbench { &-layout { display: flex; flex-direction: column; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 07bc61640ab..8eac1cf2c35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -330,6 +330,9 @@ importers: '@univerjs/uniscript': specifier: workspace:* version: link:../packages/uniscript + '@univerjs/uniui': + specifier: workspace:* + version: link:../packages-experimental/uniui '@wendellhu/redi': specifier: 0.15.5 version: 0.15.5 @@ -386,6 +389,55 @@ importers: specifier: ^5.5.3 version: 5.5.3 + packages-experimental/uniui: + dependencies: + '@univerjs/icons': + specifier: ^0.1.46 + version: 0.1.58(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-util: + specifier: ^5.43.0 + version: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + devDependencies: + '@univerjs/core': + specifier: workspace:* + version: link:../../packages/core + '@univerjs/design': + specifier: workspace:* + version: link:../../packages/design + '@univerjs/engine-render': + specifier: workspace:* + version: link:../../packages/engine-render + '@univerjs/shared': + specifier: workspace:* + version: link:../../common/shared + '@univerjs/ui': + specifier: workspace:* + version: link:../../packages/ui + '@wendellhu/redi': + specifier: ^0.15.2 + version: 0.15.5 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + less: + specifier: ^4.2.0 + version: 4.2.0 + react: + specifier: 18.3.1 + version: 18.3.1 + rxjs: + specifier: ^7.8.1 + version: 7.8.1 + typescript: + specifier: ^5.4.5 + version: 5.5.3 + vite: + specifier: ^5.2.11 + version: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.5)(terser@5.31.1) + vitest: + specifier: ^1.6.0 + version: 1.6.0(@types/node@20.14.9)(happy-dom@13.3.8)(jsdom@24.1.0)(less@4.2.0)(sass@1.77.5)(terser@5.31.1) + packages/core: dependencies: '@univerjs/protocol': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7b57b4ca0a0..b8502a4abfd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,5 @@ packages: - common/* - packages/* + - packages-experimental/* - examples From 39d5f364bc734fb8427fa83398ade817f43cd182 Mon Sep 17 00:00:00 2001 From: Wenzhao Hu <12122021+wzhudev@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:51:55 +0800 Subject: [PATCH 2/4] fix: fix uni bootstrapping --- .../controllers/uniui-desktop.controller.tsx | 10 +++++-- packages-experimental/uniui/src/plugin.ts | 16 +++++----- packages/ui/src/ui-plugin.ts | 29 +++++++------------ 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx b/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx index 1930e2ffb15..0440e651ea1 100644 --- a/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx +++ b/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx @@ -15,7 +15,7 @@ */ import { Disposable, LifecycleService, LifecycleStages, toDisposable } from '@univerjs/core'; -import type { IWorkbenchOptions } from '@univerjs/ui'; +import type { IUniverUIConfig, IWorkbenchOptions } from '@univerjs/ui'; import { BuiltInUIPart, CanvasPopup, FloatDom, IUIPartsService } from '@univerjs/ui'; import type { IDisposable } from '@wendellhu/redi'; import { Inject, Injector } from '@wendellhu/redi'; @@ -30,17 +30,21 @@ const STEADY_TIMEOUT = 3000; export class UniverUniUIController extends Disposable { constructor( + private readonly _config: IUniverUIConfig, @Inject(Injector) private readonly _injector: Injector, @Inject(LifecycleService) private readonly _lifecycleService: LifecycleService, @IUIPartsService private readonly _uiPartsService: IUIPartsService ) { super(); + this._initBuiltinComponents(); + + Promise.resolve().then(() => this._bootstrapWorkbench()); } - bootstrapWorkbench(options: IWorkbenchOptions): void { + private _bootstrapWorkbench(): void { this.disposeWithMe( - bootstrap(this._injector, options, () => { + bootstrap(this._injector, this._config, () => { this._lifecycleService.lifecycle$.pipe( filter((lifecycle) => lifecycle === LifecycleStages.Ready), delay(300), diff --git a/packages-experimental/uniui/src/plugin.ts b/packages-experimental/uniui/src/plugin.ts index d353ec5de15..afda4382d84 100644 --- a/packages-experimental/uniui/src/plugin.ts +++ b/packages-experimental/uniui/src/plugin.ts @@ -100,7 +100,6 @@ export class UniverUniUIPlugin extends Plugin { const dependencies: Dependency[] = mergeOverrideWithDependencies([ [ComponentManager], [ZIndexManager], - [ShortcutPanelService], [UnitGridService], [IUIPartsService, { useClass: UIPartsService }], @@ -124,13 +123,16 @@ export class UniverUniUIPlugin extends Plugin { [ICanvasPopupService, { useClass: CanvasPopupService }], [IProgressService, { useClass: ProgressService }], [CanvasFloatDomService], - - // This line is different from the original UI plugin. - [IUIController, { useClass: UniverUniUIController }], - - [SharedController, { useFactory: () => this._injector.createInstance(SharedController, this._config) }], + [IUIController, { + useFactory: () => this._injector.createInstance(UniverUniUIController, this._config), + }], + [SharedController, { + useFactory: () => this._injector.createInstance(SharedController, this._config), + }], [ErrorController], - [ShortcutPanelController, { useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config) }], + [ShortcutPanelController, { + useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config), + }], ], this._config.override); dependencies.forEach((dependency) => injector.add(dependency)); } diff --git a/packages/ui/src/ui-plugin.ts b/packages/ui/src/ui-plugin.ts index 0306885c4cf..75decfbc3c1 100644 --- a/packages/ui/src/ui-plugin.ts +++ b/packages/ui/src/ui-plugin.ts @@ -107,27 +107,18 @@ export class UniverUIPlugin extends Plugin { [ICanvasPopupService, { useClass: CanvasPopupService }], [IProgressService, { useClass: ProgressService }], [CanvasFloatDomService], - - // controllers - [ - IUIController, { - useFactory: (injector: Injector) => injector.createInstance(DesktopUIController, this._config), - deps: [Injector], - }, - ], - [ - SharedController, - { - useFactory: () => this._injector.createInstance(SharedController, this._config), - }, + [IUIController, { + useFactory: (injector: Injector) => injector.createInstance(DesktopUIController, this._config), + deps: [Injector], + }, ], + [SharedController, { + useFactory: () => this._injector.createInstance(SharedController, this._config), + }], [ErrorController], - [ - ShortcutPanelController, - { - useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config), - }, - ], + [ShortcutPanelController, { + useFactory: () => this._injector.createInstance(ShortcutPanelController, this._config), + }], ], this._config.override); dependencies.forEach((dependency) => injector.add(dependency)); } From 125f507a0c0a6c2b67157a24eb5a40fe9c0ed7c0 Mon Sep 17 00:00:00 2001 From: Wenzhao Hu <12122021+wzhudev@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:22:07 +0800 Subject: [PATCH 3/4] fix: fix floating components --- packages-experimental/uniui/package.json | 6 +++++- .../uniui/src/controllers/uniui-desktop.controller.tsx | 2 +- .../uniui/src/views/workbench/UniWorkbench.tsx | 6 ++++-- pnpm-lock.yaml | 3 +++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages-experimental/uniui/package.json b/packages-experimental/uniui/package.json index b69552c2e17..804e40a8f02 100644 --- a/packages-experimental/uniui/package.json +++ b/packages-experimental/uniui/package.json @@ -1,6 +1,6 @@ { "name": "@univerjs/uniui", - "version": "0.0.1", + "version": "0.2.1", "private": true, "description": "", "author": "DreamNum ", @@ -67,6 +67,7 @@ "@wendellhu/redi": ">=0.12.13", "clsx": ">=2.0.0", "react": ">=16.9.0", + "react-dom": "18.3.1", "rxjs": ">=7.0.0" }, "dependencies": { @@ -74,6 +75,8 @@ "rc-util": "^5.43.0" }, "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "@univerjs/core": "workspace:*", "@univerjs/design": "workspace:*", "@univerjs/engine-render": "workspace:*", @@ -83,6 +86,7 @@ "clsx": "^2.1.1", "less": "^4.2.0", "react": "18.3.1", + "react-dom": "18.3.1", "rxjs": "^7.8.1", "typescript": "^5.4.5", "vite": "^5.2.11", diff --git a/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx b/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx index 0440e651ea1..d75e6d720fa 100644 --- a/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx +++ b/packages-experimental/uniui/src/controllers/uniui-desktop.controller.tsx @@ -58,7 +58,7 @@ export class UniverUniUIController extends Disposable { } private _initBuiltinComponents() { - this.disposeWithMe(this._uiPartsService.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(CanvasPopup, this._injector))); + this.disposeWithMe(this._uiPartsService.registerComponent(BuiltInUIPart.FLOATING, () => connectInjector(CanvasPopup, this._injector))); this.disposeWithMe(this._uiPartsService.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(FloatDom, this._injector))); } } diff --git a/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx b/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx index 9fef22eb0f0..70e5442a7de 100644 --- a/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx +++ b/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx @@ -17,7 +17,7 @@ // Refer to packages/ui/src/views/App.tsx import { IUniverInstanceService, LocaleService, ThemeService } from '@univerjs/core'; -import { ConfigProvider, defaultTheme, themeInstance } from '@univerjs/design'; +import { ConfigContext, ConfigProvider, defaultTheme, themeInstance } from '@univerjs/design'; import type { ILocale } from '@univerjs/design'; import { builtInGlobalComponents, @@ -33,7 +33,8 @@ import { ZenZone, } from '@univerjs/ui'; import { useDependency } from '@wendellhu/redi/react-bindings'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { createPortal } from 'react-dom'; import clsx from 'clsx'; import { UnitGridService } from '../../services/unit-grid/unit-grid.service'; import styles from './workbench.module.less'; @@ -181,6 +182,7 @@ export function UniWorkbench(props: IUniWorkbenchProps) { {contextMenu && } + ); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8eac1cf2c35..322646e480e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -425,6 +425,9 @@ importers: react: specifier: 18.3.1 version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) rxjs: specifier: ^7.8.1 version: 7.8.1 From 6869b958800e7c218107b8ef90380b2dac4b2569 Mon Sep 17 00:00:00 2001 From: Wenzhao Hu <12122021+wzhudev@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:26:06 +0800 Subject: [PATCH 4/4] fix: fix lock file --- pnpm-lock.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 322646e480e..42f5b218b57 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -398,6 +398,12 @@ importers: specifier: ^5.43.0 version: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) devDependencies: + '@types/react': + specifier: ^18.3.3 + version: 18.3.3 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 '@univerjs/core': specifier: workspace:* version: link:../../packages/core