From 2a9605c52dc67e45001a65307a57e84f11267b67 Mon Sep 17 00:00:00 2001 From: zhangw Date: Mon, 18 Nov 2024 11:47:25 +0800 Subject: [PATCH 1/3] feat: add hover facade api --- packages/sheets-ui/src/facade/f-workbook.ts | 39 ++++++++++++++++++- .../src/services/hover-manager.service.ts | 25 +++++++++--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/packages/sheets-ui/src/facade/f-workbook.ts b/packages/sheets-ui/src/facade/f-workbook.ts index 16e6d3e4df1..d757763f3d7 100644 --- a/packages/sheets-ui/src/facade/f-workbook.ts +++ b/packages/sheets-ui/src/facade/f-workbook.ts @@ -14,9 +14,12 @@ * limitations under the License. */ -import { type IDisposable, ILogService } from '@univerjs/core'; +import type { IHoverRichTextInfo, IHoverRichTextPosition } from '../services/hover-manager.service'; +import { type IDisposable, ILogService, toDisposable } from '@univerjs/core'; import { FWorkbook } from '@univerjs/sheets/facade'; +import { HoverManagerService } from '@univerjs/sheets-ui'; import { type IDialogPartMethodOptions, IDialogService, type ISidebarMethodOptions, ISidebarService } from '@univerjs/ui'; +import { filter } from 'rxjs'; interface IFWorkbookSheetsUIMixin { /** @@ -38,6 +41,22 @@ interface IFWorkbookSheetsUIMixin { * @returns the disposable object */ openDialog(dialog: IDialogPartMethodOptions): IDisposable; + + /** + * Subscribe to cell click events + * + * @param callback - The callback function to be called when a cell is clicked + * @returns A disposable object that can be used to unsubscribe from the event + */ + onCellClick(callback: (cell: IHoverRichTextInfo) => void): IDisposable; + + /** + * Subscribe cell hover events + * + * @param callback - The callback function to be called when a cell is hovered + * @returns A disposable object that can be used to unsubscribe from the event + */ + onCellHover(callback: (cell: IHoverRichTextPosition) => void): IDisposable; } class FWorokbookSheetsUIMixin extends FWorkbook implements IFWorkbookSheetsUIMixin { @@ -67,6 +86,24 @@ class FWorokbookSheetsUIMixin extends FWorkbook implements IFWorkbookSheetsUIMix logService.warn('[FWorkbook]', `${name} is deprecated. Please use the function of the same name on "FUniver".`); } + + override onCellClick(callback: (cell: IHoverRichTextInfo) => void): IDisposable { + const hoverManagerService = this._injector.get(HoverManagerService); + return toDisposable( + hoverManagerService.currentClickedCell$ + .pipe(filter((cell) => !!cell)) + .subscribe(callback) + ); + } + + override onCellHover(callback: (cell: IHoverRichTextPosition) => void): IDisposable { + const hoverManagerService = this._injector.get(HoverManagerService); + return toDisposable( + hoverManagerService.currentRichText$ + .pipe(filter((cell) => !!cell)) + .subscribe(callback) + ); + } } FWorkbook.extend(FWorokbookSheetsUIMixin); diff --git a/packages/sheets-ui/src/services/hover-manager.service.ts b/packages/sheets-ui/src/services/hover-manager.service.ts index b792f08895b..5eb8dca1012 100644 --- a/packages/sheets-ui/src/services/hover-manager.service.ts +++ b/packages/sheets-ui/src/services/hover-manager.service.ts @@ -16,7 +16,7 @@ import type { ICustomRange, IParagraph, IPosition, Nullable, Workbook } from '@univerjs/core'; import type { IBoundRectNoAngle, SpreadsheetSkeleton } from '@univerjs/engine-render'; -import type { ISheetLocation } from '@univerjs/sheets'; +import type { ISheetLocation, ISheetLocationBase } from '@univerjs/sheets'; import { Disposable, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { BehaviorSubject, distinctUntilChanged, map, Subject } from 'rxjs'; @@ -33,7 +33,22 @@ export interface IHoverCellPosition { location: ISheetLocation; } -export interface IHoverRichTextPosition extends IHoverCellPosition { +export interface IHoverRichTextInfo extends IHoverCellPosition { + /** + * active custom range in cell, if cell is rich-text + */ + customRange?: Nullable; + /** + * active bullet in cell, if cell is rich-text + */ + bullet?: Nullable; + /** + * rect of custom-range or bullet + */ + rect?: Nullable; +} + +export interface IHoverRichTextPosition extends ISheetLocationBase { /** * active custom range in cell, if cell is rich-text */ @@ -50,8 +65,8 @@ export interface IHoverRichTextPosition extends IHoverCellPosition { export class HoverManagerService extends Disposable { private _currentCell$ = new BehaviorSubject>(null); - private _currentRichText$ = new BehaviorSubject>(null); - private _currentClickedCell$ = new Subject(); + private _currentRichText$ = new BehaviorSubject>(null); + private _currentClickedCell$ = new Subject(); // Notify when hovering over different cells currentCell$ = this._currentCell$.asObservable().pipe( @@ -88,7 +103,7 @@ export class HoverManagerService extends Disposable { customRange: cell.customRange, bullet: cell.bullet, rect: cell.rect, - }) + } as IHoverRichTextPosition) ); // Notify when mouse position changes From 5d39bd9588f631d7df9a4d1edf75cdc95bf6675c Mon Sep 17 00:00:00 2001 From: zhangw Date: Mon, 18 Nov 2024 13:49:55 +0800 Subject: [PATCH 2/3] feat: update --- packages/sheets-ui/src/facade/f-range.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/sheets-ui/src/facade/f-range.ts b/packages/sheets-ui/src/facade/f-range.ts index 8bb468363e5..1e963cb676d 100644 --- a/packages/sheets-ui/src/facade/f-range.ts +++ b/packages/sheets-ui/src/facade/f-range.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import type { ICellWithCoord, IDisposable, Nullable } from '@univerjs/core'; -import type { ISheetLocation } from '@univerjs/sheets'; +import type { ICellWithCoord, IDisposable, ISelectionCell, Nullable } from '@univerjs/core'; +import type { ISelectionStyle, ISheetLocation } from '@univerjs/sheets'; import type { ComponentType } from '@univerjs/ui'; -import { DisposableCollection, generateRandomId } from '@univerjs/core'; +import { DisposableCollection, generateRandomId, toDisposable } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { FRange } from '@univerjs/sheets/facade'; -import { CellAlertManagerService, type ICanvasPopup, type ICellAlert, SheetCanvasPopManagerService } from '@univerjs/sheets-ui'; +import { CellAlertManagerService, type ICanvasPopup, type ICellAlert, IMarkSelectionService, SheetCanvasPopManagerService } from '@univerjs/sheets-ui'; import { ISheetClipboardService, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; import { ComponentManager } from '@univerjs/ui'; @@ -69,6 +69,10 @@ interface IFRangeSheetsUIMixin { */ attachAlertPopup(alert: Omit): IDisposable; + /** + * Highlight this range. + */ + highlight(style?: Nullable>, primary?: Nullable): IDisposable; } class FRangeSheetsUIMixin extends FRange implements IFRangeSheetsUIMixin { @@ -138,6 +142,15 @@ class FRangeSheetsUIMixin extends FRange implements IFRangeSheetsUIMixin { }, }; } + + override highlight(style?: Nullable>, primary?: Nullable): IDisposable { + const markSelectionService = this._injector.get(IMarkSelectionService); + const id = markSelectionService.addShape({ range: this._range, style, primary }); + + return toDisposable(() => { + id && markSelectionService.removeShape(id); + }); + } } FRange.extend(FRangeSheetsUIMixin); From 88bc0ecf85ea14eb07bdaac54e3d1303c28c6e5e Mon Sep 17 00:00:00 2001 From: zhangw Date: Mon, 18 Nov 2024 16:03:06 +0800 Subject: [PATCH 3/3] feat: update --- packages/sheets-ui/src/facade/f-range.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/sheets-ui/src/facade/f-range.ts b/packages/sheets-ui/src/facade/f-range.ts index 1e963cb676d..0475afdb2d5 100644 --- a/packages/sheets-ui/src/facade/f-range.ts +++ b/packages/sheets-ui/src/facade/f-range.ts @@ -147,8 +147,11 @@ class FRangeSheetsUIMixin extends FRange implements IFRangeSheetsUIMixin { const markSelectionService = this._injector.get(IMarkSelectionService); const id = markSelectionService.addShape({ range: this._range, style, primary }); + if (!id) { + throw new Error('Failed to highlight current range'); + } return toDisposable(() => { - id && markSelectionService.removeShape(id); + markSelectionService.removeShape(id); }); } }