diff --git a/packages/docs-ui/src/docs-ui-plugin.ts b/packages/docs-ui/src/docs-ui-plugin.ts index a2f5211ed6..e59c3b4c19 100644 --- a/packages/docs-ui/src/docs-ui-plugin.ts +++ b/packages/docs-ui/src/docs-ui-plugin.ts @@ -123,7 +123,6 @@ import { DocStateChangeManagerService } from './services/doc-state-change-manage import { DocsRenderService } from './services/docs-render.service'; import { EditorService, IEditorService } from './services/editor/editor-manager.service'; import { DocFloatMenuService } from './services/float-menu.service'; -import { IRangeSelectorService, RangeSelectorService } from './services/range-selector/range-selector.service'; import { DocSelectionRenderService } from './services/selection/doc-selection-render.service'; import { BreakLineShortcut, DeleteLeftShortcut, DeleteRightShortcut } from './shortcuts/core-editing.shortcut'; import { @@ -322,7 +321,6 @@ export class UniverDocsUIPlugin extends Plugin { [AppUIController], [DocParagraphSettingController], [IEditorService, { useClass: EditorService }], - [IRangeSelectorService, { useClass: RangeSelectorService }], [IDocClipboardService, { useClass: DocClipboardService }], [DocCanvasPopManagerService], [DocsRenderService], diff --git a/packages/docs-ui/src/index.ts b/packages/docs-ui/src/index.ts index 8bdda26874..0a56c230f2 100644 --- a/packages/docs-ui/src/index.ts +++ b/packages/docs-ui/src/index.ts @@ -44,7 +44,6 @@ export { DocStateChangeManagerService } from './services/doc-state-change-manage export { DocsRenderService } from './services/docs-render.service'; export { Editor } from './services/editor/editor'; export { EditorService, IEditorService } from './services/editor/editor-manager.service'; -export { type IRangeSelectorRange, IRangeSelectorService, RangeSelectorService } from './services/range-selector/range-selector.service'; export { isInSameTableCell, isValidRectRange, NodePositionConvertToRectRange } from './services/selection/convert-rect-range'; export { NodePositionConvertToCursor } from './services/selection/convert-text-range'; diff --git a/packages/docs-ui/src/services/range-selector/range-selector.service.ts b/packages/docs-ui/src/services/range-selector/range-selector.service.ts deleted file mode 100644 index 033eb28dac..0000000000 --- a/packages/docs-ui/src/services/range-selector/range-selector.service.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * 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 { createIdentifier, Disposable } from '@univerjs/core'; -import { BehaviorSubject, Subject } from 'rxjs'; -import type { IDisposable, IUnitRange, Nullable } from '@univerjs/core'; -import type { Observable } from 'rxjs'; - -export interface IRangeSelectorRange extends IUnitRange { - sheetName: string; -} - -export interface IRangeSelectorService { - selectionChange$: Observable; - selectionChange(ranges: IRangeSelectorRange[]): void; - - setCurrentSelectorId(id: Nullable): void; - getCurrentSelectorId(): Nullable; - - openSelector$: Observable; - openSelector(): void; - - selectorModalVisible$: Observable; - get selectorModalVisible(): boolean; - triggerModalVisibleChange(visible: boolean): void; -} - -export class RangeSelectorService extends Disposable implements IRangeSelectorService, IDisposable { - private _currentSelectorId: Nullable; - - private readonly _selectionChange$ = new Subject(); - readonly selectionChange$ = this._selectionChange$.asObservable(); - - private readonly _openSelector$ = new Subject(); - readonly openSelector$ = this._openSelector$.asObservable(); - - private readonly _selectorModalVisible$ = new BehaviorSubject(false); - readonly selectorModalVisible$ = this._selectorModalVisible$.asObservable(); - - get selectorModalVisible() { - return this._selectorModalVisible$.getValue(); - } - - setCurrentSelectorId(id: Nullable) { - this._currentSelectorId = id; - } - - getCurrentSelectorId(): Nullable { - return this._currentSelectorId; - } - - selectionChange(range: IRangeSelectorRange[]) { - if (!this._currentSelectorId) { - return; - } - this._selectionChange$.next(range); - } - - openSelector() { - this._openSelector$.next(null); - } - - triggerModalVisibleChange(visible: boolean) { - this._selectorModalVisible$.next(visible); - } -} - -export const IRangeSelectorService = createIdentifier( - 'univer.range-selector.service' -); diff --git a/packages/engine-render/src/render-manager/render-manager.service.ts b/packages/engine-render/src/render-manager/render-manager.service.ts index a03f1f2caa..1ac7ce30f9 100644 --- a/packages/engine-render/src/render-manager/render-manager.service.ts +++ b/packages/engine-render/src/render-manager/render-manager.service.ts @@ -352,7 +352,7 @@ export function getCurrentTypeOfRenderer( instanceService: IUniverInstanceService, renderManageService: IRenderManagerService ): Nullable { - const currentUnit = instanceService.getCurrentUnitForType(type); + const currentUnit = instanceService.getCurrentUnitOfType(type); if (currentUnit == null) { return null; } diff --git a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/ColorScale.tsx b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/ColorScale.tsx index c1334a5d8a..db8058c729 100644 --- a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/ColorScale.tsx +++ b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/ColorScale.tsx @@ -16,13 +16,14 @@ import type { Workbook } from '@univerjs/core'; import type { IColorScale, IConditionalFormattingRuleConfig } from '@univerjs/sheets-conditional-formatting'; +import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui'; import type { IStyleEditorProps } from './type'; import { IUniverInstanceService, LocaleService, UniverInstanceType } from '@univerjs/core'; import { clsx, InputNumber, Select } from '@univerjs/design'; import { CFRuleType, CFValueType, createDefaultValueByValueType } from '@univerjs/sheets-conditional-formatting'; import { FormulaEditor } from '@univerjs/sheets-formula-ui'; import { useDependency, useSidebarClick } from '@univerjs/ui'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { ColorPicker } from '../../color-picker'; import { Preview } from '../../preview'; import stylesBase from '../index.module.less'; @@ -38,6 +39,7 @@ const TextInput = (props: { id: string; type: CFValueType | 'none'; value: numbe const formulaInitValue = useMemo(() => { return String(value).startsWith('=') ? String(value) : '='; }, [value]); + const config = useMemo(() => { if ([CFValueType.max, CFValueType.min, 'none'].includes(type as CFValueType)) { return { disabled: true }; @@ -54,12 +56,12 @@ const TextInput = (props: { id: string; type: CFValueType | 'none'; value: numbe }; }, [type]); - const formulaEditorActionsRef = useRef[0]['actions']>({}); + const formulaEditorRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); if (type === CFValueType.formula) { @@ -75,7 +77,7 @@ const TextInput = (props: { id: string; type: CFValueType | 'none'; value: numbe onChange(formula); }} onFocus={() => isFocusFormulaEditorSet(true)} - actions={formulaEditorActionsRef.current} + ref={formulaEditorRef} /> ); diff --git a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/DataBar.tsx b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/DataBar.tsx index 633b5d47a8..306b8fc992 100644 --- a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/DataBar.tsx +++ b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/DataBar.tsx @@ -16,14 +16,15 @@ import type { Workbook } from '@univerjs/core'; import type { IConditionalFormattingRuleConfig, IValueConfig } from '@univerjs/sheets-conditional-formatting'; +import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui'; import type { IStyleEditorProps } from './type'; import { IUniverInstanceService, LocaleService, UniverInstanceType } from '@univerjs/core'; import { Checkbox, InputNumber, Radio, RadioGroup, Select } from '@univerjs/design'; -import { CFRuleType, CFValueType, createDefaultValueByValueType, defaultDataBarNativeColor, defaultDataBarPositiveColor } from '@univerjs/sheets-conditional-formatting'; +import { CFRuleType, CFValueType, createDefaultValueByValueType, defaultDataBarNativeColor, defaultDataBarPositiveColor } from '@univerjs/sheets-conditional-formatting'; import { FormulaEditor } from '@univerjs/sheets-formula-ui'; import { useDependency, useSidebarClick } from '@univerjs/ui'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { ColorPicker } from '../../color-picker'; import { Preview } from '../../preview'; import stylesBase from '../index.module.less'; @@ -37,12 +38,12 @@ const InputText = (props: { disabled?: boolean; id: string; className: string; t const unitId = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getUnitId(); const subUnitId = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getActiveSheet()?.getSheetId(); - const formulaEditorActionsRef = useRef[0]['actions']>({}); + const formulaEditorRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); const _value = useRef(value); @@ -72,7 +73,7 @@ const InputText = (props: { disabled?: boolean; id: string; className: string; t onChange(formula); }} onFocus={() => isFocusFormulaEditorSet(true)} - actions={formulaEditorActionsRef.current} + ref={formulaEditorRef} /> ); diff --git a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/Formula.tsx b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/Formula.tsx index 7a8827e3e7..c1f2eb55af 100644 --- a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/Formula.tsx +++ b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/Formula.tsx @@ -16,12 +16,13 @@ import type { Workbook } from '@univerjs/core'; import type { IAverageHighlightCell, IConditionalFormattingRuleConfig, IHighlightCell, IRankHighlightCell } from '@univerjs/sheets-conditional-formatting'; +import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui'; import type { IStyleEditorProps } from './type'; import { IUniverInstanceService, LocaleService, UniverInstanceType } from '@univerjs/core'; import { CFRuleType, CFSubRuleType } from '@univerjs/sheets-conditional-formatting'; import { FormulaEditor } from '@univerjs/sheets-formula-ui'; import { useDependency, useSidebarClick } from '@univerjs/ui'; -import React, { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { ConditionalStyleEditor } from '../../conditional-style-editor'; import { Preview } from '../../preview'; import stylesBase from '../index.module.less'; @@ -38,7 +39,7 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => { const divEleRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); - const formulaEditorActionsRef = useRef[0]['actions']>({}); + const formulaEditorRef = useRef(null); const [style, styleSet] = useState({}); const [formula, formulaSet] = useState(() => { if (rule?.subType === CFSubRuleType.formula) { @@ -89,8 +90,8 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => { }; useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); return ( @@ -123,11 +124,11 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => { }} errorText={formulaError} onFocus={() => { isFocusFormulaEditorSet(true); }} - actions={formulaEditorActionsRef.current} isFocus={isFocusFormulaEditor} initValue={formula as any} unitId={workbook.getUnitId()} subUnitId={worksheet?.getSheetId()} + ref={formulaEditorRef} /> diff --git a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/IconSet.tsx b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/IconSet.tsx index befee23bee..04fbfcfed3 100644 --- a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/IconSet.tsx +++ b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/IconSet.tsx @@ -16,11 +16,13 @@ import type { Workbook } from '@univerjs/core'; import type { IIconSet, IIconType } from '@univerjs/sheets-conditional-formatting'; -import type { IStyleEditorProps } from './type'; +import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui'; +import type { IStyleEditorProps } from './type'; import { get, IUniverInstanceService, LocaleService, set, Tools, UniverInstanceType } from '@univerjs/core'; import { Checkbox, clsx, Dropdown, InputNumber, Select } from '@univerjs/design'; import { MoreDownSingle, SlashSingle } from '@univerjs/icons'; + import { CFNumberOperator, CFRuleType, @@ -33,11 +35,10 @@ import { iconGroup, iconMap, } from '@univerjs/sheets-conditional-formatting'; - import { FormulaEditor } from '@univerjs/sheets-formula-ui'; import { ILayoutService, useDependency, useScrollYOverContainer, useSidebarClick } from '@univerjs/ui'; -import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react'; +import { forwardRef, useEffect, useMemo, useRef, useState } from 'react'; import stylesBase from '../index.module.less'; import styles from './index.module.less'; @@ -58,12 +59,12 @@ const TextInput = (props: { id: number; type: CFValueType; value: number | strin return ''; }, [props.error]); - const formulaEditorActionsRef = useRef[0]['actions']>({}); + const formulaEditorRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); return (
@@ -90,7 +91,7 @@ const TextInput = (props: { id: number; type: CFValueType; value: number | strin props.onChange(formula); }} onFocus={() => isFocusFormulaEditorSet(true)} - actions={formulaEditorActionsRef.current} + ref={formulaEditorRef} />
)} diff --git a/packages/sheets-data-validation-ui/src/views/components/formula-input/custom-formula-input.tsx b/packages/sheets-data-validation-ui/src/views/components/formula-input/custom-formula-input.tsx index fce208da5f..fc9933bbb1 100644 --- a/packages/sheets-data-validation-ui/src/views/components/formula-input/custom-formula-input.tsx +++ b/packages/sheets-data-validation-ui/src/views/components/formula-input/custom-formula-input.tsx @@ -15,19 +15,20 @@ */ import type { IFormulaInputProps } from '@univerjs/data-validation'; +import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui'; import { FormulaEditor } from '@univerjs/sheets-formula-ui'; import { useSidebarClick } from '@univerjs/ui'; -import React, { useRef, useState } from 'react'; +import { useRef, useState } from 'react'; export function CustomFormulaInput(props: IFormulaInputProps) { const { unitId, subUnitId, value, onChange, showError, validResult } = props; const formula1Res = showError ? validResult?.formula1 : undefined; - const formulaEditorActionsRef = useRef[0]['actions']>({}); + const formulaEditorRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); return ( @@ -49,8 +50,8 @@ export function CustomFormulaInput(props: IFormulaInputProps) { }} errorText={formula1Res} onFocus={() => isFocusFormulaEditorSet(true)} - actions={formulaEditorActionsRef.current} isSupportAcrossSheet + ref={formulaEditorRef} /> ); } diff --git a/packages/sheets-data-validation-ui/src/views/components/formula-input/list-formula-input.tsx b/packages/sheets-data-validation-ui/src/views/components/formula-input/list-formula-input.tsx index 52c90d7904..885f261b9d 100644 --- a/packages/sheets-data-validation-ui/src/views/components/formula-input/list-formula-input.tsx +++ b/packages/sheets-data-validation-ui/src/views/components/formula-input/list-formula-input.tsx @@ -16,6 +16,7 @@ import type { IFormulaInputProps } from '@univerjs/data-validation'; import type { ListValidator } from '@univerjs/sheets-data-validation'; +import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui'; import type { CSSProperties } from 'react'; import { DataValidationType, isFormulaString, LocaleService, Tools } from '@univerjs/core'; import { DataValidationModel, DataValidatorRegistryService } from '@univerjs/data-validation'; @@ -308,12 +309,12 @@ export function ListFormulaInput(props: IFormulaInputProps) { } }); - const formulaEditorActionsRef = useRef[0]['actions']>({}); + const formulaEditorRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); return ( @@ -351,8 +352,8 @@ export function ListFormulaInput(props: IFormulaInputProps) { }} errorText={(formula1Res || localError) || undefined} onFocus={() => isFocusFormulaEditorSet(true)} - actions={formulaEditorActionsRef.current} isSupportAcrossSheet + ref={formulaEditorRef} />
{refFinalList.map((item) => { diff --git a/packages/sheets-formula-ui/src/index.ts b/packages/sheets-formula-ui/src/index.ts index 3005c79b1e..11f0006ce5 100644 --- a/packages/sheets-formula-ui/src/index.ts +++ b/packages/sheets-formula-ui/src/index.ts @@ -23,7 +23,7 @@ export { InsertFunctionOperation } from './commands/operations/insert-function.o export { MoreFunctionsOperation } from './commands/operations/more-functions.operation'; export { ReferenceAbsoluteOperation } from './commands/operations/reference-absolute.operation'; export { SearchFunctionOperation } from './commands/operations/search-function.operation'; -export { FormulaEditor } from './views/formula-editor/index'; +export { FormulaEditor, type IFormulaEditorRef } from './views/formula-editor/index'; export { type IRangeSelectorInstance, type IRangeSelectorProps, RangeSelector } from './views/range-selector/index'; export { RefSelectionsRenderService } from './services/render-services/ref-selections.render-service'; export { GlobalRangeSelectorService, type IShowRangeSelectorDialogOptions } from './services/range-selector.service'; diff --git a/packages/sheets-formula-ui/src/sheets-formula-ui.plugin.ts b/packages/sheets-formula-ui/src/sheets-formula-ui.plugin.ts index ec5f259513..ed47504491 100644 --- a/packages/sheets-formula-ui/src/sheets-formula-ui.plugin.ts +++ b/packages/sheets-formula-ui/src/sheets-formula-ui.plugin.ts @@ -80,11 +80,21 @@ export class UniverSheetsFormulaUIPlugin extends Plugin { [FormulaRenderManagerController], [FormulaReorderController], ]); + + this._initUIPart(); + } + + override onReady(): void { + // render basics + ([ + [RefSelectionsRenderService], + ] as Dependency[]).forEach((dep) => { + this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, dep)); + }); } override onRendered(): void { ([ - [RefSelectionsRenderService], [FormulaAlertRenderController], ] as Dependency[]).forEach((dep) => { this.disposeWithMe(this._renderManagerService.registerRenderModule(UniverInstanceType.UNIVER_SHEET, dep)); @@ -95,10 +105,6 @@ export class UniverSheetsFormulaUIPlugin extends Plugin { [FormulaClipboardController], [FormulaRenderManagerController], ]); - - // Since component FormulaEditor relies on RefSelectionsRenderService, it should be - // registered after RefSelectionsRenderService is registered. - this._initUIPart(); } override onSteady(): void { diff --git a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-highlight.ts b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-highlight.ts index 77147ddb06..f5010f190a 100644 --- a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-highlight.ts +++ b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-highlight.ts @@ -40,9 +40,11 @@ export interface IRefSelection { index: number; } +// eslint-disable-next-line complexity, max-lines-per-function export function calcHighlightRanges(opts: { unitId: string; subUnitId: string; + currentWorkbook: Workbook; refSelections: IRefSelection[]; editor: Editor | undefined; refSelectionsService: SheetsSelectionsService; @@ -54,6 +56,7 @@ export function calcHighlightRanges(opts: { const { unitId, subUnitId, + currentWorkbook, refSelections, editor, refSelectionsService, @@ -62,10 +65,12 @@ export function calcHighlightRanges(opts: { themeService, univerInstanceService, } = opts; + const currentUnitId = currentWorkbook.getUnitId(); const workbook = univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); const worksheet = workbook?.getActiveSheet(); const selectionWithStyle: ISelectionWithStyle[] = []; - if (!workbook || !worksheet) { + const currentActiveWorksheet = currentWorkbook?.getActiveSheet(); + if (!workbook || !worksheet || (currentUnitId !== unitId && !currentActiveWorksheet)) { refSelectionsService.setSelections(selectionWithStyle); return; } @@ -74,7 +79,6 @@ export function calcHighlightRanges(opts: { const skeleton = sheetSkeletonManagerService?.getWorksheetSkeleton(currentSheetId)?.skeleton; if (!skeleton) return; - const endIndexes: number[] = []; for (let i = 0, len = refSelections.length; i < len; i++) { const refSelection = refSelections[i]; @@ -82,11 +86,15 @@ export function calcHighlightRanges(opts: { const unitRangeName = deserializeRangeWithSheet(token); const { unitId: refUnitId, sheetName, range: rawRange } = unitRangeName; - if (refUnitId && unitId !== refUnitId) { + const refSheetId = getSheetIdByName(sheetName); + + if (currentUnitId !== unitId && refUnitId !== currentUnitId) { continue; } - const refSheetId = getSheetIdByName(sheetName); + if (refUnitId && refUnitId !== currentUnitId) { + continue; + } if ((refSheetId && refSheetId !== currentSheetId) || (!refSheetId && currentSheetId !== subUnitId)) { continue; @@ -132,10 +140,13 @@ export function useSheetHighlight(unitId: string, subUnitId: string) { const sheetSkeletonManagerService = render?.with(SheetSkeletonManagerService); const highlightSheet = useEvent((refSelections: IRefSelection[], editor?: Editor) => { + const currentWorkbook = univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_SHEET); + if (!currentWorkbook) return; if (refSelectionsRenderService?.selectionMoving) return; const selectionWithStyle = calcHighlightRanges({ unitId, subUnitId, + currentWorkbook, refSelections, editor, refSelectionsService, @@ -144,7 +155,6 @@ export function useSheetHighlight(unitId: string, subUnitId: string) { themeService, univerInstanceService, }); - if (!selectionWithStyle) return; const allControls = refSelectionsRenderService?.getSelectionControls() || []; if (allControls.length === selectionWithStyle.length) { diff --git a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-refactor-effect.ts b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-refactor-effect.ts index 47f367c578..aee586c752 100644 --- a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-refactor-effect.ts +++ b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-refactor-effect.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { EDITOR_ACTIVATED, IContextService } from '@univerjs/core'; +import type { Workbook } from '@univerjs/core'; +import { EDITOR_ACTIVATED, IContextService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { IRefSelectionsService, REF_SELECTIONS_ENABLED } from '@univerjs/sheets'; -import { IContextMenuService, useDependency } from '@univerjs/ui'; +import { IContextMenuService, useDependency, useObservable } from '@univerjs/ui'; -import { useEffect, useLayoutEffect } from 'react'; +import { useEffect, useLayoutEffect, useMemo } from 'react'; import { RefSelectionsRenderService } from '../../../services/render-services/ref-selections.render-service'; export const useRefactorEffect = (isNeed: boolean, selecting: boolean, unitId: string, disableContextMenu = true) => { @@ -27,8 +28,9 @@ export const useRefactorEffect = (isNeed: boolean, selecting: boolean, unitId: s const contextService = useDependency(IContextService); const contextMenuService = useDependency(IContextMenuService); const refSelectionsService = useDependency(IRefSelectionsService); - - const render = renderManagerService.getRenderById(unitId); + const univerInstanceService = useDependency(IUniverInstanceService); + const currentUnit = useObservable(useMemo(() => univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET), [univerInstanceService])); + const render = renderManagerService.getRenderById(currentUnit?.getUnitId() ?? ''); const refSelectionsRenderService = render?.with(RefSelectionsRenderService); useLayoutEffect(() => { diff --git a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-reset-selection.ts b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-reset-selection.ts index e5b0dfccb6..30a321d407 100644 --- a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-reset-selection.ts +++ b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-reset-selection.ts @@ -29,6 +29,10 @@ export const useResetSelection = (isNeed: boolean, unitId: string, subUnitId: st const selections = [...sheetsSelectionsService.getWorkbookSelections(unitId).getSelectionsOfWorksheet(subUnitId)]; const workbook = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); const currentSheet = workbook?.getActiveSheet(); + if (workbook?.getUnitId() !== unitId) { + univerInstanceService.setCurrentUnitForType(unitId); + } + if (currentSheet && currentSheet.getSheetId() === subUnitId) { sheetsSelectionsService.setSelections(selections); } diff --git a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-sheet-selection-change.ts b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-sheet-selection-change.ts index 84ac4a7422..4c6eaf9229 100644 --- a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-sheet-selection-change.ts +++ b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-sheet-selection-change.ts @@ -21,7 +21,7 @@ import type { Editor } from '@univerjs/docs-ui'; import type { ISelectionWithCoord, ISetSelectionsOperationParams } from '@univerjs/sheets'; import type { RefObject } from 'react'; import type { IRefSelection } from './use-highlight'; -import { DisposableCollection, ICommandService, IUniverInstanceService, ThemeService } from '@univerjs/core'; +import { DisposableCollection, ICommandService, IUniverInstanceService, ThemeService, UniverInstanceType } from '@univerjs/core'; import { DocSelectionManagerService } from '@univerjs/docs'; import { deserializeRangeWithSheet, generateStringWithSequence, LexerTreeBuilder, sequenceNodeType, serializeRange, serializeRangeWithSheet } from '@univerjs/engine-formula'; import { IRenderManagerService } from '@univerjs/engine-render'; @@ -85,11 +85,12 @@ export const useSheetSelectionChange = ( const sheetName = useMemo(() => getSheetNameById(subUnitId), [getSheetNameById, subUnitId]); const activeSheet = useObservable(workbook?.activeSheet$); const contextRef = useStateRef({ activeSheet, sheetName }); - const render = renderManagerService.getRenderById(unitId); + const currentUnit = useObservable(useMemo(() => univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET), [univerInstanceService])); + const render = renderManagerService.getRenderById(currentUnit?.getUnitId() ?? ''); + const refSelectionsRenderService = render?.with(RefSelectionsRenderService); const sheetSkeletonManagerService = render?.with(SheetSkeletonManagerService); const refSelectionsService = useDependency(IRefSelectionsService); - // eslint-disable-next-line complexity const onSelectionsChange = useEvent((selections: IRange[], isEnd: boolean) => { const ctx = prepareSelectionChangeContext({ editor, lexerTreeBuilder }); @@ -105,11 +106,12 @@ export const useSheetSelectionChange = ( const rangeSheetId = range.sheetId ?? subUnitId; const unitRangeName = { range, - unitId: range.unitId ?? unitId, + unitId: range.unitId ?? currentUnit!.getUnitId(), sheetName: getSheetNameById(rangeSheetId), }; const isAcrossSheet = rangeSheetId !== subUnitId; - const refRanges = unitRangesToText([unitRangeName], isSupportAcrossSheet && isAcrossSheet, sheetName); + const isAcrossWorkbook = currentUnit?.getUnitId() !== unitId; + const refRanges = unitRangesToText([unitRangeName], isSupportAcrossSheet && (isAcrossSheet || isAcrossWorkbook), sheetName, isAcrossWorkbook); sequenceNodes.push({ token: refRanges[0], nodeType: sequenceNodeType.REFERENCE } as any); const newSequenceNodes = [...sequenceNodes, ...lastNodes]; const result = sequenceNodeToText(newSequenceNodes); @@ -336,6 +338,7 @@ export const useSheetSelectionChange = ( sheetSkeletonManagerService, themeService, univerInstanceService, + currentWorkbook: currentUnit!, }); }); diff --git a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-switch-sheet.ts b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-switch-sheet.ts index 23a4d6fb07..c923b3528e 100644 --- a/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-switch-sheet.ts +++ b/packages/sheets-formula-ui/src/views/formula-editor/hooks/use-switch-sheet.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DOCS_NORMAL_EDITOR_UNIT_ID_KEY, ICommandService } from '@univerjs/core'; +import { DOCS_NORMAL_EDITOR_UNIT_ID_KEY, ICommandService, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; import { IEditorService } from '@univerjs/docs-ui'; import { IRenderManagerService } from '@univerjs/engine-render'; import { SetWorksheetActiveOperation } from '@univerjs/sheets'; @@ -22,29 +22,48 @@ import { useDependency } from '@univerjs/ui'; import { useEffect } from 'react'; import { RefSelectionsRenderService } from '../../../services/render-services/ref-selections.render-service'; -export const useSwitchSheet = (isNeed: boolean, unitId: string, isSupportAcrossSheet: boolean, isFocusSet: (v: boolean) => void, onBlur: () => void, refresh: () => void) => { +export const useSwitchSheet = ( + isNeed: boolean, + unitId: string, + isSupportAcrossSheet: boolean, + isFocusSet: (v: boolean) => void, + onBlur: () => void, + refresh: () => void +) => { const commandService = useDependency(ICommandService); const editorService = useDependency(IEditorService); const renderManagerService = useDependency(IRenderManagerService); const render = renderManagerService.getRenderById(unitId); + const univerInstanceService = useDependency(IUniverInstanceService); const refSelectionsRenderService = render?.with(RefSelectionsRenderService); useEffect(() => { if (isNeed && refSelectionsRenderService) { if (isSupportAcrossSheet) { + const handleRefresh = () => { + const length = refSelectionsRenderService.getSelectionControls().length; + for (let index = 1; index <= length; index++) { + refSelectionsRenderService.clearLastSelection(); + } + + return setTimeout(() => { + refresh(); + }, 30); + }; + const d = commandService.onCommandExecuted((info) => { if (info.id === SetWorksheetActiveOperation.id) { - const length = refSelectionsRenderService.getSelectionControls().length; - for (let index = 1; index <= length; index++) { - refSelectionsRenderService.clearLastSelection(); - } - setTimeout(() => { - refresh(); - }, 30); + handleRefresh(); } }); + + const d2 = univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).subscribe((unit) => { + handleRefresh(); + }); + return () => { d.dispose(); + d2.unsubscribe(); }; } else { const d = commandService.beforeCommandExecuted((info) => { diff --git a/packages/sheets-formula-ui/src/views/formula-editor/index.tsx b/packages/sheets-formula-ui/src/views/formula-editor/index.tsx index 279b868d1b..056c5510d0 100644 --- a/packages/sheets-formula-ui/src/views/formula-editor/index.tsx +++ b/packages/sheets-formula-ui/src/views/formula-editor/index.tsx @@ -17,7 +17,7 @@ import type { DocumentDataModel, IDisposable, ITextRange } from '@univerjs/core'; import type { Editor, IKeyboardEventConfig } from '@univerjs/docs-ui'; import type { KeyCode, MetaKeys } from '@univerjs/ui'; -import type { CSSProperties, ReactNode } from 'react'; +import type { CSSProperties, ReactNode, Ref } from 'react'; import type { FormulaSelectingType } from './hooks/use-formula-selection'; import type { IRefSelection } from './hooks/use-highlight'; import { BuildTextUtils, createInternalEditorID, generateRandomId, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; @@ -26,7 +26,7 @@ import { DocBackScrollRenderController, DocSelectionRenderService, IEditorServic import { IRenderManagerService } from '@univerjs/engine-render'; import { EMBEDDING_FORMULA_EDITOR } from '@univerjs/sheets-ui'; import { useDependency, useEvent, useObservable, useUpdateEffect } from '@univerjs/ui'; -import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; +import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { findIndexFromSequenceNodes, findRefSequenceIndex } from '../range-selector/utils/find-index-from-sequence-nodes'; import { HelpFunction } from './help-function/HelpFunction'; import { useFocus } from './hooks/use-focus'; @@ -55,9 +55,6 @@ export interface IFormulaEditorProps { onFocus?: () => void; onBlur?: () => void; isSupportAcrossSheet?: boolean; - actions?: { - handleOutClick?: (e: MouseEvent, cb: () => void) => void; - }; className?: string; editorId?: string; moveCursor?: boolean; @@ -76,7 +73,12 @@ export interface IFormulaEditorProps { } const noop = () => { }; -export function FormulaEditor(props: IFormulaEditorProps) { + +export interface IFormulaEditorRef { + isClickOutSide: (e: MouseEvent) => boolean; +} + +export const FormulaEditor = forwardRef((props: IFormulaEditorProps, ref: Ref) => { const { errorText, initValue, @@ -88,7 +90,6 @@ export function FormulaEditor(props: IFormulaEditorProps) { onBlur = noop, onChange: propOnChange, onVerify, - actions, className, editorId: propEditorId, moveCursor = true, @@ -106,16 +107,14 @@ export function FormulaEditor(props: IFormulaEditorProps) { const editorService = useDependency(IEditorService); const sheetEmbeddingRef = useRef(null); const onChange = useEvent(propOnChange); - // init actions - if (actions) { - actions.handleOutClick = (e: MouseEvent, cb: () => void) => { + useImperativeHandle(ref, () => ({ + isClickOutSide: (e: MouseEvent) => { if (sheetEmbeddingRef.current) { - const isContain = sheetEmbeddingRef.current.contains(e.target as Node); - !isContain && cb(); + return !sheetEmbeddingRef.current.contains(e.target as Node); } - }; - } - + return false; + }, + })); const onFormulaSelectingChange = useEvent(propOnFormulaSelectingChange); const searchFunctionRef = useRef(null); const editorRef = useRef(undefined); @@ -352,4 +351,4 @@ export function FormulaEditor(props: IFormulaEditorProps) {
) ; -} +}); diff --git a/packages/sheets-formula-ui/src/views/range-selector/utils/unit-ranges-to-text.ts b/packages/sheets-formula-ui/src/views/range-selector/utils/unit-ranges-to-text.ts index 413851c9e5..39aecfb705 100644 --- a/packages/sheets-formula-ui/src/views/range-selector/utils/unit-ranges-to-text.ts +++ b/packages/sheets-formula-ui/src/views/range-selector/utils/unit-ranges-to-text.ts @@ -15,7 +15,7 @@ */ import type { IUnitRangeName, IUniverInstanceService, Workbook } from '@univerjs/core'; -import { serializeRange, serializeRangeWithSheet } from '@univerjs/engine-formula'; +import { serializeRange, serializeRangeToRefString, serializeRangeWithSheet } from '@univerjs/engine-formula'; export function getSheetIdByName(univerInstanceService: IUniverInstanceService, unitId: string, name: string) { return univerInstanceService.getUnit(unitId)?.getSheetBySheetName(name)?.getSheetId() || ''; @@ -24,11 +24,14 @@ export function getSheetNameById(univerInstanceService: IUniverInstanceService, return univerInstanceService.getUnit(unitId)?.getSheetBySheetId(sheetId)?.getName() || ''; } -export const unitRangesToText = (ranges: IUnitRangeName[], isNeedSheetName: boolean = false, originSheetName = '') => { - if (!isNeedSheetName) { +export const unitRangesToText = (ranges: IUnitRangeName[], isNeedSheetName: boolean = false, originSheetName = '', isNeedWorkbookName = false) => { + if (!isNeedSheetName && !isNeedWorkbookName) { return ranges.map((item) => serializeRange(item.range)); } else { return ranges.map((item) => { + if (isNeedWorkbookName) { + return serializeRangeToRefString(item); + } if (item.sheetName !== '' && item.sheetName !== originSheetName) { return serializeRangeWithSheet(item.sheetName, item.range); } 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 fb4590ade4..8f04bdb83d 100644 --- a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts +++ b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts @@ -18,7 +18,6 @@ import type { DocumentDataModel, ICellData, ICommandInfo, IDisposable, IDocumentBody, IDocumentData, IDocumentStyle, IMutationInfo, IStyleData, Nullable, Styles, Workbook } from '@univerjs/core'; import type { IRichTextEditingMutationParams } from '@univerjs/docs'; -import type { IRenderContext, IRenderModule } from '@univerjs/engine-render'; import type { ISetRangeValuesCommandParams, MutationsAffectRange, WorkbookSelectionModel } from '@univerjs/sheets'; import type { IEditorBridgeServiceVisibleParam } from '../../services/editor-bridge.service'; @@ -63,7 +62,7 @@ import { IRenderManagerService, } from '@univerjs/engine-render'; -import { adjustRangeOnMutation, COMMAND_LISTENER_SKELETON_CHANGE, InsertColMutation, InsertRowMutation, MoveColsMutation, MoveRowsMutation, REF_SELECTIONS_ENABLED, RemoveColMutation, RemoveRowMutation, SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand, SetWorksheetActiveOperation, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets'; +import { adjustRangeOnMutation, COMMAND_LISTENER_SKELETON_CHANGE, InsertColMutation, InsertRowMutation, MoveColsMutation, MoveRowsMutation, REF_SELECTIONS_ENABLED, RemoveColMutation, RemoveRowMutation, SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand, SetWorksheetActiveOperation, SheetInterceptorService } from '@univerjs/sheets'; import { KeyCode, MetaKeys } from '@univerjs/ui'; import { distinctUntilChanged, filter } from 'rxjs'; import { getEditorObject } from '../../basics/editor/get-editor-object'; @@ -86,23 +85,20 @@ enum CursorChange { CursorChange, } -export class EditingRenderController extends Disposable implements IRenderModule { +export class EditingRenderController extends Disposable { /** * It is used to distinguish whether the user has actively moved the cursor in the editor, mainly through mouse clicks. */ private _cursorChange: CursorChange = CursorChange.InitialState; /** If the corresponding unit is active and prepared for editing. */ - private _isUnitEditing = false; + private _editingUnit = ''; private _workbookSelections: WorkbookSelectionModel; - private _d: Nullable; _cursorTimeout: NodeJS.Timeout; constructor( - private readonly _context: IRenderContext, - @Inject(SheetsSelectionsService) selectionManagerService: SheetsSelectionsService, @IUndoRedoService private readonly _undoRedoService: IUndoRedoService, @IContextService private readonly _contextService: IContextService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, @@ -114,48 +110,21 @@ export class EditingRenderController extends Disposable implements IRenderModule @ICommandService private readonly _commandService: ICommandService, @Inject(LocaleService) protected readonly _localService: LocaleService, @IEditorService private readonly _editorService: IEditorService, - @Inject(SheetCellEditorResizeService) private readonly _sheetCellEditorResizeService: SheetCellEditorResizeService, // RenderModule @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService + @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, + @Inject(SheetCellEditorResizeService) private readonly _sheetCellEditorResizeService: SheetCellEditorResizeService ) { super(); - this._workbookSelections = selectionManagerService.getWorkbookSelections(this._context.unitId); - // EditingRenderController is per unit. It should only handle keyboard events when the unit is // the current of its type. - this.disposeWithMe(this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).subscribe((workbook) => { - if (workbook?.getUnitId() === this._context.unitId) { - this._d = this._init(); - } else { - this._disposeCurrent(); - - // Force ending editor when he switch to another workbook. - if (this._isUnitEditing) { - this._handleEditorInvisible({ - visible: false, - eventType: DeviceInputEventType.Keyboard, - keycode: KeyCode.ESC, - unitId: this._context.unitId, - }); - - this._isUnitEditing = false; - } - } - })); + this.disposeWithMe(this._init()); this._initEditorVisibilityListener(); } override dispose(): void { super.dispose(); - - this._disposeCurrent(); - } - - private _disposeCurrent(): void { - this._d?.dispose(); - this._d = null; } private _init(): IDisposable { @@ -180,16 +149,28 @@ export class EditingRenderController extends Disposable implements IRenderModule } private _initEditorVisibilityListener(): void { + this.disposeWithMe(this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).subscribe(async (unit) => { + if (this._editingUnit && unit?.getUnitId() !== this._editingUnit && !this._editorBridgeService.isForceKeepVisible()) { + await this._handleEditorInvisible({ + visible: false, + eventType: DeviceInputEventType.Keyboard, + keycode: KeyCode.ESC, + unitId: this._editingUnit, + }); + this._editingUnit = ''; + } + })); + this.disposeWithMe( this._editorBridgeService.visible$ .pipe(distinctUntilChanged((prev, curr) => prev.visible === curr.visible)) - .subscribe((params) => { - if ((params.unitId === DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY || params.unitId === this._context.unitId) && params.visible) { - this._isUnitEditing = true; + .subscribe(async (params) => { + if (params.visible) { + this._editingUnit = params.unitId; this._handleEditorVisible(params); - } else if (this._isUnitEditing) { - this._handleEditorInvisible(params); - this._isUnitEditing = false; + } else if (this._editingUnit) { + await this._handleEditorInvisible(params); + this._editingUnit = ''; } }) ); @@ -202,7 +183,7 @@ export class EditingRenderController extends Disposable implements IRenderModule d.add(renderConfig.document.onPointerDown$.subscribeEvent(() => { // fix https://github.com/dream-num/univer/issues/628, need to recalculate the cell editor size after // it acquire focus. - if (this._isUnitEditing && this._editorBridgeService.isVisible()) { + if (this._editingUnit && this._editorBridgeService.isVisible()) { const param = this._editorBridgeService.getEditCellState(); const editorId = this._editorBridgeService.getCurrentEditorId(); @@ -210,7 +191,7 @@ export class EditingRenderController extends Disposable implements IRenderModule return; } - this._sheetCellEditorResizeService.fitTextSize(); + this._sheetCellEditorResizeService?.fitTextSize(); } })); } @@ -260,7 +241,7 @@ export class EditingRenderController extends Disposable implements IRenderModule } } - this._sheetCellEditorResizeService.resizeCellEditor(() => { + this._sheetCellEditorResizeService?.resizeCellEditor(() => { this._textSelectionManagerService.refreshSelection({ unitId: DOCS_NORMAL_EDITOR_UNIT_ID_KEY, subUnitId: DOCS_NORMAL_EDITOR_UNIT_ID_KEY, @@ -341,7 +322,7 @@ export class EditingRenderController extends Disposable implements IRenderModule const { unitId: commandUnitId } = params; // Only when the sheet it attached to is focused. Maybe we should change it to the render unit sys. - if (!this._isCurrentSheetFocused() || isRangeSelector(commandUnitId)) { + if (isRangeSelector(commandUnitId)) { return; } @@ -352,7 +333,7 @@ export class EditingRenderController extends Disposable implements IRenderModule } if (commandUnitId === DOCS_NORMAL_EDITOR_UNIT_ID_KEY) { - this._sheetCellEditorResizeService.fitTextSize(); + this._sheetCellEditorResizeService?.fitTextSize(); } } })); @@ -387,7 +368,7 @@ export class EditingRenderController extends Disposable implements IRenderModule } // You can double-click on the cell or input content by keyboard to put the cell into the edit state. - + // eslint-disable-next-line complexity private _handleEditorVisible(param: IEditorBridgeServiceVisibleParam) { const { eventType, keycode } = param; // Change `CursorChange` to changed status, when formula bar clicked. @@ -428,7 +409,7 @@ export class EditingRenderController extends Disposable implements IRenderModule return; } - this._sheetCellEditorResizeService.fitTextSize(() => { + this._sheetCellEditorResizeService?.fitTextSize(() => { const viewMain = scene.getViewport(DOC_VIEWPORT_KEY.VIEW_MAIN); viewMain?.scrollToViewportPos({ viewportScrollX: Number.POSITIVE_INFINITY, @@ -508,9 +489,8 @@ export class EditingRenderController extends Disposable implements IRenderModule const snapshot = Tools.deepClone(documentDataModel?.getSnapshot()); let { keycode } = param; this._cursorChange = CursorChange.InitialState; - + const currentUnitId = editCellState?.unitId ?? ''; this._exitInput(param); - if (editCellState == null) { return; } @@ -522,9 +502,12 @@ export class EditingRenderController extends Disposable implements IRenderModule keycode = KeyCode.ESC; } - const workbook = this._context.unit; + const workbook = this._univerInstanceService.getUnit(currentUnitId, UniverInstanceType.UNIVER_SHEET); + if (!workbook) { + return; + } const worksheet = workbook.getActiveSheet(); - const workbookId = this._context.unitId; + const workbookId = workbook.getUnitId(); const worksheetId = worksheet.getSheetId(); const { unitId, sheetId } = editCellState; @@ -548,7 +531,7 @@ export class EditingRenderController extends Disposable implements IRenderModule if (selections) { this._contextService.setContextValue(REF_SELECTIONS_ENABLED, false); this._commandService.syncExecuteCommand(SetSelectionsOperation.id, { - unitId: this._context.unit.getUnitId(), + unitId: workbookId, subUnitId: sheetId, selections, }); @@ -568,7 +551,7 @@ export class EditingRenderController extends Disposable implements IRenderModule } // moveSelection need to put behind of SetRangeValuesCommand, fix https://github.com/dream-num/univer/issues/1155 - this._moveSelection(keycode); + this._moveSelection(keycode, currentUnitId); } private _getEditorObject() { @@ -589,10 +572,12 @@ export class EditingRenderController extends Disposable implements IRenderModule if (editCellState == null) { return true; } - const { unitId, sheetId, row, column } = editCellState; - const workbook = this._context.unit; + const workbook = this._univerInstanceService.getUnit(unitId, UniverInstanceType.UNIVER_SHEET); + if (!workbook) { + return true; + } let worksheet = workbook.getActiveSheet(); // If the target cell does not exist, there is no need to execute setRangeValue @@ -673,7 +658,7 @@ export class EditingRenderController extends Disposable implements IRenderModule this._undoRedoService.clearUndoRedo(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY); } - private _moveSelection(keycode?: KeyCode) { + private _moveSelection(keycode: KeyCode | undefined, currentUnitId: string) { if (keycode == null || !MOVE_SELECTION_KEYCODE_LIST.includes(keycode)) { return; } @@ -700,6 +685,10 @@ export class EditingRenderController extends Disposable implements IRenderModule direction = Direction.RIGHT; break; } + const currentUnit = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_SHEET); + if (currentUnitId && currentUnit?.getUnitId() !== currentUnitId) { + this._univerInstanceService.setCurrentUnitForType(currentUnitId); + } if (keycode === KeyCode.ENTER || keycode === KeyCode.TAB) { this._commandService.executeCommand(MoveSelectionEnterAndTabCommand.id, { @@ -755,12 +744,6 @@ export class EditingRenderController extends Disposable implements IRenderModule return this._univerInstanceService.getUnit(DOCS_NORMAL_EDITOR_UNIT_ID_KEY, UniverInstanceType.UNIVER_DOC); } - // WTF: this is should not exist at all. It is because all editor instances reuse the singleton - // "DocSelectionManagerService" and other modules. Which will be refactored soon in August, 2024. - private _isCurrentSheetFocused(): boolean { - return this._univerInstanceService.getFocusedUnit()?.getUnitId() === this._context.unitId; - } - private _getEditorSkeleton(editorId: string) { return this._renderManagerService.getRenderById(editorId)?.with(DocSkeletonManagerService).getSkeleton(); } @@ -769,6 +752,10 @@ export class EditingRenderController extends Disposable implements IRenderModule return this._renderManagerService.getRenderById(editorId)?.with(DocSkeletonManagerService).getViewModel(); } + private _getEditingUnit() { + return this._editingUnit ? this._univerInstanceService.getUnit(this._editingUnit, UniverInstanceType.UNIVER_SHEET) : null; + } + private _emptyDocumentDataModel(documentStyle: IDocumentStyle, removeStyle: boolean) { const empty = (documentDataModel: DocumentDataModel, resetDocumentStyle?: boolean) => { const snapshot = Tools.deepClone(documentDataModel.getSnapshot()); diff --git a/packages/sheets-ui/src/controllers/render-controllers/editor-bridge.render-controller.ts b/packages/sheets-ui/src/controllers/render-controllers/editor-bridge.render-controller.ts index 0b8e7f8dcd..e6e6e7fc6f 100644 --- a/packages/sheets-ui/src/controllers/render-controllers/editor-bridge.render-controller.ts +++ b/packages/sheets-ui/src/controllers/render-controllers/editor-bridge.render-controller.ts @@ -20,7 +20,7 @@ import type { IRender, IRenderContext, IRenderModule } from '@univerjs/engine-re import type { ISelectionWithStyle, ISetRangeValuesMutationParams } from '@univerjs/sheets'; import type { ICurrentEditCellParam, IEditorBridgeServiceVisibleParam } from '../../services/editor-bridge.service'; import { DisposableCollection, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, FOCUSING_FX_BAR_EDITOR, FOCUSING_SHEET, ICommandService, IContextService, Inject, IUniverInstanceService, RxDisposable, toDisposable, UniverInstanceType } from '@univerjs/core'; -import { DocSelectionRenderService, IEditorService, IRangeSelectorService } from '@univerjs/docs-ui'; +import { DocSelectionRenderService } from '@univerjs/docs-ui'; import { DeviceInputEventType, IRenderManagerService } from '@univerjs/engine-render'; import { ClearSelectionFormatCommand, @@ -46,14 +46,9 @@ export class EditorBridgeRenderController extends RxDisposable implements IRende @IUniverInstanceService private readonly _instanceSrv: IUniverInstanceService, @ICommandService private readonly _commandService: ICommandService, @IEditorBridgeService private readonly _editorBridgeService: IEditorBridgeService, - // FIXME: should use WorkbookSelectionModel - // FIXME: should check if it is the current sheet, if it becomes the current sheet, - // it should update cell params, otherwise it should do nothing. @Inject(SheetsSelectionsService) private readonly _selectionManagerService: SheetsSelectionsService, - @IRangeSelectorService private readonly _rangeSelectorService: IRangeSelectorService, @IContextService private readonly _contextService: IContextService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @IEditorService private readonly _editorService: IEditorService, @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService ) { super(); @@ -65,8 +60,6 @@ export class EditorBridgeRenderController extends RxDisposable implements IRende this._disposeCurrent(); } })); - - this._initialRangeSelector(); } private _init(): IDisposable { @@ -93,7 +86,6 @@ export class EditorBridgeRenderController extends RxDisposable implements IRende private _updateEditorPosition(params: Nullable) { if (this._editorBridgeService.isVisible().visible) return; - if (this._rangeSelectorService.selectorModalVisible) return; const primary = params?.[params.length - 1]?.primary; if (primary) { @@ -260,56 +252,6 @@ export class EditorBridgeRenderController extends RxDisposable implements IRende }); } - private _initialRangeSelector() { - this.disposeWithMe(this._selectionManagerService.selectionMoving$.subscribe(this._rangeSelector.bind(this))); - this.disposeWithMe(this._selectionManagerService.selectionMoveStart$.subscribe(this._rangeSelector.bind(this))); - - // TODO: this method shouldn't be here. Fix in when refactor the range selector. - - /** - * pro/issues/388 - * When the range selector is opened, - * the current selection needs to be synchronized to the range selector. - */ - this.disposeWithMe( - this._rangeSelectorService.openSelector$.subscribe(() => { - const { unitId, sheetId, sheetName } = this._getCurrentUnitIdAndSheetId(); - if (!sheetId || !sheetName) return; - - const selectionWithStyle = this._selectionManagerService.getCurrentSelections(); - const ranges = selectionWithStyle?.map((value) => ({ range: value.range, unitId, sheetId, sheetName })); - if (ranges) { - this._rangeSelectorService.selectionChange(ranges); - } - }) - ); - } - - private _rangeSelector(selectionWithStyle: Nullable) { - if (!selectionWithStyle) { - return; - } - - const { unitId, sheetId, sheetName } = this._getCurrentUnitIdAndSheetId(); - if (!sheetId || !sheetName) return; - - const ranges = selectionWithStyle.map((value: ISelectionWithStyle) => { - return { range: value.range, unitId, sheetId, sheetName }; - }); - - this._rangeSelectorService.selectionChange(ranges); - } - - private _getCurrentUnitIdAndSheetId() { - const workbook = this._context.unit; - const worksheet = workbook.getActiveSheet(); - return { - unitId: workbook.getUnitId(), - sheetId: worksheet?.getSheetId(), - sheetName: worksheet?.getName(), - }; - } - private _getSheetObject() { return getSheetObject(this._context.unit, this._context)!; } diff --git a/packages/sheets-ui/src/plugin.ts b/packages/sheets-ui/src/plugin.ts index ae3c7eea6a..5af96a60f0 100644 --- a/packages/sheets-ui/src/plugin.ts +++ b/packages/sheets-ui/src/plugin.ts @@ -139,6 +139,7 @@ export class UniverSheetsUIPlugin extends Plugin { [SheetCanvasPopManagerService], [CellAlertManagerService], [SelectAllService], + [SheetCellEditorResizeService], // controllers [ActiveWorksheetController], @@ -153,6 +154,7 @@ export class UniverSheetsUIPlugin extends Plugin { [SheetsDefinedNameController], [EditorDataSyncController], [SheetCheckboxController], + [EditingRenderController], // permission [SheetPermissionPanelModel], @@ -198,6 +200,7 @@ export class UniverSheetsUIPlugin extends Plugin { [AutoWidthController], [EditorDataSyncController], [SheetCheckboxController], + [EditingRenderController], ]); } @@ -232,7 +235,6 @@ export class UniverSheetsUIPlugin extends Plugin { [SheetsScrollRenderController], [HeaderFreezeRenderController], [SheetsZoomRenderController], - [SheetCellEditorResizeService], [FormatPainterRenderController], [ClipboardRenderController], @@ -248,7 +250,6 @@ export class UniverSheetsUIPlugin extends Plugin { // editor [EditorBridgeRenderController], - [EditingRenderController], // permission [SheetPermissionInterceptorCanvasRenderController], diff --git a/packages/sheets-ui/src/services/editor/cell-editor-resize.service.ts b/packages/sheets-ui/src/services/editor/cell-editor-resize.service.ts index 45a646e3ce..015e4642c0 100644 --- a/packages/sheets-ui/src/services/editor/cell-editor-resize.service.ts +++ b/packages/sheets-ui/src/services/editor/cell-editor-resize.service.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import type { DocumentDataModel, IPosition, Nullable, Workbook } from '@univerjs/core'; -import type { DocumentSkeleton, IDocumentLayoutObject, IRenderContext, IRenderModule, Scene } from '@univerjs/engine-render'; -import { Disposable, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, HorizontalAlign, Inject, IUniverInstanceService, UniverInstanceType, VerticalAlign, WrapStrategy } from '@univerjs/core'; +import type { DocumentDataModel, IPosition, Nullable } from '@univerjs/core'; +import type { DocumentSkeleton, IDocumentLayoutObject, Scene } from '@univerjs/engine-render'; +import { Disposable, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, HorizontalAlign, IUniverInstanceService, UniverInstanceType, VerticalAlign, WrapStrategy } from '@univerjs/core'; import { DocSkeletonManagerService } from '@univerjs/docs'; import { DOCS_COMPONENT_MAIN_LAYER_INDEX, VIEWPORT_KEY } from '@univerjs/docs-ui'; -import { convertTextRotation, fixLineWidthByScale, IRenderManagerService, Rect, ScrollBar } from '@univerjs/engine-render'; +import { convertTextRotation, fixLineWidthByScale, getCurrentTypeOfRenderer, IRenderManagerService, Rect, ScrollBar } from '@univerjs/engine-render'; import { ILayoutService } from '@univerjs/ui'; import { getEditorObject } from '../../basics/editor/get-editor-object'; import { SHEET_FOOTER_BAR_HEIGHT } from '../../views/sheet-container/SheetContainer'; @@ -36,19 +36,42 @@ interface ICanvasOffset { top: number; } -export class SheetCellEditorResizeService extends Disposable implements IRenderModule { +export class SheetCellEditorResizeService extends Disposable { constructor( - private readonly _context: IRenderContext, @ILayoutService private readonly _layoutService: ILayoutService, @ICellEditorManagerService private readonly _cellEditorManagerService: ICellEditorManagerService, @IEditorBridgeService private readonly _editorBridgeService: IEditorBridgeService, @IRenderManagerService private readonly _renderManagerService: IRenderManagerService, - @Inject(SheetSkeletonManagerService) private readonly _sheetSkeletonManagerService: SheetSkeletonManagerService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService ) { super(); } + private get _currentRenderer() { + return getCurrentTypeOfRenderer(UniverInstanceType.UNIVER_SHEET, this._univerInstanceService, this._renderManagerService); + } + + private get _editingUnitId() { + return this._editorBridgeService.getEditCellState()?.unitId ?? ''; + } + + private get _editingRenderer() { + return this._renderManagerService.getRenderById(this._editingUnitId); + } + + private get _renderer() { + const currentUnitId = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_SHEET)?.getUnitId(); + return this._editingUnitId === currentUnitId ? this._editingRenderer : this._currentRenderer; + } + + private get _sheetSkeletonManagerService() { + return this._renderer?.with(SheetSkeletonManagerService); + } + + private get engine() { + return this._renderer?.engine; + } + // eslint-disable-next-line complexity fitTextSize(callback?: () => void) { const param = this._editorBridgeService.getEditCellState(); @@ -73,7 +96,7 @@ export class SheetCellEditorResizeService extends Disposable implements IRenderM scaleX, scaleY ); - if (!info) return; + if (!info || info.actualWidth <= 0) return; let { actualWidth, actualHeight } = info; const { verticalAlign, horizontalAlign, paddingData, fill } = documentLayoutObject; actualWidth = actualWidth + (paddingData.l ?? 0) + (paddingData.r ?? 0); @@ -170,7 +193,6 @@ export class SheetCellEditorResizeService extends Disposable implements IRenderM documentSkeleton.calculate(); const size = documentSkeleton.getActualSize(); - let editorWidth = endX - startX; if (editorWidth < size.actualWidth * scaleX + EDITOR_INPUT_SELF_EXTEND_GAP * scaleX) { @@ -203,7 +225,8 @@ export class SheetCellEditorResizeService extends Disposable implements IRenderM return Number.parseInt(width.replace('px', '')); } - const engine = this._context.engine; + const engine = this.engine; + if (!engine) return; const canvasElement = engine.getCanvasElement(); const canvasClientRect = canvasElement.getBoundingClientRect(); @@ -212,7 +235,7 @@ export class SheetCellEditorResizeService extends Disposable implements IRenderM const { width } = canvasClientRect; // real width affected by scale const scaleAdjust = width / widthOfCanvas; const { startX, startY, endX } = position; - const enginWidth = this._context.engine.width; + const enginWidth = engine.width; const clientHeight = document.body.clientHeight - @@ -260,7 +283,8 @@ export class SheetCellEditorResizeService extends Disposable implements IRenderM return; } - const engine = this._context.engine; + const engine = this.engine; + if (!engine) return; const canvasElement = engine.getCanvasElement(); // We should take the scale into account when canvas is scaled by CSS. @@ -394,7 +418,7 @@ export class SheetCellEditorResizeService extends Disposable implements IRenderM const editCellState = this._editorBridgeService.getEditCellState(); if (!editCellState) return; - const skeleton = this._sheetSkeletonManagerService.getSkeletonParam(editCellState.sheetId)?.skeleton; + const skeleton = this._sheetSkeletonManagerService?.getSkeletonParam(editCellState.sheetId)?.skeleton; if (!skeleton) return; const { row, column, scaleX, scaleY, position, canvasOffset, documentLayoutObject } = editCellState; const { horizontalAlign } = documentLayoutObject; diff --git a/packages/sheets-ui/src/views/defined-name/DefinedNameInput.tsx b/packages/sheets-ui/src/views/defined-name/DefinedNameInput.tsx index ba005b5236..601794d672 100644 --- a/packages/sheets-ui/src/views/defined-name/DefinedNameInput.tsx +++ b/packages/sheets-ui/src/views/defined-name/DefinedNameInput.tsx @@ -201,12 +201,12 @@ export const DefinedNameInput = (props: IDefinedNameInputProps) => { setTypeValue(type); }; - const formulaEditorActionsRef = useRef({}); + const formulaEditorRef = useRef(null); const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false); useSidebarClick((e: MouseEvent) => { - const handleOutClick = formulaEditorActionsRef.current?.handleOutClick; - handleOutClick && handleOutClick(e, () => isFocusFormulaEditorSet(false)); + const isOutSide = formulaEditorRef.current?.isClickOutSide(e); + isOutSide && isFocusFormulaEditorSet(false); }); return ( @@ -249,7 +249,7 @@ export const DefinedNameInput = (props: IDefinedNameInputProps) => { }} onFocus={() => isFocusFormulaEditorSet(true)} - actions={formulaEditorActionsRef.current} + ref={formulaEditorRef} /> ))}
diff --git a/packages/sheets-ui/src/views/editor-container/EditorContainer.tsx b/packages/sheets-ui/src/views/editor-container/EditorContainer.tsx index 894b2b1e60..268c545e05 100644 --- a/packages/sheets-ui/src/views/editor-container/EditorContainer.tsx +++ b/packages/sheets-ui/src/views/editor-container/EditorContainer.tsx @@ -104,14 +104,12 @@ export const EditorContainer: React.FC = () => { return () => { sub.unsubscribe(); }; - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Empty dependency array means this effect runs once on mount and clean up on unmount useEffect(() => { if (!disableAutoFocus) { cellEditorManagerService.setFocus(true); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [disableAutoFocus, state]); const handleClickSideBar = useEvent(() => { diff --git a/packages/sheets-ui/src/views/formula-bar/FormulaBar.tsx b/packages/sheets-ui/src/views/formula-bar/FormulaBar.tsx index 5002523a1c..48a63510b5 100644 --- a/packages/sheets-ui/src/views/formula-bar/FormulaBar.tsx +++ b/packages/sheets-ui/src/views/formula-bar/FormulaBar.tsx @@ -27,7 +27,6 @@ import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 're import { EMPTY, merge, of, switchMap } from 'rxjs'; import { SetCellEditVisibleOperation } from '../../commands/operations/cell-edit.operation'; import { EMBEDDING_FORMULA_EDITOR_COMPONENT_KEY } from '../../common/keys'; -import { useActiveWorkbook } from '../../components/hook'; import { SheetsUIPart } from '../../consts/ui-name'; import { IEditorBridgeService } from '../../services/editor-bridge.service'; import { IFormulaEditorManagerService } from '../../services/editor/formula-editor-manager.service'; @@ -47,10 +46,8 @@ interface IProps { export function FormulaBar(props: IProps) { const { className, disableDefinedName } = props; - const [iconStyle, setIconStyle] = useState(styles.formulaGrey); const [arrowDirection, setArrowDirection] = useState(ArrowDirection.Down); - const formulaEditorManagerService = useDependency(IFormulaEditorManagerService); const editorBridgeService = useDependency(IEditorBridgeService); const worksheetProtectionRuleModel = useDependency(WorksheetProtectionRuleModel); @@ -65,7 +62,6 @@ export function FormulaBar(props: IProps) { viewDisable: false, }); const [imageDisable, setImageDisable] = useState(false); - const currentWorkbook = useActiveWorkbook(); const componentManager = useDependency(ComponentManager); const workbook = useObservable(() => univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET), undefined, undefined, [])!; const isRefSelecting = useRef<0 | 1 | 2>(0); @@ -194,7 +190,7 @@ export function FormulaBar(props: IProps) { visible: false, eventType: DeviceInputEventType.Keyboard, keycode: KeyCode.ESC, - unitId: currentWorkbook?.getUnitId() ?? '', + unitId: editState!.unitId, }); } } @@ -206,7 +202,7 @@ export function FormulaBar(props: IProps) { commandService.executeCommand(SetCellEditVisibleOperation.id, { visible: false, eventType: DeviceInputEventType.PointerDown, - unitId: currentWorkbook?.getUnitId() ?? '', + unitId: editState!.unitId, }); } } @@ -230,7 +226,7 @@ export function FormulaBar(props: IProps) { { visible: true, eventType: DeviceInputEventType.PointerDown, - unitId: currentWorkbook?.getUnitId() ?? '', + unitId: editState!.unitId, } as IEditorBridgeServiceVisibleParam ); // undoRedoService.clearUndoRedo(DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY);