Skip to content

Commit

Permalink
feat(sheet): range selector (#1463)
Browse files Browse the repository at this point in the history
* feat(sheet): range selector

* fix(sheet): text blur

* feat(sheet): selector

* feat(sheet): range selector finished

* fix(sheet): type error

* fix(editor): delete invalid  file

* fix(editor): review update

* fix(editor): add comment

* docs(editor): add comment

* fix(doc): release selection event
  • Loading branch information
DR-Univer authored Mar 6, 2024
1 parent cfd5396 commit b639394
Show file tree
Hide file tree
Showing 30 changed files with 863 additions and 339 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const SidebarOperation: ICommand = {
onClose: () => {
editorService.setOperationSheetUnitId(null);
editorService.setOperationSheetSubUnitId(null);
editorService.changeEditorFocus();
editorService.closeRangePrompt();
},
});
break;
Expand All @@ -52,7 +52,7 @@ export const SidebarOperation: ICommand = {
default:
editorService.setOperationSheetUnitId(null);
editorService.setOperationSheetSubUnitId(null);
editorService.changeEditorFocus();
editorService.closeRangePrompt();
sidebarService.close();
break;
}
Expand Down
24 changes: 19 additions & 5 deletions examples/src/plugins/debugger/views/test-editor/TestTextEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

import React from 'react';

import { TextEditor } from '@univerjs/ui';
import { RangeSelector, TextEditor } from '@univerjs/ui';
import { IUniverInstanceService } from '@univerjs/core';
import { useDependency } from '@wendellhu/redi/react-bindings';

const containerStyle: React.CSSProperties = {
position: 'absolute',
Expand All @@ -35,17 +37,29 @@ const editorStyle: React.CSSProperties = {
* @returns
*/
export const TestEditorContainer = () => {
const univerInstanceService = useDependency(IUniverInstanceService);
const workbook = univerInstanceService.getCurrentUniverSheetInstance();
if (workbook == null) {
return;
}

const unitId = workbook.getUnitId();

const sheetId = workbook.getActiveSheet().getSheetId();

return (
<div
style={containerStyle}
>
<TextEditor id="test-editor-1" isReadonly={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} value="I found one cent on the roadside." />
<TextEditor id="test-editor-1" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} isReadonly={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} value="I found one cent on the roadside." />
<br></br>
<TextEditor id="test-editor-2" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} onlyInputFormula={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<br></br>
<TextEditor id="test-editor-2" onlyInputFormula={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<TextEditor id="test-editor-3" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} onlyInputRange={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<br></br>
<TextEditor id="test-editor-3" onlyInputRange={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<TextEditor id="test-editor-4" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} isSingle={false} onlyInputContent={true} style={{ ...editorStyle, height: '140px' }} canvasStyle={{ fontSize: 14 }} />
<br></br>
<TextEditor id="test-editor-4" isSingle={false} onlyInputContent={true} style={{ ...editorStyle, height: '140px' }} canvasStyle={{ fontSize: 14 }} />
<RangeSelector id="test-rangeSelector-1" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} />
</div>
);
};
6 changes: 5 additions & 1 deletion packages/design/src/components/dialog/index.module.less
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@

&-title {
margin: 0;
padding: 24px 28px 20px;
// padding: 24px 28px 20px;
font-size: var(--font-size-lg);
font-weight: 500;

> div:first-child {
padding: 24px 28px 20px;
}
}

&-content {
Expand Down
56 changes: 54 additions & 2 deletions packages/docs-ui/src/controllers/doc-editor-bridge.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import type { ICommandInfo, Nullable } from '@univerjs/core';
import { Disposable, ICommandService, IUniverInstanceService, LifecycleStages, OnLifecycle } from '@univerjs/core';
import { Inject } from '@wendellhu/redi';

import { ITextSelectionRenderManager, ScrollBar } from '@univerjs/engine-render';
import { IRenderManagerService, ITextSelectionRenderManager, ScrollBar } from '@univerjs/engine-render';
import type { IRichTextEditingMutationParams } from '@univerjs/docs';
import { CoverContentCommand, DocSkeletonManagerService, RichTextEditingMutation, VIEWPORT_KEY } from '@univerjs/docs';
import { IEditorService, SetEditorResizeOperation } from '@univerjs/ui';
import { fromEvent } from 'rxjs';

@OnLifecycle(LifecycleStages.Rendered, DocEditorBridgeController)
export class DocEditorBridgeController extends Disposable {
Expand All @@ -32,7 +33,8 @@ export class DocEditorBridgeController extends Disposable {
@Inject(DocSkeletonManagerService) private readonly _docSkeletonManagerService: DocSkeletonManagerService,
@IEditorService private readonly _editorService: IEditorService,
@ICommandService private readonly _commandService: ICommandService,
@ITextSelectionRenderManager private readonly _textSelectionRenderManager: ITextSelectionRenderManager
@ITextSelectionRenderManager private readonly _textSelectionRenderManager: ITextSelectionRenderManager,
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService

) {
super();
Expand Down Expand Up @@ -159,6 +161,23 @@ export class DocEditorBridgeController extends Disposable {
this._textSelectionRenderManager.blur();
})
);

this.disposeWithMe(
this._textSelectionRenderManager.onBlur$.subscribe(() => {
const unitId = this._currentUniverService.getCurrentUniverDocInstance().getUnitId();
if (unitId == null) {
return;
}

const editor = this._editorService.getEditor(unitId);

if (editor == null || editor.isSheetEditor()) {
return;
}

this._editorService.blur();
})
);
}

private _initialFocus() {
Expand All @@ -168,6 +187,39 @@ export class DocEditorBridgeController extends Disposable {
this._textSelectionRenderManager.addTextRanges([textRange]);
})
);

this.disposeWithMe(
fromEvent(window, 'mousedown').subscribe((event) => {
const target = event.target as HTMLElement;
const hasSearch = target.classList[0];
if (hasSearch?.indexOf('univer-formula-search') > -1 || hasSearch?.indexOf('univer-formula-help') > -1 || hasSearch?.indexOf('formula-help-decorator') || hasSearch?.indexOf('univer-formula-help-param')) {
this._editorService.changeSpreadsheetFocusState(true);
event.stopPropagation();
return;
}
this._editorService.changeSpreadsheetFocusState(false);
})
);

// this.disposeWithMe(
// fromEvent(window, 'mousedown').subscribe(() => {
// this._editorService.changeSpreadsheetFocusState(false);
// })
// );

const currentUniverSheet = this._currentUniverService.getAllUniverSheetsInstance();
currentUniverSheet.forEach((unit) => {
const unitId = unit.getUnitId();
const render = this._renderManagerService.getRenderById(unitId);
const canvasEle = render?.engine.getCanvas().getCanvasEle();
if (canvasEle == null) {
return;
}
fromEvent(canvasEle, 'mousedown').subscribe((evt) => {
this._editorService.changeSpreadsheetFocusState(true);
evt.stopPropagation();
});
});
}

private _initialValueChange() {
Expand Down
21 changes: 18 additions & 3 deletions packages/docs-ui/src/controllers/text-selection.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,23 @@ export class TextSelectionController extends Disposable {
this._currentUniverService.setCurrentUniverDocInstance(unitId);
}

this._textSelectionRenderManager.eventTrigger(evt);

this._setEditorFocus(unitId);
if (this._editorService.getEditor(unitId)) {
/**
* To accommodate focus switching between different editors.
* Since the editor for Univer is canvas-based,
* it primarily relies on focus and cannot use the focus event.
* Our editor's focus monitoring is based on PointerDown.
* The order of occurrence is such that PointerDown comes first.
* Translate the above text into English.
*/
setTimeout(() => {
this._textSelectionRenderManager.eventTrigger(evt);

this._setEditorFocus(unitId);
}, 0);
} else {
this._textSelectionRenderManager.eventTrigger(evt);
}

if (evt.button !== 2) {
state.stopPropagation();
Expand Down Expand Up @@ -168,6 +182,7 @@ export class TextSelectionController extends Disposable {
this._editorService.setOperationSheetUnitId(workbook.getUnitId());
// this._editorService.setOperationSheetSubUnitId(workbook.getActiveSheet().getSheetId());
}

this._editorService.focusStyle(unitId);
}

Expand Down
15 changes: 15 additions & 0 deletions packages/engine-formula/src/basics/match-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,18 @@ export function normalizeSheetName(sheetName: string) {
}
return sheetName;
}

/**
* Determine whether the character is a token keyword for the formula engine.
* @param char
*/
export function matchRefDrawToken(char: string) {
return (
(isFormulaLexerToken(char) &&
char !== matchToken.CLOSE_BRACES &&
char !== matchToken.CLOSE_BRACKET &&
char !== matchToken.SINGLE_QUOTATION &&
char !== matchToken.DOUBLE_QUOTATION) ||
char === ' '
);
}
1 change: 1 addition & 0 deletions packages/engine-formula/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,4 @@ export { FormulaExecutedStateType, type IAllRuntimeData } from './services/runti
export { SetNumfmtFormulaDataMutation } from './commands/mutations/set-numfmt-formula-data.mutation';
export type { ISetNumfmtFormulaDataMutationParams } from './commands/mutations/set-numfmt-formula-data.mutation';
export { isReferenceString } from './basics/regex';
export { matchRefDrawToken } from './basics/match-token';
2 changes: 2 additions & 0 deletions packages/engine-render/src/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export class Canvas {
this._canvasEle.style.left = '0';
this._canvasEle.style.zIndex = '8';

this._canvasEle.className = 'univer-render-canvas';

// support focus
this._canvasEle.tabIndex = 1;
this._canvasEle.style.touchAction = 'none';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,11 @@ export class TextSelectionRenderManager extends RxDisposable implements ITextSel

private _input!: HTMLDivElement;

private _moveObserver: Nullable<Observer<IPointerEvent | IMouseEvent>>;
private _moveObservers: Nullable<Observer<IPointerEvent | IMouseEvent>>[] = [];

private _upObserver: Nullable<Observer<IPointerEvent | IMouseEvent>>;
private _upObservers: Nullable<Observer<IPointerEvent | IMouseEvent>>[] = [];

private _scrollTimers: ScrollTimer[] = [];

private _viewportScrollX: number = 0;

Expand Down Expand Up @@ -479,6 +481,7 @@ export class TextSelectionRenderManager extends RxDisposable implements ITextSel
scene.disableEvent();

const scrollTimer = ScrollTimer.create(scene);
this._scrollTimers.push(scrollTimer);
scrollTimer.startScroll(evtOffsetX, evtOffsetY);

const { scrollX, scrollY } = getCurrentScrollXY(scrollTimer);
Expand All @@ -492,7 +495,7 @@ export class TextSelectionRenderManager extends RxDisposable implements ITextSel

let preMoveOffsetY = evtOffsetY;

this._moveObserver = scene.onPointerMoveObserver.add((moveEvt: IPointerEvent | IMouseEvent) => {
this._moveObservers.push(scene.onPointerMoveObserver.add((moveEvt: IPointerEvent | IMouseEvent) => {
const { offsetX: moveOffsetX, offsetY: moveOffsetY } = moveEvt;
scene.setCursor(CURSOR_TYPE.TEXT);

Expand All @@ -508,11 +511,23 @@ export class TextSelectionRenderManager extends RxDisposable implements ITextSel

preMoveOffsetX = moveOffsetX;
preMoveOffsetY = moveOffsetY;
});
}));

this._upObservers.push(scene.onPointerUpObserver.add(() => {
// scene.onPointerMoveObserver.remove(this._moveObserver);
// scene.onPointerUpObserver.remove(this._upObserver);

this._moveObservers.forEach((obs) => {
obs?.dispose();
});

this._upObservers.forEach((obs) => {
obs?.dispose();
});

this._moveObservers = [];

this._upObserver = scene.onPointerUpObserver.add(() => {
scene.onPointerMoveObserver.remove(this._moveObserver);
scene.onPointerUpObserver.remove(this._upObserver);
this._upObservers = [];

scene.enableEvent();

Expand All @@ -523,9 +538,14 @@ export class TextSelectionRenderManager extends RxDisposable implements ITextSel
isEditing: false,
});

scrollTimer.dispose();
this._scrollTimers.forEach((timer) => {
timer?.dispose();
});

this._scrollTimers = [];

this._updateInputPosition();
});
}));
}

removeAllTextRanges() {
Expand Down
6 changes: 5 additions & 1 deletion packages/engine-render/src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ export class Engine extends ThinEngine<Scene> {
* preventing the events from becoming ineffective once the mouse leaves the host.
*/
override setRemainCapture() {
this._canvasEle.setPointerCapture(this._remainCapture);
try {
this._canvasEle.setPointerCapture(this._remainCapture);
} catch {
console.warn('no capture');
}
}

getPixelRatio() {
Expand Down
17 changes: 15 additions & 2 deletions packages/engine-render/src/shape/base-scroll-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,17 @@ export class BaseScrollBar extends Disposable {
) {
return 1;
}
return (

const ratio = (
((this.horizontalThumbWidth - this.horizontalMinusMiniThumb) * this.miniThumbRatioX) /
this.horizontalBarWidth
);

if (Number.isNaN(ratio)) {
return 1;
} else {
return ratio;
}
}

get ratioScrollY(): number {
Expand All @@ -101,9 +108,15 @@ export class BaseScrollBar extends Disposable {
) {
return 1;
}
return (
const ratio = (
((this.verticalThumbHeight - this.verticalMinusMiniThumb) * this.miniThumbRatioY) / this.verticalBarHeight
);

if (Number.isNaN(ratio)) {
return 1;
} else {
return ratio;
}
}

get miniThumbRatioX() {
Expand Down
8 changes: 8 additions & 0 deletions packages/engine-render/src/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ export class Viewport {
x /= scaleX;
} else if (this.actualScrollX !== undefined) {
x = this.actualScrollX;
} else {
x = 0;
}

if (this._scrollBar.ratioScrollY !== 0) {
Expand All @@ -453,6 +455,8 @@ export class Viewport {
y /= scaleY;
} else if (this.actualScrollY !== undefined) {
y = this.actualScrollY;
} else {
y = 0;
}

// console.log(y, this._scrollBar.miniThumbRatioY);
Expand All @@ -461,10 +465,14 @@ export class Viewport {
} else {
if (this.actualScrollX !== undefined) {
x = this.actualScrollX;
} else {
x = 0;
}

if (this.actualScrollY !== undefined) {
y = this.actualScrollY;
} else {
y = 0;
}
}

Expand Down
Loading

0 comments on commit b639394

Please sign in to comment.