import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; import { ObservableReactComponent } from '../ObservableReactComponent'; interface IAnnotationProps extends FieldViewProps { anno: Doc; dataDoc: Doc; fieldKey: string; showInfo?: (anno: Opt) => void; pointerEvents?: () => Opt; } @observer export class Annotation extends ObservableReactComponent { constructor(props: any) { super(props); makeObservable(this); } render() { return (
{DocListCast(this._props.anno.text_inlineAnnotations).map(a => ( ))}
); } } interface IRegionAnnotationProps extends IAnnotationProps { document: Doc; pointerEvents?: () => Opt; } @observer class RegionAnnotation extends ObservableReactComponent { private _mainCont: React.RefObject = React.createRef(); @computed get annoTextRegion() { return Cast(this._props.document.annoTextRegion, Doc, null) || this._props.document; } @undoBatch deleteAnnotation = () => { const docAnnotations = DocListCast(this._props.dataDoc[this._props.fieldKey]); this._props.dataDoc[this._props.fieldKey] = new List(docAnnotations.filter(a => a !== this.annoTextRegion)); AnchorMenu.Instance.fadeOut(true); this._props.select(false); }; @undoBatch pinToPres = () => this._props.pinToPres(this.annoTextRegion, {}); @undoBatch makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); isTargetToggler = () => BoolCast(this.annoTextRegion.followLinkToggle); @undoBatch showTargetTrail = (anchor: Doc) => { const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; this._props.addDocTab(trail, OpenWhere.replaceRight); } }; @action onContextMenu = (e: React.MouseEvent) => { AnchorMenu.Instance.Status = 'annotation'; AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); AnchorMenu.Instance.Pinned = false; AnchorMenu.Instance.PinToPres = this.pinToPres; AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion); AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); e.stopPropagation(); e.preventDefault(); }; @action onPointerDown = (e: React.PointerEvent) => { if (e.button === 2 || e.ctrlKey) { e.stopPropagation(); e.preventDefault(); } else if (e.button === 0) { e.stopPropagation(); LinkFollower.FollowLink(undefined, this.annoTextRegion, false); } }; @computed get linkHighlighted() { for (const link of LinkManager.Instance.getAllDirectLinks(this._props.document)) { const a1 = LinkManager.getOppositeAnchor(link, this._props.document); if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this._props.document))) return true; } } render() { const brushed = this.annoTextRegion && Doc.GetBrushHighlightStatus(this.annoTextRegion); return (
{ Doc.BrushDoc(this._props.anno); this._props.showInfo?.(this._props.anno); })} onPointerLeave={action(() => { Doc.UnBrushDoc(this._props.anno); this._props.showInfo?.(undefined); })} onPointerDown={this.onPointerDown} onContextMenu={this.onContextMenu} style={{ left: NumCast(this._props.document.x), top: NumCast(this._props.document.y), width: NumCast(this._props.document._width), height: NumCast(this._props.document._height), opacity: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined, pointerEvents: this._props.pointerEvents?.() as any, outline: brushed === Doc.DocBrushStatus.unbrushed && this.linkHighlighted ? 'solid 1px lightBlue' : undefined, backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this._props.document.backgroundColor), }} /> ); } }