fix(sheets-ui): qualify cross-sheet editor labels (#7423)

This commit is contained in:
wpxp123456
2026-08-05 21:06:02 +08:00
committed by GitHub
parent 86bf20f5eb
commit ffbbb54938
2 changed files with 66 additions and 10 deletions
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import type { Nullable } from '@univerjs/core';
import type { Nullable, Workbook } from '@univerjs/core';
import type { KeyCode } from '@univerjs/ui';
import type { ICellEditorState } from '../../services/editor-bridge.service';
import {
@@ -31,6 +31,7 @@ import {
UniverInstanceType,
} from '@univerjs/core';
import { DocSelectionRenderService, IEditorService } from '@univerjs/docs-ui';
import { quoteSheetName } from '@univerjs/engine-formula';
import { DeviceInputEventType, IRenderManagerService } from '@univerjs/engine-render';
import {
ComponentManager,
@@ -62,6 +63,7 @@ import {
SHEET_EMBED_INTERACTION_BOUNDARY_OWNER_ATTRIBUTE,
SHEET_EMBED_RUNTIME_FOCUS_ROLE_ATTRIBUTE,
} from '../../services/sheet-embed-integration.service';
import { useActiveWorksheet } from '../hook';
import { focusSheetCellEditorElement, registerSheetCellEditorRuntimePortal } from './focus-editor';
import { useKeyEventConfig } from './hooks';
@@ -229,9 +231,18 @@ export function EditorContainer() {
);
const FormulaEditor = componentManager.get(EMBEDDING_FORMULA_EDITOR_COMPONENT_KEY);
const editState = useObservable(editorBridgeService.currentEditCellState$);
const workbook = editState
? instanceService.getUnit<Workbook>(editState.unitId, UniverInstanceType.UNIVER_SHEET) ?? null
: null;
const activeSheet = useActiveWorksheet(workbook);
const darkMode = useObservable(themeService.darkMode$, themeService.darkMode);
const [showEditCellAddress, setShowEditCellAddress] = useState(false);
const editCellAddress = editState ? `${numberToABC(editState.column)}${editState.row + 1}` : null;
const editSheetName = editState ? workbook?.getSheetBySheetId(editState.sheetId)?.getName() : null;
const editCellAddress = editState
? `${activeSheet && editSheetName && activeSheet.getSheetId() !== editState.sheetId
? `'${quoteSheetName(editSheetName)}'!`
: ''}${numberToABC(editState.column)}${editState.row + 1}`
: null;
// The editor border uses the normal selection stroke, so the address label stays visually in sync with it.
const editorBorderColor = genNormalSelectionStyle(themeService).stroke;
const focusCoordinator = injector.has(ISheetEmbedRuntimeFocusCoordinator)
@@ -99,7 +99,7 @@ class TestEditorBridgeService {
readonly visible$ = this._visible$.asObservable();
readonly currentEditCellState$ = new BehaviorSubject<Nullable<ICellEditorState>>({
unitId: 'sheet-1',
sheetId: 'sheet-1',
sheetId: 'worksheet-1',
row: 0,
column: 0,
editorUnitId: DOCS_NORMAL_EDITOR_UNIT_ID_KEY,
@@ -142,6 +142,19 @@ function createTestBed(options: { docSelectionIsFocusing?: boolean; focusedUnitI
const focusCoordinator = new EmbedRuntimeFocusCoordinator();
const interactionBoundaryService = new EmbedInteractionBoundaryService();
const editorBridgeService = new TestEditorBridgeService();
const editSheet = { getSheetId: () => 'worksheet-1', getName: () => 'Sheet1' };
const otherSheet = { getSheetId: () => 'worksheet-2', getName: () => 'Sheet2' };
const activeSheet$ = new BehaviorSubject(editSheet);
const workbook = {
activeSheet$,
getUnitId: () => 'sheet-1',
getActiveSheet: () => activeSheet$.getValue(),
getSheetBySheetId: (sheetId: string) => {
if (sheetId === editSheet.getSheetId()) return editSheet;
if (sheetId === otherSheet.getSheetId()) return otherSheet;
return null;
},
};
const cellEditorResizeService = {
resizeCellEditor: vi.fn(),
fitTextSize: vi.fn(),
@@ -178,12 +191,16 @@ function createTestBed(options: { docSelectionIsFocusing?: boolean; focusedUnitI
getFocusedUnit: () => options.focusedUnitId == null
? null
: { getUnitId: () => options.focusedUnitId },
getUnit: (unitId: string, type?: UniverInstanceType) => (
(type == null || type === UniverInstanceType.UNIVER_SHEET) &&
(options.sheetUnitIds ?? ['child-sheet', 'scoped-child-sheet', 'sheet-1']).includes(unitId)
? { getUnitId: () => unitId }
: null
),
getUnit: (unitId: string, type?: UniverInstanceType) => {
if (
(type != null && type !== UniverInstanceType.UNIVER_SHEET) ||
!(options.sheetUnitIds ?? ['child-sheet', 'scoped-child-sheet', 'sheet-1']).includes(unitId)
) {
return null;
}
return unitId === workbook.getUnitId() ? workbook : { getUnitId: () => unitId };
},
} as never,
}]);
injector.add([IContextService, {
@@ -215,7 +232,7 @@ function createTestBed(options: { docSelectionIsFocusing?: boolean; focusedUnitI
injector.add([ISheetEmbedRuntimeFocusCoordinator, { useValue: focusCoordinator }]);
injector.add([ISheetEmbedInteractionBoundaryService, { useValue: interactionBoundaryService }]);
return { injector, editorBridgeService, focusCoordinator, interactionBoundaryService, docSelectionRenderService, cellEditorResizeService, validViewportScrollInfo$ };
return { injector, editorBridgeService, focusCoordinator, interactionBoundaryService, docSelectionRenderService, cellEditorResizeService, validViewportScrollInfo$, activeSheet$, otherSheet };
}
function renderEditorContainer(root: Root, injector: Injector): void {
@@ -618,6 +635,34 @@ describe('EditorContainer embed focus lease', () => {
expect(container.querySelector('[data-u-comp="sheet-cell-editor-address"]')).toBeNull();
});
it('qualifies the edited cell address after switching worksheets', async () => {
const { injector, validViewportScrollInfo$, activeSheet$, otherSheet } = createTestBed();
container = document.createElement('div');
document.body.appendChild(container);
root = createRoot(container);
await act(async () => {
renderEditorContainer(root!, injector);
await Promise.resolve();
});
await act(async () => {
validViewportScrollInfo$.next({});
await Promise.resolve();
});
const getAddress = () => container?.querySelector('[data-u-comp="sheet-cell-editor-address"]')?.textContent;
expect(getAddress()).toBe('A1');
await act(async () => {
activeSheet$.next(otherSheet);
await Promise.resolve();
});
expect(getAddress()).toBe("'Sheet1'!A1");
});
it('keeps the cell editor visible while formula range selection moves focus to the sheet canvas', async () => {
const { injector, editorBridgeService } = createTestBed();
container = document.createElement('div');