diff options
Diffstat (limited to 'src/client/views/EditableView.tsx')
-rw-r--r-- | src/client/views/EditableView.tsx | 116 |
1 files changed, 61 insertions, 55 deletions
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index abb7ed7ee..73ac1b032 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -1,10 +1,12 @@ -import React = require('react'); -import { action, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as Autosuggest from 'react-autosuggest'; import { ObjectField } from '../../fields/ObjectField'; import './EditableView.scss'; import { DocumentIconContainer } from './nodes/DocumentIcon'; +import { FieldView, FieldViewProps } from './nodes/FieldView'; +import { ObservableReactComponent } from './ObservableReactComponent'; import { OverlayView } from './OverlayView'; export interface EditableProps { @@ -26,6 +28,7 @@ export interface EditableProps { * The contents to render when not editing */ contents: any; + fieldContents?: FieldViewProps; fontStyle?: string; fontSize?: number; height?: number | 'auto'; @@ -57,7 +60,7 @@ export interface EditableProps { * of the content, and set the value based on the entered string. */ @observer -export class EditableView extends React.Component<EditableProps> { +export class EditableView extends ObservableReactComponent<EditableProps> { private _ref = React.createRef<HTMLDivElement>(); private _inputref: HTMLInputElement | HTMLTextAreaElement | null = null; _overlayDisposer?: () => void; @@ -66,7 +69,8 @@ export class EditableView extends React.Component<EditableProps> { constructor(props: EditableProps) { super(props); - this._editing = this.props.editing ? true : false; + makeObservable(this); + this._editing = this._props.editing ? true : false; } componentDidMount(): void { @@ -89,12 +93,12 @@ export class EditableView extends React.Component<EditableProps> { ); } - @action - componentDidUpdate() { - if (this._editing && this.props.editing === false) { + componentDidUpdate(prevProps: Readonly<EditableProps>) { + super.componentDidUpdate(prevProps); + if (this._editing && this._props.editing === false) { this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false); - } else if (this.props.editing !== undefined) { - this._editing = this.props.editing; + } else if (this._props.editing !== undefined) { + this._editing = this._props.editing; } } @@ -120,28 +124,28 @@ export class EditableView extends React.Component<EditableProps> { case 'Tab': e.stopPropagation(); this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false); - this.props.OnTab?.(e.shiftKey); + this._props.OnTab?.(e.shiftKey); break; case 'Backspace': e.stopPropagation(); - if (!e.currentTarget.value) this.props.OnEmpty?.(); + if (!e.currentTarget.value) this._props.OnEmpty?.(); break; case 'Enter': - if (this.props.allowCRs !== true) { + if (this._props.allowCRs !== true) { e.stopPropagation(); if (!e.ctrlKey) { this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); - } else if (this.props.OnFillDown) { - this.props.OnFillDown(e.currentTarget.value); + } else if (this._props.OnFillDown) { + this._props.OnFillDown(e.currentTarget.value); this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); } } break; case 'Escape': e.stopPropagation(); this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); break; case 'ArrowUp': case 'ArrowDown': @@ -155,30 +159,30 @@ export class EditableView extends React.Component<EditableProps> { case 'Control': break; case ':': - if (this.props.menuCallback) { + if (this._props.menuCallback) { e.stopPropagation(); - this.props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); + this._props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); break; } default: - if (this.props.textCallback?.(e.key)) { + if (this._props.textCallback?.(e.key)) { e.stopPropagation(); this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); } } }; @action onClick = (e: React.MouseEvent) => { - if (this.props.editing !== false) { + if (this._props.editing !== false) { e.nativeEvent.stopPropagation(); - if (this._ref.current && this.props.showMenuOnLoad) { - this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y); + if (this._ref.current && this._props.showMenuOnLoad) { + this._props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y); } else { this._editing = true; - this.props.isEditingCallback?.(true); + this._props.isEditingCallback?.(true); } // e.stopPropagation(); } @@ -186,17 +190,17 @@ export class EditableView extends React.Component<EditableProps> { @action finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { - if (this.props.SetValue(value, shiftDown, enterKey)) { + if (this._props.SetValue(value, shiftDown, enterKey)) { this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); } else { this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); !lostFocus && setTimeout( action(() => { this._editing = true; - this.props.isEditingCallback?.(true); + this._props.isEditingCallback?.(true); }), 0 ); @@ -215,30 +219,32 @@ export class EditableView extends React.Component<EditableProps> { }; renderEditor() { - return this.props.autosuggestProps ? ( + return this._props.autosuggestProps ? ( <Autosuggest - {...this.props.autosuggestProps.autosuggestProps} + {...this._props.autosuggestProps.autosuggestProps} inputProps={{ className: 'editableView-input', onKeyDown: this.onKeyDown, autoFocus: true, + // @ts-ignore onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true, false), onPointerDown: this.stopPropagation, onClick: this.stopPropagation, onPointerUp: this.stopPropagation, onKeyPress: this.stopPropagation, - value: this.props.autosuggestProps.value, - onChange: this.props.autosuggestProps.onChange, + value: this._props.autosuggestProps.value, + // @ts-ignore + onChange: this._props.autosuggestProps.onChange, }} /> - ) : this.props.oneLine !== false && this.props.GetValue()?.toString().indexOf('\n') === -1 ? ( + ) : this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? ( <input className="editableView-input" ref={r => (this._inputref = r)} - style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }} - placeholder={this.props.placeholder} + style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background }} + placeholder={this._props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} - defaultValue={this.props.GetValue()} + defaultValue={this._props.GetValue()} autoFocus={true} onChange={this.onChange} onKeyDown={this.onKeyDown} @@ -251,10 +257,10 @@ export class EditableView extends React.Component<EditableProps> { <textarea className="editableView-input" ref={r => (this._inputref = r)} - style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minHeight: `min(100%, ${(this.props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, background: this.props.background }} - placeholder={this.props.placeholder} + style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, background: this._props.background }} + placeholder={this._props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} - defaultValue={this.props.GetValue()} + defaultValue={this._props.GetValue()} autoFocus={true} onChange={this.onChange} onKeyDown={this.onKeyDown} @@ -267,9 +273,9 @@ export class EditableView extends React.Component<EditableProps> { } render() { - const gval = this.props.GetValue()?.replace(/\n/g, '\\r\\n'); + const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n'); if (this._editing && gval !== undefined) { - return this.props.sizeToContent ? ( + return this._props.sizeToContent ? ( <div style={{ display: 'grid', minWidth: 100 }}> <div style={{ display: 'inline-block', position: 'relative', height: 0, width: '100%', overflow: 'hidden' }}>{gval}</div> {this.renderEditor()} @@ -278,30 +284,30 @@ export class EditableView extends React.Component<EditableProps> { this.renderEditor() ); } - setTimeout(() => this.props.autosuggestProps?.resetValue()); - return this.props.contents instanceof ObjectField ? null : ( + setTimeout(() => this._props.autosuggestProps?.resetValue()); + return this._props.contents instanceof ObjectField ? null : ( <div - className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`} + className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`} ref={this._ref} style={{ - display: this.props.display, // - textOverflow: this.props.overflow, + display: this._props.display, // + textOverflow: this._props.overflow, minHeight: '10px', - whiteSpace: this.props.oneLine ? 'nowrap' : 'pre-line', - height: this.props.height, - maxHeight: this.props.maxHeight, - fontStyle: this.props.fontStyle, - fontSize: this.props.fontSize, + whiteSpace: this._props.oneLine ? 'nowrap' : 'pre-line', + height: this._props.height, + maxHeight: this._props.maxHeight, + fontStyle: this._props.fontStyle, + fontSize: this._props.fontSize, }} //onPointerDown={this.stopPropagation} onClick={this.onClick} - placeholder={this.props.placeholder}> + placeholder={this._props.placeholder}> <span style={{ - fontStyle: this.props.fontStyle, - fontSize: this.props.fontSize, + fontStyle: this._props.fontStyle, + fontSize: this._props.fontSize, }}> - {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()} + {this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : this.props.contents ? this._props.contents?.valueOf() : this._props.placeholder?.valueOf()} </span> </div> ); |