import React = require("react"); import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { BoolCast, NumCast } from "../../../new_fields/Types"; import { emptyFunction, returnOne, Utils } from "../../../Utils"; import { SelectionManager } from "../../util/SelectionManager"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _heightDisposer?: IReactionDisposer; get gridGap() { return 10; } get gridSize() { return 20; } get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); } get columnWidth() { return this.singleColumn ? this.props.PanelWidth() - 4 * this.gridGap : NumCast(this.props.Document.columnWidth, 250); } componentDidMount() { this._heightDisposer = reaction(() => [this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized]), this.columnWidth, this.props.PanelHeight()], () => { if (this.singleColumn) { this.props.Document.height = this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => { let hgt = d[HeightSym](); let wid = d[WidthSym](); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (nw && nh) hgt = nh / nw * Math.min(this.columnWidth, wid); return height + hgt + 2 * this.gridGap; }, this.gridGap * 2); } }, { fireImmediately: true }); } componentWillUnmount() { if (this._heightDisposer) this._heightDisposer(); } @action moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { this.props.removeDocument(doc); addDocument(doc); return true; } getDocTransform(doc: Doc, dref: HTMLDivElement) { let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); } createRef = (ele: HTMLDivElement | null) => { this._masonryGridRef = ele; this.createDropTarget(ele!); } @undoBatch @action public collapseToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => { SelectionManager.DeselectAll(); if (expandedDocs) { let isMinimized: boolean | undefined; expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { if (isMinimized === undefined) { isMinimized = BoolCast(maximizedDoc.isMinimized, false); } maximizedDoc.isMinimized = !isMinimized; }); } } @computed get singleColumnChildren() { return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { let dref = React.createRef(); let script = undefined; let colWidth = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; let margin = colWidth() < this.columnWidth ? "auto" : undefined; let rowHeight = () => { let hgt = d[HeightSym](); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (nw && nh) hgt = nh / nw * colWidth(); return hgt; } let dxf = () => this.getDocTransform(d, dref.current!).scale(this.columnWidth / d[WidthSym]()); return
; }); } @computed get children() { return this.childDocs.filter(d => !d.isMinimized).map(d => { let dref = React.createRef(); let dxf = () => this.getDocTransform(d, dref.current!); let colSpan = Math.ceil(Math.min(d[WidthSym](), this.columnWidth + this.gridGap) / (this.gridSize + this.gridGap)); let rowSpan = Math.ceil((this.columnWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap)); let childFocus = (doc: Doc) => { doc.libraryBrush = true; this.props.focus(this.props.Document); // just focus on this collection, not the underlying document because the API doesn't support adding an offset to focus on and we can't pan zoom our contents to be centered. } return (
); }) } render() { let leftMargin = 2 * this.gridGap; let topMargin = 2 * this.gridGap; let itemCols = Math.ceil(this.columnWidth / (this.gridSize + this.gridGap)); let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (this.gridSize + this.gridGap))); return (
e.stopPropagation()}>
{this.singleColumn ? this.singleColumnChildren : this.children}
); } }