Skip to content

Commit

Permalink
fix(editor): controlled component and readonly (#1507)
Browse files Browse the repository at this point in the history
  • Loading branch information
DR-Univer committed Mar 7, 2024
1 parent 9f0a842 commit c8c7bf3
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 25 deletions.
18 changes: 11 additions & 7 deletions examples/src/plugins/debugger/views/test-editor/TestTextEditor.tsx
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import React from 'react';
import React, { useState } from 'react';

import { RangeSelector, TextEditor } from '@univerjs/ui';
import { IUniverInstanceService } from '@univerjs/core';
Expand Down Expand Up @@ -48,23 +48,27 @@ export const TestEditorContainer = () => {

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

const [readonly, setReadonly] = useState(false);

return (
<div
style={containerStyle}
>
<TextEditor id="test-editor-1" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} 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={readonly} 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 }} />
<TextEditor id="test-editor-2" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} isReadonly={readonly} onlyInputFormula={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<br></br>
<TextEditor id="test-editor-3" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} onlyInputRange={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<TextEditor id="test-editor-3" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} isReadonly={readonly} onlyInputRange={true} style={editorStyle} canvasStyle={{ fontSize: 10 }} />
<br></br>
<TextEditor id="test-editor-4" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} isSingle={false} onlyInputContent={true} style={{ ...editorStyle, height: '140px' }} canvasStyle={{ fontSize: 14 }} />
<TextEditor id="test-editor-4" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} isReadonly={readonly} isSingle={false} onlyInputContent={true} style={{ ...editorStyle, height: '140px' }} canvasStyle={{ fontSize: 14 }} />
<br></br>
<RangeSelector id="test-rangeSelector-1" openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} />
<RangeSelector id="test-rangeSelector-1" openForSheetUnitId={unitId} isReadonly={readonly} openForSheetSubUnitId={sheetId} />
<br></br>
<RangeSelector id="test-rangeSelector-2" isSingleChoice={true} openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} />
<RangeSelector id="test-rangeSelector-2" isSingleChoice={true} isReadonly={readonly} openForSheetUnitId={unitId} openForSheetSubUnitId={sheetId} />
<br></br>
<Input allowClear />
<br></br>
<button onClick={() => setReadonly(!readonly)}>{readonly === true ? 'enable' : 'disable'}</button>
</div>
);
};
6 changes: 6 additions & 0 deletions packages/docs-ui/src/controllers/text-selection.controller.ts
Expand Up @@ -149,6 +149,9 @@ export class TextSelectionController extends Disposable {
this.disposeWithMe(
toDisposable(
document?.onDblclickObserver.add((evt: IPointerEvent | IMouseEvent) => {
if (this._isEditorReadOnly(unitId)) {
return;
}
this._textSelectionRenderManager.handleDblClick(evt);
})
)
Expand All @@ -157,6 +160,9 @@ export class TextSelectionController extends Disposable {
this.disposeWithMe(
toDisposable(
document?.onTripleClickObserver.add((evt: IPointerEvent | IMouseEvent) => {
if (this._isEditorReadOnly(unitId)) {
return;
}
this._textSelectionRenderManager.handleTripleClick(evt);
})
)
Expand Down
11 changes: 11 additions & 0 deletions packages/ui/src/components/editor/TextEditor.tsx
Expand Up @@ -214,6 +214,17 @@ export function TextEditor(props: ITextEditorProps & Omit<MyComponentProps, 'onC
};
}, []);

useEffect(() => {
const editor = editorService.getEditor(id);
if (editor == null) {
return;
}

editor.update({
isReadonly, isSingle, isSingleChoice, onlyInputContent, onlyInputFormula, onlyInputRange, openForSheetSubUnitId, openForSheetUnitId,
});
}, [isReadonly, isSingle, isSingleChoice, onlyInputContent, onlyInputFormula, onlyInputRange, openForSheetSubUnitId, openForSheetUnitId]);

useEffect(() => {
if (value == null) {
return;
Expand Down
36 changes: 30 additions & 6 deletions packages/ui/src/components/range-selector/RangeSelector.tsx
Expand Up @@ -34,13 +34,13 @@ export interface IRangeSelectorProps {
onActive?: (state: boolean) => void; // Callback for editor active.
onValid?: (state: boolean) => void; // input value validation
isSingleChoice?: boolean; // Whether to restrict to only selecting a single region/area/district.

isReadonly?: boolean; // Set the selector to read-only state.
openForSheetUnitId?: Nullable<string>; // Configuring which workbook the selector defaults to opening in determines whether the ref includes a [unitId] prefix.
openForSheetSubUnitId?: Nullable<string>; // Configuring the default worksheet where the selector opens determines whether the ref includes a [unitId]sheet1 prefix.
}

export function RangeSelector(props: IRangeSelectorProps) {
const { onChange, id, value = '', onActive, onValid, isSingleChoice = false, openForSheetUnitId, openForSheetSubUnitId } = props;
const { onChange, id, value = '', onActive, onValid, isSingleChoice = false, openForSheetUnitId, openForSheetSubUnitId, isReadonly = false } = props;

const [rangeDataList, setRangeDataList] = useState<string[]>(['']);

Expand Down Expand Up @@ -94,6 +94,14 @@ export function RangeSelector(props: IRangeSelectorProps) {

const currentInputIndexRef = useRef<number>(-1);

const openForSheetUnitIdRef = useRef<Nullable<string>>(openForSheetUnitId);

const openForSheetSubUnitIdRef = useRef<Nullable<string>>(openForSheetSubUnitId);

const isSingleChoiceRef = useRef<Nullable<boolean>>(isSingleChoice);

const isReadonlyRef = useRef<Nullable<boolean>>(isReadonly);

useEffect(() => {
const selector = selectorRef.current;

Expand Down Expand Up @@ -129,15 +137,15 @@ export function RangeSelector(props: IRangeSelectorProps) {

let rangeRef: string = '';

if (lastRange.unitId === openForSheetUnitId && lastRange.sheetId === openForSheetSubUnitId) {
if (lastRange.unitId === openForSheetUnitIdRef.current && lastRange.sheetId === openForSheetSubUnitIdRef.current) {
rangeRef = serializeRange(lastRange.range);
} else if (lastRange.unitId === openForSheetUnitId) {
} else if (lastRange.unitId === openForSheetUnitIdRef.current) {
rangeRef = serializeRangeWithSheet(lastRange.sheetName, lastRange.range);
} else {
rangeRef = serializeRangeWithSpreadsheet(lastRange.unitId, lastRange.sheetName, lastRange.range);
}

if (addItemCount >= 1 && !isSingleChoice) {
if (addItemCount >= 1 && !isSingleChoiceRef.current) {
addNewItem(rangeRef);
setCurrentInputIndex(-1);
} else {
Expand All @@ -156,6 +164,13 @@ export function RangeSelector(props: IRangeSelectorProps) {
};
}, []);

useEffect(() => {
openForSheetUnitIdRef.current = openForSheetUnitId;
openForSheetSubUnitIdRef.current = openForSheetSubUnitId;
isSingleChoiceRef.current = isSingleChoice;
isReadonlyRef.current = isReadonly;
}, [openForSheetUnitId, openForSheetSubUnitId, isSingleChoice, isReadonly]);

useEffect(() => {
currentInputIndexRef.current = currentInputIndex;
}, [currentInputIndex]);
Expand All @@ -166,6 +181,10 @@ export function RangeSelector(props: IRangeSelectorProps) {
}

function handleOpenModal() {
if (isReadonlyRef.current === true) {
return;
}

if (valid) {
setRangeDataList(rangeValue.split(','));
} else {
Expand All @@ -190,6 +209,11 @@ export function RangeSelector(props: IRangeSelectorProps) {
}

function handleConform() {
if (isReadonlyRef.current === true) {
handleCloseModal();
return;
}

let result = '';
const list = rangeDataList.filter((rangeRef) => {
return isReferenceString(rangeRef.trim());
Expand Down Expand Up @@ -241,7 +265,7 @@ export function RangeSelector(props: IRangeSelectorProps) {
return (
<>
<div className={sClassName} ref={selectorRef}>
<TextEditor isSingleChoice={isSingleChoice} openForSheetUnitId={openForSheetUnitId} openForSheetSubUnitId={openForSheetSubUnitId} onValid={onEditorValid} onActive={onEditorActive} onChange={handleTextValueChange} id={id} onlyInputRange={true} canvasStyle={{ fontSize: 10 }} className={styles.rangeSelectorEditor} />
<TextEditor isReadonly={isReadonly} isSingleChoice={isSingleChoice} openForSheetUnitId={openForSheetUnitId} openForSheetSubUnitId={openForSheetSubUnitId} onValid={onEditorValid} onActive={onEditorActive} onChange={handleTextValueChange} id={id} onlyInputRange={true} canvasStyle={{ fontSize: 10 }} className={styles.rangeSelectorEditor} />
<Tooltip title={localeService.t('rangeSelector.buttonTooltip')} placement="bottom">
<button className={styles.rangeSelectorIcon} onClick={handleOpenModal}>
<SelectRangeSingle />
Expand Down
13 changes: 1 addition & 12 deletions packages/ui/src/services/editor/editor.service.ts
Expand Up @@ -176,7 +176,7 @@ export class Editor {
return this._param.documentDataModel.getBody();
}

update(param: IEditorStateParam) {
update(param: Partial<IEditorSetParam>) {
this._param = {
...this._param,
...param,
Expand Down Expand Up @@ -235,8 +235,6 @@ export class Editor {
export interface IEditorService {
getEditor(id?: string): Readonly<Nullable<Editor>>;

setState(param: IEditorStateParam, id: string): void;

register(config: IEditorConfigParam, container: HTMLDivElement): IDisposable;

isVisible(id: string): Nullable<boolean>;
Expand Down Expand Up @@ -552,15 +550,6 @@ export class EditorService extends Disposable implements IEditorService, IDispos
this._resize$.next(unitId);
}

setState(param: IEditorStateParam, id: string) {
const editor = this._editors.get(id);
if (editor) {
editor.update(param);
}

this._refresh(param);
}

isVisible(id: string) {
return this.getEditor(id)?.isVisible();
}
Expand Down

0 comments on commit c8c7bf3

Please sign in to comment.