import { docs } from "googleapis/build/src/apis/docs"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import * as React from "react"; import ReactLoading from 'react-loading'; import { Doc, WidthSym, HeightSym, DocListCast } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { Cast, NumCast } from "../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../Utils"; import { DocUtils } from "../documents/Documents"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { DragManager } from "../util/DragManager"; import { ScriptingGlobals } from "../util/ScriptingGlobals"; import { Transform } from "../util/Transform"; import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView"; import { DocumentView } from "./nodes/DocumentView"; import './OverlayView.scss'; import { ScriptingRepl } from './ScriptingRepl'; import { DefaultStyleProvider } from "./StyleProvider"; export type OverlayDisposer = () => void; export type OverlayElementOptions = { x: number; y: number; width?: number; height?: number; title?: string; }; export interface OverlayWindowProps { children: JSX.Element; overlayOptions: OverlayElementOptions; onClick: () => void; } @observer export class OverlayWindow extends React.Component { @observable x: number; @observable y: number; @observable width: number; @observable height: number; constructor(props: OverlayWindowProps) { super(props); const opts = props.overlayOptions; this.x = opts.x; this.y = opts.y; this.width = opts.width || 200; this.height = opts.height || 200; } onPointerDown = (_: React.PointerEvent) => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); document.addEventListener("pointerup", this.onPointerUp); } onResizerPointerDown = (_: React.PointerEvent) => { document.removeEventListener("pointermove", this.onResizerPointerMove); document.removeEventListener("pointerup", this.onResizerPointerUp); document.addEventListener("pointermove", this.onResizerPointerMove); document.addEventListener("pointerup", this.onResizerPointerUp); } @action onPointerMove = (e: PointerEvent) => { this.x += e.movementX; this.x = Math.max(Math.min(this.x, window.innerWidth - this.width), 0); this.y += e.movementY; this.y = Math.max(Math.min(this.y, window.innerHeight - this.height), 0); } @action onResizerPointerMove = (e: PointerEvent) => { this.width += e.movementX; this.width = Math.max(this.width, 30); this.height += e.movementY; this.height = Math.max(this.height, 30); } onPointerUp = (e: PointerEvent) => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); } onResizerPointerUp = (e: PointerEvent) => { document.removeEventListener("pointermove", this.onResizerPointerMove); document.removeEventListener("pointerup", this.onResizerPointerUp); } render() { return (
{this.props.overlayOptions.title || "Untitled"}
{this.props.children}
); } } @observer export class OverlayView extends React.Component { public static Instance: OverlayView; @observable.shallow private _elements: JSX.Element[] = []; constructor(props: any) { super(props); if (!OverlayView.Instance) { OverlayView.Instance = this; } } @action addElement(ele: JSX.Element, options: OverlayElementOptions): OverlayDisposer { const remove = action(() => { const index = this._elements.indexOf(ele); if (index !== -1) this._elements.splice(index, 1); }); ele =
{ele}
; this._elements.push(ele); return remove; } @action addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer { const remove = action(() => { const index = this._elements.indexOf(contents); if (index !== -1) this._elements.splice(index, 1); }); contents = {contents}; this._elements.push(contents); return remove; } removeOverlayDoc = (doc: Doc | Doc[]) => { (doc instanceof Doc ? [doc] : doc).forEach(doc => Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, doc)); return true; } docScreenToLocalXf = computedFn(function docScreenToLocalXf(this: any, doc: Doc) { return () => new Transform(-NumCast(doc.x), -NumCast(doc.y), 1); }.bind(this)); @computed get overlayDocs() { return DocListCast(CurrentUserUtils.MyOverlayDocs?.data).map(d => { let offsetx = 0, offsety = 0; const dref = React.createRef(); const onPointerMove = action((e: PointerEvent, down: number[]) => { if (e.buttons === 1) { d.x = e.clientX + offsetx; d.y = e.clientY + offsety; } if (e.metaKey) { const dragData = new DragManager.DocumentDragData([d]); dragData.offset = [-offsetx, -offsety]; dragData.dropAction = "move"; dragData.removeDocument = (doc: Doc | Doc[]) => { const docs = (doc instanceof Doc) ? [doc] : doc; docs.forEach(d => Doc.RemoveDocFromList(CurrentUserUtils.MyOverlayDocs, undefined, d)); return true; }; dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { return dragData.removeDocument!(doc) ? addDocument(doc) : false; }; DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]); return true; } return false; }); const onPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction); offsetx = NumCast(d.x) - e.clientX; offsety = NumCast(d.y) - e.clientY; }; return
; }); } public static ShowSpinner() { return OverlayView.Instance.addElement(, { x: 300, y: 200 }); } render() { return (
{this._elements}
{this.overlayDocs}
); } } // bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error ScriptingGlobals.add(function addOverlayWindow(type: string, options: OverlayElementOptions) { OverlayView.Instance.addWindow(, options); });