diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a19e69b7b0d..00c13f64c38 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,7 +52,7 @@ pnpm dev ### Architecture -Please refer to the [architecture doc](https://github.com/dream-num/univer/wiki/Univer-Architecture). +Please refer to [Architecture](https://univer.ai/guides/sheet/architecture/univer), and also [ISOMORPHIC.md](./docs/ISOMORPHIC.md) for more guidance on how to set up plugins. ### Source code organization diff --git a/README-zh.md b/README-zh.md index 2a538bb7106..885eaa32e6b 100644 --- a/README-zh.md +++ b/README-zh.md @@ -47,12 +47,14 @@ ## 🌈 亮点 - 📈 **支持多种类文档** Univer 目前支持**电子表格**和**富文本文档**,未来还会增加对**幻灯片**的支持。 +- 🧙‍♀️ **多端同构** 可以在浏览器和 Node.js 环境中运行。 - ⚙️ **易于集成** Univer 能够无缝集成到你的应用当中。 - 🎇 **功能强大** Univer 支持非常多的功能,包括但不限于**公式计算**、**条件格式**、**数据验证**、**筛选**、**协同编辑**、**打印**、**导入导出**等等,更多的功能即将陆续发布。 -- 🔌 **高度可扩展**Univer 的 *插件化架构* 和 *Facade API* 使得扩展 Univer 的功能变得轻松容易,你可以在 Univer 之上实现自己的业务需求。 +- 🔌 **高度可扩展** Univer 的*插件化架构*使得扩展 Univer 的功能变得轻松容易,你可以在 Univer 之上实现自己的业务需求。 - 💄 **高度可定制** 你可以通过*主题*来自定义 Univer 的外观,另外还支持国际化。 +- 🥤 **易于使用** *Presets* 和 *Facade API* 使得 Univer 很容易上手 - ⚡ **性能优越** - - ✏️ Univer 实现了基于 canvas 的 *渲染引擎*,能够高效地渲染不同类型的文档。渲染引擎支持 *标点挤压* *盘古之白* *图文混排* *滚动贴图* 等高级特性。 + - ✏️ Univer 实现了基于 canvas 的*渲染引擎*,能够高效地渲染不同类型的文档。渲染引擎支持 *标点挤压* *盘古之白* *图文混排* *滚动贴图* 等高级特性。 - 🧮 自研的 *公式引擎* 拥有超快的计算速度,还能在 Web Worker 中运行,未来将会支持服务端计算。 - 🌌 **高度集成** 文档、电子表格和幻灯片能够互操作,甚至是渲染在同一个画布上,使得信息和数据能够在 Univer 当中自由地流动。 @@ -76,12 +78,12 @@ Univer 提供了丰富的电子表格、文档和幻灯片功能。以下是一 - **评论**:允许向单元格添加评论以提供额外信息。 - **十字高亮**:支持在电子表格中显示十字高亮,以帮助用户快速定位选中的单元格。 - **数据透视表**[^1]:支持数据透视表,允许用户对数据进行汇总和分析。 -- **协同编辑**[^1]:支持多个用户同时编辑电子表格。 +- **协同编辑**[^1]:支持多个用户同时编辑电子表格,同时支持历史记录与恢复。 - **打印**[^1]:允许打印电子表格或将其导出为 PDF。 - **导入和导出**[^1]:支持导入导出 XLSX 格式的数据。 - **图表**[^2]:由 [VChart][vchart-link] 支持第三方图表。 -### 📝 Univer Doc(积极开发中) +### 📝 Univer Doc(beta 测试中) - **核心功能**:Univer 支持文档的核心功能,包括段落、标题、列表、上标、下标等。 - **列表**:支持有序列表、无序列表和任务列表。 diff --git a/README.md b/README.md index c3eda8709d8..8ab8e4eb21c 100644 --- a/README.md +++ b/README.md @@ -47,10 +47,12 @@ Extensible. High-performance. Embedded to your application. ## 🌈 Highlights - 📈 Univer is designed to support **spreadsheets**, **documents** and **presentation**. +- 🧙‍♀️ Univer is **isomorphic**. It can run both on browsers and Node.js (in the future, mobile devices as well), with the same API. - ⚙️ Univer is easily **embeddable**, allowing seamless integration into your applications. - 🎇 Univer is **powerful**, offering a wide range of features including **formulas**, **conditional formatting**, **data validation**, **filtering**, **collaborative editing**, **printing**, **import & export** and more features on the horizon. -- 🔌 Univer is **highly extensible**, thanks to its *plug-in architecture* and *Facade API* that makes it a delight for developers to implement their unique requirements on the top of Univer. +- 🔌 Univer is **highly extensible**, thanks to its *plug-in architecture* that makes it a delight for developers to implement their unique requirements on the top of Univer. - 💄 Univer is **highly customizable**, allowing you to personalize its appearance using *themes*. It also provides support for internationalization (i18n). +- 🥤 Univer is **easy to work with**. The *Presets* & *Facade API* make it easy to hands on. - ⚡ Univer in **performant**. - ✏️ Univer boasts an efficient *rendering engine* based on canvas, capable of rendering various document types flawlessly. The rendering engines supports advanced typesetting features such as *punctuation squeezing*, *text and image layout* and *scroll buffering*. - 🧮 Univer incorporates a lightning-fast *formula engine* that can operate in Web Workers or even on the server side. @@ -76,12 +78,12 @@ Univer provides a wide range of features for spreadsheets, documents and present - **Comments**: Enables adding comments to cells to provide additional information. - **Cross-highlighting**: Supports displaying cross-highlighting in spreadsheets to help users quickly locate selected cells. - **Pivot Tables**[^1]: Supports pivot tables, allowing users to summarize and analyze data. -- **Collaborative Editing**[^1]: Supports multiple users editing a spreadsheet simultaneously. +- **Collaborative Editing**[^1]: Supports multiple users editing a spreadsheet simultaneously. File history and recovering are also provided. - **Printing**[^1]: Allows printing a spreadsheet or exporting it to PDF. - **Import & Export**[^1]: Support for importing and exporting data in XLSX. - **Charts**[^2]: Third-party chart support via [VChart][vchart-link]. -### 📝 Univer Doc (Under Development) +### 📝 Univer Doc (beta) - **Core Features**: Univer supports core document features, including paragraphs, headings, lists, superscript, subscript, and more. - **Lists**: Supports ordered lists, unordered lists, and task lists. @@ -107,7 +109,7 @@ Univer supports multiple languages, including: - `vi-VN` - `fa-IR` -`zh-CN` and `en-US` are officially supported, while the others are contributed by the community. +`zh-CN` and `en-US` are officially supported, while the others are contributed and maintained by the community. You can add the language you want by [Using Custom Locales](https://univer.ai/guides/sheet/getting-started/i18n#using-custom-locales). You can also help us add new language support by referring to the [contribution guide](./CONTRIBUTING.md). @@ -133,6 +135,11 @@ You can find all the examples in the [Univer Examples](https://univer.ai/example Univer has a rich ecosystem that includes a wide range of tools and resources to help you get started with Univer: --> +## 🔗 Links + +- [Official Site](https://univer.ai) +- [Presets Repository](https://github.com/dream-num/univer-presets) + ## 💬 Community [![][github-community-badge]][github-community-link] [![][discord-community-badge]][discord-community-link] [![][stackoverflow-community-badge]][stackoverflow-community-link] diff --git a/common/shared/package.json b/common/shared/package.json index 8d6ac18313e..91253420791 100644 --- a/common/shared/package.json +++ b/common/shared/package.json @@ -24,6 +24,7 @@ "javascript-obfuscator": "^4.1.1", "vite": "^5.4.8", "vite-plugin-dts": "^4.2.3", + "vite-plugin-external": "^4.3.1", "vitest": "^2.1.2" } } diff --git a/common/shared/vite/index.js b/common/shared/vite/index.js index 0484cb3cb4b..3ab50883872 100644 --- a/common/shared/vite/index.js +++ b/common/shared/vite/index.js @@ -19,6 +19,7 @@ const process = require('node:process'); const react = require('@vitejs/plugin-react'); const { default: dts } = require('vite-plugin-dts'); +const vitePluginExternal = require('vite-plugin-external'); const { defineConfig, mergeConfig } = require('vitest/config'); const { autoExternalizeDependency } = require('./auto-externalize-dependency-plugin'); const { buildPkg } = require('./build-pkg'); @@ -61,6 +62,9 @@ function createViteConfig(overrideConfig, /** @type {IOptions} */ options) { }, plugins: [ autoExternalizeDependency(), + vitePluginExternal({ + nodeBuiltins: true, // exclude Node.js builtins from bundling + }), dts({ entryRoot: 'src', outDir: 'lib/types', diff --git a/docs/ISOMOPHIC.md b/docs/ISOMOPHIC.md new file mode 100644 index 00000000000..fb3dbf0b4cf --- /dev/null +++ b/docs/ISOMOPHIC.md @@ -0,0 +1,34 @@ +# Building Isomorphic Univer + +Univer is an isomorphic (full-stack) framework for building productivity tools, which means **support of Node.js is +at the same priority as browsers**. + +To make your code aligned with the isomorphic architecture, please pay +attention to the following points: + +## Separate Plugins + +If the feature your are developing both needs to run on the server and the client, you should separate the feature into +at least two plugins. One for the underlying logic and the other for the UI. + +The underlying logic often includes: models, commands and mutations to modify the data, and services to manage the data. + +The UI includes menus, shortcuts, React components, Canvas elements, or other modules that depend on the browser environment. + +For example, the filter feature is split into two plugins: `sheets-filter` and `sheets-filter-ui`. + +Some modules rely on Node.js-only API such as `fs`, `path`, `child_process`, etc. These modules should be +implemented in another server-only plugin. + +## Separate Facade API + +**The Facade API is designed to be used by both the server and the client**. It should be implemented in each plugins and +composed by users (or the `@univerjs/presets` package) to provide a unified +API for the SDK. + +You should implement the Facade API that can run on Node.js and the browser in the underlying logic plugins. + +## Consider Implementing Commands in the Underlying Logic + +Commands and especially those of type `MUTATION` should be implemented in the underlying logic plugins, and should not +read UI status directly to ensure that they can run on both Node.js and browsers. diff --git a/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts b/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts index 8cb85904340..2c836e8dcc7 100644 --- a/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts +++ b/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts @@ -31,8 +31,9 @@ test('diff default sheet toolbar', async () => { const page = await context.newPage(); await page.goto('http://localhost:3000/sheets/'); await page.waitForTimeout(2000); + await page.evaluate(() => window.E2EControllerAPI.loadDefaultSheet()); - await page.waitForTimeout(2000); + await page.waitForTimeout(8000); const filename = generateSnapshotName('default-sheet-fullpage'); const screenshot = await page.screenshot({ diff --git a/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/default-sheet-fullpage-chromium-linux.png b/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/default-sheet-fullpage-chromium-linux.png index 224c1642a58..49b312ab8df 100644 Binary files a/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/default-sheet-fullpage-chromium-linux.png and b/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/default-sheet-fullpage-chromium-linux.png differ diff --git a/examples-node/esbuild.config.mjs b/examples-node/esbuild.config.mjs index 33bcaf468b4..7e17e433ecf 100644 --- a/examples-node/esbuild.config.mjs +++ b/examples-node/esbuild.config.mjs @@ -23,11 +23,13 @@ const ctx = await esbuild[args.watch ? 'context' : 'build']({ bundle: true, color: true, sourcemap: args.watch, - minify: true, + minify: false, target: 'chrome70', entryPoints: [ './src/cases/basic.ts', + './src/sdk/worker.ts', ], + platform: 'node', outdir: './dist', define, }); diff --git a/examples-node/src/cases/basic.ts b/examples-node/src/cases/basic.ts index 1fc1625d573..05953b44168 100644 --- a/examples-node/src/cases/basic.ts +++ b/examples-node/src/cases/basic.ts @@ -14,12 +14,33 @@ * limitations under the License. */ -import type { IWorkbookData, Workbook } from '@univerjs/core'; -import { UniverInstanceType } from '@univerjs/core'; +import process from 'node:process'; +import { awaitTime, FUniver } from '@univerjs/core'; import { createUniverOnNode } from '../sdk'; -const univer = createUniverOnNode(); +import '../sdk/facade'; -univer.createUnit(UniverInstanceType.UNIVER_SHEET, {}); +// From now on, Univer is a full-stack SDK. -// TODO: Facade API here +async function run(): Promise { + const API = FUniver.newAPI(createUniverOnNode()); + const univerSheet = API.createUniverSheet({}); + + const a1 = univerSheet.getActiveSheet().getRange('A1'); + await a1.setValue({ v: 123 }); + + const b1 = univerSheet.getActiveSheet().getRange('B1'); + await b1.setValue({ f: '=SUM(A1) * 6' }); + + await awaitTime(500); + + // eslint-disable-next-line no-console + console.log('Debug, formula value', b1.getCellData()?.v); + + // eslint-disable-next-line no-console + console.log(univerSheet.save()); + + process.exit(0); +} + +run(); diff --git a/packages/sheets-hyper-link-ui/src/types/interfaces/i-sheet-hyper-link-info.ts b/examples-node/src/sdk/facade.ts similarity index 62% rename from packages/sheets-hyper-link-ui/src/types/interfaces/i-sheet-hyper-link-info.ts rename to examples-node/src/sdk/facade.ts index 0fa5ba43571..5ba94c3f48b 100644 --- a/packages/sheets-hyper-link-ui/src/types/interfaces/i-sheet-hyper-link-info.ts +++ b/examples-node/src/sdk/facade.ts @@ -14,14 +14,11 @@ * limitations under the License. */ -import type { Nullable } from '@univerjs/core'; -import type { SheetHyperLinkType } from '@univerjs/sheets-hyper-link'; -import type { ISheetUrlParams } from './i-sheet-url-params'; +// Facade API here are part of packages/facade/src/apis/everything.ts +// However some plugins are implemented incorrectly, so they are not included here. -export interface ISheetHyperLinkInfo { - type: SheetHyperLinkType; - name: string; - url: string; - searchObj: Nullable; - handler: () => void; -} +import '@univerjs/sheets/facade'; +import '@univerjs/sheets-data-validation/facade'; +import '@univerjs/engine-formula/facade'; +import '@univerjs/sheets-filter/facade'; +import '@univerjs/sheets-formula/facade'; diff --git a/examples-node/src/sdk/index.ts b/examples-node/src/sdk/index.ts index 5f01c616834..4779c67a672 100644 --- a/examples-node/src/sdk/index.ts +++ b/examples-node/src/sdk/index.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import type { IMessageProtocol } from '@univerjs/rpc'; -import type { Serializable } from 'node:child_process'; -import { fork } from 'node:child_process'; import path from 'node:path'; import { Univer } from '@univerjs/core'; import { UniverDataValidationPlugin } from '@univerjs/data-validation'; @@ -30,16 +27,16 @@ import { UniverSheetsConditionalFormattingPlugin } from '@univerjs/sheets-condit import { UniverSheetsDataValidationPlugin } from '@univerjs/sheets-data-validation'; import { UniverSheetsDrawingPlugin } from '@univerjs/sheets-drawing'; import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; +import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link'; import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort'; import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'; -import { Observable, shareReplay } from 'rxjs'; export function createUniverOnNode(): Univer { const univer = new Univer(); registerBasicPlugins(univer); - reigsterSharedPlugins(univer); + registerSharedPlugins(univer); registerRPCPlugin(univer); registerDocPlugins(univer); @@ -52,7 +49,7 @@ function registerBasicPlugins(univer: Univer): void { univer.registerPlugin(UniverFormulaEnginePlugin, { notExecuteFormula: true }); } -function reigsterSharedPlugins(univer: Univer): void { +function registerSharedPlugins(univer: Univer): void { univer.registerPlugin(UniverThreadCommentPlugin); univer.registerPlugin(UniverDrawingPlugin); } @@ -64,6 +61,7 @@ function registerDocPlugins(univer: Univer): void { function registerSheetPlugins(univer: Univer): void { univer.registerPlugin(UniverSheetsPlugin); + univer.registerPlugin(UniverSheetsFormulaPlugin); univer.registerPlugin(UniverSheetsConditionalFormattingPlugin); univer.registerPlugin(UniverDataValidationPlugin); univer.registerPlugin(UniverSheetsDataValidationPlugin); @@ -74,20 +72,6 @@ function registerSheetPlugins(univer: Univer): void { } function registerRPCPlugin(univer: Univer): void { - const childFork = fork(path.join(__dirname, './worker.js')); - const messageProtocol: IMessageProtocol = { - send(message: unknown): void { - childFork.send(message as Serializable); - }, - onMessage: new Observable((subscriber) => { - const handler = (message: unknown) => { - subscriber.next(message); - }; - - childFork.on('message', handler); - return () => childFork.off('message', handler); - }).pipe(shareReplay(1)), - }; - - univer.registerPlugin(UniverRPCNodeMainPlugin, { messageProtocol }); + const childPath = path.join(__dirname, '../sdk/worker.js'); + univer.registerPlugin(UniverRPCNodeMainPlugin, { workerSrc: childPath }); } diff --git a/examples/package.json b/examples/package.json index 9a51650070d..a52b15668c0 100644 --- a/examples/package.json +++ b/examples/package.json @@ -28,7 +28,6 @@ "@univerjs/drawing-ui": "workspace:*", "@univerjs/engine-formula": "workspace:*", "@univerjs/engine-render": "workspace:*", - "@univerjs/facade": "workspace:*", "@univerjs/find-replace": "workspace:*", "@univerjs/icons": "^0.1.84", "@univerjs/mockdata": "workspace:*", @@ -49,10 +48,11 @@ "@univerjs/sheets-hyper-link": "workspace:*", "@univerjs/sheets-hyper-link-ui": "workspace:*", "@univerjs/sheets-numfmt": "workspace:*", + "@univerjs/sheets-numfmt-ui": "workspace:*", "@univerjs/sheets-sort": "workspace:*", "@univerjs/sheets-sort-ui": "workspace:*", "@univerjs/sheets-thread-comment": "workspace:*", - "@univerjs/sheets-thread-comment-base": "workspace:*", + "@univerjs/sheets-thread-comment-ui": "workspace:*", "@univerjs/sheets-ui": "workspace:*", "@univerjs/sheets-zen-editor": "workspace:*", "@univerjs/slides": "workspace:*", diff --git a/examples/src/docs/main.ts b/examples/src/docs/main.ts index 17a36f67b63..0f36562fb29 100644 --- a/examples/src/docs/main.ts +++ b/examples/src/docs/main.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { LocaleType, LogLevel, Univer, UniverInstanceType, UserManagerService } from '@univerjs/core'; +import { FUniver, LocaleType, LogLevel, Univer, UniverInstanceType, UserManagerService } from '@univerjs/core'; import { UniverDebuggerPlugin } from '@univerjs/debugger'; import { defaultTheme } from '@univerjs/design'; import { UniverDocsPlugin } from '@univerjs/docs'; @@ -25,7 +25,6 @@ import { UniverDocsThreadCommentUIPlugin } from '@univerjs/docs-thread-comment-u import { UniverDocsUIPlugin } from '@univerjs/docs-ui'; import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; -import { FUniver } from '@univerjs/facade'; import { DEFAULT_DOCUMENT_DATA_CN } from '@univerjs/mockdata'; import { UniverUIPlugin } from '@univerjs/ui'; import { enUS, faIR, ruRU, zhCN } from '../locales'; diff --git a/examples/src/mobile-s/main.ts b/examples/src/mobile-s/main.ts index 50d9f09f6d7..c281ec561b6 100644 --- a/examples/src/mobile-s/main.ts +++ b/examples/src/mobile-s/main.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { FUniver } from '@univerjs/facade'; +import type { FUniver } from '@univerjs/core'; import type { IUniverRPCMainThreadConfig } from '@univerjs/rpc'; import { LocaleType, LogLevel, Univer, UniverInstanceType, UserManagerService } from '@univerjs/core'; import { defaultTheme } from '@univerjs/design'; diff --git a/examples/src/sheets-multi/main.tsx b/examples/src/sheets-multi/main.tsx index 948a342ee79..70c7673d292 100644 --- a/examples/src/sheets-multi/main.tsx +++ b/examples/src/sheets-multi/main.tsx @@ -25,6 +25,7 @@ import { DEFAULT_WORKBOOK_DATA_DEMO } from '@univerjs/mockdata'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; +import { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; import { UniverUIPlugin } from '@univerjs/ui'; import React, { useEffect } from 'react'; @@ -63,6 +64,7 @@ function factory(id: string) { // sheet feature plugins univer.registerPlugin(UniverSheetsNumfmtPlugin); + univer.registerPlugin(UniverSheetsNumfmtUIPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); // create univer sheet instance diff --git a/examples/src/sheets-uniscript/main.ts b/examples/src/sheets-uniscript/main.ts index fac05bcbe8b..182c21222e6 100644 --- a/examples/src/sheets-uniscript/main.ts +++ b/examples/src/sheets-uniscript/main.ts @@ -25,6 +25,7 @@ import { UNISCRIT_WORKBOOK_DATA_DEMO } from '@univerjs/mockdata'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; +import { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; import { UniverUIPlugin } from '@univerjs/ui'; import { UniverUniscriptPlugin } from '@univerjs/uniscript'; @@ -59,6 +60,7 @@ univer.registerPlugin(UniverSheetsUIPlugin); // sheet feature plugins univer.registerPlugin(UniverSheetsNumfmtPlugin); +univer.registerPlugin(UniverSheetsNumfmtUIPlugin); univer.registerPlugin(UniverDebuggerPlugin); univer.registerPlugin(UniverFormulaEnginePlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); diff --git a/examples/src/sheets/main.ts b/examples/src/sheets/main.ts index 596c27d1f08..e0970077198 100644 --- a/examples/src/sheets/main.ts +++ b/examples/src/sheets/main.ts @@ -16,15 +16,13 @@ import type { Nullable } from '@univerjs/core'; import type { IUniverRPCMainThreadConfig } from '@univerjs/rpc'; -import type { IThreadCommentMentionDataSource } from '@univerjs/thread-comment-ui'; -import { LocaleType, LogLevel, Univer, UniverInstanceType, UserManagerService } from '@univerjs/core'; +import { FUniver, LocaleType, LogLevel, Univer, UniverInstanceType, UserManagerService } from '@univerjs/core'; import { UniverDebuggerPlugin } from '@univerjs/debugger'; import { defaultTheme } from '@univerjs/design'; import { UniverDocsPlugin } from '@univerjs/docs'; import { UniverDocsUIPlugin } from '@univerjs/docs-ui'; import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; -import { FUniver } from '@univerjs/facade'; import { DEFAULT_WORKBOOK_DATA_DEMO } from '@univerjs/mockdata'; import { UniverRPCMainThreadPlugin } from '@univerjs/rpc'; import { UniverSheetsPlugin } from '@univerjs/sheets'; @@ -36,12 +34,26 @@ import { UniverSheetsFormulaUIPlugin } from '@univerjs/sheets-formula-ui'; import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link'; import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort'; -import { IThreadCommentMentionDataService, UniverSheetsThreadCommentPlugin, UniverThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment'; +import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment'; +import { UniverSheetsThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment-ui'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; import { UniverSheetsZenEditorPlugin } from '@univerjs/sheets-zen-editor'; +import { IThreadCommentMentionDataService, type IThreadCommentMentionDataSource, UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; import { UniverUIPlugin } from '@univerjs/ui'; import { enUS, faIR, ruRU, viVN, zhCN, zhTW } from '../locales'; +import '@univerjs/sheets/facade'; +import '@univerjs/ui/facade'; +import '@univerjs/docs-ui/facade'; +import '@univerjs/sheets-ui/facade'; +import '@univerjs/sheets-data-validation/facade'; +import '@univerjs/engine-formula/facade'; +import '@univerjs/sheets-filter/facade'; +import '@univerjs/sheets-formula/facade'; +import '@univerjs/sheets-numfmt/facade'; +import '@univerjs/sheets-hyper-link-ui/facade'; +import '@univerjs/sheets-thread-comment/facade'; + /* eslint-disable-next-line node/prefer-global/process */ const IS_E2E: boolean = !!process.env.IS_E2E; @@ -118,6 +130,7 @@ univer.registerPlugin(UniverThreadCommentUIPlugin, { overrides: [[IThreadCommentMentionDataService, { useClass: CustomMentionDataService }]], }); univer.registerPlugin(UniverSheetsThreadCommentPlugin); +univer.registerPlugin(UniverSheetsThreadCommentUIPlugin); // If we are running in e2e platform, we should immediately register the debugger plugin. if (IS_E2E) { diff --git a/examples/src/uni/main.ts b/examples/src/uni/main.ts index ead32bcc425..5a3fd4b6f47 100644 --- a/examples/src/uni/main.ts +++ b/examples/src/uni/main.ts @@ -17,7 +17,7 @@ import type { Nullable } from '@univerjs/core'; import type { IUniverRPCMainThreadConfig } from '@univerjs/rpc'; import type { IThreadCommentMentionDataSource } from '@univerjs/thread-comment-ui'; -import { Injector, LocaleType, LogLevel, Univer, UniverInstanceType } from '@univerjs/core'; +import { FUniver, Injector, LocaleType, LogLevel, Univer, UniverInstanceType } from '@univerjs/core'; import { UniverDebuggerPlugin } from '@univerjs/debugger'; import { defaultTheme } from '@univerjs/design'; import { UniverDocsPlugin } from '@univerjs/docs'; @@ -25,7 +25,6 @@ import { UniverDocsDrawingUIPlugin } from '@univerjs/docs-drawing-ui'; import { DocUIController, UniverDocsUIPlugin } from '@univerjs/docs-ui'; import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; -import { FUniver } from '@univerjs/facade'; import { DEFAULT_DOCUMENT_DATA_CN, DEFAULT_DOCUMENT_DATA_EN, DEFAULT_SLIDE_DATA, DEFAULT_WORKBOOK_DATA_DEMO, DEFAULT_WORKBOOK_DATA_DEMO1 } from '@univerjs/mockdata'; import { UniverRPCMainThreadPlugin } from '@univerjs/rpc'; import { UniverSheetsPlugin } from '@univerjs/sheets'; @@ -35,6 +34,7 @@ import { UniverSheetsFindReplacePlugin } from '@univerjs/sheets-find-replace'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; import { UniverSheetsHyperLinkUIPlugin } from '@univerjs/sheets-hyper-link-ui'; import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; +import { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui'; import { UniverSheetsSortUIPlugin } from '@univerjs/sheets-sort-ui'; import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment'; import { SheetUIController, UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; @@ -167,6 +167,7 @@ function registerSheetPlugins(univer: Univer) { ], }); univer.registerPlugin(UniverSheetsNumfmtPlugin); + univer.registerPlugin(UniverSheetsNumfmtUIPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); univer.registerPlugin(UniverSheetsFindReplacePlugin); univer.registerPlugin(UniverSheetsHyperLinkUIPlugin); diff --git a/mockdata/package.json b/mockdata/package.json index 495b264a3d7..084b5e549f5 100644 --- a/mockdata/package.json +++ b/mockdata/package.json @@ -75,7 +75,7 @@ "@univerjs/sheets-formula": "workspace:*", "@univerjs/sheets-hyper-link": "workspace:*", "@univerjs/sheets-sort": "workspace:*", - "@univerjs/sheets-thread-comment-base": "workspace:*", + "@univerjs/sheets-thread-comment": "workspace:*", "@univerjs/thread-comment": "workspace:*" }, "devDependencies": { diff --git a/packages-experimental/action-recorder/package.json b/packages-experimental/action-recorder/package.json index 693f4afe1f0..4dc639f1d57 100644 --- a/packages-experimental/action-recorder/package.json +++ b/packages-experimental/action-recorder/package.json @@ -67,7 +67,7 @@ "@univerjs/design": "workspace:*", "@univerjs/icons": "^0.1.84", "@univerjs/sheets": "workspace:*", - "@univerjs/sheets-filter-ui": "workspace:*", + "@univerjs/sheets-filter": "workspace:*", "@univerjs/sheets-ui": "workspace:*", "@univerjs/ui": "workspace:*", "clsx": "^2.1.1" diff --git a/packages-experimental/action-recorder/src/controllers/action-recorder.controller.tsx b/packages-experimental/action-recorder/src/controllers/action-recorder.controller.tsx index f79cb30b699..d20ec2176e8 100644 --- a/packages-experimental/action-recorder/src/controllers/action-recorder.controller.tsx +++ b/packages-experimental/action-recorder/src/controllers/action-recorder.controller.tsx @@ -20,6 +20,7 @@ import { AddWorksheetMergeAllCommand, AddWorksheetMergeCommand, AddWorksheetMergeHorizontalCommand, AddWorksheetMergeVerticalCommand, + CancelFrozenCommand, CopySheetCommand, DeleteRangeMoveLeftCommand, DeleteRangeMoveUpCommand, @@ -31,7 +32,6 @@ import { AddWorksheetMergeAllCommand, InsertRowBeforeCommand, InsertSheetCommand, RemoveSheetCommand, - SetFrozenCancelCommand, SetFrozenCommand, SetHorizontalTextAlignCommand, SetOverlineCommand, @@ -47,7 +47,7 @@ import { AddWorksheetMergeAllCommand, SetWorksheetActivateCommand, SetWorksheetActiveOperation, } from '@univerjs/sheets'; -import { RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand } from '@univerjs/sheets-filter-ui'; +import { RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand } from '@univerjs/sheets-filter'; import { SetRangeBoldCommand, SetRangeFontFamilyCommand, SetRangeFontSizeCommand, @@ -142,8 +142,8 @@ export class ActionRecorderController extends Disposable { // SetBoldCommand, // SetFontFamilyCommand, // SetFontSizeCommand, - SetFrozenCancelCommand, SetFrozenCommand, + CancelFrozenCommand, SetHorizontalTextAlignCommand, // SetItalicCommand, SetOverlineCommand, diff --git a/packages-experimental/debugger/package.json b/packages-experimental/debugger/package.json index 706fcfa5d60..c3611ecb7a3 100644 --- a/packages-experimental/debugger/package.json +++ b/packages-experimental/debugger/package.json @@ -61,7 +61,6 @@ "@univerjs/core": "workspace:*", "@univerjs/docs-ui": "workspace:*", "@univerjs/engine-render": "workspace:*", - "@univerjs/facade": "workspace:*", "@univerjs/mockdata": "workspace:*", "@univerjs/sheets": "workspace:*", "@univerjs/sheets-drawing-ui": "workspace:*", diff --git a/packages-experimental/debugger/src/commands/commands/unit.command.ts b/packages-experimental/debugger/src/commands/commands/unit.command.ts index cd21403894a..0a3c1afa466 100644 --- a/packages-experimental/debugger/src/commands/commands/unit.command.ts +++ b/packages-experimental/debugger/src/commands/commands/unit.command.ts @@ -14,10 +14,9 @@ * limitations under the License. */ +import type { FUniver, ICommand, IWorkbookData, Univer, Workbook } from '@univerjs/core'; import { CommandType, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { ILocalFileService } from '@univerjs/ui'; -import type { ICommand, IWorkbookData, Univer, Workbook } from '@univerjs/core'; -import type { FUniver } from '@univerjs/facade'; declare global { // eslint-disable-next-line ts/naming-convention diff --git a/packages-experimental/uni-formula-ui/src/commands/commands/doc.command.ts b/packages-experimental/uni-formula-ui/src/commands/commands/doc.command.ts index f9da06673b9..a3010071a8e 100644 --- a/packages-experimental/uni-formula-ui/src/commands/commands/doc.command.ts +++ b/packages-experimental/uni-formula-ui/src/commands/commands/doc.command.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { BuildTextUtils, CommandType, CustomRangeType, generateRandomId, ICommandService, LocaleService, makeCustomRangeStream, sequenceExecute } from '@univerjs/core'; -import { replaceSelectionFactory } from '@univerjs/docs-ui'; -import { AddDocUniFormulaMutation, RemoveDocUniFormulaMutation, UpdateDocUniFormulaMutation } from '@univerjs/uni-formula'; import type { ICommand, IDocumentBody, IMutationInfo } from '@univerjs/core'; import type { IAddDocUniFormulaMutationParams, IRemoveDocUniFormulaMutationParams, IUpdateDocUniFormulaMutationParams } from '@univerjs/uni-formula'; +import { BuildTextUtils, CommandType, CustomRangeType, generateRandomId, ICommandService, LocaleService, makeCustomRangeStream, sequenceExecute } from '@univerjs/core'; +import { replaceSelectionFactory } from '@univerjs/docs'; +import { AddDocUniFormulaMutation, RemoveDocUniFormulaMutation, UpdateDocUniFormulaMutation } from '@univerjs/uni-formula'; export interface IAddDocUniFormulaCommandParams { unitId: string; diff --git a/packages-experimental/uni-formula-ui/src/commands/commands/slide.command.ts b/packages-experimental/uni-formula-ui/src/commands/commands/slide.command.ts index cf62b28244a..4abe34b92eb 100644 --- a/packages-experimental/uni-formula-ui/src/commands/commands/slide.command.ts +++ b/packages-experimental/uni-formula-ui/src/commands/commands/slide.command.ts @@ -14,10 +14,10 @@ * limitations under the License. */ +import type { ICommand, IDocumentBody } from '@univerjs/core'; import { BuildTextUtils, CommandType, CustomRangeType, generateRandomId, ICommandService, LocaleService, makeCustomRangeStream } from '@univerjs/core'; -import { replaceSelectionFactory } from '@univerjs/docs-ui'; +import { replaceSelectionFactory } from '@univerjs/docs'; import { SLIDE_EDITOR_ID } from '@univerjs/slides-ui'; -import type { ICommand, IDocumentBody } from '@univerjs/core'; import { SlideUIFormulaCacheService } from '../../services/slide-ui-formula-cache.service'; export interface IAddSlideUniFormulaCommandParams { diff --git a/packages-experimental/uni-formula-ui/src/services/uni-formula.service.ts b/packages-experimental/uni-formula-ui/src/services/uni-formula.service.ts index 9fe66557bae..d33363c4898 100644 --- a/packages-experimental/uni-formula-ui/src/services/uni-formula.service.ts +++ b/packages-experimental/uni-formula-ui/src/services/uni-formula.service.ts @@ -14,6 +14,15 @@ * limitations under the License. */ +import type { + DocumentDataModel, + ICellData, + ICommand, + IDisposable, + IDocumentBody, + Nullable, + SlideDataModel } from '@univerjs/core'; +import type { IDocFormulaCache, ISlideFormulaCache } from '@univerjs/uni-formula'; import { BuildTextUtils, CommandType, @@ -29,22 +38,13 @@ import { toDisposable, UniverInstanceType, } from '@univerjs/core'; -import { replaceSelectionFactory } from '@univerjs/docs-ui'; +import { replaceSelectionFactory } from '@univerjs/docs'; import { RichText } from '@univerjs/engine-render'; import { DataSyncPrimaryController } from '@univerjs/rpc'; import { RegisterOtherFormulaService } from '@univerjs/sheets-formula'; import { CanvasView } from '@univerjs/slides-ui'; import { DumbUniFormulaService, IUniFormulaService } from '@univerjs/uni-formula'; import { take } from 'rxjs'; -import type { - DocumentDataModel, - ICellData, - ICommand, - IDisposable, - IDocumentBody, - Nullable, - SlideDataModel } from '@univerjs/core'; -import type { IDocFormulaCache, ISlideFormulaCache } from '@univerjs/uni-formula'; import { type IDocPopupPosition, type ISlidePopupPosition, isSlidePosition } from '../commands/operations/operation'; const PSEUDO_SUBUNIT = 'PSEUDO_SUBUNIT'; diff --git a/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx b/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx index d4510eb4da6..5dc77085ac3 100644 --- a/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx +++ b/packages-experimental/uniui/src/views/workbench/UniWorkbench.tsx @@ -16,9 +16,16 @@ // Refer to packages/ui/src/views/App.tsx -import { debounce, ICommandService, IContextService, IUniverInstanceService, LocaleService, ThemeService, useDependency } from '@univerjs/core'; import type { ILocale } from '@univerjs/design'; +import type { + NodeTypes, + ReactFlowInstance, + Viewport, +} from '@xyflow/react'; +import { debounce, ICommandService, IContextService, IUniverInstanceService, LocaleService, ThemeService, useDependency } from '@univerjs/core'; import { ConfigContext, ConfigProvider, defaultTheme, themeInstance } from '@univerjs/design'; +import { IRenderManagerService } from '@univerjs/engine-render'; +import { MenuSingle } from '@univerjs/icons'; import { builtInGlobalComponents, BuiltInUIPart, @@ -30,11 +37,6 @@ import { useComponentsOfPart, useObservable, } from '@univerjs/ui'; -import type { - NodeTypes, - ReactFlowInstance, - Viewport, -} from '@xyflow/react'; import { Background, NodeResizer, @@ -42,13 +44,10 @@ import { ReactFlowProvider, useNodesState, } from '@xyflow/react'; -import '@xyflow/react/dist/style.css'; import clsx from 'clsx'; import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; -import { createPortal } from 'react-dom'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { MenuSingle } from '@univerjs/icons'; +import { createPortal } from 'react-dom'; import { UniFocusUnitOperation } from '../../commands/operations/uni-focus-unit.operation'; import { FlowManagerService } from '../../services/flow/flow-manager.service'; import { IUnitGridService } from '../../services/unit-grid/unit-grid.service'; @@ -58,6 +57,7 @@ import { LeftSidebar, RightSidebar } from '../uni-sidebar/UniSidebar'; import { type IFloatingToolbarRef, UniFloatingToolbar } from '../uni-toolbar/UniFloatToolbar'; import { UniToolbar } from '../uni-toolbar/UniToolbar'; import styles from './workbench.module.less'; +import '@xyflow/react/dist/style.css'; // Refer to packages/ui/src/views/workbench/Workbench.tsx export interface IUniWorkbenchProps extends IWorkbenchOptions { @@ -119,7 +119,7 @@ export function UniWorkbench(props: IUniWorkbenchProps) { }, [commandService]); // eslint-disable-next-line react-hooks/exhaustive-deps const resizeUnits = useCallback(debounce(() => { - renderManagerService.getRenderAll().forEach(((renderer) => renderer.engine.resize())); + renderManagerService.getRenderAll().forEach((renderer) => renderer.engine.resize()); }, 400), [renderManagerService]); // TODO: this is not // Create a portal container for injecting global component themes. diff --git a/packages/core/src/docs/data-model/utils.ts b/packages/core/src/docs/data-model/utils.ts new file mode 100644 index 00000000000..3a0ac71613c --- /dev/null +++ b/packages/core/src/docs/data-model/utils.ts @@ -0,0 +1,138 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IStyleBase, ITextRotation } from '../../types/interfaces'; +import { getDefaultBaselineOffset, VERTICAL_ROTATE_ANGLE } from '../../sheets/util'; +import { DEFAULT_STYLES } from '../../types/const'; +import { BaselineOffset, BooleanNumber } from '../../types/enum'; +import { FontStyleType } from '../../types/interfaces'; + +export const DEFAULT_FONTFACE_PLANE = + '"Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif'; + +export interface IDocumentSkeletonFontStyle { + fontString: string; + fontSize: number; + originFontSize: number; + fontFamily: string; + fontCache: string; +} + +// eslint-disable-next-line max-lines-per-function +export function getFontStyleString( + textStyle?: IStyleBase +): IDocumentSkeletonFontStyle { + const defaultFont = DEFAULT_STYLES.ff; + + const defaultFontSize = DEFAULT_STYLES.fs; + + if (!textStyle) { + const fontString = `${defaultFontSize}pt ${defaultFont}`; + + return { + fontCache: fontString, + fontString, + fontSize: defaultFontSize, + originFontSize: defaultFontSize, + fontFamily: defaultFont, + }; + } + + // font-style + let italic = FontStyleType.ITALIC; + if (textStyle.it === 0 || textStyle.it === undefined) { + italic = FontStyleType.NORMAL; + } + + // font-variant + // font += `${FontStyleType.NORMAL} `; + + // font-weight + let bold = FontStyleType.BOLD; + if (textStyle.bl === 0 || textStyle.bl === undefined) { + bold = FontStyleType.NORMAL; + } + + // font-size/line-height + let originFontSize = defaultFontSize; + if (textStyle.fs) { + originFontSize = Math.ceil(textStyle.fs); + } + + let fontFamilyResult = defaultFont; + if (textStyle.ff) { + let fontFamily = textStyle.ff; + + fontFamily = fontFamily.replace(/"/g, '').replace(/'/g, ''); + + if (fontFamily.indexOf(' ') > -1) { + fontFamily = `"${fontFamily}"`; + } + + // if (fontFamily != null && document.fonts && !document.fonts.check('12px ' + fontFamily)) { + // menuButton.addFontToList(fontFamily); + // } + + if (fontFamily == null) { + fontFamily = defaultFont; + } + + fontFamilyResult = fontFamily; + } + + const { va: baselineOffset } = textStyle; + + let fontSize = originFontSize; + if ( + baselineOffset === BaselineOffset.SUBSCRIPT || + baselineOffset === BaselineOffset.SUPERSCRIPT + ) { + const baselineOffsetInfo = getBaselineOffsetInfo(fontFamilyResult, fontSize); + const { sbr, spr } = baselineOffsetInfo; + + fontSize *= baselineOffset === BaselineOffset.SUBSCRIPT ? sbr : spr; + } + + const fontStringPure = `${italic} ${bold} ${fontSize}pt ${fontFamilyResult}`; + + const fontString = `${fontStringPure}, ${DEFAULT_FONTFACE_PLANE} `; + + return { + fontCache: fontStringPure, + fontString, + fontSize, + originFontSize, + fontFamily: fontFamilyResult, + }; +} + +export function getBaselineOffsetInfo(_fontFamily: string, fontSize: number) { + // The origin FontCache.getBaselineOffsetInfo needs _fontDataMap + // But now _fontDataMap didn't not set value. So we can use getDefault. + return getDefaultBaselineOffset(fontSize); +} + +export function convertTextRotation(textRotation?: ITextRotation) { + const { a: angle = 0, v: isVertical = BooleanNumber.FALSE } = textRotation || { a: 0, v: BooleanNumber.FALSE }; + let centerAngle = 0; + let vertexAngle = angle; + if (isVertical === BooleanNumber.TRUE) { + centerAngle = VERTICAL_ROTATE_ANGLE; + vertexAngle = VERTICAL_ROTATE_ANGLE; + } + + return { centerAngle, vertexAngle }; +} diff --git a/packages/core/src/facade/f-base.ts b/packages/core/src/facade/f-base.ts new file mode 100644 index 00000000000..b81ba0d10a2 --- /dev/null +++ b/packages/core/src/facade/f-base.ts @@ -0,0 +1,53 @@ +/** + * 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. + */ + +/** + * `FBase` is a base class for all facade classes. + * It provides a way to extend classes with static and instance methods. + * The `_initialize` as a special method that will be called after the constructor. You should never call it directly. + */ +export abstract class FBase { + private static _constructorQueue: Array<() => void> = []; + + constructor() { + // eslint-disable-next-line ts/no-this-alias + const self = this; + FBase._constructorQueue.forEach(function (fn) { + fn.apply(self); + }); + } + + _initialize() { } + + static extend(source: any): void { + Object.getOwnPropertyNames(source.prototype).forEach((name) => { + if (name === '_initialize') { + FBase._constructorQueue.push(source.prototype._initialize); + } else if (name !== 'constructor') { + // @ts-ignore + this.prototype[name] = source.prototype[name]; + } + }); + + Object.getOwnPropertyNames(source).forEach((name) => { + if (name !== 'prototype' && name !== 'name' && name !== 'length') { + // @ts-ignore + this[name] = source[name]; + } + }); + } +} + diff --git a/packages/facade/src/apis/f-hooks.ts b/packages/core/src/facade/f-hooks.ts similarity index 53% rename from packages/facade/src/apis/f-hooks.ts rename to packages/core/src/facade/f-hooks.ts index b71bfc0438f..b71e05a37b4 100644 --- a/packages/facade/src/apis/f-hooks.ts +++ b/packages/core/src/facade/f-hooks.ts @@ -14,18 +14,23 @@ * limitations under the License. */ -import type { IDisposable } from '@univerjs/core'; -import { Inject, Injector, LifecycleService, LifecycleStages, toDisposable } from '@univerjs/core'; +import type { IDisposable } from '../common/di'; +import type { IUndoRedoItem } from '../services/undoredo/undoredo.service'; import { filter } from 'rxjs'; -import { FClipboardHooks } from './hooks/f-clipboard-hooks'; -import { FUndoRedoHooks } from './hooks/f-undoredo-hooks'; +import { Inject, Injector } from '../common/di'; +import { ICommandService } from '../services/command/command.service'; +import { LifecycleStages } from '../services/lifecycle/lifecycle'; +import { LifecycleService } from '../services/lifecycle/lifecycle.service'; +import { IUndoRedoService, RedoCommand, UndoCommand } from '../services/undoredo/undoredo.service'; +import { toDisposable } from '../shared/lifecycle'; +import { FBase } from './f-base'; -export class FHooks { +export class FHooks extends FBase { constructor( @Inject(Injector) protected readonly _injector: Injector, @Inject(LifecycleService) private readonly _lifecycleService: LifecycleService ) { - // empty + super(); } /** @@ -64,59 +69,79 @@ export class FHooks { return toDisposable(this._lifecycleService.lifecycle$.pipe(filter((lifecycle) => lifecycle === LifecycleStages.Steady)).subscribe(callback)); } - /** - * Hook that fires before an undo operation is executed. - * @param callback Function to be called when the event is triggered - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeUndo = FUndoRedoHooks.beforeUndo.bind(this); + /** + * Hook that fires before an undo operation is executed. + * @param callback Function to be called when the event is triggered + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeUndo(callback: (action: IUndoRedoItem) => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.beforeCommandExecuted((command) => { + if (command.id === UndoCommand.id) { + const undoredoService = this._injector.get(IUndoRedoService); + const action = undoredoService.pitchTopUndoElement(); + if (action) { + callback(action); + } + } + }); + } /** * Hook that fires after an undo operation is executed. * @param callback Function to be called when the event is triggered * @returns A disposable object that can be used to unsubscribe from the event */ - onUndo = FUndoRedoHooks.afterUndo.bind(this); + onUndo(callback: (action: IUndoRedoItem) => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.onCommandExecuted((command) => { + if (command.id === UndoCommand.id) { + const undoredoService = this._injector.get(IUndoRedoService); + const action = undoredoService.pitchTopUndoElement(); + if (action) { + callback(action); + } + } + }); + } /** * Hook that fires before a redo operation is executed. * @param callback Function to be called when the event is triggered * @returns A disposable object that can be used to unsubscribe from the event */ - onBeforeRedo = FUndoRedoHooks.beforeRedo.bind(this); + onBeforeRedo(callback: (action: IUndoRedoItem) => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.beforeCommandExecuted((command) => { + if (command.id === RedoCommand.id) { + const undoredoService = this._injector.get(IUndoRedoService); + const action = undoredoService.pitchTopRedoElement(); + if (action) { + callback(action); + } + } + }); + } /** * Hook that fires after a redo operation is executed. * @param callback Function to be called when the event is triggered * @returns A disposable object that can be used to unsubscribe from the event */ - onRedo = FUndoRedoHooks.afterRedo.bind(this); - - /** - * The onBeforeCopy event is fired before a copy operation is performed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeCopy = FClipboardHooks.onBeforeCopy.bind(this); + onRedo(callback: (action: IUndoRedoItem) => void): IDisposable { + const commandService = this._injector.get(ICommandService); - /** - * The onCopy event is fired after a copy operation is performed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onCopy = FClipboardHooks.onCopy.bind(this); - - /** - * The onBeforePaste event is fired before a paste operation is performed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforePaste = FClipboardHooks.onBeforePaste.bind(this); - - /** - * The onPaste event is fired after a paste operation is performed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onPaste = FClipboardHooks.onPaste.bind(this); + return commandService.onCommandExecuted((command) => { + if (command.id === RedoCommand.id) { + const undoredoService = this._injector.get(IUndoRedoService); + const action = undoredoService.pitchTopRedoElement(); + if (action) { + callback(action); + } + } + }); + } } diff --git a/packages/core/src/facade/f-univer.ts b/packages/core/src/facade/f-univer.ts new file mode 100644 index 00000000000..662c38c6a5a --- /dev/null +++ b/packages/core/src/facade/f-univer.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 type { IDisposable } from '../common/di'; +import type { CommandListener, IExecutionOptions } from '../services/command/command.service'; +import type { LifecycleStages } from '../services/lifecycle/lifecycle'; +import { Inject, Injector } from '../common/di'; +import { ICommandService } from '../services/command/command.service'; +import { IUniverInstanceService } from '../services/instance/instance.service'; +import { LifecycleService } from '../services/lifecycle/lifecycle.service'; +import { RedoCommand, UndoCommand } from '../services/undoredo/undoredo.service'; +import { Univer } from '../univer'; +import { FBase } from './f-base'; +import { FHooks } from './f-hooks'; + +export class FUniver extends FBase { + /** + * Create an FUniver instance, if the injector is not provided, it will create a new Univer instance. + * + * @static + * + * @param {Univer | Injector} wrapped - The Univer instance or injector instance. + * @returns {FUniver} - The FUniver instance. + */ + static newAPI(wrapped: Univer | Injector): FUniver { + const injector = wrapped instanceof Univer ? wrapped.__getInjector() : wrapped; + return injector.createInstance(FUniver); + } + + constructor( + @Inject(Injector) protected readonly _injector: Injector, + @ICommandService protected readonly _commandService: ICommandService, + @IUniverInstanceService protected readonly _univerInstanceService: IUniverInstanceService + ) { + super(); + } + + /** + * Dispose the UniverSheet by the `unitId`. The UniverSheet would be unload from the application. + * + * @param unitId The unit id of the UniverSheet. + * @returns Whether the Univer instance is disposed successfully. + */ + disposeUnit(unitId: string): boolean { + return this._univerInstanceService.disposeUnit(unitId); + } + + /** + * Get the current lifecycle stage. + * + * @returns {LifecycleStages} - The current lifecycle stage. + */ + getCurrentLifecycleStage(): LifecycleStages { + const lifecycleService = this._injector.get(LifecycleService); + return lifecycleService.stage; + } + + /** + * Undo an editing on the currently focused document. + * + * @returns {Promise} undo result + */ + undo(): Promise { + return this._commandService.executeCommand(UndoCommand.id); + } + + /** + * Redo an editing on the currently focused document. + * + * @returns {Promise} redo result + */ + redo(): Promise { + return this._commandService.executeCommand(RedoCommand.id); + } + + /** + * Register a callback that will be triggered before invoking a command. + * + * @param {CommandListener} callback The callback. + * @returns {IDisposable} The disposable instance. + */ + onBeforeCommandExecute(callback: CommandListener): IDisposable { + return this._commandService.beforeCommandExecuted((command, options?: IExecutionOptions) => { + callback(command, options); + }); + } + + /** + * Register a callback that will be triggered when a command is invoked. + * + * @param {CommandListener} callback The callback. + * @returns {IDisposable} The disposable instance. + */ + onCommandExecuted(callback: CommandListener): IDisposable { + return this._commandService.onCommandExecuted((command, options?: IExecutionOptions) => { + callback(command, options); + }); + } + + /** + * Execute command + * + * @param {string} id Command ID + * @param {object} params Command parameters + * @param {IExecutionOptions} options Command execution options + * @returns {Promise} Command execution result + */ + executeCommand

( + id: string, + params?: P, + options?: IExecutionOptions + ): Promise { + return this._commandService.executeCommand(id, params, options); + } + + /** + * Get hooks. + * + * @returns {FHooks} FHooks instance + */ + getHooks(): FHooks { + return this._injector.createInstance(FHooks); + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 290fd4ebb5b..8135d99ee24 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -40,6 +40,9 @@ export { composeInterceptors, createInterceptorKey, InterceptorEffectEnum, Inter export type { Serializable } from './common/json'; export { MemoryCursor } from './common/memory-cursor'; export { mixinClass } from './common/mixin'; +export { FBase } from './facade/f-base'; +export { FUniver } from './facade/f-univer'; +export { FHooks } from './facade/f-hooks'; export { isNumeric, isSafeNumeric } from './common/number'; export { Registry, RegistryAsMap } from './common/registry'; export { requestImmediateMacroTask } from './common/request-immediate-macro-task'; @@ -141,7 +144,7 @@ export { isBlackColor, isWhiteColor } from './shared/color/color-kit'; export { cellToRange } from './shared/common'; export { getIntersectRange } from './shared/range'; export { nameCharacterCheck } from './shared/name'; -export { bufferDebounceTime, fromCallback, takeAfter } from './shared/rxjs'; +export { afterTime, bufferDebounceTime, fromCallback, takeAfter } from './shared/rxjs'; export { awaitTime } from './shared/timer'; export { Range } from './sheets/range'; export { diff --git a/packages/core/src/services/resource-loader/resource-loader.service.ts b/packages/core/src/services/resource-loader/resource-loader.service.ts index 24c877a69f9..0286bb6979e 100644 --- a/packages/core/src/services/resource-loader/resource-loader.service.ts +++ b/packages/core/src/services/resource-loader/resource-loader.service.ts @@ -14,17 +14,17 @@ * limitations under the License. */ -import { Inject } from '../../common/di'; +import type { DocumentDataModel } from '../../docs'; import type { Workbook } from '../../sheets/workbook'; import type { IResourceHook } from '../resource-manager/type'; -import { IResourceManagerService } from '../resource-manager/type'; -import { IUniverInstanceService } from '../instance/instance.service'; -import { Disposable } from '../../shared/lifecycle'; -import { UniverInstanceType } from '../../common/unit'; -import type { DocumentDataModel } from '../../docs'; +import type { IResourceLoaderService } from './type'; import { isInternalEditorID } from '../../common/const'; +import { Inject } from '../../common/di'; +import { UniverInstanceType } from '../../common/unit'; import { Tools } from '../../shared'; -import type { IResourceLoaderService } from './type'; +import { Disposable } from '../../shared/lifecycle'; +import { IUniverInstanceService } from '../instance/instance.service'; +import { IResourceManagerService } from '../resource-manager/type'; export class ResourceLoaderService extends Disposable implements IResourceLoaderService { constructor( @@ -103,9 +103,9 @@ export class ResourceLoaderService extends Disposable implements IResourceLoader ); this.disposeWithMe( - this._univerInstanceService.getTypeOfUnitDisposed$(UniverInstanceType.UNIVER_DOC).subscribe(((doc) => { + this._univerInstanceService.getTypeOfUnitDisposed$(UniverInstanceType.UNIVER_DOC).subscribe((doc) => { this._resourceManagerService.unloadResources(doc.getUnitId()); - })) + }) ); } diff --git a/packages/core/src/shared/__tests__/rxjs.spec.ts b/packages/core/src/shared/__tests__/rxjs.spec.ts index 1e90df1e256..293db08ea0b 100644 --- a/packages/core/src/shared/__tests__/rxjs.spec.ts +++ b/packages/core/src/shared/__tests__/rxjs.spec.ts @@ -15,8 +15,8 @@ */ import { of } from 'rxjs'; -import { describe, expect, it } from 'vitest'; -import { takeAfter } from '../rxjs'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { afterTime, takeAfter } from '../rxjs'; describe('test custom rxjs utils', () => { it('should terminate when a condition is met with "takeAfter"', () => { @@ -25,5 +25,38 @@ describe('test custom rxjs utils', () => { nums$.pipe(takeAfter((val) => val === 3)).subscribe((v) => acculated.push(v)); expect(acculated).toEqual([1, 2, 3]); }); + + describe('test "createTimerObservable$"', () => { + beforeEach(() => vi.useFakeTimers()); + + afterEach(() => vi.useRealTimers()); + + it('should emit after a period of time', async () => { + let fired = false; + + const ob1 = afterTime(2000); + ob1.subscribe(() => fired = true); + vi.advanceTimersByTime(1000); + expect(fired).toBeFalsy(); + vi.advanceTimersByTime(2000); + expect(fired).toBeTruthy(); + + fired = false; + ob1.subscribe(() => fired = true); + expect(fired).toBeTruthy(); + + fired = false; + const ob2 = afterTime(2000); + ob2.subscribe(() => fired = true); + vi.advanceTimersByTime(3000); + expect(fired).toBeTruthy(); + + fired = false; + const ob3 = afterTime(2000); + vi.advanceTimersByTime(3000); + ob3.subscribe(() => fired = true); + expect(fired).toBeTruthy(); + }); + }); }); diff --git a/packages/core/src/shared/rxjs.ts b/packages/core/src/shared/rxjs.ts index 6c82a7d25a7..ecd40e0f915 100644 --- a/packages/core/src/shared/rxjs.ts +++ b/packages/core/src/shared/rxjs.ts @@ -16,7 +16,7 @@ import type { OperatorFunction } from 'rxjs'; import type { IDisposable } from '../common/di'; -import { debounceTime, map, Observable, tap } from 'rxjs'; +import { debounceTime, map, Observable, ReplaySubject, take, tap } from 'rxjs'; type CallbackFn = (cb: (...args: T) => void) => IDisposable; @@ -70,3 +70,10 @@ export function bufferDebounceTime(time: number = 0): OperatorFunction { + const subject = new ReplaySubject(1); + setTimeout(() => subject.next(), ms); + return subject.pipe(take(1)); +} + diff --git a/packages/core/src/sheets/util.ts b/packages/core/src/sheets/util.ts index 6edb4be68f3..1b6ddc8b415 100644 --- a/packages/core/src/sheets/util.ts +++ b/packages/core/src/sheets/util.ts @@ -14,8 +14,15 @@ * limitations under the License. */ -import { Rectangle } from '../shared'; +import type { Nullable } from '../shared'; import type { IRange, IUnitRange } from './typedef'; +import { DEFAULT_EMPTY_DOCUMENT_VALUE } from '../common/const'; +import { BuildTextUtils, DocumentDataModel } from '../docs'; +import { TextX } from '../docs/data-model/text-x/text-x'; +import { convertTextRotation } from '../docs/data-model/utils'; +import { Rectangle } from '../shared'; +import { type CellValueType, HorizontalAlign, type TextDirection, VerticalAlign, WrapStrategy } from '../types/enum'; +import { CustomRangeType, type IDocumentData, type IPaddingData, type IStyleBase, type IStyleData, type ITextRotation, type ITextStyle } from '../types/interfaces'; export const isRangesEqual = (oldRanges: IRange[], ranges: IRange[]): boolean => { return ranges.length === oldRanges.length && !oldRanges.some((oldRange) => ranges.some((range) => !Rectangle.equals(range, oldRange))); @@ -28,3 +35,159 @@ export const isUnitRangesEqual = (oldRanges: IUnitRange[], ranges: IUnitRange[]) }); }; +export const DEFAULT_PADDING_DATA = { + t: 0, + b: 2, // must over 1, see https://github.com/dream-num/univer/issues/2727 + l: 2, + r: 2, +}; + +export const getDefaultBaselineOffset = (fontSize: number) => ({ + sbr: 0.6, + sbo: fontSize, + spr: 0.6, + spo: fontSize, +}); + +export interface ICellStyle { + textRotation?: ITextRotation; + textDirection?: Nullable; + horizontalAlign?: HorizontalAlign; + verticalAlign?: VerticalAlign; + wrapStrategy?: WrapStrategy; + paddingData?: IPaddingData; + cellValueType?: CellValueType; +} + +export const VERTICAL_ROTATE_ANGLE = 90; + +export function createDocumentModelWithStyle(content: string, textStyle: ITextStyle, config: ICellStyle = {}) { + const contentLength = content.length; + const { + textRotation, + paddingData = DEFAULT_PADDING_DATA, + horizontalAlign = HorizontalAlign.UNSPECIFIED, + verticalAlign = VerticalAlign.UNSPECIFIED, + wrapStrategy = WrapStrategy.UNSPECIFIED, + cellValueType, + } = config; + + const { t: marginTop, r: marginRight, b: marginBottom, l: marginLeft } = paddingData; + const { vertexAngle, centerAngle } = convertTextRotation(textRotation); + const documentData: IDocumentData = { + id: 'd', + body: { + dataStream: `${content}${DEFAULT_EMPTY_DOCUMENT_VALUE}`, + textRuns: [ + { + ts: textStyle, + st: 0, + ed: contentLength, + }, + ], + paragraphs: [ + { + startIndex: contentLength, + paragraphStyle: { + horizontalAlign, + }, + }, + ], + sectionBreaks: [{ + startIndex: contentLength + 1, + }], + }, + documentStyle: { + pageSize: { + width: Number.POSITIVE_INFINITY, + height: Number.POSITIVE_INFINITY, + }, + marginTop, + marginBottom, + marginRight, + marginLeft, + renderConfig: { + horizontalAlign, + verticalAlign, + centerAngle, + vertexAngle, + wrapStrategy, + cellValueType, + }, + }, + drawings: {}, + drawingsOrder: [], + }; + + return new DocumentDataModel(documentData); +} + +export function extractOtherStyle(style?: Nullable): ICellStyle { + if (!style) return {}; + const { + tr: textRotation, + td: textDirection, + ht: horizontalAlign, + vt: verticalAlign, + tb: wrapStrategy, + pd: paddingData, + } = style; + + return { + textRotation, + textDirection, + horizontalAlign, + verticalAlign, + wrapStrategy, + paddingData, + } as ICellStyle; +} + +/** + * Pick font style from cell style. + * @param format + * @returns {IStyleBase} style + */ +export function getFontFormat(format?: Nullable): IStyleBase { + if (!format) { + return {}; + } + const { ff, fs, it, bl, ul, st, ol, cl } = format; + const style: IStyleBase = {}; + ff && (style.ff = ff); + fs && (style.fs = fs); + it && (style.it = it); + bl && (style.bl = bl); + ul && (style.ul = ul); + st && (style.st = st); + ol && (style.ol = ol); + cl && (style.cl = cl); + return style; +} + +export function addLinkToDocumentModel(documentModel: DocumentDataModel, linkUrl: string, linkId: string): void { + const body = documentModel.getBody()!; + if (body.customRanges?.some((range) => range.rangeType === CustomRangeType.HYPERLINK)) { + return; + } + + const textX = BuildTextUtils.customRange.add({ + range: { + startOffset: 0, + endOffset: body.dataStream.length - 1, + collapsed: false, + }, + rangeId: linkId, + rangeType: CustomRangeType.HYPERLINK, + body, + properties: { + url: linkUrl, + refId: linkId, + }, + }); + if (!textX) { + return; + } + + TextX.apply(body, textX.serialize()); +} diff --git a/packages/core/src/sheets/worksheet.ts b/packages/core/src/sheets/worksheet.ts index 333383318fb..2e3fad9734c 100644 --- a/packages/core/src/sheets/worksheet.ts +++ b/packages/core/src/sheets/worksheet.ts @@ -15,20 +15,54 @@ */ import type { IObjectMatrixPrimitiveType, Nullable } from '../shared'; -import type { IStyleData } from '../types/interfaces'; +import type { IDocumentData, IDocumentRenderConfig, IPaddingData, IStyleData, ITextRotation } from '../types/interfaces'; import type { Styles } from './styles'; import type { ICellData, ICellDataForSheetInterceptor, IFreeze, IRange, ISelectionCell, IWorksheetData } from './typedef'; -import { BuildTextUtils } from '../docs'; +import { BuildTextUtils, DocumentDataModel } from '../docs'; +import { convertTextRotation, getFontStyleString } from '../docs/data-model/utils'; import { composeStyles, ObjectMatrix, Tools } from '../shared'; import { createRowColIter } from '../shared/row-col-iter'; -import { type BooleanNumber, CellValueType } from '../types/enum'; +import { DEFAULT_STYLES } from '../types/const'; +import { type BooleanNumber, CellValueType, type HorizontalAlign, type TextDirection, type VerticalAlign, type WrapStrategy } from '../types/enum'; import { ColumnManager } from './column-manager'; import { Range } from './range'; import { RowManager } from './row-manager'; import { mergeWorksheetSnapshotWithDefault } from './sheet-snapshot-utils'; import { SpanModel } from './span-model'; +import { addLinkToDocumentModel, createDocumentModelWithStyle, DEFAULT_PADDING_DATA, extractOtherStyle, getFontFormat } from './util'; import { SheetViewModel } from './view-model'; +export interface IDocumentLayoutObject { + documentModel: Nullable; + fontString: string; + textRotation: ITextRotation; + wrapStrategy: WrapStrategy; + verticalAlign: VerticalAlign; + horizontalAlign: HorizontalAlign; + paddingData: IPaddingData; + fill?: Nullable; +} +export interface ICellOtherConfig { + textRotation?: ITextRotation; + textDirection?: Nullable; + horizontalAlign?: HorizontalAlign; + verticalAlign?: VerticalAlign; + wrapStrategy?: WrapStrategy; + paddingData?: IPaddingData; + cellValueType?: CellValueType; +} + +export interface ICellDocumentModelOption { + isDeepClone?: boolean; + displayRawFormula?: boolean; + ignoreTextRotation?: boolean; +} + +const DEFAULT_CELL_DOCUMENT_MODEL_OPTION = { + isDeepClone: false, + displayRawFormula: false, + ignoreTextRotation: false, +}; /** * The model of a Worksheet. */ @@ -189,6 +223,7 @@ export class Worksheet { * Get worksheet printable cell range. * @returns */ + // eslint-disable-next-line max-lines-per-function getCellMatrixPrintRange() { const matrix = this.getCellMatrix(); const mergedCells = this.getMergeData(); @@ -201,6 +236,7 @@ export class Worksheet { let rowInitd = false; let columnInitd = false; matrix.forEach((rowIndex, row) => { + // eslint-disable-next-line complexity Object.keys(row).forEach((colIndexStr) => { const colIndex = +colIndexStr; const cellValue = matrix.getValue(rowIndex, colIndex); @@ -922,6 +958,200 @@ export class Worksheet { // #endregion } + + /** + * This method generates a document model based on the cell's properties and handles the associated styles and configurations. + * If the cell does not exist, it will return null. + * PS: This method has significant impact on performance. + * @param cell + * @param options + */ + // eslint-disable-next-line complexity, max-lines-per-function + private _getCellDocumentModel( + cell: Nullable, + options: ICellDocumentModelOption = DEFAULT_CELL_DOCUMENT_MODEL_OPTION + ): Nullable { + const { isDeepClone, displayRawFormula, ignoreTextRotation } = { + ...DEFAULT_CELL_DOCUMENT_MODEL_OPTION, + ...options, + }; + + const style = this._styles.getStyleByCell(cell); + + if (!cell) { + return; + } + + let documentModel: Nullable; + let fontString = 'document'; + const cellOtherConfig = extractOtherStyle(style); + + const textRotation: ITextRotation = ignoreTextRotation + ? DEFAULT_STYLES.tr + : cellOtherConfig.textRotation || DEFAULT_STYLES.tr; + let horizontalAlign: HorizontalAlign = cellOtherConfig.horizontalAlign || DEFAULT_STYLES.ht; + const verticalAlign: VerticalAlign = cellOtherConfig.verticalAlign || DEFAULT_STYLES.vt; + const wrapStrategy: WrapStrategy = cellOtherConfig.wrapStrategy || DEFAULT_STYLES.tb; + const paddingData: IPaddingData = cellOtherConfig.paddingData || DEFAULT_PADDING_DATA; + + if (cell.f && displayRawFormula) { + // The formula does not detect horizontal alignment and rotation. + documentModel = createDocumentModelWithStyle(cell.f.toString(), {}, { verticalAlign }); + horizontalAlign = DEFAULT_STYLES.ht; + } else if (cell.p) { + const { centerAngle, vertexAngle } = convertTextRotation(textRotation); + documentModel = this._updateConfigAndGetDocumentModel( + isDeepClone ? Tools.deepClone(cell.p) : cell.p, + horizontalAlign, + paddingData, + { + horizontalAlign, + verticalAlign, + centerAngle, + vertexAngle, + wrapStrategy, + } + ); + } else if (cell.v != null) { + const textStyle = getFontFormat(style); + fontString = getFontStyleString(textStyle).fontCache; + + let cellText = extractPureTextFromCell(cell); + + // Add a single quotation mark to the force string type. Don't add single quotation mark in extractPureTextFromCell, because copy and paste will be affected. + // edit mode when displayRawFormula is true + if (cell.t === CellValueType.FORCE_STRING && displayRawFormula) { + cellText = `'${cellText}`; + } + + documentModel = createDocumentModelWithStyle(cellText, textStyle, { + ...cellOtherConfig, + textRotation, + cellValueType: cell.t!, + }); + } + + // This is a compatible code. cc @weird94 + if (documentModel && cell.linkUrl && cell.linkId) { + addLinkToDocumentModel(documentModel, cell.linkUrl, cell.linkId); + } + + /** + * the alignment mode is returned with respect to the offset of the sheet cell, + * because the document needs to render the layout for cells and + * support alignment across multiple cells (e.g., horizontal alignment of long text in overflow mode). + * The alignment mode of the document itself cannot meet this requirement, + * so an additional renderConfig needs to be added during the rendering of the document component. + * This means that there are two coexisting alignment modes. + * In certain cases, such as in an editor, conflicts may arise, + * requiring only one alignment mode to be retained. + * By removing the relevant configurations in renderConfig, + * the alignment mode of the sheet cell can be modified. + * The alternative alignment mode is applied to paragraphs within the document. + */ + return { + documentModel, + fontString, + textRotation, + wrapStrategy, + verticalAlign, + horizontalAlign, + paddingData, + fill: style?.bg?.rgb, + }; + } + + private _updateConfigAndGetDocumentModel( + documentData: IDocumentData, + horizontalAlign: HorizontalAlign, + paddingData: IPaddingData, + renderConfig?: IDocumentRenderConfig + ): Nullable { + if (!renderConfig) { + return; + } + + if (!documentData.body?.dataStream) { + return; + } + + if (!documentData.documentStyle) { + documentData.documentStyle = {}; + } + + documentData.documentStyle.marginTop = paddingData.t ?? 0; + documentData.documentStyle.marginBottom = paddingData.b ?? 2; + documentData.documentStyle.marginLeft = paddingData.l ?? 2; + documentData.documentStyle.marginRight = paddingData.r ?? 2; + + // Fix https://github.com/dream-num/univer/issues/1586 + documentData.documentStyle.pageSize = { + width: Number.POSITIVE_INFINITY, + height: Number.POSITIVE_INFINITY, + }; + + documentData.documentStyle.renderConfig = renderConfig; + + const paragraphs = documentData.body.paragraphs || []; + + for (const paragraph of paragraphs) { + if (!paragraph.paragraphStyle) { + paragraph.paragraphStyle = {}; + } + + paragraph.paragraphStyle.horizontalAlign = horizontalAlign; + } + + return new DocumentDataModel(documentData); + } + + // Only used for cell edit, and no need to rotate text when edit cell content! + getBlankCellDocumentModel(cell: Nullable): IDocumentLayoutObject { + const documentModelObject = this._getCellDocumentModel(cell, { ignoreTextRotation: true }); + + const style = this._styles.getStyleByCell(cell); + const textStyle = getFontFormat(style); + + if (documentModelObject != null) { + if (documentModelObject.documentModel == null) { + documentModelObject.documentModel = createDocumentModelWithStyle('', textStyle); + } + return documentModelObject; + } + + const content = ''; + + let fontString = 'document'; + + const textRotation: ITextRotation = DEFAULT_STYLES.tr; + const horizontalAlign: HorizontalAlign = DEFAULT_STYLES.ht; + const verticalAlign: VerticalAlign = DEFAULT_STYLES.vt; + const wrapStrategy: WrapStrategy = DEFAULT_STYLES.tb; + const paddingData: IPaddingData = DEFAULT_PADDING_DATA; + + fontString = getFontStyleString({}).fontCache; + + const documentModel = createDocumentModelWithStyle(content, textStyle); + + return { + documentModel, + fontString, + textRotation, + wrapStrategy, + verticalAlign, + horizontalAlign, + paddingData, + }; + } + + // Only used for cell edit, and no need to rotate text when edit cell content! + getCellDocumentModelWithFormula(cell: ICellData): Nullable { + return this._getCellDocumentModel(cell, { + isDeepClone: true, + displayRawFormula: true, + ignoreTextRotation: true, + }); + } } /** diff --git a/packages/docs-hyper-link-ui/src/commands/commands/add-link.command.ts b/packages/docs-hyper-link-ui/src/commands/commands/add-link.command.ts index a0953149e66..f842301e3fd 100644 --- a/packages/docs-hyper-link-ui/src/commands/commands/add-link.command.ts +++ b/packages/docs-hyper-link-ui/src/commands/commands/add-link.command.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { CommandType, CustomRangeType, generateRandomId, ICommandService } from '@univerjs/core'; -import { addCustomRangeBySelectionFactory } from '@univerjs/docs-ui'; import type { ICommand, ITextRangeParam } from '@univerjs/core'; +import { CommandType, CustomRangeType, generateRandomId, ICommandService } from '@univerjs/core'; +import { addCustomRangeBySelectionFactory } from '@univerjs/docs'; export interface IAddDocHyperLinkCommandParams { payload: string; diff --git a/packages/docs-hyper-link-ui/src/commands/commands/delete-link.command.ts b/packages/docs-hyper-link-ui/src/commands/commands/delete-link.command.ts index a434de244d1..a9156fbc9b8 100644 --- a/packages/docs-hyper-link-ui/src/commands/commands/delete-link.command.ts +++ b/packages/docs-hyper-link-ui/src/commands/commands/delete-link.command.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { CommandType, ICommandService } from '@univerjs/core'; -import { deleteCustomRangeFactory } from '@univerjs/docs-ui'; import type { ICommand } from '@univerjs/core'; +import { CommandType, ICommandService } from '@univerjs/core'; +import { deleteCustomRangeFactory } from '@univerjs/docs'; export interface IDeleteDocHyperLinkMutationParams { unitId: string; diff --git a/packages/docs-hyper-link-ui/src/commands/commands/update-link.command.ts b/packages/docs-hyper-link-ui/src/commands/commands/update-link.command.ts index 0213dd7d21e..2badef80158 100644 --- a/packages/docs-hyper-link-ui/src/commands/commands/update-link.command.ts +++ b/packages/docs-hyper-link-ui/src/commands/commands/update-link.command.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { CommandType, CustomRangeType, DataStreamTreeTokenType, generateRandomId, getBodySlice, ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; -import { DocSelectionManagerService } from '@univerjs/docs'; -import { replaceSelectionFactory } from '@univerjs/docs-ui'; import type { DocumentDataModel, ICommand } from '@univerjs/core'; +import { CommandType, CustomRangeType, DataStreamTreeTokenType, generateRandomId, getBodySlice, ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { DocSelectionManagerService, replaceSelectionFactory } from '@univerjs/docs'; export interface IUpdateDocHyperLinkCommandParams { unitId: string; diff --git a/packages/docs-mention-ui/src/commands/commands/doc-mention.command.ts b/packages/docs-mention-ui/src/commands/commands/doc-mention.command.ts index 05f21d9343c..ad43ebe39ca 100644 --- a/packages/docs-mention-ui/src/commands/commands/doc-mention.command.ts +++ b/packages/docs-mention-ui/src/commands/commands/doc-mention.command.ts @@ -14,11 +14,10 @@ * limitations under the License. */ -import { CommandType, CustomRangeType, DataStreamTreeTokenType, ICommandService } from '@univerjs/core'; -import { DocSelectionManagerService } from '@univerjs/docs'; -import { deleteCustomRangeFactory, replaceSelectionFactory } from '@univerjs/docs-ui'; import type { ICommand, IDocumentBody } from '@univerjs/core'; import type { IDocMention } from '../../types/interfaces/i-mention'; +import { CommandType, CustomRangeType, DataStreamTreeTokenType, ICommandService } from '@univerjs/core'; +import { deleteCustomRangeFactory, DocSelectionManagerService, replaceSelectionFactory } from '@univerjs/docs'; export interface IAddDocMentionCommandParams { mention: IDocMention; diff --git a/packages/docs-thread-comment-ui/src/commands/operations/show-comment-panel.operation.ts b/packages/docs-thread-comment-ui/src/commands/operations/show-comment-panel.operation.ts index 6c424095086..3d8cbe31133 100644 --- a/packages/docs-thread-comment-ui/src/commands/operations/show-comment-panel.operation.ts +++ b/packages/docs-thread-comment-ui/src/commands/operations/show-comment-panel.operation.ts @@ -14,14 +14,15 @@ * limitations under the License. */ +import type { DocumentDataModel, ICommand } from '@univerjs/core'; +import type { ActiveCommentInfo } from '@univerjs/thread-comment-ui'; import { BuildTextUtils, CommandType, ICommandService, IUniverInstanceService, UniverInstanceType, UserManagerService } from '@univerjs/core'; import { DocSelectionManagerService } from '@univerjs/docs'; import { DocSelectionRenderService } from '@univerjs/docs-ui'; import { IRenderManagerService } from '@univerjs/engine-render'; -import { getDT, ThreadCommentPanelService } from '@univerjs/thread-comment-ui'; +import { getDT } from '@univerjs/thread-comment'; +import { ThreadCommentPanelService } from '@univerjs/thread-comment-ui'; import { ISidebarService } from '@univerjs/ui'; -import type { DocumentDataModel, ICommand } from '@univerjs/core'; -import type { ActiveCommentInfo } from '@univerjs/thread-comment-ui'; import { DEFAULT_DOC_SUBUNIT_ID } from '../../common/const'; import { DocThreadCommentService } from '../../services/doc-thread-comment.service'; import { DocThreadCommentPanel } from '../../views/doc-thread-comment-panel'; diff --git a/packages/docs-ui/package.json b/packages/docs-ui/package.json index 377de4ee7ea..2cd0f023b93 100644 --- a/packages/docs-ui/package.json +++ b/packages/docs-ui/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/facade/src/apis/docs/f-document.ts b/packages/docs-ui/src/facade/f-document.ts similarity index 92% rename from packages/facade/src/apis/docs/f-document.ts rename to packages/docs-ui/src/facade/f-document.ts index 1021bc77813..4ec9b8d4810 100644 --- a/packages/facade/src/apis/docs/f-document.ts +++ b/packages/docs-ui/src/facade/f-document.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import type { DocumentDataModel, IDocumentData } from '@univerjs/core'; import { DOC_RANGE_TYPE, ICommandService, Inject, Injector, @@ -23,9 +24,9 @@ import { DOC_RANGE_TYPE, ICommandService, UndoCommand, UniverInstanceType, } from '@univerjs/core'; -import { DocSelectionRenderService, InsertCommand } from '@univerjs/docs-ui'; import { IRenderManagerService } from '@univerjs/engine-render'; -import type { DocumentDataModel, IDocumentData } from '@univerjs/core'; +import { InsertCommand } from '../commands/commands/core-editing.command'; +import { DocSelectionRenderService } from '../services/selection/doc-selection-render.service'; export class FDocument { readonly id: string; @@ -126,11 +127,4 @@ export class FDocument { , true ); } - - // setHyperLink(linkUrl: string): FDocument; - // setHyperLink(startOffset: number, endOffset: number, linkUrl: string | null): FDocument { - // this._commandService.executeCommand( - // AddDocHyperLinkCommand.id, - // ) - // } } diff --git a/packages/docs-ui/src/facade/f-univer.ts b/packages/docs-ui/src/facade/f-univer.ts new file mode 100644 index 00000000000..d2c328bdabf --- /dev/null +++ b/packages/docs-ui/src/facade/f-univer.ts @@ -0,0 +1,73 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { DocumentDataModel, IDocumentData } from '@univerjs/core'; +import { FUniver, UniverInstanceType } from '@univerjs/core'; +import { FDocument } from './f-document'; + +interface IFUniverDocsUIMixin { + /** + * Create a new document and get the API handler of that document. + * + * @param {Partial} data The snapshot of the document. + * @returns {FDocument} FDocument API instance. + */ + createUniverDoc(data: Partial): FDocument; + /** + * Get the document API handler by the document id. + * + * @param {string} id The document id. + * @returns {FDocument | null} The document API instance. + */ + getUniverDoc(id: string): FDocument | null; + /** + * Get the currently focused Univer document. + * + * @returns {FDocument | null} The currently focused Univer document. + */ + getActiveDocument(): FDocument | null; +} + +export class FUniverDocsMixin extends FUniver implements IFUniverDocsUIMixin { + override createUniverDoc(data: Partial): FDocument { + const document = this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_DOC, data); + return this._injector.createInstance(FDocument, document); + } + + override getActiveDocument(): FDocument | null { + const document = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); + if (!document) { + return null; + } + + return this._injector.createInstance(FDocument, document); + } + + override getUniverDoc(id: string): FDocument | null { + const document = this._univerInstanceService.getUniverDocInstance(id); + if (!document) { + return null; + } + + return this._injector.createInstance(FDocument, document); + } +} + +FUniver.extend(FUniverDocsMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverDocsUIMixin {} +} diff --git a/packages/sheets-numfmt/src/context/user-habit.ts b/packages/docs-ui/src/facade/index.ts similarity index 84% rename from packages/sheets-numfmt/src/context/user-habit.ts rename to packages/docs-ui/src/facade/index.ts index 191a283285a..ebb5050f51d 100644 --- a/packages/sheets-numfmt/src/context/user-habit.ts +++ b/packages/docs-ui/src/facade/index.ts @@ -14,6 +14,6 @@ * limitations under the License. */ -import { createContext } from 'react'; +import './f-univer'; -export const UserHabitCurrencyContext = createContext([]); +export { FDocument } from './f-document'; diff --git a/packages/docs-ui/src/index.ts b/packages/docs-ui/src/index.ts index 1dd3e98c194..465b9dc8e68 100644 --- a/packages/docs-ui/src/index.ts +++ b/packages/docs-ui/src/index.ts @@ -19,10 +19,8 @@ export * from './basics'; export type { IDocObjectParam } from './basics/component-tools'; export { getDocObject, getDocObjectById, neoGetDocObject } from './basics/component-tools'; export { addCustomDecorationBySelectionFactory, addCustomDecorationFactory, deleteCustomDecorationFactory } from './basics/custom-decoration-factory'; -export { addCustomRangeBySelectionFactory, addCustomRangeFactory, deleteCustomRangeFactory } from './basics/custom-range-factory'; export * from './basics/docs-view-key'; export { hasParagraphInTable } from './basics/paragraph'; -export { replaceSelectionFactory } from './basics/replace'; export { docDrawingPositionToTransform, transformToDocDrawingPosition } from './basics/transform-position'; export { getCommandSkeleton, getRichTextEditPath } from './commands/util'; diff --git a/packages/docs/src/index.ts b/packages/docs/src/index.ts index cea2bcb681e..66530a5d2aa 100644 --- a/packages/docs/src/index.ts +++ b/packages/docs/src/index.ts @@ -20,7 +20,8 @@ export { DocInterceptorService } from './services/doc-interceptor/doc-intercepto export { DOC_INTERCEPTOR_POINT } from './services/doc-interceptor/interceptor-const'; export { DocSelectionManagerService } from './services/doc-selection-manager.service'; export { DocSkeletonManagerService } from './services/doc-skeleton-manager.service'; - +export { addCustomRangeBySelectionFactory, addCustomRangeFactory, deleteCustomRangeFactory } from './utils/custom-range-factory'; +export { replaceSelectionFactory } from './utils/replace-selection-factory'; export type { IDocStateChangeInfo, IDocStateChangeParams } from './services/doc-state-emit.service'; export { DocStateEmitService } from './services/doc-state-emit.service'; diff --git a/packages/docs-ui/src/basics/custom-range-factory.ts b/packages/docs/src/utils/custom-range-factory.ts similarity index 88% rename from packages/docs-ui/src/basics/custom-range-factory.ts rename to packages/docs/src/utils/custom-range-factory.ts index bbc12ba6594..f3d8103391a 100644 --- a/packages/docs-ui/src/basics/custom-range-factory.ts +++ b/packages/docs/src/utils/custom-range-factory.ts @@ -18,12 +18,34 @@ import type { CustomRangeType, DocumentDataModel, IAccessor, IAddCustomRangeText import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import { BuildTextUtils, IUniverInstanceService, JSONX, UniverInstanceType } from '@univerjs/core'; import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; -import { getRichTextEditPath } from '../commands/util'; interface IAddCustomRangeParam extends IAddCustomRangeTextXParam { unitId: string; } +/** + * @deprecated This is a duplication from docs-ui to avoid making too much breaking changes. + */ +export function getRichTextEditPath(docDataModel: DocumentDataModel, segmentId = '') { + if (!segmentId) { + return ['body']; + } + + const { headers, footers } = docDataModel.getSnapshot(); + + if (headers == null && footers == null) { + throw new Error('Document data model must have headers or footers when update by segment id'); + } + + if (headers?.[segmentId] != null) { + return ['headers', segmentId, 'body']; + } else if (footers?.[segmentId] != null) { + return ['footers', segmentId, 'body']; + } else { + throw new Error('Segment id not found in headers or footers'); + } +} + export function addCustomRangeFactory(accessor: IAccessor, param: IAddCustomRangeParam, body: IDocumentBody) { const { unitId, segmentId } = param; const univerInstanceService = accessor.get(IUniverInstanceService); diff --git a/packages/docs-ui/src/basics/replace.ts b/packages/docs/src/utils/replace-selection-factory.ts similarity index 95% rename from packages/docs-ui/src/basics/replace.ts rename to packages/docs/src/utils/replace-selection-factory.ts index 831ef7dbff7..069fadbc86a 100644 --- a/packages/docs-ui/src/basics/replace.ts +++ b/packages/docs/src/utils/replace-selection-factory.ts @@ -14,17 +14,17 @@ * limitations under the License. */ -import { BuildTextUtils, IUniverInstanceService, JSONX } from '@univerjs/core'; -import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; import type { DocumentDataModel, IAccessor, IDocumentBody, IMutationInfo, ITextRangeParam, Nullable, TextX } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import type { ITextRangeWithStyle } from '@univerjs/engine-render'; -import { getRichTextEditPath } from '../commands/util'; +import { BuildTextUtils, IUniverInstanceService, JSONX } from '@univerjs/core'; +import { DocSelectionManagerService, RichTextEditingMutation } from '@univerjs/docs'; +import { getRichTextEditPath } from './custom-range-factory'; export interface IReplaceSelectionFactoryParams { unitId: string; /** - * slelection to be replaced, if not provided, use the current selection. + * selection to be replaced, if not provided, use the current selection. */ selection?: ITextRangeParam; diff --git a/packages/engine-formula/package.json b/packages/engine-formula/package.json index 65ff65a1a5e..7b2945a58a6 100644 --- a/packages/engine-formula/package.json +++ b/packages/engine-formula/package.json @@ -22,7 +22,8 @@ ], "exports": { ".": "./src/index.ts", - "./*": "./src/*" + "./*": "./src/*", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/facade/src/apis/sheets/f-formula.ts b/packages/engine-formula/src/facade/f-formula.ts similarity index 89% rename from packages/facade/src/apis/sheets/f-formula.ts rename to packages/engine-formula/src/facade/f-formula.ts index bc6a0f6fcd8..fefbca91c67 100644 --- a/packages/facade/src/apis/sheets/f-formula.ts +++ b/packages/engine-formula/src/facade/f-formula.ts @@ -15,9 +15,10 @@ */ import type { ICommandInfo, IDisposable } from '@univerjs/core'; -import type { FormulaExecutedStateType, IExecutionInProgressParams, ISetFormulaCalculationNotificationMutation, ISetFormulaCalculationStartMutation } from '@univerjs/engine-formula'; +import type { ISetFormulaCalculationNotificationMutation, ISetFormulaCalculationStartMutation } from '../commands/mutations/set-formula-calculation.mutation'; +import type { FormulaExecutedStateType, IExecutionInProgressParams } from '../services/runtime.service'; import { ICommandService } from '@univerjs/core'; -import { SetFormulaCalculationNotificationMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation } from '@univerjs/engine-formula'; +import { SetFormulaCalculationNotificationMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation } from '../commands/mutations/set-formula-calculation.mutation'; /** * This interface class provides methods to modify the behavior of the operation formula. @@ -26,22 +27,14 @@ export class FFormula { constructor( @ICommandService private readonly _commandService: ICommandService ) { + // empty } /** * Start the calculation of the formula. */ executeCalculation(): void { - this._commandService.executeCommand( - SetFormulaCalculationStartMutation.id, - { - commands: [], - forceCalculation: true, - }, - { - onlyLocal: true, - } - ); + this._commandService.executeCommand(SetFormulaCalculationStartMutation.id, { commands: [], forceCalculation: true }, { onlyLocal: true }); } /** diff --git a/packages/engine-formula/src/facade/f-univer.ts b/packages/engine-formula/src/facade/f-univer.ts new file mode 100644 index 00000000000..3233275bb5a --- /dev/null +++ b/packages/engine-formula/src/facade/f-univer.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FUniver } from '@univerjs/core'; +import { FFormula } from './f-formula'; + +interface IFUniverEngineFormulaMixin { + getFormula(): FFormula; +} + +class FUniverEngineFormulaMixin extends FUniver implements IFUniverEngineFormulaMixin { + override getFormula(): FFormula { + return this._injector.createInstance(FFormula); + } +} + +FUniver.extend(FUniverEngineFormulaMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverEngineFormulaMixin {} +} diff --git a/packages/sheets-hyper-link-ui/src/types/interfaces/i-sheet-url-params.ts b/packages/engine-formula/src/facade/index.ts similarity index 83% rename from packages/sheets-hyper-link-ui/src/types/interfaces/i-sheet-url-params.ts rename to packages/engine-formula/src/facade/index.ts index 0454b9e4bdf..2d6d1dc0ab4 100644 --- a/packages/sheets-hyper-link-ui/src/types/interfaces/i-sheet-url-params.ts +++ b/packages/engine-formula/src/facade/index.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -export interface ISheetUrlParams { - gid?: string; - range?: string; - rangeid?: string; - unitid?: string; -} +import './f-univer'; + +export { FFormula } from './f-formula'; diff --git a/packages/engine-formula/src/functions/financial/db/index.ts b/packages/engine-formula/src/functions/financial/db/index.ts index 04109258885..f9265501346 100644 --- a/packages/engine-formula/src/functions/financial/db/index.ts +++ b/packages/engine-formula/src/functions/financial/db/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; import { checkVariantsErrorIsStringToNumber } from '../../../engine/utils/check-variant-error'; @@ -21,7 +22,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; export class Db extends BaseFunction { override minParams = 4; diff --git a/packages/engine-formula/src/functions/financial/ddb/index.ts b/packages/engine-formula/src/functions/financial/ddb/index.ts index f799b1ee920..e0c899e99a9 100644 --- a/packages/engine-formula/src/functions/financial/ddb/index.ts +++ b/packages/engine-formula/src/functions/financial/ddb/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculateDDB } from '../../../basics/financial'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; @@ -22,7 +23,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; export class Ddb extends BaseFunction { override minParams = 4; diff --git a/packages/engine-formula/src/functions/financial/fv/index.ts b/packages/engine-formula/src/functions/financial/fv/index.ts index bd02c7e156c..12a1acad3ff 100644 --- a/packages/engine-formula/src/functions/financial/fv/index.ts +++ b/packages/engine-formula/src/functions/financial/fv/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculateFV } from '../../../basics/financial'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; @@ -22,8 +24,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; -import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; export class Fv extends BaseFunction { override minParams = 3; diff --git a/packages/engine-formula/src/functions/financial/ipmt/index.ts b/packages/engine-formula/src/functions/financial/ipmt/index.ts index eee30dcaa1e..64e7189fc15 100644 --- a/packages/engine-formula/src/functions/financial/ipmt/index.ts +++ b/packages/engine-formula/src/functions/financial/ipmt/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculateIPMT } from '../../../basics/financial'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; @@ -22,8 +24,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; -import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; export class Ipmt extends BaseFunction { override minParams = 4; diff --git a/packages/engine-formula/src/functions/financial/npv/index.ts b/packages/engine-formula/src/functions/financial/npv/index.ts index 98edad4fa4e..4b5481151f8 100644 --- a/packages/engine-formula/src/functions/financial/npv/index.ts +++ b/packages/engine-formula/src/functions/financial/npv/index.ts @@ -14,13 +14,13 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculateNpv } from '../../../basics/financial'; import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; interface IValuesType { isError: boolean; diff --git a/packages/engine-formula/src/functions/financial/pmt/index.ts b/packages/engine-formula/src/functions/financial/pmt/index.ts index 1febbe24901..04b26d5dae7 100644 --- a/packages/engine-formula/src/functions/financial/pmt/index.ts +++ b/packages/engine-formula/src/functions/financial/pmt/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculatePMT } from '../../../basics/financial'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; @@ -22,8 +24,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; -import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; export class Pmt extends BaseFunction { override minParams = 3; diff --git a/packages/engine-formula/src/functions/financial/ppmt/index.ts b/packages/engine-formula/src/functions/financial/ppmt/index.ts index 85560c3cca1..18b80d8bdc4 100644 --- a/packages/engine-formula/src/functions/financial/ppmt/index.ts +++ b/packages/engine-formula/src/functions/financial/ppmt/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculateIPMT, calculatePMT } from '../../../basics/financial'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; @@ -22,8 +24,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; -import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; export class Ppmt extends BaseFunction { override minParams = 4; diff --git a/packages/engine-formula/src/functions/financial/pv/index.ts b/packages/engine-formula/src/functions/financial/pv/index.ts index 800ff5bc14e..feec180f89e 100644 --- a/packages/engine-formula/src/functions/financial/pv/index.ts +++ b/packages/engine-formula/src/functions/financial/pv/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; import { ErrorType } from '../../../basics/error-type'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; import { checkVariantsErrorIsStringToNumber } from '../../../engine/utils/check-variant-error'; @@ -21,8 +23,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; -import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; export class Pv extends BaseFunction { override minParams = 3; diff --git a/packages/engine-formula/src/functions/financial/sln/index.ts b/packages/engine-formula/src/functions/financial/sln/index.ts index a85f3078da2..e05047b7eb8 100644 --- a/packages/engine-formula/src/functions/financial/sln/index.ts +++ b/packages/engine-formula/src/functions/financial/sln/index.ts @@ -14,13 +14,13 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; export class Sln extends BaseFunction { override minParams = 3; diff --git a/packages/engine-formula/src/functions/financial/syd/index.ts b/packages/engine-formula/src/functions/financial/syd/index.ts index 4bd97a470ef..1ded2281729 100644 --- a/packages/engine-formula/src/functions/financial/syd/index.ts +++ b/packages/engine-formula/src/functions/financial/syd/index.ts @@ -14,13 +14,13 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; export class Syd extends BaseFunction { override minParams = 4; diff --git a/packages/engine-formula/src/functions/financial/vdb/index.ts b/packages/engine-formula/src/functions/financial/vdb/index.ts index cb807d70b52..5edbeca996a 100644 --- a/packages/engine-formula/src/functions/financial/vdb/index.ts +++ b/packages/engine-formula/src/functions/financial/vdb/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { calculateDDB } from '../../../basics/financial'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; @@ -22,7 +23,6 @@ import { getCurrencyFormat } from '../../../engine/utils/numfmt-kit'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { BooleanValueObject, NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; export class Vdb extends BaseFunction { override minParams = 5; diff --git a/packages/engine-formula/src/functions/text/exact/index.ts b/packages/engine-formula/src/functions/text/exact/index.ts index 149e35d9a5c..80dd32bccaf 100644 --- a/packages/engine-formula/src/functions/text/exact/index.ts +++ b/packages/engine-formula/src/functions/text/exact/index.ts @@ -14,11 +14,11 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; +import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; import { expandArrayValueObject } from '../../../engine/utils/array-object'; import { BooleanValueObject, NullValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; -import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; export class Exact extends BaseFunction { override minParams = 2; diff --git a/packages/engine-formula/src/functions/text/function-map.ts b/packages/engine-formula/src/functions/text/function-map.ts index 611df6df110..bbde97ccfa0 100644 --- a/packages/engine-formula/src/functions/text/function-map.ts +++ b/packages/engine-formula/src/functions/text/function-map.ts @@ -32,11 +32,11 @@ import { Len } from './len'; import { Lenb } from './lenb'; import { Lower } from './lower'; import { Mid } from './mid'; +import { Numbervalue } from './numbervalue'; +import { Proper } from './proper'; import { Regexextract } from './regexextract'; import { Regexmatch } from './regexmatch'; import { Regexreplace } from './regexreplace'; -import { Numbervalue } from './numbervalue'; -import { Proper } from './proper'; import { Rept } from './rept'; import { Right } from './right'; import { Rightb } from './rightb'; diff --git a/packages/engine-formula/src/functions/text/proper/index.ts b/packages/engine-formula/src/functions/text/proper/index.ts index 56cfd3300ff..b633230543a 100644 --- a/packages/engine-formula/src/functions/text/proper/index.ts +++ b/packages/engine-formula/src/functions/text/proper/index.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { StringValueObject } from '../../../engine/value-object/primitive-object'; -import { BaseFunction } from '../../base-function'; import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { StringValueObject } from '../../../engine/value-object/primitive-object'; +import { BaseFunction } from '../../base-function'; export class Proper extends BaseFunction { override minParams = 1; diff --git a/packages/engine-formula/src/functions/text/t/index.ts b/packages/engine-formula/src/functions/text/t/index.ts index 1e19b8686ad..82927005e51 100644 --- a/packages/engine-formula/src/functions/text/t/index.ts +++ b/packages/engine-formula/src/functions/text/t/index.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { StringValueObject } from '../../../engine/value-object/primitive-object'; -import { BaseFunction } from '../../base-function'; import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import type { BaseValueObject } from '../../../engine/value-object/base-value-object'; +import { StringValueObject } from '../../../engine/value-object/primitive-object'; +import { BaseFunction } from '../../base-function'; export class T extends BaseFunction { override minParams = 1; diff --git a/packages/engine-formula/src/functions/text/unicode/index.ts b/packages/engine-formula/src/functions/text/unicode/index.ts index bcb2d58c6df..d930620007b 100644 --- a/packages/engine-formula/src/functions/text/unicode/index.ts +++ b/packages/engine-formula/src/functions/text/unicode/index.ts @@ -14,11 +14,11 @@ * limitations under the License. */ +import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; import { ErrorType } from '../../../basics/error-type'; import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; import { NumberValueObject } from '../../../engine/value-object/primitive-object'; import { BaseFunction } from '../../base-function'; -import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; export class Unicode extends BaseFunction { override minParams = 1; diff --git a/packages/engine-render/src/basics/tools.ts b/packages/engine-render/src/basics/tools.ts index 907414f1601..7cf5c3ddc76 100644 --- a/packages/engine-render/src/basics/tools.ts +++ b/packages/engine-render/src/basics/tools.ts @@ -21,7 +21,6 @@ import type { ISelectionCell, ISelectionCellWithMergeInfo, IStyleBase, - LocaleService, Nullable, } from '@univerjs/core'; import type { IDocumentSkeletonFontStyle } from './i-document-skeleton-cached'; @@ -247,8 +246,7 @@ export function fixLineWidthByScale(num: number, scale: number) { // eslint-disable-next-line max-lines-per-function export function getFontStyleString( - textStyle?: IStyleBase, - _localeService?: LocaleService + textStyle?: IStyleBase ): IDocumentSkeletonFontStyle { const defaultFont = DEFAULT_STYLES.ff; diff --git a/packages/engine-render/src/components/docs/layout/block/paragraph/bullet.ts b/packages/engine-render/src/components/docs/layout/block/paragraph/bullet.ts index fb5e5d4c165..a8232649bae 100644 --- a/packages/engine-render/src/components/docs/layout/block/paragraph/bullet.ts +++ b/packages/engine-render/src/components/docs/layout/block/paragraph/bullet.ts @@ -16,9 +16,9 @@ import type { IBullet, ILists, INestingLevel, ITextStyle, LocaleService, Nullable } from '@univerjs/core'; +import type { IDocumentSkeletonBullet } from '../../../../../basics/i-document-skeleton-cached'; import { getFontStyleString } from '../../../../../basics/tools'; import { getBulletOrderedSymbol } from './bullet-ruler'; -import type { IDocumentSkeletonBullet } from '../../../../../basics/i-document-skeleton-cached'; export function dealWithBullet( bullet?: IBullet, @@ -91,7 +91,7 @@ function _getBulletSke( nestings: INestingLevel[], listLevelAncestors?: Array>, textStyleConfig?: ITextStyle, - localeService?: LocaleService + _localeService?: LocaleService ): IDocumentSkeletonBullet { const nesting = nestings[nestingLevel]; const { @@ -105,7 +105,7 @@ function _getBulletSke( const textStyle = { ...textStyleConfig, ...textStyleFirst }; - const fontStyle = getFontStyleString(textStyle, localeService); // 获得canvas.font格式的字体样式 + const fontStyle = getFontStyleString(textStyle); // 获得canvas.font格式的字体样式 let symbolContent: string; if (glyphSymbol) { diff --git a/packages/engine-render/src/components/docs/layout/doc-skeleton.ts b/packages/engine-render/src/components/docs/layout/doc-skeleton.ts index fbd6a198b26..30588d0a259 100644 --- a/packages/engine-render/src/components/docs/layout/doc-skeleton.ts +++ b/packages/engine-render/src/components/docs/layout/doc-skeleton.ts @@ -1019,7 +1019,7 @@ export class DocumentSkeleton extends Skeleton { lists, drawings, - localeService: this._localService, + localeService: this._localeService, paragraphLineGapDefault, defaultTabStop, documentTextStyle: textStyle, diff --git a/packages/engine-render/src/components/docs/layout/tools.ts b/packages/engine-render/src/components/docs/layout/tools.ts index 170c5bcc99e..46e9c620a9b 100644 --- a/packages/engine-render/src/components/docs/layout/tools.ts +++ b/packages/engine-render/src/components/docs/layout/tools.ts @@ -823,7 +823,7 @@ export function getFontCreateConfig( }, marginRight = 0, marginLeft = 0, - localeService, + // localeService, renderConfig = {}, } = sectionBreakConfig; const { paragraphStyle = {}, bullet } = paragraph; @@ -859,7 +859,7 @@ export function getFontCreateConfig( ...bulletTextStyle, }; - const fontStyle = getFontStyleString(textStyle, localeService); + const fontStyle = getFontStyleString(textStyle); const mixTextStyle: ITextStyle = { ...documentTextStyle, diff --git a/packages/engine-render/src/components/sheets/sheet-skeleton.ts b/packages/engine-render/src/components/sheets/sheet-skeleton.ts index cb12bffcef8..82f9b12400f 100644 --- a/packages/engine-render/src/components/sheets/sheet-skeleton.ts +++ b/packages/engine-render/src/components/sheets/sheet-skeleton.ts @@ -37,26 +37,21 @@ import type { IStyleBase, IStyleData, ITextRotation, - ITextStyle, IWorksheetData, Nullable, Styles, TextDirection, + VerticalAlign, Worksheet, } from '@univerjs/core'; import type { IDocumentSkeletonColumn } from '../../basics/i-document-skeleton-cached'; - import type { IBoundRectNoAngle, IViewportInfo } from '../../basics/vector2'; -import { type BorderCache, type IFontCacheItem, type IStylesCache, SHEET_VIEWPORT_KEY } from './interfaces'; -/* eslint-disable max-lines-per-function */ -/* eslint-disable no-param-reassign */ import { BooleanNumber, BuildTextUtils, CellValueType, composeStyles, CustomRangeType, - DEFAULT_EMPTY_DOCUMENT_VALUE, DEFAULT_STYLES, DocumentDataModel, extractPureTextFromCell, @@ -74,7 +69,6 @@ import { searchArray, TextX, Tools, - VerticalAlign, WrapStrategy, } from '@univerjs/core'; import { distinctUntilChanged, startWith } from 'rxjs'; @@ -94,6 +88,8 @@ import { columnIterator } from '../docs/layout/tools'; import { DocumentViewModel } from '../docs/view-model/document-view-model'; import { Skeleton } from '../skeleton'; import { EXPAND_SIZE_FOR_RENDER_OVERFLOW } from './constants'; +import { type BorderCache, type IFontCacheItem, type IStylesCache, SHEET_VIEWPORT_KEY } from './interfaces'; +import { createDocumentModelWithStyle, extractOtherStyle, getFontFormat } from './util'; function addLinkToDocumentModel(documentModel: DocumentDataModel, linkUrl: string, linkId: string): void { const body = documentModel.getBody()!; @@ -178,31 +174,12 @@ export function getDocsSkeletonPageSize(documentSkeleton: DocumentSkeleton, angl } interface ICellOtherConfig { - /** - * textRotation - */ textRotation?: ITextRotation; - /** - * textDirection - */ textDirection?: Nullable; - /** - * horizontalAlignment - */ horizontalAlign?: HorizontalAlign; - /** - * verticalAlignment - */ verticalAlign?: VerticalAlign; - /** - * wrapStrategy - */ wrapStrategy?: WrapStrategy; - /** - * padding - */ paddingData?: IPaddingData; - cellValueType?: CellValueType; } @@ -645,7 +622,7 @@ export class SpreadsheetSkeleton extends Skeleton { documentModel.updateDocumentDataPageSize(colWidth); } - const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localService); + const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localeService); documentSkeleton.calculate(); let { height: h = 0 } = getDocsSkeletonPageSize(documentSkeleton, angle) ?? {}; @@ -837,7 +814,7 @@ export class SpreadsheetSkeleton extends Skeleton { documentModel.updateDocumentDataPageSize(Infinity, Infinity); } - const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localService); + const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localeService); documentSkeleton.calculate(); // key @@ -1363,16 +1340,14 @@ export class SpreadsheetSkeleton extends Skeleton { // Only used for cell edit, and no need to rotate text when edit cell content! getBlankCellDocumentModel(cell: Nullable): IDocumentLayoutObject { - const documentModelObject = this._getCellDocumentModel(cell, { - ignoreTextRotation: true, - }); + const documentModelObject = this._getCellDocumentModel(cell, { ignoreTextRotation: true }); const style = this._styles.getStyleByCell(cell); - const textStyle = this._getFontFormat(style); + const textStyle = getFontFormat(style); if (documentModelObject != null) { if (documentModelObject.documentModel == null) { - documentModelObject.documentModel = this._getDocumentDataByStyle('', textStyle, {}); + documentModelObject.documentModel = createDocumentModelWithStyle('', textStyle); } return documentModelObject; } @@ -1387,9 +1362,9 @@ export class SpreadsheetSkeleton extends Skeleton { const wrapStrategy: WrapStrategy = DEFAULT_STYLES.tb; const paddingData: IPaddingData = DEFAULT_PADDING_DATA; - fontString = getFontStyleString({}, this._localService).fontCache; + fontString = getFontStyleString({}).fontCache; - const documentModel = this._getDocumentDataByStyle(content, textStyle, {}); + const documentModel = createDocumentModelWithStyle(content, textStyle); return { documentModel, @@ -1436,7 +1411,7 @@ export class SpreadsheetSkeleton extends Skeleton { let documentModel: Nullable; let fontString = 'document'; - const cellOtherConfig = this._getOtherStyle(style) as ICellOtherConfig; + const cellOtherConfig = extractOtherStyle(style); const textRotation: ITextRotation = ignoreTextRotation ? DEFAULT_STYLES.tr @@ -1448,7 +1423,7 @@ export class SpreadsheetSkeleton extends Skeleton { if (cell.f && displayRawFormula) { // The formula does not detect horizontal alignment and rotation. - documentModel = this._getDocumentDataByStyle(cell.f.toString(), {}, { verticalAlign }); + documentModel = createDocumentModelWithStyle(cell.f.toString(), {}, { verticalAlign }); horizontalAlign = DEFAULT_STYLES.ht; } else if (cell.p) { const { centerAngle, vertexAngle } = convertTextRotation(textRotation); @@ -1464,10 +1439,9 @@ export class SpreadsheetSkeleton extends Skeleton { wrapStrategy, } ); - // console.log(cell.p); } else if (cell.v != null) { - const textStyle = this._getFontFormat(style); - fontString = getFontStyleString(textStyle, this._localService).fontCache; + const textStyle = getFontFormat(style); + fontString = getFontStyleString(textStyle).fontCache; let cellText = extractPureTextFromCell(cell); @@ -1477,12 +1451,14 @@ export class SpreadsheetSkeleton extends Skeleton { cellText = `'${cellText}`; } - documentModel = this._getDocumentDataByStyle(cellText, textStyle, { + documentModel = createDocumentModelWithStyle(cellText, textStyle, { ...cellOtherConfig, textRotation, cellValueType: cell.t!, }); } + + // This is a compatible code. cc @weird94 if (documentModel && cell.linkUrl && cell.linkId) { addLinkToDocumentModel(documentModel, cell.linkUrl, cell.linkId); } @@ -1892,20 +1868,6 @@ export class SpreadsheetSkeleton extends Skeleton { return Boolean(mergedData); } - // private _getMergeRangeCache() { - // const dataMergeCache = this.dataMergeCache; - // const mergeRangeCache = new ObjectMatrix>(); - // dataMergeCache?.forEach((r, dataMergeRow) => { - // dataMergeRow?.forEach((c, dataCache) => { - // const { startRow: startRowMargeIndex, endRow: endRowMargeIndex, startColumn: startColumnMargeIndex, endColumn: endColumnMargeIndex } = dataCache; - // const endObject = new ObjectMatrix(); - // endObject.setValue(endRowMargeIndex, endColumnMargeIndex, true); - // mergeRangeCache.setValue(startRowMargeIndex, startColumnMargeIndex, endObject); - // }); - // }); - // return mergeRangeCache; - // } - /** * get the current row and column segment visible merge data * @returns {IRange} The visible merge data @@ -2035,7 +1997,7 @@ export class SpreadsheetSkeleton extends Skeleton { const documentViewModel = new DocumentViewModel(documentModel); if (documentViewModel) { const { vertexAngle, centerAngle } = convertTextRotation(textRotation); - const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localService); + const documentSkeleton = DocumentSkeleton.create(documentViewModel, this._localeService); documentSkeleton.calculate(); const config: IFontCacheItem = { @@ -2149,69 +2111,6 @@ export class SpreadsheetSkeleton extends Skeleton { return new DocumentDataModel(documentData); } - private _getDocumentDataByStyle(content: string, textStyle: ITextStyle, config: ICellOtherConfig): DocumentDataModel { - const contentLength = content.length; - const { - textRotation, - paddingData = DEFAULT_PADDING_DATA, - horizontalAlign = HorizontalAlign.UNSPECIFIED, - verticalAlign = VerticalAlign.UNSPECIFIED, - wrapStrategy = WrapStrategy.UNSPECIFIED, - cellValueType, - } = config; - - const { t: marginTop, r: marginRight, b: marginBottom, l: marginLeft } = paddingData || {}; - - const { vertexAngle, centerAngle } = convertTextRotation(textRotation); - - const documentData: IDocumentData = { - id: 'd', - body: { - dataStream: `${content}${DEFAULT_EMPTY_DOCUMENT_VALUE}`, - textRuns: [ - { - ts: textStyle, - st: 0, - ed: contentLength, - }, - ], - paragraphs: [ - { - startIndex: contentLength, - paragraphStyle: { - horizontalAlign, - }, - }, - ], - sectionBreaks: [{ - startIndex: contentLength + 1, - }], - }, - documentStyle: { - pageSize: { - width: Number.POSITIVE_INFINITY, - height: Number.POSITIVE_INFINITY, - }, - marginTop, - marginBottom, - marginRight, - marginLeft, - renderConfig: { - horizontalAlign, - verticalAlign, - centerAngle, - vertexAngle, - wrapStrategy, - cellValueType, - }, - }, - drawings: {}, - drawingsOrder: [], - }; - - return new DocumentDataModel(documentData); - } - /** * pro/issues/344 * In Excel, for the border rendering of merged cells to take effect, the outermost cells need to have the same border style. @@ -2357,35 +2256,6 @@ export class SpreadsheetSkeleton extends Skeleton { return style; } - private _getOtherStyle(format?: Nullable): ICellOtherConfig { - if (!format) { - return {}; - } - - const { - tr: textRotation, - - td: textDirection, - - ht: horizontalAlign, - - vt: verticalAlign, - - tb: wrapStrategy, - - pd: paddingData, - } = format; - - return { - textRotation, - textDirection, - horizontalAlign, - verticalAlign, - wrapStrategy, - paddingData, - } as ICellOtherConfig; - } - /** * New version to get merge data. * @param row diff --git a/packages/engine-render/src/components/sheets/util.ts b/packages/engine-render/src/components/sheets/util.ts new file mode 100644 index 00000000000..5dae347b0f2 --- /dev/null +++ b/packages/engine-render/src/components/sheets/util.ts @@ -0,0 +1,129 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { CellValueType, IDocumentData, IPaddingData, IStyleBase, IStyleData, ITextRotation, ITextStyle, Nullable, TextDirection } from '@univerjs/core'; +import { DEFAULT_EMPTY_DOCUMENT_VALUE, DocumentDataModel, HorizontalAlign, VerticalAlign, WrapStrategy } from '@univerjs/core'; +import { convertTextRotation } from '../../basics/text-rotation'; +import { DEFAULT_PADDING_DATA } from './sheet-skeleton'; + +export interface ICellStyle { + textRotation?: ITextRotation; + textDirection?: Nullable; + horizontalAlign?: HorizontalAlign; + verticalAlign?: VerticalAlign; + wrapStrategy?: WrapStrategy; + paddingData?: IPaddingData; + cellValueType?: CellValueType; +} + +export function createDocumentModelWithStyle(content: string, textStyle: ITextStyle, config: ICellStyle = {}) { + const contentLength = content.length; + const { + textRotation, + paddingData = DEFAULT_PADDING_DATA, + horizontalAlign = HorizontalAlign.UNSPECIFIED, + verticalAlign = VerticalAlign.UNSPECIFIED, + wrapStrategy = WrapStrategy.UNSPECIFIED, + cellValueType, + } = config; + + const { t: marginTop, r: marginRight, b: marginBottom, l: marginLeft } = paddingData; + const { vertexAngle, centerAngle } = convertTextRotation(textRotation); + const documentData: IDocumentData = { + id: 'd', + body: { + dataStream: `${content}${DEFAULT_EMPTY_DOCUMENT_VALUE}`, + textRuns: [ + { + ts: textStyle, + st: 0, + ed: contentLength, + }, + ], + paragraphs: [ + { + startIndex: contentLength, + paragraphStyle: { + horizontalAlign, + }, + }, + ], + sectionBreaks: [{ + startIndex: contentLength + 1, + }], + }, + documentStyle: { + pageSize: { + width: Number.POSITIVE_INFINITY, + height: Number.POSITIVE_INFINITY, + }, + marginTop, + marginBottom, + marginRight, + marginLeft, + renderConfig: { + horizontalAlign, + verticalAlign, + centerAngle, + vertexAngle, + wrapStrategy, + cellValueType, + }, + }, + drawings: {}, + drawingsOrder: [], + }; + + return new DocumentDataModel(documentData); +} + +export function extractOtherStyle(style?: Nullable): ICellStyle { + if (!style) return {}; + const { + tr: textRotation, + td: textDirection, + ht: horizontalAlign, + vt: verticalAlign, + tb: wrapStrategy, + pd: paddingData, + } = style; + + return { + textRotation, + textDirection, + horizontalAlign, + verticalAlign, + wrapStrategy, + paddingData, + } as ICellStyle; +} + +export function getFontFormat(format?: Nullable): IStyleBase { + if (!format) { + return {}; + } + const { ff, fs, it, bl, ul, st, ol, cl } = format; + const style: IStyleBase = {}; + ff && (style.ff = ff); + fs && (style.fs = fs); + it && (style.it = it); + bl && (style.bl = bl); + ul && (style.ul = ul); + st && (style.st = st); + ol && (style.ol = ol); + cl && (style.cl = cl); + return style; +} diff --git a/packages/engine-render/src/components/skeleton.ts b/packages/engine-render/src/components/skeleton.ts index 4805399db19..3ac47588b2c 100644 --- a/packages/engine-render/src/components/skeleton.ts +++ b/packages/engine-render/src/components/skeleton.ts @@ -14,16 +14,16 @@ * limitations under the License. */ -import { Disposable, Inject, LocaleService } from '@univerjs/core'; - import type { IFontLocale } from '../basics/interfaces'; +import { Disposable, Inject, LocaleService } from '@univerjs/core'; + export class Skeleton extends Disposable { private _fontLocale!: IFontLocale; private _dirty = true; - constructor(@Inject(LocaleService) protected readonly _localService: LocaleService) { + constructor(@Inject(LocaleService) protected readonly _localeService: LocaleService) { super(); this._localeInitial(); diff --git a/packages/facade/package.json b/packages/facade/package.json index 64fc447ce34..27e322168c8 100644 --- a/packages/facade/package.json +++ b/packages/facade/package.json @@ -80,6 +80,7 @@ "@univerjs/sheets-hyper-link": "workspace:*", "@univerjs/sheets-hyper-link-ui": "workspace:*", "@univerjs/sheets-numfmt": "workspace:*", + "@univerjs/sheets-numfmt-ui": "workspace:*", "@univerjs/sheets-thread-comment": "workspace:*", "@univerjs/sheets-ui": "workspace:*", "@univerjs/thread-comment": "workspace:*", diff --git a/packages/facade/src/apis/__tests__/create-test-bed.ts b/packages/facade/src/apis/__tests__/create-test-bed.ts index bae3cf55938..189d2008066 100644 --- a/packages/facade/src/apis/__tests__/create-test-bed.ts +++ b/packages/facade/src/apis/__tests__/create-test-bed.ts @@ -46,7 +46,6 @@ import { WorksheetProtectionRuleModel, } from '@univerjs/sheets'; import { ConditionalFormattingFormulaService, ConditionalFormattingRuleModel, ConditionalFormattingService, ConditionalFormattingViewModel } from '@univerjs/sheets-conditional-formatting'; - import { DataValidationCacheService, DataValidationCustomFormulaService, DataValidationFormulaService, SheetDataValidationModel, SheetsDataValidationValidatorService } from '@univerjs/sheets-data-validation'; import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; import { @@ -62,7 +61,7 @@ import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { ISheetSelectionRenderService, SheetRenderController, SheetSelectionRenderService, SheetSkeletonManagerService, SheetsRenderService } from '@univerjs/sheets-ui'; import { IThreadCommentDataSourceService, ThreadCommentDataSourceService, ThreadCommentModel } from '@univerjs/thread-comment'; import { IPlatformService, IShortcutService, PlatformService, ShortcutService } from '@univerjs/ui'; -import { FUniver } from '../facade'; +import { FUniver } from '../everything'; function getTestWorkbookDataDemo(): IWorkbookData { return { diff --git a/packages/facade/src/apis/__tests__/f-hooks.spec.ts b/packages/facade/src/apis/__tests__/f-hooks.spec.ts index e60443f6bba..3bac3fddcbd 100644 --- a/packages/facade/src/apis/__tests__/f-hooks.spec.ts +++ b/packages/facade/src/apis/__tests__/f-hooks.spec.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { LifecycleService, LifecycleStages } from '@univerjs/core'; import type { Injector } from '@univerjs/core'; +import type { FUniver } from '../everything'; +import { LifecycleService, LifecycleStages } from '@univerjs/core'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; -import type { FUniver } from '../facade'; import { createFacadeTestBed } from './create-test-bed'; describe('Test FUniver', () => { diff --git a/packages/facade/src/apis/__tests__/facade.spec.ts b/packages/facade/src/apis/__tests__/facade.spec.ts index 1f9c9c27b4b..d84b0f4fee7 100644 --- a/packages/facade/src/apis/__tests__/facade.spec.ts +++ b/packages/facade/src/apis/__tests__/facade.spec.ts @@ -14,16 +14,7 @@ * limitations under the License. */ -import { ICommandService, IUniverInstanceService } from '@univerjs/core'; -import { RegisterFunctionMutation, SetFormulaCalculationStartMutation } from '@univerjs/engine-formula'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { SetRangeValuesCommand, SetRangeValuesMutation, SetStyleCommand } from '@univerjs/sheets'; - -import { IDescriptionService } from '@univerjs/sheets-formula'; -import { SHEET_VIEW_KEY } from '@univerjs/sheets-ui'; -import { AddCommentCommand, AddCommentMutation, DeleteCommentCommand, DeleteCommentMutation, DeleteCommentTreeCommand, ResolveCommentMutation, UpdateCommentCommand, UpdateCommentMutation, UpdateCommentRefMutation } from '@univerjs/thread-comment'; -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import type { ICellData, Injector, IStyleData, Nullable } from '@univerjs/core'; +import type { ICellData, Injector, Nullable } from '@univerjs/core'; import type { ColumnHeaderLayout, RenderComponentType, @@ -32,9 +23,20 @@ import type { SpreadsheetColumnHeader, SpreadsheetRowHeader, } from '@univerjs/engine-render'; +import type { FUniver } from '../everything'; +import { ICommandService, IUniverInstanceService } from '@univerjs/core'; + +import { RegisterFunctionMutation, SetFormulaCalculationStartMutation } from '@univerjs/engine-formula'; +import { IRenderManagerService } from '@univerjs/engine-render'; +import { SetRangeValuesCommand, SetRangeValuesMutation, SetStyleCommand } from '@univerjs/sheets'; +import { IDescriptionService } from '@univerjs/sheets-formula'; +import { SHEET_VIEW_KEY } from '@univerjs/sheets-ui'; +import { AddCommentCommand, AddCommentMutation, DeleteCommentCommand, DeleteCommentMutation, DeleteCommentTreeCommand, ResolveCommentMutation, UpdateCommentCommand, UpdateCommentMutation, UpdateCommentRefMutation } from '@univerjs/thread-comment'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createFacadeTestBed } from './create-test-bed'; import { COLUMN_UNIQUE_KEY, ColumnHeaderCustomExtension, MAIN_UNIQUE_KEY, MainCustomExtension, ROW_UNIQUE_KEY, RowHeaderCustomExtension } from './utils/sheet-extension-util'; -import type { FUniver } from '../facade'; + +import '../everything'; describe('Test FUniver', () => { let get: Injector['get']; @@ -47,12 +49,6 @@ describe('Test FUniver', () => { endColumn: number ) => Nullable; - let getStyleByPosition: ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ) => Nullable; let getSheetRenderComponent: (unitId: string, viewKey: SHEET_VIEW_KEY) => Nullable; beforeEach(() => { @@ -90,19 +86,6 @@ describe('Test FUniver', () => { ?.getRange(startRow, startColumn, endRow, endColumn) .getValue(); - getStyleByPosition = ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ): Nullable => { - const value = getValueByPosition(startRow, startColumn, endRow, endColumn); - const styles = get(IUniverInstanceService).getUniverSheetInstance('test')?.getStyles(); - if (value && styles) { - return styles.getStyleByCell(value); - } - }; - getSheetRenderComponent = (unitId: string, viewKey: SHEET_VIEW_KEY): Nullable => { const render = get(IRenderManagerService).getRenderById(unitId); if (!render) { diff --git a/packages/facade/src/apis/docs/__tests__/create-test-bed.ts b/packages/facade/src/apis/docs/__tests__/create-test-bed.ts index a897760bc62..a1e466f0e9e 100644 --- a/packages/facade/src/apis/docs/__tests__/create-test-bed.ts +++ b/packages/facade/src/apis/docs/__tests__/create-test-bed.ts @@ -31,8 +31,7 @@ import { DocIMEInputManagerService, DocsRenderService, DocStateChangeManagerServ import { IRenderManagerService, RenderManagerService } from '@univerjs/engine-render'; import enUS from '@univerjs/sheets-formula-ui/locale/en-US'; import zhCN from '@univerjs/sheets-formula-ui/locale/zh-CN'; - -import { FUniver } from '../../facade'; +import { FUniver } from '../../everything'; function getTestDocumentDataDemo(): IDocumentData { return { diff --git a/packages/facade/src/apis/docs/__tests__/f-document.spec.ts b/packages/facade/src/apis/docs/__tests__/f-document.spec.ts index 94aae44e2f4..902ab91ee01 100644 --- a/packages/facade/src/apis/docs/__tests__/f-document.spec.ts +++ b/packages/facade/src/apis/docs/__tests__/f-document.spec.ts @@ -14,14 +14,13 @@ * limitations under the License. */ +import type { Injector } from '@univerjs/core'; +import type { FUniver } from '../../everything'; import { ICommandService } from '@univerjs/core'; import { RichTextEditingMutation } from '@univerjs/docs'; import { InsertCommand } from '@univerjs/docs-ui'; - import { beforeEach, describe, expect, it } from 'vitest'; -import type { Injector } from '@univerjs/core'; import { createTestBed } from './create-test-bed'; -import type { FUniver } from '../../facade'; describe('Test FDocument', () => { let get: Injector['get']; diff --git a/packages/facade/src/apis/everything.ts b/packages/facade/src/apis/everything.ts new file mode 100644 index 00000000000..f156f677888 --- /dev/null +++ b/packages/facade/src/apis/everything.ts @@ -0,0 +1,36 @@ +/** + * 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 '@univerjs/sheets/facade'; +import '@univerjs/ui/facade'; +import '@univerjs/docs-ui/facade'; +import '@univerjs/sheets-ui/facade'; +import '@univerjs/sheets-data-validation/facade'; +import '@univerjs/engine-formula/facade'; +import '@univerjs/sheets-filter/facade'; +import '@univerjs/sheets-formula/facade'; +import '@univerjs/sheets-numfmt/facade'; +import '@univerjs/sheets-hyper-link/facade'; +import '@univerjs/sheets-hyper-link-ui/facade'; +import '@univerjs/sheets-thread-comment/facade'; + +export { FHooks, FUniver } from '@univerjs/core'; +export { FFormula } from '@univerjs/engine-formula/facade'; +export { FPermission, FRange, FSelection, FWorkbook, FWorksheet } from '@univerjs/sheets/facade'; +export { FDataValidation, FDataValidationBuilder } from '@univerjs/sheets-data-validation/facade'; +export { FFilter } from '@univerjs/sheets-filter/facade'; +export { FThreadComment } from '@univerjs/sheets-thread-comment/facade'; +export { FSheetHooks } from '@univerjs/sheets-ui/facade'; diff --git a/packages/facade/src/apis/facade.ts b/packages/facade/src/apis/facade.ts index 9a301fa709e..94afe4ec1e7 100644 --- a/packages/facade/src/apis/facade.ts +++ b/packages/facade/src/apis/facade.ts @@ -15,94 +15,28 @@ */ import type { - CommandListener, Dependency, - DocumentDataModel, - IDisposable, - IDocumentData, - IExecutionOptions, - IWorkbookData, - LifecycleStages, - Nullable, - Workbook, + Injector, } from '@univerjs/core'; -import type { - IColumnsHeaderCfgParam, - IRowsHeaderCfgParam, - RenderComponentType, - SheetComponent, - SheetExtension, SpreadsheetColumnHeader, - SpreadsheetRowHeader, -} from '@univerjs/engine-render'; import type { ISocket } from '@univerjs/network'; -import type { ISetCrosshairHighlightColorOperationParams } from '@univerjs/sheets-crosshair-highlight'; -import type { IRegisterFunctionParams } from '@univerjs/sheets-formula'; -import type { IImageWatermarkConfig, ITextWatermarkConfig } from '@univerjs/watermark'; import { - BorderStyleTypes, - debounce, - ICommandService, - Inject, - Injector, - IUniverInstanceService, - LifecycleService, + FUniver, Quantity, - RedoCommand, - toDisposable, - UndoCommand, Univer, - UniverInstanceType, - WrapStrategy, } from '@univerjs/core'; -import { SetFormulaCalculationStartMutation } from '@univerjs/engine-formula'; -import { IRenderManagerService } from '@univerjs/engine-render'; import { ISocketService, WebSocketService } from '@univerjs/network'; -import { DisableCrosshairHighlightOperation, EnableCrosshairHighlightOperation, SetCrosshairHighlightColorOperation } from '@univerjs/sheets-crosshair-highlight'; -import { IRegisterFunctionService, RegisterFunctionService } from '@univerjs/sheets-formula'; -import { SHEET_VIEW_KEY } from '@univerjs/sheets-ui'; -import { CopyCommand, PasteCommand } from '@univerjs/ui'; -import { IWatermarkTypeEnum, WatermarkImageBaseConfig, WatermarkService, WatermarkTextBaseConfig } from '@univerjs/watermark'; -import { FDocument } from './docs/f-document'; -import { FHooks } from './f-hooks'; -import { FDataValidationBuilder } from './sheets/f-data-validation-builder'; -import { FFormula } from './sheets/f-formula'; -import { FPermission } from './sheets/f-permission'; -import { FSheetHooks } from './sheets/f-sheet-hooks'; -import { FWorkbook } from './sheets/f-workbook'; - -export class FUniver { - static BorderStyle = BorderStyleTypes; - - static WrapStrategy = WrapStrategy; - - constructor( - @Inject(Injector) protected readonly _injector: Injector, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @ICommandService private readonly _commandService: ICommandService - ) { - this._initialize(); - } +interface IFUniverLegacy { /** - * Initialize the FUniver instance. + * Set WebSocket URL for WebSocketService * - * @private + * @param {string} url WebSocket URL + * @returns {ISocket} WebSocket instance */ - private _initialize(): void { - this._debouncedFormulaCalculation = debounce(() => { - this._commandService.executeCommand( - SetFormulaCalculationStartMutation.id, - { - commands: [], - forceCalculation: true, - }, - { - onlyLocal: true, - } - ); - }, 10); - } + createSocket(url: string): ISocket; +} +class FUniverLegacy extends FUniver implements IFUniverLegacy { /** * Get dependencies for FUniver, you can override newAPI to add more dependencies. * @@ -131,282 +65,14 @@ export class FUniver { * @param {Univer | Injector} wrapped - The Univer instance or injector instance. * @returns {FUniver} - The FUniver instance. */ - static newAPI(wrapped: Univer | Injector): FUniver { + static override newAPI(wrapped: Univer | Injector): FUniver { const injector = wrapped instanceof Univer ? wrapped.__getInjector() : wrapped; - const dependencies = FUniver.getDependencies(injector); + const dependencies = FUniverLegacy.getDependencies(injector); dependencies.forEach((dependency) => injector.add(dependency)); return injector.createInstance(FUniver); } - static newDataValidation(): FDataValidationBuilder { - return new FDataValidationBuilder(); - } - - /** - * registerFunction may be executed multiple times, triggering multiple formula forced refreshes - */ - private _debouncedFormulaCalculation: () => void; - - /** - * Create a new spreadsheet and get the API handler of that spreadsheet. - * - * @param {Partial} data The snapshot of the spreadsheet. - * @returns {FWorkbook} FWorkbook API instance. - */ - createUniverSheet(data: Partial): FWorkbook { - const workbook = this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_SHEET, data); - return this._injector.createInstance(FWorkbook, workbook); - } - - /** - * Create a new document and get the API handler of that document. - * - * @param {Partial} data The snapshot of the document. - * @returns {FDocument} FDocument API instance. - */ - createUniverDoc(data: Partial): FDocument { - const document = this._univerInstanceService.createUnit(UniverInstanceType.UNIVER_DOC, data); - return this._injector.createInstance(FDocument, document); - } - - /** - * Dispose the UniverSheet by the `unitId`. The UniverSheet would be unload from the application. - * - * @param unitId The unit id of the UniverSheet. - * @returns Whether the Univer instance is disposed successfully. - */ - disposeUnit(unitId: string): boolean { - return this._univerInstanceService.disposeUnit(unitId); - } - - /** - * Get the spreadsheet API handler by the spreadsheet id. - * - * @param {string} id The spreadsheet id. - * @returns {FWorkbook | null} The spreadsheet API instance. - */ - getUniverSheet(id: string): FWorkbook | null { - const workbook = this._univerInstanceService.getUniverSheetInstance(id); - if (!workbook) { - return null; - } - - return this._injector.createInstance(FWorkbook, workbook); - } - - /** - * Get the document API handler by the document id. - * - * @param {string} id The document id. - * @returns {FDocument | null} The document API instance. - */ - getUniverDoc(id: string): FDocument | null { - const document = this._univerInstanceService.getUniverDocInstance(id); - if (!document) { - return null; - } - - return this._injector.createInstance(FDocument, document); - } - - /** - * Get the currently focused Univer spreadsheet. - * - * @returns {FWorkbook | null} The currently focused Univer spreadsheet. - */ - getActiveWorkbook(): FWorkbook | null { - const workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); - if (!workbook) { - return null; - } - - return this._injector.createInstance(FWorkbook, workbook); - } - - /** - * Get the currently focused Univer document. - * - * @returns {FDocument | null} The currently focused Univer document. - */ - getActiveDocument(): FDocument | null { - const document = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); - if (!document) { - return null; - } - - return this._injector.createInstance(FDocument, document); - } - - /** - * Register a function to the spreadsheet. - * - * @param {IRegisterFunctionParams} config The configuration of the function. - * @returns {IDisposable} The disposable instance. - */ - registerFunction(config: IRegisterFunctionParams): IDisposable { - let registerFunctionService = this._injector.get(IRegisterFunctionService); - - if (!registerFunctionService) { - this._injector.add([IRegisterFunctionService, { useClass: RegisterFunctionService }]); - registerFunctionService = this._injector.get(IRegisterFunctionService); - } - - const functionsDisposable = registerFunctionService.registerFunctions(config); - - // When the initialization workbook data already contains custom formulas, and then register the formula, you need to trigger a forced calculation to refresh the calculation results - this._debouncedFormulaCalculation(); - - return toDisposable(() => { - functionsDisposable.dispose(); - }); - } - - /** - * Register sheet row header render extensions. - * - * @param {string} unitId The unit id of the spreadsheet. - * @param {SheetExtension[]} extensions The extensions to register. - * @returns {IDisposable} The disposable instance. - */ - registerSheetRowHeaderExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable { - const sheetComponent = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.ROW) as SheetComponent; - const registerDisposable = sheetComponent.register(...extensions); - - return toDisposable(() => { - registerDisposable.dispose(); - sheetComponent.makeDirty(true); - }); - } - - /** - * Register sheet column header render extensions. - * - * @param {string} unitId The unit id of the spreadsheet. - * @param {SheetExtension[]} extensions The extensions to register. - * @returns {IDisposable} The disposable instance. - */ - registerSheetColumnHeaderExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable { - const sheetComponent = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.COLUMN) as SheetComponent; - const registerDisposable = sheetComponent.register(...extensions); - - return toDisposable(() => { - registerDisposable.dispose(); - sheetComponent.makeDirty(true); - }); - } - - /** - * Register sheet main render extensions. - * - * @param {string} unitId The unit id of the spreadsheet. - * @param {SheetExtension[]} extensions The extensions to register. - * @returns {IDisposable} The disposable instance. - */ - registerSheetMainExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable { - const sheetComponent = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.MAIN) as SheetComponent; - const registerDisposable = sheetComponent.register(...extensions); - - return toDisposable(() => { - registerDisposable.dispose(); - sheetComponent.makeDirty(true); - }); - } - - getFormula(): FFormula { - return this._injector.createInstance(FFormula); - } - - /** - * Get the current lifecycle stage. - * - * @returns {LifecycleStages} - The current lifecycle stage. - */ - getCurrentLifecycleStage(): LifecycleStages { - const lifecycleService = this._injector.get(LifecycleService); - return lifecycleService.stage; - } - - // #region - - /** - * Undo an editing on the currently focused document. - * - * @returns {Promise} undo result - */ - undo(): Promise { - return this._commandService.executeCommand(UndoCommand.id); - } - - /** - * Redo an editing on the currently focused document. - * - * @returns {Promise} redo result - */ - redo(): Promise { - return this._commandService.executeCommand(RedoCommand.id); - } - - copy(): Promise { - return this._commandService.executeCommand(CopyCommand.id); - } - - paste(): Promise { - return this._commandService.executeCommand(PasteCommand.id); - } - - // #endregion - - // #region listeners - - /** - * Register a callback that will be triggered before invoking a command. - * - * @param {CommandListener} callback The callback. - * @returns {IDisposable} The disposable instance. - */ - onBeforeCommandExecute(callback: CommandListener): IDisposable { - return this._commandService.beforeCommandExecuted((command, options?: IExecutionOptions) => { - callback(command, options); - }); - } - - /** - * Register a callback that will be triggered when a command is invoked. - * - * @param {CommandListener} callback The callback. - * @returns {IDisposable} The disposable instance. - */ - onCommandExecuted(callback: CommandListener): IDisposable { - return this._commandService.onCommandExecuted((command, options?: IExecutionOptions) => { - callback(command, options); - }); - } - - // #endregion - - /** - * Execute command - * - * @param {string} id Command ID - * @param {object} params Command parameters - * @param {IExecutionOptions} options Command execution options - * @returns {Promise} Command execution result - */ - executeCommand

( - id: string, - params?: P, - options?: IExecutionOptions - ): Promise { - return this._commandService.executeCommand(id, params, options); - } - - /** - * Set WebSocket URL for WebSocketService - * - * @param {string} url WebSocket URL - * @returns {ISocket} WebSocket instance - */ - createSocket(url: string): ISocket { + override createSocket(url: string): ISocket { const wsService = this._injector.get(ISocketService); const ws = wsService.createSocket(url); @@ -416,180 +82,10 @@ export class FUniver { return ws; } +} - /** - * Get sheet hooks - * - * @returns {FSheetHooks} FSheetHooks instance - */ - getSheetHooks(): FSheetHooks { - return this._injector.createInstance(FSheetHooks); - } - - /** - * Get hooks - * - * @returns {FHooks} FHooks instance - */ - getHooks(): FHooks { - return this._injector.createInstance(FHooks); - } - - /** - * Get sheet render component from render by unitId and view key. - * - * @private - * - * @param {string} unitId The unit id of the spreadsheet. - * @param {SHEET_VIEW_KEY} viewKey The view key of the spreadsheet. - * @returns {Nullable} The render component. - */ - private _getSheetRenderComponent(unitId: string, viewKey: SHEET_VIEW_KEY): Nullable { - const renderManagerService = this._injector.get(IRenderManagerService); - const render = renderManagerService.getRenderById(unitId); - if (!render) { - throw new Error('Render not found'); - } - - const { components } = render; - - const renderComponent = components.get(viewKey); - if (!renderComponent) { - throw new Error('Render component not found'); - } - - return renderComponent; - } - - /** - * Customize the column header of the spreadsheet. - * - * @param {IColumnsHeaderCfgParam} cfg The configuration of the column header. - * - * @example - * ```typescript - * customizeColumnHeader({ headerStyle: { backgroundColor: 'pink', fontSize: 9 }, columnsCfg: ['MokaII', undefined, null, { text: 'Size', textAlign: 'left' }] }); - * ``` - */ - customizeColumnHeader(cfg: IColumnsHeaderCfgParam): void { - const wb = this.getActiveWorkbook(); - if (!wb) { - console.error('WorkBook not exist'); - return; - } - const unitId = wb?.getId(); - const sheetColumn = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.COLUMN) as SpreadsheetColumnHeader; - sheetColumn.setCustomHeader(cfg); - } - - /** - * Customize the row header of the spreadsheet. - * - * @param {IRowsHeaderCfgParam} cfg The configuration of the row header. - * - * @example - * ```typescript - * customizeRowHeader({ headerStyle: { backgroundColor: 'pink', fontSize: 9 }, rowsCfg: ['MokaII', undefined, null, { text: 'Size', textAlign: 'left' }] }); - * ``` - */ - customizeRowHeader(cfg: IRowsHeaderCfgParam): void { - const wb = this.getActiveWorkbook(); - if (!wb) { - console.error('WorkBook not exist'); - return; - } - const unitId = wb?.getId(); - const sheetRow = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.ROW) as SpreadsheetRowHeader; - sheetRow.setCustomHeader(cfg); - } - - // #region API applies to all workbooks - - /** - * Enable or disable crosshair highlight. - * @param {boolean} enabled if crosshair highlight should be enabled - */ - setCrosshairHighlightEnabled(enabled: boolean): void { - if (enabled) { - this._commandService.executeCommand(EnableCrosshairHighlightOperation.id); - } else { - this._commandService.executeCommand(DisableCrosshairHighlightOperation.id); - } - } - - /** - * Set the color of the crosshair highlight. - * @param {string} color the color of the crosshair highlight - */ - setCrosshairHighlightColor(color: string): void { - this._commandService.executeCommand(SetCrosshairHighlightColorOperation.id, { - value: color, - } as ISetCrosshairHighlightColorOperationParams); - } - - // #endregion - - /** - * Get the PermissionInstance. - * - * @returns {FPermission} - The PermissionInstance. - */ - getPermission(): FPermission { - return this._injector.createInstance(FPermission); - } - - // #region watermark - - /** - * Adds a watermark to the unit. Supports both text and image watermarks based on the specified type. - * - * @param {IWatermarkTypeEnum.Text | IWatermarkTypeEnum.Image} type - The type of watermark to add. Can be either 'Text' or 'Image'. - * @param {ITextWatermarkConfig | IImageWatermarkConfig} config - The configuration object for the watermark. - * - If the type is 'Text', the config should follow the ITextWatermarkConfig interface. - * - If the type is 'Image', the config should follow the IImageWatermarkConfig interface. - * @throws {Error} Throws an error if the watermark type is unknown. - */ - addWatermark(type: IWatermarkTypeEnum.Text, config: ITextWatermarkConfig): void; - addWatermark(type: IWatermarkTypeEnum.Image, config: IImageWatermarkConfig): void; - addWatermark( - type: IWatermarkTypeEnum.Text | IWatermarkTypeEnum.Image, - config: ITextWatermarkConfig | IImageWatermarkConfig - ): void { - const watermarkService = this._injector.get(WatermarkService); - if (type === IWatermarkTypeEnum.Text) { - watermarkService.updateWatermarkConfig({ - type: IWatermarkTypeEnum.Text, - config: { - text: { - ...WatermarkTextBaseConfig, - ...config, - }, - }, - }); - } else if (type === IWatermarkTypeEnum.Image) { - watermarkService.updateWatermarkConfig({ - type: IWatermarkTypeEnum.Image, - config: { - image: { - ...WatermarkImageBaseConfig, - ...config, - }, - }, - }); - } else { - throw new Error('Unknown watermark type'); - } - } - - /** - * Deletes the currently applied watermark from the unit. - * - * This function retrieves the watermark service and invokes the method to remove any existing watermark configuration. - */ - deleteWatermark(): void { - const watermarkService = this._injector.get(WatermarkService); - watermarkService.deleteWatermarkConfig(); - } - - // #endregion +FUniver.extend(FUniverLegacy); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverLegacy {} } diff --git a/packages/facade/src/apis/hooks/__tests__/f-clipboard-hooks.spec.ts b/packages/facade/src/apis/hooks/__tests__/f-clipboard-hooks.spec.ts index ff905cc3056..fb30abc9028 100644 --- a/packages/facade/src/apis/hooks/__tests__/f-clipboard-hooks.spec.ts +++ b/packages/facade/src/apis/hooks/__tests__/f-clipboard-hooks.spec.ts @@ -14,14 +14,13 @@ * limitations under the License. */ +import type { FWorkbook, FWorksheet } from '@univerjs/sheets/facade'; import { ICommandService, type Injector, IUniverInstanceService, Univer, UniverInstanceType } from '@univerjs/core'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; +import { UniverSheetsPlugin } from '@univerjs/sheets'; import { CopyCommand, PasteCommand } from '@univerjs/ui'; -import { FUniver } from '../../facade'; -import type { FWorksheet } from '../../sheets/f-worksheet'; -import type { FWorkbook } from '../../sheets/f-workbook'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { FUniver } from '../../everything'; function createUnitTestBed(): { univer: Univer; diff --git a/packages/facade/src/apis/hooks/__tests__/f-undoredo-hooks.spec.ts b/packages/facade/src/apis/hooks/__tests__/f-undoredo-hooks.spec.ts index 349ac19677f..f2d49e571f9 100644 --- a/packages/facade/src/apis/hooks/__tests__/f-undoredo-hooks.spec.ts +++ b/packages/facade/src/apis/hooks/__tests__/f-undoredo-hooks.spec.ts @@ -14,12 +14,12 @@ * limitations under the License. */ +import type { FWorksheet } from '@univerjs/sheets/facade'; import { type Injector, IUndoRedoService, IUniverInstanceService, Univer, UniverInstanceType } from '@univerjs/core'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverRenderEnginePlugin } from '@univerjs/engine-render'; -import { FUniver } from '../../facade'; -import type { FWorksheet } from '../../sheets/f-worksheet'; +import { UniverSheetsPlugin } from '@univerjs/sheets'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { FUniver } from '../../everything'; function createUnitTestBed(): { univer: Univer; diff --git a/packages/facade/src/apis/hooks/f-clipboard-hooks.ts b/packages/facade/src/apis/hooks/f-clipboard-hooks.ts deleted file mode 100644 index f5d6defc95e..00000000000 --- a/packages/facade/src/apis/hooks/f-clipboard-hooks.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { IDisposable } from '@univerjs/core'; -import { ICommandService } from '@univerjs/core'; -import { CopyCommand, PasteCommand } from '@univerjs/ui'; -import type { FHooks } from '../f-hooks'; - -export const FClipboardHooks = { - - onBeforeCopy(this: FHooks, callback: () => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.beforeCommandExecuted((command) => { - if (command.id === CopyCommand.id) { - callback(); - } - }); - }, - onCopy(this: FHooks, callback: () => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.onCommandExecuted((command) => { - if (command.id === CopyCommand.id) { - callback(); - } - }); - }, - - onBeforePaste(this: FHooks, callback: () => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.beforeCommandExecuted((command) => { - if (command.id === PasteCommand.id) { - callback(); - } - }); - }, - onPaste(this: FHooks, callback: () => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.onCommandExecuted((command) => { - if (command.id === PasteCommand.id) { - callback(); - } - }); - }, -}; diff --git a/packages/facade/src/apis/hooks/f-undoredo-hooks.ts b/packages/facade/src/apis/hooks/f-undoredo-hooks.ts deleted file mode 100644 index 21efe97f592..00000000000 --- a/packages/facade/src/apis/hooks/f-undoredo-hooks.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { IDisposable, IUndoRedoItem } from '@univerjs/core'; -import { ICommandService, IUndoRedoService, RedoCommand, UndoCommand } from '@univerjs/core'; -import type { FHooks } from '../f-hooks'; - -export const FUndoRedoHooks = { - /** - * Hook that fires before an undo operation is executed. - * @param callback Function to be called when the event is triggered - * @returns A disposable object that can be used to unsubscribe from the event - */ - beforeUndo(this: FHooks, callback: (action: IUndoRedoItem) => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.beforeCommandExecuted((command) => { - if (command.id === UndoCommand.id) { - const undoredoService = this._injector.get(IUndoRedoService); - const action = undoredoService.pitchTopUndoElement(); - if (action) { - callback(action); - } - } - }); - }, - /** - * Hook that fires after an undo operation is executed. - * @param callback Function to be called when the event is triggered - * @returns A disposable object that can be used to unsubscribe from the event - */ - afterUndo(this: FHooks, callback: (action: IUndoRedoItem) => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.onCommandExecuted((command) => { - if (command.id === UndoCommand.id) { - const undoredoService = this._injector.get(IUndoRedoService); - const action = undoredoService.pitchTopUndoElement(); - if (action) { - callback(action); - } - } - }); - }, - /** - * Hook that fires before a redo operation is executed. - * @param callback Function to be called when the event is triggered - * @returns A disposable object that can be used to unsubscribe from the event - */ - beforeRedo(this: FHooks, callback: (action: IUndoRedoItem) => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.beforeCommandExecuted((command) => { - if (command.id === RedoCommand.id) { - const undoredoService = this._injector.get(IUndoRedoService); - const action = undoredoService.pitchTopRedoElement(); - if (action) { - callback(action); - } - } - }); - }, - /** - * Hook that fires after a redo operation is executed. - * @param callback Function to be called when the event is triggered - * @returns A disposable object that can be used to unsubscribe from the event - */ - afterRedo(this: FHooks, callback: (action: IUndoRedoItem) => void): IDisposable { - const commandService = this._injector.get(ICommandService); - - return commandService.onCommandExecuted((command) => { - if (command.id === RedoCommand.id) { - const undoredoService = this._injector.get(IUndoRedoService); - const action = undoredoService.pitchTopRedoElement(); - if (action) { - callback(action); - } - } - }); - }, -}; diff --git a/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts b/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts index 307ffe73507..3621607fa6d 100644 --- a/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts +++ b/packages/facade/src/apis/sheets/__tests__/create-formula-test-bed.ts @@ -38,9 +38,8 @@ import { RegisterFunctionService, } from '@univerjs/sheets-formula'; import enUS from '@univerjs/sheets-formula-ui/locale/en-US'; - import zhCN from '@univerjs/sheets-formula-ui/locale/zh-CN'; -import { FUniver } from '../../facade'; +import { FUniver } from '../../everything'; function getTestWorkbookDataDemo(): IWorkbookData { return { diff --git a/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts b/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts index 3d6b59b9f2d..3364f46b6ed 100644 --- a/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts +++ b/packages/facade/src/apis/sheets/__tests__/create-worksheet-test-bed.ts @@ -59,7 +59,7 @@ import enUS from '@univerjs/sheets-formula-ui/locale/en-US'; import zhCN from '@univerjs/sheets-formula-ui/locale/zh-CN'; import { ISheetSelectionRenderService, SheetRenderController, SheetSelectionRenderService, SheetSkeletonManagerService, SheetsRenderService } from '@univerjs/sheets-ui'; import { IPlatformService, IShortcutService, PlatformService, ShortcutService } from '@univerjs/ui'; -import { FUniver } from '../../facade'; +import { FUniver } from '../../everything'; function getTestWorkbookDataDemo(): IWorkbookData { return { diff --git a/packages/facade/src/apis/sheets/__tests__/f-active-range.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-active-range.spec.ts index f2adf228f9c..baa490fdf0a 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-active-range.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-active-range.spec.ts @@ -15,11 +15,10 @@ */ import type { Injector } from '@univerjs/core'; +import type { FUniver } from '../../everything'; import { ICommandService } from '@univerjs/core'; import { InsertSheetCommand, InsertSheetMutation, RemoveSheetCommand, RemoveSheetMutation, SetSelectionsOperation, SetWorksheetActiveOperation } from '@univerjs/sheets'; import { beforeEach, describe, expect, it } from 'vitest'; - -import type { FUniver } from '../../facade'; import { createFacadeTestBed } from '../../__tests__/create-test-bed'; describe('Test Active Range', () => { diff --git a/packages/facade/src/apis/sheets/__tests__/f-data-validation-builder.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-data-validation-builder.spec.ts index 1bb693a3f56..12b6d287751 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-data-validation-builder.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-data-validation-builder.spec.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import { beforeEach, describe, expect, it } from 'vitest'; import type { Injector } from '@univerjs/core'; +import type { FUniver } from '../../everything'; import { DataValidationOperator, DataValidationType, ICommandService } from '@univerjs/core'; import { SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMutation, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand } from '@univerjs/sheets'; -import { FDataValidationBuilder } from '../f-data-validation-builder'; +import { FDataValidationBuilder } from '@univerjs/sheets-data-validation/facade/f-data-validation-builder.js'; +import { beforeEach, describe, expect, it } from 'vitest'; import { createFacadeTestBed } from '../../__tests__/create-test-bed'; -import type { FUniver } from '../../facade'; describe('Test FDataValidationBuilder', () => { let get: Injector['get']; diff --git a/packages/facade/src/apis/sheets/__tests__/f-formula.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-formula.spec.ts index a9a32c86120..12dafd06e61 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-formula.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-formula.spec.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import type { ICellData, Injector, IStyleData, Nullable } from '@univerjs/core'; -import type { FUniver } from '../../facade'; +import type { FUniver, ICellData, Injector, IStyleData, Nullable } from '@univerjs/core'; import { ICommandService, IUniverInstanceService } from '@univerjs/core'; import { SetArrayFormulaDataMutation, SetFormulaCalculationNotificationMutation, SetFormulaCalculationResultMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation } from '@univerjs/engine-formula'; @@ -23,6 +22,8 @@ import { SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMut import { beforeEach, describe, expect, it } from 'vitest'; import { createFormulaTestBed } from './create-formula-test-bed'; +import '../../everything'; + describe('Test FFormula', () => { let get: Injector['get']; let commandService: ICommandService; diff --git a/packages/facade/src/apis/sheets/__tests__/f-permission.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-permission.spec.ts index fb0e7442e72..cba8db68d53 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-permission.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-permission.spec.ts @@ -15,11 +15,10 @@ */ import type { Injector } from '@univerjs/core'; +import type { FUniver } from '../../everything'; import { ICommandService, IPermissionService } from '@univerjs/core'; import { AddRangeProtectionMutation, AddWorksheetProtectionMutation, DeleteRangeProtectionMutation, DeleteWorksheetProtectionMutation, RangeProtectionPermissionEditPoint, RangeProtectionRuleModel, SetRangeProtectionMutation, WorkbookEditablePermission, WorksheetEditPermission } from '@univerjs/sheets'; import { beforeEach, describe, expect, it } from 'vitest'; - -import type { FUniver } from '../../facade'; import { createFacadeTestBed } from '../../__tests__/create-test-bed'; describe('Test FPermission', () => { diff --git a/packages/facade/src/apis/sheets/__tests__/f-range.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-range.spec.ts index cec1b0e523d..0147d62b410 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-range.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-range.spec.ts @@ -20,12 +20,11 @@ import type { ICellData, Injector, IRange, IStyleData, Nullable } from '@univerj import { DataValidationType, HorizontalAlign, ICommandService, IUniverInstanceService, VerticalAlign, WrapStrategy } from '@univerjs/core'; import { FormulaDataModel } from '@univerjs/engine-formula'; import { AddWorksheetMergeCommand, SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMutation, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand } from '@univerjs/sheets'; - import { AddSheetDataValidationCommand } from '@univerjs/sheets-data-validation'; -import { ClearSheetsFilterCriteriaCommand, RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand } from '@univerjs/sheets-filter-ui'; +import { ClearSheetsFilterCriteriaCommand, RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand } from '@univerjs/sheets-filter'; import { beforeEach, describe, expect, it } from 'vitest'; import { createFacadeTestBed } from '../../__tests__/create-test-bed'; -import { FUniver } from '../../facade'; +import { FUniver } from '../../everything'; describe('Test FRange', () => { let get: Injector['get']; diff --git a/packages/facade/src/apis/sheets/__tests__/f-sheet-hooks.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-sheet-hooks.spec.ts index f4c9c088775..39cefa06283 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-sheet-hooks.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-sheet-hooks.spec.ts @@ -15,15 +15,15 @@ */ import type { ICellData, Injector, IStyleData, Nullable, Workbook } from '@univerjs/core'; +import type { IDragCellPosition, IHoverCellPosition } from '@univerjs/sheets-ui'; import { ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMutation, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand } from '@univerjs/sheets'; -import { beforeEach, describe, expect, it } from 'vitest'; -import { Subject } from 'rxjs'; -import type { IDragCellPosition, IHoverCellPosition } from '@univerjs/sheets-ui'; import { DragManagerService, HoverManagerService } from '@univerjs/sheets-ui'; +import { Subject } from 'rxjs'; +import { beforeEach, describe, expect, it } from 'vitest'; import { createFacadeTestBed } from '../../__tests__/create-test-bed'; -import { FSheetHooks } from '../f-sheet-hooks'; +import { FSheetHooks } from '../../everything'; class MockDataTransfer implements DataTransfer { effectAllowed: 'none' | 'copy' | 'link' | 'move' | 'all' | 'copyLink' | 'copyMove' | 'linkMove' | 'uninitialized'; diff --git a/packages/facade/src/apis/sheets/__tests__/f-workbook.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-workbook.spec.ts index cb2837d8337..35b189ec849 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-workbook.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-workbook.spec.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import type { ICellData, Injector, IStyleData, Nullable } from '@univerjs/core'; +import type { ICellData, Injector, Nullable } from '@univerjs/core'; +import type { FUniver } from '../../everything'; import { ICommandService, IUniverInstanceService } from '@univerjs/core'; import { InsertSheetCommand, InsertSheetMutation, RemoveSheetCommand, RemoveSheetMutation, SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMutation, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand, SetWorksheetActiveOperation } from '@univerjs/sheets'; import { beforeEach, describe, expect, it } from 'vitest'; - -import type { FUniver } from '../../facade'; import { createFacadeTestBed } from '../../__tests__/create-test-bed'; describe('Test FWorkbook', () => { @@ -32,12 +31,6 @@ describe('Test FWorkbook', () => { endRow: number, endColumn: number ) => Nullable; - let getStyleByPosition: ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ) => Nullable; beforeEach(() => { const testBed = createFacadeTestBed(); @@ -68,19 +61,6 @@ describe('Test FWorkbook', () => { ?.getSheetBySheetId('sheet1') ?.getRange(startRow, startColumn, endRow, endColumn) .getValue(); - - getStyleByPosition = ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ): Nullable => { - const value = getValueByPosition(startRow, startColumn, endRow, endColumn); - const styles = get(IUniverInstanceService).getUniverSheetInstance('test')?.getStyles(); - if (value && styles) { - return styles.getStyleByCell(value); - } - }; }); it('Workbook getSheets', () => { diff --git a/packages/facade/src/apis/sheets/__tests__/f-worksheet.spec.ts b/packages/facade/src/apis/sheets/__tests__/f-worksheet.spec.ts index 2be1983f2c5..3cb9c24a2d3 100644 --- a/packages/facade/src/apis/sheets/__tests__/f-worksheet.spec.ts +++ b/packages/facade/src/apis/sheets/__tests__/f-worksheet.spec.ts @@ -14,31 +14,20 @@ * limitations under the License. */ -import type { ICellData, Injector, IStyleData, Nullable, Workbook } from '@univerjs/core'; -import type { FUniver } from '../../facade'; +import type { FUniver, Injector, Workbook } from '@univerjs/core'; import { ICommandService, IUniverInstanceService, RANGE_TYPE, UniverInstanceType } from '@univerjs/core'; -import { AddWorksheetMergeCommand, AddWorksheetMergeMutation, InsertColCommand, InsertColMutation, InsertRowCommand, InsertRowMutation, MoveColsCommand, MoveColsMutation, MoveRowsCommand, MoveRowsMutation, RemoveColCommand, RemoveColMutation, RemoveRowCommand, RemoveRowMutation, RemoveWorksheetMergeCommand, RemoveWorksheetMergeMutation, SetColDataCommand, SetColDataMutation, SetColHiddenCommand, SetColHiddenMutation, SetColVisibleMutation, SetColWidthCommand, SetFrozenCommand, SetFrozenMutation, SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMutation, SetRowDataCommand, SetRowDataMutation, SetRowHeightCommand, SetRowHiddenCommand, SetRowHiddenMutation, SetRowVisibleMutation, SetSelectionsOperation, SetSpecificColsVisibleCommand, SetSpecificRowsVisibleCommand, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand, SetWorksheetColWidthMutation, SetWorksheetRowHeightMutation, SetWorksheetRowIsAutoHeightCommand, SetWorksheetRowIsAutoHeightMutation, SheetsSelectionsService } from '@univerjs/sheets'; +import { AddWorksheetMergeCommand, AddWorksheetMergeMutation, CancelFrozenCommand, InsertColCommand, InsertColMutation, InsertRowCommand, InsertRowMutation, MoveColsCommand, MoveColsMutation, MoveRowsCommand, MoveRowsMutation, RemoveColCommand, RemoveColMutation, RemoveRowCommand, RemoveRowMutation, RemoveWorksheetMergeCommand, RemoveWorksheetMergeMutation, SetColDataCommand, SetColDataMutation, SetColHiddenCommand, SetColHiddenMutation, SetColVisibleMutation, SetColWidthCommand, SetFrozenCommand, SetFrozenMutation, SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRangeValuesMutation, SetRowDataCommand, SetRowDataMutation, SetRowHeightCommand, SetRowHiddenCommand, SetRowHiddenMutation, SetRowVisibleMutation, SetSelectionsOperation, SetSpecificColsVisibleCommand, SetSpecificRowsVisibleCommand, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand, SetWorksheetColWidthMutation, SetWorksheetRowHeightMutation, SetWorksheetRowIsAutoHeightCommand, SetWorksheetRowIsAutoHeightMutation, SheetsSelectionsService } from '@univerjs/sheets'; -import { CancelFrozenCommand } from '@univerjs/sheets-ui'; import { beforeEach, describe, expect, it } from 'vitest'; import { createWorksheetTestBed } from './create-worksheet-test-bed'; +import '../../everything'; + describe('Test FWorksheet', () => { let get: Injector['get']; let commandService: ICommandService; let univerAPI: FUniver; - let getValueByPosition: ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ) => Nullable; - let getStyleByPosition: ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ) => Nullable; + let setSelection: (startRow: number, endRow: number, startColumn: number, endColumn: number) => void; beforeEach(() => { @@ -100,31 +89,6 @@ describe('Test FWorksheet', () => { commandService.registerCommand(SetFrozenMutation); commandService.registerCommand(CancelFrozenCommand); - getValueByPosition = ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ): Nullable => - get(IUniverInstanceService) - .getUniverSheetInstance('test') - ?.getSheetBySheetId('sheet1') - ?.getRange(startRow, startColumn, endRow, endColumn) - .getValue(); - - getStyleByPosition = ( - startRow: number, - startColumn: number, - endRow: number, - endColumn: number - ): Nullable => { - const value = getValueByPosition(startRow, startColumn, endRow, endColumn); - const styles = get(IUniverInstanceService).getUniverSheetInstance('test')?.getStyles(); - if (value && styles) { - return styles.getStyleByCell(value); - } - }; - setSelection = (startRow: number, endRow: number, startColumn: number, endColumn: number, rangeType: RANGE_TYPE = RANGE_TYPE.NORMAL) => { const selectionManagerService = get(SheetsSelectionsService); selectionManagerService.addSelections([ diff --git a/packages/facade/src/apis/sheets/f-workbook.ts b/packages/facade/src/apis/sheets/f-workbook.ts deleted file mode 100644 index e4d2ff16574..00000000000 --- a/packages/facade/src/apis/sheets/f-workbook.ts +++ /dev/null @@ -1,634 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { CommandListener, ICommandInfo, IDisposable, IExecutionOptions, IRange, IWorkbookData, Nullable, ObjectMatrix, Workbook } from '@univerjs/core'; -import type { IRuleChange } from '@univerjs/data-validation'; -import type { IUpdateCommandParams } from '@univerjs/docs-ui'; -import type { - ISetSelectionsOperationParams, - ISheetCommandSharedParams, -} from '@univerjs/sheets'; -import type { IAddSheetDataValidationCommandParams, IDataValidationResCache, IRemoveSheetAllDataValidationCommandParams, IRemoveSheetDataValidationCommandParams, IUpdateSheetDataValidationOptionsCommandParams, IUpdateSheetDataValidationRangeCommandParams, IUpdateSheetDataValidationSettingCommandParams, IValidStatusChange } from '@univerjs/sheets-data-validation'; -import type { ICanvasFloatDom } from '@univerjs/sheets-drawing-ui'; -import type { ISheetHyperLinkInfo } from '@univerjs/sheets-hyper-link-ui'; -import type { CommentUpdate, IAddCommentCommandParams, IDeleteCommentCommandParams } from '@univerjs/thread-comment'; -import type { IDialogPartMethodOptions, ISidebarMethodOptions } from '@univerjs/ui'; - -import type { IFComponentKey } from './utils'; -import { - ICommandService, - ILogService, - Inject, - Injector, - IPermissionService, - IResourceLoaderService, - IUniverInstanceService, - mergeWorksheetSnapshotWithDefault, - RedoCommand, - toDisposable, - UndoCommand, - UniverInstanceType, -} from '@univerjs/core'; -import { getPrimaryForRange, InsertSheetCommand, RemoveSheetCommand, SetSelectionsOperation, SetWorksheetActiveOperation, SheetsSelectionsService, WorkbookEditablePermission } from '@univerjs/sheets'; -import { AddSheetDataValidationCommand, RemoveSheetAllDataValidationCommand, RemoveSheetDataValidationCommand, SheetDataValidationModel, SheetsDataValidationValidatorService, UpdateSheetDataValidationOptionsCommand, UpdateSheetDataValidationRangeCommand, UpdateSheetDataValidationSettingCommand } from '@univerjs/sheets-data-validation'; -import { SheetsHyperLinkResolverService } from '@univerjs/sheets-hyper-link-ui'; -import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, ThreadCommentModel, UpdateCommentCommand } from '@univerjs/thread-comment'; -import { IDialogService, ISidebarService } from '@univerjs/ui'; - -import { filter } from 'rxjs'; -import { FRange } from './f-range'; -import { FWorksheet } from './f-worksheet'; - -export interface IFICanvasFloatDom extends Omit, IFComponentKey { - -} - -export class FWorkbook { - readonly id: string; - - constructor( - private readonly _workbook: Workbook, - @Inject(Injector) protected readonly _injector: Injector, - @Inject(IResourceLoaderService) private readonly _resourceLoaderService: IResourceLoaderService, - @Inject(SheetsSelectionsService) private readonly _selectionManagerService: SheetsSelectionsService, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @ICommandService private readonly _commandService: ICommandService, - @IPermissionService private readonly _permissionService: IPermissionService, - @ILogService private readonly _logService: ILogService - - ) { - this.id = this._workbook.getUnitId(); - } - - private get _dataValidationModel(): SheetDataValidationModel { - return this._injector.get(SheetDataValidationModel); - } - - private get _threadCommentModel(): ThreadCommentModel { - return this._injector.get(ThreadCommentModel); - } - - getId(): string { - return this.id; - } - - getName(): string { - return this._workbook.getName(); - } - - /** - * save workbook snapshot data, including conditional formatting, data validation, and other plugin data. - */ - save(): IWorkbookData { - const snapshot = this._resourceLoaderService.saveUnit(this._workbook.getUnitId())!; - return snapshot; - } - - /** - * @deprecated use 'save' instead. - * @return {*} {IWorkbookData} - * @memberof FWorkbook - */ - getSnapshot(): IWorkbookData { - this._logService.warn(`use 'save' instead of 'getSnapshot'`); - return this.save(); - } - - /** - * Get the active sheet of the workbook. - * @returns The active sheet of the workbook - */ - getActiveSheet(): FWorksheet { - const activeSheet = this._workbook.getActiveSheet(); - return this._injector.createInstance(FWorksheet, this, this._workbook, activeSheet); - } - - /** - * Gets all the worksheets in this workbook - * @returns An array of all the worksheets in the workbook - */ - getSheets(): FWorksheet[] { - return this._workbook.getSheets().map((sheet) => { - return this._injector.createInstance(FWorksheet, this, this._workbook, sheet); - }); - } - - /** - * Create a new worksheet and returns a handle to it. - * @param name Name of the new sheet - * @param rows How may rows would the new sheet have - * @param column How many columns would the new sheet have - * @returns The new created sheet - */ - create(name: string, rows: number, column: number): FWorksheet { - const newSheet = mergeWorksheetSnapshotWithDefault({}); - newSheet.rowCount = rows; - newSheet.columnCount = column; - newSheet.name = name; - newSheet.id = name.toLowerCase().replace(/ /g, '-'); - - this._commandService.syncExecuteCommand(InsertSheetCommand.id, { - unitId: this.id, - index: this._workbook.getSheets().length, - sheet: newSheet, - }); - this._commandService.syncExecuteCommand(SetWorksheetActiveOperation.id, { - unitId: this.id, - subUnitId: this._workbook.getSheets()[this._workbook.getSheets().length - 1].getSheetId(), - }); - const worksheet = this._workbook.getActiveSheet(); - if (!worksheet) { - throw new Error('No active sheet found'); - } - - return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); - } - - /** - * Get a worksheet by sheet id. - * @param sheetId The id of the sheet to get. - * @return The worksheet with given sheet id - */ - getSheetBySheetId(sheetId: string): FWorksheet | null { - const worksheet = this._workbook.getSheetBySheetId(sheetId); - if (!worksheet) { - return null; - } - - return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); - } - - /** - * Get a worksheet by sheet name. - * @param name The name of the sheet to get. - * @returns The worksheet with given sheet name - */ - getSheetByName(name: string): FWorksheet | null { - const worksheet = this._workbook.getSheetBySheetName(name); - if (!worksheet) { - return null; - } - - return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); - } - - /** - * Sets the given worksheet to be the active worksheet in the workbook. - * @param sheet The worksheet to set as the active worksheet. - * @returns The active worksheet - */ - setActiveSheet(sheet: FWorksheet): FWorksheet { - this._commandService.syncExecuteCommand(SetWorksheetActiveOperation.id, { - unitId: this.id, - subUnitId: sheet.getSheetId(), - }); - - return sheet; - } - - /** - * Inserts a new worksheet into the workbook. - * Using a default sheet name. The new sheet becomes the active sheet - * @returns The new sheet - */ - insertSheet(): FWorksheet { - this._commandService.syncExecuteCommand(InsertSheetCommand.id); - - const unitId = this.id; - const subUnitId = this._workbook.getSheets()[this._workbook.getSheets().length - 1].getSheetId(); - - this._commandService.syncExecuteCommand(SetWorksheetActiveOperation.id, { - unitId, - subUnitId, - }); - const worksheet = this._workbook.getActiveSheet(); - if (!worksheet) { - throw new Error('No active sheet found'); - } - - return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); - } - - /** - * Deletes the specified worksheet. - * @param sheet The worksheet to delete. - */ - deleteSheet(sheet: FWorksheet): void { - const unitId = this.id; - const subUnitId = sheet.getSheetId(); - this._commandService.executeCommand(RemoveSheetCommand.id, { - unitId, - subUnitId, - }); - } - - // #region editing - - undo(): Promise { - this._univerInstanceService.focusUnit(this.id); - return this._commandService.executeCommand(UndoCommand.id); - } - - redo(): Promise { - this._univerInstanceService.focusUnit(this.id); - return this._commandService.executeCommand(RedoCommand.id); - } - - // #endregion - /** - * open a sidebar - * @param params the sidebar options - * @returns the disposable object - */ - openSiderbar(params: ISidebarMethodOptions): IDisposable { - const sideBarService = this._injector.get(ISidebarService); - return sideBarService.open(params); - } - - /** - * open a dialog - * @param dialog the dialog options - * @returns the disposable object - */ - openDialog(dialog: IDialogPartMethodOptions): IDisposable { - const dialogService = this._injector.get(IDialogService); - const disposable = dialogService.open({ - ...dialog, - onClose: () => { - disposable.dispose(); - }, - }); - return disposable; - } - // #region callbacks - - /** - * Register a callback that will be triggered before invoking a command targeting the Univer sheet. - * @param callback the callback. - * @returns A function to dispose the listening. - */ - onBeforeCommandExecute(callback: CommandListener): IDisposable { - return this._commandService.beforeCommandExecuted((command) => { - if ((command as ICommandInfo).params?.unitId !== this.id) { - return; - } - - callback(command); - }); - } - - /** - * Register a callback that will be triggered when a command is invoked targeting the Univer sheet. - * @param callback the callback. - * @returns A function to dispose the listening. - */ - onCommandExecuted(callback: CommandListener): IDisposable { - return this._commandService.onCommandExecuted((command) => { - if ((command as ICommandInfo).params?.unitId !== this.id) { - return; - } - - callback(command); - }); - } - - onSelectionChange(callback: (selections: IRange[]) => void): IDisposable { - return toDisposable( - this._selectionManagerService.selectionMoveEnd$.subscribe((selections) => { - if (this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getUnitId() !== this.id) { - return; - } - - if (!selections?.length) { - callback([]); - } else { - // TODO@wzhudev: filtered out ranges changes not other currently sheet - callback(selections!.map((s) => s.range)); - } - }) - ); - } - - /** - * Used to modify the editing permissions of the workbook. When the value is false, editing is not allowed. - * @param {boolean} value editable value want to set - */ - setEditable(value: boolean): void { - const instance = new WorkbookEditablePermission(this._workbook.getUnitId()); - const editPermissionPoint = this._permissionService.getPermissionPoint(instance.id); - if (!editPermissionPoint) { - this._permissionService.addPermissionPoint(instance); - } - this._permissionService.updatePermissionPoint(instance.id, value); - } - - // #region callbacks - - /** - * get data validation validator status for current workbook - * @returns matrix of validator status - */ - getValidatorStatus(): Promise>>> { - const validatorService = this._injector.get(SheetsDataValidationValidatorService); - return validatorService.validatorWorkbook( - this._workbook.getUnitId() - ); - } - - /** - * Sets the active selection region for this sheet. - * @param range The range to set as the active selection. - */ - setActiveRange(range: FRange): void { - // In theory, FRange should belong to a specific context, rather than getting the currently active sheet - const sheet = this.getActiveSheet(); - const sheetId = range.getRange().sheetId || sheet.getSheetId(); - - const worksheet = sheetId ? this._workbook.getSheetBySheetId(sheetId) : this._workbook.getActiveSheet(true); - if (!worksheet) { - throw new Error('No active sheet found'); - } - - // if the range is not in the current sheet, set the active sheet to the range's sheet - if (worksheet.getSheetId() !== sheet.getSheetId()) { - this.setActiveSheet(this._injector.createInstance(FWorksheet, this, this._workbook, worksheet)); - } - - const setSelectionOperationParams: ISetSelectionsOperationParams = { - unitId: this.getId(), - subUnitId: sheetId, - - selections: [range].map((r) => ({ range: r.getRange(), primary: getPrimaryForRange(r.getRange(), worksheet), style: null })), - }; - - this._commandService.syncExecuteCommand(SetSelectionsOperation.id, setSelectionOperationParams); - } - - /** - * Returns the selected range in the active sheet, or null if there is no active range. - * @returns the active range - */ - getActiveRange(): FRange | null { - const activeSheet = this._workbook.getActiveSheet(); - const selections = this._selectionManagerService.getCurrentSelections(); - const active = selections.find((selection) => !!selection.primary); - if (!active) { - return null; - } - - return this._injector.createInstance(FRange, this._workbook, activeSheet, active.range); - } - - // region DataValidationHooks - /** - * The onDataValidationChange event is fired when the data validation rule of this sheet is changed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onDataValidationChange(callback: (ruleChange: IRuleChange) => void): IDisposable { - return toDisposable(this._dataValidationModel.ruleChange$.pipe(filter((change) => change.unitId === this._workbook.getUnitId())).subscribe(callback)); - } - - /** - * The onDataValidationStatusChange event is fired when the data validation status of this sheet is changed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onDataValidationStatusChange(callback: (statusChange: IValidStatusChange) => void): IDisposable { - return toDisposable(this._dataValidationModel.validStatusChange$.pipe(filter((change) => change.unitId === this._workbook.getUnitId())).subscribe(callback)); - } - - /** - * The onBeforeAddDataValidation event is fired before the data validation rule is added. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeAddDataValidation(callback: (params: IAddSheetDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IAddSheetDataValidationCommandParams; - if (commandInfo.id === AddSheetDataValidationCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeAddDataValidation'); - } - } - })); - } - - /** - * The onBeforeUpdateDataValidationCriteria event is fired before the data validation rule is updated. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeUpdateDataValidationCriteria(callback: (params: IUpdateSheetDataValidationSettingCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IUpdateSheetDataValidationSettingCommandParams; - if (commandInfo.id === UpdateSheetDataValidationSettingCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeUpdateDataValidationCriteria'); - } - } - })); - } - - /** - * The onBeforeUpdateDataValidationRange event is fired before the data validation rule is updated. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeUpdateDataValidationRange(callback: (params: IUpdateSheetDataValidationRangeCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IUpdateSheetDataValidationRangeCommandParams; - if (commandInfo.id === UpdateSheetDataValidationRangeCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeUpdateDataValidationRange'); - } - } - })); - } - - /** - * The onBeforeUpdateDataValidationOptions event is fired before the data validation rule is updated. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeUpdateDataValidationOptions(callback: (params: IUpdateSheetDataValidationOptionsCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IUpdateSheetDataValidationOptionsCommandParams; - if (commandInfo.id === UpdateSheetDataValidationOptionsCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeUpdateDataValidationOptions'); - } - } - })); - } - - /** - * The onBeforeDeleteDataValidation event is fired before the data validation rule is deleted. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeDeleteDataValidation(callback: (params: IRemoveSheetDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IRemoveSheetDataValidationCommandParams; - if (commandInfo.id === RemoveSheetDataValidationCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeDeleteDataValidation'); - } - } - })); - } - - /** - * The onBeforeDeleteAllDataValidation event is fired before delete all data validation rules. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeDeleteAllDataValidation(callback: (params: IRemoveSheetAllDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IRemoveSheetAllDataValidationCommandParams; - if (commandInfo.id === RemoveSheetAllDataValidationCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeDeleteAllDataValidation'); - } - } - })); - } - - // endregion - - // region ThreadCommentHooks - /** - * The onThreadCommentChange event is fired when the thread comment of this sheet is changed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onThreadCommentChange(callback: (commentUpdate: CommentUpdate) => void | false): IDisposable { - return toDisposable(this._threadCommentModel.commentUpdate$.pipe(filter((change) => change.unitId === this._workbook.getUnitId())).subscribe(callback)); - } - - /** - * The onThreadCommentChange event is fired when the thread comment of this sheet is changed. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeAddThreadComment(callback: (params: IAddCommentCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IAddCommentCommandParams; - if (commandInfo.id === AddCommentCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeAddThreadComment'); - } - } - })); - } - - /** - * The onBeforeUpdateThreadComment event is fired before the thread comment is updated. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeUpdateThreadComment(callback: (params: IUpdateCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IUpdateCommandParams; - if (commandInfo.id === UpdateCommentCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeUpdateThreadComment'); - } - } - })); - } - - /** - * The onBeforeDeleteThreadComment event is fired before the thread comment is deleted. - * @param callback Callback function that will be called when the event is fired - * @returns A disposable object that can be used to unsubscribe from the event - */ - onBeforeDeleteThreadComment(callback: (params: IDeleteCommentCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { - return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { - const params = commandInfo.params as IDeleteCommentCommandParams; - if (commandInfo.id === DeleteCommentCommand.id || commandInfo.id === DeleteCommentTreeCommand.id) { - if (params.unitId !== this._workbook.getUnitId()) { - return; - } - if (callback(params, options) === false) { - throw new Error('Command is stopped by the hook onBeforeDeleteThreadComment'); - } - } - })); - } - - // endregion - - // #region hyperlink - /** - * create a hyperlink for the sheet - * @param sheetId the sheet id to link - * @param range the range to link, or define-name id - * @returns the hyperlink string - */ - createSheetHyperlink(sheetId: string, range?: string | IRange): string { - const resolverService = this._injector.get(SheetsHyperLinkResolverService); - return resolverService.buildHyperLink(this.getId(), sheetId, range); - } - - /** - * parse the hyperlink string to get the hyperlink info - * @param hyperlink the hyperlink string - * @returns the hyperlink info - */ - parseSheetHyperlink(hyperlink: string): ISheetHyperLinkInfo { - const resolverService = this._injector.get(SheetsHyperLinkResolverService); - return resolverService.parseHyperLink(hyperlink); - } - - /** - * navigate to the sheet hyperlink - * @param hyperlink the hyperlink string - */ - navigateToSheetHyperlink(hyperlink: string): void { - const resolverService = this._injector.get(SheetsHyperLinkResolverService); - const info = resolverService.parseHyperLink(hyperlink); - info.handler(); - } - // #endregion -} diff --git a/packages/facade/src/index.ts b/packages/facade/src/index.ts index f7d930be878..77ab72f73c2 100644 --- a/packages/facade/src/index.ts +++ b/packages/facade/src/index.ts @@ -14,24 +14,10 @@ * limitations under the License. */ -export type { FontLine, FontStyle, FontWeight } from './apis/sheets/f-range'; +import './apis/everything'; +import './apis/facade'; -export { FUniver } from './apis/facade'; +export * from './apis/everything'; -export { FHooks } from './apis/f-hooks'; - -// #region - Univer Sheet - -export { FFilter } from './apis/sheets/f-filter'; -export { FFormula } from './apis/sheets/f-formula'; -export { FPermission } from './apis/sheets/f-permission'; -export { FRange } from './apis/sheets/f-range'; -export { FSelection } from './apis/sheets/f-selection'; -export { FSheetHooks } from './apis/sheets/f-sheet-hooks'; -export { FWorkbook } from './apis/sheets/f-workbook'; -export { FWorksheet } from './apis/sheets/f-worksheet'; -export { FDataValidation } from './apis/sheets/f-data-validation'; -export { FDataValidationBuilder } from './apis/sheets/f-data-validation-builder'; -export { FThreadComment } from './apis/sheets/f-thread-comment'; - -// #endregion +console.error(`[!DEPRECATION WARNING!] @univerjs/facade and @univerjs-pro/facade is deprecated and will be removed in v0.6.0. +Please refer to our official guide to migrate. https://univer.ai/guides/sheet/getting-started/facade`); diff --git a/packages-experimental/rpc-node/README.md b/packages/rpc-node/README.md similarity index 100% rename from packages-experimental/rpc-node/README.md rename to packages/rpc-node/README.md diff --git a/packages-experimental/rpc-node/package.json b/packages/rpc-node/package.json similarity index 98% rename from packages-experimental/rpc-node/package.json rename to packages/rpc-node/package.json index d719ebb1b7f..e8b38dafb75 100644 --- a/packages-experimental/rpc-node/package.json +++ b/packages/rpc-node/package.json @@ -1,7 +1,7 @@ { "name": "@univerjs/rpc-node", - "version": "0.0.1", - "private": true, + "version": "0.5.0", + "private": false, "description": "", "author": "DreamNum ", "license": "Apache-2.0", diff --git a/packages-experimental/rpc-node/src/index.ts b/packages/rpc-node/src/index.ts similarity index 100% rename from packages-experimental/rpc-node/src/index.ts rename to packages/rpc-node/src/index.ts diff --git a/packages-experimental/rpc-node/src/plugin.ts b/packages/rpc-node/src/plugin.ts similarity index 70% rename from packages-experimental/rpc-node/src/plugin.ts rename to packages/rpc-node/src/plugin.ts index 75916acbac3..8f5254abb01 100644 --- a/packages-experimental/rpc-node/src/plugin.ts +++ b/packages/rpc-node/src/plugin.ts @@ -16,10 +16,11 @@ import type { Dependency } from '@univerjs/core'; import type { IMessageProtocol } from '@univerjs/rpc'; -import type { Serializable } from 'node:child_process'; +import { fork, type Serializable } from 'node:child_process'; import process from 'node:process'; -import { IConfigService, Inject, Injector, Plugin } from '@univerjs/core'; -import { ChannelService, +import { IConfigService, ILogService, Inject, Injector, Plugin } from '@univerjs/core'; +import { + ChannelService, DataSyncPrimaryController, DataSyncReplicaController, IRemoteInstanceService, @@ -31,7 +32,8 @@ import { ChannelService, import { Observable, shareReplay } from 'rxjs'; export interface IUniverRPCNodeMainConfig { - messageProtocol: IMessageProtocol; + /** Path of the computing worker scripts. */ + workerSrc: string; } const UNIVER_RPC_NODE_MAIN_PLUGIN_CONFIG_KEY = 'node-rpc.main.config'; @@ -50,9 +52,12 @@ export class UniverRPCNodeMainPlugin extends Plugin { } override onStarting(): void { + const { workerSrc } = this._config; + const messageProtocol = createNodeMessagePortOnMain(this._injector, workerSrc); + const dependencies: Dependency[] = [ [IRPCChannelService, { - useFactory: () => new ChannelService(this._config.messageProtocol), + useFactory: () => new ChannelService(messageProtocol), }], [DataSyncPrimaryController], [IRemoteSyncService, { useClass: RemoteSyncPrimaryService }], @@ -87,12 +92,36 @@ export class UniverRPCNodeWorkerPlugin extends Plugin { } } +function createNodeMessagePortOnMain(injector: Injector, path: string): IMessageProtocol { + const logService = injector.get(ILogService); + + const child = fork(path); + child.on('spawn', () => logService.log('Child computing process spawned!')); + child.on('error', (error) => logService.error(error)); + + const messageProtocol: IMessageProtocol = { + send(message: unknown): void { + child.send(message as Serializable); + }, + onMessage: new Observable((subscriber) => { + const handler = (message: unknown) => { + subscriber.next(message); + }; + + child.on('message', handler); + return () => child.off('message', handler); + }).pipe(shareReplay(1)), + }; + + return messageProtocol; +} + function createNodeWorkerMessageProtocol(): IMessageProtocol { return { send(message) { process.send!(message as Serializable); }, - onMessage: new Observable((subscriber) => { + onMessage: new Observable((subscriber) => { const handler = (event: unknown) => { subscriber.next(event); }; diff --git a/packages-experimental/rpc-node/src/vite-env.d.ts b/packages/rpc-node/src/vite-env.d.ts similarity index 100% rename from packages-experimental/rpc-node/src/vite-env.d.ts rename to packages/rpc-node/src/vite-env.d.ts diff --git a/packages-experimental/rpc-node/tsconfig.json b/packages/rpc-node/tsconfig.json similarity index 100% rename from packages-experimental/rpc-node/tsconfig.json rename to packages/rpc-node/tsconfig.json diff --git a/packages-experimental/rpc-node/tsconfig.node.json b/packages/rpc-node/tsconfig.node.json similarity index 100% rename from packages-experimental/rpc-node/tsconfig.node.json rename to packages/rpc-node/tsconfig.node.json diff --git a/packages-experimental/rpc-node/vite.config.ts b/packages/rpc-node/vite.config.ts similarity index 100% rename from packages-experimental/rpc-node/vite.config.ts rename to packages/rpc-node/vite.config.ts diff --git a/packages/rpc/src/services/rpc/rpc.service.ts b/packages/rpc/src/services/rpc/rpc.service.ts index 914cf41dcf3..e03eb5b0310 100644 --- a/packages/rpc/src/services/rpc/rpc.service.ts +++ b/packages/rpc/src/services/rpc/rpc.service.ts @@ -14,23 +14,31 @@ * limitations under the License. */ -import { RxDisposable } from '@univerjs/core'; import type { Subscription } from 'rxjs'; +import { RxDisposable } from '@univerjs/core'; import { BehaviorSubject, firstValueFrom, isObservable, Observable, of } from 'rxjs'; import { filter, take, takeUntil } from 'rxjs/operators'; +// TODO: change this parameter type to `Serializable`. + /** This protocol is for transferring data from the two peer univer instance running in different locations. */ export interface IMessageProtocol { + // eslint-disable-next-line ts/no-explicit-any send(message: any): void; + // eslint-disable-next-line ts/no-explicit-any onMessage: Observable; } +// TODO: change this parameter type to `Serializable`. + /** * Channel is a combination of methods and event sources. These methods and * event sources are usually provided by the same service or controller. */ export interface IChannel { + // eslint-disable-next-line ts/no-explicit-any call(method: string, args?: any): Promise; + // eslint-disable-next-line ts/no-explicit-any subscribe(event: string, args?: any): Observable; } diff --git a/packages/sheets-conditional-formatting-ui/src/controllers/cf.editor.controller.ts b/packages/sheets-conditional-formatting-ui/src/controllers/cf.editor.controller.ts index c70d9576129..6c35d32fdaa 100644 --- a/packages/sheets-conditional-formatting-ui/src/controllers/cf.editor.controller.ts +++ b/packages/sheets-conditional-formatting-ui/src/controllers/cf.editor.controller.ts @@ -20,17 +20,16 @@ import { Inject, toDisposable, } from '@univerjs/core'; - +import { AFTER_CELL_EDIT, SheetInterceptorService } from '@univerjs/sheets'; import { ConditionalFormattingService } from '@univerjs/sheets-conditional-formatting'; -import { IEditorBridgeService } from '@univerjs/sheets-ui'; export class ConditionalFormattingEditorController extends Disposable { constructor( - @Inject(IEditorBridgeService) private _editorBridgeService: IEditorBridgeService, - @Inject(ConditionalFormattingService) private _conditionalFormattingService: ConditionalFormattingService - + @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, + @Inject(ConditionalFormattingService) private readonly _conditionalFormattingService: ConditionalFormattingService ) { super(); + this._initInterceptorEditorEnd(); } @@ -42,8 +41,8 @@ export class ConditionalFormattingEditorController extends Disposable { private _initInterceptorEditorEnd() { this.disposeWithMe( toDisposable( - this._editorBridgeService.interceptor.intercept( - this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT, + this._sheetInterceptorService.writeCellInterceptor.intercept( + AFTER_CELL_EDIT, { handler: (value, context, next) => { const result = this._conditionalFormattingService.composeStyle(context.unitId, context.subUnitId, context.row, context.col); diff --git a/packages/sheets-crosshair-highlight/package.json b/packages/sheets-crosshair-highlight/package.json index 5e38819a74d..5e54d0afe23 100644 --- a/packages/sheets-crosshair-highlight/package.json +++ b/packages/sheets-crosshair-highlight/package.json @@ -21,7 +21,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/sheets-crosshair-highlight/src/facade/f-univer.ts b/packages/sheets-crosshair-highlight/src/facade/f-univer.ts new file mode 100644 index 00000000000..272cd6c1c89 --- /dev/null +++ b/packages/sheets-crosshair-highlight/src/facade/f-univer.ts @@ -0,0 +1,55 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ISetCrosshairHighlightColorOperationParams } from '../commands/operations/operation'; +import { FUniver } from '@univerjs/core'; +import { DisableCrosshairHighlightOperation, EnableCrosshairHighlightOperation, SetCrosshairHighlightColorOperation } from '../commands/operations/operation'; + +interface IFUniverCrosshairHighlightMixin { + /** + * Enable or disable crosshair highlight. + * @param {boolean} enabled if crosshair highlight should be enabled + */ + setCrosshairHighlightEnabled(enabled: boolean): void; + + /** + * Set the color of the crosshair highlight. + * @param {string} color the color of the crosshair highlight + */ + setCrosshairHighlightColor(color: string): void; +} + +class FUniverCrosshairHighlightMixin extends FUniver implements IFUniverCrosshairHighlightMixin { + override setCrosshairHighlightEnabled(enabled: boolean): void { + if (enabled) { + this._commandService.executeCommand(EnableCrosshairHighlightOperation.id); + } else { + this._commandService.executeCommand(DisableCrosshairHighlightOperation.id); + } + } + + override setCrosshairHighlightColor(color: string): void { + this._commandService.executeCommand(SetCrosshairHighlightColorOperation.id, { + value: color, + } as ISetCrosshairHighlightColorOperationParams); + } +} + +FUniver.extend(FUniverCrosshairHighlightMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverCrosshairHighlightMixin {} +} diff --git a/packages/sheets-hyper-link-ui/src/types/interfaces/index.ts b/packages/sheets-crosshair-highlight/src/facade/index.ts similarity index 82% rename from packages/sheets-hyper-link-ui/src/types/interfaces/index.ts rename to packages/sheets-crosshair-highlight/src/facade/index.ts index b5fa96c68cc..14bcba31dc0 100644 --- a/packages/sheets-hyper-link-ui/src/types/interfaces/index.ts +++ b/packages/sheets-crosshair-highlight/src/facade/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export type { ISheetHyperLinkInfo } from './i-sheet-hyper-link-info'; -export type { ISheetUrlParams } from './i-sheet-url-params'; +import './f-univer'; diff --git a/packages/sheets-data-validation-ui/src/controllers/dv-reject-input.controller.ts b/packages/sheets-data-validation-ui/src/controllers/dv-reject-input.controller.ts index e5ac5f27a9c..05b4fd7a961 100644 --- a/packages/sheets-data-validation-ui/src/controllers/dv-reject-input.controller.ts +++ b/packages/sheets-data-validation-ui/src/controllers/dv-reject-input.controller.ts @@ -17,14 +17,14 @@ import { DataValidationErrorStyle, Disposable, Inject, LocaleService } from '@univerjs/core'; import { DataValidatorRegistryService } from '@univerjs/data-validation'; import { Button } from '@univerjs/design'; +import { AFTER_CELL_EDIT_ASYNC, SheetInterceptorService } from '@univerjs/sheets'; import { getCellValueOrigin, SheetDataValidationModel } from '@univerjs/sheets-data-validation'; -import { IEditorBridgeService } from '@univerjs/sheets-ui'; import { IDialogService } from '@univerjs/ui'; import React from 'react'; export class DataValidationRejectInputController extends Disposable { constructor( - @IEditorBridgeService private readonly _editorBridgeService: IEditorBridgeService, + @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, @Inject(SheetDataValidationModel) private readonly _dataValidationModel: SheetDataValidationModel, @Inject(DataValidatorRegistryService) private readonly _dataValidatorRegistryService: DataValidatorRegistryService, @IDialogService private readonly _dialogService: IDialogService, @@ -35,8 +35,8 @@ export class DataValidationRejectInputController extends Disposable { } private _initEditorBridgeInterceptor() { - this._editorBridgeService.interceptor.intercept( - this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT_ASYNC, + this._sheetInterceptorService.writeCellInterceptor.intercept( + AFTER_CELL_EDIT_ASYNC, { handler: async (cellPromise, context, next) => { const cell = await cellPromise; diff --git a/packages/sheets-data-validation/package.json b/packages/sheets-data-validation/package.json index c7646c76720..6aded10a0cf 100644 --- a/packages/sheets-data-validation/package.json +++ b/packages/sheets-data-validation/package.json @@ -22,7 +22,8 @@ ], "exports": { ".": "./src/index.ts", - "./*": "./src/*" + "./*": "./src/*", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/facade/src/apis/sheets/f-data-validation-builder.ts b/packages/sheets-data-validation/src/facade/f-data-validation-builder.ts similarity index 98% rename from packages/facade/src/apis/sheets/f-data-validation-builder.ts rename to packages/sheets-data-validation/src/facade/f-data-validation-builder.ts index 7aa5db2fca8..aca9164279a 100644 --- a/packages/facade/src/apis/sheets/f-data-validation-builder.ts +++ b/packages/sheets-data-validation/src/facade/f-data-validation-builder.ts @@ -15,18 +15,18 @@ */ import type { IDataValidationRule, IDataValidationRuleOptions } from '@univerjs/core'; -import type { FRange } from './f-range'; +import type { FRange } from '@univerjs/sheets/facade'; import { DataValidationErrorStyle, DataValidationOperator, DataValidationType, generateRandomId } from '@univerjs/core'; import { serializeRangeToRefString } from '@univerjs/engine-formula'; import { FDataValidation } from './f-data-validation'; - /** - * Builder for data validation rules. - * - * Set the data validation for cell A1 to require a value from B1:B10. - * var rule = FUniver.newDataValidation().requireValueInRange(range).build(); - * cell.setDataValidation(rule); - */ +/** + * Builder for data validation rules. + * + * Set the data validation for cell A1 to require a value from B1:B10. + * var rule = FUniver.newDataValidation().requireValueInRange(range).build(); + * cell.setDataValidation(rule); + */ export class FDataValidationBuilder { private _rule: IDataValidationRule; diff --git a/packages/facade/src/apis/sheets/f-data-validation.ts b/packages/sheets-data-validation/src/facade/f-data-validation.ts similarity index 97% rename from packages/facade/src/apis/sheets/f-data-validation.ts rename to packages/sheets-data-validation/src/facade/f-data-validation.ts index eb5454db878..d00b9db9248 100644 --- a/packages/facade/src/apis/sheets/f-data-validation.ts +++ b/packages/sheets-data-validation/src/facade/f-data-validation.ts @@ -15,13 +15,13 @@ */ import type { DataValidationOperator, DataValidationType, IDataValidationRule, IDataValidationRuleOptions, IRange } from '@univerjs/core'; -import type { IRemoveSheetDataValidationCommandParams, IUpdateSheetDataValidationOptionsCommandParams, IUpdateSheetDataValidationRangeCommandParams, IUpdateSheetDataValidationSettingCommandParams } from '@univerjs/sheets-data-validation'; -import type { FWorksheet } from './f-worksheet'; +import type { FWorksheet } from '@univerjs/sheets/facade'; +import type { IRemoveSheetDataValidationCommandParams, IUpdateSheetDataValidationOptionsCommandParams, IUpdateSheetDataValidationRangeCommandParams, IUpdateSheetDataValidationSettingCommandParams } from '../commands/commands/data-validation.command'; import { DataValidationErrorStyle, ICommandService } from '@univerjs/core'; import { DataValidationModel, getRuleOptions } from '@univerjs/data-validation'; -import { RemoveSheetDataValidationCommand, UpdateSheetDataValidationOptionsCommand, UpdateSheetDataValidationRangeCommand, UpdateSheetDataValidationSettingCommand } from '@univerjs/sheets-data-validation'; +import { FRange } from '@univerjs/sheets/facade'; +import { RemoveSheetDataValidationCommand, UpdateSheetDataValidationOptionsCommand, UpdateSheetDataValidationRangeCommand, UpdateSheetDataValidationSettingCommand } from '../commands/commands/data-validation.command'; import { FDataValidationBuilder } from './f-data-validation-builder'; -import { FRange } from './f-range'; export class FDataValidation { rule: IDataValidationRule; diff --git a/packages/sheets-data-validation/src/facade/f-range.ts b/packages/sheets-data-validation/src/facade/f-range.ts new file mode 100644 index 00000000000..82d4964e6c3 --- /dev/null +++ b/packages/sheets-data-validation/src/facade/f-range.ts @@ -0,0 +1,108 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { DataValidationStatus, Nullable } from '@univerjs/core'; +import type { IAddSheetDataValidationCommandParams, IClearRangeDataValidationCommandParams } from '../commands/commands/data-validation.command'; +import { FRange } from '@univerjs/sheets/facade'; +import { AddSheetDataValidationCommand, ClearRangeDataValidationCommand } from '../commands/commands/data-validation.command'; +import { SheetsDataValidationValidatorService } from '../services/dv-validator-service'; +import { FDataValidation } from './f-data-validation'; + +interface IFRangeDataValidationMixin { + /** + * set a data validation rule to current range + * @param rule data validation rule, build by `FUniver.newDataValidation` + * @returns current range + */ + setDataValidation(this: FRange, rule: Nullable): Promise; + /** + * get first data validation rule in current range + * @returns data validation rule + */ + getDataValidation(this: FRange): Nullable; + + /** + * get all data validation rules in current range + * @returns all data validation rules + */ + getDataValidations(this: FRange): FDataValidation[]; + getValidatorStatus(): Promise[][]>; +} + +export class FRangeDataValidationMixin extends FRange implements IFRangeDataValidationMixin { + override async setDataValidation(rule: Nullable): Promise { + if (!rule) { + this._commandService.executeCommand(ClearRangeDataValidationCommand.id, { + unitId: this._workbook.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + ranges: [this._range], + } as IClearRangeDataValidationCommandParams); + + return this; + } + + const params: IAddSheetDataValidationCommandParams = { + unitId: this._workbook.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + rule: { + ...rule.rule, + ranges: [this._range], + }, + }; + + await this._commandService.executeCommand(AddSheetDataValidationCommand.id, params); + return this; + } + + override getDataValidation(): Nullable { + const validatorService = this._injector.get(SheetsDataValidationValidatorService); + const rule = validatorService.getDataValidation( + this._workbook.getUnitId(), + this._worksheet.getSheetId(), + [this._range] + ); + + if (rule) { + return new FDataValidation(rule); + } + + return rule; + } + + override getDataValidations(): FDataValidation[] { + const validatorService = this._injector.get(SheetsDataValidationValidatorService); + return validatorService.getDataValidations( + this._workbook.getUnitId(), + this._worksheet.getSheetId(), + [this._range] + ).map((rule) => new FDataValidation(rule)); + } + + override async getValidatorStatus(): Promise[][]> { + const validatorService = this._injector.get(SheetsDataValidationValidatorService); + return validatorService.validatorRanges( + this._workbook.getUnitId(), + this._worksheet.getSheetId(), + [this._range] + ); + } +} + +FRange.extend(FRangeDataValidationMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FRange extends IFRangeDataValidationMixin { } +} diff --git a/packages/sheets-data-validation/src/facade/f-univer.ts b/packages/sheets-data-validation/src/facade/f-univer.ts new file mode 100644 index 00000000000..1fd52e4183d --- /dev/null +++ b/packages/sheets-data-validation/src/facade/f-univer.ts @@ -0,0 +1,33 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FUniver } from '@univerjs/core'; +import { FDataValidationBuilder } from './f-data-validation-builder'; + +class FUnvierDataValidationMixin { + static newDataValidation(): FDataValidationBuilder { + return new FDataValidationBuilder(); + } +} + +FUniver.extend(FUnvierDataValidationMixin); + +declare module '@univerjs/core' { + // eslint-disable-next-line ts/no-namespace + namespace FUniver { + function newDataValidation(): FDataValidationBuilder; + } +} diff --git a/packages/sheets-data-validation/src/facade/f-workbook.ts b/packages/sheets-data-validation/src/facade/f-workbook.ts new file mode 100644 index 00000000000..06fe8998724 --- /dev/null +++ b/packages/sheets-data-validation/src/facade/f-workbook.ts @@ -0,0 +1,274 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IRuleChange } from '@univerjs/data-validation'; +import type { IValidStatusChange } from '../models/sheet-data-validation-model'; +import type { IDataValidationResCache } from '../services/dv-cache.service'; +import { type IDisposable, type IExecutionOptions, type Nullable, type ObjectMatrix, toDisposable } from '@univerjs/core'; +import { FWorkbook } from '@univerjs/sheets/facade'; +import { filter } from 'rxjs'; +import { + AddSheetDataValidationCommand, + type IAddSheetDataValidationCommandParams, + type IRemoveSheetAllDataValidationCommandParams, + type IRemoveSheetDataValidationCommandParams, + type IUpdateSheetDataValidationOptionsCommandParams, + type IUpdateSheetDataValidationRangeCommandParams, + type IUpdateSheetDataValidationSettingCommandParams, + RemoveSheetAllDataValidationCommand, + RemoveSheetDataValidationCommand, + UpdateSheetDataValidationOptionsCommand, + UpdateSheetDataValidationRangeCommand, + UpdateSheetDataValidationSettingCommand, +} from '../commands/commands/data-validation.command'; +import { SheetDataValidationModel } from '../models/sheet-data-validation-model'; +import { SheetsDataValidationValidatorService } from '../services/dv-validator-service'; + +interface IFWorkbookDataValidationMixin { + /** + * get data validation validator status for current workbook + * @returns matrix of validator status + */ + getValidatorStatus(this: FWorkbook): Promise>>>; + + /** + * The onDataValidationChange event is fired when the data validation rule of this sheet is changed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onDataValidationChange( + callback: (ruleChange: IRuleChange) => void + ): IDisposable; + + /** + * The onDataValidationStatusChange event is fired when the data validation status of this sheet is changed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onDataValidationStatusChange( + callback: (statusChange: IValidStatusChange) => void + ): IDisposable; + + /** + * The onBeforeAddDataValidation event is fired before the data validation rule is added. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeAddDataValidation( + this: FWorkbook, + callback: (params: IAddSheetDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + + /** + * The onBeforeUpdateDataValidationCriteria event is fired before the data validation rule is updated. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeUpdateDataValidationCriteria( + this: FWorkbook, + callback: (params: IUpdateSheetDataValidationSettingCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + + /** + * The onBeforeUpdateDataValidationRange event is fired before the data validation rule is updated. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeUpdateDataValidationRange( + this: FWorkbook, + callback: (params: IUpdateSheetDataValidationRangeCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + /** + * The onBeforeUpdateDataValidationOptions event is fired before the data validation rule is updated. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeUpdateDataValidationOptions( + this: FWorkbook, + callback: (params: IUpdateSheetDataValidationOptionsCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + + /** + * The onBeforeDeleteDataValidation event is fired before the data validation rule is deleted. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeDeleteDataValidation( + this: FWorkbook, + callback: (params: IRemoveSheetDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + + /** + * The onBeforeDeleteAllDataValidation event is fired before delete all data validation rules. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeDeleteAllDataValidation( + this: FWorkbook, + callback: (params: IRemoveSheetAllDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; +} + +class FWorkbookDataValidationMixin extends FWorkbook implements IFWorkbookDataValidationMixin { + declare _dataValidationModel: SheetDataValidationModel; + + override _initialize(): void { + Object.defineProperty(this, '_dataValidationModel', { + get() { + return this._injector.get(SheetDataValidationModel); + }, + }); + } + + /** + * get data validation validator status for current workbook + * @returns matrix of validator status + */ + override getValidatorStatus(): Promise>>> { + const validatorService = this._injector.get(SheetsDataValidationValidatorService); + return validatorService.validatorWorkbook(this._workbook.getUnitId()); + } + + // region DataValidationHooks + /** + * The onDataValidationChange event is fired when the data validation rule of this sheet is changed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + override onDataValidationChange( + callback: (ruleChange: IRuleChange) => void + ): IDisposable { + return toDisposable(this._dataValidationModel.ruleChange$ + + .pipe(filter((change) => change.unitId === this._workbook.getUnitId())) + .subscribe(callback)); + } + + /** + * The onDataValidationStatusChange event is fired when the data validation status of this sheet is changed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + override onDataValidationStatusChange( + callback: (statusChange: IValidStatusChange) => void + ): IDisposable { + return toDisposable(this._dataValidationModel.validStatusChange$ + .pipe(filter((change) => change.unitId === this._workbook.getUnitId())) + .subscribe(callback)); + } + + /** + * The onBeforeAddDataValidation event is fired before the data validation rule is added. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + override onBeforeAddDataValidation( + callback: (params: IAddSheetDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IAddSheetDataValidationCommandParams; + if (commandInfo.id === AddSheetDataValidationCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeAddDataValidation'); + } + } + })); + } + + override onBeforeUpdateDataValidationCriteria( + callback: (params: IUpdateSheetDataValidationSettingCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IUpdateSheetDataValidationSettingCommandParams; + if (commandInfo.id === UpdateSheetDataValidationSettingCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeUpdateDataValidationCriteria'); + } + } + })); + } + + override onBeforeUpdateDataValidationRange(callback: (params: IUpdateSheetDataValidationRangeCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IUpdateSheetDataValidationRangeCommandParams; + if (commandInfo.id === UpdateSheetDataValidationRangeCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeUpdateDataValidationRange'); + } + } + })); + } + + override onBeforeUpdateDataValidationOptions(callback: (params: IUpdateSheetDataValidationOptionsCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IUpdateSheetDataValidationOptionsCommandParams; + if (commandInfo.id === UpdateSheetDataValidationOptionsCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeUpdateDataValidationOptions'); + } + } + })); + } + + override onBeforeDeleteDataValidation(callback: (params: IRemoveSheetDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IRemoveSheetDataValidationCommandParams; + if (commandInfo.id === RemoveSheetDataValidationCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeDeleteDataValidation'); + } + } + })); + } + + override onBeforeDeleteAllDataValidation(callback: (params: IRemoveSheetAllDataValidationCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IRemoveSheetAllDataValidationCommandParams; + if (commandInfo.id === RemoveSheetAllDataValidationCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeDeleteAllDataValidation'); + } + } + })); + } +} + +FWorkbook.extend(FWorkbookDataValidationMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorkbook extends IFWorkbookDataValidationMixin { } +} diff --git a/packages/sheets-data-validation/src/facade/f-worksheet.ts b/packages/sheets-data-validation/src/facade/f-worksheet.ts new file mode 100644 index 00000000000..04517bbe9ce --- /dev/null +++ b/packages/sheets-data-validation/src/facade/f-worksheet.ts @@ -0,0 +1,56 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Nullable, ObjectMatrix } from '@univerjs/core'; +import type { IDataValidationResCache } from '../services/dv-cache.service'; +import { DataValidationModel } from '@univerjs/data-validation'; +import { FWorksheet } from '@univerjs/sheets/facade'; +import { SheetsDataValidationValidatorService } from '../services/dv-validator-service'; +import { FDataValidation } from './f-data-validation'; + +interface IFWorksheetDataValidationMixin { + /** + * get all data validation rules in current sheet + * @returns all data validation rules + */ + getDataValidations(): FDataValidation[]; + /** + * get data validation validator status for current sheet + * @returns matrix of validator status + */ + getValidatorStatus(): Promise>>; +} + +class FWorksheetDataValidationMixin extends FWorksheet implements IFWorksheetDataValidationMixin { + override getDataValidations(): FDataValidation[] { + const dataValidationModel = this._injector.get(DataValidationModel); + return dataValidationModel.getRules(this._workbook.getUnitId(), this._worksheet.getSheetId()).map((rule) => new FDataValidation(rule)); + } + + override getValidatorStatus(): Promise>> { + const validatorService = this._injector.get(SheetsDataValidationValidatorService); + return validatorService.validatorWorksheet( + this._workbook.getUnitId(), + this._worksheet.getSheetId() + ); + } +} + +FWorksheet.extend(FWorksheetDataValidationMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorksheet extends IFWorksheetDataValidationMixin {} +} diff --git a/packages/sheets-thread-comment-base/src/controllers/config.schema.ts b/packages/sheets-data-validation/src/facade/index.ts similarity index 69% rename from packages/sheets-thread-comment-base/src/controllers/config.schema.ts rename to packages/sheets-data-validation/src/facade/index.ts index f224283b804..7eceb54fc82 100644 --- a/packages/sheets-thread-comment-base/src/controllers/config.schema.ts +++ b/packages/sheets-data-validation/src/facade/index.ts @@ -14,11 +14,10 @@ * limitations under the License. */ -export const PLUGIN_CONFIG_KEY = 'sheets-thread-comment-base.config'; +import './f-range'; +import './f-univer'; +import './f-workbook'; +import './f-worksheet'; -export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); - -export interface IUniverSheetsThreadCommentBaseConfig { -} - -export const defaultPluginConfig: IUniverSheetsThreadCommentBaseConfig = {}; +export { FDataValidation } from './f-data-validation'; +export { FDataValidationBuilder } from './f-data-validation-builder'; diff --git a/packages/sheets-drawing-ui/package.json b/packages/sheets-drawing-ui/package.json index dc4decf362c..449c7b929e1 100644 --- a/packages/sheets-drawing-ui/package.json +++ b/packages/sheets-drawing-ui/package.json @@ -21,7 +21,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/sheets-drawing-ui/src/facade/f-worksheet.ts b/packages/sheets-drawing-ui/src/facade/f-worksheet.ts new file mode 100644 index 00000000000..6c34494ad07 --- /dev/null +++ b/packages/sheets-drawing-ui/src/facade/f-worksheet.ts @@ -0,0 +1,69 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Nullable } from '@univerjs/core'; +import { FWorksheet } from '@univerjs/sheets/facade'; +import { type IFComponentKey, transformComponentKey } from '@univerjs/sheets-ui/facade'; +import { ComponentManager } from '@univerjs/ui'; +import { type ICanvasFloatDom, SheetCanvasFloatDomManagerService } from '../services/canvas-float-dom-manager.service'; + +interface IFICanvasFloatDom extends Omit, IFComponentKey {} + +interface IFWorksheetLegacy { + /** + * add a float dom to position + * @param layer float dom config + * @param id float dom id, if not given will be auto generated + * @returns float dom id and dispose function + */ + addFloatDomToPosition(layer: IFICanvasFloatDom, id?: string): Nullable<{ + id: string; + dispose: () => void; + }>; +} + +class FWorksheetLegacy extends FWorksheet implements IFWorksheetLegacy { + override addFloatDomToPosition(layer: IFICanvasFloatDom, id?: string): Nullable<{ + id: string; + dispose: () => void; + }> { + const unitId = this._workbook.getUnitId(); + const subUnitId = this._worksheet.getSheetId(); + const { key, disposableCollection } = transformComponentKey(layer, this._injector.get(ComponentManager)); + const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService); + const res = floatDomService.addFloatDomToPosition({ ...layer, componentKey: key, unitId, subUnitId }, id); + + if (res) { + disposableCollection.add(res.dispose); + return { + id: res.id, + dispose: (): void => { + disposableCollection.dispose(); + res.dispose(); + }, + }; + } + + disposableCollection.dispose(); + return null; + } +} + +FWorksheet.extend(FWorksheetLegacy); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorksheet extends IFWorksheetLegacy {} +} diff --git a/packages/sheets-drawing-ui/src/facade/index.ts b/packages/sheets-drawing-ui/src/facade/index.ts new file mode 100644 index 00000000000..5673ed5ec12 --- /dev/null +++ b/packages/sheets-drawing-ui/src/facade/index.ts @@ -0,0 +1,17 @@ +/** + * 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 './f-worksheet'; diff --git a/packages/sheets-filter-ui/src/commands/commands/__tests__/sheets-filter.command.spec.ts b/packages/sheets-filter-ui/src/commands/commands/__tests__/sheets-filter.command.spec.ts index 9e93c0d5ad8..cd7ee5d4d46 100644 --- a/packages/sheets-filter-ui/src/commands/commands/__tests__/sheets-filter.command.spec.ts +++ b/packages/sheets-filter-ui/src/commands/commands/__tests__/sheets-filter.command.spec.ts @@ -17,15 +17,15 @@ import type { Dependency, IRange, IWorkbookData, Workbook } from '@univerjs/core'; import type { ISetRangeValuesCommandParams } from '@univerjs/sheets'; import type { FilterModel, ISetSheetsFilterRangeMutationParams } from '@univerjs/sheets-filter'; -import type { ISetSheetsFilterCriteriaCommandParams } from '../sheets-filter.command'; +import type { ISetSheetsFilterCriteriaCommandParams } from '@univerjs/sheets-filter/commands/commands/sheets-filter.command.js'; import { AuthzIoLocalService, IAuthzIoService, ICommandService, Inject, Injector, IUniverInstanceService, LocaleType, Plugin, RANGE_TYPE, RedoCommand, UndoCommand, Univer, UniverInstanceType } from '@univerjs/core'; import { RangeProtectionRuleModel, RefRangeService, SetRangeValuesCommand, SetRangeValuesMutation, SheetInterceptorService, SheetsSelectionsService, WorkbookPermissionService, WorksheetPermissionService, WorksheetProtectionPointModel, WorksheetProtectionRuleModel } from '@univerjs/sheets'; import { SetSheetsFilterRangeMutation, SheetsFilterService, UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; +import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand, SmartToggleSheetsFilterCommand } from '@univerjs/sheets-filter/commands/commands/sheets-filter.command.js'; import { IMessageService } from '@univerjs/ui'; -import { MockMessageService } from '@univerjs/ui/services/message/__testing__/mock-message.service.js'; +import { MockMessageService } from '@univerjs/ui/services/message/__testing__/mock-message.service.js'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand, SmartToggleSheetsFilterCommand } from '../sheets-filter.command'; function testWorkbookDataFactory(): IWorkbookData { return { diff --git a/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts b/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts index 075be0b5787..aae41c58d90 100644 --- a/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts +++ b/packages/sheets-filter-ui/src/controllers/__tests__/sheets-filter.menu.spec.ts @@ -19,9 +19,9 @@ import type { ISetSheetsFilterCriteriaMutationParams, ISetSheetsFilterRangeMutat import { AuthzIoLocalService, DisposableCollection, IAuthzIoService, ICommandService, Inject, Injector, LocaleType, Plugin, Univer, UniverInstanceType } from '@univerjs/core'; import { ExclusiveRangeService, IExclusiveRangeService, RangeProtectionRuleModel, RefRangeService, SetWorksheetActiveOperation, SheetInterceptorService, SheetsSelectionsService, WorkbookPermissionService, WorksheetPermissionService, WorksheetProtectionPointModel, WorksheetProtectionRuleModel } from '@univerjs/sheets'; import { RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation, UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; +import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SmartToggleSheetsFilterCommand } from '@univerjs/sheets-filter/commands/commands/sheets-filter.command.js'; import { IMenuManagerService, IPlatformService, IShortcutService, MenuManagerService, PlatformService, ShortcutService } from '@univerjs/ui'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SmartToggleSheetsFilterCommand } from '../../commands/commands/sheets-filter.command'; import { CloseFilterPanelOperation, OpenFilterPanelOperation } from '../../commands/operations/sheets-filter.operation'; import { ClearFilterCriteriaMenuItemFactory, ReCalcFilterMenuItemFactory, SmartToggleFilterMenuItemFactory } from '../sheets-filter.menu'; diff --git a/packages/sheets-filter-ui/src/controllers/menu.schema.ts b/packages/sheets-filter-ui/src/controllers/menu.schema.ts index 3c47722b67c..7d4d1473415 100644 --- a/packages/sheets-filter-ui/src/controllers/menu.schema.ts +++ b/packages/sheets-filter-ui/src/controllers/menu.schema.ts @@ -15,11 +15,11 @@ */ import type { MenuSchemaType } from '@univerjs/ui'; -import { RibbonStartGroup } from '@univerjs/ui'; import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SmartToggleSheetsFilterCommand, -} from '../commands/commands/sheets-filter.command'; +} from '@univerjs/sheets-filter'; +import { RibbonStartGroup } from '@univerjs/ui'; import { ClearFilterCriteriaMenuItemFactory, ReCalcFilterMenuItemFactory, diff --git a/packages/sheets-filter-ui/src/controllers/sheets-filter-permission.controller.ts b/packages/sheets-filter-ui/src/controllers/sheets-filter-permission.controller.ts index dc9ffced6f0..ef6771575fa 100644 --- a/packages/sheets-filter-ui/src/controllers/sheets-filter-permission.controller.ts +++ b/packages/sheets-filter-ui/src/controllers/sheets-filter-permission.controller.ts @@ -14,15 +14,14 @@ * limitations under the License. */ -import { Disposable, ICommandService, Inject, Injector, IUniverInstanceService, LocaleService, Tools } from '@univerjs/core'; -import { expandToContinuousRange, getSheetCommandTarget, RangeProtectionPermissionViewPoint, SheetsSelectionsService, WorksheetFilterPermission, WorksheetViewPermission } from '@univerjs/sheets'; +import type { ICommandInfo } from '@univerjs/core'; +import type { MenuConfig } from '@univerjs/ui'; -import { SheetsFilterService } from '@univerjs/sheets-filter'; +import { Disposable, ICommandService, Inject, Injector, IUniverInstanceService, LocaleService, Tools } from '@univerjs/core'; +import { expandToContinuousRange, getSheetCommandTarget, RangeProtectionPermissionViewPoint, SheetsSelectionsService, WorksheetFilterPermission, WorksheetViewPermission } from '@univerjs/sheets'; +import { SheetsFilterService, SmartToggleSheetsFilterCommand } from '@univerjs/sheets-filter'; import { SheetPermissionInterceptorBaseController } from '@univerjs/sheets-ui'; -import type { ICommandInfo } from '@univerjs/core'; -import type { MenuConfig } from '@univerjs/ui'; -import { SmartToggleSheetsFilterCommand } from '../commands/commands/sheets-filter.command'; import { type IOpenFilterPanelOperationParams, OpenFilterPanelOperation } from '../commands/operations/sheets-filter.operation'; export interface IUniverSheetsFilterUIConfig { diff --git a/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts b/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts index c995db55554..e69eed557ec 100644 --- a/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts +++ b/packages/sheets-filter-ui/src/controllers/sheets-filter-ui-desktop.controller.ts @@ -16,22 +16,21 @@ import type { IDisposable, Nullable } from '@univerjs/core'; import { ICommandService, IContextService, Inject, Injector, LocaleService } from '@univerjs/core'; -import { ComponentManager, IMenuManagerService, IMessageService, IShortcutService } from '@univerjs/ui'; +import { MessageType } from '@univerjs/design'; -import { distinctUntilChanged } from 'rxjs'; -import { SheetCanvasPopManagerService, SheetsRenderService } from '@univerjs/sheets-ui'; +import { IRenderManagerService } from '@univerjs/engine-render'; import { FilterSingle } from '@univerjs/icons'; +import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand, SheetsFilterService, SmartToggleSheetsFilterCommand } from '@univerjs/sheets-filter'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { SheetsFilterService } from '@univerjs/sheets-filter'; -import { MessageType } from '@univerjs/design'; -import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, RemoveSheetFilterCommand, SetSheetFilterRangeCommand, SetSheetsFilterCriteriaCommand, SmartToggleSheetsFilterCommand } from '../commands/commands/sheets-filter.command'; -import { FilterPanel } from '../views/components/SheetsFilterPanel'; +import { SheetCanvasPopManagerService, SheetsRenderService } from '@univerjs/sheets-ui'; +import { ComponentManager, IMenuManagerService, IMessageService, IShortcutService } from '@univerjs/ui'; +import { distinctUntilChanged } from 'rxjs'; import { ChangeFilterByOperation, CloseFilterPanelOperation, FILTER_PANEL_OPENED_KEY, OpenFilterPanelOperation } from '../commands/operations/sheets-filter.operation'; import { SheetsFilterPanelService } from '../services/sheets-filter-panel.service'; +import { FilterPanel } from '../views/components/SheetsFilterPanel'; +import { menuSchema } from './menu.schema'; import { SmartToggleFilterShortcut } from './sheets-filter.shortcut'; import { SheetsFilterUIMobileController } from './sheets-filter-ui-mobile.controller'; -import { menuSchema } from './menu.schema'; export const FILTER_PANEL_POPUP_KEY = 'FILTER_PANEL_POPUP'; diff --git a/packages/sheets-filter-ui/src/controllers/sheets-filter.menu.ts b/packages/sheets-filter-ui/src/controllers/sheets-filter.menu.ts index fc3fd1d8eba..d9bddf62420 100644 --- a/packages/sheets-filter-ui/src/controllers/sheets-filter.menu.ts +++ b/packages/sheets-filter-ui/src/controllers/sheets-filter.menu.ts @@ -14,16 +14,15 @@ * limitations under the License. */ -import { getMenuHiddenObservable, MenuItemType } from '@univerjs/ui'; -import type { IMenuButtonItem, IMenuSelectorItem } from '@univerjs/ui'; import type { IAccessor } from '@univerjs/core'; -import { SheetsFilterService } from '@univerjs/sheets-filter'; +import type { IMenuButtonItem, IMenuSelectorItem } from '@univerjs/ui'; import { UniverInstanceType } from '@univerjs/core'; +import { RangeProtectionPermissionViewPoint, WorksheetFilterPermission, WorksheetViewPermission } from '@univerjs/sheets'; +import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SheetsFilterService, SmartToggleSheetsFilterCommand } from '@univerjs/sheets-filter'; -import { map, of, switchMap } from 'rxjs'; import { getCurrentRangeDisable$, getObservableWithExclusiveRange$ } from '@univerjs/sheets-ui'; -import { RangeProtectionPermissionViewPoint, WorksheetFilterPermission, WorksheetViewPermission } from '@univerjs/sheets'; -import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SmartToggleSheetsFilterCommand } from '../commands/commands/sheets-filter.command'; +import { getMenuHiddenObservable, MenuItemType } from '@univerjs/ui'; +import { map, of, switchMap } from 'rxjs'; export function SmartToggleFilterMenuItemFactory(accessor: IAccessor): IMenuSelectorItem { const sheetsFilterService = accessor.get(SheetsFilterService); diff --git a/packages/sheets-filter-ui/src/controllers/sheets-filter.shortcut.ts b/packages/sheets-filter-ui/src/controllers/sheets-filter.shortcut.ts index fb0e9b2d67a..9d5c43106e2 100644 --- a/packages/sheets-filter-ui/src/controllers/sheets-filter.shortcut.ts +++ b/packages/sheets-filter-ui/src/controllers/sheets-filter.shortcut.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { type IShortcutItem, KeyCode, MetaKeys } from '@univerjs/ui'; +import { SmartToggleSheetsFilterCommand } from '@univerjs/sheets-filter'; import { whenSheetEditorFocused } from '@univerjs/sheets-ui'; -import { SmartToggleSheetsFilterCommand } from '../commands/commands/sheets-filter.command'; +import { type IShortcutItem, KeyCode, MetaKeys } from '@univerjs/ui'; export const SmartToggleFilterShortcut: IShortcutItem = { id: SmartToggleSheetsFilterCommand.id, diff --git a/packages/sheets-filter-ui/src/index.ts b/packages/sheets-filter-ui/src/index.ts index a1811d10cd4..02879d1a520 100644 --- a/packages/sheets-filter-ui/src/index.ts +++ b/packages/sheets-filter-ui/src/index.ts @@ -20,16 +20,6 @@ export { UniverSheetsFilterUIWorkerPlugin } from './worker/plugin'; // #region - all commands -export { - ClearSheetsFilterCriteriaCommand, - type ISetSheetFilterRangeCommandParams, - type ISetSheetsFilterCriteriaCommandParams, - ReCalcSheetsFilterCommand, - RemoveSheetFilterCommand, - SetSheetFilterRangeCommand, - SetSheetsFilterCriteriaCommand, - SmartToggleSheetsFilterCommand, -} from './commands/commands/sheets-filter.command'; export { ChangeFilterByOperation, CloseFilterPanelOperation, diff --git a/packages/sheets-filter-ui/src/services/__tests__/sheets-filter-panel.service.spec.ts b/packages/sheets-filter-ui/src/services/__tests__/sheets-filter-panel.service.spec.ts index 252d8567eef..533b9734384 100644 --- a/packages/sheets-filter-ui/src/services/__tests__/sheets-filter-panel.service.spec.ts +++ b/packages/sheets-filter-ui/src/services/__tests__/sheets-filter-panel.service.spec.ts @@ -21,9 +21,9 @@ import type { IFilterConditionFormParams } from '../../models/conditions'; import { CommandType, ICommandService, Inject, Injector, LocaleService, Plugin, Univer, UniverInstanceType } from '@univerjs/core'; import { RefRangeService, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets'; import { CustomFilterOperator, SheetsFilterService, UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; +import { SetSheetsFilterCriteriaCommand } from '@univerjs/sheets-filter/commands/commands/sheets-filter.command.js'; import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest'; import { E_ITEMS, ITEMS, WithCustomFilterModelFactory, WithMergedCellFilterFactory, WithMultiEmptyCellsModelFactory, WithTwoFilterColumnsFactory, WithValuesAndEmptyFilterModelFactory, WithValuesFilterModelFactory } from '../../__testing__/data'; -import { SetSheetsFilterCriteriaCommand } from '../../commands/commands/sheets-filter.command'; import { CloseFilterPanelOperation, OpenFilterPanelOperation } from '../../commands/operations/sheets-filter.operation'; import { FilterConditionItems } from '../../models/conditions'; import { ExtendCustomFilterOperator } from '../../models/extended-operators'; diff --git a/packages/sheets-filter-ui/src/services/sheets-filter-panel.service.ts b/packages/sheets-filter-ui/src/services/sheets-filter-panel.service.ts index 263e138f553..4696bb5286f 100644 --- a/packages/sheets-filter-ui/src/services/sheets-filter-panel.service.ts +++ b/packages/sheets-filter-ui/src/services/sheets-filter-panel.service.ts @@ -15,15 +15,15 @@ */ import type { IDisposable, IRange, Nullable } from '@univerjs/core'; -import { createIdentifier, Disposable, ICommandService, Inject, Injector, IUniverInstanceService, LocaleService, Quantity } from '@univerjs/core'; -import type { FilterColumn, FilterModel, IFilterColumn } from '@univerjs/sheets-filter'; +import type { FilterColumn, FilterModel, IFilterColumn, ISetSheetsFilterCriteriaCommandParams } from '@univerjs/sheets-filter'; import type { Observable } from 'rxjs'; -import { BehaviorSubject, combineLatest, map, merge, of, ReplaySubject, shareReplay, startWith, Subject, throttleTime } from 'rxjs'; +import type { FilterOperator, IFilterConditionFormParams, IFilterConditionItem } from '../models/conditions'; +import { createIdentifier, Disposable, ICommandService, Inject, Injector, IUniverInstanceService, LocaleService, Quantity } from '@univerjs/core'; import { RefRangeService } from '@univerjs/sheets'; +import { SetSheetsFilterCriteriaCommand } from '@univerjs/sheets-filter'; -import type { FilterOperator, IFilterConditionFormParams, IFilterConditionItem } from '../models/conditions'; +import { BehaviorSubject, combineLatest, map, merge, of, ReplaySubject, shareReplay, startWith, Subject, throttleTime } from 'rxjs'; import { FilterConditionItems } from '../models/conditions'; -import { type ISetSheetsFilterCriteriaCommandParams, SetSheetsFilterCriteriaCommand } from '../commands/commands/sheets-filter.command'; import { statisticFilterByValueItems } from '../models/utils'; import { getFilterByValueItems, ISheetsGenerateFilterValuesService } from '../worker/generate-filter-values.service'; diff --git a/packages/sheets-filter-ui/src/views/components/SheetsFilterPanel.stories.tsx b/packages/sheets-filter-ui/src/views/components/SheetsFilterPanel.stories.tsx index c5a4efba2ab..8b5ce3eccf3 100644 --- a/packages/sheets-filter-ui/src/views/components/SheetsFilterPanel.stories.tsx +++ b/packages/sheets-filter-ui/src/views/components/SheetsFilterPanel.stories.tsx @@ -14,22 +14,21 @@ * limitations under the License. */ -import React, { useState } from 'react'; import type { Meta } from '@storybook/react'; -import { CommandType, ICommandService, ILogService, LocaleService, LocaleType, LogLevel, Plugin, RediContext, Univer, UniverInstanceType } from '@univerjs/core'; import type { Injector, IWorkbookData } from '@univerjs/core'; -import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; +import type { IOpenFilterPanelOperationParams } from '../../commands/operations/sheets-filter.operation'; +import { CommandType, ICommandService, ILogService, LocaleService, LocaleType, LogLevel, Plugin, RediContext, Univer, UniverInstanceType } from '@univerjs/core'; import { RefRangeService, SheetInterceptorService, SheetsSelectionsService, WorksheetProtectionPointModel } from '@univerjs/sheets'; -import { IMenuService, IShortcutService, MenuService, ShortcutService } from '@univerjs/ui'; +import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SetSheetsFilterCriteriaCommand, SmartToggleSheetsFilterCommand, UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'; import { SetCellEditVisibleOperation } from '@univerjs/sheets-ui'; -import { SheetsFilterPanelService } from '../../services/sheets-filter-panel.service'; -import { ClearSheetsFilterCriteriaCommand, ReCalcSheetsFilterCommand, SetSheetsFilterCriteriaCommand, SmartToggleSheetsFilterCommand } from '../../commands/commands/sheets-filter.command'; -import type { IOpenFilterPanelOperationParams } from '../../commands/operations/sheets-filter.operation'; +import { IMenuService, IShortcutService, MenuService, ShortcutService } from '@univerjs/ui'; +import React, { useState } from 'react'; +import { WithCustomFilterModelFactory, WithValuesFilterModelFactory } from '../../__testing__/data'; import { ChangeFilterByOperation, CloseFilterPanelOperation, OpenFilterPanelOperation } from '../../commands/operations/sheets-filter.operation'; import enUS from '../../locale/en-US'; -import zhCN from '../../locale/zh-CN'; import ruRU from '../../locale/ru-RU'; -import { WithCustomFilterModelFactory, WithValuesFilterModelFactory } from '../../__testing__/data'; +import zhCN from '../../locale/zh-CN'; +import { SheetsFilterPanelService } from '../../services/sheets-filter-panel.service'; import { FilterPanel } from './SheetsFilterPanel'; const meta: Meta = { diff --git a/packages/sheets-filter/package.json b/packages/sheets-filter/package.json index b5affa60ea5..2ade098c653 100644 --- a/packages/sheets-filter/package.json +++ b/packages/sheets-filter/package.json @@ -20,7 +20,8 @@ "keywords": [], "exports": { ".": "./src/index.ts", - "./*": "./src/*" + "./*": "./src/*", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/sheets-filter-ui/src/commands/commands/sheets-filter.command.ts b/packages/sheets-filter/src/commands/commands/sheets-filter.command.ts similarity index 96% rename from packages/sheets-filter-ui/src/commands/commands/sheets-filter.command.ts rename to packages/sheets-filter/src/commands/commands/sheets-filter.command.ts index 93c11d2e730..60e2ca6c06b 100644 --- a/packages/sheets-filter-ui/src/commands/commands/sheets-filter.command.ts +++ b/packages/sheets-filter/src/commands/commands/sheets-filter.command.ts @@ -17,11 +17,9 @@ import type { IAccessor, ICommand, IMutationInfo, IRange, Nullable, Workbook } from '@univerjs/core'; import type { ISheetCommandSharedParams } from '@univerjs/sheets'; import type { FilterColumn, IAutoFilter, IFilterColumn, ISetSheetsFilterCriteriaMutationParams, ISetSheetsFilterRangeMutationParams } from '@univerjs/sheets-filter'; -import { CommandType, ICommandService, IUndoRedoService, IUniverInstanceService, LocaleService, Quantity, sequenceExecute, UniverInstanceType } from '@univerjs/core'; -import { MessageType } from '@univerjs/design'; +import { CommandType, ErrorService, ICommandService, IUndoRedoService, IUniverInstanceService, LocaleService, sequenceExecute, UniverInstanceType } from '@univerjs/core'; import { expandToContinuousRange, getSheetCommandTarget, isSingleCellSelection, SheetsSelectionsService } from '@univerjs/sheets'; import { ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation, SheetsFilterService } from '@univerjs/sheets-filter'; -import { IMessageService } from '@univerjs/ui'; /** * Parameters of command {@link SetSheetFilterRangeCommand}. @@ -53,9 +51,9 @@ export const SetSheetFilterRangeCommand: ICommand; + /** + * Get the filter for the current range's worksheet. + * + * @return {FFilter | null} The interface class to handle the filter. If the worksheet does not have a filter, + * this method would return `null`. + */ + getFilter(): FFilter | null; +} + +class FRangeFilter extends FRange implements IFRangeFilter { + override async createFilter(): Promise { + if (this._getFilterModel()) return null; + + const success = await this._commandService.executeCommand(SetSheetFilterRangeCommand.id, { + unitId: this._workbook.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + range: this._range, + }); + + if (!success) return null; + + return this.getFilter(); + } + + /** + * Get the filter for the current range's worksheet. + * + * @return {FFilter | null} The interface class to handle the filter. If the worksheet does not have a filter, + * this method would return `null`. + */ + override getFilter(): FFilter | null { + const filterModel = this._getFilterModel(); + if (!filterModel) return null; + + return this._injector.createInstance(FFilter, this._workbook, this._worksheet, filterModel); + } + + private _getFilterModel(): Nullable { + return this._injector.get(SheetsFilterService).getFilterModel( + this._workbook.getUnitId(), + this._worksheet.getSheetId() + ); + } +} + +FRange.extend(FRangeFilter); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FRange extends IFRangeFilter {} +} diff --git a/packages/sheets-filter/src/facade/f-worksheet.ts b/packages/sheets-filter/src/facade/f-worksheet.ts new file mode 100644 index 00000000000..ab18ab0fa30 --- /dev/null +++ b/packages/sheets-filter/src/facade/f-worksheet.ts @@ -0,0 +1,47 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Nullable } from '@univerjs/core'; +import type { FilterModel } from '../models/filter-model'; +import { FWorksheet } from '@univerjs/sheets/facade'; +import { SheetsFilterService } from '../services/sheet-filter.service'; +import { FFilter } from './f-filter'; + +interface IFWorksheetFilter { + getFilter(): FFilter | null; +} + +class FWorksheetFilter extends FWorksheet implements IFWorksheetFilter { + override getFilter(): FFilter | null { + const filterModel = this._getFilterModel(); + if (!filterModel) return null; + + return this._injector.createInstance(FFilter, this._workbook, this._worksheet, filterModel); + } + + private _getFilterModel(): Nullable { + return this._injector.get(SheetsFilterService).getFilterModel( + this._workbook.getUnitId(), + this._worksheet.getSheetId() + ); + } +} + +FWorksheet.extend(FWorksheetFilter); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorksheet extends IFWorksheetFilter {} +} diff --git a/packages/sheets-filter/src/facade/index.ts b/packages/sheets-filter/src/facade/index.ts new file mode 100644 index 00000000000..c4b24419033 --- /dev/null +++ b/packages/sheets-filter/src/facade/index.ts @@ -0,0 +1,21 @@ +/** + * 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 './f-filter'; +import './f-range'; +import './f-worksheet'; + +export { FFilter } from './f-filter'; diff --git a/packages/sheets-filter/src/index.ts b/packages/sheets-filter/src/index.ts index d2f187cbbc2..db24a1dad63 100644 --- a/packages/sheets-filter/src/index.ts +++ b/packages/sheets-filter/src/index.ts @@ -39,5 +39,15 @@ export { SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation, } from './commands/mutations/sheets-filter.mutation'; +export { + ClearSheetsFilterCriteriaCommand, + type ISetSheetFilterRangeCommandParams, + type ISetSheetsFilterCriteriaCommandParams, + ReCalcSheetsFilterCommand, + RemoveSheetFilterCommand, + SetSheetFilterRangeCommand, + SetSheetsFilterCriteriaCommand, + SmartToggleSheetsFilterCommand, +} from './commands/commands/sheets-filter.command'; // #endregion diff --git a/packages/sheets-filter/src/models/filter-model.ts b/packages/sheets-filter/src/models/filter-model.ts index cb47a983a8e..2ccc9ca9856 100644 --- a/packages/sheets-filter/src/models/filter-model.ts +++ b/packages/sheets-filter/src/models/filter-model.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { CellValueType, Disposable, extractPureTextFromCell, mergeSets, Rectangle, Tools } from '@univerjs/core'; import type { CellValue, ICellData, IRange, Nullable, Worksheet } from '@univerjs/core'; -import { BehaviorSubject } from 'rxjs'; import type { Observable } from 'rxjs'; +import { CellValueType, Disposable, extractPureTextFromCell, mergeSets, Rectangle, Tools } from '@univerjs/core'; +import { BehaviorSubject } from 'rxjs'; import { ensureNumeric, getCustomFilterFn, isNumericFilterFn, notEquals } from './custom-filters'; import { CustomFilterOperator, type IAutoFilter, type ICustomFilter, type ICustomFilters, type IFilterColumn, type IFilters } from './types'; @@ -553,3 +553,4 @@ function extractFilterValueFromCell(cell: ICellData): string | number { return ''; } + diff --git a/packages/sheets-find-replace/src/controllers/__tests__/utils.spec.ts b/packages/sheets-find-replace/src/controllers/__tests__/utils.spec.ts index c6b49ee324f..a4ffc69a943 100644 --- a/packages/sheets-find-replace/src/controllers/__tests__/utils.spec.ts +++ b/packages/sheets-find-replace/src/controllers/__tests__/utils.spec.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; - import type { Dependency, IWorkbookData, Worksheet } from '@univerjs/core'; -import { ILogService, IUniverInstanceService, LocaleType, LogLevel, Univer } from '@univerjs/core'; + import type { IFindQuery } from '@univerjs/find-replace'; +import { ILogService, IUniverInstanceService, LocaleType, LogLevel, Univer } from '@univerjs/core'; import { FindBy, FindDirection, FindScope } from '@univerjs/find-replace'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { hitCell } from '../sheet-find-replace.controller'; import { isBeforePositionWithColumnPriority, isBeforePositionWithRowPriority, @@ -27,7 +28,6 @@ import { isBehindPositionWithRowPriority, isSamePosition, } from '../utils'; -import { hitCell } from '../sheet-find-replace.controller'; describe('Test sheet find replace utils', () => { it('Should "isSamePosition" work as expected', () => { diff --git a/packages/sheets-formula-ui/package.json b/packages/sheets-formula-ui/package.json index 4f1ea201e8d..f54c32f9cfd 100644 --- a/packages/sheets-formula-ui/package.json +++ b/packages/sheets-formula-ui/package.json @@ -77,7 +77,7 @@ "@univerjs/icons": "^0.1.84", "@univerjs/sheets": "workspace:*", "@univerjs/sheets-formula": "workspace:*", - "@univerjs/sheets-numfmt": "workspace:*", + "@univerjs/sheets-numfmt-ui": "workspace:*", "@univerjs/sheets-ui": "workspace:*", "@univerjs/ui": "workspace:*", "clsx": "^2.1.1" diff --git a/packages/sheets-formula-ui/src/controllers/formula-editor-show.controller.ts b/packages/sheets-formula-ui/src/controllers/formula-editor-show.controller.ts index 9bd25d750eb..446da7b3d03 100644 --- a/packages/sheets-formula-ui/src/controllers/formula-editor-show.controller.ts +++ b/packages/sheets-formula-ui/src/controllers/formula-editor-show.controller.ts @@ -33,9 +33,8 @@ import { SetFormulaCalculationResultMutation, } from '@univerjs/engine-formula'; import { IRenderManagerService } from '@univerjs/engine-render'; -import { SetWorksheetRowAutoHeightMutation } from '@univerjs/sheets'; +import { BEFORE_CELL_EDIT, SetWorksheetRowAutoHeightMutation, SheetInterceptorService } from '@univerjs/sheets'; import { - IEditorBridgeService, ISheetSelectionRenderService, SELECTION_SHAPE_DEPTH, SelectionShape, @@ -48,7 +47,7 @@ export class FormulaEditorShowController extends Disposable implements IRenderMo constructor( private readonly _context: IRenderContext, - @Inject(IEditorBridgeService) private _editorBridgeService: IEditorBridgeService, + @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, @Inject(FormulaDataModel) private readonly _formulaDataModel: FormulaDataModel, @Inject(ThemeService) private readonly _themeService: ThemeService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @@ -93,8 +92,7 @@ export class FormulaEditorShowController extends Disposable implements IRenderMo private _initInterceptorEditorStart(): void { this.disposeWithMe( toDisposable( - this._editorBridgeService.interceptor.intercept( - this._editorBridgeService.interceptor.getInterceptPoints().BEFORE_CELL_EDIT, + this._sheetInterceptorService.writeCellInterceptor.intercept(BEFORE_CELL_EDIT, { handler: (value, context, next) => { const { row, col, unitId, subUnitId, worksheet } = context; diff --git a/packages/sheets-formula/package.json b/packages/sheets-formula/package.json index 81aa3ec8740..db04445f14c 100644 --- a/packages/sheets-formula/package.json +++ b/packages/sheets-formula/package.json @@ -21,7 +21,8 @@ ], "exports": { ".": "./src/index.ts", - "./*": "./src/*" + "./*": "./src/*", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/sheets-formula/src/commands/commands/insert-function.command.ts b/packages/sheets-formula/src/commands/commands/insert-function.command.ts index 3c4167109e3..96cced6a561 100644 --- a/packages/sheets-formula/src/commands/commands/insert-function.command.ts +++ b/packages/sheets-formula/src/commands/commands/insert-function.command.ts @@ -15,8 +15,8 @@ */ import type { IAccessor, ICellData, ICommand, IRange } from '@univerjs/core'; -import { CommandType, ICommandService, ObjectMatrix, Tools } from '@univerjs/core'; import type { ISetRangeValuesCommandParams } from '@univerjs/sheets'; +import { CommandType, ICommandService, ObjectMatrix, Tools } from '@univerjs/core'; import { SetRangeValuesCommand } from '@univerjs/sheets'; export interface IInsertFunction { @@ -44,7 +44,7 @@ export interface IInsertFunctionCommandParams { } export const InsertFunctionCommand: ICommand = { - id: 'formula-ui.command.insert-function', + id: 'formula.command.insert-function', type: CommandType.COMMAND, handler: async (accessor: IAccessor, params: IInsertFunctionCommandParams) => { const { list } = params; diff --git a/packages/sheets-formula/src/facade/f-univer.ts b/packages/sheets-formula/src/facade/f-univer.ts new file mode 100644 index 00000000000..5ab0d04e905 --- /dev/null +++ b/packages/sheets-formula/src/facade/f-univer.ts @@ -0,0 +1,81 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IDisposable } from '@univerjs/core'; +import { debounce, FUniver } from '@univerjs/core'; +import { SetFormulaCalculationStartMutation } from '@univerjs/engine-formula'; +import { type IRegisterFunctionParams, IRegisterFunctionService, RegisterFunctionService } from '../services/register-function.service'; + +interface IFUniverSheetsFormulaMixin { + /** + * Register a function to the spreadsheet. + * + * @param {IRegisterFunctionParams} config The configuration of the function. + * @returns {IDisposable} The disposable instance. + */ + registerFunction(config: IRegisterFunctionParams): IDisposable; + + // TODO@Dushusir: this API should be implemented on FFormula. +} + +class FUniverSheetsFormulaMixin extends FUniver implements IFUniverSheetsFormulaMixin { + /** + * registerFunction may be executed multiple times, triggering multiple formula forced refreshes + */ + declare private _debouncedFormulaCalculation: () => void; + + /** + * Initialize the FUniver instance. + * + * @private + */ + override _initialize(): void { + this._debouncedFormulaCalculation = debounce(() => { + this._commandService.executeCommand( + SetFormulaCalculationStartMutation.id, + { + commands: [], + forceCalculation: true, + }, + { + onlyLocal: true, + } + ); + }, 10); + } + + override registerFunction(config: IRegisterFunctionParams): IDisposable { + let registerFunctionService = this._injector.get(IRegisterFunctionService); + + if (!registerFunctionService) { + this._injector.add([IRegisterFunctionService, { useClass: RegisterFunctionService }]); + registerFunctionService = this._injector.get(IRegisterFunctionService); + } + + const functionsDisposable = registerFunctionService.registerFunctions(config); + + // When the initialization workbook data already contains custom formulas, and then register the formula, you need to trigger a forced calculation to refresh the calculation results + // TODO@Dushusir: this should be moved to the services not API. + this._debouncedFormulaCalculation(); + return functionsDisposable; + } +} + +FUniver.extend(FUniverSheetsFormulaMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverSheetsFormulaMixin {} +} diff --git a/packages/sheets-formula/src/facade/index.ts b/packages/sheets-formula/src/facade/index.ts new file mode 100644 index 00000000000..14bcba31dc0 --- /dev/null +++ b/packages/sheets-formula/src/facade/index.ts @@ -0,0 +1,17 @@ +/** + * 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 './f-univer'; diff --git a/packages/sheets-formula/src/services/description.service.ts b/packages/sheets-formula/src/services/description.service.ts index 91cab1cd291..9cc1f56fef8 100644 --- a/packages/sheets-formula/src/services/description.service.ts +++ b/packages/sheets-formula/src/services/description.service.ts @@ -115,7 +115,7 @@ export interface IDescriptionService { isFormulaDefinedName(name: string): boolean; } -export const IDescriptionService = createIdentifier('formula-ui.description-service'); +export const IDescriptionService = createIdentifier('formula.description-service'); export class DescriptionService implements IDescriptionService, IDisposable { private _descriptions: IFunctionInfo[] = []; diff --git a/packages/sheets-formula/src/services/function-list/math.ts b/packages/sheets-formula/src/services/function-list/math.ts index 6b6ca9a2610..c8ed2677015 100644 --- a/packages/sheets-formula/src/services/function-list/math.ts +++ b/packages/sheets-formula/src/services/function-list/math.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { FUNCTION_NAMES_MATH, FunctionType } from '@univerjs/engine-formula'; import type { IFunctionInfo } from '@univerjs/engine-formula'; +import { FUNCTION_NAMES_MATH, FunctionType } from '@univerjs/engine-formula'; export const FUNCTION_LIST_MATH: IFunctionInfo[] = [ { diff --git a/packages/sheets-formula/tsconfig.json b/packages/sheets-formula/tsconfig.json index 29d914bcd53..c62210cbad2 100644 --- a/packages/sheets-formula/tsconfig.json +++ b/packages/sheets-formula/tsconfig.json @@ -5,5 +5,5 @@ "outDir": "lib/types" }, "references": [{ "path": "./tsconfig.node.json" }], - "include": ["src", "../sheets/src/services/ref-selections.service.ts"] + "include": ["src"] } diff --git a/packages/sheets-hyper-link-ui/package.json b/packages/sheets-hyper-link-ui/package.json index 63d1f8e2267..55fa221e299 100644 --- a/packages/sheets-hyper-link-ui/package.json +++ b/packages/sheets-hyper-link-ui/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/sheets-hyper-link-ui/src/controllers/set-range.controller.ts b/packages/sheets-hyper-link-ui/src/controllers/set-range.controller.ts index f8ce3c9dd9d..a341b59b317 100644 --- a/packages/sheets-hyper-link-ui/src/controllers/set-range.controller.ts +++ b/packages/sheets-hyper-link-ui/src/controllers/set-range.controller.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import type { IMutationInfo } from '@univerjs/core'; +import type { IMutationInfo, Workbook } from '@univerjs/core'; import type { ISetRangeValuesMutationParams } from '@univerjs/sheets'; -import { BuildTextUtils, CustomRangeType, DataStreamTreeTokenType, Disposable, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, generateRandomId, Inject, IUniverInstanceService, ObjectMatrix, Range, TextX, Tools } from '@univerjs/core'; +import { BuildTextUtils, CustomRangeType, DataStreamTreeTokenType, Disposable, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, generateRandomId, Inject, IUniverInstanceService, ObjectMatrix, Range, TextX, Tools, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; -import { ClearSelectionAllCommand, ClearSelectionContentCommand, ClearSelectionFormatCommand, getSheetCommandTarget, SetRangeValuesCommand, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets'; +import { AFTER_CELL_EDIT, ClearSelectionAllCommand, ClearSelectionContentCommand, ClearSelectionFormatCommand, getSheetCommandTarget, SetRangeValuesCommand, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets'; import { AddHyperLinkMutation, HyperLinkModel, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link'; -import { IEditorBridgeService, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; +import { IEditorBridgeService } from '@univerjs/sheets-ui'; export class SheetHyperLinkSetRangeController extends Disposable { constructor( @@ -141,7 +141,7 @@ export class SheetHyperLinkSetRangeController extends Disposable { } private _initAfterEditor() { - this.disposeWithMe(this._editorBridgeService.interceptor.intercept(this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT, { + this.disposeWithMe(this._sheetInterceptorService.writeCellInterceptor.intercept(AFTER_CELL_EDIT, { handler: (cell, context, next) => { if (!cell || cell.p) { return next(cell); @@ -149,12 +149,18 @@ export class SheetHyperLinkSetRangeController extends Disposable { if (typeof cell.v === 'string' && Tools.isLegalUrl(cell.v) && cell.v[cell.v.length - 1] !== ' ') { const { unitId, subUnitId } = context; - const renderer = this._renderManagerService.getRenderById(unitId); - const skeleton = renderer?.with(SheetSkeletonManagerService).getWorksheetSkeleton(subUnitId); - if (!skeleton) { + + const workbook = this._univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); + const worksheet = workbook?.getSheetBySheetId(subUnitId); + if (!worksheet) { return next(cell); } - const doc = skeleton.skeleton.getBlankCellDocumentModel(cell); + // const renderer = this._renderManagerService.getRenderById(unitId); + // const skeleton = renderer?.with(SheetSkeletonManagerService).getWorksheetSkeleton(subUnitId); + // if (!skeleton) { + // return next(cell); + // } + const doc = worksheet.getBlankCellDocumentModel(cell); if (!doc.documentModel) { return next(cell); } diff --git a/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts b/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts index 45b61450eb0..db138adf324 100644 --- a/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts +++ b/packages/sheets-hyper-link-ui/src/controllers/ui.controller.ts @@ -17,9 +17,6 @@ import { Disposable, ICommandService, Inject, Injector } from '@univerjs/core'; import { LinkSingle } from '@univerjs/icons'; import { ComponentManager, IMenuManagerService, IShortcutService } from '@univerjs/ui'; -import { AddHyperLinkCommand, AddRichHyperLinkCommand } from '../commands/commands/add-hyper-link.command'; -import { CancelHyperLinkCommand, CancelRichHyperLinkCommand } from '../commands/commands/remove-hyper-link.command'; -import { UpdateHyperLinkCommand, UpdateRichHyperLinkCommand } from '../commands/commands/update-hyper-link.command'; import { CloseHyperLinkPopupOperation, InsertHyperLinkOperation, InsertHyperLinkToolbarOperation, OpenHyperLinkEditPanelOperation } from '../commands/operations/popup.operations'; import { CellLinkEdit } from '../views/CellLinkEdit'; import { CellLinkPopup } from '../views/CellLinkPopup'; @@ -58,13 +55,6 @@ export class SheetsHyperLinkUIController extends Disposable { CloseHyperLinkPopupOperation, InsertHyperLinkOperation, InsertHyperLinkToolbarOperation, - - AddHyperLinkCommand, - UpdateHyperLinkCommand, - CancelHyperLinkCommand, - UpdateRichHyperLinkCommand, - CancelRichHyperLinkCommand, - AddRichHyperLinkCommand, ].forEach((command) => { this._commandService.registerCommand(command); }); diff --git a/packages/sheets-hyper-link-ui/src/controllers/url.controller.ts b/packages/sheets-hyper-link-ui/src/controllers/url.controller.ts index fd1dcc5361f..cd01cdbf57b 100644 --- a/packages/sheets-hyper-link-ui/src/controllers/url.controller.ts +++ b/packages/sheets-hyper-link-ui/src/controllers/url.controller.ts @@ -15,10 +15,12 @@ */ import { Disposable, Inject } from '@univerjs/core'; +import { SheetsHyperLinkParserService } from '@univerjs/sheets-hyper-link'; import { SheetsHyperLinkResolverService } from '../services/resolver.service'; export class SheetHyperLinkUrlController extends Disposable { constructor( + @Inject(SheetsHyperLinkParserService) private readonly _parserService: SheetsHyperLinkParserService, @Inject(SheetsHyperLinkResolverService) private _resolverService: SheetsHyperLinkResolverService ) { super(); @@ -28,8 +30,8 @@ export class SheetHyperLinkUrlController extends Disposable { private _handleInitUrl() { const hash = location.hash; if (hash) { - const linkInfo = this._resolverService.parseHyperLink(hash); - linkInfo.handler(); + const linkInfo = this._parserService.parseHyperLink(hash); + this._resolverService.navigate(linkInfo); } } } diff --git a/packages/sheets-hyper-link-ui/src/facade/f-workbook.ts b/packages/sheets-hyper-link-ui/src/facade/f-workbook.ts new file mode 100644 index 00000000000..028695ccad9 --- /dev/null +++ b/packages/sheets-hyper-link-ui/src/facade/f-workbook.ts @@ -0,0 +1,44 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FWorkbook } from '@univerjs/sheets/facade'; +import { SheetsHyperLinkParserService } from '@univerjs/sheets-hyper-link'; +import { FWorkbookHyperLinkMixin } from '@univerjs/sheets-hyper-link/facade'; +import { SheetsHyperLinkResolverService } from '../services/resolver.service'; + +interface IFWorkbookHyperlinkUIMixin { + /** + * navigate to the sheet hyperlink + * @param hyperlink the hyperlink string + */ + navigateToSheetHyperlink(this: FWorkbook, hyperlink: string): void; +} + +class FWorkbookHyperLinkUIMixin extends FWorkbookHyperLinkMixin implements IFWorkbookHyperlinkUIMixin { + // TODO: this should be migrated back to hyperlink ui plugin + override navigateToSheetHyperlink(hyperlink: string): void { + const parserService = this._injector.get(SheetsHyperLinkParserService); + const resolverService = this._injector.get(SheetsHyperLinkResolverService); + const info = parserService.parseHyperLink(hyperlink); + resolverService.navigate(info); + } +} + +FWorkbook.extend(FWorkbookHyperLinkUIMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorkbook extends IFWorkbookHyperlinkUIMixin {} +} diff --git a/packages/sheets-hyper-link-ui/src/facade/index.ts b/packages/sheets-hyper-link-ui/src/facade/index.ts new file mode 100644 index 00000000000..cf732b1e137 --- /dev/null +++ b/packages/sheets-hyper-link-ui/src/facade/index.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/packages/sheets-hyper-link-ui/src/index.ts b/packages/sheets-hyper-link-ui/src/index.ts index 4e6d6510362..dc2d08d8cbf 100644 --- a/packages/sheets-hyper-link-ui/src/index.ts +++ b/packages/sheets-hyper-link-ui/src/index.ts @@ -22,13 +22,9 @@ export { SheetsHyperLinkPopupService } from './services/popup.service'; export { SheetsHyperLinkResolverService } from './services/resolver.service'; export { type ICustomHyperLinkView, SheetsHyperLinkSidePanelService } from './services/side-panel.service'; -export type { ISheetHyperLinkInfo, ISheetUrlParams } from './types/interfaces'; // #region - all commands -export { AddHyperLinkCommand, type IAddHyperLinkCommandParams } from './commands/commands/add-hyper-link.command'; -export { CancelHyperLinkCommand, type ICancelHyperLinkCommandParams } from './commands/commands/remove-hyper-link.command'; -export { type IUpdateHyperLinkCommandParams, UpdateHyperLinkCommand } from './commands/commands/update-hyper-link.command'; export { CloseHyperLinkPopupOperation, InsertHyperLinkOperation, diff --git a/packages/sheets-hyper-link-ui/src/services/resolver.service.ts b/packages/sheets-hyper-link-ui/src/services/resolver.service.ts index 4fd039698f5..65d3f9d520d 100644 --- a/packages/sheets-hyper-link-ui/src/services/resolver.service.ts +++ b/packages/sheets-hyper-link-ui/src/services/resolver.service.ts @@ -16,12 +16,11 @@ import type { IRange, Workbook, Worksheet } from '@univerjs/core'; import type { ISetSelectionsOperationParams } from '@univerjs/sheets'; +import type { ISheetHyperLinkInfo, ISheetUrlParams } from '@univerjs/sheets-hyper-link'; import type { IUniverSheetsHyperLinkUIConfig } from '../controllers/config.schema'; -import type { ISheetHyperLinkInfo } from '../types/interfaces/i-sheet-hyper-link-info'; -import type { ISheetUrlParams } from '../types/interfaces/i-sheet-url-params'; import { ICommandService, IConfigService, Inject, isValidRange, IUniverInstanceService, LocaleService, RANGE_TYPE, Rectangle, UniverInstanceType } from '@univerjs/core'; import { MessageType } from '@univerjs/design'; -import { deserializeRangeWithSheet, IDefinedNamesService, serializeRange, serializeRangeWithSheet } from '@univerjs/engine-formula'; +import { deserializeRangeWithSheet, IDefinedNamesService } from '@univerjs/engine-formula'; import { SetSelectionsOperation, SetWorksheetActiveOperation } from '@univerjs/sheets'; import { ERROR_RANGE, SheetHyperLinkType } from '@univerjs/sheets-hyper-link'; import { ScrollToRangeOperation } from '@univerjs/sheets-ui'; @@ -64,66 +63,25 @@ export class SheetsHyperLinkResolverService { @IConfigService private _configService: IConfigService ) { } - private _getURLName(params: ISheetUrlParams) { - const { gid, range, rangeid, unitid } = params; - const workbook = unitid ? - this._univerInstanceService.getUnit(unitid, UniverInstanceType.UNIVER_SHEET) - : this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); - const invalidLink = { - type: SheetHyperLinkType.INVALID, - name: this._localeService.t('hyperLink.message.refError'), - }; - - if (!workbook) { - return invalidLink; - } - - const sheet = gid ? workbook.getSheetBySheetId(gid) : workbook.getActiveSheet(); - const sheetName = sheet?.getName() ?? ''; - - if (range) { - if (!sheet) return invalidLink; - const rangeObj = deserializeRangeWithSheet(range).range; - if (isValidRange(rangeObj, sheet) && range !== ERROR_RANGE) { - return { - type: SheetHyperLinkType.RANGE, - name: serializeRangeWithSheet(sheetName, rangeObj), - }; - } - return invalidLink; - } - - if (rangeid) { - const range = this._definedNamesService.getValueById(workbook.getUnitId(), rangeid); - if (range) { - return { - type: SheetHyperLinkType.DEFINE_NAME, - name: range.formulaOrRefString, - }; - } - return invalidLink; - } - - if (gid) { - const worksheet = workbook.getSheetBySheetId(gid); - if (worksheet) { - return { - type: SheetHyperLinkType.SHEET, - name: worksheet.getName(), - }; - } - return invalidLink; + navigate(info: ISheetHyperLinkInfo): void { + switch (info.type) { + case SheetHyperLinkType.URL: + this.navigateToOtherWebsite(info.url); + break; + default: + this._navigateToUniver(info.searchObj!); } - - return invalidLink; } - navigateTo(params: ISheetUrlParams) { + private _navigateToUniver(params: ISheetUrlParams) { + // NOTE: should we always use current unit and active worksheet? + const { gid, range, rangeid } = params; const workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); if (!workbook) { return; } + const unitId = workbook.getUnitId(); if (rangeid) { const item = this._definedNamesService.getValueById(unitId, rangeid); @@ -171,44 +129,6 @@ export class SheetsHyperLinkResolverService { this.navigateToSheetById(unitId, gid); } - buildHyperLink(unitId: string, sheetId: string, range?: string | IRange): string { - return `#${SheetHyperLinkType.SHEET}=${sheetId}${range ? `&${typeof range === 'string' ? SheetHyperLinkType.DEFINE_NAME : SheetHyperLinkType.RANGE}=${typeof range === 'string' ? range : serializeRange(range)}` : ''}`; - } - - parseHyperLink(urlStr: string): ISheetHyperLinkInfo { - if (urlStr.startsWith('#')) { - const search = new URLSearchParams(urlStr.slice(1)); - // range, gid, rangeid - const searchObj: ISheetUrlParams = { - gid: search.get('gid') ?? '', - range: search.get('range') ?? '', - rangeid: search.get('rangeid') ?? '', - unitid: search.get('unitid') ?? '', - }; - const urlInfo = this._getURLName(searchObj); - - return { - type: urlInfo.type, - name: urlInfo.name, - url: urlStr, - searchObj, - handler: () => { - this.navigateTo(searchObj); - }, - }; - } else { - return { - type: SheetHyperLinkType.URL, - name: urlStr, - url: urlStr, - handler: () => { - this.navigateToOtherWebsite(urlStr); - }, - searchObj: null, - }; - } - } - async navigateToRange(unitId: string, subUnitId: string, range: IRange) { const worksheet = await this.navigateToSheetById(unitId, subUnitId); if (worksheet) { @@ -230,37 +150,6 @@ export class SheetsHyperLinkResolverService { } } - async navigateToSheet(unitId: string, sheetName: string) { - const workbook = this._univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); - if (!workbook) { - return false; - } - const worksheet = workbook.getActiveSheet(); - - if (worksheet?.getName() === sheetName) { - return true; - } - const targetSheet = workbook.getSheetBySheetName(sheetName); - - if (!targetSheet) { - this._messageService.show({ - content: this._localeService.t('hyperLink.message.noSheet'), - type: MessageType.Error, - }); - return; - } - - const sheetId = targetSheet.getSheetId(); - if (workbook.getHiddenWorksheets().indexOf(sheetId) > -1) { - this._messageService.show({ - content: this._localeService.t('hyperLink.message.hiddenSheet'), - type: MessageType.Error, - }); - } - - return await this._commandService.executeCommand(SetWorksheetActiveOperation.id, { unitId, subUnitId: sheetId }); - } - async navigateToSheetById(unitId: string, subUnitId: string) { const workbook = this._univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); if (!workbook) { @@ -299,8 +188,8 @@ export class SheetsHyperLinkResolverService { return false; } - async navigateToDefineName(unitId: string, rangeid: string) { - this._definedNamesService.focusRange(unitId, rangeid); + async navigateToDefineName(unitId: string, rangeId: string) { + this._definedNamesService.focusRange(unitId, rangeId); return true; } diff --git a/packages/sheets-hyper-link-ui/src/views/CellLinkEdit/index.tsx b/packages/sheets-hyper-link-ui/src/views/CellLinkEdit/index.tsx index 58cfe8d1063..f7990544970 100644 --- a/packages/sheets-hyper-link-ui/src/views/CellLinkEdit/index.tsx +++ b/packages/sheets-hyper-link-ui/src/views/CellLinkEdit/index.tsx @@ -22,15 +22,12 @@ import { DocSelectionManagerService } from '@univerjs/docs'; import { DocBackScrollRenderController, DocSelectionRenderService } from '@univerjs/docs-ui'; import { deserializeRangeWithSheet, IDefinedNamesService, serializeRange, serializeRangeToRefString, serializeRangeWithSheet } from '@univerjs/engine-formula'; import { IRenderManagerService } from '@univerjs/engine-render'; - import { SetSelectionsOperation, SetWorksheetActiveOperation } from '@univerjs/sheets'; import { RangeSelector } from '@univerjs/sheets-formula-ui'; -import { SheetHyperLinkType } from '@univerjs/sheets-hyper-link'; +import { AddHyperLinkCommand, AddRichHyperLinkCommand, SheetHyperLinkType, SheetsHyperLinkParserService, UpdateHyperLinkCommand, UpdateRichHyperLinkCommand } from '@univerjs/sheets-hyper-link'; import { IEditorBridgeService, IMarkSelectionService, ScrollToRangeOperation } from '@univerjs/sheets-ui'; import { IZenZoneService, KeyCode, useEvent, useObservable } from '@univerjs/ui'; import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { AddHyperLinkCommand, AddRichHyperLinkCommand } from '../../commands/commands/add-hyper-link.command'; -import { UpdateHyperLinkCommand, UpdateRichHyperLinkCommand } from '../../commands/commands/update-hyper-link.command'; import { CloseHyperLinkPopupOperation } from '../../commands/operations/popup.operations'; import { isLegalLink, serializeUrl } from '../../common/util'; import { SheetsHyperLinkPopupService } from '../../services/popup.service'; @@ -53,6 +50,7 @@ export const CellLinkEdit = () => { const univerInstanceService = useDependency(IUniverInstanceService); const popupService = useDependency(SheetsHyperLinkPopupService); const editing = useObservable(popupService.currentEditing$); + const parserService = useDependency(SheetsHyperLinkParserService); const resolverService = useDependency(SheetsHyperLinkResolverService); const commandService = useDependency(ICommandService); const sidePanelService = useDependency(SheetsHyperLinkSidePanelService); @@ -145,7 +143,7 @@ export const CellLinkEdit = () => { return; } setDisplay(link.display); - const linkInfo = resolverService.parseHyperLink(link.payload); + const linkInfo = parserService.parseHyperLink(link.payload); setType(linkInfo.type === SheetHyperLinkType.INVALID ? SheetHyperLinkType.RANGE : linkInfo.type); switch (linkInfo.type) { case SheetHyperLinkType.URL: { diff --git a/packages/sheets-hyper-link-ui/src/views/CellLinkPopup/index.tsx b/packages/sheets-hyper-link-ui/src/views/CellLinkPopup/index.tsx index 729d0fb6f02..cd7b7d7f4ca 100644 --- a/packages/sheets-hyper-link-ui/src/views/CellLinkPopup/index.tsx +++ b/packages/sheets-hyper-link-ui/src/views/CellLinkPopup/index.tsx @@ -18,12 +18,11 @@ import type { IHyperLinkPopup } from '../../services/popup.service'; import { DOCS_ZEN_EDITOR_UNIT_ID_KEY, ICommandService, LocaleService, useDependency, useObservable } from '@univerjs/core'; import { MessageType, Tooltip } from '@univerjs/design'; import { AllBorderSingle, CopySingle, LinkSingle, UnlinkSingle, WriteSingle, Xlsx } from '@univerjs/icons'; -import { SheetHyperLinkType } from '@univerjs/sheets-hyper-link'; +import { CancelHyperLinkCommand, CancelRichHyperLinkCommand, SheetHyperLinkType, SheetsHyperLinkParserService } from '@univerjs/sheets-hyper-link'; import { IEditorBridgeService } from '@univerjs/sheets-ui'; import { IMessageService, IZenZoneService } from '@univerjs/ui'; import cs from 'clsx'; import React, { useEffect, useState } from 'react'; -import { CancelHyperLinkCommand, CancelRichHyperLinkCommand } from '../../commands/commands/remove-hyper-link.command'; import { OpenHyperLinkEditPanelOperation } from '../../commands/operations/popup.operations'; import { SheetsHyperLinkPopupService } from '../../services/popup.service'; import { SheetsHyperLinkResolverService } from '../../services/resolver.service'; @@ -46,6 +45,7 @@ export const CellLinkPopup = () => { const [currentPopup, setCurrentPopup] = useState(null); const resolverService = useDependency(SheetsHyperLinkResolverService); const editorBridgeService = useDependency(IEditorBridgeService); + const parserHyperLinkService = useDependency(SheetsHyperLinkParserService); const zenZoneService = useDependency(IZenZoneService); const visible = useObservable(zenZoneService.visible$); @@ -67,7 +67,7 @@ export const CellLinkPopup = () => { if (!customRange?.properties?.url) { return null; } - const linkObj = resolverService.parseHyperLink(customRange.properties.url ?? ''); + const linkObj = parserHyperLinkService.parseHyperLink(customRange.properties.url ?? ''); const isError = linkObj.type === SheetHyperLinkType.INVALID; return ( @@ -78,7 +78,8 @@ export const CellLinkPopup = () => { if (zenZoneService.visible) { return; } - linkObj.handler(); + + resolverService.navigate(linkObj); }} >

diff --git a/packages/sheets-hyper-link/package.json b/packages/sheets-hyper-link/package.json index 6a79b4688a3..7a1ccb5f3bb 100644 --- a/packages/sheets-hyper-link/package.json +++ b/packages/sheets-hyper-link/package.json @@ -20,7 +20,8 @@ "keywords": [], "exports": { ".": "./src/index.ts", - "./*": "./src/*" + "./*": "./src/*", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", @@ -61,6 +62,7 @@ }, "dependencies": { "@univerjs/core": "workspace:*", + "@univerjs/docs": "workspace:*", "@univerjs/engine-formula": "workspace:*", "@univerjs/protocol": "0.1.39-alpha.38", "@univerjs/sheets": "workspace:*" diff --git a/packages/sheets-hyper-link-ui/src/commands/commands/add-hyper-link.command.ts b/packages/sheets-hyper-link/src/commands/commands/add-hyper-link.command.ts similarity index 80% rename from packages/sheets-hyper-link-ui/src/commands/commands/add-hyper-link.command.ts rename to packages/sheets-hyper-link/src/commands/commands/add-hyper-link.command.ts index 91922e20d5b..17542826342 100644 --- a/packages/sheets-hyper-link-ui/src/commands/commands/add-hyper-link.command.ts +++ b/packages/sheets-hyper-link/src/commands/commands/add-hyper-link.command.ts @@ -14,14 +14,12 @@ * limitations under the License. */ -import type { ICellData, ICommand, IDocumentData, IMutationInfo, Workbook } from '@univerjs/core'; +import type { ICellData, ICommand, IDocumentData, IMutationInfo } from '@univerjs/core'; import type { ISetRangeValuesMutationParams } from '@univerjs/sheets'; -import { BuildTextUtils, CellValueType, CommandType, CustomRangeType, DataStreamTreeTokenType, generateRandomId, ICommandService, IUndoRedoService, IUniverInstanceService, sequenceExecuteAsync, TextX, Tools, UniverInstanceType } from '@univerjs/core'; -import { addCustomRangeBySelectionFactory } from '@univerjs/docs-ui'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets'; +import { BuildTextUtils, CellValueType, CommandType, CustomRangeType, DataStreamTreeTokenType, generateRandomId, ICommandService, IUndoRedoService, IUniverInstanceService, sequenceExecuteAsync, TextX, Tools } from '@univerjs/core'; +import { addCustomRangeBySelectionFactory } from '@univerjs/docs'; +import { getSheetCommandTarget, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory, SheetInterceptorService } from '@univerjs/sheets'; import { AddHyperLinkMutation, HyperLinkModel, type ICellHyperLink, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link'; -import { IEditorBridgeService, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; export interface IAddHyperLinkCommandParams { unitId: string; @@ -37,35 +35,26 @@ export const AddHyperLinkCommand: ICommand = { // eslint-disable-next-line max-lines-per-function async handler(accessor, params) { - if (!params) { - return false; - } + if (!params) return false; + const commandService = accessor.get(ICommandService); const undoRedoService = accessor.get(IUndoRedoService); - const renderManagerService = accessor.get(IRenderManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const hyperLinkModel = accessor.get(HyperLinkModel); - const editorBridgeService = accessor.get(IEditorBridgeService); - const { unitId, subUnitId, link } = params; - const workbook = univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); - const currentRender = renderManagerService.getRenderById(unitId); - if (!currentRender || !workbook) { - return false; - } - const worksheet = workbook?.getSheetBySheetId(subUnitId); - const skeletonManagerService = currentRender.with(SheetSkeletonManagerService); - const skeleton = skeletonManagerService.getCurrent()?.skeleton; - if (!worksheet || !skeleton) { - return false; - } + const sheetInterceptorService = accessor.get(SheetInterceptorService); + + const target = getSheetCommandTarget(univerInstanceService, params); + if (!target) return false; + + const { unitId, subUnitId, workbook, worksheet } = target; + const { link } = params; const { payload, display, row, column, id } = link; + const cellData = worksheet.getCell(row, column); - const doc = skeleton.getBlankCellDocumentModel(cellData); + const doc = worksheet.getBlankCellDocumentModel(cellData); const snapshot = doc.documentModel!.getSnapshot(); const body = Tools.deepClone(snapshot.body); - if (!body) { - return false; - } + if (!body) return false; let textX: TextX | false; if (display) { @@ -103,9 +92,7 @@ export const AddHyperLinkCommand: ICommand = { }); } - if (!textX) { - return false; - } + if (!textX) return false; const newBody = TextX.apply(body, textX.serialize()); const rangeValue: IDocumentData = { @@ -118,8 +105,7 @@ export const AddHyperLinkCommand: ICommand = { t: CellValueType.STRING, }; - const finalCellData = await editorBridgeService.beforeSetRangeValue(workbook, worksheet, row, column, newCellData); - + const finalCellData = await sheetInterceptorService.onWriteCell(workbook, worksheet, row, column, newCellData); const redoParams: ISetRangeValuesMutationParams = { unitId, subUnitId, diff --git a/packages/sheets-hyper-link-ui/src/commands/commands/remove-hyper-link.command.ts b/packages/sheets-hyper-link/src/commands/commands/remove-hyper-link.command.ts similarity index 77% rename from packages/sheets-hyper-link-ui/src/commands/commands/remove-hyper-link.command.ts rename to packages/sheets-hyper-link/src/commands/commands/remove-hyper-link.command.ts index 19c3f34a029..a83ac1cdcbb 100644 --- a/packages/sheets-hyper-link-ui/src/commands/commands/remove-hyper-link.command.ts +++ b/packages/sheets-hyper-link/src/commands/commands/remove-hyper-link.command.ts @@ -14,14 +14,12 @@ * limitations under the License. */ +import type { DocumentDataModel, ICommand, IDocumentBody, IMutationInfo, Nullable } from '@univerjs/core'; +import type { IAddHyperLinkMutationParams } from '@univerjs/sheets-hyper-link'; import { BuildTextUtils, CellValueType, CommandType, ICommandService, IUndoRedoService, IUniverInstanceService, sequenceExecute, TextX, Tools, UniverInstanceType } from '@univerjs/core'; -import { deleteCustomRangeFactory } from '@univerjs/docs-ui'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets'; +import { deleteCustomRangeFactory } from '@univerjs/docs'; +import { getSheetCommandTarget, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets'; import { AddHyperLinkMutation, HyperLinkModel, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link'; -import { SheetSkeletonManagerService } from '@univerjs/sheets-ui'; -import type { DocumentDataModel, ICommand, IDocumentBody, IMutationInfo, Nullable, Workbook } from '@univerjs/core'; -import type { IAddHyperLinkMutationParams } from '@univerjs/sheets-hyper-link'; export interface ICancelHyperLinkCommandParams { unitId: string; @@ -40,47 +38,31 @@ export const CancelHyperLinkCommand: ICommand = { // eslint-disable-next-line max-lines-per-function handler(accessor, params) { - if (!params) { - return false; - } + if (!params) return false; + const commandService = accessor.get(ICommandService); const undoRedoService = accessor.get(IUndoRedoService); - const renderManagerService = accessor.get(IRenderManagerService); - const univerInstanceService = accessor.get(IUniverInstanceService); + const instanceSrv = accessor.get(IUniverInstanceService); const hyperLinkModel = accessor.get(HyperLinkModel); - const { unitId, subUnitId, row, column, id } = params; - const workbook = univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); - const currentRender = renderManagerService.getRenderById(unitId); - if (!currentRender || !workbook) { - return false; - } - const worksheet = workbook?.getSheetBySheetId(subUnitId); - const skeletonManagerService = currentRender.with(SheetSkeletonManagerService); - const skeleton = skeletonManagerService.getCurrent()?.skeleton; - if (!worksheet || !skeleton) { - return false; - } + const target = getSheetCommandTarget(instanceSrv, params); + if (!target) return false; + + const { row, column, id } = params; + const { unitId, subUnitId, worksheet } = target; + const cellData = worksheet.getCell(row, column); - if (!cellData) { - return false; - } - const doc = skeleton.getCellDocumentModelWithFormula(cellData); - if (!doc?.documentModel) { - return false; - } - const snapshot = Tools.deepClone(doc.documentModel!.getSnapshot()); + if (!cellData) return false; + + const doc = worksheet.getCellDocumentModelWithFormula(cellData); + if (!doc?.documentModel) return false; + const snapshot = Tools.deepClone(doc.documentModel!.getSnapshot()); const range = snapshot.body?.customRanges?.find((range) => range.rangeId === id); - if (!range) { - return false; - } + if (!range) return false; const textX = BuildTextUtils.customRange.delete(accessor, { documentDataModel: doc.documentModel, rangeId: id }); - - if (!textX) { - return false; - } + if (!textX) return false; const newBody = TextX.apply(snapshot.body!, textX.serialize()); const redos: IMutationInfo[] = []; diff --git a/packages/sheets-hyper-link-ui/src/commands/commands/update-hyper-link.command.ts b/packages/sheets-hyper-link/src/commands/commands/update-hyper-link.command.ts similarity index 80% rename from packages/sheets-hyper-link-ui/src/commands/commands/update-hyper-link.command.ts rename to packages/sheets-hyper-link/src/commands/commands/update-hyper-link.command.ts index b97720c4ae0..ef05d7878fe 100644 --- a/packages/sheets-hyper-link-ui/src/commands/commands/update-hyper-link.command.ts +++ b/packages/sheets-hyper-link/src/commands/commands/update-hyper-link.command.ts @@ -14,13 +14,11 @@ * limitations under the License. */ -import type { DocumentDataModel, ICellData, ICommand, IMutationInfo, Workbook } from '@univerjs/core'; +import type { DocumentDataModel, ICellData, ICommand, IMutationInfo } from '@univerjs/core'; import { CellValueType, CommandType, CustomRangeType, DataStreamTreeTokenType, generateRandomId, getBodySlice, ICommandService, IUndoRedoService, IUniverInstanceService, sequenceExecuteAsync, TextX, Tools, UniverInstanceType } from '@univerjs/core'; -import { replaceSelectionFactory } from '@univerjs/docs-ui'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { SetRangeValuesMutation, SetRangeValuesUndoMutationFactory } from '@univerjs/sheets'; +import { replaceSelectionFactory } from '@univerjs/docs'; +import { getSheetCommandTarget, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory, SheetInterceptorService } from '@univerjs/sheets'; import { AddHyperLinkMutation, HyperLinkModel, type ICellLinkContent, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link'; -import { IEditorBridgeService, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; export interface IUpdateHyperLinkCommandParams { unitId: string; @@ -34,45 +32,32 @@ export interface IUpdateHyperLinkCommandParams { export const UpdateHyperLinkCommand: ICommand = { type: CommandType.COMMAND, id: 'sheets.command.update-hyper-link', - // eslint-disable-next-line max-lines-per-function, complexity + // eslint-disable-next-line max-lines-per-function async handler(accessor, params) { - if (!params) { - return false; - } + if (!params) return false; + const commandService = accessor.get(ICommandService); const undoRedoService = accessor.get(IUndoRedoService); - const renderManagerService = accessor.get(IRenderManagerService); - const univerInstanceService = accessor.get(IUniverInstanceService); + const instanceSrv = accessor.get(IUniverInstanceService); const hyperLinkModel = accessor.get(HyperLinkModel); - const editorBridgeService = accessor.get(IEditorBridgeService); + const interceptorService = accessor.get(SheetInterceptorService); + + const target = getSheetCommandTarget(instanceSrv); + if (!target) return false; + + const { payload: link, row, column, id } = params; + const { workbook, worksheet, unitId, subUnitId } = target; - const { unitId, subUnitId, payload: link, row, column, id } = params; - const workbook = univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); - const currentRender = renderManagerService.getRenderById(unitId); - if (!currentRender || !workbook) { - return false; - } - const worksheet = workbook?.getSheetBySheetId(subUnitId); - const skeletonManagerService = currentRender.with(SheetSkeletonManagerService); - const skeleton = skeletonManagerService.getCurrent()?.skeleton; - if (!worksheet || !skeleton) { - return false; - } const { payload, display = '' } = link; const cellData = worksheet.getCell(row, column); - if (!cellData) { - return false; - } - const doc = skeleton.getCellDocumentModelWithFormula(cellData); - if (!doc?.documentModel) { - return false; - } - const snapshot = doc.documentModel.getSnapshot(); + if (!cellData) return false; + const doc = worksheet.getCellDocumentModelWithFormula(cellData); + if (!doc?.documentModel) return false; + + const snapshot = doc.documentModel.getSnapshot(); const range = snapshot.body?.customRanges?.find((range) => range.rangeId === id); - if (!range) { - return false; - } + if (!range) return false; const newId = generateRandomId(); const oldBody = getBodySlice(doc.documentModel.getBody()!, range.startIndex, range.endIndex + 1); @@ -115,7 +100,7 @@ export const UpdateHyperLinkCommand: ICommand = { t: CellValueType.STRING, }; - const finalCellData = await editorBridgeService.beforeSetRangeValue(workbook, worksheet, row, column, newCellData); + const finalCellData = await interceptorService.onWriteCell(workbook, worksheet, row, column, newCellData); const redo = { id: SetRangeValuesMutation.id, diff --git a/packages/sheets-hyper-link/src/controllers/sheet-hyper-link.controller.ts b/packages/sheets-hyper-link/src/controllers/sheet-hyper-link.controller.ts index 45c728b95ad..8cfeda355c8 100644 --- a/packages/sheets-hyper-link/src/controllers/sheet-hyper-link.controller.ts +++ b/packages/sheets-hyper-link/src/controllers/sheet-hyper-link.controller.ts @@ -15,6 +15,9 @@ */ import { Disposable, ICommandService } from '@univerjs/core'; +import { AddHyperLinkCommand, AddRichHyperLinkCommand } from '../commands/commands/add-hyper-link.command'; +import { CancelHyperLinkCommand, CancelRichHyperLinkCommand } from '../commands/commands/remove-hyper-link.command'; +import { UpdateHyperLinkCommand, UpdateRichHyperLinkCommand } from '../commands/commands/update-hyper-link.command'; import { AddHyperLinkMutation } from '../commands/mutations/add-hyper-link.mutation'; import { RemoveHyperLinkMutation } from '../commands/mutations/remove-hyper-link.mutation'; import { UpdateHyperLinkMutation, UpdateHyperLinkRefMutation } from '../commands/mutations/update-hyper-link.mutation'; @@ -30,6 +33,12 @@ export class SheetsHyperLinkController extends Disposable { private _registerCommands() { [ + AddHyperLinkCommand, + UpdateHyperLinkCommand, + CancelHyperLinkCommand, + UpdateRichHyperLinkCommand, + CancelRichHyperLinkCommand, + AddRichHyperLinkCommand, AddHyperLinkMutation, UpdateHyperLinkMutation, RemoveHyperLinkMutation, diff --git a/packages/sheets-hyper-link/src/facade/f-range.ts b/packages/sheets-hyper-link/src/facade/f-range.ts new file mode 100644 index 00000000000..8d90831dfb5 --- /dev/null +++ b/packages/sheets-hyper-link/src/facade/f-range.ts @@ -0,0 +1,132 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IAddHyperLinkCommandParams } from '../commands/commands/add-hyper-link.command'; +import type { ICancelHyperLinkCommandParams } from '../commands/commands/remove-hyper-link.command'; +import type { IUpdateHyperLinkCommandParams } from '../commands/commands/update-hyper-link.command'; +import { CustomRangeType, generateRandomId } from '@univerjs/core'; +import { FRange } from '@univerjs/sheets/facade'; +import { AddHyperLinkCommand } from '../commands/commands/add-hyper-link.command'; +import { CancelHyperLinkCommand } from '../commands/commands/remove-hyper-link.command'; +import { UpdateHyperLinkCommand } from '../commands/commands/update-hyper-link.command'; + +export interface ICellHyperLink { + id: string; + startIndex: number; + endIndex: number; + url: string; + label: string; +} + +interface IFRangeHyperlinkMixin { + /** + * Get all hyperlinks in the cell in the range. + * @returns hyperlinks + */ + getHyperLinks(): ICellHyperLink[]; + /** + * Update hyperlink in the cell in the range. + * @param id id of the hyperlink + * @param url url + * @param label optional, label of the url + * @returns success or not + */ + updateHyperLink(id: string, url: string, label?: string): Promise; + /** + * Cancel hyperlink in the cell in the range. + * @param id id of the hyperlink + * @returns success or not + */ + cancelHyperLink(id: string): Promise; +} + +class FRangeHyperlinkMixin extends FRange implements IFRangeHyperlinkMixin { + // #region hyperlink + + setHyperLink(url: string, label?: string): Promise { + const params: IAddHyperLinkCommandParams = { + unitId: this.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + link: { + row: this._range.startRow, + column: this._range.startColumn, + payload: url, + display: label, + id: generateRandomId(), + }, + }; + + return this._commandService.executeCommand(AddHyperLinkCommand.id, params); + } + + override getHyperLinks(): ICellHyperLink[] { + const cellValue = this._worksheet.getCellRaw(this._range.startRow, this._range.startColumn); + if (!cellValue?.p) { + return []; + } + + return cellValue.p.body?.customRanges + ?.filter((range) => range.rangeType === CustomRangeType.HYPERLINK) + .map((range) => ({ + id: range.rangeId, + startIndex: range.startIndex, + endIndex: range.endIndex, + url: range.properties?.url ?? '', + label: cellValue.p?.body?.dataStream.slice(range.startIndex + 1, range.endIndex) ?? '', + })) ?? []; + } + + override updateHyperLink(id: string, url: string, label?: string): Promise { + const params: IUpdateHyperLinkCommandParams = { + unitId: this.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + row: this._range.startRow, + column: this._range.startColumn, + id, + payload: { + payload: url, + display: label, + }, + }; + + return this._commandService.executeCommand(UpdateHyperLinkCommand.id, params); + } + + /** + * Cancel hyperlink in the cell in the range. + * @param id id of the hyperlink + * @returns success or not + */ + override cancelHyperLink(id: string): Promise { + const params: ICancelHyperLinkCommandParams = { + unitId: this.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + row: this._range.startRow, + column: this._range.startColumn, + id, + }; + + return this._commandService.executeCommand(CancelHyperLinkCommand.id, params); + } + + // #endregion +} + +FRange.extend(FRangeHyperlinkMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FRange extends IFRangeHyperlinkMixin {} +} diff --git a/packages/sheets-hyper-link/src/facade/f-workbook.ts b/packages/sheets-hyper-link/src/facade/f-workbook.ts new file mode 100644 index 00000000000..f2f2cf8f471 --- /dev/null +++ b/packages/sheets-hyper-link/src/facade/f-workbook.ts @@ -0,0 +1,60 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IRange } from '@univerjs/core'; +import type { ISheetHyperLinkInfo } from '../services/parser.service'; +import { FWorkbook } from '@univerjs/sheets/facade'; +import { SheetsHyperLinkParserService } from '../services/parser.service'; + +interface IFWorkbookHyperlinkMixin { + /** + * create a hyperlink for the sheet + * @param sheetId the sheet id to link + * @param range the range to link, or define-name id + * @returns the hyperlink string + */ + createSheetHyperlink(this: FWorkbook, sheetId: string, range?: string | IRange): string; + /** + * parse the hyperlink string to get the hyperlink info + * @param hyperlink the hyperlink string + * @returns the hyperlink info + */ + // TODO@weird94: this should be moved to hyperlink plugin + parseSheetHyperlink(this: FWorkbook, hyperlink: string): ISheetHyperLinkInfo; +} + +export class FWorkbookHyperLinkMixin extends FWorkbook implements IFWorkbookHyperlinkMixin { + override createSheetHyperlink(sheetId: string, range?: string | IRange): string { + const parserService = this._injector.get(SheetsHyperLinkParserService); + return parserService.buildHyperLink(this.getId(), sheetId, range); + } + + /** + * parse the hyperlink string to get the hyperlink info + * @param hyperlink the hyperlink string + * @returns the hyperlink info + */ + override parseSheetHyperlink(hyperlink: string): ISheetHyperLinkInfo { + const resolverService = this._injector.get(SheetsHyperLinkParserService); + return resolverService.parseHyperLink(hyperlink); + } +} + +FWorkbook.extend(FWorkbookHyperLinkMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorkbook extends IFWorkbookHyperlinkMixin {} +} diff --git a/packages/sheets-hyper-link/src/facade/index.ts b/packages/sheets-hyper-link/src/facade/index.ts new file mode 100644 index 00000000000..43ce6d9d445 --- /dev/null +++ b/packages/sheets-hyper-link/src/facade/index.ts @@ -0,0 +1,20 @@ +/** + * 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 './f-workbook'; +import './f-range'; + +export { FWorkbookHyperLinkMixin } from './f-workbook'; diff --git a/packages/sheets-hyper-link/src/index.ts b/packages/sheets-hyper-link/src/index.ts index 547b4c1121c..72b48f49015 100644 --- a/packages/sheets-hyper-link/src/index.ts +++ b/packages/sheets-hyper-link/src/index.ts @@ -18,11 +18,14 @@ export { HyperLinkModel } from './models/hyper-link.model'; export { SheetHyperLinkType } from './types/enums/hyper-link-type'; export { UniverSheetsHyperLinkPlugin } from './plugin'; export type { ICellHyperLink, ICellLinkContent } from './types/interfaces/i-hyper-link'; - +export { type ISheetHyperLinkInfo, type ISheetUrlParams, SheetsHyperLinkParserService } from './services/parser.service'; export { ERROR_RANGE } from './types/const'; // #region - all commands +export { AddHyperLinkCommand, AddRichHyperLinkCommand, type IAddHyperLinkCommandParams, type IAddRichHyperLinkCommandParams } from './commands/commands/add-hyper-link.command'; +export { CancelHyperLinkCommand, CancelRichHyperLinkCommand, type ICancelHyperLinkCommandParams, type ICancelRichHyperLinkCommandParams } from './commands/commands/remove-hyper-link.command'; +export { type IUpdateHyperLinkCommandParams, type IUpdateRichHyperLinkCommandParams, UpdateHyperLinkCommand, UpdateRichHyperLinkCommand } from './commands/commands/update-hyper-link.command'; export { AddHyperLinkMutation, type IAddHyperLinkMutationParams } from './commands/mutations/add-hyper-link.mutation'; export { type IRemoveHyperLinkMutationParams, RemoveHyperLinkMutation } from './commands/mutations/remove-hyper-link.mutation'; export { @@ -33,4 +36,3 @@ export { } from './commands/mutations/update-hyper-link.mutation'; // #endregion - diff --git a/packages/sheets-hyper-link/src/plugin.ts b/packages/sheets-hyper-link/src/plugin.ts index cb518001538..42fdccbe2a7 100644 --- a/packages/sheets-hyper-link/src/plugin.ts +++ b/packages/sheets-hyper-link/src/plugin.ts @@ -14,15 +14,15 @@ * limitations under the License. */ -import type { Dependency } from '@univerjs/core'; import type { IUniverSheetsHyperLinkConfig } from './controllers/config.schema'; -import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, registerDependencies, touchDependencies, UniverInstanceType } from '@univerjs/core'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; import { SheetsHyperLinkRefRangeController } from './controllers/ref-range.controller'; import { SheetsHyperLinkController } from './controllers/sheet-hyper-link.controller'; import { SheetsHyperLinkResourceController } from './controllers/sheet-hyper-link-resource.controller'; import { HyperLinkModel } from './models/hyper-link.model'; +import { SheetsHyperLinkParserService } from './services/parser.service'; import { SHEET_HYPER_LINK_PLUGIN } from './types/const'; @DependentOn(UniverSheetsPlugin) @@ -43,17 +43,18 @@ export class UniverSheetsHyperLinkPlugin extends Plugin { } override onStarting(): void { - ([ + registerDependencies(this._injector, [ + [SheetsHyperLinkParserService], [SheetsHyperLinkResourceController], [SheetsHyperLinkController], [SheetsHyperLinkRefRangeController], [HyperLinkModel], - ] as Dependency[]).forEach((dep) => { - this._injector.add(dep); - }); + ]); - this._injector.get(SheetsHyperLinkRefRangeController); - this._injector.get(SheetsHyperLinkResourceController); - this._injector.get(SheetsHyperLinkController); + touchDependencies(this._injector, [ + [SheetsHyperLinkRefRangeController], + [SheetsHyperLinkResourceController], + [SheetsHyperLinkController], + ]); } } diff --git a/packages/sheets-hyper-link/src/services/parser.service.ts b/packages/sheets-hyper-link/src/services/parser.service.ts new file mode 100644 index 00000000000..79454ae8fe4 --- /dev/null +++ b/packages/sheets-hyper-link/src/services/parser.service.ts @@ -0,0 +1,128 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IRange, Nullable, Workbook } from '@univerjs/core'; +import { Inject, isValidRange, IUniverInstanceService, LocaleService, UniverInstanceType } from '@univerjs/core'; +import { deserializeRangeWithSheet, IDefinedNamesService, serializeRange, serializeRangeWithSheet } from '@univerjs/engine-formula'; +import { ERROR_RANGE } from '../types/const'; +import { SheetHyperLinkType } from '../types/enums/hyper-link-type'; + +export interface ISheetUrlParams { + gid?: string; + range?: string; + rangeid?: string; + unitid?: string; +} + +export interface ISheetHyperLinkInfo { + type: SheetHyperLinkType; + name: string; + url: string; + searchObj: Nullable; +} + +export class SheetsHyperLinkParserService { + constructor( + @IUniverInstanceService private _univerInstanceService: IUniverInstanceService, + @Inject(LocaleService) private _localeService: LocaleService, + @IDefinedNamesService private _definedNamesService: IDefinedNamesService + ) {} + + buildHyperLink(unitId: string, sheetId: string, range?: string | IRange): string { + return `#${SheetHyperLinkType.SHEET}=${sheetId}${range ? `&${typeof range === 'string' ? SheetHyperLinkType.DEFINE_NAME : SheetHyperLinkType.RANGE}=${typeof range === 'string' ? range : serializeRange(range)}` : ''}`; + } + + parseHyperLink(urlStr: string): ISheetHyperLinkInfo { + if (urlStr.startsWith('#')) { + const search = new URLSearchParams(urlStr.slice(1)); + const searchObj: ISheetUrlParams = { + gid: search.get('gid') ?? '', + range: search.get('range') ?? '', + rangeid: search.get('rangeid') ?? '', + unitid: search.get('unitid') ?? '', + }; + const urlInfo = this._getURLName(searchObj); + + return { + type: urlInfo.type, + name: urlInfo.name, + url: urlStr, + searchObj, + }; + } else { + return { + type: SheetHyperLinkType.URL, + name: urlStr, + url: urlStr, + searchObj: null, + }; + } + } + + private _getURLName(params: ISheetUrlParams) { + const { gid, range, rangeid, unitid } = params; + const workbook = unitid ? + this._univerInstanceService.getUnit(unitid, UniverInstanceType.UNIVER_SHEET) + : this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); + const invalidLink = { + type: SheetHyperLinkType.INVALID, + name: this._localeService.t('hyperLink.message.refError'), + }; + + if (!workbook) { + return invalidLink; + } + + const sheet = gid ? workbook.getSheetBySheetId(gid) : workbook.getActiveSheet(); + const sheetName = sheet?.getName() ?? ''; + + if (range) { + if (!sheet) return invalidLink; + const rangeObj = deserializeRangeWithSheet(range).range; + if (isValidRange(rangeObj, sheet) && range !== ERROR_RANGE) { + return { + type: SheetHyperLinkType.RANGE, + name: serializeRangeWithSheet(sheetName, rangeObj), + }; + } + return invalidLink; + } + + if (rangeid) { + const range = this._definedNamesService.getValueById(workbook.getUnitId(), rangeid); + if (range) { + return { + type: SheetHyperLinkType.DEFINE_NAME, + name: range.formulaOrRefString, + }; + } + return invalidLink; + } + + if (gid) { + const worksheet = workbook.getSheetBySheetId(gid); + if (worksheet) { + return { + type: SheetHyperLinkType.SHEET, + name: worksheet.getName(), + }; + } + return invalidLink; + } + + return invalidLink; + } +} diff --git a/packages/sheets-numfmt-ui/README.md b/packages/sheets-numfmt-ui/README.md new file mode 100644 index 00000000000..3c255321eda --- /dev/null +++ b/packages/sheets-numfmt-ui/README.md @@ -0,0 +1,58 @@ +# @univerjs/sheets-numfmt-ui +sheets-numfmt + +## Package Overview + +| Package Name | UMD Namespace | Version | License | Downloads | Contains CSS | Contains i18n locales | +| --- | --- | --- | --- | --- | :---: | :---: | +| `@univerjs/sheets-numfmt-ui` | `UniverSheetsNumfmtUI` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ⭕️ | ⭕️ | + +## Introduction + +Providing editing/rendering capabilities around `number format`, such as edit panels, toolbar buttons, real-time previews, row/column variations, etc. + +> [!NOTE] +> Numerical format is one of the core functions of electronic spreadsheets, and therefore, parsing and handling of numerical format is done within `@univerjs/sheets`. + +## Usage + +### Installation + +```shell +# Using npm +npm install @univerjs/sheets-numfmt-ui + +# Using pnpm +pnpm add @univerjs/sheets-numfmt-ui +``` + +### How to use + +Import `@univerjs/sheets-numfmt-ui` at the entrance . + +```typescript +import { LocaleType, LogLevel, Univer } from '@univerjs/core'; +import { defaultTheme } from '@univerjs/design'; +import { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui'; + +// univer +const univer = new Univer({ + theme: defaultTheme, + locale: LocaleType.EN_US, + locales, + logLevel: LogLevel.VERBOSE, +}); + +// ... Other plug-ins are registered + +univer.registerPlugin(UniverSheetsNumfmtUIPlugin); +``` + +> [!NOTE] +> If you need to export the snapshot to support the export data format, you need to add [some additional code](/) + + +[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-numfmt-ui?style=flat-square +[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-numfmt-ui +[npm-license-shield]: https://img.shields.io/npm/l/@univerjs/sheets-numfmt-ui?style=flat-square +[npm-downloads-shield]: https://img.shields.io/npm/dm/@univerjs/sheets-numfmt-ui?style=flat-square diff --git a/packages/sheets-thread-comment-base/package.json b/packages/sheets-numfmt-ui/package.json similarity index 76% rename from packages/sheets-thread-comment-base/package.json rename to packages/sheets-numfmt-ui/package.json index 71a5a2bb216..56475836617 100644 --- a/packages/sheets-thread-comment-base/package.json +++ b/packages/sheets-numfmt-ui/package.json @@ -1,8 +1,8 @@ { - "name": "@univerjs/sheets-thread-comment-base", + "name": "@univerjs/sheets-numfmt-ui", "version": "0.4.2", "private": false, - "description": "Univer sheets thread comment base plugin", + "description": "UniverSheet numfmt plugin", "author": "DreamNum ", "license": "Apache-2.0", "funding": { @@ -17,10 +17,13 @@ "bugs": { "url": "https://github.com/dream-num/univer/issues" }, - "keywords": [], + "keywords": [ + "univer" + ], "exports": { ".": "./src/index.ts", - "./*": "./src/*" + "./*": "./src/*", + "./locale/*": "./src/locale/*.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", @@ -40,7 +43,8 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*" + "./lib/*": "./lib/*", + "./locale/*": "./lib/locale/*.json" } }, "directories": { @@ -57,18 +61,25 @@ "build": "tsc && vite build" }, "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18.0.0", "rxjs": ">=7.0.0" }, "dependencies": { "@univerjs/core": "workspace:*", "@univerjs/design": "workspace:*", "@univerjs/engine-formula": "workspace:*", + "@univerjs/engine-numfmt": "workspace:*", + "@univerjs/engine-render": "workspace:*", + "@univerjs/icons": "^0.1.79", "@univerjs/sheets": "workspace:*", - "@univerjs/thread-comment": "workspace:*", + "@univerjs/sheets-numfmt": "workspace:*", + "@univerjs/sheets-ui": "workspace:*", "@univerjs/ui": "workspace:*" }, "devDependencies": { + "@types/react": "^18.3.11", "@univerjs-infra/shared": "workspace:*", + "less": "^4.2.0", "react": "18.3.1", "rxjs": "^7.8.1", "typescript": "^5.6.3", @@ -86,6 +97,7 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*" + "./lib/*": "./lib/*", + "./locale/*": "./lib/locale/*.json" } } diff --git a/packages/sheets-numfmt/src/controllers/__tests__/cell-content.controller.spec.ts b/packages/sheets-numfmt-ui/src/controllers/__tests__/cell-content.controller.spec.ts similarity index 96% rename from packages/sheets-numfmt/src/controllers/__tests__/cell-content.controller.spec.ts rename to packages/sheets-numfmt-ui/src/controllers/__tests__/cell-content.controller.spec.ts index 70ecae49df4..339ef71937c 100644 --- a/packages/sheets-numfmt/src/controllers/__tests__/cell-content.controller.spec.ts +++ b/packages/sheets-numfmt-ui/src/controllers/__tests__/cell-content.controller.spec.ts @@ -15,12 +15,12 @@ */ import type { Workbook } from '@univerjs/core'; -import { ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import type { ISetNumfmtMutationParams } from '@univerjs/sheets'; +import { ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { SetNumfmtMutation } from '@univerjs/sheets'; -import { beforeEach, describe, expect, it } from 'vitest'; +import { SheetsNumfmtCellContentController } from '@univerjs/sheets-numfmt/controllers/numfmt-cell-content.controller.js'; -import { SheetsNumfmtCellContentController } from '../numfmt.cell-content.controller'; +import { beforeEach, describe, expect, it } from 'vitest'; import { createTestBed } from './test.util'; describe('test cell-content', () => { diff --git a/packages/sheets-numfmt/src/controllers/__tests__/editor.controller.spec.ts b/packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts similarity index 84% rename from packages/sheets-numfmt/src/controllers/__tests__/editor.controller.spec.ts rename to packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts index 315d26b363d..0f8ac1932a1 100644 --- a/packages/sheets-numfmt/src/controllers/__tests__/editor.controller.spec.ts +++ b/packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts @@ -14,25 +14,27 @@ * limitations under the License. */ -import { createInterceptorKey, ICommandService, InterceptorManager, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; -import { SetNumfmtMutation } from '@univerjs/sheets'; -import { IEditorBridgeService } from '@univerjs/sheets-ui'; -import { beforeEach, describe, expect, it } from 'vitest'; import type { ICellDataForSheetInterceptor, Workbook, Worksheet } from '@univerjs/core'; import type { ISetNumfmtMutationParams, ISheetLocation } from '@univerjs/sheets'; +import { createInterceptorKey, ICommandService, InterceptorManager, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { SetNumfmtMutation, SheetInterceptorService } from '@univerjs/sheets'; -import { SheetsNumfmtCellContentController } from '../numfmt.cell-content.controller'; +import { SheetsNumfmtCellContentController } from '@univerjs/sheets-numfmt'; +import { IEditorBridgeService } from '@univerjs/sheets-ui'; +import { beforeEach, describe, expect, it } from 'vitest'; import { NumfmtEditorController } from '../numfmt.editor.controller'; import { createTestBed } from './test.util'; const BEFORE_CELL_EDIT = createInterceptorKey('BEFORE_CELL_EDIT'); const AFTER_CELL_EDIT = createInterceptorKey('AFTER_CELL_EDIT'); + class MockEditorBridgeService { interceptor = new InterceptorManager({ BEFORE_CELL_EDIT, AFTER_CELL_EDIT, }); } + describe('test editor', () => { let unitId: string = ''; let subUnitId: string = ''; @@ -47,6 +49,7 @@ describe('test editor', () => { [SheetsNumfmtCellContentController], [IEditorBridgeService, { useClass: MockEditorBridgeService }], ]); + unitId = testBed.unitId; subUnitId = testBed.subUnitId; commandService = testBed.get(ICommandService); @@ -73,7 +76,7 @@ describe('test editor', () => { }, }; commandService.syncExecuteCommand(SetNumfmtMutation.id, params); - const editorBridgeService = testBed.get(IEditorBridgeService); + const sheetInterceptorService = testBed.get(SheetInterceptorService); const cellData = worksheet.getCell(0, 0); const location = { workbook, @@ -88,9 +91,7 @@ describe('test editor', () => { expect(cellData!.v).toEqual('$0'); expect(cellData!.t).toEqual(2); - const result = editorBridgeService.interceptor.fetchThroughInterceptors( - editorBridgeService.interceptor.getInterceptPoints().BEFORE_CELL_EDIT - )(cellData, location); + const result = sheetInterceptorService.writeCellInterceptor.fetchThroughInterceptors(BEFORE_CELL_EDIT)(cellData, location); // The currency format needs to be entered in the editor with real values, not with currency symbols expect(result!.v).toEqual(0); expect(result!.t).toEqual(2); @@ -111,7 +112,7 @@ describe('test editor', () => { }, }; commandService.syncExecuteCommand(SetNumfmtMutation.id, params); - const editorBridgeService = testBed.get(IEditorBridgeService); + const sheetInterceptorService = testBed.get(SheetInterceptorService); const cellData = worksheet.getCell(0, 0); const location = { workbook, @@ -123,9 +124,7 @@ describe('test editor', () => { origin: cellData, }; - const result = editorBridgeService.interceptor.fetchThroughInterceptors( - editorBridgeService.interceptor.getInterceptPoints().BEFORE_CELL_EDIT - )(cellData, location); + const result = sheetInterceptorService.writeCellInterceptor.fetchThroughInterceptors(BEFORE_CELL_EDIT)(cellData, location); // The data format needs to be entered in the editor with data string, not with real values expect(result!.v).toEqual(cellData!.v); }); @@ -145,7 +144,7 @@ describe('test editor', () => { }, }; commandService.syncExecuteCommand(SetNumfmtMutation.id, params); - const editorBridgeService = testBed.get(IEditorBridgeService); + const sheetInterceptorService = testBed.get(SheetInterceptorService); const cellData = { v: '12:33:22', t: 2 }; const location = { workbook, @@ -157,9 +156,7 @@ describe('test editor', () => { origin: cellData, }; - const result = editorBridgeService.interceptor.fetchThroughInterceptors( - editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT - )(cellData, location); + const result = sheetInterceptorService.writeCellInterceptor.fetchThroughInterceptors(AFTER_CELL_EDIT)(cellData, location); // The date-time drop is a numeric value, not a literal string expect(result?.v).toBe(0.5231712962962963); }); diff --git a/packages/sheets-numfmt/src/controllers/__tests__/test.util.ts b/packages/sheets-numfmt-ui/src/controllers/__tests__/test.util.ts similarity index 100% rename from packages/sheets-numfmt/src/controllers/__tests__/test.util.ts rename to packages/sheets-numfmt-ui/src/controllers/__tests__/test.util.ts diff --git a/packages/sheets-numfmt/src/controllers/config.schema.ts b/packages/sheets-numfmt-ui/src/controllers/config.schema.ts similarity index 87% rename from packages/sheets-numfmt/src/controllers/config.schema.ts rename to packages/sheets-numfmt-ui/src/controllers/config.schema.ts index a8145359a5e..013c7c89a2c 100644 --- a/packages/sheets-numfmt/src/controllers/config.schema.ts +++ b/packages/sheets-numfmt-ui/src/controllers/config.schema.ts @@ -20,8 +20,8 @@ export const PLUGIN_CONFIG_KEY = 'sheets-numfmt.config'; export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); -export interface IUniverSheetsNumfmtConfig { +export interface IUniverSheetsNumfmtUIConfig { menu?: MenuConfig; } -export const defaultPluginConfig: IUniverSheetsNumfmtConfig = {}; +export const defaultPluginConfig: IUniverSheetsNumfmtUIConfig = {}; diff --git a/packages/sheets-numfmt/src/controllers/menu.schema.ts b/packages/sheets-numfmt-ui/src/controllers/menu.schema.ts similarity index 75% rename from packages/sheets-numfmt/src/controllers/menu.schema.ts rename to packages/sheets-numfmt-ui/src/controllers/menu.schema.ts index 8cbc0b84929..302c0bb31d9 100644 --- a/packages/sheets-numfmt/src/controllers/menu.schema.ts +++ b/packages/sheets-numfmt-ui/src/controllers/menu.schema.ts @@ -15,13 +15,9 @@ */ import type { MenuSchemaType } from '@univerjs/ui'; +import { AddDecimalCommand, OpenNumfmtPanelOperator, SetCurrencyCommand, SetPercentCommand, SubtractDecimalCommand } from '@univerjs/sheets-numfmt'; import { RibbonStartGroup } from '@univerjs/ui'; -import { SetCurrencyCommand } from '../commands/commands/set-currency.command'; -import { AddDecimalMenuItem, CurrencyMenuItem, FactoryOtherMenuItem, PercentMenuItem, SubtractDecimalMenuItem } from '../menu/menu'; -import { SubtractDecimalCommand } from '../commands/commands/subtract-decimal.command'; -import { SetPercentCommand } from '../commands/commands/set-percent.command'; -import { OpenNumfmtPanelOperator } from '../commands/operations/open.numfmt.panel.operation'; -import { AddDecimalCommand } from '../commands/commands/add-decimal.command'; +import { AddDecimalMenuItem, CurrencyMenuItem, FactoryOtherMenuItem, PercentMenuItem, SubtractDecimalMenuItem } from './menu'; export const menuSchema: MenuSchemaType = { [RibbonStartGroup.FORMULAS_INSERT]: { diff --git a/packages/sheets-numfmt/src/menu/menu.ts b/packages/sheets-numfmt-ui/src/controllers/menu.ts similarity index 82% rename from packages/sheets-numfmt/src/menu/menu.ts rename to packages/sheets-numfmt-ui/src/controllers/menu.ts index 85b62ffcfd8..5df38a5f3f4 100644 --- a/packages/sheets-numfmt/src/menu/menu.ts +++ b/packages/sheets-numfmt-ui/src/controllers/menu.ts @@ -14,7 +14,10 @@ * limitations under the License. */ +import type { IAccessor } from '@univerjs/core'; +import type { IMenuSelectorItem } from '@univerjs/ui'; import { ICommandService, IUniverInstanceService, LocaleService, UniverInstanceType } from '@univerjs/core'; +import { DEFAULT_TEXT_FORMAT } from '@univerjs/engine-numfmt'; import { RangeProtectionPermissionEditPoint, RemoveNumfmtMutation, @@ -24,22 +27,66 @@ import { WorksheetEditPermission, WorksheetSetCellStylePermission, } from '@univerjs/sheets'; -import type { IMenuSelectorItem } from '@univerjs/ui'; +import { AddDecimalCommand, countryCurrencyMap, isPatternEqualWithoutDecimal, MenuCurrencyService, OpenNumfmtPanelOperator, SetCurrencyCommand, SetPercentCommand, SubtractDecimalCommand } from '@univerjs/sheets-numfmt'; +import { deriveStateFromActiveSheet$, getCurrentRangeDisable$ } from '@univerjs/sheets-ui'; import { getMenuHiddenObservable, MenuItemType } from '@univerjs/ui'; -import type { IAccessor } from '@univerjs/core'; import { merge, Observable } from 'rxjs'; -import { deriveStateFromActiveSheet$, getCurrentRangeDisable$ } from '@univerjs/sheets-ui'; -import { countryCurrencyMap } from '../base/const/CURRENCY-SYMBOLS'; +import { MORE_NUMFMT_TYPE_KEY, OPTIONS_KEY } from '../views/components/more-numfmt-type/MoreNumfmtType'; -import { MENU_OPTIONS } from '../base/const/MENU-OPTIONS'; -import { AddDecimalCommand } from '../commands/commands/add-decimal.command'; -import { SetCurrencyCommand } from '../commands/commands/set-currency.command'; -import { SubtractDecimalCommand } from '../commands/commands/subtract-decimal.command'; -import { OpenNumfmtPanelOperator } from '../commands/operations/open.numfmt.panel.operation'; -import { MORE_NUMFMT_TYPE_KEY, OPTIONS_KEY } from '../components/more-numfmt-type/MoreNumfmtType'; -import { isPatternEqualWithoutDecimal } from '../utils/decimal'; -import { SetPercentCommand } from '../commands/commands/set-percent.command'; -import { MenuCurrencyService } from '../service/menu.currency.service'; +export const MENU_OPTIONS: Array<{ label: string; pattern: string | null } | '|'> = [ + { + label: 'sheet.numfmt.general', + pattern: null, + }, + { + label: 'sheet.numfmt.text', + pattern: DEFAULT_TEXT_FORMAT, + }, + '|', + { + label: 'sheet.numfmt.number', + pattern: '0', + }, + '|', + { + label: 'sheet.numfmt.accounting', + pattern: '"¥" #,##0.00_);[Red]("¥"#,##0.00)', + }, + { + label: 'sheet.numfmt.financialValue', + pattern: '#,##0.00;[Red]#,##0.00', + }, + { + label: 'sheet.numfmt.currency', + pattern: '"¥"#,##0.00_);[Red]("¥"#,##0.00)', + }, + { + label: 'sheet.numfmt.roundingCurrency', + pattern: '"¥"#,##0;[Red]"¥"#,##0', + }, + '|', + { + label: 'sheet.numfmt.date', + pattern: 'yyyy-mm-dd;@', + }, + { + label: 'sheet.numfmt.time', + pattern: 'am/pm h":"mm":"ss', + }, + { + label: 'sheet.numfmt.dateTime', + pattern: 'yyyy-m-d am/pm h:mm', + }, + { + label: 'sheet.numfmt.timeDuration', + pattern: 'h:mm:ss', + }, + '|', + { + label: 'sheet.numfmt.moreFmt', + pattern: '', + }, +]; export const CurrencyMenuItem = (accessor: IAccessor) => { return { diff --git a/packages/sheets-numfmt/src/controllers/numfmt.controller.ts b/packages/sheets-numfmt-ui/src/controllers/numfmt.controller.ts similarity index 90% rename from packages/sheets-numfmt/src/controllers/numfmt.controller.ts rename to packages/sheets-numfmt-ui/src/controllers/numfmt.controller.ts index d0598d4668e..ac806c6e20c 100644 --- a/packages/sheets-numfmt/src/controllers/numfmt.controller.ts +++ b/packages/sheets-numfmt-ui/src/controllers/numfmt.controller.ts @@ -16,9 +16,8 @@ import type { IDisposable, IRange, Workbook } from '@univerjs/core'; import type { ISetNumfmtMutationParams } from '@univerjs/sheets'; -import type { ISetNumfmtCommandParams } from '../commands/commands/set-numfmt.command'; -import type { ISheetNumfmtPanelProps } from '../components/index'; -import type { INumfmtController } from './type'; +import type { ISetNumfmtCommandParams } from '@univerjs/sheets-numfmt'; +import type { ISheetNumfmtPanelProps } from '../views/components'; import { CellValueType, Disposable, @@ -33,6 +32,7 @@ import { toDisposable, UniverInstanceType, } from '@univerjs/core'; + import { IRenderManagerService } from '@univerjs/engine-render'; import { INTERCEPTOR_POINT, @@ -42,23 +42,16 @@ import { SheetInterceptorService, SheetsSelectionsService, } from '@univerjs/sheets'; - +import { CloseNumfmtPanelOperator, getPatternPreviewIgnoreGeneral, getPatternType, OpenNumfmtPanelOperator, SetNumfmtCommand } from '@univerjs/sheets-numfmt'; import { SheetSkeletonManagerService } from '@univerjs/sheets-ui'; import { ComponentManager, ISidebarService } from '@univerjs/ui'; import { combineLatest, Observable } from 'rxjs'; import { debounceTime, map, switchMap, tap } from 'rxjs/operators'; -import { SHEET_NUMFMT_PLUGIN } from '../base/const/PLUGIN_NAME'; -import { AddDecimalCommand } from '../commands/commands/add-decimal.command'; -import { SetCurrencyCommand } from '../commands/commands/set-currency.command'; -import { SetNumfmtCommand } from '../commands/commands/set-numfmt.command'; -import { SetPercentCommand } from '../commands/commands/set-percent.command'; -import { SubtractDecimalCommand } from '../commands/commands/subtract-decimal.command'; -import { CloseNumfmtPanelOperator } from '../commands/operations/close.numfmt.panel.operation'; -import { OpenNumfmtPanelOperator } from '../commands/operations/open.numfmt.panel.operation'; -import { SheetNumfmtPanel } from '../components/index'; -import { getPatternPreviewIgnoreGeneral, getPatternType } from '../utils/pattern'; +import { SheetNumfmtPanel } from '../views/components'; + +const SHEET_NUMFMT_PANEL = 'SHEET_NUMFMT_PANEL'; -export class NumfmtController extends Disposable implements INumfmtController { +export class SheetNumfmtUIController extends Disposable { /** * If _previewPattern is null ,the realTimeRenderingInterceptor will skip and if it is '',realTimeRenderingInterceptor will clear numfmt. * @private @@ -153,7 +146,7 @@ export class NumfmtController extends Disposable implements INumfmtController { this._sidebarDisposable = sidebarService.open({ header: { title: localeService.t('sheet.numfmt.title') }, children: { - label: SHEET_NUMFMT_PLUGIN, + label: SHEET_NUMFMT_PANEL, ...(props as any), // need passthrough to react props. }, onClose: () => { @@ -176,20 +169,15 @@ export class NumfmtController extends Disposable implements INumfmtController { private _initCommands() { [ - AddDecimalCommand, - SubtractDecimalCommand, - SetCurrencyCommand, - SetPercentCommand, OpenNumfmtPanelOperator, CloseNumfmtPanelOperator, - SetNumfmtCommand, ].forEach((config) => { this.disposeWithMe(this._commandService.registerCommand(config)); }); } private _initPanel() { - this._componentManager.register(SHEET_NUMFMT_PLUGIN, SheetNumfmtPanel); + this._componentManager.register(SHEET_NUMFMT_PANEL, SheetNumfmtPanel); } private _initRealTimeRenderingInterceptor() { diff --git a/packages/sheets-numfmt/src/controllers/numfmt.editor.controller.ts b/packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts similarity index 96% rename from packages/sheets-numfmt/src/controllers/numfmt.editor.controller.ts rename to packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts index 94d83a685c8..7c034609a37 100644 --- a/packages/sheets-numfmt/src/controllers/numfmt.editor.controller.ts +++ b/packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts @@ -34,6 +34,8 @@ import { } from '@univerjs/core'; import { DEFAULT_TEXT_FORMAT } from '@univerjs/engine-numfmt'; import { + AFTER_CELL_EDIT, + BEFORE_CELL_EDIT, factoryRemoveNumfmtUndoMutation, factorySetNumfmtUndoMutation, INumfmtService, @@ -44,8 +46,8 @@ import { transformCellsToRange, } from '@univerjs/sheets'; +import { getPatternType } from '@univerjs/sheets-numfmt'; import { IEditorBridgeService } from '@univerjs/sheets-ui'; -import { getPatternType } from '../utils/pattern'; const createCollectEffectMutation = () => { interface IConfig { @@ -93,8 +95,7 @@ export class NumfmtEditorController extends Disposable { this.disposeWithMe( toDisposable( - this._editorBridgeService.interceptor.intercept( - this._editorBridgeService.interceptor.getInterceptPoints().BEFORE_CELL_EDIT, + this._sheetInterceptorService.writeCellInterceptor.intercept(BEFORE_CELL_EDIT, { handler: (value, context, next) => { const row = context.row; @@ -139,14 +140,9 @@ export class NumfmtEditorController extends Disposable { */ private _initInterceptorEditorEnd() { - if (!this._editorBridgeService) { - return; - } - this.disposeWithMe( toDisposable( - this._editorBridgeService.interceptor.intercept( - this._editorBridgeService.interceptor.getInterceptPoints().AFTER_CELL_EDIT, + this._sheetInterceptorService.writeCellInterceptor.intercept(AFTER_CELL_EDIT, { handler: (value, context, next) => { // clear the effect diff --git a/packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts b/packages/sheets-numfmt-ui/src/controllers/numfmt.menu.controller.ts similarity index 95% rename from packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts rename to packages/sheets-numfmt-ui/src/controllers/numfmt.menu.controller.ts index f0dc57e11af..4b3bed51509 100644 --- a/packages/sheets-numfmt/src/controllers/numfmt.menu.controller.ts +++ b/packages/sheets-numfmt-ui/src/controllers/numfmt.menu.controller.ts @@ -17,7 +17,7 @@ import { Disposable, Inject } from '@univerjs/core'; import { ComponentManager, IMenuManagerService } from '@univerjs/ui'; -import { MORE_NUMFMT_TYPE_KEY, MoreNumfmtType, Options, OPTIONS_KEY } from '../components/more-numfmt-type/MoreNumfmtType'; +import { MORE_NUMFMT_TYPE_KEY, MoreNumfmtType, Options, OPTIONS_KEY } from '../views/components/more-numfmt-type/MoreNumfmtType'; import { menuSchema } from './menu.schema'; export class NumfmtMenuController extends Disposable { diff --git a/packages/sheets-numfmt/src/controllers/user-habit.controller.ts b/packages/sheets-numfmt-ui/src/controllers/user-habit.controller.ts similarity index 96% rename from packages/sheets-numfmt/src/controllers/user-habit.controller.ts rename to packages/sheets-numfmt-ui/src/controllers/user-habit.controller.ts index ed0184ea5b4..e20ac6e99ff 100644 --- a/packages/sheets-numfmt/src/controllers/user-habit.controller.ts +++ b/packages/sheets-numfmt-ui/src/controllers/user-habit.controller.ts @@ -15,6 +15,7 @@ */ import { ILocalStorageService, Inject } from '@univerjs/core'; +import { createContext } from 'react'; type HabitValue = string | number; interface IUserHabitController { @@ -24,6 +25,8 @@ interface IUserHabitController { getHabit(habit: string, sortList?: HabitValue[]): Promise; } +export const UserHabitCurrencyContext = createContext([]); + export class UserHabitController implements IUserHabitController { constructor(@Inject(ILocalStorageService) private _localStorageService: ILocalStorageService) { // super diff --git a/packages/sheets-numfmt-ui/src/index.ts b/packages/sheets-numfmt-ui/src/index.ts new file mode 100644 index 00000000000..02036f06f77 --- /dev/null +++ b/packages/sheets-numfmt-ui/src/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { UniverSheetsNumfmtUIPlugin } from './plugin'; diff --git a/packages/sheets-numfmt/src/locale/en-US.ts b/packages/sheets-numfmt-ui/src/locale/en-US.ts similarity index 100% rename from packages/sheets-numfmt/src/locale/en-US.ts rename to packages/sheets-numfmt-ui/src/locale/en-US.ts diff --git a/packages/sheets-numfmt/src/locale/fa-IR.ts b/packages/sheets-numfmt-ui/src/locale/fa-IR.ts similarity index 100% rename from packages/sheets-numfmt/src/locale/fa-IR.ts rename to packages/sheets-numfmt-ui/src/locale/fa-IR.ts diff --git a/packages/sheets-numfmt/src/locale/ru-RU.ts b/packages/sheets-numfmt-ui/src/locale/ru-RU.ts similarity index 100% rename from packages/sheets-numfmt/src/locale/ru-RU.ts rename to packages/sheets-numfmt-ui/src/locale/ru-RU.ts diff --git a/packages/sheets-numfmt/src/locale/vi-VN.ts b/packages/sheets-numfmt-ui/src/locale/vi-VN.ts similarity index 100% rename from packages/sheets-numfmt/src/locale/vi-VN.ts rename to packages/sheets-numfmt-ui/src/locale/vi-VN.ts diff --git a/packages/sheets-numfmt/src/locale/zh-CN.ts b/packages/sheets-numfmt-ui/src/locale/zh-CN.ts similarity index 100% rename from packages/sheets-numfmt/src/locale/zh-CN.ts rename to packages/sheets-numfmt-ui/src/locale/zh-CN.ts diff --git a/packages/sheets-numfmt/src/locale/zh-TW.ts b/packages/sheets-numfmt-ui/src/locale/zh-TW.ts similarity index 100% rename from packages/sheets-numfmt/src/locale/zh-TW.ts rename to packages/sheets-numfmt-ui/src/locale/zh-TW.ts diff --git a/packages/sheets-numfmt-ui/src/plugin.ts b/packages/sheets-numfmt-ui/src/plugin.ts new file mode 100644 index 00000000000..a19b6e1168c --- /dev/null +++ b/packages/sheets-numfmt-ui/src/plugin.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IUniverSheetsNumfmtUIConfig } from './controllers/config.schema'; +import { DependentOn, IConfigService, Inject, Injector, Plugin, registerDependencies, touchDependencies, UniverInstanceType } from '@univerjs/core'; +import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; +import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; +import { PLUGIN_CONFIG_KEY } from '@univerjs/ui'; +import { defaultPluginConfig } from './controllers/config.schema'; +import { SheetNumfmtUIController } from './controllers/numfmt.controller'; +import { NumfmtEditorController } from './controllers/numfmt.editor.controller'; +import { NumfmtMenuController } from './controllers/numfmt.menu.controller'; +import { UserHabitController } from './controllers/user-habit.controller'; + +export const SHEET_NUMFMT_UI_PLUGIN = 'SHEET_NUMFMT_UI_PLUGIN'; + +@DependentOn(UniverSheetsUIPlugin, UniverSheetsNumfmtPlugin) +export class UniverSheetsNumfmtUIPlugin extends Plugin { + static override pluginName = SHEET_NUMFMT_UI_PLUGIN; + static override type = UniverInstanceType.UNIVER_SHEET; + + constructor( + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) override readonly _injector: Injector, + @IConfigService private readonly _configService: IConfigService + ) { + super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + } + + override onStarting(): void { + registerDependencies(this._injector, [ + [SheetNumfmtUIController], + [NumfmtEditorController], + [UserHabitController], + [NumfmtMenuController], + ]); + } + + override onRendered(): void { + touchDependencies(this._injector, [ + [SheetNumfmtUIController], + [NumfmtEditorController], + [NumfmtMenuController], + ]); + } +} diff --git a/packages/sheets-numfmt/src/components/accounting/index.tsx b/packages/sheets-numfmt-ui/src/views/components/accounting/index.tsx similarity index 76% rename from packages/sheets-numfmt/src/components/accounting/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/accounting/index.tsx index 47a7f466677..38def71a213 100644 --- a/packages/sheets-numfmt/src/components/accounting/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/accounting/index.tsx @@ -14,15 +14,13 @@ * limitations under the License. */ +import type { FC } from 'react'; +import type { IBusinessComponentProps } from '../interface'; import { LocaleService, useDependency } from '@univerjs/core'; import { InputNumber, Select } from '@univerjs/design'; -import type { FC } from 'react'; +import { getCurrencyType, getDecimalFromPattern, setPatternDecimal } from '@univerjs/sheets-numfmt'; import React, { useContext, useMemo, useState } from 'react'; - -import type { IBusinessComponentProps } from '../../base/types'; -import { UserHabitCurrencyContext } from '../../context/user-habit'; -import { getCurrencyType } from '../../utils/currency'; -import { getDecimalFromPattern, setPatternDecimal } from '../../utils/decimal'; +import { UserHabitCurrencyContext } from '../../../controllers/user-habit.controller'; export const isAccountingPanel = (pattern: string) => { const type = getCurrencyType(pattern); @@ -30,25 +28,27 @@ export const isAccountingPanel = (pattern: string) => { }; export const AccountingPanel: FC = (props) => { - const [decimal, decimalSet] = useState(() => getDecimalFromPattern(props.defaultPattern || '', 2)); + const { defaultPattern, action, onChange } = props; + + const [decimal, decimalSet] = useState(() => getDecimalFromPattern(defaultPattern || '', 2)); const userHabitCurrency = useContext(UserHabitCurrencyContext); - const [suffix, suffixSet] = useState(() => getCurrencyType(props.defaultPattern) || userHabitCurrency[0]); + const [suffix, suffixSet] = useState(() => getCurrencyType(defaultPattern) || userHabitCurrency[0]); const options = useMemo(() => userHabitCurrency.map((key) => ({ label: key, value: key })), []); const localeService = useDependency(LocaleService); const t = localeService.t; - props.action.current = () => setPatternDecimal(`_("${suffix}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal); + action.current = () => setPatternDecimal(`_("${suffix}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal); const onSelect = (v: string) => { suffixSet(v); - props.onChange(setPatternDecimal(`_("${v}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal)); + onChange(setPatternDecimal(`_("${v}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal)); }; const onDecimalChange = (v: number | null) => { const decimal = v || 0; decimalSet(decimal); - props.onChange(setPatternDecimal(`_("${suffix}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal)); + onChange(setPatternDecimal(`_("${suffix}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal)); }; return ( diff --git a/packages/sheets-numfmt/src/components/currency/index.less b/packages/sheets-numfmt-ui/src/views/components/currency/index.less similarity index 100% rename from packages/sheets-numfmt/src/components/currency/index.less rename to packages/sheets-numfmt-ui/src/views/components/currency/index.less diff --git a/packages/sheets-numfmt/src/components/currency/index.tsx b/packages/sheets-numfmt-ui/src/views/components/currency/index.tsx similarity index 91% rename from packages/sheets-numfmt/src/components/currency/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/currency/index.tsx index cf6ecf28aa6..e1c8db24227 100644 --- a/packages/sheets-numfmt/src/components/currency/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/currency/index.tsx @@ -14,19 +14,16 @@ * limitations under the License. */ -// FIXME: DO NOT USE GLOBAL STYLES -import './index.less'; - +import type { FC } from 'react'; +import type { IBusinessComponentProps } from '../interface'; import { LocaleService, useDependency } from '@univerjs/core'; import { InputNumber, Select, SelectList } from '@univerjs/design'; -import type { FC } from 'react'; +import { getCurrencyFormatOptions, getCurrencyType, getDecimalFromPattern, isPatternEqualWithoutDecimal, setPatternDecimal } from '@univerjs/sheets-numfmt'; import React, { useContext, useMemo, useState } from 'react'; +import { UserHabitCurrencyContext } from '../../../controllers/user-habit.controller'; -import type { IBusinessComponentProps } from '../../base/types'; -import { UserHabitCurrencyContext } from '../../context/user-habit'; -import { getCurrencyType } from '../../utils/currency'; -import { getDecimalFromPattern, isPatternEqualWithoutDecimal, setPatternDecimal } from '../../utils/decimal'; -import { getCurrencyFormatOptions } from '../../utils/options'; +// FIXME: DO NOT USE GLOBAL STYLES +import './index.less'; export const isCurrencyPanel = (pattern: string) => { const type = getCurrencyType(pattern); diff --git a/packages/sheets-numfmt/src/components/custom-format/index.module.less b/packages/sheets-numfmt-ui/src/views/components/custom-format/index.module.less similarity index 100% rename from packages/sheets-numfmt/src/components/custom-format/index.module.less rename to packages/sheets-numfmt-ui/src/views/components/custom-format/index.module.less diff --git a/packages/sheets-numfmt/src/components/custom-format/index.tsx b/packages/sheets-numfmt-ui/src/views/components/custom-format/index.tsx similarity index 93% rename from packages/sheets-numfmt/src/components/custom-format/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/custom-format/index.tsx index 494846704f4..752b29c3477 100644 --- a/packages/sheets-numfmt/src/components/custom-format/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/custom-format/index.tsx @@ -14,13 +14,13 @@ * limitations under the License. */ -import React, { useEffect, useState } from 'react'; +import type { IBusinessComponentProps } from '../interface'; import { ILocalStorageService, LocaleService, useDependency } from '@univerjs/core'; import { Input } from '@univerjs/design'; import { CheckMarkSingle } from '@univerjs/icons'; -import type { IBusinessComponentProps } from '../../base/types'; -import { CURRENCYFORMAT, DATEFMTLISG, NUMBERFORMAT } from '../../base/const/FORMATDETAIL'; -import { UserHabitController } from '../../controllers/user-habit.controller'; +import { CURRENCYFORMAT, DATEFMTLISG, NUMBERFORMAT } from '@univerjs/sheets-numfmt'; +import React, { useEffect, useState } from 'react'; +import { UserHabitController } from '../../../controllers/user-habit.controller'; import styles from './index.module.less'; const key = 'customFormat'; diff --git a/packages/sheets-numfmt/src/components/date/index.tsx b/packages/sheets-numfmt-ui/src/views/components/date/index.tsx similarity index 94% rename from packages/sheets-numfmt/src/components/date/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/date/index.tsx index adee89cacf9..c0fe9c83217 100644 --- a/packages/sheets-numfmt/src/components/date/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/date/index.tsx @@ -14,14 +14,13 @@ * limitations under the License. */ +import type { FC } from 'react'; +import type { IBusinessComponentProps } from '../interface'; import { LocaleService, numfmt, useDependency } from '@univerjs/core'; import { SelectList } from '@univerjs/design'; -import type { FC } from 'react'; +import { getDateFormatOptions } from '@univerjs/sheets-numfmt'; import React, { useMemo, useState } from 'react'; -import type { IBusinessComponentProps } from '../../base/types'; -import { getDateFormatOptions } from '../../utils/options'; - export const isDatePanel = (pattern: string) => { const info = numfmt.getInfo(pattern); return ( diff --git a/packages/sheets-numfmt/src/components/general/index.tsx b/packages/sheets-numfmt-ui/src/views/components/general/index.tsx similarity index 94% rename from packages/sheets-numfmt/src/components/general/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/general/index.tsx index c89642ee5d5..f599b0e704e 100644 --- a/packages/sheets-numfmt/src/components/general/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/general/index.tsx @@ -14,12 +14,11 @@ * limitations under the License. */ -import { LocaleService, useDependency } from '@univerjs/core'; import type { FC } from 'react'; +import type { IBusinessComponentProps } from '../interface'; +import { LocaleService, useDependency } from '@univerjs/core'; import React from 'react'; -import type { IBusinessComponentProps } from '../../base/types'; - export const isGeneralPanel = (pattern: string) => !pattern; export const GeneralPanel: FC = (props) => { diff --git a/packages/sheets-numfmt/src/components/index.less b/packages/sheets-numfmt-ui/src/views/components/index.less similarity index 100% rename from packages/sheets-numfmt/src/components/index.less rename to packages/sheets-numfmt-ui/src/views/components/index.less diff --git a/packages/sheets-numfmt/src/components/index.tsx b/packages/sheets-numfmt-ui/src/views/components/index.tsx similarity index 96% rename from packages/sheets-numfmt/src/components/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/index.tsx index bb1ea6ca96d..2e08ccc66a0 100644 --- a/packages/sheets-numfmt/src/components/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/index.tsx @@ -14,24 +14,25 @@ * limitations under the License. */ +import type { ISelectProps } from '@univerjs/design'; +import type { FC } from 'react'; +import type { IBusinessComponentProps } from './interface'; import { LocaleService, useDependency } from '@univerjs/core'; - import { Button, Select } from '@univerjs/design'; +import { getCurrencyType } from '@univerjs/sheets-numfmt'; import React, { useEffect, useMemo, useRef, useState } from 'react'; -import type { ISelectProps } from '@univerjs/design'; -import type { FC } from 'react'; -import { UserHabitCurrencyContext } from '../context/user-habit'; - +import { UserHabitCurrencyContext } from '../../controllers/user-habit.controller'; import { useCurrencyOptions } from '../hooks/useCurrencyOptions'; import { useNextTick } from '../hooks/useNextTick'; -import { getCurrencyType } from '../utils/currency'; import { AccountingPanel, isAccountingPanel } from './accounting'; import { CurrencyPanel, isCurrencyPanel } from './currency'; import { CustomFormat } from './custom-format'; + import { DatePanel, isDatePanel } from './date'; import { GeneralPanel, isGeneralPanel } from './general'; + import { isThousandthPercentilePanel, ThousandthPercentilePanel } from './thousandth-percentile'; -import type { IBusinessComponentProps } from '../base/types'; +// TODO@Gggpound: fix this // FIXME: DO NOT USE GLOBAL STYLES import './index.less'; diff --git a/packages/sheets-numfmt/src/base/types/index.ts b/packages/sheets-numfmt-ui/src/views/components/interface.ts similarity index 100% rename from packages/sheets-numfmt/src/base/types/index.ts rename to packages/sheets-numfmt-ui/src/views/components/interface.ts diff --git a/packages/sheets-numfmt/src/components/more-numfmt-type/MoreNumfmtType.tsx b/packages/sheets-numfmt-ui/src/views/components/more-numfmt-type/MoreNumfmtType.tsx similarity index 92% rename from packages/sheets-numfmt/src/components/more-numfmt-type/MoreNumfmtType.tsx rename to packages/sheets-numfmt-ui/src/views/components/more-numfmt-type/MoreNumfmtType.tsx index 2db35984f51..d25b56ba8cb 100644 --- a/packages/sheets-numfmt/src/components/more-numfmt-type/MoreNumfmtType.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/more-numfmt-type/MoreNumfmtType.tsx @@ -14,17 +14,15 @@ * limitations under the License. */ -import { ICommandService, LocaleService, Range, useDependency, useInjector } from '@univerjs/core'; +import type { FormatType } from '@univerjs/sheets'; +import { ICommandService, LocaleService, Range, useDependency, useInjector } from '@univerjs/core'; import { SheetsSelectionsService } from '@univerjs/sheets'; +import { getPatternPreview, getPatternType, OpenNumfmtPanelOperator, SetNumfmtCommand } from '@univerjs/sheets-numfmt'; import { ILayoutService } from '@univerjs/ui'; import React from 'react'; -import type { FormatType } from '@univerjs/sheets'; +import { MENU_OPTIONS } from '../../../controllers/menu'; -import { MENU_OPTIONS } from '../../base/const/MENU-OPTIONS'; -import { SetNumfmtCommand } from '../../commands/commands/set-numfmt.command'; -import { OpenNumfmtPanelOperator } from '../../commands/operations/open.numfmt.panel.operation'; -import { getPatternPreview, getPatternType } from '../../utils/pattern'; // FIXME: DO NOT USE GLOBAL STYLES import './index.less'; diff --git a/packages/sheets-numfmt/src/components/more-numfmt-type/index.less b/packages/sheets-numfmt-ui/src/views/components/more-numfmt-type/index.less similarity index 100% rename from packages/sheets-numfmt/src/components/more-numfmt-type/index.less rename to packages/sheets-numfmt-ui/src/views/components/more-numfmt-type/index.less diff --git a/packages/sheets-numfmt/src/components/stories/Panel.stories.tsx b/packages/sheets-numfmt-ui/src/views/components/stories/Panel.stories.tsx similarity index 90% rename from packages/sheets-numfmt/src/components/stories/Panel.stories.tsx rename to packages/sheets-numfmt-ui/src/views/components/stories/Panel.stories.tsx index d72928b30ce..c1e929426da 100644 --- a/packages/sheets-numfmt/src/components/stories/Panel.stories.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/stories/Panel.stories.tsx @@ -15,15 +15,15 @@ */ import type { Meta, StoryObj } from '@storybook/react'; -import { LocaleService, LocaleType, RediContext } from '@univerjs/core'; import type { Dependency } from '@univerjs/core'; -import React, { useContext, useState } from 'react'; -import enUS from '../../locale/en-US'; -import zhCN from '../../locale/zh-CN'; -import ruRU from '../../locale/ru-RU'; import type { ISheetNumfmtPanelProps } from '../index'; +import { LocaleService, LocaleType, RediContext } from '@univerjs/core'; +import React, { useContext, useState } from 'react'; +import { UserHabitController } from '../../../controllers/user-habit.controller'; +import enUS from '../../../locale/en-US'; +import ruRU from '../../../locale/ru-RU'; +import zhCN from '../../../locale/zh-CN'; import { SheetNumfmtPanel } from '../index'; -import { UserHabitController } from '../../controllers/user-habit.controller'; const meta: Meta = { title: 'numfmt', diff --git a/packages/sheets-numfmt/src/components/thousandth-percentile/index.tsx b/packages/sheets-numfmt-ui/src/views/components/thousandth-percentile/index.tsx similarity index 91% rename from packages/sheets-numfmt/src/components/thousandth-percentile/index.tsx rename to packages/sheets-numfmt-ui/src/views/components/thousandth-percentile/index.tsx index 6a87ecc4881..d848cf9cd0b 100644 --- a/packages/sheets-numfmt/src/components/thousandth-percentile/index.tsx +++ b/packages/sheets-numfmt-ui/src/views/components/thousandth-percentile/index.tsx @@ -14,20 +14,13 @@ * limitations under the License. */ +import type { FC } from 'react'; +import type { IBusinessComponentProps } from '../interface'; import { LocaleService, useDependency } from '@univerjs/core'; import { InputNumber, SelectList } from '@univerjs/design'; -import type { FC } from 'react'; +import { getDecimalFromPattern, getNumberFormatOptions, isPatternEqualWithoutDecimal, isPatternHasDecimal, setPatternDecimal } from '@univerjs/sheets-numfmt'; import React, { useMemo, useState } from 'react'; -import type { IBusinessComponentProps } from '../../base/types'; -import { - getDecimalFromPattern, - isPatternEqualWithoutDecimal, - isPatternHasDecimal, - setPatternDecimal, -} from '../../utils/decimal'; -import { getNumberFormatOptions } from '../../utils/options'; - export const isThousandthPercentilePanel = (pattern: string) => getNumberFormatOptions().some((item) => isPatternEqualWithoutDecimal(item.value, pattern)); diff --git a/packages/sheets-numfmt/src/hooks/useCurrencyOptions.ts b/packages/sheets-numfmt-ui/src/views/hooks/useCurrencyOptions.ts similarity index 90% rename from packages/sheets-numfmt/src/hooks/useCurrencyOptions.ts rename to packages/sheets-numfmt-ui/src/views/hooks/useCurrencyOptions.ts index 85f260d46c0..910ed2f02a6 100644 --- a/packages/sheets-numfmt/src/hooks/useCurrencyOptions.ts +++ b/packages/sheets-numfmt-ui/src/views/hooks/useCurrencyOptions.ts @@ -15,10 +15,9 @@ */ import { useDependency } from '@univerjs/core'; +import { currencySymbols } from '@univerjs/sheets-numfmt'; import { useEffect, useState } from 'react'; - -import { currencySymbols } from '../base/const/CURRENCY-SYMBOLS'; -import { UserHabitController } from '../controllers/user-habit.controller'; +import { UserHabitController } from '../../controllers/user-habit.controller'; const key = 'numfmtCurrency'; export const useCurrencyOptions = (onOptionChange?: (options: string[]) => void) => { diff --git a/packages/sheets-numfmt/src/hooks/useNextTick.ts b/packages/sheets-numfmt-ui/src/views/hooks/useNextTick.ts similarity index 100% rename from packages/sheets-numfmt/src/hooks/useNextTick.ts rename to packages/sheets-numfmt-ui/src/views/hooks/useNextTick.ts diff --git a/packages/sheets-numfmt/src/vite-env.d.ts b/packages/sheets-numfmt-ui/src/vite-env.d.ts similarity index 100% rename from packages/sheets-numfmt/src/vite-env.d.ts rename to packages/sheets-numfmt-ui/src/vite-env.d.ts diff --git a/packages/sheets-thread-comment-base/tsconfig.json b/packages/sheets-numfmt-ui/tsconfig.json similarity index 100% rename from packages/sheets-thread-comment-base/tsconfig.json rename to packages/sheets-numfmt-ui/tsconfig.json diff --git a/packages/sheets-thread-comment-base/tsconfig.node.json b/packages/sheets-numfmt-ui/tsconfig.node.json similarity index 100% rename from packages/sheets-thread-comment-base/tsconfig.node.json rename to packages/sheets-numfmt-ui/tsconfig.node.json diff --git a/packages/sheets-numfmt-ui/vite.config.ts b/packages/sheets-numfmt-ui/vite.config.ts new file mode 100644 index 00000000000..ff0e0966ce6 --- /dev/null +++ b/packages/sheets-numfmt-ui/vite.config.ts @@ -0,0 +1,12 @@ +import createViteConfig from '@univerjs-infra/shared/vite'; +import pkg from './package.json'; + +export default ({ mode }) => createViteConfig({}, { + mode, + pkg, + features: { + react: true, + css: true, + dom: true, + }, +}); diff --git a/packages/sheets-numfmt/README.md b/packages/sheets-numfmt/README.md index 3bd0604f7f6..a25e947dca2 100644 --- a/packages/sheets-numfmt/README.md +++ b/packages/sheets-numfmt/README.md @@ -1,11 +1,11 @@ -# @univerjs/sheets-numfmt +# @univerjs/sheets-numfmt-ui sheets-numfmt ## Package Overview | Package Name | UMD Namespace | Version | License | Downloads | Contains CSS | Contains i18n locales | | --- | --- | --- | --- | --- | :---: | :---: | -| `@univerjs/sheets-numfmt` | `UniverSheetsNumfmt` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ⭕️ | ⭕️ | +| `@univerjs/sheets-numfmt-ui` | `UniverSheetsNumfmt` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ⭕️ | ⭕️ | ## Introduction @@ -20,20 +20,20 @@ Providing editing/rendering capabilities around `number format`, such as edit pa ```shell # Using npm -npm install @univerjs/sheets-numfmt +npm install @univerjs/sheets-numfmt-ui # Using pnpm -pnpm add @univerjs/sheets-numfmt +pnpm add @univerjs/sheets-numfmt-ui ``` ### How to use -Import `@univerjs/sheets-numfmt` at the entrance . +Import `@univerjs/sheets-numfmt-ui` at the entrance . ```typescript import { LocaleType, LogLevel, Univer } from '@univerjs/core'; import { defaultTheme } from '@univerjs/design'; -import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'; +import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt-ui'; // univer const univer = new Univer({ @@ -52,7 +52,7 @@ univer.registerPlugin(UniverSheetsNumfmtPlugin); > If you need to export the snapshot to support the export data format, you need to add [some additional code](/) -[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-numfmt?style=flat-square -[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-numfmt -[npm-license-shield]: https://img.shields.io/npm/l/@univerjs/sheets-numfmt?style=flat-square -[npm-downloads-shield]: https://img.shields.io/npm/dm/@univerjs/sheets-numfmt?style=flat-square +[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-numfmt-ui?style=flat-square +[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-numfmt-ui +[npm-license-shield]: https://img.shields.io/npm/l/@univerjs/sheets-numfmt-ui?style=flat-square +[npm-downloads-shield]: https://img.shields.io/npm/dm/@univerjs/sheets-numfmt-ui?style=flat-square diff --git a/packages/sheets-numfmt/package.json b/packages/sheets-numfmt/package.json index 7d6f697c032..5b9e9b51d06 100644 --- a/packages/sheets-numfmt/package.json +++ b/packages/sheets-numfmt/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", @@ -43,8 +44,7 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*", - "./locale/*": "./lib/locale/*.json" + "./lib/*": "./lib/*" } }, "directories": { @@ -61,25 +61,16 @@ "build": "tsc && vite build" }, "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18.0.0", "rxjs": ">=7.0.0" }, "dependencies": { "@univerjs/core": "workspace:*", - "@univerjs/design": "workspace:*", "@univerjs/engine-formula": "workspace:*", "@univerjs/engine-numfmt": "workspace:*", - "@univerjs/engine-render": "workspace:*", - "@univerjs/icons": "^0.1.84", - "@univerjs/sheets": "workspace:*", - "@univerjs/sheets-ui": "workspace:*", - "@univerjs/ui": "workspace:*" + "@univerjs/sheets": "workspace:*" }, "devDependencies": { - "@types/react": "^18.3.11", "@univerjs-infra/shared": "workspace:*", - "less": "^4.2.0", - "react": "18.3.1", "rxjs": "^7.8.1", "typescript": "^5.6.3", "vite": "^5.4.8", @@ -96,7 +87,6 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*", - "./locale/*": "./lib/locale/*.json" + "./lib/*": "./lib/*" } } diff --git a/packages/sheets-numfmt/src/base/const/MENU-OPTIONS.ts b/packages/sheets-numfmt/src/base/const/MENU-OPTIONS.ts deleted file mode 100644 index 9dc2e3ddb20..00000000000 --- a/packages/sheets-numfmt/src/base/const/MENU-OPTIONS.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { DEFAULT_TEXT_FORMAT } from '@univerjs/engine-numfmt'; - -export const MENU_OPTIONS: Array<{ label: string; pattern: string | null } | '|'> = [ - { - label: 'sheet.numfmt.general', - pattern: null, - }, - { - label: 'sheet.numfmt.text', - pattern: DEFAULT_TEXT_FORMAT, - }, - '|', - { - label: 'sheet.numfmt.number', - pattern: '0', - }, - '|', - { - label: 'sheet.numfmt.accounting', - pattern: '"¥" #,##0.00_);[Red]("¥"#,##0.00)', - }, - { - label: 'sheet.numfmt.financialValue', - pattern: '#,##0.00;[Red]#,##0.00', - }, - { - label: 'sheet.numfmt.currency', - pattern: '"¥"#,##0.00_);[Red]("¥"#,##0.00)', - }, - { - label: 'sheet.numfmt.roundingCurrency', - pattern: '"¥"#,##0;[Red]"¥"#,##0', - }, - '|', - { - label: 'sheet.numfmt.date', - pattern: 'yyyy-mm-dd;@', - }, - { - label: 'sheet.numfmt.time', - pattern: 'am/pm h":"mm":"ss', - }, - { - label: 'sheet.numfmt.dateTime', - pattern: 'yyyy-m-d am/pm h:mm', - }, - { - label: 'sheet.numfmt.timeDuration', - pattern: 'h:mm:ss', - }, - '|', - { - label: 'sheet.numfmt.moreFmt', - pattern: '', - }, -]; diff --git a/packages/sheets-numfmt/src/commands/commands/add-decimal.command.ts b/packages/sheets-numfmt/src/commands/commands/add-decimal.command.ts index 9d4ff9d6173..27880c85d14 100644 --- a/packages/sheets-numfmt/src/commands/commands/add-decimal.command.ts +++ b/packages/sheets-numfmt/src/commands/commands/add-decimal.command.ts @@ -15,11 +15,10 @@ */ import type { IAccessor, ICommand } from '@univerjs/core'; +import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { CellValueType, CommandType, ICommandService, IUniverInstanceService, Range } from '@univerjs/core'; import { getSheetCommandTarget, INumfmtService, SheetsSelectionsService } from '@univerjs/sheets'; - import { getDecimalFromPattern, setPatternDecimal } from '../../utils/decimal'; -import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { SetNumfmtCommand } from './set-numfmt.command'; export const AddDecimalCommand: ICommand = { diff --git a/packages/sheets-numfmt/src/commands/commands/set-currency.command.ts b/packages/sheets-numfmt/src/commands/commands/set-currency.command.ts index 54d049d5771..fcf321b4c70 100644 --- a/packages/sheets-numfmt/src/commands/commands/set-currency.command.ts +++ b/packages/sheets-numfmt/src/commands/commands/set-currency.command.ts @@ -15,13 +15,12 @@ */ import type { IAccessor, ICommand } from '@univerjs/core'; +import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { CommandType, ICommandService, Range } from '@univerjs/core'; import { SheetsSelectionsService } from '@univerjs/sheets'; - -import { CURRENCYFORMAT } from '../../base/const/FORMATDETAIL'; import { countryCurrencyMap } from '../../base/const/CURRENCY-SYMBOLS'; +import { CURRENCYFORMAT } from '../../base/const/FORMATDETAIL'; import { MenuCurrencyService } from '../../service/menu.currency.service'; -import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { SetNumfmtCommand } from './set-numfmt.command'; export const SetCurrencyCommand: ICommand = { diff --git a/packages/sheets-numfmt/src/commands/commands/set-numfmt.command.ts b/packages/sheets-numfmt/src/commands/commands/set-numfmt.command.ts index 1c4f8ebbe67..27a682240d6 100644 --- a/packages/sheets-numfmt/src/commands/commands/set-numfmt.command.ts +++ b/packages/sheets-numfmt/src/commands/commands/set-numfmt.command.ts @@ -15,6 +15,12 @@ */ import type { IAccessor, ICommand, IMutationInfo } from '@univerjs/core'; +import type { + FormatType, + IRemoveNumfmtMutationParams, + ISetCellsNumfmt, + ISetNumfmtMutationParams, +} from '@univerjs/sheets'; import { CommandType, ICommandService, @@ -22,12 +28,6 @@ import { IUniverInstanceService, sequenceExecute, } from '@univerjs/core'; -import type { - FormatType, - IRemoveNumfmtMutationParams, - ISetCellsNumfmt, - ISetNumfmtMutationParams, -} from '@univerjs/sheets'; import { factoryRemoveNumfmtUndoMutation, factorySetNumfmtUndoMutation, diff --git a/packages/sheets-numfmt/src/commands/commands/set-percent.command.ts b/packages/sheets-numfmt/src/commands/commands/set-percent.command.ts index 17d6ecf3ea9..a7d0689ae11 100644 --- a/packages/sheets-numfmt/src/commands/commands/set-percent.command.ts +++ b/packages/sheets-numfmt/src/commands/commands/set-percent.command.ts @@ -15,10 +15,9 @@ */ import type { IAccessor, ICommand } from '@univerjs/core'; +import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { CommandType, ICommandService, Range } from '@univerjs/core'; import { SheetsSelectionsService } from '@univerjs/sheets'; - -import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { SetNumfmtCommand } from './set-numfmt.command'; export const SetPercentCommand: ICommand = { diff --git a/packages/sheets-numfmt/src/commands/commands/subtract-decimal.command.ts b/packages/sheets-numfmt/src/commands/commands/subtract-decimal.command.ts index 66e2a9a2036..ba9a98b77e5 100644 --- a/packages/sheets-numfmt/src/commands/commands/subtract-decimal.command.ts +++ b/packages/sheets-numfmt/src/commands/commands/subtract-decimal.command.ts @@ -15,11 +15,10 @@ */ import type { IAccessor, ICommand } from '@univerjs/core'; +import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { CellValueType, CommandType, ICommandService, IUniverInstanceService, Range } from '@univerjs/core'; import { getSheetCommandTarget, INumfmtService, SheetsSelectionsService } from '@univerjs/sheets'; - import { getDecimalFromPattern, setPatternDecimal } from '../../utils/decimal'; -import type { ISetNumfmtCommandParams } from './set-numfmt.command'; import { SetNumfmtCommand } from './set-numfmt.command'; export const SubtractDecimalCommand: ICommand = { diff --git a/packages/sheets-numfmt/src/controllers/numfmt.cell-content.controller.ts b/packages/sheets-numfmt/src/controllers/numfmt-cell-content.controller.ts similarity index 99% rename from packages/sheets-numfmt/src/controllers/numfmt.cell-content.controller.ts rename to packages/sheets-numfmt/src/controllers/numfmt-cell-content.controller.ts index 66d112967f4..1795ac23a49 100644 --- a/packages/sheets-numfmt/src/controllers/numfmt.cell-content.controller.ts +++ b/packages/sheets-numfmt/src/controllers/numfmt-cell-content.controller.ts @@ -34,7 +34,6 @@ import { UniverInstanceType, } from '@univerjs/core'; import { InterceptCellContentPriority, INTERCEPTOR_POINT, INumfmtService, SetNumfmtMutation, SetRangeValuesMutation, SheetInterceptorService } from '@univerjs/sheets'; - import { of, skip, switchMap } from 'rxjs'; import { getPatternPreviewIgnoreGeneral } from '../utils/pattern'; diff --git a/packages/sheets-numfmt/src/controllers/numfmt.currency.controller.ts b/packages/sheets-numfmt/src/controllers/numfmt-currency.controller.ts similarity index 100% rename from packages/sheets-numfmt/src/controllers/numfmt.currency.controller.ts rename to packages/sheets-numfmt/src/controllers/numfmt-currency.controller.ts diff --git a/packages/sheets-numfmt/src/facade/f-range.ts b/packages/sheets-numfmt/src/facade/f-range.ts new file mode 100644 index 00000000000..4141f59841a --- /dev/null +++ b/packages/sheets-numfmt/src/facade/f-range.ts @@ -0,0 +1,50 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ISetNumfmtCommandParams } from '../commands/commands/set-numfmt.command'; +import { FRange } from '@univerjs/sheets/facade'; +import { SetNumfmtCommand } from '../commands/commands/set-numfmt.command'; + +interface IFRangeSheetsNumfmtMixin { + // TODO@wzhudev: should separate numfmt package to two + + /** + * Set the number format of the range. + * @param pattern number format pattern. + * @returns Execution result. + */ + setNumberFormat(pattern: string): Promise; +} + +class FRangeLegacy extends FRange implements IFRangeSheetsNumfmtMixin { + override setNumberFormat(pattern: string): Promise { + // TODO@Gggpound: the API should support other types of parameters + const values: ISetNumfmtCommandParams['values'] = []; + + // Add number format info to the `values` array. + this.forEach((row, col) => values.push({ row, col, pattern })); + return this._commandService.executeCommand(SetNumfmtCommand.id, { + unitId: this._workbook.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + } as ISetNumfmtCommandParams); + } +} + +FRange.extend(FRangeLegacy); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FRange extends IFRangeSheetsNumfmtMixin { } +} diff --git a/packages/sheets-numfmt/src/facade/index.ts b/packages/sheets-numfmt/src/facade/index.ts new file mode 100644 index 00000000000..3b980c7d773 --- /dev/null +++ b/packages/sheets-numfmt/src/facade/index.ts @@ -0,0 +1,17 @@ +/** + * 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 './f-range'; diff --git a/packages/sheets-numfmt/src/index.ts b/packages/sheets-numfmt/src/index.ts index 9454a17d7a9..709e2aaa170 100644 --- a/packages/sheets-numfmt/src/index.ts +++ b/packages/sheets-numfmt/src/index.ts @@ -15,16 +15,21 @@ */ export { countryCurrencyMap } from './base/const/CURRENCY-SYMBOLS'; +export { CURRENCYFORMAT, DATEFMTLISG, NUMBERFORMAT } from './base/const/FORMATDETAIL'; export { UniverSheetsNumfmtPlugin } from './numfmt-plugin'; export { MenuCurrencyService } from './service/menu.currency.service'; -export { getPatternPreview, getPatternType } from './utils/pattern'; +export { getPatternPreview, getPatternPreviewIgnoreGeneral, getPatternType } from './utils/pattern'; +export { getDecimalFromPattern, getDecimalString, isPatternEqualWithoutDecimal, isPatternHasDecimal, setPatternDecimal } from './utils/decimal'; +export { getCurrencyType } from './utils/currency'; +export { currencySymbols } from './base/const/CURRENCY-SYMBOLS'; +export { SheetsNumfmtCellContentController } from './controllers/numfmt-cell-content.controller'; +export { getCurrencyFormatOptions, getCurrencyOptions, getDateFormatOptions, getNumberFormatOptions } from './utils/options'; // #region - all commands export { AddDecimalCommand } from './commands/commands/add-decimal.command'; export { SetCurrencyCommand } from './commands/commands/set-currency.command'; export { type ISetNumfmtCommandParams, SetNumfmtCommand } from './commands/commands/set-numfmt.command'; - export { SetPercentCommand } from './commands/commands/set-percent.command'; export { SubtractDecimalCommand } from './commands/commands/subtract-decimal.command'; export { CloseNumfmtPanelOperator } from './commands/operations/close.numfmt.panel.operation'; diff --git a/packages/sheets-numfmt/src/numfmt-plugin.ts b/packages/sheets-numfmt/src/numfmt-plugin.ts index be84aa63fee..88b4e4c97b9 100644 --- a/packages/sheets-numfmt/src/numfmt-plugin.ts +++ b/packages/sheets-numfmt/src/numfmt-plugin.ts @@ -14,57 +14,55 @@ * limitations under the License. */ -import type { IUniverSheetsNumfmtConfig } from './controllers/config.schema'; - -import { DependentOn, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { DependentOn, ICommandService, Inject, Injector, Plugin, registerDependencies, touchDependencies, UniverInstanceType } from '@univerjs/core'; import { UniverSheetsPlugin } from '@univerjs/sheets'; -import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; import { SHEET_NUMFMT_PLUGIN } from './base/const/PLUGIN_NAME'; -import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; -import { SheetsNumfmtCellContentController } from './controllers/numfmt.cell-content.controller'; -import { NumfmtController } from './controllers/numfmt.controller'; -import { NumfmtCurrencyController } from './controllers/numfmt.currency.controller'; -import { NumfmtEditorController } from './controllers/numfmt.editor.controller'; -import { NumfmtMenuController } from './controllers/numfmt.menu.controller'; +import { AddDecimalCommand } from './commands/commands/add-decimal.command'; +import { SetCurrencyCommand } from './commands/commands/set-currency.command'; +import { SetNumfmtCommand } from './commands/commands/set-numfmt.command'; +import { SetPercentCommand } from './commands/commands/set-percent.command'; +import { SubtractDecimalCommand } from './commands/commands/subtract-decimal.command'; +import { SheetsNumfmtCellContentController } from './controllers/numfmt-cell-content.controller'; +import { NumfmtCurrencyController } from './controllers/numfmt-currency.controller'; import { INumfmtController } from './controllers/type'; -import { UserHabitController } from './controllers/user-habit.controller'; import { MenuCurrencyService } from './service/menu.currency.service'; -@DependentOn(UniverSheetsPlugin, UniverSheetsUIPlugin) +@DependentOn(UniverSheetsPlugin) export class UniverSheetsNumfmtPlugin extends Plugin { static override pluginName = SHEET_NUMFMT_PLUGIN; static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = defaultPluginConfig, + private readonly _config: undefined = undefined, @Inject(Injector) override readonly _injector: Injector, - @IConfigService private readonly _configService: IConfigService + @ICommandService private readonly _commandService: ICommandService ) { super(); - - // Manage the plugin configuration. - const { menu, ...rest } = this._config; - if (menu) { - this._configService.setConfig('menu', menu, { merge: true }); - } - this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { - this._injector.add([INumfmtController, { useClass: NumfmtController, lazy: false }]); - this._injector.add([NumfmtEditorController]); - this._injector.add([UserHabitController]); - this._injector.add([SheetsNumfmtCellContentController]); - this._injector.add([MenuCurrencyService]); - this._injector.add([NumfmtCurrencyController]); - this._injector.add([NumfmtMenuController]); + registerDependencies(this._injector, [ + [SheetsNumfmtCellContentController], + [MenuCurrencyService], + [NumfmtCurrencyController], + ]); } override onRendered(): void { - this._injector.get(INumfmtController); - this._injector.get(SheetsNumfmtCellContentController); - this._injector.get(NumfmtCurrencyController); - this._injector.get(NumfmtEditorController); - this._injector.get(NumfmtMenuController); + touchDependencies(this._injector, [ + [INumfmtController], + [SheetsNumfmtCellContentController], + [NumfmtCurrencyController], + ]); + + [ + AddDecimalCommand, + SubtractDecimalCommand, + SetCurrencyCommand, + SetPercentCommand, + SetNumfmtCommand, + ].forEach((config) => { + this.disposeWithMe(this._commandService.registerCommand(config)); + }); } } diff --git a/packages/sheets-numfmt/src/service/menu.currency.service.ts b/packages/sheets-numfmt/src/service/menu.currency.service.ts index de13a292493..62958d3c4df 100644 --- a/packages/sheets-numfmt/src/service/menu.currency.service.ts +++ b/packages/sheets-numfmt/src/service/menu.currency.service.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { BehaviorSubject } from 'rxjs'; import type { countryCurrencyMap } from '../base/const/CURRENCY-SYMBOLS'; +import { BehaviorSubject } from 'rxjs'; export class MenuCurrencyService { private _currencySymbol$ = new BehaviorSubject('US'); diff --git a/packages/sheets-thread-comment-base/README.md b/packages/sheets-thread-comment-base/README.md deleted file mode 100644 index d7a34c98cb4..00000000000 --- a/packages/sheets-thread-comment-base/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# @univerjs/sheets-thread-comment-base - -## Package Overview - -| Package Name | UMD Namespace | Version | License | Downloads | Contains CSS | Contains i18n locales | -| --- | --- | --- | --- | --- | :---: | :---: | -| `@univerjs/sheets-thread-comment-base` | `UniverSheetsThreadCommentBase` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ❌ | ❌ | - -## Introduction - -`@univerjs/sheets-thread-comment-base` core package for sheet comment. For using, please refer to [@univerjs/sheets-thread-comment](../sheets-thread-comment/README.md) - -## Usage - -### Installation - -```shell -# Using npm -npm install @univerjs/sheets-thread-comment-base - -# Using pnpm -pnpm add @univerjs/sheets-thread-comment-base -``` - - -[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-thread-comment-base?style=flat-square -[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-thread-comment-base -[npm-license-shield]: https://img.shields.io/npm/l/@univerjs/sheets-thread-comment-base?style=flat-square -[npm-downloads-shield]: https://img.shields.io/npm/dm/@univerjs/sheets-thread-comment-base?style=flat-square diff --git a/packages/sheets-thread-comment-base/src/index.ts b/packages/sheets-thread-comment-base/src/index.ts deleted file mode 100644 index ecf3dc60668..00000000000 --- a/packages/sheets-thread-comment-base/src/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { SheetsThreadCommentRefRangeController } from './controllers/sheets-thread-comment-ref-range.controller'; -export { SheetsThreadCommentModel } from './models/sheets-thread-comment.model'; -export type { ISheetThreadComment } from './types/interfaces/i-sheet-thread-comment'; -export { UniverSheetsThreadCommentBasePlugin } from './plugin'; diff --git a/packages/sheets-thread-comment-base/src/plugin.ts b/packages/sheets-thread-comment-base/src/plugin.ts deleted file mode 100644 index 6098d735e3f..00000000000 --- a/packages/sheets-thread-comment-base/src/plugin.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Dependency } from '@univerjs/core'; -import { DependentOn, ICommandService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; -import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'; -import { SheetsThreadCommentRefRangeController } from './controllers/sheets-thread-comment-ref-range.controller'; -import { SheetsThreadCommentModel } from './models/sheets-thread-comment.model'; -import { SHEET_THREAD_COMMENT_BASE } from './types/const'; - -@DependentOn(UniverThreadCommentPlugin) -export class UniverSheetsThreadCommentBasePlugin extends Plugin { - static override pluginName = SHEET_THREAD_COMMENT_BASE; - static override type = UniverInstanceType.UNIVER_SHEET; - - constructor( - config: unknown, - @Inject(Injector) protected override _injector: Injector, - @Inject(ICommandService) protected _commandService: ICommandService - ) { - super(); - } - - override onStarting(): void { - ([ - [SheetsThreadCommentModel], - [SheetsThreadCommentRefRangeController], - ] as Dependency[]).forEach((dep) => { - this._injector.add(dep); - }); - - this._injector.get(SheetsThreadCommentRefRangeController); - } -} diff --git a/packages/sheets-thread-comment-ui/README.md b/packages/sheets-thread-comment-ui/README.md new file mode 100644 index 00000000000..893f74bd2a2 --- /dev/null +++ b/packages/sheets-thread-comment-ui/README.md @@ -0,0 +1,98 @@ +# @univerjs/sheets-thread-comment-ui + +## Package Overview + +| Package Name | UMD Namespace | Version | License | Downloads | Contains CSS | Contains i18n locales | +| --- | --- | --- | --- | --- | :---: | :---: | +| `@univerjs/sheets-thread-comment-ui` | `UniverSheetsThreadComment` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ⭕️ | ⭕️ | + +## Introduction + +`@univerjs/sheets-thread-comment-ui` provides the comment/annotation function of Univer Sheets. + +## Usage + +### Installation + +```shell +# Use npm +npm install @univerjs/sheets-thread-comment-ui + +# Use pnpm +pnpm add @univerjs/sheets-thread-comment-ui +``` + +### Register the plugin + +```typescript +import { UniverSheetsThreadCommentPlugin, IThreadCommentMentionDataService} from '@univerjs/sheets-thread-comment-ui'; + +const mockUser = { + userID: 'mockId', + name: 'MockUser', + avatar: 'icon-url', + anonymous: false, + canBindAnonymous: false, +}; + +class CustomMentionDataService implements IThreadCommentMentionDataService { + trigger: string = '@'; + + // Get the common interface implementation of the mentioned user + async getMentions(search: string) { + return [ + { + id: mockUser.userID, + label: mockUser.name, + type: 'user', + icon: mockUser.avatar, + }, + { + id: '2', + label: 'User2', + type: 'user', + icon: mockUser.avatar, + }, + ]; + } +} + +univer.registerPlugin(UniverSheetsThreadCommentPlugin, { + overrides: [[IThreadCommentMentionDataService, { useClass: CustomMentionDataService }]], +}); +``` + +### API +```typescript +import { + AddCommentCommand, + DeleteCommentCommand, + UpdateCommentCommand, + ResolveCommentCommand, + DeleteCommentTreeCommand, +} from '@univerjs/sheets-thread-comment-ui'; +import type { + IAddCommentCommandParams, + IDeleteCommentCommandParams, + IResolveCommentCommandParams, + IUpdateCommentCommandParams, + IDeleteCommentTreeCommandParams, +} from '@univerjs/sheets-thread-comment-ui'; + +// Add comment by command +const commandService = univer.__getInjector().get(ICommandService); + +commandService.executeCommand(AddCommentCommand.id, { + unitId: 'unitId', + subUnitId: 'subUnitId', + comment: { + // comment content + }, +} as IAddCommentCommandParams); +``` + + +[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-thread-comment-ui?style=flat-square +[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-thread-comment-ui +[npm-license-shield]: https://img.shields.io/npm/l/@univerjs/sheets-thread-comment-ui?style=flat-square +[npm-downloads-shield]: https://img.shields.io/npm/dm/@univerjs/sheets-thread-comment-ui?style=flat-square diff --git a/packages/sheets-thread-comment-ui/package.json b/packages/sheets-thread-comment-ui/package.json new file mode 100644 index 00000000000..f209788e202 --- /dev/null +++ b/packages/sheets-thread-comment-ui/package.json @@ -0,0 +1,102 @@ +{ + "name": "@univerjs/sheets-thread-comment-ui", + "version": "0.4.0-alpha.1", + "private": false, + "description": "Univer thread comment plugin", + "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": [], + "exports": { + ".": "./src/index.ts", + "./*": "./src/*", + "./locale/*": "./src/locale/*.ts" + }, + "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/*", + "./locale/*": "./lib/locale/*.json" + } + }, + "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": { + "react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "rxjs": ">=7.0.0" + }, + "dependencies": { + "@univerjs/core": "workspace:*", + "@univerjs/design": "workspace:*", + "@univerjs/docs-ui": "workspace:*", + "@univerjs/engine-formula": "workspace:*", + "@univerjs/engine-render": "workspace:*", + "@univerjs/icons": "^0.1.79", + "@univerjs/sheets": "workspace:*", + "@univerjs/sheets-thread-comment": "workspace:*", + "@univerjs/sheets-ui": "workspace:*", + "@univerjs/thread-comment": "workspace:*", + "@univerjs/thread-comment-ui": "workspace:*", + "@univerjs/ui": "workspace:*", + "clsx": "^2.1.1" + }, + "devDependencies": { + "@univerjs-infra/shared": "workspace:*", + "react": "18.3.1", + "rxjs": "^7.8.1", + "typescript": "^5.6.3", + "vite": "^5.4.8", + "vitest": "^2.1.2" + }, + "univerSpace": { + ".": { + "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/*", + "./locale/*": "./lib/locale/*.json" + } +} diff --git a/packages/sheets-thread-comment/src/commands/operations/comment.operation.ts b/packages/sheets-thread-comment-ui/src/commands/operations/comment.operation.ts similarity index 99% rename from packages/sheets-thread-comment/src/commands/operations/comment.operation.ts rename to packages/sheets-thread-comment-ui/src/commands/operations/comment.operation.ts index 1cf12495666..819d6f21258 100644 --- a/packages/sheets-thread-comment/src/commands/operations/comment.operation.ts +++ b/packages/sheets-thread-comment-ui/src/commands/operations/comment.operation.ts @@ -14,12 +14,12 @@ * limitations under the License. */ +import type { ICommand } from '@univerjs/core'; +import type { ISheetLocation } from '@univerjs/sheets'; import { CommandType, IUniverInstanceService } from '@univerjs/core'; import { getSheetCommandTarget, SheetsSelectionsService } from '@univerjs/sheets'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; +import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { ThreadCommentPanelService } from '@univerjs/thread-comment-ui'; -import type { ICommand } from '@univerjs/core'; -import type { ISheetLocation } from '@univerjs/sheets'; import { SheetsThreadCommentPopupService } from '../../services/sheets-thread-comment-popup.service'; export const ShowAddSheetCommentModalOperation: ICommand = { diff --git a/packages/sheets-thread-comment-ui/src/controllers/config.schema.ts b/packages/sheets-thread-comment-ui/src/controllers/config.schema.ts new file mode 100644 index 00000000000..c0b0c2ee106 --- /dev/null +++ b/packages/sheets-thread-comment-ui/src/controllers/config.schema.ts @@ -0,0 +1,29 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { DependencyOverride } from '@univerjs/core'; +import type { MenuConfig } from '@univerjs/ui'; + +export const PLUGIN_CONFIG_KEY = 'sheets-thread-comment.config'; + +export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); + +export interface IUniverSheetsThreadCommentUIConfig { + menu?: MenuConfig; + overrides?: DependencyOverride; +} + +export const defaultPluginConfig: IUniverSheetsThreadCommentUIConfig = {}; diff --git a/packages/sheets-thread-comment/src/controllers/menu.schema.ts b/packages/sheets-thread-comment-ui/src/controllers/menu.schema.ts similarity index 100% rename from packages/sheets-thread-comment/src/controllers/menu.schema.ts rename to packages/sheets-thread-comment-ui/src/controllers/menu.schema.ts index 28a224a8958..d9ec23e5688 100644 --- a/packages/sheets-thread-comment/src/controllers/menu.schema.ts +++ b/packages/sheets-thread-comment-ui/src/controllers/menu.schema.ts @@ -15,8 +15,8 @@ */ import type { MenuSchemaType } from '@univerjs/ui'; -import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; import { ToggleSheetCommentPanelOperation } from '@univerjs/thread-comment-ui'; +import { ContextMenuGroup, ContextMenuPosition, RibbonStartGroup } from '@univerjs/ui'; import { ShowAddSheetCommentModalOperation } from '../commands/operations/comment.operation'; import { threadCommentMenuFactory, threadPanelMenuFactory } from './menu'; diff --git a/packages/sheets-thread-comment/src/controllers/menu.ts b/packages/sheets-thread-comment-ui/src/controllers/menu.ts similarity index 100% rename from packages/sheets-thread-comment/src/controllers/menu.ts rename to packages/sheets-thread-comment-ui/src/controllers/menu.ts index 17dc2723823..8cae85aa2b5 100644 --- a/packages/sheets-thread-comment/src/controllers/menu.ts +++ b/packages/sheets-thread-comment-ui/src/controllers/menu.ts @@ -14,13 +14,13 @@ * limitations under the License. */ +import type { IAccessor } from '@univerjs/core'; +import type { IMenuItem, IShortcutItem } from '@univerjs/ui'; import { UniverInstanceType } from '@univerjs/core'; import { RangeProtectionPermissionViewPoint, WorkbookCommentPermission, WorksheetViewPermission } from '@univerjs/sheets'; import { getCurrentRangeDisable$, whenSheetEditorFocused } from '@univerjs/sheets-ui'; import { ToggleSheetCommentPanelOperation } from '@univerjs/thread-comment-ui'; import { getMenuHiddenObservable, KeyCode, MenuItemType, MetaKeys } from '@univerjs/ui'; -import type { IAccessor } from '@univerjs/core'; -import type { IMenuItem, IShortcutItem } from '@univerjs/ui'; import { ShowAddSheetCommentModalOperation } from '../commands/operations/comment.operation'; import { COMMENT_SINGLE_ICON } from '../types/const'; diff --git a/packages/sheets-thread-comment/src/controllers/render-controllers/render.controller.ts b/packages/sheets-thread-comment-ui/src/controllers/render-controllers/render.controller.ts similarity index 99% rename from packages/sheets-thread-comment/src/controllers/render-controllers/render.controller.ts rename to packages/sheets-thread-comment-ui/src/controllers/render-controllers/render.controller.ts index 81674184761..625acfe731b 100644 --- a/packages/sheets-thread-comment/src/controllers/render-controllers/render.controller.ts +++ b/packages/sheets-thread-comment-ui/src/controllers/render-controllers/render.controller.ts @@ -18,7 +18,7 @@ import type { Workbook } from '@univerjs/core'; import { Disposable, Inject, InterceptorEffectEnum, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { INTERCEPTOR_POINT, SheetInterceptorService } from '@univerjs/sheets'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; +import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { debounceTime } from 'rxjs'; export class SheetsThreadCommentRenderController extends Disposable { diff --git a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-copy-paste.controller.ts b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-copy-paste.controller.ts similarity index 99% rename from packages/sheets-thread-comment/src/controllers/sheets-thread-comment-copy-paste.controller.ts rename to packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-copy-paste.controller.ts index 30a9eae91c2..af3b3ea3bd7 100644 --- a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-copy-paste.controller.ts +++ b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-copy-paste.controller.ts @@ -17,7 +17,7 @@ import type { IMutationInfo, IRange, Nullable } from '@univerjs/core'; import { Disposable, Inject, Range } from '@univerjs/core'; import { serializeRange, singleReferenceToGrid } from '@univerjs/engine-formula'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; +import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { COPY_TYPE, ISheetClipboardService } from '@univerjs/sheets-ui'; import { AddCommentMutation, DeleteCommentMutation, type IThreadComment, IThreadCommentDataSourceService } from '@univerjs/thread-comment'; import { SHEETS_THREAD_COMMENT } from '../types/const'; diff --git a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-hover.controller.ts b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-hover.controller.ts similarity index 99% rename from packages/sheets-thread-comment/src/controllers/sheets-thread-comment-hover.controller.ts rename to packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-hover.controller.ts index 3777d53b1a7..daabcbc8e54 100644 --- a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-hover.controller.ts +++ b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-hover.controller.ts @@ -16,7 +16,7 @@ import { Disposable, Inject } from '@univerjs/core'; import { RangeProtectionPermissionViewPoint, WorkbookCommentPermission, WorksheetViewPermission } from '@univerjs/sheets'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; +import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { HoverManagerService, SheetPermissionInterceptorBaseController } from '@univerjs/sheets-ui'; import { debounceTime } from 'rxjs'; import { SheetsThreadCommentPopupService } from '../services/sheets-thread-comment-popup.service'; diff --git a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-popup.controller.ts b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-popup.controller.ts similarity index 99% rename from packages/sheets-thread-comment/src/controllers/sheets-thread-comment-popup.controller.ts rename to packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-popup.controller.ts index b6e41c27c84..5fe654adf18 100644 --- a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-popup.controller.ts +++ b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-popup.controller.ts @@ -21,7 +21,7 @@ import { Disposable, ICommandService, Inject, IUniverInstanceService, RANGE_TYPE import { singleReferenceToGrid } from '@univerjs/engine-formula'; import { IRenderManagerService } from '@univerjs/engine-render'; import { RangeProtectionPermissionViewPoint, SetWorksheetActiveOperation, SheetsSelectionsService, WorkbookCommentPermission, WorksheetViewPermission } from '@univerjs/sheets'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; +import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { IEditorBridgeService, IMarkSelectionService, ScrollToRangeOperation, SheetPermissionInterceptorBaseController, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; import { DeleteCommentMutation } from '@univerjs/thread-comment'; import { SetActiveCommentOperation, ThreadCommentPanelService } from '@univerjs/thread-comment-ui'; diff --git a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-remove.controller.ts b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-remove.controller.ts similarity index 100% rename from packages/sheets-thread-comment/src/controllers/sheets-thread-comment-remove.controller.ts rename to packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment-remove.controller.ts diff --git a/packages/sheets-thread-comment/src/controllers/sheets-thread-comment.controller.ts b/packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment.controller.ts similarity index 100% rename from packages/sheets-thread-comment/src/controllers/sheets-thread-comment.controller.ts rename to packages/sheets-thread-comment-ui/src/controllers/sheets-thread-comment.controller.ts diff --git a/packages/sheets-thread-comment-ui/src/index.ts b/packages/sheets-thread-comment-ui/src/index.ts new file mode 100644 index 00000000000..da4ed6e5223 --- /dev/null +++ b/packages/sheets-thread-comment-ui/src/index.ts @@ -0,0 +1,42 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation'; +export { UniverSheetsThreadCommentUIPlugin } from './plugin'; +export { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service'; +export { SHEETS_THREAD_COMMENT } from './types/const'; +export { IThreadCommentDataSourceService } from '@univerjs/thread-comment'; +export { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; +export { IThreadCommentMentionDataService } from '@univerjs/thread-comment-ui'; + +// #region - all commands + +export { + AddCommentCommand, + DeleteCommentCommand, + DeleteCommentTreeCommand, + ResolveCommentCommand, + UpdateCommentCommand, +} from '@univerjs/thread-comment'; +export type { + IAddCommentCommandParams, + IDeleteCommentCommandParams, + IDeleteCommentTreeCommandParams, + IResolveCommentCommandParams, + IUpdateCommentCommandParams, +} from '@univerjs/thread-comment'; + +// #endregion diff --git a/packages/sheets-thread-comment/src/locale/en-US.ts b/packages/sheets-thread-comment-ui/src/locale/en-US.ts similarity index 100% rename from packages/sheets-thread-comment/src/locale/en-US.ts rename to packages/sheets-thread-comment-ui/src/locale/en-US.ts diff --git a/packages/sheets-thread-comment/src/locale/fa-IR.ts b/packages/sheets-thread-comment-ui/src/locale/fa-IR.ts similarity index 100% rename from packages/sheets-thread-comment/src/locale/fa-IR.ts rename to packages/sheets-thread-comment-ui/src/locale/fa-IR.ts diff --git a/packages/sheets-thread-comment/src/locale/ru-RU.ts b/packages/sheets-thread-comment-ui/src/locale/ru-RU.ts similarity index 100% rename from packages/sheets-thread-comment/src/locale/ru-RU.ts rename to packages/sheets-thread-comment-ui/src/locale/ru-RU.ts diff --git a/packages/sheets-thread-comment/src/locale/vi-VN.ts b/packages/sheets-thread-comment-ui/src/locale/vi-VN.ts similarity index 100% rename from packages/sheets-thread-comment/src/locale/vi-VN.ts rename to packages/sheets-thread-comment-ui/src/locale/vi-VN.ts diff --git a/packages/sheets-thread-comment/src/locale/zh-CN.ts b/packages/sheets-thread-comment-ui/src/locale/zh-CN.ts similarity index 100% rename from packages/sheets-thread-comment/src/locale/zh-CN.ts rename to packages/sheets-thread-comment-ui/src/locale/zh-CN.ts diff --git a/packages/sheets-thread-comment/src/locale/zh-TW.ts b/packages/sheets-thread-comment-ui/src/locale/zh-TW.ts similarity index 100% rename from packages/sheets-thread-comment/src/locale/zh-TW.ts rename to packages/sheets-thread-comment-ui/src/locale/zh-TW.ts diff --git a/packages/sheets-thread-comment-ui/src/plugin.ts b/packages/sheets-thread-comment-ui/src/plugin.ts new file mode 100644 index 00000000000..2ae0e91c22b --- /dev/null +++ b/packages/sheets-thread-comment-ui/src/plugin.ts @@ -0,0 +1,84 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Dependency } from '@univerjs/core'; +import type { IUniverSheetsThreadCommentUIConfig } from './controllers/config.schema'; +import { DependentOn, ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment'; +import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; +import { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation'; +import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; +import { SheetsThreadCommentRenderController } from './controllers/render-controllers/render.controller'; +import { SheetsThreadCommentController } from './controllers/sheets-thread-comment.controller'; +import { SheetsThreadCommentCopyPasteController } from './controllers/sheets-thread-comment-copy-paste.controller'; +import { SheetsThreadCommentHoverController } from './controllers/sheets-thread-comment-hover.controller'; +import { SheetsThreadCommentPopupController } from './controllers/sheets-thread-comment-popup.controller'; +import { ThreadCommentRemoveSheetsController } from './controllers/sheets-thread-comment-remove.controller'; +import { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service'; +import { SHEETS_THREAD_COMMENT } from './types/const'; + +@DependentOn(UniverThreadCommentUIPlugin, UniverSheetsThreadCommentPlugin) +export class UniverSheetsThreadCommentUIPlugin extends Plugin { + static override pluginName = SHEETS_THREAD_COMMENT; + static override type = UniverInstanceType.UNIVER_SHEET; + + constructor( + private readonly _config: Partial = defaultPluginConfig, + @Inject(Injector) protected override _injector: Injector, + @Inject(ICommandService) protected _commandService: ICommandService, + @IConfigService private readonly _configService: IConfigService + ) { + super(); + + // Manage the plugin configuration. + const { menu, ...rest } = this._config; + if (menu) { + this._configService.setConfig('menu', menu, { merge: true }); + } + this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); + } + + override onStarting(): void { + ([ + [SheetsThreadCommentController], + [SheetsThreadCommentRenderController], + [SheetsThreadCommentCopyPasteController], + [SheetsThreadCommentHoverController], + [ThreadCommentRemoveSheetsController], + [SheetsThreadCommentPopupController], + [SheetsThreadCommentPopupService], + ] as Dependency[]).forEach((dep) => { + this._injector.add(dep); + }); + + [ShowAddSheetCommentModalOperation].forEach((command) => { + this._commandService.registerCommand(command); + }); + + this._injector.get(SheetsThreadCommentController); + } + + override onReady(): void { + this._injector.get(SheetsThreadCommentRenderController); + this._injector.get(ThreadCommentRemoveSheetsController); + } + + override onRendered(): void { + this._injector.get(SheetsThreadCommentCopyPasteController); + this._injector.get(SheetsThreadCommentHoverController); + this._injector.get(SheetsThreadCommentPopupController); + } +} diff --git a/packages/sheets-thread-comment/src/services/sheets-thread-comment-popup.service.ts b/packages/sheets-thread-comment-ui/src/services/sheets-thread-comment-popup.service.ts similarity index 100% rename from packages/sheets-thread-comment/src/services/sheets-thread-comment-popup.service.ts rename to packages/sheets-thread-comment-ui/src/services/sheets-thread-comment-popup.service.ts index e17129236f7..2a84f8f9e77 100644 --- a/packages/sheets-thread-comment/src/services/sheets-thread-comment-popup.service.ts +++ b/packages/sheets-thread-comment-ui/src/services/sheets-thread-comment-popup.service.ts @@ -15,8 +15,8 @@ */ import type { IDisposable, Nullable } from '@univerjs/core'; -import { Disposable, DisposableCollection, Inject } from '@univerjs/core'; import type { ISheetLocationBase } from '@univerjs/sheets'; +import { Disposable, DisposableCollection, Inject } from '@univerjs/core'; import { SheetCanvasPopManagerService } from '@univerjs/sheets-ui'; import { IZenZoneService } from '@univerjs/ui'; import { BehaviorSubject } from 'rxjs'; diff --git a/packages/sheets-thread-comment-base/src/types/const.ts b/packages/sheets-thread-comment-ui/src/types/const.ts similarity index 75% rename from packages/sheets-thread-comment-base/src/types/const.ts rename to packages/sheets-thread-comment-ui/src/types/const.ts index b95c8ca064d..51726d6665d 100644 --- a/packages/sheets-thread-comment-base/src/types/const.ts +++ b/packages/sheets-thread-comment-ui/src/types/const.ts @@ -14,4 +14,6 @@ * limitations under the License. */ -export const SHEET_THREAD_COMMENT_BASE = 'SHEET_THREAD_COMMENT_BASE_PLUGIN'; +export const SHEETS_THREAD_COMMENT_MODAL = 'univer.sheet.thread-comment-modal'; +export const COMMENT_SINGLE_ICON = 'comment-single'; +export const SHEETS_THREAD_COMMENT = 'SHEET_THREAD_COMMENT'; diff --git a/packages/sheets-thread-comment-base/src/types/interfaces/i-sheet-thread-comment.ts b/packages/sheets-thread-comment-ui/src/types/interfaces/i-sheet-thread-comment.ts similarity index 100% rename from packages/sheets-thread-comment-base/src/types/interfaces/i-sheet-thread-comment.ts rename to packages/sheets-thread-comment-ui/src/types/interfaces/i-sheet-thread-comment.ts diff --git a/packages/sheets-thread-comment/src/views/sheets-thread-comment-cell/index.tsx b/packages/sheets-thread-comment-ui/src/views/sheets-thread-comment-cell/index.tsx similarity index 99% rename from packages/sheets-thread-comment/src/views/sheets-thread-comment-cell/index.tsx rename to packages/sheets-thread-comment-ui/src/views/sheets-thread-comment-cell/index.tsx index a5d1ec9ed3f..d935c954ae9 100644 --- a/packages/sheets-thread-comment/src/views/sheets-thread-comment-cell/index.tsx +++ b/packages/sheets-thread-comment-ui/src/views/sheets-thread-comment-cell/index.tsx @@ -14,12 +14,12 @@ * limitations under the License. */ +import type { Workbook } from '@univerjs/core'; import { IUniverInstanceService, Tools, UniverInstanceType, useDependency } from '@univerjs/core'; -import React from 'react'; +import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; import { ThreadCommentTree } from '@univerjs/thread-comment-ui'; -import type { Workbook } from '@univerjs/core'; import { useObservable } from '@univerjs/ui'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; +import React from 'react'; import { SheetsThreadCommentPopupService } from '../../services/sheets-thread-comment-popup.service'; export const SheetsThreadCommentCell = () => { diff --git a/packages/sheets-thread-comment/src/views/sheets-thread-comment-panel/index.tsx b/packages/sheets-thread-comment-ui/src/views/sheets-thread-comment-panel/index.tsx similarity index 100% rename from packages/sheets-thread-comment/src/views/sheets-thread-comment-panel/index.tsx rename to packages/sheets-thread-comment-ui/src/views/sheets-thread-comment-panel/index.tsx diff --git a/packages/sheets-thread-comment-base/src/vite-env.d.ts b/packages/sheets-thread-comment-ui/src/vite-env.d.ts similarity index 100% rename from packages/sheets-thread-comment-base/src/vite-env.d.ts rename to packages/sheets-thread-comment-ui/src/vite-env.d.ts diff --git a/packages/sheets-thread-comment-ui/tsconfig.json b/packages/sheets-thread-comment-ui/tsconfig.json new file mode 100644 index 00000000000..c62210cbad2 --- /dev/null +++ b/packages/sheets-thread-comment-ui/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@univerjs-infra/shared/tsconfigs/base", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types" + }, + "references": [{ "path": "./tsconfig.node.json" }], + "include": ["src"] +} diff --git a/packages/sheets-thread-comment-ui/tsconfig.node.json b/packages/sheets-thread-comment-ui/tsconfig.node.json new file mode 100644 index 00000000000..50ef1e6862b --- /dev/null +++ b/packages/sheets-thread-comment-ui/tsconfig.node.json @@ -0,0 +1,4 @@ +{ + "extends": "@univerjs-infra/shared/tsconfigs/node", + "include": ["vite.config.ts"] +} diff --git a/packages/sheets-thread-comment-base/vite.config.ts b/packages/sheets-thread-comment-ui/vite.config.ts similarity index 100% rename from packages/sheets-thread-comment-base/vite.config.ts rename to packages/sheets-thread-comment-ui/vite.config.ts diff --git a/packages/sheets-thread-comment/README.md b/packages/sheets-thread-comment/README.md index 2a780918ed9..de698650b8f 100644 --- a/packages/sheets-thread-comment/README.md +++ b/packages/sheets-thread-comment/README.md @@ -4,93 +4,24 @@ | Package Name | UMD Namespace | Version | License | Downloads | Contains CSS | Contains i18n locales | | --- | --- | --- | --- | --- | :---: | :---: | -| `@univerjs/sheets-thread-comment` | `UniverSheetsThreadComment` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ⭕️ | ⭕️ | +| `@univerjs/sheets-thread-comment` | `UniverSheetsThreadCommentBase` | [![][npm-version-shield]][npm-version-link] | ![][npm-license-shield] | ![][npm-downloads-shield] | ❌ | ❌ | ## Introduction -`@univerjs/sheets-thread-comment` provides the comment/annotation function of Univer Sheets. +`@univerjs/sheets-thread-comment` core package for sheet comment. For using, please refer to [@univerjs/sheets-thread-comment](../sheets-thread-comment/README.md) ## Usage ### Installation ```shell -# Use npm +# Using npm npm install @univerjs/sheets-thread-comment -# Use pnpm +# Using pnpm pnpm add @univerjs/sheets-thread-comment ``` -### Register the plugin - -```typescript -import { UniverSheetsThreadCommentPlugin, IThreadCommentMentionDataService} from '@univerjs/sheets-thread-comment'; - -const mockUser = { - userID: 'mockId', - name: 'MockUser', - avatar: 'icon-url', - anonymous: false, - canBindAnonymous: false, -}; - -class CustomMentionDataService implements IThreadCommentMentionDataService { - trigger: string = '@'; - - // Get the common interface implementation of the mentioned user - async getMentions(search: string) { - return [ - { - id: mockUser.userID, - label: mockUser.name, - type: 'user', - icon: mockUser.avatar, - }, - { - id: '2', - label: 'User2', - type: 'user', - icon: mockUser.avatar, - }, - ]; - } -} - -univer.registerPlugin(UniverSheetsThreadCommentPlugin, { - overrides: [[IThreadCommentMentionDataService, { useClass: CustomMentionDataService }]], -}); -``` - -### API -```typescript -import { - AddCommentCommand, - DeleteCommentCommand, - UpdateCommentCommand, - ResolveCommentCommand, - DeleteCommentTreeCommand, -} from '@univerjs/sheets-thread-comment'; -import type { - IAddCommentCommandParams, - IDeleteCommentCommandParams, - IResolveCommentCommandParams, - IUpdateCommentCommandParams, - IDeleteCommentTreeCommandParams, -} from '@univerjs/sheets-thread-comment'; - -// Add comment by command -const commandService = univer.__getInjector().get(ICommandService); - -commandService.executeCommand(AddCommentCommand.id, { - unitId: 'unitId', - subUnitId: 'subUnitId', - comment: { - // comment content - }, -} as IAddCommentCommandParams); -``` - [npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-thread-comment?style=flat-square [npm-version-link]: https://npmjs.com/package/@univerjs/sheets-thread-comment diff --git a/packages/sheets-thread-comment/package.json b/packages/sheets-thread-comment/package.json index 638e0f64bc1..1e209e4fffc 100644 --- a/packages/sheets-thread-comment/package.json +++ b/packages/sheets-thread-comment/package.json @@ -2,7 +2,7 @@ "name": "@univerjs/sheets-thread-comment", "version": "0.4.2", "private": false, - "description": "Univer thread comment plugin", + "description": "Univer sheets thread comment base plugin", "author": "DreamNum ", "license": "Apache-2.0", "funding": { @@ -21,7 +21,7 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", @@ -41,8 +41,7 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*", - "./locale/*": "./lib/locale/*.json" + "./lib/*": "./lib/*" } }, "directories": { @@ -59,22 +58,13 @@ "build": "tsc && vite build" }, "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18.0.0", "rxjs": ">=7.0.0" }, "dependencies": { "@univerjs/core": "workspace:*", - "@univerjs/design": "workspace:*", "@univerjs/engine-formula": "workspace:*", - "@univerjs/engine-render": "workspace:*", - "@univerjs/icons": "^0.1.84", "@univerjs/sheets": "workspace:*", - "@univerjs/sheets-thread-comment-base": "workspace:*", - "@univerjs/sheets-ui": "workspace:*", - "@univerjs/thread-comment": "workspace:*", - "@univerjs/thread-comment-ui": "workspace:*", - "@univerjs/ui": "workspace:*", - "clsx": "^2.1.1" + "@univerjs/thread-comment": "workspace:*" }, "devDependencies": { "@univerjs-infra/shared": "workspace:*", @@ -95,7 +85,6 @@ "require": "./lib/cjs/*", "types": "./lib/types/index.d.ts" }, - "./lib/*": "./lib/*", - "./locale/*": "./lib/locale/*.json" + "./lib/*": "./lib/*" } } diff --git a/packages/sheets-thread-comment/src/controllers/config.schema.ts b/packages/sheets-thread-comment/src/controllers/config.schema.ts index f1d5b86d308..ea650aef222 100644 --- a/packages/sheets-thread-comment/src/controllers/config.schema.ts +++ b/packages/sheets-thread-comment/src/controllers/config.schema.ts @@ -14,16 +14,11 @@ * limitations under the License. */ -import type { MenuConfig } from '@univerjs/ui'; -import type { DependencyOverride } from '@univerjs/core'; - export const PLUGIN_CONFIG_KEY = 'sheets-thread-comment.config'; export const configSymbol = Symbol(PLUGIN_CONFIG_KEY); -export interface IUniverSheetsThreadCommentConfig { - menu?: MenuConfig; - overrides?: DependencyOverride; +export interface IUniverSheetsThreadCommentBaseConfig { } -export const defaultPluginConfig: IUniverSheetsThreadCommentConfig = {}; +export const defaultPluginConfig: IUniverSheetsThreadCommentBaseConfig = {}; diff --git a/packages/sheets-thread-comment-base/src/controllers/sheets-thread-comment-ref-range.controller.ts b/packages/sheets-thread-comment/src/controllers/sheets-thread-comment-ref-range.controller.ts similarity index 100% rename from packages/sheets-thread-comment-base/src/controllers/sheets-thread-comment-ref-range.controller.ts rename to packages/sheets-thread-comment/src/controllers/sheets-thread-comment-ref-range.controller.ts diff --git a/packages/sheets-thread-comment/src/facade/f-range.ts b/packages/sheets-thread-comment/src/facade/f-range.ts new file mode 100644 index 00000000000..1d5bf2c3834 --- /dev/null +++ b/packages/sheets-thread-comment/src/facade/f-range.ts @@ -0,0 +1,113 @@ +/** + * 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 { ICommandService, type IDocumentBody, type Nullable, Tools, UserManagerService } from '@univerjs/core'; +import { FRange } from '@univerjs/sheets/facade'; +import { AddCommentCommand, DeleteCommentTreeCommand, getDT } from '@univerjs/thread-comment'; +import { SheetsThreadCommentModel } from '../models/sheets-thread-comment.model'; +import { FThreadComment } from './f-thread-comment'; + +interface IFRangeCommentMixin { + /** + * Get the comment of the start cell in the current range. + * @returns The comment of the start cell in the current range. If the cell does not have a comment, return `null`. + */ + getComment(): Nullable; + /** + * Add a comment to the start cell in the current range. + * @param content The content of the comment. + * @returns Whether the comment is added successfully. + */ + addComment(this: FRange, content: IDocumentBody): Promise; + /** + * Clear the comment of the start cell in the current range. + * @returns Whether the comment is cleared successfully. + */ + clearComment(): Promise; +} + +class FRangeCommentMixin extends FRange implements IFRangeCommentMixin { + override getComment(): Nullable { + const injector = this._injector; + const sheetsTheadCommentModel = injector.get(SheetsThreadCommentModel); + const unitId = this._workbook.getUnitId(); + const sheetId = this._worksheet.getSheetId(); + const commentId = sheetsTheadCommentModel.getByLocation(unitId, sheetId, this._range.startRow, this._range.startColumn); + if (!commentId) { + return null; + } + + const comment = sheetsTheadCommentModel.getComment(unitId, sheetId, commentId); + if (comment) { + return this._injector.createInstance(FThreadComment, comment); + } + + return null; + } + + override addComment(content: IDocumentBody): Promise { + const injector = this._injector; + const currentComment = this.getComment()?.getCommentData(); + const commentService = injector.get(ICommandService); + const userService = injector.get(UserManagerService); + const unitId = this._workbook.getUnitId(); + const sheetId = this._worksheet.getSheetId(); + const refStr = `${Tools.chatAtABC(this._range.startColumn)}${this._range.startRow + 1}`; + const currentUser = userService.getCurrentUser(); + + return commentService.executeCommand(AddCommentCommand.id, { + unitId, + subUnitId: sheetId, + comment: { + text: content, + attachments: [], + dT: getDT(), + id: Tools.generateRandomId(), + ref: refStr!, + personId: currentUser.userID, + parentId: currentComment?.id, + unitId, + subUnitId: sheetId, + threadId: currentComment?.threadId, + }, + }); + } + + override clearComment(): Promise { + const injector = this._injector; + const currentComment = this.getComment()?.getCommentData(); + const commentService = injector.get(ICommandService); + const unitId = this._workbook.getUnitId(); + const sheetId = this._worksheet.getSheetId(); + + if (currentComment) { + return commentService.executeCommand(DeleteCommentTreeCommand.id, { + unitId, + subUnitId: sheetId, + threadId: currentComment.threadId, + commentId: currentComment.id, + }); + } + + return Promise.resolve(true); + } +} + +FRange.extend(FRangeCommentMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FRange extends IFRangeCommentMixin {} +} diff --git a/packages/facade/src/apis/sheets/f-thread-comment.ts b/packages/sheets-thread-comment/src/facade/f-thread-comment.ts similarity index 94% rename from packages/facade/src/apis/sheets/f-thread-comment.ts rename to packages/sheets-thread-comment/src/facade/f-thread-comment.ts index e80efbac9d1..e54af51b1a7 100644 --- a/packages/facade/src/apis/sheets/f-thread-comment.ts +++ b/packages/sheets-thread-comment/src/facade/f-thread-comment.ts @@ -18,10 +18,9 @@ import type { IDocumentBody, IRange, Workbook } from '@univerjs/core'; import type { IBaseComment, IDeleteCommentCommandParams, IResolveCommentCommandParams, IThreadComment, IUpdateCommentCommandParams } from '@univerjs/thread-comment'; import { ICommandService, Inject, Injector, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { deserializeRangeWithSheet } from '@univerjs/engine-formula'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; -import { DeleteCommentCommand, DeleteCommentTreeCommand, ResolveCommentCommand, UpdateCommentCommand } from '@univerjs/thread-comment'; -import { getDT } from '@univerjs/thread-comment-ui'; -import { FRange } from './f-range'; +import { FRange } from '@univerjs/sheets/facade'; +import { DeleteCommentCommand, DeleteCommentTreeCommand, getDT, ResolveCommentCommand, UpdateCommentCommand } from '@univerjs/thread-comment'; +import { SheetsThreadCommentModel } from '../models/sheets-thread-comment.model'; export class FThreadComment { constructor( diff --git a/packages/sheets-thread-comment/src/facade/f-workbook.ts b/packages/sheets-thread-comment/src/facade/f-workbook.ts new file mode 100644 index 00000000000..6d998fa39bf --- /dev/null +++ b/packages/sheets-thread-comment/src/facade/f-workbook.ts @@ -0,0 +1,131 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IDisposable, IExecutionOptions } from '@univerjs/core'; +import type { CommentUpdate, IAddCommentCommandParams, IDeleteCommentCommandParams } from '@univerjs/thread-comment'; +import { toDisposable } from '@univerjs/core'; +import { FWorkbook } from '@univerjs/sheets/facade'; +import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, ThreadCommentModel, UpdateCommentCommand } from '@univerjs/thread-comment'; +import { filter } from 'rxjs'; + +// FIXME@weird94: this plugin should not rely on docs-ui +// eslint-disable-next-line ts/no-explicit-any +type IUpdateCommandParams = any; + +interface IFWorkbookThreadCommentMixin { + /** + * The onThreadCommentChange event is fired when the thread comment of this sheet is changed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onThreadCommentChange(callback: (commentUpdate: CommentUpdate) => void | false): IDisposable; + + /** + * The onThreadCommentChange event is fired when the thread comment of this sheet is changed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeAddThreadComment( + this: FWorkbook, + callback: (params: IAddCommentCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + + /** + * The onBeforeUpdateThreadComment event is fired before the thread comment is updated. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeUpdateThreadComment( + this: FWorkbook, + callback: (params: IUpdateCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; + + /** + * The onBeforeDeleteThreadComment event is fired before the thread comment is deleted. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeDeleteThreadComment( + this: FWorkbook, + callback: (params: IDeleteCommentCommandParams, options: IExecutionOptions | undefined) => void | false + ): IDisposable; +} + +class FWorkbookThreadCommentMixin extends FWorkbook implements IFWorkbookThreadCommentMixin { + declare _threadCommentModel: ThreadCommentModel; + + override _initialize(): void { + Object.defineProperty(this, '_threadCommentModel', { + get() { + return this._injector.get(ThreadCommentModel); + }, + }); + } + + override onThreadCommentChange(callback: (commentUpdate: CommentUpdate) => void | false): IDisposable { + return toDisposable(this._threadCommentModel.commentUpdate$ + .pipe(filter((change) => change.unitId === this._workbook.getUnitId())) + .subscribe(callback)); + } + + override onBeforeAddThreadComment(callback: (params: IAddCommentCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IAddCommentCommandParams; + if (commandInfo.id === AddCommentCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeAddThreadComment'); + } + } + })); + } + + override onBeforeUpdateThreadComment(callback: (params: IUpdateCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IUpdateCommandParams; + if (commandInfo.id === UpdateCommentCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeUpdateThreadComment'); + } + } + })); + } + + override onBeforeDeleteThreadComment(callback: (params: IDeleteCommentCommandParams, options: IExecutionOptions | undefined) => void | false): IDisposable { + return toDisposable(this._commandService.beforeCommandExecuted((commandInfo, options) => { + const params = commandInfo.params as IDeleteCommentCommandParams; + if (commandInfo.id === DeleteCommentCommand.id || commandInfo.id === DeleteCommentTreeCommand.id) { + if (params.unitId !== this._workbook.getUnitId()) { + return; + } + if (callback(params, options) === false) { + throw new Error('Command is stopped by the hook onBeforeDeleteThreadComment'); + } + } + })); + } +} + +FWorkbook.extend(FWorkbookThreadCommentMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorkbook extends IFWorkbookThreadCommentMixin {} +} diff --git a/packages/sheets-thread-comment/src/facade/f-worksheet.ts b/packages/sheets-thread-comment/src/facade/f-worksheet.ts new file mode 100644 index 00000000000..f03230dc87c --- /dev/null +++ b/packages/sheets-thread-comment/src/facade/f-worksheet.ts @@ -0,0 +1,41 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FWorksheet } from '@univerjs/sheets/facade'; +import { SheetsThreadCommentModel } from '../models/sheets-thread-comment.model'; +import { FThreadComment } from './f-thread-comment'; + +interface IFWorksheetCommentMixin { + /** + * Get all comments in the current sheet + * @returns all comments in the current sheet + */ + getComments(): FThreadComment[]; +} + +class FWorksheetCommentMixin extends FWorksheet implements IFWorksheetCommentMixin { + override getComments(): FThreadComment[] { + const sheetsTheadCommentModel = this._injector.get(SheetsThreadCommentModel); + const comments = sheetsTheadCommentModel.getSubUnitAll(this._workbook.getUnitId(), this._worksheet.getSheetId()); + return comments.map((comment) => this._injector.createInstance(FThreadComment, comment)); + } +} + +FWorksheet.extend(FWorksheetCommentMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorksheet extends IFWorksheetCommentMixin {} +} diff --git a/packages/sheets-thread-comment/src/facade/index.ts b/packages/sheets-thread-comment/src/facade/index.ts new file mode 100644 index 00000000000..fc678771721 --- /dev/null +++ b/packages/sheets-thread-comment/src/facade/index.ts @@ -0,0 +1,21 @@ +/** + * 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 './f-range'; +import './f-workbook'; +import './f-worksheet'; + +export { FThreadComment } from './f-thread-comment'; diff --git a/packages/sheets-thread-comment/src/index.ts b/packages/sheets-thread-comment/src/index.ts index 9754967a1b0..a4055cfab4c 100644 --- a/packages/sheets-thread-comment/src/index.ts +++ b/packages/sheets-thread-comment/src/index.ts @@ -14,31 +14,7 @@ * limitations under the License. */ -export { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation'; +export { SheetsThreadCommentRefRangeController } from './controllers/sheets-thread-comment-ref-range.controller'; +export { SheetsThreadCommentModel } from './models/sheets-thread-comment.model'; +export type { ISheetThreadComment } from './types/interfaces/i-sheet-thread-comment'; export { UniverSheetsThreadCommentPlugin } from './plugin'; -export { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service'; -export { SHEETS_THREAD_COMMENT } from './types/const'; - -export { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base'; -export { IThreadCommentDataSourceService } from '@univerjs/thread-comment'; - -// #region - all commands - -export { - AddCommentCommand, - DeleteCommentCommand, - DeleteCommentTreeCommand, - ResolveCommentCommand, - UpdateCommentCommand, -} from '@univerjs/thread-comment'; -export type { - IAddCommentCommandParams, - IDeleteCommentCommandParams, - IDeleteCommentTreeCommandParams, - IResolveCommentCommandParams, - IUpdateCommentCommandParams, -} from '@univerjs/thread-comment'; -export { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; -export { IThreadCommentMentionDataService } from '@univerjs/thread-comment-ui'; - -// #endregion diff --git a/packages/sheets-thread-comment-base/src/models/sheets-thread-comment.model.ts b/packages/sheets-thread-comment/src/models/sheets-thread-comment.model.ts similarity index 100% rename from packages/sheets-thread-comment-base/src/models/sheets-thread-comment.model.ts rename to packages/sheets-thread-comment/src/models/sheets-thread-comment.model.ts diff --git a/packages/sheets-thread-comment/src/plugin.ts b/packages/sheets-thread-comment/src/plugin.ts index 3d401b2e0e8..00a902c2347 100644 --- a/packages/sheets-thread-comment/src/plugin.ts +++ b/packages/sheets-thread-comment/src/plugin.ts @@ -15,70 +15,33 @@ */ import type { Dependency } from '@univerjs/core'; -import type { IUniverSheetsThreadCommentConfig } from './controllers/config.schema'; -import { DependentOn, ICommandService, IConfigService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; -import { UniverSheetsThreadCommentBasePlugin } from '@univerjs/sheets-thread-comment-base'; -import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'; -import { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation'; -import { defaultPluginConfig, PLUGIN_CONFIG_KEY } from './controllers/config.schema'; -import { SheetsThreadCommentRenderController } from './controllers/render-controllers/render.controller'; -import { SheetsThreadCommentController } from './controllers/sheets-thread-comment.controller'; -import { SheetsThreadCommentCopyPasteController } from './controllers/sheets-thread-comment-copy-paste.controller'; -import { SheetsThreadCommentHoverController } from './controllers/sheets-thread-comment-hover.controller'; -import { SheetsThreadCommentPopupController } from './controllers/sheets-thread-comment-popup.controller'; -import { ThreadCommentRemoveSheetsController } from './controllers/sheets-thread-comment-remove.controller'; -import { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service'; -import { SHEETS_THREAD_COMMENT } from './types/const'; +import { DependentOn, ICommandService, Inject, Injector, Plugin, UniverInstanceType } from '@univerjs/core'; +import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'; +import { SheetsThreadCommentRefRangeController } from './controllers/sheets-thread-comment-ref-range.controller'; +import { SheetsThreadCommentModel } from './models/sheets-thread-comment.model'; +import { SHEET_THREAD_COMMENT_BASE } from './types/const'; -@DependentOn(UniverThreadCommentUIPlugin, UniverSheetsThreadCommentBasePlugin) +@DependentOn(UniverThreadCommentPlugin) export class UniverSheetsThreadCommentPlugin extends Plugin { - static override pluginName = SHEETS_THREAD_COMMENT; + static override pluginName = SHEET_THREAD_COMMENT_BASE; static override type = UniverInstanceType.UNIVER_SHEET; constructor( - private readonly _config: Partial = defaultPluginConfig, + config: unknown, @Inject(Injector) protected override _injector: Injector, - @Inject(ICommandService) protected _commandService: ICommandService, - @IConfigService private readonly _configService: IConfigService + @Inject(ICommandService) protected _commandService: ICommandService ) { super(); - - // Manage the plugin configuration. - const { menu, ...rest } = this._config; - if (menu) { - this._configService.setConfig('menu', menu, { merge: true }); - } - this._configService.setConfig(PLUGIN_CONFIG_KEY, rest); } override onStarting(): void { ([ - [SheetsThreadCommentController], - [SheetsThreadCommentRenderController], - [SheetsThreadCommentCopyPasteController], - [SheetsThreadCommentHoverController], - [ThreadCommentRemoveSheetsController], - [SheetsThreadCommentPopupController], - [SheetsThreadCommentPopupService], + [SheetsThreadCommentModel], + [SheetsThreadCommentRefRangeController], ] as Dependency[]).forEach((dep) => { this._injector.add(dep); }); - [ShowAddSheetCommentModalOperation].forEach((command) => { - this._commandService.registerCommand(command); - }); - - this._injector.get(SheetsThreadCommentController); - } - - override onReady(): void { - this._injector.get(SheetsThreadCommentRenderController); - this._injector.get(ThreadCommentRemoveSheetsController); - } - - override onRendered(): void { - this._injector.get(SheetsThreadCommentCopyPasteController); - this._injector.get(SheetsThreadCommentHoverController); - this._injector.get(SheetsThreadCommentPopupController); + this._injector.get(SheetsThreadCommentRefRangeController); } } diff --git a/packages/sheets-thread-comment/src/types/const.ts b/packages/sheets-thread-comment/src/types/const.ts index 51726d6665d..b95c8ca064d 100644 --- a/packages/sheets-thread-comment/src/types/const.ts +++ b/packages/sheets-thread-comment/src/types/const.ts @@ -14,6 +14,4 @@ * limitations under the License. */ -export const SHEETS_THREAD_COMMENT_MODAL = 'univer.sheet.thread-comment-modal'; -export const COMMENT_SINGLE_ICON = 'comment-single'; -export const SHEETS_THREAD_COMMENT = 'SHEET_THREAD_COMMENT'; +export const SHEET_THREAD_COMMENT_BASE = 'SHEET_THREAD_COMMENT_BASE_PLUGIN'; diff --git a/packages/sheets-ui/package.json b/packages/sheets-ui/package.json index b65f3132cf9..708fb94d885 100644 --- a/packages/sheets-ui/package.json +++ b/packages/sheets-ui/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", 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 c6ed1fbf6d4..769a9a445d7 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 @@ -17,14 +17,13 @@ import type { IWorkbookData } from '@univerjs/core'; import { Disposable, DisposableCollection, ICommandService, LocaleType, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService, RenderManagerService } from '@univerjs/engine-render'; -import { SetFrozenMutation, SetSelectionsOperation } from '@univerjs/sheets'; +import { CancelFrozenCommand, SetFrozenMutation, SetSelectionsOperation } from '@univerjs/sheets'; import { SheetScrollManagerService } from '../../../services/scroll-manager.service'; import { SelectAllService } from '../../../services/select-all/select-all.service'; import { SheetSkeletonManagerService } from '../../../services/sheet-skeleton-manager.service'; import { ShortcutExperienceService } from '../../../services/shortcut-experience.service'; import { - CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand, 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 3fa6e3404f0..f4ef4189d95 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 @@ -16,12 +16,11 @@ import type { IFreeze, Injector, IWorkbookData, Univer, Workbook } from '@univerjs/core'; import { ICommandService, IUniverInstanceService, RANGE_TYPE, UniverInstanceType } from '@univerjs/core'; -import { SheetsSelectionsService } from '@univerjs/sheets'; +import { CancelFrozenCommand, SheetsSelectionsService } from '@univerjs/sheets'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { SheetScrollManagerService } from '../../../services/scroll-manager.service'; import { - CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand, 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 02798026c14..0673767ada0 100644 --- a/packages/sheets-ui/src/commands/commands/set-frozen.command.ts +++ b/packages/sheets-ui/src/commands/commands/set-frozen.command.ts @@ -132,42 +132,3 @@ export const SetColumnFrozenCommand: ICommand = { }, }; -export interface ICancelFrozenCommandParams { - unitId?: string; - subUnitId?: string; -} - -export const CancelFrozenCommand: ICommand = { - type: CommandType.COMMAND, - id: 'sheet.command.cancel-frozen', - handler: (accessor, params) => { - const commandService = accessor.get(ICommandService); - const univerInstanceService = accessor.get(IUniverInstanceService); - const undoRedoService = accessor.get(IUndoRedoService); - const target = getSheetCommandTarget(univerInstanceService, { unitId: params?.unitId, subUnitId: params?.subUnitId }); - if (!target) return false; - - const { unitId, subUnitId } = target; - - const redoMutationParams: ISetFrozenMutationParams = { - unitId, - subUnitId, - startRow: -1, - startColumn: -1, - xSplit: 0, - ySplit: 0, - }; - const undoMutationParams: ISetFrozenMutationParams = SetFrozenMutationFactory(accessor, redoMutationParams); - - const result = commandService.syncExecuteCommand(SetFrozenMutation.id, redoMutationParams); - if (result) { - undoRedoService.pushUndoRedo({ - unitID: unitId, - undoMutations: [{ id: SetFrozenMutation.id, params: undoMutationParams }], - redoMutations: [{ id: SetFrozenMutation.id, params: redoMutationParams }], - }); - return true; - } - 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 b0e34164e94..f30b1c8ab14 100644 --- a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts +++ b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts @@ -20,8 +20,8 @@ import type { DocumentDataModel, ICellData, ICommandInfo, IDisposable, IDocument import type { IRichTextEditingMutationParams } from '@univerjs/docs'; import type { IRenderContext, IRenderModule } from '@univerjs/engine-render'; import type { WorkbookSelections } from '@univerjs/sheets'; -import type { IEditorBridgeServiceVisibleParam } from '../../services/editor-bridge.service'; +import type { IEditorBridgeServiceVisibleParam } from '../../services/editor-bridge.service'; import { CellValueType, DEFAULT_EMPTY_DOCUMENT_VALUE, Direction, Disposable, DisposableCollection, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, EDITOR_ACTIVATED, FOCUSING_EDITOR_BUT_HIDDEN, @@ -56,7 +56,8 @@ import { DeviceInputEventType, IRenderManagerService, } from '@univerjs/engine-render'; -import { COMMAND_LISTENER_SKELETON_CHANGE, SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand, SetWorksheetActiveOperation, SheetsSelectionsService } from '@univerjs/sheets'; + +import { COMMAND_LISTENER_SKELETON_CHANGE, SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand, SetWorksheetActiveOperation, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets'; import { KeyCode, SetEditorResizeOperation } from '@univerjs/ui'; import { distinctUntilChanged, filter } from 'rxjs'; import { getEditorObject } from '../../basics/editor/get-editor-object'; @@ -109,7 +110,8 @@ export class EditingRenderController extends Disposable implements IRenderModule @Inject(LocaleService) protected readonly _localService: LocaleService, @IEditorService private readonly _editorService: IEditorService, @Inject(SheetCellEditorResizeService) private readonly _sheetCellEditorResizeService: SheetCellEditorResizeService, - @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService + @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, + @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService ) { super(); @@ -566,7 +568,7 @@ export class EditingRenderController extends Disposable implements IRenderModule return; } - const finalCell = await this._editorBridgeService.beforeSetRangeValue(workbook, worksheet, row, column, cellData); + const finalCell = await this._sheetInterceptorService.onWriteCell(workbook, worksheet, row, column, cellData); this._commandService.executeCommand(SetRangeValuesCommand.id, { subUnitId: sheetId, diff --git a/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts b/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts index a827506c954..f7b7364c213 100644 --- a/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts +++ b/packages/sheets-ui/src/controllers/editor/formula-editor.controller.ts @@ -38,7 +38,6 @@ import { } from '@univerjs/docs'; import { CoverContentCommand, VIEWPORT_KEY as DOC_VIEWPORT_KEY } from '@univerjs/docs-ui'; import { DeviceInputEventType, IRenderManagerService, ScrollBar } from '@univerjs/engine-render'; - import { takeUntil } from 'rxjs'; import { getEditorObject } from '../../basics/editor/get-editor-object'; import { IFormulaEditorManagerService } from '../../services/editor/formula-editor-manager.service'; diff --git a/packages/sheets-ui/src/controllers/menu.schema.ts b/packages/sheets-ui/src/controllers/menu.schema.ts index a93394dd317..c9831f311a2 100644 --- a/packages/sheets-ui/src/controllers/menu.schema.ts +++ b/packages/sheets-ui/src/controllers/menu.schema.ts @@ -20,6 +20,7 @@ import { AddWorksheetMergeCommand, AddWorksheetMergeHorizontalCommand, AddWorksheetMergeVerticalCommand, + CancelFrozenCommand, ClearSelectionAllCommand, ClearSelectionContentCommand, ClearSelectionFormatCommand, CopySheetCommand, @@ -79,7 +80,7 @@ import { import { RemoveColConfirmCommand, RemoveRowConfirmCommand } from '../commands/commands/remove-row-col-confirm.command'; import { RemoveSheetConfirmCommand } from '../commands/commands/remove-sheet-confirm.command'; import { SetOnceFormatPainterCommand } from '../commands/commands/set-format-painter.command'; -import { CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand } from '../commands/commands/set-frozen.command'; +import { SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand } from '../commands/commands/set-frozen.command'; import { SetWorksheetColAutoWidthCommand } from '../commands/commands/set-worksheet-auto-col-width.command'; import { ShowMenuListCommand } from '../commands/commands/unhide.command'; import { diff --git a/packages/sheets-ui/src/controllers/menu/menu.ts b/packages/sheets-ui/src/controllers/menu/menu.ts index da71934a3a5..206ed3b6e0f 100644 --- a/packages/sheets-ui/src/controllers/menu/menu.ts +++ b/packages/sheets-ui/src/controllers/menu/menu.ts @@ -38,6 +38,7 @@ import { import { DocSelectionManagerService, SetTextSelectionsOperation } from '@univerjs/docs'; import { SetInlineFormatCommand } from '@univerjs/docs-ui'; import { + CancelFrozenCommand, RangeProtectionPermissionEditPoint, RangeProtectionPermissionViewPoint, ResetBackgroundColorCommand, @@ -105,7 +106,6 @@ import { SetOnceFormatPainterCommand, } from '../../commands/commands/set-format-painter.command'; import { - CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand, diff --git a/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts b/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts index 1d6346a615f..61ef1e385fc 100644 --- a/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts +++ b/packages/sheets-ui/src/controllers/mobile/mobile-sheet-ui.controller.ts @@ -58,7 +58,6 @@ import { SetOnceFormatPainterCommand, } from '../../commands/commands/set-format-painter.command'; import { - CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand, @@ -235,7 +234,6 @@ export class SheetUIMobileController extends Disposable { SetSelectionFrozenCommand, SetRowFrozenCommand, SetColumnFrozenCommand, - CancelFrozenCommand, SetUnderlineCommand, SetZoomRatioCommand, SetZoomRatioOperation, diff --git a/packages/sheets-ui/src/controllers/sheet-ui.controller.ts b/packages/sheets-ui/src/controllers/sheet-ui.controller.ts index ea68dfe4ef5..90cfd46310a 100644 --- a/packages/sheets-ui/src/controllers/sheet-ui.controller.ts +++ b/packages/sheets-ui/src/controllers/sheet-ui.controller.ts @@ -63,7 +63,6 @@ import { SetOnceFormatPainterCommand, } from '../commands/commands/set-format-painter.command'; import { - CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand, @@ -202,7 +201,6 @@ export class SheetUIController extends Disposable { this.disposeWithMe(componentManager.register('HideGridlines', HideGridlines)); } - // eslint-disable-next-line max-lines-per-function private _initCommands(): void { [ AddWorksheetMergeAllCommand, @@ -251,7 +249,6 @@ export class SheetUIController extends Disposable { SetRowFrozenCommand, SetColumnFrozenCommand, ScrollToRangeOperation, - CancelFrozenCommand, SetUnderlineCommand, SetZoomRatioCommand, SetZoomRatioOperation, diff --git a/packages/sheets-ui/src/facade/f-permission.ts b/packages/sheets-ui/src/facade/f-permission.ts new file mode 100644 index 00000000000..34c473dce74 --- /dev/null +++ b/packages/sheets-ui/src/facade/f-permission.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FPermission } from '@univerjs/sheets/facade'; + +interface IFPermissionSheetsUIMixin { + /** + * Set visibility of unauthorized pop-up window + * + * @param {boolean} visible + */ + setPermissionDialogVisible(visible: boolean): void; +} + +class FPermissionSheetsUIMixin extends FPermission implements IFPermissionSheetsUIMixin { + override setPermissionDialogVisible(visible: boolean): void { + this._permissionService.setShowComponents(visible); + } +} + +FPermission.extend(FPermissionSheetsUIMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FPermission extends IFPermissionSheetsUIMixin {} +} diff --git a/packages/sheets-ui/src/facade/f-range.ts b/packages/sheets-ui/src/facade/f-range.ts new file mode 100644 index 00000000000..ace59123d40 --- /dev/null +++ b/packages/sheets-ui/src/facade/f-range.ts @@ -0,0 +1,165 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ISheetLocation } from '@univerjs/sheets'; +import type { ComponentType } from '@univerjs/ui'; +import { DisposableCollection, generateRandomId, type IDisposable, type ISelectionCellWithMergeInfo, type Nullable } from '@univerjs/core'; +import { IRenderManagerService } from '@univerjs/engine-render'; +import { FRange } from '@univerjs/sheets/facade'; +import { ComponentManager } from '@univerjs/ui'; +import { type ICanvasPopup, SheetCanvasPopManagerService } from '../services/canvas-pop-manager.service'; +import { CellAlertManagerService, type ICellAlert } from '../services/cell-alert-manager.service'; +import { ISheetClipboardService } from '../services/clipboard/clipboard.service'; +import { SheetSkeletonManagerService } from '../services/sheet-skeleton-manager.service'; + +export interface IFComponentKey { + /** + * The key of the component to be rendered in the popup. + * if key is a string, it will be query from the component registry. + * if key is a React or Vue3 component, it will be rendered directly. + */ + componentKey: string | ComponentType; + /** + * If componentKey is a Vue3 component, this must be set to true + */ + isVue3?: boolean; +} + +export interface IFCanvasPopup extends Omit, IFComponentKey { } + +interface IFRangeSheetsUIMixin { + /** + * Return this cell information, including whether it is merged and cell coordinates + * @returns The cell information + */ + getCell(): ISelectionCellWithMergeInfo; + /** + * Returns the coordinates of this cell,does not include units + * @returns coordinates of the cell, top, right, bottom, left + */ + getCellRect(): DOMRect; + /** + * Generate HTML content for the range. + */ + generateHTML(this: FRange): string; + /** + * Attach a popup to the start cell of current range. + * If current worksheet is not active, the popup will not be shown. + * Be careful to manager the detach disposable object, if not dispose correctly, it might memory leaks. + * @param popup The popup to attach + * @returns The disposable object to detach the popup, if the popup is not attached, return `null`. + */ + attachPopup(popup: IFCanvasPopup): Nullable; + /** + * Attach an alert popup to the start cell of current range. + * @param alert The alert to attach + * @returns The disposable object to detach the alert. + */ + attachAlertPopup(alert: Omit): IDisposable; + +} + +class FRangeSheetsUIMixin extends FRange implements IFRangeSheetsUIMixin { + override getCell(): ISelectionCellWithMergeInfo { + const renderManagerService = this._injector.get(IRenderManagerService); + const unitId = this._workbook.getUnitId(); + const subUnitId = this._worksheet.getSheetId(); + const skeleton = renderManagerService.getRenderById(unitId)! + .with(SheetSkeletonManagerService) + .getWorksheetSkeleton(subUnitId)!.skeleton; + return skeleton.getCellByIndex(this._range.startRow, this._range.startColumn); + } + + override getCellRect(): DOMRect { + const { startX: x, startY: y, endX: x2, endY: y2 } = this.getCell(); + const data = { x, y, width: x2 - x, height: y2 - y, top: y, left: x, bottom: y2, right: x2 }; + return { ...data, toJSON: () => JSON.stringify(data) }; + } + + override generateHTML(): string { + const copyContent = this._injector.get(ISheetClipboardService).generateCopyContent( + this._workbook.getUnitId(), + this._worksheet.getSheetId(), + this._range + ); + + return copyContent?.html ?? ''; + } + + override attachPopup(popup: IFCanvasPopup): Nullable { + const { key, disposableCollection } = transformComponentKey(popup, this._injector.get(ComponentManager)); + const sheetsPopupService = this._injector.get(SheetCanvasPopManagerService); + const disposePopup = sheetsPopupService.attachPopupToCell( + this._range.startRow, + this._range.startColumn, + { ...popup, componentKey: key }, + this.getUnitId(), + this._worksheet.getSheetId() + ); + if (disposePopup) { + disposableCollection.add(disposePopup); + return disposableCollection; + } + + disposableCollection.dispose(); + return null; + } + + override attachAlertPopup(alert: Omit): IDisposable { + const cellAlertService = this._injector.get(CellAlertManagerService); + const location: ISheetLocation = { + workbook: this._workbook, + worksheet: this._worksheet, + row: this._range.startRow, + col: this._range.startColumn, + unitId: this.getUnitId(), + subUnitId: this._worksheet.getSheetId(), + }; + cellAlertService.showAlert({ + ...alert, + location, + }); + + return { + dispose: (): void => { + cellAlertService.removeAlert(alert.key); + }, + }; + } +} + +FRange.extend(FRangeSheetsUIMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FRange extends IFRangeSheetsUIMixin {} +} + +export function transformComponentKey(component: IFComponentKey, componentManager: ComponentManager): { key: string; disposableCollection: DisposableCollection } { + const { componentKey, isVue3 } = component; + let key: string; + const disposableCollection = new DisposableCollection(); + if (typeof componentKey === 'string') { + key = componentKey; + } else { + key = `External_${generateRandomId(6)}`; + disposableCollection.add(componentManager.register(key, componentKey, { framework: isVue3 ? 'vue3' : 'react' })); + } + + return { + key, + disposableCollection, + }; +} diff --git a/packages/facade/src/apis/sheets/f-sheet-hooks.ts b/packages/sheets-ui/src/facade/f-sheet-hooks.ts similarity index 86% rename from packages/facade/src/apis/sheets/f-sheet-hooks.ts rename to packages/sheets-ui/src/facade/f-sheet-hooks.ts index d7a75f842d6..63a3f106666 100644 --- a/packages/facade/src/apis/sheets/f-sheet-hooks.ts +++ b/packages/sheets-ui/src/facade/f-sheet-hooks.ts @@ -15,17 +15,17 @@ */ import type { IDisposable, Nullable } from '@univerjs/core'; -import type { IDragCellPosition, IHoverCellPosition } from '@univerjs/sheets-ui'; - -import { ICommandService, Inject, Injector, toDisposable } from '@univerjs/core'; -import { DragManagerService, HoverManagerService } from '@univerjs/sheets-ui'; +import type { IDragCellPosition } from '../services/drag-manager.service'; +import type { IHoverCellPosition } from '../services/hover-manager.service'; +import { Inject, Injector, toDisposable } from '@univerjs/core'; +import { DragManagerService } from '../services/drag-manager.service'; +import { HoverManagerService } from '../services/hover-manager.service'; export class FSheetHooks { constructor( + @Inject(Injector) private readonly _injector: Injector, @Inject(HoverManagerService) private readonly _hoverManagerService: HoverManagerService, - @Inject(DragManagerService) private readonly _dragManagerService: DragManagerService, - @Inject(ICommandService) private readonly _commandService: ICommandService, - @Inject(Injector) private readonly _injector: Injector + @Inject(DragManagerService) private readonly _dragManagerService: DragManagerService ) { // empty } diff --git a/packages/sheets-ui/src/facade/f-univer.ts b/packages/sheets-ui/src/facade/f-univer.ts new file mode 100644 index 00000000000..5e96b495cc4 --- /dev/null +++ b/packages/sheets-ui/src/facade/f-univer.ts @@ -0,0 +1,166 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IDisposable, Nullable } from '@univerjs/core'; +import type { + IColumnsHeaderCfgParam, + IRowsHeaderCfgParam, + RenderComponentType, + SheetComponent, + SheetExtension, + SpreadsheetColumnHeader, + SpreadsheetRowHeader, +} from '@univerjs/engine-render'; +import { FUniver, toDisposable } from '@univerjs/core'; +import { IRenderManagerService } from '@univerjs/engine-render'; +import { SHEET_VIEW_KEY } from '../common/keys'; +import '@univerjs/sheets/facade'; + +interface IFUniverSheetsUIMixin { + /** + * Customize the column header of the spreadsheet. + * + * @param {IColumnsHeaderCfgParam} cfg The configuration of the column header. + * + * @example + * ```typescript + * customizeColumnHeader({ headerStyle: { backgroundColor: 'pink', fontSize: 9 }, columnsCfg: ['MokaII', undefined, null, { text: 'Size', textAlign: 'left' }] }); + * ``` + */ + customizeColumnHeader(cfg: IColumnsHeaderCfgParam): void; + /** + * Customize the row header of the spreadsheet. + * + * @param {IRowsHeaderCfgParam} cfg The configuration of the row header. + * + * @example + * ```typescript + * customizeRowHeader({ headerStyle: { backgroundColor: 'pink', fontSize: 9 }, rowsCfg: ['MokaII', undefined, null, { text: 'Size', textAlign: 'left' }] }); + * ``` + */ + customizeRowHeader(cfg: IRowsHeaderCfgParam): void; + /** + * Register sheet row header render extensions. + * + * @param {string} unitId The unit id of the spreadsheet. + * @param {SheetExtension[]} extensions The extensions to register. + * @returns {IDisposable} The disposable instance. + */ + registerSheetRowHeaderExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable; + /** + * Register sheet column header render extensions. + * + * @param {string} unitId The unit id of the spreadsheet. + * @param {SheetExtension[]} extensions The extensions to register. + * @returns {IDisposable} The disposable instance. + */ + registerSheetColumnHeaderExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable; + /** + * Register sheet main render extensions. + * + * @param {string} unitId The unit id of the spreadsheet. + * @param {SheetExtension[]} extensions The extensions to register. + * @returns {IDisposable} The disposable instance. + */ + registerSheetMainExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable; +} + +export class FUniverSheetsUIMixin extends FUniver implements IFUniverSheetsUIMixin { + override customizeColumnHeader(cfg: IColumnsHeaderCfgParam): void { + const wb = this.getActiveWorkbook(); + if (!wb) { + console.error('WorkBook not exist'); + return; + } + const unitId = wb?.getId(); + const sheetColumn = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.COLUMN) as SpreadsheetColumnHeader; + sheetColumn.setCustomHeader(cfg); + } + + override customizeRowHeader(cfg: IRowsHeaderCfgParam): void { + const wb = this.getActiveWorkbook(); + if (!wb) { + console.error('WorkBook not exist'); + return; + } + const unitId = wb?.getId(); + const sheetRow = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.ROW) as SpreadsheetRowHeader; + sheetRow.setCustomHeader(cfg); + } + + override registerSheetRowHeaderExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable { + const sheetComponent = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.ROW) as SheetComponent; + const registerDisposable = sheetComponent.register(...extensions); + + return toDisposable(() => { + registerDisposable.dispose(); + sheetComponent.makeDirty(true); + }); + } + + override registerSheetColumnHeaderExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable { + const sheetComponent = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.COLUMN) as SheetComponent; + const registerDisposable = sheetComponent.register(...extensions); + + return toDisposable(() => { + registerDisposable.dispose(); + sheetComponent.makeDirty(true); + }); + } + + override registerSheetMainExtension(unitId: string, ...extensions: SheetExtension[]): IDisposable { + const sheetComponent = this._getSheetRenderComponent(unitId, SHEET_VIEW_KEY.MAIN) as SheetComponent; + const registerDisposable = sheetComponent.register(...extensions); + + return toDisposable(() => { + registerDisposable.dispose(); + sheetComponent.makeDirty(true); + }); + } + + /** + * Get sheet render component from render by unitId and view key. + * + * @private + * + * @param {string} unitId The unit id of the spreadsheet. + * @param {SHEET_VIEW_KEY} viewKey The view key of the spreadsheet. + * @returns {Nullable} The render component. + */ + private _getSheetRenderComponent(unitId: string, viewKey: SHEET_VIEW_KEY): Nullable { + const renderManagerService = this._injector.get(IRenderManagerService); + const render = renderManagerService.getRenderById(unitId); + if (!render) { + throw new Error('Render not found'); + } + + const { components } = render; + + const renderComponent = components.get(viewKey); + if (!renderComponent) { + throw new Error('Render component not found'); + } + + return renderComponent; + } +} + +FUniver.extend(FUniverSheetsUIMixin); + +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverSheetsUIMixin { } +} diff --git a/packages/sheets-ui/src/facade/f-workbook.ts b/packages/sheets-ui/src/facade/f-workbook.ts new file mode 100644 index 00000000000..16e6d3e4df1 --- /dev/null +++ b/packages/sheets-ui/src/facade/f-workbook.ts @@ -0,0 +1,77 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { type IDisposable, ILogService } from '@univerjs/core'; +import { FWorkbook } from '@univerjs/sheets/facade'; +import { type IDialogPartMethodOptions, IDialogService, type ISidebarMethodOptions, ISidebarService } from '@univerjs/ui'; + +interface IFWorkbookSheetsUIMixin { + /** + * Open a sidebar. + * + * @deprecated + * + * @param params the sidebar options + * @returns the disposable object + */ + openSiderbar(params: ISidebarMethodOptions): IDisposable; + + /** + * Open a dialog. + * + * @deprecated + * + * @param dialog the dialog options + * @returns the disposable object + */ + openDialog(dialog: IDialogPartMethodOptions): IDisposable; +} + +class FWorokbookSheetsUIMixin extends FWorkbook implements IFWorkbookSheetsUIMixin { + override openSiderbar(params: ISidebarMethodOptions): IDisposable { + this._logDeprecation('openSiderbar'); + + const sideBarService = this._injector.get(ISidebarService); + return sideBarService.open(params); + } + + override openDialog(dialog: IDialogPartMethodOptions): IDisposable { + this._logDeprecation('openDialog'); + + const dialogService = this._injector.get(IDialogService); + const disposable = dialogService.open({ + ...dialog, + onClose: () => { + disposable.dispose(); + }, + }); + + return disposable; + } + + private _logDeprecation(name: string): void { + const logService = this._injector.get(ILogService); + + logService.warn('[FWorkbook]', `${name} is deprecated. Please use the function of the same name on "FUniver".`); + } +} + +FWorkbook.extend(FWorokbookSheetsUIMixin); +declare module '@univerjs/sheets/facade' { + // eslint-disable-next-line ts/naming-convention + interface FWorkbook extends IFWorkbookSheetsUIMixin {} +} + diff --git a/packages/sheets-ui/src/facade/index.ts b/packages/sheets-ui/src/facade/index.ts new file mode 100644 index 00000000000..209462782a6 --- /dev/null +++ b/packages/sheets-ui/src/facade/index.ts @@ -0,0 +1,22 @@ +/** + * 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 './f-univer'; +import './f-workbook'; +import './f-permission'; + +export { type IFComponentKey, transformComponentKey } from './f-range'; +export { FSheetHooks } from './f-sheet-hooks'; diff --git a/packages/sheets-ui/src/index.ts b/packages/sheets-ui/src/index.ts index f641aa22ca0..87d0c19d929 100644 --- a/packages/sheets-ui/src/index.ts +++ b/packages/sheets-ui/src/index.ts @@ -160,7 +160,7 @@ export { RefillCommand } from './commands/commands/refill.command'; export { RemoveColConfirmCommand, RemoveRowConfirmCommand } from './commands/commands/remove-row-col-confirm.command'; export { RemoveSheetConfirmCommand } from './commands/commands/remove-sheet-confirm.command'; export { ApplyFormatPainterCommand, SetInfiniteFormatPainterCommand, SetOnceFormatPainterCommand } from './commands/commands/set-format-painter.command'; -export { CancelFrozenCommand, SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand } from './commands/commands/set-frozen.command'; +export { SetColumnFrozenCommand, SetRowFrozenCommand, SetSelectionFrozenCommand } from './commands/commands/set-frozen.command'; export { type IScrollCommandParams, type IScrollToCellCommandParams, diff --git a/packages/sheets-ui/src/services/drag-manager.service.ts b/packages/sheets-ui/src/services/drag-manager.service.ts index 7dc4ff56068..a1476a9d75a 100644 --- a/packages/sheets-ui/src/services/drag-manager.service.ts +++ b/packages/sheets-ui/src/services/drag-manager.service.ts @@ -15,14 +15,14 @@ */ import type { Nullable, Workbook } from '@univerjs/core'; -import { Disposable, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; -import { distinctUntilChanged, Subject } from 'rxjs'; import type { IDragEvent } from '@univerjs/engine-render'; +import type { IHoverCellPosition } from './hover-manager.service'; +import { Disposable, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; +import { distinctUntilChanged, Subject } from 'rxjs'; import { getHoverCellPosition } from '../common/utils'; import { SheetScrollManagerService } from './scroll-manager.service'; import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service'; -import type { IHoverCellPosition } from './hover-manager.service'; export interface IDragCellPosition extends IHoverCellPosition { dataTransfer: DataTransfer; @@ -30,14 +30,14 @@ export interface IDragCellPosition extends IHoverCellPosition { export class DragManagerService extends Disposable { private _currentCell$ = new Subject>(); - currentCell$ = this._currentCell$.asObservable().pipe(distinctUntilChanged(( + currentCell$ = this._currentCell$.asObservable().pipe(distinctUntilChanged( (pre, aft) => ( pre?.location?.unitId === aft?.location?.unitId && pre?.location?.subUnitId === aft?.location?.subUnitId && pre?.location?.row === aft?.location?.row && pre?.location?.col === aft?.location?.col ) - ))); + )); private _endCell$ = new Subject>(); endCell$ = this._endCell$.asObservable(); diff --git a/packages/sheets-ui/src/services/editor-bridge.service.ts b/packages/sheets-ui/src/services/editor-bridge.service.ts index 4da73dc8d43..8163a9541ff 100644 --- a/packages/sheets-ui/src/services/editor-bridge.service.ts +++ b/packages/sheets-ui/src/services/editor-bridge.service.ts @@ -14,15 +14,14 @@ * limitations under the License. */ -import type { ICellData, ICellDataForSheetInterceptor, IDisposable, IPosition, ISelectionCell, Nullable, Workbook, Worksheet } from '@univerjs/core'; +import type { IDisposable, IPosition, ISelectionCell, Nullable, Workbook } from '@univerjs/core'; import type { Engine, IDocumentLayoutObject, Scene } from '@univerjs/engine-render'; -import type { ISheetLocation, SheetsSelectionsService } from '@univerjs/sheets'; +import type { SheetsSelectionsService } from '@univerjs/sheets'; import type { KeyCode } from '@univerjs/ui'; import type { Observable } from 'rxjs'; import { CellValueType, createIdentifier, - createInterceptorKey, Disposable, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, EDITOR_ACTIVATED, @@ -30,17 +29,15 @@ import { FOCUSING_UNIVER_EDITOR_STANDALONE_SINGLE_MODE, IContextService, Inject, - InterceptorManager, IUniverInstanceService, makeCellToSelection, ThemeService, toDisposable, - Tools, UniverInstanceType, } from '@univerjs/core'; import { getCanvasOffsetByEngine, IEditorService } from '@univerjs/docs-ui'; import { convertTextRotation, DeviceInputEventType, IRenderManagerService } from '@univerjs/engine-render'; -import { IRefSelectionsService } from '@univerjs/sheets'; +import { BEFORE_CELL_EDIT, IRefSelectionsService, SheetInterceptorService } from '@univerjs/sheets'; import { BehaviorSubject, map, switchMap } from 'rxjs'; import { ISheetSelectionRenderService } from './selection/base-selection-render.service'; import { attachPrimaryWithCoord } from './selection/util'; @@ -82,25 +79,13 @@ export interface IEditorBridgeServiceParam extends ICellEditorState, ICellEditor } -interface ISheetLocationForEditor extends ISheetLocation { - origin: Nullable; -} - -const BEFORE_CELL_EDIT = createInterceptorKey('BEFORE_CELL_EDIT'); -const AFTER_CELL_EDIT = createInterceptorKey('AFTER_CELL_EDIT'); -const AFTER_CELL_EDIT_ASYNC = createInterceptorKey>, ISheetLocationForEditor>('AFTER_CELL_EDIT_ASYNC'); - export interface IEditorBridgeService { currentEditCellState$: Observable>; currentEditCellLayout$: Observable>; currentEditCell$: Observable>; visible$: Observable; - interceptor: InterceptorManager<{ - BEFORE_CELL_EDIT: typeof BEFORE_CELL_EDIT; - AFTER_CELL_EDIT: typeof AFTER_CELL_EDIT; - AFTER_CELL_EDIT_ASYNC: typeof AFTER_CELL_EDIT_ASYNC; - }>; + dispose(): void; refreshEditCellState(): void; refreshEditCellPosition(resetSizeOnly?: boolean): void; @@ -118,8 +103,6 @@ export interface IEditorBridgeService { disableForceKeepVisible(): void; isForceKeepVisible(): boolean; getCurrentEditorId(): Nullable; - - beforeSetRangeValue(workbook: Workbook, worksheet: Worksheet, row: number, column: number, cellData: ICellData): Promise>; } export class EditorBridgeService extends Disposable implements IEditorBridgeService, IDisposable { @@ -157,13 +140,8 @@ export class EditorBridgeService extends Disposable implements IEditorBridgeServ private readonly _afterVisible$ = new BehaviorSubject(this._visible); readonly afterVisible$ = this._afterVisible$.asObservable(); - readonly interceptor = new InterceptorManager({ - BEFORE_CELL_EDIT, - AFTER_CELL_EDIT, - AFTER_CELL_EDIT_ASYNC, - }); - constructor( + @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @Inject(ThemeService) private readonly _themeService: ThemeService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, @@ -178,21 +156,6 @@ export class EditorBridgeService extends Disposable implements IEditorBridgeServ this._currentEditCell = null; })); - this.disposeWithMe(this.interceptor.intercept(this.interceptor.getInterceptPoints().AFTER_CELL_EDIT, { - priority: -1, - handler: (_value) => _value, - })); - - this.disposeWithMe(this.interceptor.intercept(this.interceptor.getInterceptPoints().BEFORE_CELL_EDIT, { - priority: -1, - handler: (_value) => _value, - })); - - this.disposeWithMe(this.interceptor.intercept(this.interceptor.getInterceptPoints().AFTER_CELL_EDIT_ASYNC, { - priority: -1, - handler: (_value) => _value, - })); - this._univerInstanceService.getTypeOfUnitDisposed$(UniverInstanceType.UNIVER_SHEET).subscribe((unit) => { if (unit.getUnitId() === this._currentEditCellState?.unitId) { this._clearCurrentEditCellState(); @@ -379,7 +342,7 @@ export class EditorBridgeService extends Disposable implements IEditorBridgeServ }; let documentLayoutObject: Nullable; - const cell = this.interceptor.fetchThroughInterceptors(this.interceptor.getInterceptPoints().BEFORE_CELL_EDIT)( + const cell = this._sheetInterceptorService.writeCellInterceptor.fetchThroughInterceptors(BEFORE_CELL_EDIT)( worksheet.getCell(startRow, startColumn), location ); @@ -497,28 +460,6 @@ export class EditorBridgeService extends Disposable implements IEditorBridgeServ getEditorDirty() { return this._editorIsDirty; } - - async beforeSetRangeValue(workbook: Workbook, worksheet: Worksheet, row: number, column: number, cellData: ICellData) { - const context = { - subUnitId: worksheet.getSheetId(), - unitId: workbook.getUnitId(), - workbook: workbook!, - worksheet, - row, - col: column, - origin: Tools.deepClone(cellData), - }; - const cell = this.interceptor.fetchThroughInterceptors( - this.interceptor.getInterceptPoints().AFTER_CELL_EDIT - )(cellData, context); - - const finalCell = await this.interceptor.fetchThroughInterceptors( - this.interceptor.getInterceptPoints().AFTER_CELL_EDIT_ASYNC - )(Promise.resolve(cell), context); - - // remove temp value - return finalCell; - } } export const IEditorBridgeService = createIdentifier('univer.sheet-editor-bridge.service'); diff --git a/packages/sheets/package.json b/packages/sheets/package.json index e8f66595a9c..ec3e445d13f 100644 --- a/packages/sheets/package.json +++ b/packages/sheets/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/sheets/src/commands/commands/set-frozen-cancel.command.ts b/packages/sheets/src/commands/commands/set-frozen-cancel.command.ts deleted file mode 100644 index 0f82ec608b5..00000000000 --- a/packages/sheets/src/commands/commands/set-frozen-cancel.command.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright 2023-present DreamNum Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { CommandType, ICommandService, IUndoRedoService, IUniverInstanceService } from '@univerjs/core'; -import type { IAccessor, ICommand } from '@univerjs/core'; - -import { SetFrozenMutation, SetFrozenMutationFactory } from '../mutations/set-frozen.mutation'; -import { getSheetCommandTarget } from './utils/target-util'; -import type { ISetFrozenMutationParams } from '../mutations/set-frozen.mutation'; - -export const SetFrozenCancelCommand: ICommand = { - type: CommandType.COMMAND, - id: 'sheet.command.set-frozen-cancel', - handler: (accessor: IAccessor) => { - const commandService = accessor.get(ICommandService); - const undoRedoService = accessor.get(IUndoRedoService); - const univerInstanceService = accessor.get(IUniverInstanceService); - - const target = getSheetCommandTarget(univerInstanceService); - if (!target) return false; - - const { unitId, subUnitId } = target; - const redoMutationParams: ISetFrozenMutationParams = { - unitId, - subUnitId, - startRow: -1, - startColumn: -1, - ySplit: 0, - xSplit: 0, - }; - - const undoMutationParams: ISetFrozenMutationParams = SetFrozenMutationFactory(accessor, redoMutationParams); - const result = commandService.syncExecuteCommand(SetFrozenMutation.id, redoMutationParams); - - if (result) { - undoRedoService.pushUndoRedo({ - unitID: unitId, - undoMutations: [{ id: SetFrozenMutation.id, params: undoMutationParams }], - redoMutations: [{ id: SetFrozenMutation.id, params: redoMutationParams }], - }); - return true; - } - return false; - }, -}; diff --git a/packages/sheets/src/commands/commands/set-frozen.command.ts b/packages/sheets/src/commands/commands/set-frozen.command.ts index 3aad298bf56..4af7738983e 100644 --- a/packages/sheets/src/commands/commands/set-frozen.command.ts +++ b/packages/sheets/src/commands/commands/set-frozen.command.ts @@ -14,14 +14,13 @@ * limitations under the License. */ -import { CommandType, ICommandService, IUndoRedoService, IUniverInstanceService } from '@univerjs/core'; import type { IAccessor, ICommand } from '@univerjs/core'; - +import type { ISetFrozenMutationParams } from '../mutations/set-frozen.mutation'; +import { CommandType, ICommandService, IUndoRedoService, IUniverInstanceService } from '@univerjs/core'; import { SetFrozenMutation, SetFrozenMutationFactory } from '../mutations/set-frozen.mutation'; import { getSheetCommandTarget } from './utils/target-util'; -import type { ISetFrozenMutationParams } from '../mutations/set-frozen.mutation'; -interface ISetFrozenCommandParams { +export interface ISetFrozenCommandParams { startRow: number; startColumn: number; ySplit: number; @@ -72,3 +71,43 @@ export const SetFrozenCommand: ICommand = { return false; }, }; + +export interface ICancelFrozenCommandParams { + unitId?: string; + subUnitId?: string; +} + +export const CancelFrozenCommand: ICommand = { + type: CommandType.COMMAND, + id: 'sheet.command.cancel-frozen', + handler: (accessor, params) => { + const commandService = accessor.get(ICommandService); + const univerInstanceService = accessor.get(IUniverInstanceService); + const undoRedoService = accessor.get(IUndoRedoService); + const target = getSheetCommandTarget(univerInstanceService, { unitId: params?.unitId, subUnitId: params?.subUnitId }); + if (!target) return false; + + const { unitId, subUnitId } = target; + + const redoMutationParams: ISetFrozenMutationParams = { + unitId, + subUnitId, + startRow: -1, + startColumn: -1, + xSplit: 0, + ySplit: 0, + }; + const undoMutationParams: ISetFrozenMutationParams = SetFrozenMutationFactory(accessor, redoMutationParams); + + const result = commandService.syncExecuteCommand(SetFrozenMutation.id, redoMutationParams); + if (result) { + undoRedoService.pushUndoRedo({ + unitID: unitId, + undoMutations: [{ id: SetFrozenMutation.id, params: undoMutationParams }], + redoMutations: [{ id: SetFrozenMutation.id, params: redoMutationParams }], + }); + return true; + } + return true; + }, +}; diff --git a/packages/sheets/src/controllers/basic-worksheet.controller.ts b/packages/sheets/src/controllers/basic-worksheet.controller.ts index 7da9e971b70..b6dac6910af 100644 --- a/packages/sheets/src/controllers/basic-worksheet.controller.ts +++ b/packages/sheets/src/controllers/basic-worksheet.controller.ts @@ -59,8 +59,7 @@ import { SetSpecificColsVisibleCommand, } from '../commands/commands/set-col-visible.command'; import { SetDefinedNameCommand } from '../commands/commands/set-defined-name.command'; -import { SetFrozenCommand } from '../commands/commands/set-frozen.command'; -import { SetFrozenCancelCommand } from '../commands/commands/set-frozen-cancel.command'; +import { CancelFrozenCommand, SetFrozenCommand } from '../commands/commands/set-frozen.command'; import { SetRangeProtectionCommand } from '../commands/commands/set-range-protection.command'; import { SetRangeValuesCommand } from '../commands/commands/set-range-values.command'; import { SetRowDataCommand } from '../commands/commands/set-row-data.command'; @@ -224,9 +223,9 @@ export class BasicWorksheetController extends Disposable implements IDisposable SetColWidthCommand, SetColDataCommand, SetColDataMutation, - SetFrozenCancelCommand, SetFrozenCommand, SetFrozenMutation, + CancelFrozenCommand, SetHorizontalTextAlignCommand, SetRangeValuesCommand, SetRowHeightCommand, diff --git a/packages/facade/src/apis/sheets/__tests__/utils.spec.ts b/packages/sheets/src/facade/__tests__/utils.spec.ts similarity index 99% rename from packages/facade/src/apis/sheets/__tests__/utils.spec.ts rename to packages/sheets/src/facade/__tests__/utils.spec.ts index 40c880bc723..4b723b0b438 100644 --- a/packages/facade/src/apis/sheets/__tests__/utils.spec.ts +++ b/packages/sheets/src/facade/__tests__/utils.spec.ts @@ -15,7 +15,6 @@ */ import { describe, expect, it } from 'vitest'; - import { covertCellValue, covertCellValues } from '../utils'; describe('Test utils', () => { diff --git a/packages/facade/src/apis/sheets/f-permission.ts b/packages/sheets/src/facade/f-permission.ts similarity index 93% rename from packages/facade/src/apis/sheets/f-permission.ts rename to packages/sheets/src/facade/f-permission.ts index 459d36f0056..a8d1b53ac1c 100644 --- a/packages/facade/src/apis/sheets/f-permission.ts +++ b/packages/sheets/src/facade/f-permission.ts @@ -15,20 +15,20 @@ */ import type { IRange, RangePermissionPointConstructor, WorkbookPermissionPointConstructor, WorkSheetPermissionPointConstructor } from '@univerjs/core'; -import { generateRandomId, IAuthzIoService, ICommandService, Inject, Injector, IPermissionService, Rectangle } from '@univerjs/core'; +import { FBase, generateRandomId, IAuthzIoService, ICommandService, Inject, Injector, IPermissionService, Rectangle } from '@univerjs/core'; import { AddRangeProtectionMutation, AddWorksheetProtectionMutation, DeleteRangeProtectionMutation, DeleteWorksheetProtectionMutation, getAllWorksheetPermissionPoint, getAllWorksheetPermissionPointByPointPanel, RangeProtectionRuleModel, SetRangeProtectionMutation, SetWorksheetPermissionPointsMutation, UnitObject, WorkbookEditablePermission, WorksheetEditPermission, WorksheetProtectionPointModel, WorksheetProtectionRuleModel, WorksheetViewPermission } from '@univerjs/sheets'; -export class FPermission { +export class FPermission extends FBase { constructor( - @Inject(Injector) private readonly _injector: Injector, - @ICommandService private readonly _commandService: ICommandService, - @IPermissionService private readonly _permissionService: IPermissionService, - @Inject(WorksheetProtectionRuleModel) private readonly _worksheetProtectionRuleModel: WorksheetProtectionRuleModel, - @Inject(RangeProtectionRuleModel) private readonly _rangeProtectionRuleModel: RangeProtectionRuleModel, - @Inject(WorksheetProtectionPointModel) private readonly _worksheetProtectionPointRuleModel: WorksheetProtectionPointModel, - @Inject(IAuthzIoService) private readonly _authzIoService: IAuthzIoService + @Inject(Injector) protected readonly _injector: Injector, + @ICommandService protected readonly _commandService: ICommandService, + @IPermissionService protected readonly _permissionService: IPermissionService, + @Inject(WorksheetProtectionRuleModel) protected readonly _worksheetProtectionRuleModel: WorksheetProtectionRuleModel, + @Inject(RangeProtectionRuleModel) protected readonly _rangeProtectionRuleModel: RangeProtectionRuleModel, + @Inject(WorksheetProtectionPointModel) protected readonly _worksheetProtectionPointRuleModel: WorksheetProtectionPointModel, + @Inject(IAuthzIoService) protected readonly _authzIoService: IAuthzIoService ) { - // empty + super(); } /** @@ -289,13 +289,4 @@ export class FPermission { }); } } - - /** - * Set visibility of unauthorized pop-up window - * - * @param {boolean} visible - */ - setPermissionDialogVisible(visible: boolean): void { - this._permissionService.setShowComponents(visible); - } } diff --git a/packages/facade/src/apis/sheets/f-range.ts b/packages/sheets/src/facade/f-range.ts similarity index 52% rename from packages/facade/src/apis/sheets/f-range.ts rename to packages/sheets/src/facade/f-range.ts index e1439533de6..9249cc0aa29 100644 --- a/packages/facade/src/apis/sheets/f-range.ts +++ b/packages/sheets/src/facade/f-range.ts @@ -14,100 +14,32 @@ * limitations under the License. */ -import type { - CellValue, - DataValidationStatus, - ICellData, - IColorStyle, - IDisposable, - IDocumentBody, - IObjectMatrixPrimitiveType, - IRange, - ISelectionCellWithMergeInfo, - IStyleData, - ITextDecoration, - Nullable, - Workbook, - Worksheet, -} from '@univerjs/core'; -import type { - ISetHorizontalTextAlignCommandParams, - ISetStyleCommandParams, - ISetTextWrapCommandParams, - ISetVerticalTextAlignCommandParams, - ISheetLocation, - IStyleTypeValue, -} from '@univerjs/sheets'; -import type { IAddSheetDataValidationCommandParams, IClearRangeDataValidationCommandParams } from '@univerjs/sheets-data-validation'; -import type { FilterModel } from '@univerjs/sheets-filter'; -import type { ISetSheetFilterRangeCommandParams } from '@univerjs/sheets-filter-ui'; -import type { IAddHyperLinkCommandParams, ICancelHyperLinkCommandParams, IUpdateHyperLinkCommandParams } from '@univerjs/sheets-hyper-link-ui'; -import type { ISetNumfmtCommandParams } from '@univerjs/sheets-numfmt'; -import type { ICanvasPopup, ICellAlert } from '@univerjs/sheets-ui'; -import type { FHorizontalAlignment, FVerticalAlignment, IFComponentKey } from './utils'; -import { BooleanNumber, CustomRangeType, Dimension, generateRandomId, ICommandService, Inject, Injector, Tools, UserManagerService, WrapStrategy } from '@univerjs/core'; +import type { CellValue, ICellData, IColorStyle, IObjectMatrixPrimitiveType, IRange, IStyleData, ITextDecoration, Nullable, Workbook, Worksheet } from '@univerjs/core'; +import type { ISetHorizontalTextAlignCommandParams, ISetStyleCommandParams, ISetTextWrapCommandParams, ISetVerticalTextAlignCommandParams, IStyleTypeValue } from '../commands/commands/set-style.command'; +import type { FHorizontalAlignment, FVerticalAlignment } from './utils'; +import { BooleanNumber, Dimension, FBase, ICommandService, Inject, Injector, Rectangle, WrapStrategy } from '@univerjs/core'; import { FormulaDataModel } from '@univerjs/engine-formula'; -import { IRenderManagerService } from '@univerjs/engine-render'; -import { - addMergeCellsUtil, - getAddMergeMutationRangeByType, - RemoveWorksheetMergeCommand, - SetHorizontalTextAlignCommand, - SetRangeValuesCommand, - SetStyleCommand, - SetTextWrapCommand, - SetVerticalTextAlignCommand, -} from '@univerjs/sheets'; -import { AddSheetDataValidationCommand, ClearRangeDataValidationCommand, SheetsDataValidationValidatorService } from '@univerjs/sheets-data-validation'; -import { SheetsFilterService } from '@univerjs/sheets-filter'; -import { SetSheetFilterRangeCommand } from '@univerjs/sheets-filter-ui'; -import { AddHyperLinkCommand, CancelHyperLinkCommand, UpdateHyperLinkCommand } from '@univerjs/sheets-hyper-link-ui'; -import { SetNumfmtCommand } from '@univerjs/sheets-numfmt'; -import { AddCommentCommand, DeleteCommentTreeCommand, SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; -import { CellAlertManagerService, ISheetClipboardService, SheetCanvasPopManagerService, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; -import { getDT } from '@univerjs/thread-comment-ui'; -import { ComponentManager } from '@univerjs/ui'; -import { FDataValidation } from './f-data-validation'; -import { FFilter } from './f-filter'; -import { FThreadComment } from './f-thread-comment'; -import { - covertCellValue, - covertCellValues, - isCellMerged, - transformComponentKey, - transformCoreHorizontalAlignment, - transformCoreVerticalAlignment, - transformFacadeHorizontalAlignment, - transformFacadeVerticalAlignment, -} from './utils'; +import { addMergeCellsUtil } from '../commands/commands/add-worksheet-merge.command'; +import { RemoveWorksheetMergeCommand } from '../commands/commands/remove-worksheet-merge.command'; +import { SetRangeValuesCommand } from '../commands/commands/set-range-values.command'; +import { SetHorizontalTextAlignCommand, SetStyleCommand, SetTextWrapCommand, SetVerticalTextAlignCommand } from '../commands/commands/set-style.command'; +import { getAddMergeMutationRangeByType } from '../controllers/merge-cell.controller'; +import { covertCellValue, covertCellValues, transformCoreHorizontalAlignment, transformCoreVerticalAlignment, transformFacadeHorizontalAlignment, transformFacadeVerticalAlignment } from './utils'; export type FontLine = 'none' | 'underline' | 'line-through'; export type FontStyle = 'normal' | 'italic'; export type FontWeight = 'normal' | 'bold'; -export interface IFCanvasPopup extends Omit, IFComponentKey { - -} - -export interface ICellHyperLink { - id: string; - startIndex: number; - endIndex: number; - url: string; - label: string; -} - -export class FRange { +export class FRange extends FBase { constructor( - private readonly _workbook: Workbook, - private readonly _worksheet: Worksheet, - private readonly _range: IRange, - @Inject(Injector) private readonly _injector: Injector, - @ICommandService private readonly _commandService: ICommandService, - @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @Inject(FormulaDataModel) private readonly _formulaDataModel: FormulaDataModel + protected readonly _workbook: Workbook, + protected readonly _worksheet: Worksheet, + protected readonly _range: IRange, + @Inject(Injector) protected readonly _injector: Injector, + @ICommandService protected readonly _commandService: ICommandService, + @Inject(FormulaDataModel) protected readonly _formulaDataModel: FormulaDataModel ) { - // empty + super(); } /** @@ -181,35 +113,14 @@ export class FRange { return this._worksheet.getCell(this._range.startRow, this._range.startColumn) ?? null; } - /** - * Return this cell information, including whether it is merged and cell coordinates - * @returns The cell information - */ - getCell(): ISelectionCellWithMergeInfo { - const unitId = this._workbook.getUnitId(); - const subUnitId = this._worksheet.getSheetId(); - const skeleton = this._renderManagerService.getRenderById(unitId)! - .with(SheetSkeletonManagerService) - .getWorksheetSkeleton(subUnitId)!.skeleton; - return skeleton.getCellByIndex(this._range.startRow, this._range.startColumn); - } - /** * Return range whether this range is merged * @returns if true is merged */ isMerged(): boolean { - return isCellMerged(this.getCell().mergeInfo, this._range); - } - - /** - * Returns the coordinates of this cell,does not include units - * @returns coordinates of the cell, top, right, bottom, left - */ - getCellRect(): DOMRect { - const { startX: x, startY: y, endX: x2, endY: y2 } = this.getCell(); - const data = { x, y, width: x2 - x, height: y2 - y, top: y, left: x, bottom: y2, right: x2 }; - return { ...data, toJSON: () => JSON.stringify(data) }; + const { startColumn, startRow, endColumn, endRow } = this._range; + const mergedCells = this._worksheet.getMergedCellRange(startRow, startColumn, endRow, endColumn); + return mergedCells.some((range) => Rectangle.equals(range, this._range)); } /** @@ -398,23 +309,6 @@ export class FRange { } as ISetHorizontalTextAlignCommandParams); } - /** - * Set the number format of the range. - * @param pattern number format pattern. - * @returns Execution result. - */ - setNumberFormat(pattern: string): Promise { - // TODO@Gggpound: the API should support other types of parameters - const values: ISetNumfmtCommandParams['values'] = []; - - // Add number format info to the `values` array. - this.forEach((row, col) => values.push({ row, col, pattern })); - return this._commandService.executeCommand(SetNumfmtCommand.id, { - unitId: this._workbook.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - } as ISetNumfmtCommandParams); - } - /** * Sets a different value for each cell in the range. The value can be a two-dimensional array or a standard range matrix (must match the dimensions of this range), consisting of numbers, strings, Boolean values or Composed of standard cell formats. If a value begins with `=`, it is interpreted as a formula. * @param value @@ -634,287 +528,6 @@ export class FRange { // #endregion editing - /** - * Iterate cells in this range. Merged cells will be respected. - * @param callback - */ - forEach(callback: (row: number, col: number, cell: ICellData) => void): void { - // Iterate each cell in this range. - const { startColumn, startRow, endColumn, endRow } = this._range; - this._worksheet - .getMatrixWithMergedCells(startRow, startColumn, endRow, endColumn) - .forValue((row, col, value) => { - callback(row, col, value); - }); - } - - /** - * Generate HTML content for the range. - */ - generateHTML(): string { - const copyContent = this._injector.get(ISheetClipboardService).generateCopyContent( - this._workbook.getUnitId(), - this._worksheet.getSheetId(), - this._range - ); - - return copyContent?.html ?? ''; - } - - // #region DataValidation - - /** - * set a data validation rule to current range - * @param rule data validation rule, build by `FUniver.newDataValidation` - * @returns current range - */ - setDataValidation(rule: Nullable): this { - if (!rule) { - this._commandService.syncExecuteCommand(ClearRangeDataValidationCommand.id, { - unitId: this._workbook.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - ranges: [this._range], - } as IClearRangeDataValidationCommandParams); - return this; - } - - const params: IAddSheetDataValidationCommandParams = { - unitId: this._workbook.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - rule: { - ...rule.rule, - ranges: [this._range], - }, - }; - - this._commandService.syncExecuteCommand(AddSheetDataValidationCommand.id, params); - return this; - } - - /** - * get first data validation rule in current range - * @returns data validation rule - */ - getDataValidation(): Nullable { - const validatorService = this._injector.get(SheetsDataValidationValidatorService); - const rule = validatorService.getDataValidation( - this._workbook.getUnitId(), - this._worksheet.getSheetId(), - [this._range] - ); - - if (rule) { - return new FDataValidation(rule); - } - - return rule; - } - - /** - * get all data validation rules in current range - * @returns all data validation rules - */ - getDataValidations(): FDataValidation[] { - const validatorService = this._injector.get(SheetsDataValidationValidatorService); - return validatorService.getDataValidations( - this._workbook.getUnitId(), - this._worksheet.getSheetId(), - [this._range] - ).map((rule) => new FDataValidation(rule)); - } - - /** - * get data validation validator status for current range - * @returns matrix of validator status - */ - async getValidatorStatus(): Promise[][]> { - const validatorService = this._injector.get(SheetsDataValidationValidatorService); - return validatorService.validatorRanges( - this._workbook.getUnitId(), - this._worksheet.getSheetId(), - [this._range] - ); - } - - // #endregion - - // #region Filter - - /** - * Create a filter for the current range. If the worksheet already has a filter, this method would return `null`. - * - * @async - * - * @return The interface class to handle the filter. If the worksheet already has a filter, - * this method would return `null`. - */ - async createFilter(): Promise { - if (this._getFilterModel()) return null; - - const success = await this._commandService.executeCommand(SetSheetFilterRangeCommand.id, { - unitId: this._workbook.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - range: this._range, - }); - - if (!success) return null; - - return this.getFilter(); - } - - /** - * Get the filter for the current range's worksheet. - * - * @return {FFilter | null} The interface class to handle the filter. If the worksheet does not have a filter, - * this method would return `null`. - */ - getFilter(): FFilter | null { - const filterModel = this._getFilterModel(); - if (!filterModel) return null; - - return this._injector.createInstance(FFilter, this._workbook, this._worksheet, filterModel); - } - - private _getFilterModel(): Nullable { - return this._injector.get(SheetsFilterService).getFilterModel( - this._workbook.getUnitId(), - this._worksheet.getSheetId() - ); - } - - // #endregion - - /** - * Attach a popup to the start cell of current range. - * If current worksheet is not active, the popup will not be shown. - * Be careful to manager the detach disposable object, if not dispose correctly, it might memory leaks. - * @param popup The popup to attach - * @returns The disposable object to detach the popup, if the popup is not attached, return `null`. - */ - attachPopup(popup: IFCanvasPopup): Nullable { - const { key, disposableCollection } = transformComponentKey(popup, this._injector.get(ComponentManager)); - const sheetsPopupService = this._injector.get(SheetCanvasPopManagerService); - const disposePopup = sheetsPopupService.attachPopupToCell( - this._range.startRow, - this._range.startColumn, - { ...popup, componentKey: key }, - this.getUnitId(), - this._worksheet.getSheetId() - ); - if (disposePopup) { - disposableCollection.add(disposePopup); - return disposableCollection; - } - - disposableCollection.dispose(); - return null; - } - - /** - * Attach an alert popup to the start cell of current range. - * @param alert The alert to attach - * @returns The disposable object to detach the alert. - */ - attachAlertPopup(alert: Omit): IDisposable { - const cellAlertService = this._injector.get(CellAlertManagerService); - const location: ISheetLocation = { - workbook: this._workbook, - worksheet: this._worksheet, - row: this._range.startRow, - col: this._range.startColumn, - unitId: this.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - }; - cellAlertService.showAlert({ - ...alert, - location, - }); - - return { - dispose: (): void => { - cellAlertService.removeAlert(alert.key); - }, - }; - } - - /** - * Get the comment of the start cell in the current range. - * @returns The comment of the start cell in the current range. If the cell does not have a comment, return `null`. - */ - getComment(): Nullable { - const injector = this._injector; - const sheetsTheadCommentModel = injector.get(SheetsThreadCommentModel); - const unitId = this._workbook.getUnitId(); - const sheetId = this._worksheet.getSheetId(); - const commentId = sheetsTheadCommentModel.getByLocation(unitId, sheetId, this._range.startRow, this._range.startColumn); - if (!commentId) { - return null; - } - - const comment = sheetsTheadCommentModel.getComment(unitId, sheetId, commentId); - if (comment) { - return this._injector.createInstance(FThreadComment, comment); - } - - return null; - } - - /** - * Add a comment to the start cell in the current range. - * @param content The content of the comment. - * @returns Whether the comment is added successfully. - */ - addComment(content: IDocumentBody): Promise { - const injector = this._injector; - const currentComment = this.getComment()?.getCommentData(); - const commentService = injector.get(ICommandService); - const userService = injector.get(UserManagerService); - const unitId = this._workbook.getUnitId(); - const sheetId = this._worksheet.getSheetId(); - const refStr = `${Tools.chatAtABC(this._range.startColumn)}${this._range.startRow + 1}`; - const currentUser = userService.getCurrentUser(); - - return commentService.executeCommand(AddCommentCommand.id, { - unitId, - subUnitId: sheetId, - comment: { - text: content, - attachments: [], - dT: getDT(), - id: Tools.generateRandomId(), - ref: refStr!, - personId: currentUser.userID, - parentId: currentComment?.id, - unitId, - subUnitId: sheetId, - threadId: currentComment?.threadId, - }, - }); - } - - /** - * Clear the comment of the start cell in the current range. - * @returns Whether the comment is cleared successfully. - */ - clearComment(): Promise { - const injector = this._injector; - const currentComment = this.getComment()?.getCommentData(); - const commentService = injector.get(ICommandService); - const unitId = this._workbook.getUnitId(); - const sheetId = this._worksheet.getSheetId(); - - if (currentComment) { - return commentService.executeCommand(DeleteCommentTreeCommand.id, { - unitId, - subUnitId: sheetId, - threadId: currentComment.threadId, - commentId: currentComment.id, - }); - } - - return Promise.resolve(true); - } - //#region Merge cell /** @@ -975,90 +588,20 @@ export class FRange { this._commandService.executeCommand(RemoveWorksheetMergeCommand.id, { ranges: [this._range] }); return this; } - //#endregion - - // #region hyperlink - /** - * Set a hyperlink to the cell in the range. - * @param url url - * @param label optional, label of the url - * @returns success or not - */ - setHyperLink(url: string, label?: string): Promise { - const params: IAddHyperLinkCommandParams = { - unitId: this.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - link: { - row: this._range.startRow, - column: this._range.startColumn, - payload: url, - display: label, - id: generateRandomId(), - }, - }; - - return this._commandService.executeCommand(AddHyperLinkCommand.id, params); - } - - /** - * Get all hyperlinks in the cell in the range. - * @returns hyperlinks - */ - getHyperLinks(): ICellHyperLink[] { - const cellValue = this._worksheet.getCellRaw(this._range.startRow, this._range.startColumn); - if (!cellValue?.p) { - return []; - } - - return cellValue.p.body?.customRanges - ?.filter((range) => range.rangeType === CustomRangeType.HYPERLINK) - .map((range) => ({ - id: range.rangeId, - startIndex: range.startIndex, - endIndex: range.endIndex, - url: range.properties?.url ?? '', - label: cellValue.p?.body?.dataStream.slice(range.startIndex + 1, range.endIndex) ?? '', - })) ?? []; - } - /** - * Update hyperlink in the cell in the range. - * @param id id of the hyperlink - * @param url url - * @param label optional, label of the url - * @returns success or not - */ - updateHyperLink(id: string, url: string, label?: string): Promise { - const params: IUpdateHyperLinkCommandParams = { - unitId: this.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - row: this._range.startRow, - column: this._range.startColumn, - id, - payload: { - payload: url, - display: label, - }, - }; - - return this._commandService.executeCommand(UpdateHyperLinkCommand.id, params); - } + //#endregion /** - * Cancel hyperlink in the cell in the range. - * @param id id of the hyperlink - * @returns success or not + * Iterate cells in this range. Merged cells will be respected. + * @param callback */ - cancelHyperLink(id: string): Promise { - const params: ICancelHyperLinkCommandParams = { - unitId: this.getUnitId(), - subUnitId: this._worksheet.getSheetId(), - row: this._range.startRow, - column: this._range.startColumn, - id, - }; - - return this._commandService.executeCommand(CancelHyperLinkCommand.id, params); + forEach(callback: (row: number, col: number, cell: ICellData) => void): void { + // Iterate each cell in this range. + const { startColumn, startRow, endColumn, endRow } = this._range; + this._worksheet + .getMatrixWithMergedCells(startRow, startColumn, endRow, endColumn) + .forValue((row, col, value) => { + callback(row, col, value); + }); } - // #endregion } diff --git a/packages/facade/src/apis/sheets/f-selection.ts b/packages/sheets/src/facade/f-selection.ts similarity index 99% rename from packages/facade/src/apis/sheets/f-selection.ts rename to packages/sheets/src/facade/f-selection.ts index 67b2adf84a7..b533eef70c9 100644 --- a/packages/facade/src/apis/sheets/f-selection.ts +++ b/packages/sheets/src/facade/f-selection.ts @@ -39,3 +39,4 @@ export class FSelection { return this._injector.createInstance(FRange, this._workbook, this._worksheet, active.range); } } + diff --git a/packages/sheets/src/facade/f-univer.ts b/packages/sheets/src/facade/f-univer.ts new file mode 100644 index 00000000000..6151de774c8 --- /dev/null +++ b/packages/sheets/src/facade/f-univer.ts @@ -0,0 +1,76 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IWorkbookData, Workbook } from '@univerjs/core'; +import { FUniver, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { FPermission } from './f-permission'; +import { FWorkbook } from './f-workbook'; + +interface IFUniverSheetsMixin { + /** + * Create a new spreadsheet and get the API handler of that spreadsheet. + * + * @param {Partial} data The snapshot of the spreadsheet. + * @returns {FWorkbook} FWorkbook API instance. + */ + createUniverSheet(data: Partial): FWorkbook; + /** + * Get the currently focused Univer spreadsheet. + * + * @returns {FWorkbook | null} The currently focused Univer spreadsheet. + */ + getActiveWorkbook(): FWorkbook | null; + /** + * Get the spreadsheet API handler by the spreadsheet id. + * + * @param {string} id The spreadsheet id. + * @returns {FWorkbook | null} The spreadsheet API instance. + */ + getUniverSheet(id: string): FWorkbook | null; + /** + * Get the PermissionInstance. + * + * @returns {FPermission} - The PermissionInstance. + */ + getPermission(): FPermission; +} + +class FUniverSheetsMixin extends FUniver { + override createUniverSheet(data: Partial): FWorkbook { + const instanceService = this._injector.get(IUniverInstanceService); + const workbook = instanceService.createUnit(UniverInstanceType.UNIVER_SHEET, data); + return this._injector.createInstance(FWorkbook, workbook); + }; + + override getActiveWorkbook(): FWorkbook | null { + const workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); + if (!workbook) { + return null; + } + + return this._injector.createInstance(FWorkbook, workbook); + } + + override getPermission(): FPermission { + return this._injector.createInstance(FPermission); + } +} + +FUniver.extend(FUniverSheetsMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverSheetsMixin { } +} diff --git a/packages/sheets/src/facade/f-workbook.ts b/packages/sheets/src/facade/f-workbook.ts new file mode 100644 index 00000000000..33169daf043 --- /dev/null +++ b/packages/sheets/src/facade/f-workbook.ts @@ -0,0 +1,320 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { CommandListener, ICommandInfo, IDisposable, IRange, IWorkbookData, Workbook } from '@univerjs/core'; +import type { ISetSelectionsOperationParams } from '../commands/operations/selection.operation'; +import type { ISheetCommandSharedParams } from '../commands/utils/interface'; +import { FBase, ICommandService, ILogService, Inject, Injector, IPermissionService, IResourceLoaderService, IUniverInstanceService, mergeWorksheetSnapshotWithDefault, RedoCommand, toDisposable, UndoCommand, UniverInstanceType } from '@univerjs/core'; +import { InsertSheetCommand } from '../commands/commands/insert-sheet.command'; +import { RemoveSheetCommand } from '../commands/commands/remove-sheet.command'; +import { getPrimaryForRange } from '../commands/commands/utils/selection-utils'; +import { SetSelectionsOperation } from '../commands/operations/selection.operation'; +import { SetWorksheetActiveOperation } from '../commands/operations/set-worksheet-active.operation'; +import { WorkbookEditablePermission } from '../services/permission/permission-point'; +import { SheetsSelectionsService } from '../services/selections/selection-manager.service'; +import { FRange } from './f-range'; +import { FWorksheet } from './f-worksheet'; + +export class FWorkbook extends FBase { + readonly id: string; + + constructor( + protected readonly _workbook: Workbook, + @Inject(Injector) protected readonly _injector: Injector, + @Inject(IResourceLoaderService) protected readonly _resourceLoaderService: IResourceLoaderService, + @Inject(SheetsSelectionsService) protected readonly _selectionManagerService: SheetsSelectionsService, + @IUniverInstanceService protected readonly _univerInstanceService: IUniverInstanceService, + @ICommandService protected readonly _commandService: ICommandService, + @IPermissionService protected readonly _permissionService: IPermissionService, + @ILogService protected readonly _logService: ILogService + ) { + super(); + + this.id = this._workbook.getUnitId(); + } + + getId(): string { + return this.id; + } + + getName(): string { + return this._workbook.getName(); + } + + /** + * save workbook snapshot data, including conditional formatting, data validation, and other plugin data. + */ + save(): IWorkbookData { + const snapshot = this._resourceLoaderService.saveUnit(this._workbook.getUnitId())!; + return snapshot; + } + + /** + * @deprecated use 'save' instead. + * @return {*} {IWorkbookData} + * @memberof FWorkbook + */ + getSnapshot(): IWorkbookData { + this._logService.warn(`use 'save' instead of 'getSnapshot'`); + return this.save(); + } + + /** + * Get the active sheet of the workbook. + * @returns The active sheet of the workbook + */ + getActiveSheet(): FWorksheet { + const activeSheet = this._workbook.getActiveSheet(); + return this._injector.createInstance(FWorksheet, this, this._workbook, activeSheet); + } + + /** + * Gets all the worksheets in this workbook + * @returns An array of all the worksheets in the workbook + */ + getSheets(): FWorksheet[] { + return this._workbook.getSheets().map((sheet) => { + return this._injector.createInstance(FWorksheet, this, this._workbook, sheet); + }); + } + + /** + * Create a new worksheet and returns a handle to it. + * @param name Name of the new sheet + * @param rows How may rows would the new sheet have + * @param column How many columns would the new sheet have + * @returns The new created sheet + */ + create(name: string, rows: number, column: number): FWorksheet { + const newSheet = mergeWorksheetSnapshotWithDefault({}); + newSheet.rowCount = rows; + newSheet.columnCount = column; + newSheet.name = name; + newSheet.id = name.toLowerCase().replace(/ /g, '-'); + + this._commandService.syncExecuteCommand(InsertSheetCommand.id, { + unitId: this.id, + index: this._workbook.getSheets().length, + sheet: newSheet, + }); + + this._commandService.syncExecuteCommand(SetWorksheetActiveOperation.id, { + unitId: this.id, + subUnitId: this._workbook.getSheets()[this._workbook.getSheets().length - 1].getSheetId(), + }); + + const worksheet = this._workbook.getActiveSheet(); + if (!worksheet) { + throw new Error('No active sheet found'); + } + + return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); + } + + /** + * Get a worksheet by sheet id. + * @param sheetId The id of the sheet to get. + * @return The worksheet with given sheet id + */ + getSheetBySheetId(sheetId: string): FWorksheet | null { + const worksheet = this._workbook.getSheetBySheetId(sheetId); + if (!worksheet) { + return null; + } + + return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); + } + + /** + * Get a worksheet by sheet name. + * @param name The name of the sheet to get. + * @returns The worksheet with given sheet name + */ + getSheetByName(name: string): FWorksheet | null { + const worksheet = this._workbook.getSheetBySheetName(name); + if (!worksheet) { + return null; + } + + return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); + } + + /** + * Sets the given worksheet to be the active worksheet in the workbook. + * @param sheet The worksheet to set as the active worksheet. + * @returns The active worksheet + */ + setActiveSheet(sheet: FWorksheet): FWorksheet { + this._commandService.syncExecuteCommand(SetWorksheetActiveOperation.id, { + unitId: this.id, + subUnitId: sheet.getSheetId(), + }); + + return sheet; + } + + /** + * Inserts a new worksheet into the workbook. + * Using a default sheet name. The new sheet becomes the active sheet + * @returns The new sheet + */ + insertSheet(): FWorksheet { + this._commandService.syncExecuteCommand(InsertSheetCommand.id); + + const unitId = this.id; + const subUnitId = this._workbook.getSheets()[this._workbook.getSheets().length - 1].getSheetId(); + + this._commandService.syncExecuteCommand(SetWorksheetActiveOperation.id, { + unitId, + subUnitId, + }); + const worksheet = this._workbook.getActiveSheet(); + if (!worksheet) { + throw new Error('No active sheet found'); + } + + return this._injector.createInstance(FWorksheet, this, this._workbook, worksheet); + } + + /** + * Deletes the specified worksheet. + * @param sheet The worksheet to delete. + */ + deleteSheet(sheet: FWorksheet): void { + const unitId = this.id; + const subUnitId = sheet.getSheetId(); + this._commandService.executeCommand(RemoveSheetCommand.id, { + unitId, + subUnitId, + }); + } + + // #region editing + + undo(): Promise { + this._univerInstanceService.focusUnit(this.id); + return this._commandService.executeCommand(UndoCommand.id); + } + + redo(): Promise { + this._univerInstanceService.focusUnit(this.id); + return this._commandService.executeCommand(RedoCommand.id); + } + + /** + * Register a callback that will be triggered before invoking a command targeting the Univer sheet. + * @param callback the callback. + * @returns A function to dispose the listening. + */ + onBeforeCommandExecute(callback: CommandListener): IDisposable { + return this._commandService.beforeCommandExecuted((command) => { + if ((command as ICommandInfo).params?.unitId !== this.id) { + return; + } + + callback(command); + }); + } + + /** + * Register a callback that will be triggered when a command is invoked targeting the Univer sheet. + * @param callback the callback. + * @returns A function to dispose the listening. + */ + onCommandExecuted(callback: CommandListener): IDisposable { + return this._commandService.onCommandExecuted((command) => { + if ((command as ICommandInfo).params?.unitId !== this.id) { + return; + } + + callback(command); + }); + } + + onSelectionChange(callback: (selections: IRange[]) => void): IDisposable { + return toDisposable( + this._selectionManagerService.selectionMoveEnd$.subscribe((selections) => { + if (this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getUnitId() !== this.id) { + return; + } + + if (!selections?.length) { + callback([]); + } else { + // TODO@wzhudev: filtered out ranges changes not other currently sheet + callback(selections!.map((s) => s.range)); + } + }) + ); + } + + /** + * Used to modify the editing permissions of the workbook. When the value is false, editing is not allowed. + * @param {boolean} value editable value want to set + */ + setEditable(value: boolean): void { + const instance = new WorkbookEditablePermission(this._workbook.getUnitId()); + const editPermissionPoint = this._permissionService.getPermissionPoint(instance.id); + if (!editPermissionPoint) { + this._permissionService.addPermissionPoint(instance); + } + this._permissionService.updatePermissionPoint(instance.id, value); + } + + /** + * Sets the active selection region for this sheet. + * @param range The range to set as the active selection. + */ + setActiveRange(range: FRange): void { + // In theory, FRange should belong to a specific context, rather than getting the currently active sheet + const sheet = this.getActiveSheet(); + const sheetId = range.getRange().sheetId || sheet.getSheetId(); + + const worksheet = sheetId ? this._workbook.getSheetBySheetId(sheetId) : this._workbook.getActiveSheet(true); + if (!worksheet) { + throw new Error('No active sheet found'); + } + + // if the range is not in the current sheet, set the active sheet to the range's sheet + if (worksheet.getSheetId() !== sheet.getSheetId()) { + this.setActiveSheet(this._injector.createInstance(FWorksheet, this, this._workbook, worksheet)); + } + + const setSelectionOperationParams: ISetSelectionsOperationParams = { + unitId: this.getId(), + subUnitId: sheetId, + + selections: [range].map((r) => ({ range: r.getRange(), primary: getPrimaryForRange(r.getRange(), worksheet), style: null })), + }; + + this._commandService.syncExecuteCommand(SetSelectionsOperation.id, setSelectionOperationParams); + } + + /** + * Returns the selected range in the active sheet, or null if there is no active range. + * @returns the active range + */ + getActiveRange(): FRange | null { + const activeSheet = this._workbook.getActiveSheet(); + const selections = this._selectionManagerService.getCurrentSelections(); + const active = selections.find((selection) => !!selection.primary); + if (!active) { + return null; + } + + return this._injector.createInstance(FRange, this._workbook, activeSheet, active.range); + } +} diff --git a/packages/facade/src/apis/sheets/f-worksheet.ts b/packages/sheets/src/facade/f-worksheet.ts similarity index 88% rename from packages/facade/src/apis/sheets/f-worksheet.ts rename to packages/sheets/src/facade/f-worksheet.ts index ac5c8ac1e6b..db498d1d7a9 100644 --- a/packages/facade/src/apis/sheets/f-worksheet.ts +++ b/packages/sheets/src/facade/f-worksheet.ts @@ -15,37 +15,42 @@ */ import type { CustomData, ICellData, IColumnData, IDisposable, IFreeze, IObjectArrayPrimitiveType, IRange, IRowData, IStyleData, Nullable, Workbook, Worksheet } from '@univerjs/core'; - -import type { ISetColDataCommandParams, ISetRangeValuesMutationParams, ISetRowDataCommandParams, ISetWorksheetDefaultStyleMutationParams, IToggleGridlinesCommandParams } from '@univerjs/sheets'; -import type { FilterModel } from '@univerjs/sheets-filter'; -import type { FWorkbook, IFICanvasFloatDom } from './f-workbook'; -import { BooleanNumber, Direction, ICommandService, Inject, Injector, ObjectMatrix, RANGE_TYPE } from '@univerjs/core'; -import { DataValidationModel } from '@univerjs/data-validation'; +import type { ISetColDataCommandParams } from '../commands/commands/set-col-data.command'; +import type { ISetRowDataCommandParams } from '../commands/commands/set-row-data.command'; +import type { IToggleGridlinesCommandParams } from '../commands/commands/toggle-gridlines.command'; +import type { ISetRangeValuesMutationParams } from '../commands/mutations/set-range-values.mutation'; +import type { FWorkbook } from './f-workbook'; +import { BooleanNumber, Direction, FBase, ICommandService, Inject, Injector, ObjectMatrix, RANGE_TYPE } from '@univerjs/core'; import { deserializeRangeWithSheet } from '@univerjs/engine-formula'; -import { copyRangeStyles, InsertColCommand, InsertRowCommand, MoveColsCommand, MoveRowsCommand, RemoveColCommand, RemoveRowCommand, SetColDataCommand, SetColHiddenCommand, SetColWidthCommand, SetFrozenCommand, SetRangeValuesMutation, SetRowDataCommand, SetRowHeightCommand, SetRowHiddenCommand, SetSpecificColsVisibleCommand, SetSpecificRowsVisibleCommand, SetWorksheetDefaultStyleCommand, SetWorksheetRowIsAutoHeightCommand, SheetsSelectionsService, ToggleGridlinesCommand } from '@univerjs/sheets'; -import { type IDataValidationResCache, SheetsDataValidationValidatorService } from '@univerjs/sheets-data-validation'; -import { SheetCanvasFloatDomManagerService } from '@univerjs/sheets-drawing-ui'; -import { SheetsFilterService } from '@univerjs/sheets-filter'; -import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment'; -import { CancelFrozenCommand } from '@univerjs/sheets-ui'; -import { ComponentManager } from '@univerjs/ui'; -import { FDataValidation } from './f-data-validation'; -import { FFilter } from './f-filter'; +import { InsertColCommand, InsertRowCommand } from '../commands/commands/insert-row-col.command'; +import { MoveColsCommand, MoveRowsCommand } from '../commands/commands/move-rows-cols.command'; +import { RemoveColCommand, RemoveRowCommand } from '../commands/commands/remove-row-col.command'; +import { SetColDataCommand } from '../commands/commands/set-col-data.command'; +import { SetColHiddenCommand, SetSpecificColsVisibleCommand } from '../commands/commands/set-col-visible.command'; +import { CancelFrozenCommand, SetFrozenCommand } from '../commands/commands/set-frozen.command'; +import { SetRowDataCommand } from '../commands/commands/set-row-data.command'; +import { SetRowHiddenCommand, SetSpecificRowsVisibleCommand } from '../commands/commands/set-row-visible.command'; +import { SetColWidthCommand } from '../commands/commands/set-worksheet-col-width.command'; +import { SetRowHeightCommand, SetWorksheetRowIsAutoHeightCommand } from '../commands/commands/set-worksheet-row-height.command'; +import { ToggleGridlinesCommand } from '../commands/commands/toggle-gridlines.command'; +import { copyRangeStyles } from '../commands/commands/utils/selection-utils'; +import { SetRangeValuesMutation } from '../commands/mutations/set-range-values.mutation'; +import { SetWorksheetDefaultStyleMutation } from '../commands/mutations/set-worksheet-default-style.mutation'; +import { SheetsSelectionsService } from '../services/selections/selection-manager.service'; import { FRange } from './f-range'; import { FSelection } from './f-selection'; -import { FThreadComment } from './f-thread-comment'; -import { covertToColRange, covertToRowRange, transformComponentKey } from './utils'; +import { covertToColRange, covertToRowRange } from './utils'; -export class FWorksheet { +export class FWorksheet extends FBase { constructor( - private readonly _fWorkbook: FWorkbook, - private readonly _workbook: Workbook, - private readonly _worksheet: Worksheet, - @Inject(Injector) private readonly _injector: Injector, - @Inject(SheetsSelectionsService) private readonly _selectionManagerService: SheetsSelectionsService, - @ICommandService private readonly _commandService: ICommandService + protected readonly _fWorkbook: FWorkbook, + protected readonly _workbook: Workbook, + protected readonly _worksheet: Worksheet, + @Inject(Injector) protected readonly _injector: Injector, + @Inject(SheetsSelectionsService) protected readonly _selectionManagerService: SheetsSelectionsService, + @ICommandService protected readonly _commandService: ICommandService ) { - // empty + super(); } /** @@ -89,7 +94,9 @@ export class FWorksheet { return this._injector.createInstance(FSelection, this._workbook, this._worksheet, selections); } - //#region default style + // #region rows + + // #region default style /** * Get the default style of the worksheet @@ -124,17 +131,15 @@ export class FWorksheet { * @param style default style * @returns this worksheet */ - async setDefaultStyle(style: Nullable): Promise { + async setDefaultStyle(style: string): Promise { const unitId = this._workbook.getUnitId(); const subUnitId = this._worksheet.getSheetId(); - - const params: ISetWorksheetDefaultStyleMutationParams = { + await this._commandService.executeCommand(SetWorksheetDefaultStyleMutation.id, { unitId, subUnitId, defaultStyle: style, - }; - - await this._commandService.executeCommand(SetWorksheetDefaultStyleCommand.id, params); + }); + this._worksheet.setDefaultCellStyle(style); return this; } @@ -183,6 +188,7 @@ export class FWorksheet { await this._commandService.executeCommand(SetRowDataCommand.id, params); return this; } + // #endregion /** @@ -192,7 +198,6 @@ export class FWorksheet { * @returns A Range object representing the specified cell. */ getRange(row: number, column: number): FRange; - /** * Returns a Range object representing a range starting at the specified row and column, with the specified number of rows. * @param row The starting row index of the range. @@ -201,7 +206,6 @@ export class FWorksheet { * @returns A Range object representing the specified range. */ getRange(row: number, column: number, numRows: number): FRange; - /** * Returns a Range object representing a range starting at the specified row and column, with the specified number of rows and columns. * @param row The starting row index of the range. @@ -211,14 +215,12 @@ export class FWorksheet { * @returns A Range object representing the specified range. */ getRange(row: number, column: number, numRows: number, numColumns: number): FRange; - /** * Returns a Range object specified by A1 notation. * @param a1Notation A string representing a range in A1 notation. * @returns A Range object representing the specified range. */ getRange(a1Notation: string): FRange; - getRange(rowOrA1Notation: number | string, column?: number, numRows?: number, numColumns?: number): FRange { let range: IRange; let sheet: Worksheet; @@ -279,89 +281,6 @@ export class FWorksheet { return this._worksheet.getMaxRows(); } - /** - * get all data validation rules in current sheet - * @returns all data validation rules - */ - getDataValidations(): FDataValidation[] { - const dataValidationModel = this._injector.get(DataValidationModel); - return dataValidationModel.getRules(this._workbook.getUnitId(), this._worksheet.getSheetId()).map((rule) => new FDataValidation(rule)); - } - - /** - * get data validation validator status for current sheet - * @returns matrix of validator status - */ - getValidatorStatus(): Promise>> { - const validatorService = this._injector.get(SheetsDataValidationValidatorService); - return validatorService.validatorWorksheet( - this._workbook.getUnitId(), - this._worksheet.getSheetId() - ); - } - - // #region Filter - - getFilter(): FFilter | null { - const filterModel = this._getFilterModel(); - if (!filterModel) return null; - - return this._injector.createInstance(FFilter, this._workbook, this._worksheet, filterModel); - } - - private _getFilterModel(): Nullable { - return this._injector.get(SheetsFilterService).getFilterModel( - this._workbook.getUnitId(), - this._worksheet.getSheetId() - ); - } - - // #endregion - - // #region Comment - /** - * Get all comments in the current sheet - * @returns all comments in the current sheet - */ - getComments(): FThreadComment[] { - const sheetsTheadCommentModel = this._injector.get(SheetsThreadCommentModel); - const comments = sheetsTheadCommentModel.getSubUnitAll(this._workbook.getUnitId(), this._worksheet.getSheetId()); - return comments.map((comment) => this._injector.createInstance(FThreadComment, comment)); - } - // #endregion - - /** - * add a float dom to position - * @param layer float dom config - * @param id float dom id, if not given will be auto generated - * @returns float dom id and dispose function - */ - addFloatDomToPosition(layer: IFICanvasFloatDom, id?: string): Nullable<{ - id: string; - dispose: () => void; - }> { - const unitId = this._workbook.getUnitId(); - const subUnitId = this._worksheet.getSheetId(); - const { key, disposableCollection } = transformComponentKey(layer, this._injector.get(ComponentManager)); - const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService); - const res = floatDomService.addFloatDomToPosition({ ...layer, componentKey: key, unitId, subUnitId }, id); - - if (res) { - disposableCollection.add(res.dispose); - return { - id: res.id, - dispose: (): void => { - disposableCollection.dispose(); - res.dispose(); - }, - }; - } - - disposableCollection.dispose(); - return null; - } - // #region Row - /** * Inserts a row after the given row position. * @param afterPosition The row after which the new row should be added, starting at 0 for the first row. @@ -699,6 +618,8 @@ export class FWorksheet { return this; } + // #endregion + /** * Set custom properties for given rows. * @param custom The custom properties to set. @@ -726,8 +647,6 @@ export class FWorksheet { return this; } - // #endregion - // #region Column /** @@ -1016,6 +935,8 @@ export class FWorksheet { return this; } + // #endregion + /** * Set custom properties for given columns. * @param custom The custom properties to set. @@ -1043,8 +964,6 @@ export class FWorksheet { return this; } - // #endregion - // #region merge cells /** @@ -1118,6 +1037,7 @@ export class FWorksheet { * @returns True if the command was successful, false otherwise. */ cancelFreeze(): boolean { + // TODO: this command should not be implemented in sheets-ui package return this._commandService.syncExecuteCommand(CancelFrozenCommand.id, { unitId: this._workbook.getUnitId(), subUnitId: this.getSheetId(), diff --git a/packages/sheets/src/facade/index.ts b/packages/sheets/src/facade/index.ts new file mode 100644 index 00000000000..9f8159f7f17 --- /dev/null +++ b/packages/sheets/src/facade/index.ts @@ -0,0 +1,24 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import './f-univer'; + +export { FPermission } from './f-permission'; +export { FRange } from './f-range'; +export type { FontLine, FontStyle, FontWeight } from './f-range'; +export { FSelection } from './f-selection'; +export { FWorkbook } from './f-workbook'; +export { FWorksheet } from './f-worksheet'; diff --git a/packages/facade/src/apis/sheets/utils.ts b/packages/sheets/src/facade/utils.ts similarity index 81% rename from packages/facade/src/apis/sheets/utils.ts rename to packages/sheets/src/facade/utils.ts index fccb8987e5e..46ff30b3fd0 100644 --- a/packages/facade/src/apis/sheets/utils.ts +++ b/packages/sheets/src/facade/utils.ts @@ -15,10 +15,7 @@ */ import type { CellValue, ICellData, IObjectMatrixPrimitiveType, IRange, IRangeWithCoord, Nullable, Worksheet } from '@univerjs/core'; -import type { ComponentManager, ComponentType } from '@univerjs/ui'; import { - DisposableCollection, - generateRandomId, HorizontalAlign, isCellV, isFormulaString, @@ -155,36 +152,6 @@ export function isSingleCell(mergeInfo: IRangeWithCoord, range: IRange): boolean && mergeInfo.endRow === range.endRow; } -export interface IFComponentKey { - /** - * The key of the component to be rendered in the popup. - * if key is a string, it will be query from the component registry. - * if key is a React or Vue3 component, it will be rendered directly. - */ - componentKey: string | ComponentType; - /** - * If componentKey is a Vue3 component, this must be set to true - */ - isVue3?: boolean; -} - -export function transformComponentKey(component: IFComponentKey, componentManager: ComponentManager): { key: string; disposableCollection: DisposableCollection } { - const { componentKey, isVue3 } = component; - let key: string; - const disposableCollection = new DisposableCollection(); - if (typeof componentKey === 'string') { - key = componentKey; - } else { - key = `External_${generateRandomId(6)}`; - disposableCollection.add(componentManager.register(key, componentKey, { framework: isVue3 ? 'vue3' : 'react' })); - } - - return { - key, - disposableCollection, - }; -} - export function covertToRowRange(range: IRange, worksheet: Worksheet): IRange { return { startRow: range.startRow, diff --git a/packages/sheets/src/index.ts b/packages/sheets/src/index.ts index 9f53a042863..0c6b2e1fc9e 100644 --- a/packages/sheets/src/index.ts +++ b/packages/sheets/src/index.ts @@ -89,7 +89,7 @@ export { runRefRangeMutations, } from './services/ref-range/util'; export { InterceptCellContentPriority, INTERCEPTOR_POINT } from './services/sheet-interceptor/interceptor-const'; -export { SheetInterceptorService } from './services/sheet-interceptor/sheet-interceptor.service'; +export { AFTER_CELL_EDIT, AFTER_CELL_EDIT_ASYNC, BEFORE_CELL_EDIT, SheetInterceptorService } from './services/sheet-interceptor/sheet-interceptor.service'; export type { ISheetLocation, ISheetLocationBase, ISheetRowLocation } from './services/sheet-interceptor/utils/interceptor'; export { MERGE_CELL_INTERCEPTOR_CHECK, MergeCellController } from './controllers/merge-cell.controller'; export { AddMergeRedoSelectionsOperationFactory, AddMergeUndoSelectionsOperationFactory } from './commands/utils/handle-merge-operation'; @@ -249,8 +249,8 @@ export { } from './commands/commands/set-col-visible.command'; export { SetDefinedNameCommand } from './commands/commands/set-defined-name.command'; -export { SetFrozenCancelCommand } from './commands/commands/set-frozen-cancel.command'; -export { SetFrozenCommand } from './commands/commands/set-frozen.command'; +export { type ICancelFrozenCommandParams, type ISetFrozenCommandParams } from './commands/commands/set-frozen.command'; +export { CancelFrozenCommand, SetFrozenCommand } from './commands/commands/set-frozen.command'; export { type IToggleGridlinesCommandParams, ToggleGridlinesCommand } from './commands/commands/toggle-gridlines.command'; export { type ISetRangeProtectionCommandParams, SetRangeProtectionCommand } from './commands/commands/set-range-protection.command'; export { type ISetRangeValuesCommandParams, SetRangeValuesCommand } from './commands/commands/set-range-values.command'; diff --git a/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts b/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts index e41a9cfc655..a050bd7f671 100644 --- a/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts +++ b/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts @@ -16,6 +16,7 @@ import type { ICellData, + ICellDataForSheetInterceptor, ICellInterceptor, ICommandInfo, IDisposable, @@ -26,17 +27,21 @@ import type { Workbook, Worksheet, } from '@univerjs/core'; +import type { ISheetLocation } from './utils/interceptor'; + import { composeInterceptors, + createInterceptorKey, Disposable, DisposableCollection, InterceptorEffectEnum, + InterceptorManager, IUniverInstanceService, remove, toDisposable, + Tools, UniverInstanceType, } from '@univerjs/core'; - import { INTERCEPTOR_POINT } from './interceptor-const'; export interface IBeforeCommandInterceptor { @@ -60,6 +65,14 @@ export interface IRangeInterceptors { getMutations(rangesInfo: IRangesInfo): IUndoRedoCommandInfosByInterceptor; } +interface ISheetLocationForEditor extends ISheetLocation { + origin: Nullable; +} + +export const BEFORE_CELL_EDIT = createInterceptorKey('BEFORE_CELL_EDIT'); +export const AFTER_CELL_EDIT = createInterceptorKey('AFTER_CELL_EDIT'); +export const AFTER_CELL_EDIT_ASYNC = createInterceptorKey>, ISheetLocationForEditor>('AFTER_CELL_EDIT_ASYNC'); + /** * This class expose methods for sheet features to inject code to sheet underlying logic. */ @@ -73,6 +86,12 @@ export class SheetInterceptorService extends Disposable { private readonly _workbookDisposables = new Map(); private readonly _worksheetDisposables = new Map(); + readonly writeCellInterceptor = new InterceptorManager({ + BEFORE_CELL_EDIT, + AFTER_CELL_EDIT, + AFTER_CELL_EDIT_ASYNC, + }); + /** @ignore */ constructor( @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService @@ -102,6 +121,21 @@ export class SheetInterceptorService extends Disposable { return rawData; }, }); + + this.disposeWithMe(this.writeCellInterceptor.intercept(AFTER_CELL_EDIT, { + priority: -1, + handler: (_value) => _value, + })); + + this.disposeWithMe(this.writeCellInterceptor.intercept(BEFORE_CELL_EDIT, { + priority: -1, + handler: (_value) => _value, + })); + + this.disposeWithMe(this.writeCellInterceptor.intercept(AFTER_CELL_EDIT_ASYNC, { + priority: -1, + handler: (_value) => _value, + })); } override dispose(): void { @@ -112,6 +146,16 @@ export class SheetInterceptorService extends Disposable { this._worksheetDisposables.clear(); } + // #region Intercept command execution + + /** + * Add a listener function to a specific command to add affiliated mutations. It should be called in controllers. + * + * Pairs with {@link onCommandExecute}. + * + * @param interceptor + * @returns + */ interceptCommand(interceptor: ICommandInterceptor): IDisposable { if (this._commandInterceptors.includes(interceptor)) { throw new Error('[SheetInterceptorService]: Interceptor already exists!'); @@ -123,7 +167,31 @@ export class SheetInterceptorService extends Disposable { return this.disposeWithMe(toDisposable(() => remove(this._commandInterceptors, interceptor))); } - // Add a listener function to the command, which will be run before the command is run to get whether it can be executed the command + /** + * When command is executing, call this method to gether undo redo mutations from upper features. + * @param command + * @returns + */ + onCommandExecute(info: ICommandInfo): IUndoRedoCommandInfosByInterceptor { + const infos = this._commandInterceptors.map((i) => i.getMutations(info)); + + return { + preUndos: infos.map((i) => i.preUndos ?? []).flat(), + undos: infos.map((i) => i.undos).flat(), + preRedos: infos.map((i) => i.preRedos ?? []).flat(), + redos: infos.map((i) => i.redos).flat(), + }; + } + + /** + * Add a listener function to a specific command to deteminte if the command can execute mutations. It should be + * called in controllers. + * + * Pairs with {@link beforeCommandExecute}. + * + * @param interceptor + * @returns + */ interceptBeforeCommand(interceptor: IBeforeCommandInterceptor): IDisposable { if (this._beforeCommandInterceptor.includes(interceptor)) { throw new Error('[SheetInterceptorService]: Interceptor already exists!'); @@ -145,6 +213,10 @@ export class SheetInterceptorService extends Disposable { return allPerformCheckRes.every((perform) => perform); } + // #endregion + + // #region intercept ranges - mainly for pivot table currrently (2024/10/28). + /** * By adding callbacks to some Ranges can get some additional mutations, such as clearing all plugin data in a certain area. * @param interceptor IRangeInterceptors @@ -161,14 +233,8 @@ export class SheetInterceptorService extends Disposable { return this.disposeWithMe(toDisposable(() => remove(this._rangeInterceptors, interceptor))); } - /** - * When command is executing, call this method to gether undo redo mutations from upper features. - * @param command - * @returns - */ - - onCommandExecute(info: ICommandInfo): IUndoRedoCommandInfosByInterceptor { - const infos = this._commandInterceptors.map((i) => i.getMutations(info)); + generateMutationsByRanges(info: IRangesInfo): IUndoRedoCommandInfosByInterceptor { + const infos = this._rangeInterceptors.map((i) => i.getMutations(info)); return { preUndos: infos.map((i) => i.preUndos ?? []).flat(), @@ -178,17 +244,28 @@ export class SheetInterceptorService extends Disposable { }; } - generateMutationsByRanges(info: IRangesInfo): IUndoRedoCommandInfosByInterceptor { - const infos = this._rangeInterceptors.map((i) => i.getMutations(info)); - - return { - preUndos: infos.map((i) => i.preUndos ?? []).flat(), - undos: infos.map((i) => i.undos).flat(), - preRedos: infos.map((i) => i.preRedos ?? []).flat(), - redos: infos.map((i) => i.redos).flat(), + // #region write cell + + async onWriteCell(workbook: Workbook, worksheet: Worksheet, row: number, col: number, cellData: ICellData) { + const context = { + subUnitId: worksheet.getSheetId(), + unitId: workbook.getUnitId(), + workbook: workbook!, + worksheet, + row, + col, + origin: Tools.deepClone(cellData), }; + + const cell = this.writeCellInterceptor.fetchThroughInterceptors(AFTER_CELL_EDIT)(cellData, context); + const finalCell = await this.writeCellInterceptor.fetchThroughInterceptors(AFTER_CELL_EDIT_ASYNC)(Promise.resolve(cell), context); + return finalCell; } + // #endregion + + // #endregion + intercept>(name: T, interceptor: T): IDisposable { const key = name as unknown as string; if (!this._interceptorsByName.has(key)) { @@ -203,14 +280,14 @@ export class SheetInterceptorService extends Disposable { `${key}-${(InterceptorEffectEnum.Style | InterceptorEffectEnum.Value)}`, sortedInterceptors ); - // 3 means both style and value + const BOTH_EFFECT = InterceptorEffectEnum.Style | InterceptorEffectEnum.Value; this._interceptorsByName.set( `${key}-${(InterceptorEffectEnum.Style)}`, - (sortedInterceptors as ICellInterceptor[]).filter((i) => ((i.effect || 3) & InterceptorEffectEnum.Style) > 0) + (sortedInterceptors as ICellInterceptor[]).filter((i) => ((i.effect || BOTH_EFFECT) & InterceptorEffectEnum.Style) > 0) ); this._interceptorsByName.set( `${key}-${(InterceptorEffectEnum.Value)}`, - (sortedInterceptors as ICellInterceptor[]).filter((i) => ((i.effect || 3) & InterceptorEffectEnum.Value) > 0) + (sortedInterceptors as ICellInterceptor[]).filter((i) => ((i.effect || BOTH_EFFECT) & InterceptorEffectEnum.Value) > 0) ); } else { this._interceptorsByName.set( diff --git a/packages/thread-comment-ui/src/index.ts b/packages/thread-comment-ui/src/index.ts index 074246225aa..6d8971cbf2c 100644 --- a/packages/thread-comment-ui/src/index.ts +++ b/packages/thread-comment-ui/src/index.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -export { getDT } from './common/utils'; export { UniverThreadCommentUIPlugin } from './plugin'; export { type ActiveCommentInfo, ThreadCommentPanelService } from './services/thread-comment-panel.service'; export { ThreadCommentPanel } from './views/thread-comment-panel'; diff --git a/packages/thread-comment-ui/src/views/thread-comment-tree/index.tsx b/packages/thread-comment-ui/src/views/thread-comment-tree/index.tsx index f6c931b1d2a..86ba1091b98 100644 --- a/packages/thread-comment-ui/src/views/thread-comment-tree/index.tsx +++ b/packages/thread-comment-ui/src/views/thread-comment-tree/index.tsx @@ -20,13 +20,12 @@ import { generateRandomId, useDependency } from '@univerjs/core'; import { ICommandService, type IUser, LocaleService, type UniverInstanceType, UserManagerService } from '@univerjs/core'; import { Dropdown, Menu, MenuItem, Tooltip } from '@univerjs/design'; import { DeleteSingle, MoreHorizontalSingle, ReplyToCommentSingle, ResolvedSingle, SolveSingle } from '@univerjs/icons'; -import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, ResolveCommentCommand, ThreadCommentModel, UpdateCommentCommand } from '@univerjs/thread-comment'; +import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, getDT, ResolveCommentCommand, ThreadCommentModel, UpdateCommentCommand } from '@univerjs/thread-comment'; import { useObservable } from '@univerjs/ui'; import cs from 'clsx'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import { debounceTime } from 'rxjs'; import { SetActiveCommentOperation } from '../../commands/operations/comment.operations'; -import { getDT } from '../../common/utils'; import { ThreadCommentEditor } from '../thread-comment-editor'; import { transformDocument2TextNodes, transformTextNodes2Document } from '../thread-comment-editor/util'; import styles from './index.module.less'; diff --git a/packages/thread-comment/package.json b/packages/thread-comment/package.json index 63eaa0fe510..0b2526c2851 100644 --- a/packages/thread-comment/package.json +++ b/packages/thread-comment/package.json @@ -61,7 +61,8 @@ }, "dependencies": { "@univerjs/core": "workspace:*", - "@univerjs/protocol": "0.1.39-alpha.38" + "@univerjs/protocol": "0.1.39-alpha.38", + "dayjs": "^1.11.13" }, "devDependencies": { "@univerjs-infra/shared": "workspace:*", diff --git a/packages/thread-comment-ui/src/common/utils.ts b/packages/thread-comment/src/common/utils.ts similarity index 100% rename from packages/thread-comment-ui/src/common/utils.ts rename to packages/thread-comment/src/common/utils.ts diff --git a/packages/thread-comment/src/index.ts b/packages/thread-comment/src/index.ts index 21ed1da2949..1b54ec25b0f 100644 --- a/packages/thread-comment/src/index.ts +++ b/packages/thread-comment/src/index.ts @@ -19,6 +19,7 @@ export { ThreadCommentResourceController } from './controllers/tc-resource.contr export { TC_PLUGIN_NAME } from './types/const'; export type { IBaseComment, IThreadComment, IThreadCommentMention } from './types/interfaces/i-thread-comment'; export { UniverThreadCommentPlugin } from './plugin'; +export { getDT } from './common/utils'; export { type IThreadCommentDataSource, diff --git a/packages/ui/package.json b/packages/ui/package.json index c374473be34..ad285386bce 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/ui/src/facade/f-hooks.ts b/packages/ui/src/facade/f-hooks.ts new file mode 100644 index 00000000000..020653a6b97 --- /dev/null +++ b/packages/ui/src/facade/f-hooks.ts @@ -0,0 +1,104 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IDisposable } from '@univerjs/core'; +import { FHooks, ICommandService } from '@univerjs/core'; +import { CopyCommand, PasteCommand } from '../services/clipboard/clipboard.command'; + +interface IFHooksSheetsUIMixin { + /** + * The onBeforeCopy event is fired before a copy operation is performed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforeCopy(callback: () => void): IDisposable; + + /** + * The onBeforeCopy event is fired before a copy operation is performed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforePaste(callback: () => void): IDisposable; + + /** + * The onCopy event is fired after a copy operation is performed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onCopy(callback: () => void): IDisposable; + + /** + * The onBeforePaste event is fired before a paste operation is performed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onBeforePaste(callback: () => void): IDisposable; + + /** + * The onPaste event is fired after a paste operation is performed. + * @param callback Callback function that will be called when the event is fired + * @returns A disposable object that can be used to unsubscribe from the event + */ + onPaste(callback: () => void): IDisposable; +} + +class FHooksSheetsMixin extends FHooks implements IFHooksSheetsUIMixin { + override onBeforeCopy(callback: () => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.beforeCommandExecuted((command) => { + if (command.id === CopyCommand.id) { + callback(); + } + }); + } + + override onCopy(callback: () => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.onCommandExecuted((command) => { + if (command.id === CopyCommand.id) { + callback(); + } + }); + } + + override onBeforePaste(callback: () => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.beforeCommandExecuted((command) => { + if (command.id === PasteCommand.id) { + callback(); + } + }); + } + + override onPaste(callback: () => void): IDisposable { + const commandService = this._injector.get(ICommandService); + + return commandService.onCommandExecuted((command) => { + if (command.id === PasteCommand.id) { + callback(); + } + }); + } +} + +FHooks.extend(FHooksSheetsMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FHooks extends IFHooksSheetsUIMixin {} +} diff --git a/packages/ui/src/facade/f-univer.ts b/packages/ui/src/facade/f-univer.ts new file mode 100644 index 00000000000..2b6ef0a3379 --- /dev/null +++ b/packages/ui/src/facade/f-univer.ts @@ -0,0 +1,75 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IDisposable } from '@univerjs/core'; +import type { IDialogPartMethodOptions } from '../views/components/dialog-part/interface'; +import type { ISidebarMethodOptions } from '../views/components/sidebar/interface'; +import { FUniver } from '@univerjs/core'; +import { CopyCommand, PasteCommand } from '../services/clipboard/clipboard.command'; +import { IDialogService } from '../services/dialog/dialog.service'; +import { ISidebarService } from '../services/sidebar/sidebar.service'; + +interface IFUniverUIMixin { + copy(): Promise; + + paste(): Promise; + + /** + * Open a sidebar. + * @param params the sidebar options + * @returns the disposable object + */ + openSiderbar(params: ISidebarMethodOptions): IDisposable; + + /** + * Open a dialog. + * @param dialog the dialog options + * @returns the disposable object + */ + openDialog(dialog: IDialogPartMethodOptions): IDisposable; +} + +class FUniverUIMixin extends FUniver implements IFUniverUIMixin { + override copy(): Promise { + return this._commandService.executeCommand(CopyCommand.id); + } + + override paste(): Promise { + return this._commandService.executeCommand(PasteCommand.id); + } + + override openSiderbar(params: ISidebarMethodOptions): IDisposable { + const sideBarService = this._injector.get(ISidebarService); + return sideBarService.open(params); + } + + override openDialog(dialog: IDialogPartMethodOptions): IDisposable { + const dialogService = this._injector.get(IDialogService); + const disposable = dialogService.open({ + ...dialog, + onClose: () => { + disposable.dispose(); + }, + }); + return disposable; + } +} + +FUniver.extend(FUniverUIMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverUIMixin {} +} diff --git a/packages/ui/src/facade/index.ts b/packages/ui/src/facade/index.ts new file mode 100644 index 00000000000..e2b6382f7b0 --- /dev/null +++ b/packages/ui/src/facade/index.ts @@ -0,0 +1,18 @@ +/** + * 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 './f-univer'; +import './f-hooks'; diff --git a/packages/ui/src/services/shortcut/shortcut.service.ts b/packages/ui/src/services/shortcut/shortcut.service.ts index 4d0b81ffd89..88a477aa8ec 100644 --- a/packages/ui/src/services/shortcut/shortcut.service.ts +++ b/packages/ui/src/services/shortcut/shortcut.service.ts @@ -14,16 +14,15 @@ * limitations under the License. */ -import { createIdentifier, Disposable, ICommandService, IContextService, Optional, toDisposable } from '@univerjs/core'; -import { Subject } from 'rxjs'; import type { IDisposable } from '@univerjs/core'; import type { Observable } from 'rxjs'; - +import type { KeyCode } from './keycode'; +import { createIdentifier, Disposable, ICommandService, IContextService, Optional, toDisposable } from '@univerjs/core'; +import { Subject } from 'rxjs'; import { fromGlobalEvent } from '../../common/lifecycle'; import { ILayoutService } from '../layout/layout.service'; import { IPlatformService } from '../platform/platform.service'; import { KeyCodeToChar, MetaKeys } from './keycode'; -import type { KeyCode } from './keycode'; /** * A shortcut item that could be registered to the {@link IShortcutService}. diff --git a/packages/umd/package.json b/packages/umd/package.json index 94d0a29b27c..2989b51d893 100644 --- a/packages/umd/package.json +++ b/packages/umd/package.json @@ -72,11 +72,11 @@ "@univerjs/sheets-formula-ui": "workspace:*", "@univerjs/sheets-hyper-link": "workspace:*", "@univerjs/sheets-hyper-link-ui": "workspace:*", - "@univerjs/sheets-numfmt": "workspace:*", + "@univerjs/sheets-numfmt-ui": "workspace:*", "@univerjs/sheets-sort": "workspace:*", "@univerjs/sheets-sort-ui": "workspace:*", "@univerjs/sheets-thread-comment": "workspace:*", - "@univerjs/sheets-thread-comment-base": "workspace:*", + "@univerjs/sheets-thread-comment-ui": "workspace:*", "@univerjs/sheets-ui": "workspace:*", "@univerjs/sheets-zen-editor": "workspace:*", "@univerjs/slides": "workspace:*", diff --git a/packages/umd/scripts/index.mjs b/packages/umd/scripts/index.mjs index e591f352484..9ae647a046a 100644 --- a/packages/umd/scripts/index.mjs +++ b/packages/umd/scripts/index.mjs @@ -64,8 +64,8 @@ async function generateLocale() { '@univerjs/sheets-find-replace', '@univerjs/sheets-formula-ui', '@univerjs/sheets-hyper-link-ui', - '@univerjs/sheets-numfmt', - '@univerjs/sheets-thread-comment', + '@univerjs/sheets-numfmt-ui', + '@univerjs/sheets-thread-comment-ui', '@univerjs/sheets-ui', '@univerjs/sheets-zen-editor', '@univerjs/slides-ui', @@ -136,7 +136,7 @@ function buildCSS() { '@univerjs/docs-drawing-ui', '@univerjs/sheets-ui', '@univerjs/sheets-formula-ui', - '@univerjs/sheets-numfmt', + '@univerjs/sheets-numfmt-ui', '@univerjs/sheets-zen-editor', '@univerjs/sheets-data-validation-ui', '@univerjs/sheets-drawing-ui', @@ -211,7 +211,7 @@ function buildJS() { '@univerjs/sheets-ui', '@univerjs/sheets-formula', '@univerjs/sheets-formula-ui', - '@univerjs/sheets-numfmt', + '@univerjs/sheets-numfmt-ui', '@univerjs/sheets-zen-editor', '@univerjs/sheets-conditional-formatting', '@univerjs/sheets-conditional-formatting-ui', @@ -226,7 +226,7 @@ function buildJS() { '@univerjs/sheets-sort-ui', '@univerjs/thread-comment', '@univerjs/thread-comment-ui', - '@univerjs/sheets-thread-comment-base', + '@univerjs/sheets-thread-comment', '@univerjs/sheets-thread-comment', '@univerjs/docs-thread-comment-ui', '@univerjs/drawing', diff --git a/packages/uniscript/src/services/script-execution.service.ts b/packages/uniscript/src/services/script-execution.service.ts index c6c93eb8cdf..47cf9049a96 100644 --- a/packages/uniscript/src/services/script-execution.service.ts +++ b/packages/uniscript/src/services/script-execution.service.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { createIdentifier, Disposable, ILogService, Inject, Injector } from '@univerjs/core'; -import { FUniver } from '@univerjs/facade'; +import { createIdentifier, Disposable, FUniver, ILogService, Inject, Injector } from '@univerjs/core'; export const IUniscriptExecutionService = createIdentifier('univer.uniscript.execution-service'); diff --git a/packages/watermark/package.json b/packages/watermark/package.json index 4fe823be645..b70944adb2a 100644 --- a/packages/watermark/package.json +++ b/packages/watermark/package.json @@ -23,7 +23,8 @@ "exports": { ".": "./src/index.ts", "./*": "./src/*", - "./locale/*": "./src/locale/*.ts" + "./locale/*": "./src/locale/*.ts", + "./facade/*": "./src/facade/index.ts" }, "main": "./lib/cjs/index.js", "module": "./lib/es/index.js", diff --git a/packages/watermark/src/facade/f-univer.ts b/packages/watermark/src/facade/f-univer.ts new file mode 100644 index 00000000000..3dd67e34d4b --- /dev/null +++ b/packages/watermark/src/facade/f-univer.ts @@ -0,0 +1,93 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IImageWatermarkConfig, ITextWatermarkConfig } from '../common/type'; +import { FUniver } from '@univerjs/core'; +import { WatermarkImageBaseConfig, WatermarkTextBaseConfig } from '../common/const'; +import { IWatermarkTypeEnum } from '../common/type'; +import { WatermarkService } from '../services/watermark.service'; + +interface IFUniverWatermarkMixin { + /** + * Adds a watermark to the unit. Supports both text and image watermarks based on the specified type. + * + * @param {IWatermarkTypeEnum.Text | IWatermarkTypeEnum.Image} type - The type of watermark to add. Can be either 'Text' or 'Image'. + * @param {ITextWatermarkConfig | IImageWatermarkConfig} config - The configuration object for the watermark. + * - If the type is 'Text', the config should follow the ITextWatermarkConfig interface. + * - If the type is 'Image', the config should follow the IImageWatermarkConfig interface. + * @throws {Error} Throws an error if the watermark type is unknown. + */ + addWatermark(type: IWatermarkTypeEnum.Text, config: ITextWatermarkConfig): void; + addWatermark(type: IWatermarkTypeEnum.Image, config: IImageWatermarkConfig): void; + addWatermark( + type: IWatermarkTypeEnum.Text | IWatermarkTypeEnum.Image, + config: ITextWatermarkConfig | IImageWatermarkConfig + ): void; + + /** + * Deletes the currently applied watermark from the unit. + * + * This function retrieves the watermark service and invokes the method to remove any existing watermark configuration. + */ + deleteWatermark(): void; +} + +class FUniverWatermarkMixin extends FUniver { + // #region watermark + + override addWatermark(type: IWatermarkTypeEnum.Text, config: ITextWatermarkConfig): void; + override addWatermark(type: IWatermarkTypeEnum.Image, config: IImageWatermarkConfig): void; + override addWatermark( + type: IWatermarkTypeEnum.Text | IWatermarkTypeEnum.Image, + config: ITextWatermarkConfig | IImageWatermarkConfig + ): void { + const watermarkService = this._injector.get(WatermarkService); + if (type === IWatermarkTypeEnum.Text) { + watermarkService.updateWatermarkConfig({ + type: IWatermarkTypeEnum.Text, + config: { + text: { + ...WatermarkTextBaseConfig, + ...config, + }, + }, + }); + } else if (type === IWatermarkTypeEnum.Image) { + watermarkService.updateWatermarkConfig({ + type: IWatermarkTypeEnum.Image, + config: { + image: { + ...WatermarkImageBaseConfig, + ...config, + }, + }, + }); + } else { + throw new Error('Unknown watermark type'); + } + } + + override deleteWatermark(): void { + const watermarkService = this._injector.get(WatermarkService); + watermarkService.deleteWatermarkConfig(); + } +} + +FUniver.extend(FUniverWatermarkMixin); +declare module '@univerjs/core' { + // eslint-disable-next-line ts/naming-convention + interface FUniver extends IFUniverWatermarkMixin {} +} diff --git a/packages/watermark/src/facade/index.ts b/packages/watermark/src/facade/index.ts new file mode 100644 index 00000000000..14bcba31dc0 --- /dev/null +++ b/packages/watermark/src/facade/index.ts @@ -0,0 +1,17 @@ +/** + * 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 './f-univer'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c48415640c9..42c3954d28d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@antfu/eslint-config': specifier: 3.7.3 - version: 3.7.3(@eslint-react/eslint-plugin@1.14.3(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@vue/compiler-sfc@3.4.38)(eslint-plugin-format@0.1.2(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-hooks@5.0.0(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-refresh@0.4.12(eslint@9.12.0(jiti@1.21.6)))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6)) + version: 3.7.3(@eslint-react/eslint-plugin@1.14.3(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@vue/compiler-sfc@3.4.38)(eslint-plugin-format@0.1.2(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-hooks@5.0.0(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-refresh@0.4.12(eslint@9.12.0(jiti@1.21.6)))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6)) '@commitlint/cli': specifier: ^19.5.0 version: 19.5.0(@types/node@22.7.5)(typescript@5.6.3) @@ -119,6 +119,9 @@ importers: vite-plugin-dts: specifier: ^4.2.3 version: 4.2.3(@types/node@22.7.5)(rollup@4.21.2)(typescript@5.6.3)(vite@5.4.8(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6)) + vite-plugin-external: + specifier: ^4.3.1 + version: 4.3.1 vitest: specifier: ^2.1.2 version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) @@ -243,9 +246,6 @@ importers: '@univerjs/engine-render': specifier: workspace:* version: link:../packages/engine-render - '@univerjs/facade': - specifier: workspace:* - version: link:../packages/facade '@univerjs/find-replace': specifier: workspace:* version: link:../packages/find-replace @@ -306,6 +306,9 @@ importers: '@univerjs/sheets-numfmt': specifier: workspace:* version: link:../packages/sheets-numfmt + '@univerjs/sheets-numfmt-ui': + specifier: workspace:* + version: link:../packages/sheets-numfmt-ui '@univerjs/sheets-sort': specifier: workspace:* version: link:../packages/sheets-sort @@ -315,9 +318,9 @@ importers: '@univerjs/sheets-thread-comment': specifier: workspace:* version: link:../packages/sheets-thread-comment - '@univerjs/sheets-thread-comment-base': + '@univerjs/sheets-thread-comment-ui': specifier: workspace:* - version: link:../packages/sheets-thread-comment-base + version: link:../packages/sheets-thread-comment-ui '@univerjs/sheets-ui': specifier: workspace:* version: link:../packages/sheets-ui @@ -419,6 +422,82 @@ importers: specifier: ^5.6.3 version: 5.6.3 + examples-node: + dependencies: + '@univerjs/core': + specifier: workspace:* + version: link:../packages/core + '@univerjs/data-validation': + specifier: workspace:* + version: link:../packages/data-validation + '@univerjs/docs': + specifier: workspace:* + version: link:../packages/docs + '@univerjs/docs-drawing': + specifier: workspace:* + version: link:../packages/docs-drawing + '@univerjs/drawing': + specifier: workspace:* + version: link:../packages/drawing + '@univerjs/engine-formula': + specifier: workspace:* + version: link:../packages/engine-formula + '@univerjs/rpc': + specifier: workspace:* + version: link:../packages/rpc + '@univerjs/rpc-node': + specifier: workspace:* + version: link:../packages/rpc-node + '@univerjs/sheets': + specifier: workspace:* + version: link:../packages/sheets + '@univerjs/sheets-conditional-formatting': + specifier: workspace:* + version: link:../packages/sheets-conditional-formatting + '@univerjs/sheets-data-validation': + specifier: workspace:* + version: link:../packages/sheets-data-validation + '@univerjs/sheets-drawing': + specifier: workspace:* + version: link:../packages/sheets-drawing + '@univerjs/sheets-filter': + specifier: workspace:* + version: link:../packages/sheets-filter + '@univerjs/sheets-formula': + specifier: workspace:* + version: link:../packages/sheets-formula + '@univerjs/sheets-hyper-link': + specifier: workspace:* + version: link:../packages/sheets-hyper-link + '@univerjs/sheets-sort': + specifier: workspace:* + version: link:../packages/sheets-sort + '@univerjs/thread-comment': + specifier: workspace:* + version: link:../packages/thread-comment + rxjs: + specifier: ^7.8.1 + version: 7.8.1 + devDependencies: + '@univerjs-infra/shared': + specifier: workspace:* + version: link:../common/shared + esbuild: + specifier: ^0.24.0 + version: 0.24.0 + esbuild-plugin-clean: + specifier: ^1.0.1 + version: 1.0.1(esbuild@0.24.0) + esbuild-plugin-copy: + specifier: ^2.1.1 + version: 2.1.1(esbuild@0.24.0) + minimist: + specifier: ^1.2.8 + version: 1.2.8 + typescript: + specifier: ^5.6.3 + version: 5.6.3 + mockdata: dependencies: '@univerjs/core': @@ -463,9 +542,9 @@ importers: '@univerjs/sheets-sort': specifier: workspace:* version: link:../packages/sheets-sort - '@univerjs/sheets-thread-comment-base': + '@univerjs/sheets-thread-comment': specifier: workspace:* - version: link:../packages/sheets-thread-comment-base + version: link:../packages/sheets-thread-comment '@univerjs/thread-comment': specifier: workspace:* version: link:../packages/thread-comment @@ -500,9 +579,9 @@ importers: '@univerjs/sheets': specifier: workspace:* version: link:../../packages/sheets - '@univerjs/sheets-filter-ui': + '@univerjs/sheets-filter': specifier: workspace:* - version: link:../../packages/sheets-filter-ui + version: link:../../packages/sheets-filter '@univerjs/sheets-ui': specifier: workspace:* version: link:../../packages/sheets-ui @@ -546,9 +625,6 @@ importers: '@univerjs/engine-render': specifier: workspace:* version: link:../../packages/engine-render - '@univerjs/facade': - specifier: workspace:* - version: link:../../packages/facade '@univerjs/mockdata': specifier: workspace:* version: link:../../mockdata @@ -588,31 +664,6 @@ importers: specifier: ^2.1.2 version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) - packages-experimental/rpc-node: - dependencies: - '@univerjs/core': - specifier: workspace:* - version: link:../../packages/core - '@univerjs/rpc': - specifier: workspace:* - version: link:../../packages/rpc - rxjs: - specifier: ^7.8.1 - version: 7.8.1 - devDependencies: - '@univerjs-infra/shared': - specifier: workspace:* - version: link:../../common/shared - typescript: - specifier: ^5.6.3 - version: 5.6.3 - vite: - specifier: ^5.4.8 - version: 5.4.8(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) - vitest: - specifier: ^2.1.2 - version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) - packages-experimental/uni-docs-ui: dependencies: '@univerjs/core': @@ -1683,6 +1734,9 @@ importers: '@univerjs/sheets-numfmt': specifier: workspace:* version: link:../sheets-numfmt + '@univerjs/sheets-numfmt-ui': + specifier: workspace:* + version: link:../sheets-numfmt-ui '@univerjs/sheets-thread-comment': specifier: workspace:* version: link:../sheets-thread-comment @@ -1814,6 +1868,31 @@ importers: specifier: ^2.1.2 version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + packages/rpc-node: + dependencies: + '@univerjs/core': + specifier: workspace:* + version: link:../core + '@univerjs/rpc': + specifier: workspace:* + version: link:../rpc + rxjs: + specifier: ^7.8.1 + version: 7.8.1 + devDependencies: + '@univerjs-infra/shared': + specifier: workspace:* + version: link:../../common/shared + typescript: + specifier: ^5.6.3 + version: 5.6.3 + vite: + specifier: ^5.4.8 + version: 5.4.8(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + vitest: + specifier: ^2.1.2 + version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + packages/sheets: dependencies: '@univerjs/core': @@ -2413,9 +2492,9 @@ importers: '@univerjs/sheets-formula': specifier: workspace:* version: link:../sheets-formula - '@univerjs/sheets-numfmt': + '@univerjs/sheets-numfmt-ui': specifier: workspace:* - version: link:../sheets-numfmt + version: link:../sheets-numfmt-ui '@univerjs/sheets-ui': specifier: workspace:* version: link:../sheets-ui @@ -2459,6 +2538,9 @@ importers: '@univerjs/core': specifier: workspace:* version: link:../core + '@univerjs/docs': + specifier: workspace:* + version: link:../docs '@univerjs/engine-formula': specifier: workspace:* version: link:../engine-formula @@ -2547,6 +2629,37 @@ importers: version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) packages/sheets-numfmt: + dependencies: + '@univerjs/core': + specifier: workspace:* + version: link:../core + '@univerjs/engine-formula': + specifier: workspace:* + version: link:../engine-formula + '@univerjs/engine-numfmt': + specifier: workspace:* + version: link:../engine-numfmt + '@univerjs/sheets': + specifier: workspace:* + version: link:../sheets + devDependencies: + '@univerjs-infra/shared': + specifier: workspace:* + version: link:../../common/shared + rxjs: + specifier: ^7.8.1 + version: 7.8.1 + typescript: + specifier: ^5.6.3 + version: 5.6.3 + vite: + specifier: ^5.4.8 + version: 5.4.8(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + vitest: + specifier: ^2.1.2 + version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + + packages/sheets-numfmt-ui: dependencies: '@univerjs/core': specifier: workspace:* @@ -2564,11 +2677,14 @@ importers: specifier: workspace:* version: link:../engine-render '@univerjs/icons': - specifier: ^0.1.84 + specifier: ^0.1.79 version: 0.1.84(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@univerjs/sheets': specifier: workspace:* version: link:../sheets + '@univerjs/sheets-numfmt': + specifier: workspace:* + version: link:../sheets-numfmt '@univerjs/sheets-ui': specifier: workspace:* version: link:../sheets-ui @@ -2692,39 +2808,15 @@ importers: '@univerjs/core': specifier: workspace:* version: link:../core - '@univerjs/design': - specifier: workspace:* - version: link:../design '@univerjs/engine-formula': specifier: workspace:* version: link:../engine-formula - '@univerjs/engine-render': - specifier: workspace:* - version: link:../engine-render - '@univerjs/icons': - specifier: ^0.1.84 - version: 0.1.84(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@univerjs/sheets': specifier: workspace:* version: link:../sheets - '@univerjs/sheets-thread-comment-base': - specifier: workspace:* - version: link:../sheets-thread-comment-base - '@univerjs/sheets-ui': - specifier: workspace:* - version: link:../sheets-ui '@univerjs/thread-comment': specifier: workspace:* version: link:../thread-comment - '@univerjs/thread-comment-ui': - specifier: workspace:* - version: link:../thread-comment-ui - '@univerjs/ui': - specifier: workspace:* - version: link:../ui - clsx: - specifier: ^2.1.1 - version: 2.1.1 devDependencies: '@univerjs-infra/shared': specifier: workspace:* @@ -2745,7 +2837,7 @@ importers: specifier: ^2.1.2 version: 2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) - packages/sheets-thread-comment-base: + packages/sheets-thread-comment-ui: dependencies: '@univerjs/core': specifier: workspace:* @@ -2753,18 +2845,39 @@ importers: '@univerjs/design': specifier: workspace:* version: link:../design + '@univerjs/docs-ui': + specifier: workspace:* + version: link:../docs-ui '@univerjs/engine-formula': specifier: workspace:* version: link:../engine-formula + '@univerjs/engine-render': + specifier: workspace:* + version: link:../engine-render + '@univerjs/icons': + specifier: ^0.1.79 + version: 0.1.84(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@univerjs/sheets': specifier: workspace:* version: link:../sheets + '@univerjs/sheets-thread-comment': + specifier: workspace:* + version: link:../sheets-thread-comment + '@univerjs/sheets-ui': + specifier: workspace:* + version: link:../sheets-ui '@univerjs/thread-comment': specifier: workspace:* version: link:../thread-comment + '@univerjs/thread-comment-ui': + specifier: workspace:* + version: link:../thread-comment-ui '@univerjs/ui': specifier: workspace:* version: link:../ui + clsx: + specifier: ^2.1.1 + version: 2.1.1 devDependencies: '@univerjs-infra/shared': specifier: workspace:* @@ -3032,6 +3145,9 @@ importers: '@univerjs/protocol': specifier: 0.1.39-alpha.38 version: 0.1.39-alpha.38(@grpc/grpc-js@1.10.9)(rxjs@7.8.1) + dayjs: + specifier: ^1.11.13 + version: 1.11.13 devDependencies: '@univerjs-infra/shared': specifier: workspace:* @@ -3288,9 +3404,9 @@ importers: '@univerjs/sheets-hyper-link-ui': specifier: workspace:* version: link:../sheets-hyper-link-ui - '@univerjs/sheets-numfmt': + '@univerjs/sheets-numfmt-ui': specifier: workspace:* - version: link:../sheets-numfmt + version: link:../sheets-numfmt-ui '@univerjs/sheets-sort': specifier: workspace:* version: link:../sheets-sort @@ -3300,9 +3416,9 @@ importers: '@univerjs/sheets-thread-comment': specifier: workspace:* version: link:../sheets-thread-comment - '@univerjs/sheets-thread-comment-base': + '@univerjs/sheets-thread-comment-ui': specifier: workspace:* - version: link:../sheets-thread-comment-base + version: link:../sheets-thread-comment-ui '@univerjs/sheets-ui': specifier: workspace:* version: link:../sheets-ui @@ -4553,55 +4669,46 @@ packages: resolution: {integrity: sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.21.2': resolution: {integrity: sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.21.2': resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.21.2': resolution: {integrity: sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.21.2': resolution: {integrity: sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.21.2': resolution: {integrity: sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.21.2': resolution: {integrity: sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.21.2': resolution: {integrity: sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.21.2': resolution: {integrity: sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.21.2': resolution: {integrity: sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==} @@ -4883,28 +4990,24 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-musl@1.7.5': resolution: {integrity: sha512-5ArGdqvFMszNHdi4a67vopeYq8d1K+FuTWDrblHrAvZFhAyv+GQz2PnKqYOgl0sWmQxsNPfNwBFtxACpUO3Jzg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-x64-gnu@1.7.5': resolution: {integrity: sha512-mSVVV/PFzCGtI1nVQQyx34NwCMgSurF6ZX/me8pUAX054vsE/pSFL66xN+kQOe/1Z/LOd4UmXFkZ/EzOSnYcSg==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-musl@1.7.5': resolution: {integrity: sha512-09hY3ZKMUORXVunESKS9yuP78+gQbr759GKHo8wyCdtAx8lCZdEjfI5NtC7/1VqwfeE32/U6u+5MBTVhZTt0AA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-win32-arm64-msvc@1.7.5': resolution: {integrity: sha512-B/UDtPI3RlYRFW42xQxOpl6kI/9LtkD7No+XeRIKQTPe15EP2o+rUlv7CmKljVBXgJ8KmaQbZlaEh1YP+QZEEQ==} @@ -5056,6 +5159,9 @@ packages: '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -5068,6 +5174,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/less@3.0.6': resolution: {integrity: sha512-PecSzorDGdabF57OBeQO/xFbAkYWo88g4Xvnsx7LRwqLC17I7OoKtA3bQB9uXkY6UkMWCOsA8HSVpaoitscdXw==} @@ -5092,6 +5201,9 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/node@14.18.63': + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} + '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} @@ -10265,6 +10377,10 @@ packages: vite: optional: true + vite-plugin-external@4.3.1: + resolution: {integrity: sha512-aoukfac66QevFAbRF2ZD81WPSqeqhgEfbfhPYQP9RPWO1en+Lw4HyhWRdvSjYn56gcKUJCtHdFG2jEpYgleLng==} + engines: {node: '>=14.18.0', vite: '>=3.1.0'} + vite@5.4.8: resolution: {integrity: sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -10577,7 +10693,7 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 - '@antfu/eslint-config@3.7.3(@eslint-react/eslint-plugin@1.14.3(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@vue/compiler-sfc@3.4.38)(eslint-plugin-format@0.1.2(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-hooks@5.0.0(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-refresh@0.4.12(eslint@9.12.0(jiti@1.21.6)))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6))': + '@antfu/eslint-config@3.7.3(@eslint-react/eslint-plugin@1.14.3(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(@vue/compiler-sfc@3.4.38)(eslint-plugin-format@0.1.2(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-hooks@5.0.0(eslint@9.12.0(jiti@1.21.6)))(eslint-plugin-react-refresh@0.4.12(eslint@9.12.0(jiti@1.21.6)))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6))': dependencies: '@antfu/install-pkg': 0.4.1 '@clack/prompts': 0.7.0 @@ -10586,7 +10702,7 @@ snapshots: '@stylistic/eslint-plugin': 2.8.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3) '@typescript-eslint/eslint-plugin': 8.7.0(@typescript-eslint/parser@8.8.1(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3) '@typescript-eslint/parser': 8.8.1(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3) - '@vitest/eslint-plugin': 1.1.4(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6)) + '@vitest/eslint-plugin': 1.1.4(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6)) eslint: 9.12.0(jiti@1.21.6) eslint-config-flat-gitignore: 0.3.0(eslint@9.12.0(jiti@1.21.6)) eslint-flat-config-utils: 0.4.0 @@ -12263,6 +12379,11 @@ snapshots: '@types/qs': 6.9.15 '@types/serve-static': 1.15.7 + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 22.7.5 + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -12273,6 +12394,10 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 22.7.5 + '@types/less@3.0.6': {} '@types/lodash-es@4.17.12': @@ -12293,6 +12418,8 @@ snapshots: '@types/ms@0.7.34': {} + '@types/node@14.18.63': {} + '@types/node@22.7.5': dependencies: undici-types: 6.19.8 @@ -12522,7 +12649,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/eslint-plugin@1.1.4(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6))': + '@vitest/eslint-plugin@1.1.4(@typescript-eslint/utils@8.7.0(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3))(eslint@9.12.0(jiti@1.21.6))(typescript@5.6.3)(vitest@2.1.2(@types/node@22.7.5)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6))': dependencies: eslint: 9.12.0(jiti@1.21.6) optionalDependencies: @@ -18316,6 +18443,12 @@ snapshots: - rollup - supports-color + vite-plugin-external@4.3.1: + dependencies: + '@types/fs-extra': 11.0.4 + '@types/node': 14.18.63 + fs-extra: 11.2.0 + vite@5.4.8(@types/node@22.7.5)(less@4.2.0)(sass@1.77.5)(terser@5.31.6): dependencies: esbuild: 0.21.5 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 063339911bd..bc7a8af1841 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,7 @@ packages: - common/* - examples - # - examples-node + - examples-node - mockdata - packages-experimental/* - packages/*