/* eslint-disable jsx-a11y/no-static-element-interactions */ import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { NodeSelection } from 'prosemirror-state'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { ClientUtils, returnFalse } from '../../../../ClientUtils'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast } from '../../../../fields/Types'; import { DocServer } from '../../../DocServer'; import { Docs } from '../../../documents/Documents'; import { DocUtils } from '../../../documents/DocUtils'; import { Transform } from '../../../util/Transform'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../DocumentView'; import { FocusViewOptions } from '../FocusViewOptions'; import { FormattedTextBox } from './FormattedTextBox'; const horizPadding = 3; // horizontal padding to container to allow cursor to show up on either side. interface IDashDocViewInternal { docId: string; embedding: string; tbox: FormattedTextBox; width: string; height: string; hidden: boolean; fieldKey: string; view: any; node: any; getPos: any; } @observer export class DashDocViewInternal extends ObservableReactComponent { _spanRef = React.createRef(); _disposers: { [name: string]: IReactionDisposer } = {}; _textBox: FormattedTextBox; @observable _dashDoc: Doc | undefined = undefined; @computed get _width() { return NumCast(this._dashDoc?._width); } @computed get _height() { return NumCast(this._dashDoc?._height); } updateDoc = action((dashDoc: Doc) => { this._dashDoc = dashDoc; if (this._props.width !== (this._dashDoc?._width ?? '') + 'px' || this._props.height !== (this._dashDoc?._height ?? '') + 'px') { try { // bcz: an exception will be thrown if two embeddings are open at the same time when a doc view comment is made this._props.view.dispatch( this._props.view.state.tr.setNodeMarkup(this._props.getPos(), null, { ...this._props.node.attrs, width: this._width + 'px', height: this._height + 'px', }) ); } catch (e) { console.log('DashDocView:' + e); } } }); constructor(props: IDashDocViewInternal) { super(props); makeObservable(this); this._textBox = this._props.tbox; DocServer.GetRefField(this._props.docId + this._props.embedding).then(async dashDoc => { if (!(dashDoc instanceof Doc)) { this._props.embedding && DocServer.GetRefField(this._props.docId).then(async dashDocBase => { if (dashDocBase instanceof Doc) { const embedding = Doc.MakeEmbedding(dashDocBase, this._props.docId + this._props.embedding); embedding.layout_fieldKey = 'layout'; this._props.fieldKey && DocUtils.makeCustomViewClicked(embedding, Docs.Create.StackingDocument, this._props.fieldKey, undefined); this.updateDoc(embedding); } }); } else { this.updateDoc(dashDoc); } }); } componentDidMount() { this._disposers.upater = reaction( () => ({ width: this._width, height: this._height, parent: this._spanRef.current?.parentNode as HTMLElement }), action(({ width, height, parent }) => { if (parent) { parent.style.width = width + 'px'; parent.style.height = height + 'px'; } }) ); } removeDoc = () => { this._props.view.dispatch(this._props.view.state.tr.setSelection(new NodeSelection(this._props.view.state.doc.resolve(this._props.getPos()))).deleteSelection()); return true; }; getDocTransform = () => { if (!this._spanRef.current) return Transform.Identity(); const { scale, translateX, translateY } = ClientUtils.GetScreenTransform(this._spanRef.current); return new Transform(-translateX, -translateY, 1).scale(1 / scale); }; outerFocus = (target: Doc, options: FocusViewOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target onKeyDown = (e: any) => { e.stopPropagation(); if (e.key === 'Tab' || e.key === 'Enter') { e.preventDefault(); } }; onPointerLeave = () => { const ele = document.getElementById('DashDocCommentView-' + this._props.docId) as HTMLDivElement; ele && (ele.style.backgroundColor = ''); }; onPointerEnter = () => { const ele = document.getElementById('DashDocCommentView-' + this._props.docId) as HTMLDivElement; ele && (ele.style.backgroundColor = 'orange'); }; componentWillUnmount = () => Object.values(this._disposers).forEach(disposer => disposer?.()); isContentActive = () => this._props.tbox._props.isContentActive() || this._props.tbox.isAnyChildContentActive?.(); render() { return !this._dashDoc || this._props.hidden ? null : (
e.stopPropagation()} onKeyUp={e => e.stopPropagation()} onWheel={e => e.preventDefault()}>
); } } export class DashDocView { dom: HTMLSpanElement; // container for label and value root: any; constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { this.dom = document.createElement('span'); this.dom.style.position = 'relative'; this.dom.style.textIndent = '0'; this.dom.style.width = (+node.attrs.width.toString().replace('px', '') + horizPadding).toString(); this.dom.style.height = node.attrs.height; this.dom.style.display = node.attrs.hidden ? 'none' : 'inline-block'; (this.dom.style as any).float = node.attrs.float; this.dom.onkeypress = function (e: any) { e.stopPropagation(); }; this.dom.onkeydown = function (e: any) { e.stopPropagation(); }; this.dom.onkeyup = function (e: any) { e.stopPropagation(); }; this.dom.onmousedown = function (e: any) { e.stopPropagation(); }; this.root = ReactDOM.createRoot(this.dom); this.root.render(