From 118ecb14ce519bcbade12b3d52e11b22fcc371b3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 19 Jun 2019 22:40:54 -0400
Subject: cleaned up and enhanced tree view

---
 .../views/collections/CollectionTreeView.tsx       | 347 +++++++++------------
 1 file changed, 152 insertions(+), 195 deletions(-)

(limited to 'src/client/views/collections/CollectionTreeView.tsx')

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 1eab541b3..856430036 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,38 +1,35 @@
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt, faCaretSquareRight, faCaretSquareDown } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, observable, trace, computed } from "mobx";
+import { action, observable } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { Id } from '../../../new_fields/FieldSymbols';
+import { List } from '../../../new_fields/List';
 import { Document, listSpec } from '../../../new_fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast, PromiseValue } from '../../../new_fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types';
+import { emptyFunction, Utils } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager";
+import { SelectionManager } from '../../util/SelectionManager';
+import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
 import { EditableView } from "../EditableView";
 import { MainView } from '../MainView';
+import { Templates } from '../Templates';
 import { CollectionViewType } from './CollectionBaseView';
 import { CollectionDockingView } from './CollectionDockingView';
-import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView";
+import { CollectionSchemaPreview } from './CollectionSchemaView';
+import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
-import { Transform } from '../../util/Transform';
-import { SelectionManager } from '../../util/SelectionManager';
-import { emptyFunction, returnFalse, Utils, returnOne, returnZero } from '../../../Utils';
-import { List } from '../../../new_fields/List';
-import { Templates } from '../Templates';
-import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
-import { number } from 'prop-types';
-import ReactTable from 'react-table';
-import { MainOverlayTextBox } from '../MainOverlayTextBox';
 
 
 export interface TreeViewProps {
     document: Doc;
-    deleteDoc: (doc: Doc) => void;
+    deleteDoc: (doc: Doc) => boolean;
     moveDocument: DragManager.MoveFunction;
     dropAction: "alias" | "copy" | undefined;
     addDocTab: (doc: Doc, where: string) => void;
@@ -41,22 +38,18 @@ export interface TreeViewProps {
     addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean;
     indentDocument?: () => void;
     ScreenToLocalTransform: () => Transform;
-    outerXf: () => number[];
+    outerXf: () => { translateX: number, translateY: number };
     treeViewId: string;
     parentKey: string;
     active: () => boolean;
 }
 
-export enum BulletType {
-    Collapsed,
-    Collapsible,
-    List
-}
-
 library.add(faTrashAlt);
 library.add(faAngleRight);
 library.add(faCaretDown);
 library.add(faCaretRight);
+library.add(faCaretSquareDown);
+library.add(faCaretSquareRight);
 
 @observer
 /**
@@ -64,25 +57,22 @@ library.add(faCaretRight);
  */
 class TreeView extends React.Component<TreeViewProps> {
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
-    private treedropDisposer?: DragManager.DragDropDisposer;
-    private _mainEle?: HTMLDivElement;
+    private _treedropDisposer?: DragManager.DragDropDisposer;
+    private _dref = React.createRef<HTMLDivElement>();
+    @observable _chosenKey: string = "data";
+    @observable _collapsed: boolean = true;
+
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
-        this.treedropDisposer && this.treedropDisposer();
+        this._treedropDisposer && this._treedropDisposer();
         if (ele) {
-            this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } });
+            this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } });
         }
-        this._mainEle = ele;
     }
 
-    @observable _isOver: boolean = false;
-    @observable _collapsed: boolean = true;
-
     @undoBatch delete = () => this.props.deleteDoc(this.props.document);
     @undoBatch openRight = async () => this.props.addDocTab(this.props.document, "openRight");
 
-    @action onMouseEnter = () => { this._isOver = true; };
-    @action onMouseLeave = () => { this._isOver = false; };
-
+    onPointerDown = (e: React.PointerEvent) => e.stopPropagation()
     onPointerEnter = (e: React.PointerEvent): void => {
         this.props.active() && (this.props.document.libraryBrush = true);
         if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
@@ -101,80 +91,60 @@ class TreeView extends React.Component<TreeViewProps> {
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
         let before = x[1] < bounds[1];
-        let inside = x[0] > bounds[0] + 75 || (!before && this._bulletType === BulletType.Collapsible);
+        let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed);
         this._header!.current!.className = "treeViewItem-header";
-        if (inside && this._bulletType !== BulletType.List) this._header!.current!.className += " treeViewItem-header-inside";
+        if (inside) this._header!.current!.className += " treeViewItem-header-inside";
         else if (before) this._header!.current!.className += " treeViewItem-header-above";
         else if (!before) this._header!.current!.className += " treeViewItem-header-below";
         e.stopPropagation();
     }
-    onPointerDown = (e: React.PointerEvent) => {
-        e.stopPropagation();
-    }
 
     @action
-    remove = (document: Document, key: string) => {
+    remove = (document: Document, key: string): boolean => {
         let children = Cast(this.props.document[key], listSpec(Doc), []);
-        children.indexOf(document) !== -1 && children.splice(children.indexOf(document), 1);
+        if (children.indexOf(document) !== -1) {
+            children.splice(children.indexOf(document), 1);
+            return true;
+        }
+        return false;
     }
 
     @action
-    move: DragManager.MoveFunction = (document: Doc, target: Doc, addDoc) => {
-        if (this.props.document !== target) {
-            //TODO This should check if it was removed
-            this.props.deleteDoc(document);
-            return addDoc(document);
-        }
-        return true;
+    move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => {
+        return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
     }
     @action
-    indent = () => {
-        this.props.addDocument(this.props.document);
-        this.delete();
-    }
-
+    indent = () => this.props.addDocument(this.props.document) && this.delete();
 
-    renderBullet(type: BulletType) {
-        let onClicked = action(() => this._collapsed = !this._collapsed);
-        let bullet: IconProp | undefined = undefined;
-        switch (type) {
-            case BulletType.Collapsed: bullet = "caret-right"; break;
-            case BulletType.Collapsible: bullet = "caret-down"; break;
-        }
-        return <div className="bullet" onClick={onClicked}>{bullet ? <FontAwesomeIcon icon={bullet} /> : ""} </div>;
+    renderBullet() {
+        let docList = Cast(this.props.document["data"], listSpec(Doc));
+        let doc = Cast(this.props.document["data"], Doc);
+        let isDoc = doc instanceof Doc || docList;
+        return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)}>
+            {<FontAwesomeIcon icon={this._collapsed ? (isDoc ? "caret-square-right" : "caret-right") : (isDoc ? "caret-square-down" : "caret-down")} />}
+        </div>;
     }
-    static loadId = "";
-    editableView = (key: string, style?: string) =>
-        (<EditableView
-            oneLine={true}
-            display={"inline"}
-            editing={this.props.document[Id] === TreeView.loadId}
-            contents={StrCast(this.props.document[key])}
-            height={36}
-            fontStyle={style}
-            GetValue={() => StrCast(this.props.document[key])}
-            OnFillDown={(value: string) => {
-                Doc.GetProto(this.props.document)[key] = value;
-                let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25 });
-                TreeView.loadId = doc[Id];
-                doc.templates = new List<string>([Templates.Title.Layout]);
-                this.props.addDocument(doc);
-                return true;
-            }}
-            OnTab={() => this.props.indentDocument && this.props.indentDocument()}
-            SetValue={(value: string) => {
-                Doc.GetProto(this.props.document)[key] = value;
-                return true;
-            }}
-        />)
 
-    /**
-     * Renders the EditableView title element for placement into the tree.
-     */
-    renderTitle() {
-        let reference = React.createRef<HTMLDivElement>();
-        let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true);
+    static loadId = "";
+    editableView = (key: string, style?: string) => (<EditableView
+        oneLine={true}
+        display={"inline"}
+        editing={this.props.document[Id] === TreeView.loadId}
+        contents={StrCast(this.props.document[key])}
+        height={36}
+        fontStyle={style}
+        GetValue={() => StrCast(this.props.document[key])}
+        SetValue={(value: string) => (Doc.GetProto(this.props.document)[key] = value) ? true : true}
+        OnFillDown={(value: string) => {
+            Doc.GetProto(this.props.document)[key] = value;
+            let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
+            TreeView.loadId = doc[Id];
+            return this.props.addDocument(doc);
+        }}
+        OnTab={() => this.props.indentDocument && this.props.indentDocument()}
+    />)
 
+    get keyList() {
         let keyList: string[] = [];
         let keys = Array.from(Object.keys(this.props.document));
         if (this.props.document.proto instanceof Doc) {
@@ -192,19 +162,26 @@ class TreeView extends React.Component<TreeViewProps> {
                 keyList.push(key);
             }
         });
-        let headerElements = this._bulletType === BulletType.List ? (null) : [this._chosenKey].map(key =>
-            <span className="collectionTreeView-keyHeader" key={key} onPointerDown={action(() => { this._chosenKey = key; this.props.document.embed = !BoolCast(this.props.document.embed, false) })}
-                style={{ background: key === this._chosenKey ? "lightgray" : undefined }}>
-                {key}
+        return keyList;
+    }
+    /**
+     * Renders the EditableView title element for placement into the tree.
+     */
+    renderTitle() {
+        let reference = React.createRef<HTMLDivElement>();
+        let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true);
+
+        let headerElements = (
+            <span className="collectionTreeView-keyHeader" key={this._chosenKey} onPointerDown={action(() => this.props.document.embed = !BoolCast(this.props.document.embed))} >
+                {this._chosenKey}
             </span>);
         let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []) : [];
         let openRight = dataDocs && dataDocs.indexOf(this.props.document) !== -1 ? (null) : (
             <div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
                 <FontAwesomeIcon icon="angle-right" size="lg" />
-                {/* <FontAwesomeIcon icon="angle-right" size="lg" /> */}
             </div>);
         return <>
-            <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}
+            <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
                     background: BoolCast(this.props.document.protoBrush, false) ? "#06123232" : BoolCast(this.props.document.libraryBrush, false) ? "#06121212" : "0",
                     pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
@@ -241,7 +218,7 @@ class TreeView extends React.Component<TreeViewProps> {
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
         let before = x[1] < bounds[1];
-        let inside = x[0] > bounds[0] + 75 || (!before && this._bulletType === BulletType.Collapsible);
+        let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed);
         if (de.data instanceof DragManager.DocumentDragData) {
             let addDoc = (doc: Doc) => this.props.addDocument(doc, this.props.document, before);
             if (inside) {
@@ -250,18 +227,13 @@ class TreeView extends React.Component<TreeViewProps> {
                     addDoc = (doc: Doc) => { docList && docList.push(doc); return true; };
                 }
             }
-            let added = false;
-            if (de.data.dropAction || de.data.userDropAction) {
-                added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before) || added, false);
-            } else if (de.data.moveDocument) {
-                let movedDocs = de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments;
-                added = movedDocs.reduce((added: boolean, d) =>
-                    de.data.moveDocument(d, this.props.document, addDoc) || added, false);
-            } else {
-                added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before), false);
-            }
             e.stopPropagation();
-            return added;
+            let movedDocs = (de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments);
+            return (de.data.dropAction || de.data.userDropAction) ?
+                de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before) || added, false)
+                : (de.data.moveDocument) ?
+                    movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.props.document, addDoc) || added, false)
+                    : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.props.document, before), false);
         }
         return false;
     }
@@ -279,62 +251,47 @@ class TreeView extends React.Component<TreeViewProps> {
     docTransform = () => {
         let { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.current!);
         let outerXf = this.props.outerXf();
-        let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf[0] - translateX, outerXf[1] - translateY);
+        let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
         let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
         return finalXf;
     }
-    @observable _chosenKey: string = "data";
-    _bulletType: BulletType = BulletType.List;
 
-    _dref = React.createRef<HTMLDivElement>();
     render() {
-        let bulletType = BulletType.List;
-        let contentElement: (JSX.Element | null)[] = [];
-        [this._chosenKey].map(key => {
-            let docList = Cast(this.props.document[key], listSpec(Doc));
-            let remDoc = (doc: Doc) => this.remove(doc, key);
-            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, key, doc, addBefore, before);
-            let doc = Cast(this.props.document[key], Doc);
-            if (doc instanceof Doc || (docList && (DocListCast(docList).length > 0 || key === "data"))) {
-                if (!this._collapsed) {
-                    bulletType = BulletType.Collapsible;
-                    if (this.props.document.embed) {
-                        contentElement.push(
-                            <div ref={this._dref} style={{ width: "max-content", display: "unset" }} key={this.props.document[Id]}>
-                                <DocumentView Document={this.props.document}
-                                    ContainingCollectionView={undefined}
-                                    ScreenToLocalTransform={this.docTransform}
-                                    isTopMost={false}
-                                    useActualDimensions={true}
-                                    ContentScaling={returnOne}
-                                    PanelWidth={this.props.document[WidthSym]}
-                                    PanelHeight={this.props.document[HeightSym]}
-                                    focus={emptyFunction}
-                                    selectOnLoad={false}
-                                    parentActive={returnFalse}
-                                    whenActiveChanged={emptyFunction}
-                                    bringToFront={emptyFunction}
-                                    addDocTab={this.props.addDocTab}
-                                /></div>);
-                    } else
-                        contentElement.push(<ul key={key + "more"}>
-                            <div style={{ display: "block" }}>
-                                {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, key, addDoc, remDoc, this.move,
-                                    this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.panelHeight)}
-                            </div>
-                        </ul >);
-                } else {
-                    bulletType = BulletType.Collapsed;
-                }
+        let contentElement: (JSX.Element | null) = null;
+        let docList = Cast(this.props.document[this._chosenKey], listSpec(Doc));
+        let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey);
+        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, this._chosenKey, doc, addBefore, before);
+        let doc = Cast(this.props.document[this._chosenKey], Doc);
+        let docWidth = () => NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 5) : this.props.panelWidth() - 5;
+        if (!this._collapsed) {
+            if (!this.props.document.embed && (docList && (DocListCast(docList).length > 0 || this._chosenKey === "data"))) {
+                contentElement = <ul key={this._chosenKey + "more"}>
+                    {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this._chosenKey, addDoc, remDoc, this.move,
+                        this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth)}
+                </ul >;
+            } else {
+                contentElement = <div ref={this._dref} style={{ display: "inline-block", height: this.props.panelHeight() }} key={this.props.document[Id]}>
+                    <CollectionSchemaPreview
+                        Document={this.props.document}
+                        width={docWidth}
+                        height={this.props.panelHeight}
+                        getTransform={this.docTransform}
+                        CollectionView={undefined}
+                        addDocument={emptyFunction as any}
+                        moveDocument={this.props.moveDocument}
+                        removeDocument={emptyFunction as any}
+                        active={this.props.active}
+                        whenActiveChanged={emptyFunction as any}
+                        addDocTab={this.props.addDocTab}
+                        setPreviewScript={emptyFunction}>
+                    </CollectionSchemaPreview>
+                </div>
             }
-        });
-        this._bulletType = bulletType;
-        return <div className="treeViewItem-container"
-            ref={this.createTreeDropTarget}
-            onContextMenu={this.onWorkspaceContextMenu}>
+        }
+        return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onContextMenu={this.onWorkspaceContextMenu}>
             <li className="collection-child">
                 <div className="treeViewItem-header" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    {this.renderBullet(bulletType)}
+                    {this.renderBullet()}
                     {this.renderTitle()}
                 </div>
                 <div className="treeViewItem-border">
@@ -348,17 +305,17 @@ class TreeView extends React.Component<TreeViewProps> {
         treeViewId: string,
         key: string,
         add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean,
-        remove: ((doc: Doc) => void),
+        remove: ((doc: Doc) => boolean),
         move: DragManager.MoveFunction,
         dropAction: dropActionType,
         addDocTab: (doc: Doc, where: string) => void,
         screenToLocalXf: () => Transform,
-        outerXf: () => number[],
+        outerXf: () => { translateX: number, translateY: number },
         active: () => boolean,
         panelWidth: () => number,
-        panelHeight: () => number
     ) {
         let docList = docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized));
+        let rowWidth = () => panelWidth() - 20;
         return docList.map((child, i) => {
             let indent = i === 0 ? undefined : () => {
                 if (StrCast(docList[i - 1].layout).indexOf("CollectionView") !== -1) {
@@ -368,15 +325,22 @@ class TreeView extends React.Component<TreeViewProps> {
                     remove(child);
                 }
             }
+            let addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => {
+                return add(doc, relativeTo ? relativeTo : docList[i], before !== undefined ? before : false);
+            }
+            let rowHeight = () => {
+                let aspect = NumCast(child.nativeWidth, 0) / NumCast(child.nativeHeight, 0);
+                return aspect ? Math.min(child[WidthSym](), rowWidth()) / aspect : child[HeightSym]();
+            }
             return <TreeView
                 document={child}
                 treeViewId={treeViewId}
                 key={child[Id]}
                 indentDocument={indent}
                 deleteDoc={remove}
-                addDocument={add}
-                panelWidth={panelWidth}
-                panelHeight={panelHeight}
+                addDocument={addDocument}
+                panelWidth={rowWidth}
+                panelHeight={rowHeight}
                 moveDocument={move}
                 dropAction={dropAction}
                 addDocTab={addDocTab}
@@ -392,20 +356,26 @@ class TreeView extends React.Component<TreeViewProps> {
 export class CollectionTreeView extends CollectionSubView(Document) {
     private treedropDisposer?: DragManager.DragDropDisposer;
     private _mainEle?: HTMLDivElement;
+
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
-        if (this.treedropDisposer) {
-            this.treedropDisposer();
-        }
-        if (ele) {
+        this.treedropDisposer && this.treedropDisposer();
+        if (this._mainEle = ele) {
             this.treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
         }
-        this._mainEle = ele;
+    }
+
+    componentWillUnmount() {
+        this.treedropDisposer && this.treedropDisposer();
     }
 
     @action
-    remove = (document: Document) => {
+    remove = (document: Document): boolean => {
         let children = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []);
-        children.indexOf(document) !== -1 && children.splice(children.indexOf(document), 1);
+        if (children.indexOf(document) !== -1) {
+            children.splice(children.indexOf(document), 1);
+            return true;
+        }
+        return false;
     }
     onContextMenu = (e: React.MouseEvent): void => {
         // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
@@ -415,26 +385,16 @@ export class CollectionTreeView extends CollectionSubView(Document) {
         }
     }
 
-    outerXf = () => {
-        let outerXf = Utils.GetScreenTransform(this._mainEle!);
-        return [outerXf.translateX, outerXf.translateY];
-    }
-    onTreeDrop = (e: React.DragEvent) => {
-        this.onDrop(e, {});
-    }
+    outerXf = () => Utils.GetScreenTransform(this._mainEle!);
+    onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
+
     render() {
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
-        if (!this.childDocs) {
-            return (null);
-        }
         let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
         let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
-        let childElements = TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove,
-            moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, () => 25);
 
-        return (
+        return !this.childDocs ? (null) : (
             <div id="body" className="collectionTreeView-dropTarget"
-                style={{ borderRadius: "inherit" }}
                 onContextMenu={this.onContextMenu}
                 onWheel={(e: React.WheelEvent) => this.props.isSelected() && e.stopPropagation()}
                 onDrop={this.onTreeDrop}
@@ -445,22 +405,19 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         display={"inline"}
                         height={72}
                         GetValue={() => StrCast(this.props.Document.title)}
+                        SetValue={(value: string) => (Doc.GetProto(this.props.Document).title = value) ? true : true}
                         OnFillDown={(value: string) => {
-                            let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
-                            target.title = value;
-                            let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25 });
+                            Doc.GetProto(this.props.Document).title = value;
+                            let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
                             TreeView.loadId = doc[Id];
-                            doc.templates = new List<string>([Templates.Title.Layout]);
-                            this.props.addDocument(doc);
-                        }}
-                        SetValue={(value: string) => {
-                            let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
-                            target.title = value;
-                            return true;
+                            TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
                         }} />
                 </div>
                 <ul className="no-indent">
-                    {childElements}
+                    {
+                        TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove,
+                            moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth)
+                    }
                 </ul>
             </div >
         );
-- 
cgit v1.2.3-70-g09d2

